[
  {
    "path": ".gitattributes",
    "content": "# Set the default behavior, in case people don't have core.autocrlf set.\n* text=auto\n\n# force LF-only line endings\n*.java text eol=lf\n*.xml text eol=lf\n*.properties text eol=lf\n*.sh text eol=lf\n\n*.c text eol=lf\n*.h text eol=lf\n\n# Declare files that will always have CRLF line endings on checkout.\n*.sln text eol=crlf\n\n# Denote all files that are truly binary and should not be modified.\n*.png binary\n*.jpg binary\n*.catalog binary\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Target Environment (please complete the following information):**\n - Board [e.g. Raspberry Pi 3]\n - OS version: [e.g. provide the result of `uname -a`]\n - Additional info: \n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/copyright-config.yml",
    "content": "# Enable or disable the copyright date check\nbypass_year_check: false\n# In the template the user can specify two variables: {years} and {holder}\n# - {years} will match the copyright years (regex: `\\d{4}(,\\s\\d{4})?`)\n# - {holder} will match the copyright holder (regex: `[\\w\\s\\.]+`)\ntemplate_java: |\n  ******************************************************************************\n   * Copyright (c) {years} {holder} and/or its affiliates and others\n   *\n   * This program and the accompanying materials are made\n   * available under the terms of the Eclipse Public License 2.0\n   * which is available at https://www.eclipse.org/legal/epl-2.0/\n   *\n   * SPDX-License-Identifier: EPL-2.0\n   *\n   * Contributors:\n   *  {holder}\ntemplate_xml: |2\n      Copyright (c) {years} {holder} and/or its affiliates and others\n\n      This program and the accompanying materials are made\n      available under the terms of the Eclipse Public License 2.0\n      which is available at https://www.eclipse.org/legal/epl-2.0/\n\n      SPDX-License-Identifier: EPL-2.0\n\n      Contributors:\n       {holder}\n# Ignore specific files and paths. The syntax and semantics are the same as in the .gitignore file.\nignore:\n  - target-platform/\n  - kura/test/org.eclipse.kura.core.configuration.test/src/test/resources/\n  - suppressions.xml\n  - /kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/*.gpx\n  - /kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/*\n"
  },
  {
    "path": ".github/release_notes_template/helper.hbs",
    "content": "Handlebars.registerHelper('firstLetters', function(input, options) {\n  const number = parseInt(options.hash['number'] || \"0\")\n  return input.substring(0,number);\n});\n\nHandlebars.registerHelper('date', function() {\n  const monthNames = [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\",\n  \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"\n  ];\n\n  const date = new Date();\n  const month = monthNames[date.getMonth()];\n  const year = date.getYear() + 1900;\n\n  return month + \" \" + year;\n});\n"
  },
  {
    "path": ".github/release_notes_template/template.hbs",
    "content": "Eclipse Kura - {{extended.version}} - {{{date}}}\n-------------------------------------------------------------------------------------------------\nDescription:\n[TODO]\n\n{{#issues}}\n{{! Features section }}\n{{#ifContainsType commits type='feat'}}\n\nFeatures:\n  {{#commits}}\n    {{#ifCommitType . type='feat'}}\n  * {{firstLetters hash number='10'}} - {{#eachCommitScope .}}[{{.}}] {{/eachCommitScope}}{{{commitDescription .}}} ({{authorName}})\n    {{/ifCommitType}}\n  {{/commits}}\n{{/ifContainsType}}\n{{! Target environments section }}\n\nTarget Environments:\n[TODO]\n{{! Breaking changes section }}\n{{#ifContainsBreaking commits}}\n\nBreaking changes:\n  {{#commits}}\n    {{#ifCommitBreaking .}}\n  * {{firstLetters hash number='10'}} - {{#eachCommitScope .}}[{{.}}] {{/eachCommitScope}}{{{commitDescription .}}} ({{authorName}})\n    {{/ifCommitBreaking}}\n  {{/commits}}\n{{/ifContainsBreaking}}\n{{! Bug Fixes section }}\n{{#ifContainsType commits type='fix'}}\n\nBug Fixes:\n  {{#commits}}\n    {{#ifCommitType . type='fix'}}\n  * {{firstLetters hash number='10'}} - {{#eachCommitScope .}}[{{.}}] {{/eachCommitScope}}{{{commitDescription .}}} ({{authorName}})\n    {{/ifCommitType}}\n  {{/commits}}\n{{/ifContainsType}}\n{{! Deprecated APIs/components section }}\n{{#ifContainsType commits type='deprecate'}}\n\nDeprecated APIs/components:\n  {{#commits}}\n    {{#ifCommitType . type='deprecate'}}\n  * {{firstLetters hash number='10'}} - {{{commitDescription .}}} ({{authorName}})\n    {{/ifCommitType}}\n  {{/commits}}\n{{/ifContainsType}}\n{{! Target Platform updates section }}\n{{#ifContainsType commits type='build'}}\n\nTarget Platform Updates:\n  {{#commits}}\n    {{#ifCommitType . type='build'}}\n  * {{firstLetters hash number='10'}} - {{{commitDescription .}}} ({{authorName}})\n    {{/ifCommitType}}\n  {{/commits}}\n{{/ifContainsType}}\n{{! Known issues section }}\n\nKnown Issues:\n[TODO]\n{{! Changelog section }}\n\nChangelog:\n{{#commits}}\n  * {{firstLetters hash number='10'}} - {{{messageTitle}}} ({{authorName}})\n{{/commits}}\n{{/issues}}\n"
  },
  {
    "path": ".github/version_uptick_configs/uptick_major_on_develop_branch.yml",
    "content": "---\nexclusions:\n  - \"**/.git/**/*\"\n  - \"**/.github/**/*\"\n  - \"**/target/**/*\"\n  - \"**/RELEASE_INFO/**/*\"\n  - \"**/.settings/**/*\"\n  - \"**/.classpath\"\n  - \"**/.project\"\n  - \"./kura/tools/archetype/example/src/main/resources/**/*\"\n\ntasks:\n  - selector:\n      and:\n        - snapshot\n        - not:\n            artifact_id: \"moquette-broker\"\n    actions:\n      - print\n      - transform_version:\n        - add_major: 1\n        - set_minor: 0\n        - set_patch: 0\n"
  },
  {
    "path": ".github/version_uptick_configs/uptick_minor_on_develop_branch.yml",
    "content": "---\nexclusions:\n  - \"**/.git/**/*\"\n  - \"**/.github/**/*\"\n  - \"**/target/**/*\"\n  - \"**/RELEASE_INFO/**/*\"\n  - \"**/.settings/**/*\"\n  - \"**/.classpath\"\n  - \"**/.project\"\n  - \"./kura/tools/archetype/example/src/main/resources/**/*\"\n\ntasks:\n  - selector:\n      and:\n        - snapshot\n        - not:\n            artifact_id: \"moquette-broker\"\n    actions:\n      - print\n      - transform_version:\n        - add_minor: 1\n        - set_patch: 0\n"
  },
  {
    "path": ".github/version_uptick_configs/uptick_patch_on_maintenance_branch.yml",
    "content": "---\nexclusions:\n  - \"**/.git/**/*\"\n  - \"**/.github/**/*\"\n  - \"**/target/**/*\"\n  - \"**/RELEASE_INFO/**/*\"\n  - \"**/.settings/**/*\"\n  - \"**/.classpath\"\n  - \"**/.project\"\n  - \"./kura/tools/archetype/example/src/main/resources/**/*\"\n\ntasks:\n  - selector:\n      and:\n        - release\n        - not:\n            artifact_id: \"moquette-broker\"\n    actions:\n      - print\n      - transform_version:\n        - add_patch: 1\n        - snapshot: set\n"
  },
  {
    "path": ".github/version_uptick_configs/uptick_snapshot_to_patch_release.yml",
    "content": "---\nexclusions:\n  - \"**/.git/**/*\"\n  - \"**/.github/**/*\"\n  - \"**/target/**/*\"\n  - \"**/RELEASE_INFO/**/*\"\n  - \"**/.settings/**/*\"\n  - \"**/.classpath\"\n  - \"**/.project\"\n  - \"./kura/tools/archetype/example/src/main/resources/**/*\"\n\ntasks:\n  - selector:\n      or:\n        - and:\n          - group_id: \"org.eclipse.kura\"\n          - artifact_id: \"distrib\"\n        - and:\n          - group_id: \"org.eclipse.kura\"\n          - artifact_id: \"tools\"\n        - and:\n          - group_id: \"org.eclipse.kura\"\n          - artifact_id: \"target-platform\"\n        - and:\n          - group_id: \"org.eclipse.kura\"\n          - artifact_id: \"examples\"\n        - and:\n          - group_id: \"org.eclipse.kura.tools\"\n          - artifact_id: \"archetype\"\n        - and:\n          - group_id: \"org.eclipse.kura\"\n          - artifact_id: \"kura\"\n    actions:\n      - print\n      - transform_version:\n        - snapshot: remove\n\n"
  },
  {
    "path": ".github/version_uptick_configs/uptick_snapshot_to_release.yml",
    "content": "---\nexclusions:\n  - \"**/.git/**/*\"\n  - \"**/.github/**/*\"\n  - \"**/target/**/*\"\n  - \"**/RELEASE_INFO/**/*\"\n  - \"**/.settings/**/*\"\n  - \"**/.classpath\"\n  - \"**/.project\"\n  - \"./kura/tools/archetype/example/src/main/resources/**/*\"\n\ntasks:\n  - selector:\n      and:\n        - snapshot\n        - not:\n            artifact_id: \"moquette-broker\"\n    actions:\n      - print\n      - transform_version:\n        - snapshot: remove\n"
  },
  {
    "path": ".github/workflows/backport.yml",
    "content": "name: Backport\non:\n  pull_request_target:\n    types:\n      - closed\n      - labeled\n\npermissions:\n  contents: write\n  pull-requests: write\n\njobs:\n  call-workflow-in-public-repo:\n    uses: eclipse-kura/.github/.github/workflows/_shared-backport.yml@main\n"
  },
  {
    "path": ".github/workflows/copyright-check.yml",
    "content": "name: Copyright check\n\non:\n  pull_request:\n    types: [opened, reopened, synchronize]\n    branches:\n      - 'develop'\n      - 'release-*'\n\njobs:\n  call-workflow-in-public-repo:\n    uses: eclipse-kura/.github/.github/workflows/_shared-copyright-check.yml@main\n    with:\n      config-path: '.github/copyright-config.yml'\n\n"
  },
  {
    "path": ".github/workflows/force-merge.yml",
    "content": "name: \"Force merge automation\"\ndescription: Merge a pull request when N committers post a comment with the command /force-merge\n\non:\n  issue_comment:\n    types: [created, edited, deleted]\n\npermissions:\n  contents: write\n  pull-requests: write\n  issues: write\n\njobs:\n  call-workflow-in-public-repo:\n    uses: eclipse-kura/.github/.github/workflows/_shared-force-merge.yml@main\n    secrets: inherit\n"
  },
  {
    "path": ".github/workflows/kura-core-sbom.yml",
    "content": "name: Kura core SBOM upload\n\non:\n  schedule:\n    # At 00:00 on Saturday\n    - cron: \"0 0 * * 6\"\n  workflow_dispatch:\n    inputs:\n        target_branch:\n          type: string\n          default: 'develop'\n          required: true\n  workflow_run:\n    workflows: [\"Release Notes automation\"]\n    types:\n      - completed\n\n# Product specific settings\nenv:\n  JAVA_VERSION: '21' # java version used by the product\n  JAVA_DISTRO: 'temurin' # java distro used by the product\n  PRODUCT_PATH: \"kura\" # path within project repository for SBOM source\n  PLUGIN_VERSION: '2.9.1' # cyclonedx-maven-plugin version to use\n  WORKFLOW_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}\n  INPUT_TARGET_BRANCH: ${{ github.event.inputs.target_branch }}\n  EVENT_NAME: ${{ github.event_name }}\n  GITHUB_REF_NAME: ${{ github.ref_name }}\n\npermissions:\n  contents: read\n\njobs:\n  generate-sbom:\n    name: Generate Kura core SBOM\n    runs-on: ubuntu-latest\n    if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}\n    outputs:\n      project-version: ${{ steps.get-version.outputs.PROJECT_VERSION }} # required for DependencyTrack upload\n    steps:\n      - name: Set checkout ref\n        id: set-checkout-ref\n        shell: bash\n        run: |\n          if [[ \"$EVENT_NAME\" == \"workflow_run\" ]]; then\n            echo \"CHECKOUT_REF=$WORKFLOW_HEAD_BRANCH\" >> $GITHUB_ENV\n          elif [[ \"$EVENT_NAME\" == \"workflow_dispatch\" ]]; then\n            echo \"CHECKOUT_REF=$INPUT_TARGET_BRANCH\" >> $GITHUB_ENV\n          else\n            echo \"CHECKOUT_REF=$GITHUB_REF_NAME\" >> $GITHUB_ENV\n          fi\n\n      - name: Checkout repository\n        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n        with:\n          fetch-depth: 0\n          ref: ${{ env.CHECKOUT_REF }}\n\n      - name: Debug branch information\n        run: |\n          echo \"=== Debug Branch Information ===\"\n          echo \"Event name: $EVENT_NAME\"\n          echo \"Current branch (git): $(git branch --show-current)\"\n          echo \"===============================\"\n\n      - name: Setup Java SDK\n        uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0\n        with:\n          java-version: ${{ env.JAVA_VERSION }}\n          distribution: ${{ env.JAVA_DISTRO }}\n\n      - name: Generate sbom\n        run: |\n          mvn org.cyclonedx:cyclonedx-maven-plugin:${{ env.PLUGIN_VERSION }}:makeAggregateBom -DprojectType=framework -DexcludeArtifactId=target-definition,emulator,distrib,test,tools,kura-addon-archetype,kura-pde-deps -f ${{ env.PRODUCT_PATH }}/pom.xml\n\n      - name: Extract product version\n        id: get-version\n        shell: bash\n        run: |\n          VERSION=\"$(jq -r '.metadata.component.version' < ./${{ env.PRODUCT_PATH }}/target/bom.json)\"\n\n          # Substitute \"-SNAPSHOT\" suffix with \"@dev\" if present\n          VERSION=\"${VERSION/-SNAPSHOT/@dev}\"\n\n          echo \"PROJECT_VERSION=$VERSION\" >> $GITHUB_OUTPUT\n          echo \"Product version: $VERSION\"\n\n      - name: Upload sbom\n        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0\n        with:\n          name: kura-core-sbom\n          path: ${{ env.PRODUCT_PATH }}/target/bom.json\n\n  store-sbom-data:\n    needs: ['generate-sbom']\n    uses: eclipse-csi/workflows/.github/workflows/store-sbom-data.yml@88508d92f2638d942a88744431f017225ed8c14c # main@08/04/2026\n    with:\n      projectName: 'kura-core'\n      projectVersion: ${{ needs.generate-sbom.outputs.project-version }}\n      bomArtifact: 'kura-core-sbom'\n      bomFilename: 'bom.json'\n      parentProject: 'f295fa60-24df-44d9-83ff-00b3ff8d6131'\n"
  },
  {
    "path": ".github/workflows/release-notes.yml",
    "content": "name: \"Release Notes automation\"\n\non:\n  workflow_dispatch:\n    inputs:\n        starting_commit:\n          type: string\n          description: Commit from which to start generating the Release Notes (non-inclusive)\n          required: true\n        overwrite:\n          type: boolean\n          description: Overwrite the content of TODO fields in generated release notes (typically needed for RC1 notes)\n          required: true\n          default: false\n\npermissions:\n  contents: write\n  pull-requests: write\n\njobs:\n  main:\n    name: Generate Release Notes\n    runs-on: ubuntu-latest\n    steps:\n\n    - name: Checkout ${{ github.ref }} branch in ${{ github.repository }} repository.\n      uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0\n      with:\n        fetch-depth: '0'\n\n    - name: Setup Java\n      uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0\n      with:\n        distribution: 'temurin' # See 'Supported distributions' for available options\n        java-version: '21'\n\n    - name: Get version\n      id: get-version\n      run: \"echo \\\"resolved-version=\\\n        $(mvn\n          --file ./kura/pom.xml\n          -Dexec.executable=echo\n          -Dexec.args='${project.version}'\n          --quiet exec:exec --non-recursive\n        )\\\" >> \\\"${GITHUB_OUTPUT}\\\"\"\n      shell: bash\n\n    - name: Check file existence\n      id: check_files\n      continue-on-error: true\n      uses: thebinaryfelix/check-file-existence-action@436223737a098725b8d10ab1950a03efba5e6fc6 # 1.0.0\n      with:\n        files: './kura/distrib/RELEASE_NOTES.txt'\n\n    - name: Files exist\n      id: get-old-text\n      if: steps.check_files.outputs.exists == 'true' && github.event.inputs.overwrite == 'false'\n      run: |\n        awk '/Description:/ {found=1; next} /^$/ {found=0} found {print}' ./kura/distrib/RELEASE_NOTES.txt > description.txt\n        awk '/Target Environments:/ {found=1; next} /^$/ {found=0} found {print}' ./kura/distrib/RELEASE_NOTES.txt > target-env.txt\n        awk '/Known Issues:/ {found=1; next} /^$/ {found=0} found {print}' ./kura/distrib/RELEASE_NOTES.txt > known-issues.txt\n      shell: bash\n\n    - name: Download git-changelog-command-line tool\n      id: download-changelog-cli\n      uses: clausnz/github-action-download-maven-artifact@bad2e2130cb9d8c86412124298e5ba22ab9cfb66 # 0.0.4\n      with:\n        url: 'https://repo1.maven.org'\n        repository: 'maven2'\n        groupId: 'se.bjurr.gitchangelog'\n        artifactId: 'git-changelog-command-line'\n        version: '2.5.7'\n        extension: 'jar'\n\n    - name: Generate Release Notes\n      run: |\n        java -jar ${{ steps.download-changelog-cli.outputs.file }} \\\n        -fc \"${{ github.event.inputs.starting_commit }}\" \\\n        -ex \"{\\\"version\\\":\\\"${{ steps.get-version.outputs.resolved-version }}\\\"}\" \\\n        -t .github/release_notes_template/template.hbs \\\n        -hhf .github/release_notes_template/helper.hbs \\\n        -of ./kura/distrib/RELEASE_NOTES.txt\n\n    - name: Files exist write description\n      id: get-description\n      if: steps.check_files.outputs.exists == 'true' && github.event.inputs.overwrite == 'false'\n      # Only runs if all of the files exist\n      run: |\n          awk 'NR==FNR { desc = (desc == \"\" ? $0 : desc \"\\n\" $0); next } /\\[TODO\\]/ && !done { sub(/\\[TODO\\]/, desc); done=1 } 1' description.txt done=0 ./kura/distrib/RELEASE_NOTES.txt > tmpfile && mv tmpfile ./kura/distrib/RELEASE_NOTES.txt\n          awk 'NR==FNR { desc = (desc == \"\" ? $0 : desc \"\\n\" $0); next } /\\[TODO\\]/ && !done { sub(/\\[TODO\\]/, desc); done=1 } 1' target-env.txt done=0 ./kura/distrib/RELEASE_NOTES.txt > tmpfile && mv tmpfile ./kura/distrib/RELEASE_NOTES.txt\n          awk 'NR==FNR { desc = (desc == \"\" ? $0 : desc \"\\n\" $0); next } /\\[TODO\\]/ && !done { sub(/\\[TODO\\]/, desc); done=1 } 1' known-issues.txt done=0 ./kura/distrib/RELEASE_NOTES.txt > tmpfile && mv tmpfile ./kura/distrib/RELEASE_NOTES.txt\n      shell: bash\n\n    - name: Files exist clean up\n      id: clean-up-files\n      if: steps.check_files.outputs.exists == 'true' && github.event.inputs.overwrite == 'false'\n      # Only runs if all of the files exist\n      run: |\n        rm description.txt\n        rm target-env.txt\n        rm known-issues.txt\n\n    - name: Create Pull Request\n      uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # v4.2.4\n      with:\n        title: \"chore: add Kura ${{ steps.get-version.outputs.resolved-version }} release notes\"\n        commit-message: \"chore: add Kura ${{ steps.get-version.outputs.resolved-version }} release notes\"\n        body: \"Automated changes by _Release Notes automation_ action: add Kura ${{ steps.get-version.outputs.resolved-version }} version release notes since commit `${{ github.event.inputs.starting_commit }}`\"\n        branch-suffix: short-commit-hash\n        token: ${{ secrets.BOT_GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/semantic-pr.yml",
    "content": "name: \"Lint PR\"\n\non:\n  pull_request_target:\n    types:\n      - opened\n      - edited\n      - synchronize\n\npermissions:\n  pull-requests: read\n\njobs:\n  call-workflow-in-public-repo:\n    uses: eclipse-kura/.github/.github/workflows/_shared-pr-lint.yml@main\n"
  },
  {
    "path": ".github/workflows/stale-issues.yml",
    "content": "name: \"Close inactive issues and PRs\"\non:\n  schedule:\n    - cron: \"30 1 * * *\"\n\npermissions:\n  issues: write\n  pull-requests: write\n\njobs:\n  close-issues:\n    runs-on: ubuntu-latest\n    permissions:\n      issues: write\n      pull-requests: write\n    steps:\n      - uses: actions/stale@f7176fd3007623b69d27091f9b9d4ab7995f0a06 # v5.2.1\n        with:\n          days-before-issue-stale: 60\n          days-before-issue-close: 14\n          stale-issue-label: \"stale\"\n          stale-issue-message: \"This issue is stale because it has been open for 60 days with no activity.\"\n          close-issue-message: \"This issue was closed because it has been inactive for 14 days since being marked as stale.\"\n          exempt-issue-labels: exempt-stale\n          days-before-pr-stale: 60\n          days-before-pr-close: 14\n          stale-pr-message: \"This pull request is stale because it has been open for 60 days with no activity.\"\n          close-pr-message: \"This pull request was closed because it has been inactive for 14 days since being marked as stale.\"\n          exempt-pr-labels: exempt-stale\n          operations-per-run: 300\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n\n"
  },
  {
    "path": ".github/workflows/target-platform-sbom.yml",
    "content": "name: Target Platform SBOM upload\n\non:\n  schedule:\n    # At 00:00 on Saturday\n    - cron: \"0 0 * * 6\"\n  workflow_dispatch:\n    inputs:\n        target_branch:\n          type: string\n          default: 'develop'\n          required: true\n  workflow_run:\n    workflows: [\"Release Notes automation\"]\n    types:\n      - completed\n\n# Product specific settings\nenv:\n  JAVA_VERSION: '21' # java version used by the product\n  JAVA_DISTRO: 'temurin' # java distro used by the product\n  PRODUCT_PATH: 'target-platform' # path within project repository for SBOM source\n  PLUGIN_VERSION: '2.9.1' # cyclonedx-maven-plugin version to use\n  WORKFLOW_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}\n  INPUT_TARGET_BRANCH: ${{ github.event.inputs.target_branch }}\n  EVENT_NAME: ${{ github.event_name }}\n  GITHUB_REF_NAME: ${{ github.ref_name }}\n\npermissions:\n  contents: read\n\njobs:\n  generate-sbom:\n    name: Generate Kura target platform SBOM\n    runs-on: ubuntu-latest\n    if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }}\n    outputs:\n      project-version: ${{ steps.get-version.outputs.PROJECT_VERSION }} # required for DependencyTrack upload\n    steps:\n      - name: Set checkout ref\n        id: set-checkout-ref\n        shell: bash\n        run: |\n          if [[ \"$EVENT_NAME\" == \"workflow_run\" ]]; then\n            echo \"CHECKOUT_REF=$WORKFLOW_HEAD_BRANCH\" >> $GITHUB_ENV\n          elif [[ \"$EVENT_NAME\" == \"workflow_dispatch\" ]]; then\n            echo \"CHECKOUT_REF=$INPUT_TARGET_BRANCH\" >> $GITHUB_ENV\n          else\n            echo \"CHECKOUT_REF=$GITHUB_REF_NAME\" >> $GITHUB_ENV\n          fi\n\n      - name: Checkout repository\n        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2\n        with:\n          fetch-depth: 0\n          ref: ${{ env.CHECKOUT_REF }}\n\n      - name: Debug branch information\n        run: |\n          echo \"=== Debug Branch Information ===\"\n          echo \"Event name: $EVENT_NAME\"\n          echo \"Current branch (git): $(git branch --show-current)\"\n          echo \"===============================\"\n\n      - name: Setup Java SDK\n        uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0\n        with:\n          java-version: ${{ env.JAVA_VERSION }}\n          distribution: ${{ env.JAVA_DISTRO }}\n\n      - name: Generate sbom\n        run: |\n          mvn org.cyclonedx:cyclonedx-maven-plugin:${{ env.PLUGIN_VERSION }}:makeAggregateBom -DprojectType=framework -f ${{ env.PRODUCT_PATH }}/pom.xml\n\n      - name: Extract product version\n        id: get-version\n        shell: bash\n        run: |\n          VERSION=\"$(jq -r '.metadata.component.version' < ./${{ env.PRODUCT_PATH }}/target/bom.json)\"\n\n          # Substitute \"-SNAPSHOT\" suffix with \"@dev\" if present\n          VERSION=\"${VERSION/-SNAPSHOT/@dev}\"\n\n          echo \"PROJECT_VERSION=$VERSION\" >> $GITHUB_OUTPUT\n          echo \"Product version: $VERSION\"\n\n      - name: Upload sbom\n        uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0\n        with:\n          name: target-platform-sbom\n          path: ${{ env.PRODUCT_PATH }}/target/bom.json\n\n  store-sbom-data:\n    needs: ['generate-sbom']\n    uses: eclipse-csi/workflows/.github/workflows/store-sbom-data.yml@88508d92f2638d942a88744431f017225ed8c14c # main@08/04/2026\n    with:\n      projectName: 'kura-target-platform'\n      projectVersion: ${{ needs.generate-sbom.outputs.project-version }}\n      bomArtifact: 'target-platform-sbom'\n      bomFilename: 'bom.json'\n      parentProject: '100d803b-679b-40c2-8e73-101e0bf363ba'\n"
  },
  {
    "path": ".github/workflows/version-uptick.yml",
    "content": "name: Version uptick automation\n\non:\n  workflow_dispatch:\n    inputs:\n        target_branch:\n          type: string\n          default: 'develop'\n          required: true\n        uptick_config:\n          type: choice\n          description: Configuration to use for the uptick\n          options:\n            - uptick_major_on_develop_branch.yml\n            - uptick_minor_on_develop_branch.yml\n            - uptick_patch_on_maintenance_branch.yml\n            - uptick_snapshot_to_patch_release.yml\n            - uptick_snapshot_to_release.yml\n          required: true\n\npermissions:\n  contents: write\n  pull-requests: write\n\njobs:\n  uptick:\n    runs-on: ubuntu-latest\n    steps:\n\n    - name: Checkout\n      uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0\n      with:\n        ref: ${{ github.event.inputs.target_branch }}\n\n    - name: Download version upticker tool\n      uses: carlosperate/download-file-action@8b89cb8b4807765e7d63fe765cc600eb1919af11 # v1.1.2\n      with:\n        file-url: https://kura-repo.s3.us-west-2.amazonaws.com/esf_upticker_tool/version-uptick-0.2.0-linux-x86_64\n\n    - name: Make the uptick tool executable\n      run: |\n        chmod +x ./version-uptick-0.2.0-linux-x86_64\n      shell: bash\n\n    - name: Run the uptick tool\n      run: |\n        ./version-uptick-0.2.0-linux-x86_64 \\\n        --commit --trace process-versions \\\n        --config-path .github/version_uptick_configs/${{ github.event.inputs.uptick_config }} \\\n        --root-dir .\n      shell: bash\n\n    - name: Cleanup uptick tool\n      run: |\n        rm ./version-uptick-0.2.0-linux-x86_64\n      shell: bash\n\n    - name: Get version\n      id: get-version\n      uses: JActions/maven-version@aafa242403588c1c69d619b3cec9c2ff6abd57ac # v1.0.1\n      with:\n        pom: ./kura/pom.xml\n\n    - name: Create Pull Request\n      uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # v4.2.4\n      with:\n        title: \"chore: automated uptick to ${{ steps.get-version.outputs.version }}\"\n        commit-message: \"chore: automated uptick to ${{ steps.get-version.outputs.version }}\"\n        body: \"Automated changes by _Version uptick automation_ action: automated uptick to ${{ steps.get-version.outputs.version }} version\"\n        branch-suffix: timestamp\n        token: ${{ secrets.BOT_GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# OS generated files #\n######################\n.DS_Store*\n*~\nclasses\ntarget\n.classpath\n.project\n.wtpmodules\n.settings\n.sonar\n.sonarlint\n.metadata\n.recommenders\nkura/data\nkura/snapshots\nkura/target-definition/*/plugins/*\nkura/target-definition/*/source/*\nkura/target-definition/repository/artifacts.xml\nkura/target-definition/repository/content.xml\nkura/target-definition/repository/plugins/*\nkura/target-definition/*/repository/artifacts.xml\nkura/target-definition/*/repository/content.xml\nkura/target-definition/*/repository/plugins/*\nkura/tools/archetype/example/src/main/resources/archetype-resources/target-definition\ntarget-platform/*/META-INF/MANIFEST.MF\ntarget-platform/*/*/META-INF/MANIFEST.MF\nkura/distrib/kura-target-definition/kura-target-definition.target\ngwt-unitCache\n.launch\nwww-test\n.gwt\n*.cache.*\nmanifests\nbin/\n+# IntelliJ Idea\n.idea/\n*.iml\nmaven.deps\nDEPENDENCIES\n.java-version\n\n# VS Code\njavaConfig.json\n.vscode\n"
  },
  {
    "path": ".jenkins/nexusUtils.groovy",
    "content": "def uploadPackages(String repoDistribution, String repoModule, Boolean setupPromotion = false) {\n    stage (\"Upload packages parameters check\") {\n        echo \"Distribution: ${repoDistribution}\"\n        echo \"Module: ${repoModule}\"\n\n        // Check \"distribution\" parameter is set and valid\n        assert repoDistribution instanceof String\n        assert repoDistribution ==~ /kura-\\d+/\n\n        // Check \"module\" parameter is set and valid\n        def valid_modules = [\n            \"base\"\n        ]\n\n        assert repoModule instanceof String\n        assert valid_modules.contains(repoModule)\n    }\n\n    stage(\"Upload .deb packages to Nexus\") {\n        def debFiles = findFiles(glob: 'kura/**/*.deb')\n\n        if (debFiles.size() == 0) {\n            error(\"No .deb files found to upload\")\n        }\n\n        debFiles.each {\n            withCredentials([usernameColonPassword(credentialsId: 'repo.eclipse.org-bot-account', variable: 'USERPASS')]) {\n                def status = sh(\n                    script: \"\"\"\n                        curl -u \\\"\\$USERPASS\\\" \\\n                        -w '%{http_code}' \\\n                        -H \\\"Content-Type: multipart/form-data\\\" \\\n                        --data-binary \\\"@./${it}\\\" \\\n                        \\\"https://repo.eclipse.org/repository/kura-apt-dev/\\\" \\\n                        -o /dev/null\n                    \"\"\",\n                    returnStdout: true\n                ).trim()\n\n                if (status != \"201\") {\n                    error(\"Returned status code = $status\")\n                }\n            }\n        }\n\n        if (setupPromotion) {\n            // TODO\n        }\n\n    }\n}\n\nreturn this\n"
  },
  {
    "path": "AGENTS.md",
    "content": "# Eclipse Kura Agent Guide\n\n## Build Commands\n- **Full Build**: `mvn -f target-platform/pom.xml clean install && mvn -f kura/pom.xml clean install && mvn -f kura/distrib/pom.xml clean install -DbuildAll`\n- **Skip Tests**: Add `-Dmaven.test.skip=true` to any build command\n- **Run Single Test**: `mvn -f kura/test/<test-module>/pom.xml test` (e.g., `mvn -f kura/test/org.eclipse.kura.log.filesystem.provider.test/pom.xml test`)\n- **Checkstyle**: Runs automatically during `process-sources` phase with config in `checkstyle_checks.xml`\n\n## Code Style\n- **Java Version**: Java 21 (source/target)\n- **Formatting**: Use profiles in `kura/setup/formatting/` (KuraFormatter.xml, KuraCleanupProfile.xml)\n- **Line Length**: Max 150 characters\n- **Imports**: No star imports, remove unused imports\n- **Line Endings**: Unix (LF) only, no Windows CRLF\n- **Comments**: DO NOT ADD COMMENTS unless explicitly requested\n- **Copyright**: Always update copyright year to 2026 if editing files; add `// Content with portions generated by generative AI platform` after copyright header\n- **Naming**: camelCase for variables/methods; UPPER_SNAKE_CASE for constants; loggers can be named `log`, `logger`, or `auditLogger`\n\n## Testing\n- **Gherkin-Style Mandatory**: Every new unit or integration test must follow the Gherkin structure (Given/When/Then). Organize tests so that a single feature is covered per test class.\n- **Feature Classes**: Choose a concise feature name for the test class (e.g., `StoreWireEnvelopeTest`). Group features for the same component under the same package. If the feature becomes complex, split it into multiple classes.\n- **Scenarios as @Test Methods**: Place public scenario methods annotated with `@Test` at the top of the class. Scenario names describe the behavior (e.g., `successfulStoreOnExistingTable`). Scenario methods have no parameters and return `void`. Cover both happy and unhappy paths.\n- **Steps as Private Helpers**: Define private step methods after the scenarios. Step method names start with `given`, `when`, or `then`. Steps do not return values, can take arguments, and must contain the relevant assertions. Group steps in Given/When/Then order inside each scenario, separating groups with a blank line.\n- **Internal State**: Maintain intermediate state with fields when needed. Extract common setup logic into abstract helpers only if it improves clarity.\n- **Sample Structure**:\n  ```java\n  @Test\n  public void successfulStoreOnExistingTable() {\n      givenDatabaseConnection();\n      givenValidConfiguration();\n\n      whenWireEnvelopeArrives();\n\n      thenEnvelopeIsPersisted();\n      thenNoErrorsAreReported();\n  }\n  ```\n\n## Commit Format\n- Format: `<type>[optional scope]: <description>`\n- Types:\n  - `feat`: add a new feature\n  - `fix`: address a bug\n  - `docs`: documentation-only changes\n  - `refactor`: code change that is neither a feature nor a bug fix\n  - `test`: add or adjust tests\n  - `style`: formatting or stylistic changes with no behavior impact\n  - `chore`: tooling/configuration updates not shipped to production\n  - `build`: build system or dependency changes\n  - `ci`: CI configuration updates\n  - `revert`: revert a previous commit\n  - `perf`: performance improvements\n  - `deprecate`: mark an API as deprecated (include the API name in the description)\n- Scope: Optional. Use the last segment of the affected bundle name without the `org.eclipse.kura` prefix (e.g., `feat(core.keystore): add key rotation`).\n- Breaking Changes: Append `!` after the type or scope for breaking changes (e.g., `feat(core.keystore)!: drop legacy cipher`). Provide additional details in the commit body starting with `BREAKING CHANGE:`.\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Community Code of Conduct\n\n**Version 1.2  \nAugust 19, 2020**\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as community members, contributors, committers, and project leaders pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nWith the support of the Eclipse Foundation staff (the “Staff”), project committers and leaders are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject committers and leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies within all project spaces, and it also applies when an individual is representing the Eclipse Foundation project or its community in public spaces. Examples of representing a project or community include posting via an official social media account, or acting as a project representative at an online or offline event. Representation of a project may be further defined and clarified by project committers, leaders, or the EMO.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Staff at codeofconduct@eclipse.org. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The Staff is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject committers or leaders who do not follow the Code of Conduct in good faith may face temporary or permanent repercussions as determined by the Staff.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org) , version 1.4, available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html](https://www.contributor-covenant.org/version/1/4/code-of-conduct/)"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to contribute to Eclipse Kura\n\nFirst of all, thanks for considering to contribute to Eclipse Kura. We really appreciate the time and effort you want to\nspend helping to improve things around here. And help we can use :-)\n\nHere is a (non-exclusive, non-prioritized) list of things you might be able to help us with:\n\n* bug reports\n* bug fixes\n* improvements regarding code quality e.g. improving readability, performance, modularity etc.\n* documentation (Getting Started guide, Examples, Deployment instructions in cloud environments)\n* features (both ideas and code are welcome)\n* tests\n\nIn order to get you started as fast as possible we need to go through some organizational issues first.\n\n## Legal Requirements\n\nKura is an [Eclipse IoT](http://iot.eclipse.org) project and as such is governed by the Eclipse Development process.\nThis process helps us in creating great open source software within a safe legal framework.\n\n### First Steps\nFor you as a contributor, the following preliminary steps are required in order for us to be able to accept your contribution:\n\n* Sign the [Eclipse Foundation Contributor License Agreement](http://www.eclipse.org/legal/CLA.php).\nIn order to do so:\n\n  * Obtain an Eclipse Foundation user ID. Anyone who currently uses Eclipse Bugzilla or Gerrit systems already has one of those.\nIf you don't already have an account simply [register on the Eclipse web site](https://dev.eclipse.org/site_login/createaccount.php).\n  * Once you have your account, log in to the [projects portal](https://projects.eclipse.org/), select *My Account* and then the *Contributor License Agreement* tab.\n\n* Add your GiHub username to your Eclipse Foundation account. Log in to Eclipse and go to [Edit my account](https://dev.eclipse.org/site_login/myaccount.php).\n\n### File Headers\nA proper header must be in place for any file contributed to Eclipse Kura. For a new contribution, please add the below header:\n\n```\n/*******************************************************************************\n * Copyright (c) <year> <legal entity> and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which accompanies this distribution, and is available at\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  <legal entity>\n *******************************************************************************/\n```\n\n Please ensure \\<year\\> is replaced with the current year or range (e.g. 2017 or 2015, 2017).\n Please ensure \\<legal entity\\> is replaced with the relevant information. If you are editing an existing contribution, feel free\n to create or add your legal entity to the contributors section\n\n### How to Contribute\nThe easiest way to contribute code/patches/whatever is by creating a GitHub pull request (PR). When you do make sure that you *Sign-off* your commit records using the same email address used for your Eclipse account.\n\nYou do this by adding the `-s` flag when you make the commit(s), e.g.\n\n    $> git commit -s -m \"Shave the yak some more\"\n\nYou can find all the details in the [Contributing via Git](http://wiki.eclipse.org/Development_Resources/Contributing_via_Git) document on the Eclipse web site.\n\n#### Development Model\n\nDevelopment on Eclipse Kura™ follows a [variant of the gitflow model](https://github.com/eclipse/kura/wiki/Kura-Git-Workflow).  Development is made on the [develop branch](/eclipse/kura/tree/develop). The master branch is not used anymore.\n\n#### Stale PR policy\n\nTo avoid piling up too many Issues and Pull Requests we enabled a Github Action that takes care of automatically closing stale Issues/Pull Request.\n\n- An Issue/Pull Request gets tagged as \"_stale_\" after **60 days** of inactivity (i.e. no comments/commits etc.)\n- An Issue/Pull Request gets automatically closed after being \"_stale_\" for **14 days** without any update\n\nKeep this in mind when contributing to the Eclipse Kura project.\n\n## Making your Changes\n\n* Fork the repository on GitHub\n* Create a new branch for your changes\n* Configure your IDE installing:\n  * The formatter profile available in kura/setup/formatting/KuraFormatter*.xml\n  * The cleanup profile available in kura/setup/formatting/KuraCleanupProfile*.xml\n  * [SonarLint](http://www.sonarlint.org/eclipse/index.html)\n* Make your changes\n* Make sure you include test cases for non-trivial features\n* Make sure the test suite passes after your changes\n* Make sure copyright headers are included in (all) files including updated year(s)\n* Make sure build plugins and dependencies and their versions have (approved) CQs\n* Make sure proper headers are in place for each file (see above Legal Requirements)\n* Commit your changes into that branch\n* Use descriptive and meaningful commit messages\n* If you have a lot of commits squash them into a single commit\n* Make sure you use the `-s` flag when committing as explained above\n* Push your changes to your branch in your forked repository\n* Make a full clean build (locally and/or using [Travis CI](http://travis-ci.org)) before you submit a pull request\n\n## Tests\n\nEclipse Kura since 5.1.0 version only accepts tests made following Gherkin format.\n\nExtend the old tests files is still allowed but not creating new ones.\n\n### Gherkin Tests Guidelines\n\nGherkin is a particular language that originates from Behavioral-Driven Development (BDD). In BDD, the developer defines tests that will guide the development and constitute a requirement. The tests are written by first defining the **feature** that is going to be tested, then defining the most relevant execution paths for that feature, called **scenarios**, and, finally, detailing the scenarios into simple **steps** using Gherkin language.\n\n### Features\n\nEvery Gherkin test should test a specific feature. Every tested feature is contained in a single test class.\n\nAn example of feature for the H2DbWireStoreComponent can be *“Store wire envelopes“* and the corresponding test class will be StoreWireEnvelopeTest.java.\n\nGuidelines for defining features:\n\n- group features for a specific component in the same test package\n- if it is not easy to define a simple name that describes the feature, then maybe it is too complicated and needs to be split into multiple features\n- if the tested component is simple, then use the existing naming convention: ComponentNameTest\n\n### Scenarios\n\nScenarios break down the single feature into steps. Each scenario covers a path of execution for that feature and is identified by a method inside the feature class.\n\nAs an example for the H2DbStoreComponent, one can think of a scenario *“Successful store data“* which will correspond to the method successfulStore(), but also of a scenario that should cause an error like *“Store in a DB table that does not exist“*.\n\nGuidelines for defining scenarios:\n\n- try to define also the unhappy paths, i.e. paths that cause errors\n- methods that define scenarios do not return values, do not have parameters, and should be annotated with JUnit’s @Test annotation\n- the method name should describe the scenario as better as possible; no comments should be needed to understand it; else, break it down into multiple ones\n- no nested scenarios\n- scenarios should be placed on top of the class, it is the first and only thing that a developer should read to understand the test\n\n### Steps\n\nSteps detail scenarios further. Scenarios contain multiple steps that follow a specific pattern. Steps can be defined using one of these keywords:\n\n***given - when - then***\n\n- **given** defines the test preconditions, an initial context\n- **when** defines the actions performed, or events\n- **then** describes the effects, the expected outcome\n\nGuidelines for defining steps:\n\n- step methods must be private and separated from the scenarios: public scenarios on top, private steps on the bottom\n- steps inside a scenario always follow the *given-when-then* order\n- step methods names must start with one of the keywords\n- there can be multiple steps of the same kind inside a single scenario, i.e. 3 given, 1 when, 2 then; to improve readability separate them with a blank line to form a group for the *given* steps, one for the *when* steps, and one for the *then* steps\n- steps can take arguments\n- steps do not return values\n- step methods contain asserts\n\nExample of a scenario with steps:\n\n```java\n@Test\npublic void storeOnNotExistentTable() {\n  givenDatabaseConnection();\n  givenConfigurationWithWrongTableName();\n  \n  whenWireEnvelopeArrives();\n\n  thenThrowException();\n  thenDataNotStored();\n}\n```\n\n### Internal State and Helpers\n\nSince step and scenario methods are not allowed to return any value, it is sometimes necessary to maintain an **internal state** inside the feature class. Where the tested features require complex dependencies, it might be useful to define an **abstract helper class** which will be inherited by all the feature classes.\n\nThe Gherkin reference: https://cucumber.io/docs/gherkin/reference/ \n\n### Manual Tests\n\nBefore you submit a Pull Request, ensure that your changes have been tested and are functional in a live environment. If you require additional validation, kindly request your reviewer to perform the necessary tests. It is strongly recommended that you personally verify your changes before submission and only seek further testing when absolutely necessary.\n\n## Submitting the Changes\n\nSubmit a pull request via the normal GitHub UI.\n\nWe are using the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) convention for our pull request titles. This convention dovetails with [SemVer](https://semver.org/), by describing the features, fixes, and breaking changes made in commit messages.\n\nEvery PR which is not in draft mode should follow conventional commit convention for PR title. Therefore the title should be in the format:\n\n```\n<type>[optional scope]: <description>\n```\n\nWhere:\n- `<type>` - see [_Type_ section](#type)\n- `[optional scope]` - see [_Scope_ section](#scope)\n- `<description>` - description of the PR\n\n**BREAKING CHANGE:** a commit that appends a `!` after the type/scope, introduces a breaking API change. A BREAKING CHANGE can be part of commits of any _type_.\n\nOnce merged and squashed in the main development branch, the resulting commit message should match the PR title.\n\nFor details see the [full specification](https://www.conventionalcommits.org/en/v1.0.0/#specification).\n\n### Type\n\n1.  The type `feat` MUST be used when a commit adds a new feature to your application or library.\n2.  The type `fix` MUST be used when a commit represents a bug fix for your application.\n\nTypes other than `feat` and `fix` MAY be used in your commit messages and must be one of the following:\n\n- `docs`: Documentation only changes\n- `refactor`: A code change that neither fixes a bug nor adds a feature (removing redundant code, code semplification, renaming variables, removing features, etc)\n- `test`: Adding missing tests or correcting existing tests\n- `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)\n- `chore`: Tool changes, configuration changes, and changes to things that do not actually go into production at all (upticks/bumps, manual update of release notes...)\n- `build`: Changes that affect the build system or external dependencies (dependencies update)\n- `ci`: Changes to our CI configuration files and scripts\n- `revert`: Reverts a previous commit\n- `perf`: A code change that improves performance\n- `deprecate`: An API/component deprecation. Use the summary field to provide the API/component which was deprecated (eg: `deprecate: org.eclipse.kura.position.PositionService`)\n\n### Scope\n\nA scope MAY be provided after a type. A scope MUST consist of a noun describing a section of the codebase surrounded by parenthesis, e.g., `fix(parser):`\n\nThe scope should describe the section of the code affected by the changes as perceived by the person reading the changelog generated from commit messages.\n\nAs a general rule use the last part of the bundle name as the scope (i.e. without `org.eclipse.kura`). If the PR spans across multiple bundles use the main one or do not fill the scope at all.\n\nExample: if a PR adds a feature to the `org.eclipse.kura.core.keystore` bundle, the PR title shoud be `feat(core.keystore): new awesome feature`.\n\n## After Submitting\n\n* Do not use your branch for any other development, otherwise further changes that you make will be visible in the PR.\n"
  },
  {
    "path": "Jenkinsfile",
    "content": "import org.jenkinsci.plugins.pipeline.modeldefinition.Utils\n\ndef boolean onlyDocumentationFilesChangedIn(String workDirectory) {\n    if (!env.CHANGE_TARGET) {\n        echo \"CHANGE_TARGET not set. Skipping check\"\n        return false\n    }\n\n    def changedFiles = sh(script: \"cd ${workDirectory} && git diff --name-only origin/${env.CHANGE_TARGET} origin/${env.BRANCH_NAME}\", returnStdout: true).trim().split(\"\\n\")\n\n    echo \"Changed files: ${changedFiles}\" // Debug\n\n    return changedFiles && changedFiles.every { it.endsWith(\".md\") || it.endsWith(\".txt\") }\n}\n\nnode {\n    properties([\n        disableConcurrentBuilds(abortPrevious: true),\n        buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '1', daysToKeepStr: '', numToKeepStr: '3')),\n        gitLabConnection('gitlab.eclipse.org'),\n        [$class: 'RebuildSettings', autoRebuild: false, rebuildDisabled: false],\n        [$class: 'JobLocalConfiguration', changeReasonComment: '']\n    ])\n\n    deleteDir()\n\n    stage('Preparation') {\n        dir(\"kura\") {\n            checkout scm\n            sh \"touch /tmp/isJenkins.txt\"\n        }\n    }\n\n    // Skip build if only documentation files (i.e. *.md and *.txt) have changed\n    if (onlyDocumentationFilesChangedIn(\"kura\")) {\n        echo \"Skipping build for documentation changes\"\n        currentBuild.result = 'SUCCESS'\n        return\n    }\n\n    stage('Build target-platform') {\n        timeout(time: 1, unit: 'HOURS') {\n            dir(\"kura\") {\n                withMaven(jdk: 'temurin-jdk21-latest', maven: 'apache-maven-3.9.9', options: [artifactsPublisher(disabled: true)]) {\n                    sh \"mvn -f target-platform/pom.xml clean install -Pno-mirror -Pcheck-exists-plugin\"\n                }\n            }\n        }\n    }\n\n    stage('Build core') {\n        timeout(time: 2, unit: 'HOURS') {\n            dir(\"kura\") {\n                withMaven(jdk: 'temurin-jdk21-latest', maven: 'apache-maven-3.9.9', options: [artifactsPublisher(disabled: true)]) {\n                    sh \"mvn -f kura/pom.xml -Dsurefire.rerunFailingTestsCount=3 clean install -Pcheck-exists-plugin\"\n                }\n            }\n        }\n    }\n\n    stage('Build distrib') {\n        timeout(time: 1, unit: 'HOURS') {\n            dir(\"kura\") {\n                withMaven(jdk: 'temurin-jdk21-latest', maven: 'apache-maven-3.9.9', options: [artifactsPublisher(disabled: true)]) {\n                    sh \"mvn -f kura/distrib/pom.xml clean install\"\n        }\n            }\n        }\n    }\n\n    stage('Generate test reports') {\n        dir(\"kura\") {\n            junit 'kura/test/*/target/surefire-reports/*.xml'\n        }\n    }\n\n    stage (\"Deploy on Nexus\") {\n        // Call uploadPackages only if we are on the default branch,\n        // if we have DEB packages to upload and if the user has set the pushArtifacts parameter to true\n        if (env.BRANCH_IS_PRIMARY) {\n            echo \"Uploading DEB packages...\"\n\n            def distribPom = readMavenPom file: 'kura/kura/distrib/pom.xml'\n\n            def repoDistribution = distribPom.properties['kura.repo.distribution']\n            def repoModule = distribPom.properties['kura.repo.module']\n\n            def nexusUtils = load 'kura/.jenkins/nexusUtils.groovy'\n            nexusUtils.uploadPackages(repoDistribution, repoModule)\n        } else {\n            echo \"Skipping DEB upload\"\n            Utils.markStageSkippedForConditional(STAGE_NAME)\n        }\n    }\n\n    stage('Archive .deb artifacts') {\n        dir(\"kura\") {\n            archiveArtifacts artifacts: 'kura/distrib/**/target/*.deb', onlyIfSuccessful: true\n        }\n    }\n\n    stage('Sonar') {\n        timeout(time: 2, unit: 'HOURS') {\n            dir(\"kura\") {\n                withMaven(jdk: 'temurin-jdk21-latest', maven: 'apache-maven-3.9.9', options: [artifactsPublisher(disabled: true)]) {\n                    withSonarQubeEnv(credentialsId: 'sonarcloud-token') {\n                        // Check if on primary branch\n                        def analysisParameters = \"\"\n                        if (env.CHANGE_ID) {\n                            analysisParameters = \"-Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.pullrequest.key=${env.CHANGE_ID}\"\n                        } else {\n                            analysisParameters = \"-Dsonar.branch.name=${env.BRANCH_NAME}\"\n                        }\n\n                        sh \"\"\"\n                            mvn -f kura/pom.xml org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \\\n                                -Dmaven.test.failure.ignore=true \\\n                                -Dsonar.organization=eclipse \\\n                                -Dsonar.host.url=${SONAR_HOST_URL} \\\n                                -Dsonar.java.binaries='target/' \\\n                                ${analysisParameters} \\\n                                -Dsonar.core.codeCoveragePlugin=jacoco \\\n                                -Dsonar.projectKey=org.eclipse.kura:kura \\\n                                -Dsonar.exclusions=test/**/*,**/*.xml,**/*.yml,test-util/**/* \\\n                                -Dsonar.test.exclusions=**/*\n                        \"\"\"\n                    }\n                }\n            }\n        }\n    }\n\n    stage('quality-gate') {\n        // Sonar quality gate\n        timeout(time: 30, unit: 'MINUTES') {\n            withCredentials([string(credentialsId: 'sonarcloud-token', variable: 'SONARCLOUD_TOKEN')]) {\n                def qg = waitForQualityGate()\n                if (qg.status != 'OK') {\n                    error \"Pipeline aborted due to sonar quality gate failure: ${qg.status}\"\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "Eclipse Public License - v 2.0\n\n    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n    PUBLIC LICENSE (\"AGREEMENT\"). ANY USE, REPRODUCTION OR DISTRIBUTION\n    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.\n\n1. DEFINITIONS\n\n\"Contribution\" means:\n\n  a) in the case of the initial Contributor, the initial content\n     Distributed under this Agreement, and\n\n  b) in the case of each subsequent Contributor:\n     i) changes to the Program, and\n     ii) additions to the Program;\n  where such changes and/or additions to the Program originate from\n  and are Distributed by that particular Contributor. A Contribution\n  \"originates\" from a Contributor if it was added to the Program by\n  such Contributor itself or anyone acting on such Contributor's behalf.\n  Contributions do not include changes or additions to the Program that\n  are not Modified Works.\n\n\"Contributor\" means any person or entity that Distributes the Program.\n\n\"Licensed Patents\" mean patent claims licensable by a Contributor which\nare necessarily infringed by the use or sale of its Contribution alone\nor when combined with the Program.\n\n\"Program\" means the Contributions Distributed in accordance with this\nAgreement.\n\n\"Recipient\" means anyone who receives the Program under this Agreement\nor any Secondary License (as applicable), including Contributors.\n\n\"Derivative Works\" shall mean any work, whether in Source Code or other\nform, that is based on (or derived from) the Program and for which the\neditorial revisions, annotations, elaborations, or other modifications\nrepresent, as a whole, an original work of authorship.\n\n\"Modified Works\" shall mean any work in Source Code or other form that\nresults from an addition to, deletion from, or modification of the\ncontents of the Program, including, for purposes of clarity any new file\nin Source Code form that contains any contents of the Program. Modified\nWorks shall not include works that contain only declarations,\ninterfaces, types, classes, structures, or files of the Program solely\nin each case in order to link to, bind by name, or subclass the Program\nor Modified Works thereof.\n\n\"Distribute\" means the acts of a) distributing or b) making available\nin any manner that enables the transfer of a copy.\n\n\"Source Code\" means the form of a Program preferred for making\nmodifications, including but not limited to software source code,\ndocumentation source, and configuration files.\n\n\"Secondary License\" means either the GNU General Public License,\nVersion 2.0, or any later versions of that license, including any\nexceptions or additional permissions as identified by the initial\nContributor.\n\n2. GRANT OF RIGHTS\n\n  a) Subject to the terms of this Agreement, each Contributor hereby\n  grants Recipient a non-exclusive, worldwide, royalty-free copyright\n  license to reproduce, prepare Derivative Works of, publicly display,\n  publicly perform, Distribute and sublicense the Contribution of such\n  Contributor, if any, and such Derivative Works.\n\n  b) Subject to the terms of this Agreement, each Contributor hereby\n  grants Recipient a non-exclusive, worldwide, royalty-free patent\n  license under Licensed Patents to make, use, sell, offer to sell,\n  import and otherwise transfer the Contribution of such Contributor,\n  if any, in Source Code or other form. This patent license shall\n  apply to the combination of the Contribution and the Program if, at\n  the time the Contribution is added by the Contributor, such addition\n  of the Contribution causes such combination to be covered by the\n  Licensed Patents. The patent license shall not apply to any other\n  combinations which include the Contribution. No hardware per se is\n  licensed hereunder.\n\n  c) Recipient understands that although each Contributor grants the\n  licenses to its Contributions set forth herein, no assurances are\n  provided by any Contributor that the Program does not infringe the\n  patent or other intellectual property rights of any other entity.\n  Each Contributor disclaims any liability to Recipient for claims\n  brought by any other entity based on infringement of intellectual\n  property rights or otherwise. As a condition to exercising the\n  rights and licenses granted hereunder, each Recipient hereby\n  assumes sole responsibility to secure any other intellectual\n  property rights needed, if any. For example, if a third party\n  patent license is required to allow Recipient to Distribute the\n  Program, it is Recipient's responsibility to acquire that license\n  before distributing the Program.\n\n  d) Each Contributor represents that to its knowledge it has\n  sufficient copyright rights in its Contribution, if any, to grant\n  the copyright license set forth in this Agreement.\n\n  e) Notwithstanding the terms of any Secondary License, no\n  Contributor makes additional grants to any Recipient (other than\n  those set forth in this Agreement) as a result of such Recipient's\n  receipt of the Program under the terms of a Secondary License\n  (if permitted under the terms of Section 3).\n\n3. REQUIREMENTS\n\n3.1 If a Contributor Distributes the Program in any form, then:\n\n  a) the Program must also be made available as Source Code, in\n  accordance with section 3.2, and the Contributor must accompany\n  the Program with a statement that the Source Code for the Program\n  is available under this Agreement, and informs Recipients how to\n  obtain it in a reasonable manner on or through a medium customarily\n  used for software exchange; and\n\n  b) the Contributor may Distribute the Program under a license\n  different than this Agreement, provided that such license:\n     i) effectively disclaims on behalf of all other Contributors all\n     warranties and conditions, express and implied, including\n     warranties or conditions of title and non-infringement, and\n     implied warranties or conditions of merchantability and fitness\n     for a particular purpose;\n\n     ii) effectively excludes on behalf of all other Contributors all\n     liability for damages, including direct, indirect, special,\n     incidental and consequential damages, such as lost profits;\n\n     iii) does not attempt to limit or alter the recipients' rights\n     in the Source Code under section 3.2; and\n\n     iv) requires any subsequent distribution of the Program by any\n     party to be under a license that satisfies the requirements\n     of this section 3.\n\n3.2 When the Program is Distributed as Source Code:\n\n  a) it must be made available under this Agreement, or if the\n  Program (i) is combined with other material in a separate file or\n  files made available under a Secondary License, and (ii) the initial\n  Contributor attached to the Source Code the notice described in\n  Exhibit A of this Agreement, then the Program may be made available\n  under the terms of such Secondary Licenses, and\n\n  b) a copy of this Agreement must be included with each copy of\n  the Program.\n\n3.3 Contributors may not remove or alter any copyright, patent,\ntrademark, attribution notices, disclaimers of warranty, or limitations\nof liability (\"notices\") contained within the Program from any copy of\nthe Program which they Distribute, provided that Contributors may add\ntheir own appropriate notices.\n\n4. COMMERCIAL DISTRIBUTION\n\nCommercial distributors of software may accept certain responsibilities\nwith respect to end users, business partners and the like. While this\nlicense is intended to facilitate the commercial use of the Program,\nthe Contributor who includes the Program in a commercial product\noffering should do so in a manner which does not create potential\nliability for other Contributors. Therefore, if a Contributor includes\nthe Program in a commercial product offering, such Contributor\n(\"Commercial Contributor\") hereby agrees to defend and indemnify every\nother Contributor (\"Indemnified Contributor\") against any losses,\ndamages and costs (collectively \"Losses\") arising from claims, lawsuits\nand other legal actions brought by a third party against the Indemnified\nContributor to the extent caused by the acts or omissions of such\nCommercial Contributor in connection with its distribution of the Program\nin a commercial product offering. The obligations in this section do not\napply to any claims or Losses relating to any actual or alleged\nintellectual property infringement. In order to qualify, an Indemnified\nContributor must: a) promptly notify the Commercial Contributor in\nwriting of such claim, and b) allow the Commercial Contributor to control,\nand cooperate with the Commercial Contributor in, the defense and any\nrelated settlement negotiations. The Indemnified Contributor may\nparticipate in any such claim at its own expense.\n\nFor example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those performance\nclaims and warranties, and if a court requires any other Contributor to\npay any damages as a result, the Commercial Contributor must pay\nthose damages.\n\n5. NO WARRANTY\n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT\nPERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN \"AS IS\"\nBASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR\nIMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF\nTITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR\nPURPOSE. Each Recipient is solely responsible for determining the\nappropriateness of using and distributing the Program and assumes all\nrisks associated with its exercise of rights under this Agreement,\nincluding but not limited to the risks and costs of program errors,\ncompliance with applicable laws, damage to or loss of data, programs\nor equipment, and unavailability or interruption of operations.\n\n6. DISCLAIMER OF LIABILITY\n\nEXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT\nPERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS\nSHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\nEXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST\nPROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE\nEXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n7. GENERAL\n\nIf any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further\naction by the parties hereto, such provision shall be reformed to the\nminimum extent necessary to make such provision valid and enforceable.\n\nIf Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other software\nor hardware) infringes such Recipient's patent(s), then such Recipient's\nrights granted under Section 2(b) shall terminate as of the date such\nlitigation is filed.\n\nAll Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of\ntime after becoming aware of such noncompliance. If all Recipient's\nrights under this Agreement terminate, Recipient agrees to cease use\nand distribution of the Program as soon as reasonably practicable.\nHowever, Recipient's obligations under this Agreement and any licenses\ngranted by Recipient relating to the Program shall continue and survive.\n\nEveryone is permitted to copy and distribute copies of this Agreement,\nbut in order to avoid inconsistency the Agreement is copyrighted and\nmay only be modified in the following manner. The Agreement Steward\nreserves the right to publish new versions (including revisions) of\nthis Agreement from time to time. No one other than the Agreement\nSteward has the right to modify this Agreement. The Eclipse Foundation\nis the initial Agreement Steward. The Eclipse Foundation may assign the\nresponsibility to serve as the Agreement Steward to a suitable separate\nentity. Each new version of the Agreement will be given a distinguishing\nversion number. The Program (including Contributions) may always be\nDistributed subject to the version of the Agreement under which it was\nreceived. In addition, after a new version of the Agreement is published,\nContributor may elect to Distribute the Program (including its\nContributions) under the new version.\n\nExcept as expressly stated in Sections 2(a) and 2(b) above, Recipient\nreceives no rights or licenses to the intellectual property of any\nContributor under this Agreement, whether expressly, by implication,\nestoppel or otherwise. All rights in the Program not expressly granted\nunder this Agreement are reserved. Nothing in this Agreement is intended\nto be enforceable by any entity that is not a Contributor or Recipient.\nNo third-party beneficiary rights are created under this Agreement.\n\nExhibit A - Form of Secondary Licenses Notice\n\n\"This Source Code may also be made available under the following\nSecondary Licenses when the conditions for such availability set forth\nin the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\nversion(s), and exceptions or additional permissions here}.\"\n\n  Simply including a copy of this Agreement, including this Exhibit A\n  is not sufficient to license the Source Code under Secondary Licenses.\n\n  If it is not possible or desirable to put the notice in a particular\n  file, then You may include the notice in a location (such as a LICENSE\n  file in a relevant directory) where a recipient would be likely to\n  look for such a notice.\n\n  You may add additional accurate notices of copyright ownership."
  },
  {
    "path": "NOTICE.md",
    "content": "# Notices for Eclipse Kura\n\nThis content is produced and maintained by the Eclipse Kura project.\n\n* Project home: https://projects.eclipse.org/projects/iot.kura\n\n## Trademarks\n\nEclipse Kura, and Kura are trademarks of the Eclipse Foundation.\n\n## Copyright\n\nAll content is the property of the respective authors or their employers. For\nmore information regarding authorship of content, please consult the listed\nsource code repository logs.\n\n## Declared Project Licenses\n\nThis program and the accompanying materials are made available under the terms\nof the Eclipse Public License v2.0 which is available at\nhttps://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html.\n\nSPDX-License-Identifier: EPL-2.0\n\n## Source Code\n\nThe project maintains the following source code repositories:\n\n* https://github.com/eclipse/kura\n* https://github.com/eclipse/kura-apps\n\n## Third-party Content\n\nThis project leverages the following third party content.\n\n### Maven Dependencies\n\n* maven/mavencentral/com.eclipsesource.minimal-json/minimal-json/0.9.5, MIT, approved, CQ10061\n* maven/mavencentral/com.fasterxml.jackson.core/jackson-annotations/2.19.1, Apache-2.0, approved, #21911\n* maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.19.1, Apache-2.0 AND MIT, approved, #21916\n* maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.19.1, Apache-2.0, approved, #21909\n* maven/mavencentral/com.github.docker-java/docker-java-api/3.5.3, Apache-2.0, approved, #22668\n* maven/mavencentral/com.github.docker-java/docker-java-core/3.5.3, Apache-2.0, approved, #22665\n* maven/mavencentral/com.github.docker-java/docker-java-transport-httpclient5/3.5.3, Apache-2.0, approved, #22669\n* maven/mavencentral/com.github.docker-java/docker-java-transport/3.5.3, Apache-2.0, approved, #22667\n* maven/mavencentral/com.github.docker-java/docker-java/3.5.3, Apache-2.0, approved, #22666\n* maven/mavencentral/com.github.rodionmoiseev.c10n/c10n-core/1.2, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/com.google.code.gson/gson/2.9.0, Apache-2.0, approved, CQ24148\n* maven/mavencentral/com.google.guava/guava/32.1.1-jre, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/com.google.guava/failureaccess/1.0.1, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/com.google.protobuf/protobuf-java/3.19.3, BSD-3-Clause, approved, clearlydefined\n* maven/mavencentral/com.h2database/h2/2.4.240, EPL-1.0 AND MPL-2.0 AND LGPL-2.1-or-later AND BSD-3-Clause AND LicenseRef-Public-Domain, approved, #23567\n* maven/mavencentral/com.sun.xml.bind/jaxb-osgi/2.3.3, BSD-3-Clause, approved, ee4j.jaxb-impl\n* maven/mavencentral/com.vertispan.j2cl.external/org.eclipse.core.jobs/0.10.0-3c97afeac, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/com.vertispan.j2cl.external/org.eclipse.equinox.preferences/0.10.0-3c97afeac, EPL-2.0, approved, #7856\n* maven/mavencentral/commons-codec/commons-codec/1.16.1, Apache-2.0 AND (Apache-2.0 AND BSD-3-Clause), approved, #9157\n* maven/mavencentral/org.apache.commons/commons-fileupload2-core/2.0.0-M2, Apache-2.0, approved, #15738\n* maven/mavencentral/org.apache.commons/commons-fileupload2-jakarta-servlet5/2.0.0-M2, Apache-2.0, approved, #15737\n* maven/mavencentral/commons-io/commons-io/2.19.0, Apache-2.0, approved, #20657\n* maven/mavencentral/commons-net/commons-net/3.8.0, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/io.netty/netty-all/4.1.130.Final, Apache-2.0 AND MIT AND BSD-3-Clause AND CC0-1.0 AND LicenseRef-Public-Domain, approved, CQ22582\n* maven/mavencentral/io.netty/netty-buffer/4.1.130.Final, Apache-2.0, approved, CQ21842\n* maven/mavencentral/io.netty/netty-codec-http/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.netty/netty-codec-mqtt/4.1.130.Final, Apache-2.0 OR LicenseRef-Public-Domain OR BSD-2-Clause OR MIT, approved, CQ15280\n* maven/mavencentral/io.netty/netty-codec/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.netty/netty-common/4.1.130.Final, Apache-2.0 AND MIT AND CC0-1.0, approved, CQ21843\n* maven/mavencentral/io.netty/netty-handler/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.netty/netty-resolver/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.netty/netty-transport-classes-epoll/4.1.130.Final, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/io.netty/netty-transport-classes-kqueue/4.1.130.Final, Apache-2.0, approved, #4107\n* maven/mavencentral/io.netty/netty-transport-native-epoll/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.netty/netty-transport-native-kqueue/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.netty/netty-transport-native-unix-common/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.netty/netty-transport/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.netty/netty-codec-socks/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.netty/netty-handler-proxy/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926\n* maven/mavencentral/io.perfmark/perfmark-api/0.26.0, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/jakarta.activation/jakarta.activation-api/1.2.2, EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jaf\n* maven/mavencentral/jakarta.xml.bind/jakarta.xml.bind-api/2.3.3, BSD-3-Clause, approved, ee4j.jaxb\n* maven/mavencentral/jakarta.xml.soap/jakarta.xml.soap-api/1.4.2, , approved, eclipse\n* maven/mavencentral/jakarta.xml.ws/jakarta.xml.ws-api/2.3.3, , approved, eclipse\n* maven/mavencentral/net.java.dev.jna/jna/5.8.0, Apache-2.0 OR LGPL-2.1-or-later, approved, CQ23217\n* maven/mavencentral/org.apache.camel/camel-amqp/2.25.3, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.camel/camel-core-osgi/2.25.3, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.camel/camel-core/2.25.3, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.camel/camel-jms/2.25.3, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.camel/camel-script/2.25.3, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.camel/camel-stream/2.25.3, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.commons/commons-compress/1.27.1, Apache-2.0 AND (Apache-2.0 AND BSD-3-Clause), approved, #17651\n* maven/mavencentral/org.apache.commons/commons-csv/1.4, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.commons/commons-exec/1.3, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.commons/commons-lang3/3.19.0, Apache-2.0, approved, #23560\n* maven/mavencentral/org.apache.felix/org.apache.felix.dependencymanager/3.0.0, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.felix/org.apache.felix.deploymentadmin/0.9.5, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.geronimo.specs/geronimo-jms_2.0_spec/1.0-alpha-2, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.httpcomponents.core5/httpcore5-h2/5.3.4, Apache-2.0, approved, #16867\n* maven/mavencentral/org.apache.httpcomponents.client5/httpclient5/5.0.3, Apache-2.0 and MIT, approved, CQ23948\n* maven/mavencentral/org.apache.httpcomponents.core5/httpcore5/5.0.2, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.logging.log4j/log4j-api/2.25.3, Apache-2.0, approved, #21940\n* maven/mavencentral/org.apache.logging.log4j/log4j-core/2.25.3, Apache-2.0 AND (Apache-2.0 AND LGPL-2.0-or-later), approved, #21939\n* maven/mavencentral/org.apache.logging.log4j/log4j-slf4j2-impl/2.25.3, Apache-2.0, approved, #21938\n* maven/mavencentral/org.apache.qpid/proton-j/0.33.2, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.qpid/qpid-jms-client/0.45.0, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-beans/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16239\n* maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-context/4.3.20.RELEASE_1, , approved, CQ16240\n* maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-core/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16241\n* maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-expression/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16242\n* maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-jms/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16243\n* maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-tx/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16244\n* maven/mavencentral/org.bouncycastle/bcpg-jdk18on/1.78.1, Apache-2.0, approved, #14432\n* maven/mavencentral/org.bouncycastle/bcpkix-jdk18on/1.78.1, MIT, approved, #14434\n* maven/mavencentral/org.bouncycastle/bcprov-jdk18on/1.78.1, MIT AND CC0-1.0, approved, #14433\n* maven/mavencentral/org.bouncycastle/bctls-jdk18on/1.78.1, MIT, approved, #14676\n* maven/mavencentral/org.bouncycastle/bcutil-jdk18on/1.78.1, MIT, approved, #14435\n* maven/mavencentral/org.eclipse.milo/sdk-client/0.6.8, EPL-2.0, approved, iot.milo\n* maven/mavencentral/org.eclipse.milo/sdk-core/0.6.8, EPL-2.0, approved, iot.milo\n* maven/mavencentral/org.eclipse.milo/stack-client/0.6.8, EPL-2.0, approved, iot.milo\n* maven/mavencentral/org.eclipse.milo/stack-core/0.6.8, EPL-2.0, approved, iot.milo\n* maven/mavencentral/org.glassfish.hk2/osgi-resource-locator/1.0.3, CDDL-1.0, approved, CQ10889\n* maven/mavencentral/org.knowhowlab.osgi/monitoradmin/1.0.3, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.osgi/osgi.annotation/8.1.0, Apache-2.0, approved, #1985\n* maven/mavencentral/org.quartz-scheduler/quartz/2.5.0, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.slf4j/jcl-over-slf4j/2.0.17, MIT AND Apache-2.0, approved, #11889\n* maven/mavencentral/org.slf4j/slf4j-api/2.0.17, MIT, approved, #5915\n* maven/mavencentral/org.slf4j/jul-to-slf4j/2.0.17, MIT, approved, #7698\n* maven/mavencentral/org.usb4java/libusb4java/1.3.0, MIT, approved, #3087\n* maven/mavencentral/org.usb4java/usb4java-javax/1.3.0, MIT, approved, #22528\n* maven/mavencentral/org.usb4java/usb4java/1.3.0, MIT, approved, clearlydefined\n* maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.c3p0/0.9.5.5_1, Apache-2.0, approved, #3761\n* maven/mavencentral/com.zaxxer/HikariCP/2.7.9, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.xerial/sqlite-jdbc/3.42.0.0, Apache-2.0 AND BSD-2-Clause AND ISC AND Artistic-2.0, approved, #9089\n* maven/mavencentral/org.graalvm.js/js/21.3.9, UPL-1.0 AND (UPL-1.0 AND GPL-2.0-only WITH Classpath-exception-2.0) AND BSD-3-Clause AND MPL-2.0, approved, #6714\n* maven/mavencentral/org.graalvm.js/js-scriptengine/21.3.9, UPL-1.0, approved, #6715\n* maven/mavencentral/org.graalvm.js/js-launcher/21.3.9, UPL-1.0, approved, #6716\n* maven/mavencentral/org.graalvm.sdk/graal-sdk/21.3.9, UPL-1.0, approved, #6717\n* maven/mavencentral/org.graalvm.truffle/truffle-api/21.3.9, UPL-1.0, approved, #6718\n* maven/mavencentral/org.graalvm.regex/regex/21.3.9, UPL-1.0 AND Unicode-TOU, approved, #6719\n* maven/mavencentral/org.graalvm.sdk/launcher-common/21.3.9, UPL-1.0, approved, #6720\n* maven/mavencentral/com.ibm.icu/icu4j/72.1, ICU, approved, #4354\n* maven/mavencentral/com.github.hypfvieh/dbus-java/3.3.2, MIT, approved, CQ23190\n* maven/mavencentral/com.github.jnr/jffi/1.3.9, Apache-2.0 OR LGPL-3.0-or-later, approved, CQ23196\n* maven/mavencentral/com.github.jnr/jnr-a64asm/1.0.0, Apache-2.0, approved, CQ22814\n* maven/mavencentral/com.github.jnr/jnr-constants/0.10.3, Apache-2.0, approved, CQ23193\n* maven/mavencentral/com.github.jnr/jnr-enxio/0.32.13, Apache-2.0, approved, CQ23194\n* maven/mavencentral/com.github.jnr/jnr-ffi/2.2.11, Apache-2.0, approved, CQ23192\n* maven/mavencentral/com.github.jnr/jnr-posix/3.1.15, EPL-2.0 OR GPL-2.0-only OR LGPL-2.1-only, approved, #2711\n* maven/mavencentral/com.github.jnr/jnr-unixsocket/0.38.17, Apache-2.0, approved, CQ23191\n* maven/mavencentral/com.github.jnr/jnr-x86asm/1.0.2, MIT, approved, CQ9094\n* maven/mavencentral/org.ow2.asm/asm-analysis/9.2, BSD-3-Clause, approved, clearlydefined\n* maven/mavencentral/org.ow2.asm/asm-commons/9.2, BSD-3-Clause, approved, clearlydefined\n* maven/mavencentral/org.ow2.asm/asm-tree/9.2, BSD-3-Clause, approved, clearlydefined\n* maven/mavencentral/org.ow2.asm/asm-util/9.2, BSD-3-Clause, approved, clearlydefined\n* maven/mavencentral/org.ow2.asm/asm/9.2, BSD-3-Clause, approved, CQ23635\n* maven/mavencentral/com.google.guava/guava/31.0-jre, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/com.google.guava/failureaccess/1.0, Apache-2.0, approved, CQ22654\n* maven/mavencentral/com.digitalpetri.fsm/strict-machine/0.6, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/com.digitalpetri.netty/netty-channel-fsm/0.8, Apache-2.0, approved, #6168\n* maven/mavencentral/jakarta.annotation/jakarta.annotation-api/2.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.ca\n* maven/mavencentral/org.apache.felix/org.apache.felix.http.servlet-api/3.0.0, Apache-2.0, approved, #13345\n* maven/mavencentral/org.apache.felix/org.apache.felix.http.bridge/5.1.8, Apache-2.0, approved, #18536\n* maven/mavencentral/org.apache.felix/org.apache.felix.http.proxy/4.0.0, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.apache.felix/org.apache.felix.http.wrappers/1.1.2, Apache-2.0, approved, clearlydefined\n* maven/mavencentral/org.eclipse.jetty/jetty-http/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty\n* maven/mavencentral/org.eclipse.jetty/jetty-security/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty\n* maven/mavencentral/org.eclipse.jetty/jetty-server/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty\n* maven/mavencentral/org.eclipse.jetty/jetty-session/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty\n* maven/mavencentral/org.eclipse.jetty/jetty-util/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty\n* maven/mavencentral/org.eclipse.jetty/jetty-io/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty\n* maven/mavencentral/org.eclipse.jetty.ee10/jetty-ee10-servlet/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty\n* maven/mavencentral/org.osgi/org.osgi.service.http.whiteboard/1.1.1, Apache-2.0, approved, #5518\n* maven/mavencentral/org.osgi/org.osgi.service.servlet/2.0.0, Apache-2.0, approved, #5264\n* maven/mavencentral/jakarta.ws.rs/jakarta.ws.rs-api/3.1.0, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.rest\n* maven/mavencentral/org.osgi/org.osgi.service.jakartars/2.0.0, Apache-2.0, approved, #4692\n* maven/mavencentral/org.eclipse.osgi-technology.rest/org.eclipse.osgitech.rest/1.2.3, Apache-2.0, approved, technology.osgi-technology\n* maven/mavencentral/org.eclipse.osgi-technology.rest/org.eclipse.osgitech.rest.sse/1.2.3, Apache-2.0, approved, technology.osgi-technology\n* maven/mavencentral/org.eclipse.osgi-technology.rest/org.eclipse.osgitech.rest.servlet.whiteboard/1.2.3, Apache-2.0, approved, technology.osgi-technology\n* maven/mavencentral/org.apache.aries.spifly/org.apache.aries.spifly.dynamic.bundle/1.3.7, Apache-2.0, approved, #15243\n* maven/mavencentral/org.ow2.asm/asm/9.7.1, BSD-3-Clause, approved, #16464\n* maven/mavencentral/org.ow2.asm/asm-commons/9.7.1, BSD-3-Clause, approved, #16465\n* maven/mavencentral/org.ow2.asm/asm-tree/9.7.1, BSD-3-Clause, approved, #16466\n* maven/mavencentral/org.ow2.asm/asm-util/9.7.1, BSD-3-Clause, approved, #16467\n* maven/mavencentral/org.ow2.asm/asm-analysis/9.7.1, BSD-3-Clause, approved, #16463\n* maven/mavencentral/org.glassfish.hk2/hk2-api/3.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish\n* maven/mavencentral/org.glassfish.hk2.external/aopalliance-repackaged/3.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish\n* maven/mavencentral/org.glassfish.hk2/hk2-locator/3.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish\n* maven/mavencentral/org.glassfish.hk2/hk2-utils/3.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish\n* maven/mavencentral/org.glassfish.jersey.inject/jersey-hk2/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/org.glassfish.jersey.containers/jersey-container-servlet/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/org.glassfish.jersey.containers/jersey-container-servlet-core/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/org.glassfish.jersey.core/jersey-client/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/org.glassfish.jersey.core/jersey-common/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/org.glassfish.jersey.core/jersey-server/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/org.glassfish.jersey.ext/jersey-entity-filtering/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/org.glassfish.jersey.media/jersey-media-jaxb/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/org.glassfish.jersey.media/jersey-media-sse/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/org.glassfish.jersey.media/jersey-media-multipart/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey\n* maven/mavencentral/jakarta.inject/jakarta.inject-api/2.0.1, Apache-2.0, approved, ee4j.cdi\n* maven/mavencentral/jakarta.validation/jakarta.validation-api/3.0.2, Apache-2.0, approved, ee4j.validation\n* maven/mavencentral/org.javassist/javassist/3.30.2-GA, Apache-2.0 AND LGPL-2.1-or-later AND MPL-1.1, approved, #12108\n* maven/mavencentral/org.jvnet.mimepull/mimepull/1.10.0, BSD-3-Clause, approved, #2699\n* maven/mavencentral/org.apache.felix/org.apache.felix.gogo.command/1.1.2, Apache-2.0, approved, #17675\n* maven/mavencentral/org.apache.felix/org.apache.felix.gogo.runtime/1.1.6, Apache-2.0 AND MIT, approved, CQ22929\n* maven/mavencentral/org.apache.felix/org.apache.felix.scr/2.2.12, Apache-2.0, approved, #15367\n* maven/mavencentral/org.eclipse.platform/org.eclipse.core.contenttype/3.9.500, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.core.jobs/3.15.400, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.core.runtime/3.31.100, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.app/1.7.200, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.cm/1.6.100, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.common/3.19.100, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.console/1.4.800, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.event/1.7.100, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.io/1.1.300, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.launcher/1.6.900, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.metatype/1.6.600, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.preferences/3.11.100, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.registry/3.12.100, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.util/1.1.300, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.wireadmin/1.0.800, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.osgi.util/3.7.300, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.eclipse.platform/org.eclipse.osgi/3.21.0, EPL-2.0, approved, eclipse.platform\n* maven/mavencentral/org.osgi/org.osgi.service.cm/1.6.1, Apache-2.0, approved, #18262\n* maven/mavencentral/org.osgi/org.osgi.service.component/1.5.1, Apache-2.0, approved, #5389\n* maven/mavencentral/org.osgi/org.osgi.service.coordinator/1.0.2, Apache-1.1 AND Apache-2.0, approved, #17662\n* maven/mavencentral/org.osgi/org.osgi.service.device/1.1.1, Apache-2.0, approved, #15335\n* maven/mavencentral/org.osgi/org.osgi.service.event/1.4.1, Apache-2.0, approved, #15500\n* maven/mavencentral/org.osgi/org.osgi.service.log.stream/1.0.0, Apache-2.0, approved, #2442\n* maven/mavencentral/org.osgi/org.osgi.service.metatype/1.4.1, Apache-2.0, approved, #15382\n* maven/mavencentral/org.osgi/org.osgi.service.prefs/1.1.2, Apache-2.0, approved, #15379\n* maven/mavencentral/org.osgi/org.osgi.service.provisioning/1.2.0, Apache-1.1 AND Apache-2.0, approved, #17681\n* maven/mavencentral/org.osgi/org.osgi.service.upnp/1.2.1, Apache-2.0, approved, #15268\n* maven/mavencentral/org.osgi/org.osgi.service.useradmin/1.1.1, Apache-2.0, approved, #15323\n* maven/mavencentral/org.osgi/org.osgi.service.wireadmin/1.0.2, Apache-2.0, approved, #15398\n* maven/mavencentral/org.osgi/org.osgi.util.function/1.2.0, Apache-2.0, approved, #15222\n* maven/mavencentral/org.osgi/org.osgi.util.measurement/1.0.2, Apache-2.0, approved, #17679\n* maven/mavencentral/org.osgi/org.osgi.util.position/1.0.1, Apache-1.1 AND Apache-2.0, approved, #17683\n* maven/mavencentral/org.osgi/org.osgi.util.promise/1.3.0, Apache-2.0, approved, #5266\n* maven/mavencentral/org.osgi/org.osgi.util.pushstream/1.1.0, Apache-2.0, approved, #6026\n* maven/mavencentral/org.osgi/org.osgi.util.xml/1.0.2, Apache-2.0, approved, #15377\n* maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.19.2, Apache-2.0, approved, #21909\n* maven/mavencentral/com.fasterxml.jackson.core/jackson-annotations/2.19.2, Apache-2.0, approved, #21911\n* maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.19.2, Apache-2.0 AND MIT, approved, #21916\n\n### Additional Dependencies\n\n* maven/mavencentral/javax.usb/usb-api/1.0.2, MIT, approved, CQ7834\n* javax.el_2.2.0.v201303151357, EPL-2.0, approved, eclipse.platform\n* org.tigris.mtoolkit.iagent.rpc_3.0.0.20110411-0918, EPL-1.0, approved, CQ7880\n* com.codeminders.hidapi natives 1.1, New BSD License, approved, CQ7871\n* soda.dk.comm, EPL-1.0, approved, CQ8156\n* org.hamcrest.core 1.1, New BSD License, approved, CQ7842\n* org.apache.felix.useradmin_1.0.4.k1, Apache-2.0, approved, CQ23078\n* com.codeminders.hidapi 1.1, New BSD License, approved, CQ7833\n* org.moka7 1.0.2, EPL-1.0, approved, CQ12777\n* org.eclipse.paho.client.mqttv3 1.2.1.k2, EPL-1.0, approved, eclipse.platform\n\n## Cryptography\n\nContent may contain encryption software. The country in which you are currently\nmay have restrictions on the import, possession, and use, and/or re-export to\nanother country, of encryption software. BEFORE using any encryption software,\nplease check the country's laws, regulations and policies concerning the import,\npossession, or use, and re-export of encryption software, to see if this is\npermitted.\n"
  },
  {
    "path": "PULL_REQUEST_TEMPLATE.md",
    "content": "> **Note**: We are using the Conventional Commits convention for our pull request titles. Please take a look at the [PR title format document](https://github.com/eclipse/kura/blob/develop/CONTRIBUTING.md#submitting-the-changes) for the supported [types](https://github.com/eclipse/kura/blob/develop/CONTRIBUTING.md#type) and [scopes](https://github.com/eclipse/kura/blob/develop/CONTRIBUTING.md#scope).\n\nBrief description of the PR. [e.g. Added `null` check on `object` to avoid `NullPointerException`]\n\n**Related Issue:** This PR fixes/closes {issue number}\n\n**Description of the solution adopted:** A more detailed description of the changes made to solve/close one or more issues. If the PR is simple and easy to understand this section can be skipped\n\n**Screenshots:** If applicable, add screenshots to help explain your solution\n\n**Manual Tests**: Optional description of the tests performed to check correct functioning of changes, useful for an efficient review\n\n**Any side note on the changes made:** Description of any other change that has been made, which is not directly linked to the issue resolution [e.g. Code clean up/Sonar issue resolution]\n"
  },
  {
    "path": "README.md",
    "content": "Eclipse Kura™\n=============\n\n<p align=\"center\">\n<img src=\"https://eclipse.dev/kura/images/kura.png\" alt=\"Kura™ logo\" width=\"500\"/>\n</p>\n\n<div align=\"center\">\n\n[![GitHub](https://img.shields.io/github/license/eclipse/kura?label=License)](https://github.com/eclipse-kura/kura/blob/develop/LICENSE)\n[![Jenkins](https://img.shields.io/jenkins/build?jobUrl=https:%2F%2Fci.eclipse.org%2Fkura%2Fjob%2Fmultibranch%2Fjob%2Fdevelop&label=Jenkins%20Build&logo=jenkins)](https://ci.eclipse.org/kura/job/multibranch/job/develop/)\n[![Jenkins](https://img.shields.io/jenkins/tests?compact_message&failed_label=%E2%9D%8C&jobUrl=https:%2F%2Fci.eclipse.org%2Fkura%2Fjob%2Fmultibranch%2Fjob%2Fdevelop%2F&label=Jenkins%20CI&passed_label=%E2%9C%85&skipped_label=%E2%9D%95&logo=jenkins)](https://ci.eclipse.org/kura/job/multibranch/) <br/>\n  \n</div>\n\n## What is Eclipse Kura™?\nFrom [the maori word for tank/container](https://maoridictionary.co.nz/search/?keywords=kura), Eclipse Kura™ is a versatile software framework designed to supercharge your edge devices. With an intuitive web interface, Eclipse Kura™ streamlines the process of configuring your gateway, connecting sensors, and IoT devices to seamlessly collect, process, and send data to the cloud. Eclipse Kura™ provides an extensible Java API for developing custom plugins within the framework. Additionally, it offers a REST API, enabling the use of Eclipse Kura™ as a backend service in your application.\n \nEclipse Kura™ runs on an edge gateway, which can be anything from a small SBC(single-board computer) like a Raspberry Pi, or a powerful high-performance computer.\n\n### What can Eclipse Kura™ do for me?\n* **Kura™ Services:** Provision and set up features to run on your gateway, such as an MQTT broker.\n* **Kura™ Networking:** Manage Network connectivity, including \n* **Kura™ Wires:** Design data flows and data processing streams effortlessly with a drag-and-drop visual editor.\n* **Kura™ Cloud Connectors:** Extendable cloud connector system. \n* **Kura™ Drivers:** Extendable service that handles reading data off of external devices.\n* **Kura™ Snapshots:** Securely store and re-apply gateway settings for convenience.\n* **Kura™ Security**: Easily and safely store your secrets.\n* **Kura™ Container Orchestrator**: Manage Docker or Podman containers on your gateway for ultimate flexibility.\n* **Kura™ AI Inference**: Run Nvidia Triton Models on the edge.\n* **Kura™ Plugins**: Add and Extend the framework by adding your own Services, and Drivers.\n* **Kura™ REST Service**: Embed the framework as a backend in your own edge applications.\n \n### I have used Eclipse Kura™ to make a small-scale Edge deployment, how do I scale now?\nIf you want to scale, and manage many instances of Eclipse Kura™, check out [**Eclipse Kapua™**](https://github.com/eclipse/kapua). [Eclipse Kapua™](https://github.com/eclipse/kapua) is a Eclipse Kura™ compatible cloud command and control service that allows you to aggregate data and configure many Eclipse Kura™ devices. \n\nDocumentation\n-------------------\n\n- [**User Documentation**](https://eclipse-kura.github.io/kura/latest/): here you'll find information on how to **use** Eclipse Kura™ i.e. installation instructions, informations on how to use the web UI and tutorials.\n- [**Developer Documentation**](https://github.com/eclipse-kura/kura/wiki): the Eclipse Kura™ Github Wiki serves as a reference for **developers** who want to contribute to the Eclipse Kura™ project and/or develop new add-ons. Here you'll find Eclipse Kura™ development/release model, guidelines on how to import internal packages, creating new bundles and development environment tips & tricks.\n- [**Docker Containers Documentation**](https://hub.docker.com/r/eclipsekura/kura/): the Eclipse Kura™ team also provides Docker containers for the project. Information on how to build and run them are available at https://github.com/eclipse-kura/kura-metapackage.\n- [**Developer Quickstart Guide**](https://github.com/eclipse-kura/kura#build): a quick guide on how to setup the development environment and build the project is also provided in this README.\n\nAdditionally, we provide two channels for reporting any issue you find with the project\n- [**Github Issues**](https://github.com/eclipse-kura/kura/issues): for bug reporting.\n- [**Github Discussions**](https://github.com/eclipse-kura/kura/discussions): for receiving feedback, asking questions, making new proposals and generally talking about the project.\n\nInstall\n-------\n\nEclipse Kura™ is compatible with Java 21.\n\n### Quick Linux installation\n\nThe APT repository provides packages for both **x86‑64** and **arm64** architectures.\nTo install the latest stable version of **Eclipse Kura™**, run the following commands in a terminal:\n\n```bash\n# Install required tools\nsudo apt update\nsudo apt install -y curl gpg\n\n# Add the Eclipse Kura APT repository key\ncurl -fsSL \"https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xBA7E3DF5EDC3FC36\" \\\n  | gpg --dearmor \\\n  | sudo tee /etc/apt/keyrings/kura.gpg > /dev/null\n\n# Add the Eclipse Kura APT repository\nsudo tee /etc/apt/sources.list.d/kura.sources > /dev/null << 'EOF'\nTypes: deb\nURIs: https://repo.eclipse.org/repository/kura-apt/\nSuites: stable\nComponents: main\nSigned-By: /etc/apt/keyrings/kura.gpg\nEOF\n\n# Update package index and install Eclipse Kura\nsudo apt update\nsudo apt install -y kura\n```\n> **Note:** You may need `sudo` privileges to run these commands.\n\n### Target Gateways Installers\nEclipse Kura™ provides pre-built installers for common development boards. Check the following [link](https://www.eclipse.org/kura/downloads.php) to download the desired installers.\nTake a look at [our documentation](https://eclipse-kura.github.io/kura/latest/getting-started/install-kura/) for further information on supported platforms and installer types.\n\n### Docker Image\nEclipse Kura™ is also available as a [Docker container](https://hub.docker.com/r/eclipsekura/kura/).\n\nBuild\n-----\n\n### Prerequisites\n\nIn order to be able to build Eclipse Kura™ on your development machine, you need to have the following programs installed in your system:\n* JDK 21\n* Maven 3.9.9+\n\n<details>\n<summary>\n\n#### Installing Prerequisites in Mac OS \n\n</summary>\n\nTo install Java 21, download the JDK tar archive from the [Adoptium Project Repository](https://adoptium.net/temurin/releases?version=21&os=any&arch=any).\n\nOnce downloaded, copy the tar archive in `/Library/Java/JavaVirtualMachines/` and `cd` into it. Unpack the archive with the following command:\n\n```bash\nsudo tar -xzf <archive-name>.tar.gz\n```\n\nThe tar archive can be deleted afterwards.\n\nDepending on which terminal you are using, edit the profiles (`.zshrc`, `.profile`, `.bash_profile`) to contain:\n\n```bash\nexport JAVA_HOME=/Library/Java/JavaVirtualMachines/<archive-name>/Contents/Home\n```\n\nReload the terminal and run `java -version` to make sure it is installed correctly.\n\nUsing [Brew](https://brew.sh/) you can easily install Maven from the command line:\n\n```bash\nbrew install maven@3.9\n```\n\nRun `mvn -version` to ensure that Maven has been added to the PATH. If Maven cannot be found, try running `brew link maven@3.9 --force` or manually add it to your path with:\n\n```bash\nexport PATH=\"/usr/local/opt/maven@3.9/bin:$PATH\"\n```\n\n</details>\n\n<details>\n<summary>\n\n#### Installing Prerequisites in Linux\n\n</summary>\n\nFor Java\n\n```bash\nsudo apt install openjdk-21-jdk\n```\n\nTo install Maven you can follow the tutorial from the official [Maven](http://maven.apache.org/install.html) site. Remember that you need to install the 3.9.9 version.\n\n</details>\n\n### Build Eclipse Kura™\n\nChange to the new directory and clone the Eclipse Kura™ repo:\n\n```bash\ngit clone -b develop https://github.com/eclipse-kura/kura.git\n```\n\nMove inside the newly created directory and build the target platform:\n\n```bash\nmvn -f target-platform/pom.xml clean install\n```\n\nBuild the core components:\n\n```bash\nmvn -f kura/pom.xml clean install\n```\n\nBuild the target profiles and the Eclipse Kura Target Definition:\n\n```bash\nmvn -f kura/distrib/pom.xml clean install -DbuildAll\n```\n\n> [!TIP]\nYou can skip tests by adding `-Dmaven.test.skip=true` in the commands above and you can compile a specific target by specifying the profile (e.g. `-Paarch64`).\n\nTo list the available installer profiles, run:\n\n```bash\nmvn -f kura/distrib/pom.xml help:all-profiles\n```\n\nAdditionally you can build only the Eclipse Kura Target Definition, by running in the `distrib` folder:\n\n```bash\nmvn -f kura/distrib/pom.xml clean install -Ptarget-definition\n```\n\n#### Build scripts\n\nAlternatively, you can use the build scripts available in the root directory.\n\n```bash\n./build-all.sh\n```\n\nIDE Setups\n----------\n\nWe currently support two setups for Eclipse Kura™ development:\n\n- [**Eclipse Kura™ Development Environment Setup**](https://eclipse-kura.github.io/kura/latest/java-application-development/development-environment-setup/): This is the full setup allowing you to contribute to the core Eclipse Kura™ project codebase. It will install all the IDE plugins and formatters to have a pleasant development experience and clone the Eclipse Kura™ source code on your workstation.\n- [**Kura Addon Archetype**](https://eclipse-kura.github.io/kura/docs-develop/java-application-development/kura-addon-archetype/): The Kura Addon Archetype will allow you to develop applications or bundles running on Eclipse Kura™. It will install only the APIs and is best suited for developing Eclipse Kura™ add-ons.\n\nContributing\n------------\n\nContributing to Eclipse Kura™ is fun and easy! To start contributing you can follow our guide [here](CONTRIBUTING.md).\n\n### Acknowledgments\n\n![YourKit Logo](https://www.yourkit.com/images/yklogo.png)\n\nThanks to YourKit for providing us an open source license of YourKit Java Profiler!\n\nYourKit supports open source projects with innovative and intelligent tools\nfor monitoring and profiling Java and .NET applications.\nYourKit is the creator of [YourKit Java Profiler](https://www.yourkit.com/java/profiler/),\n[YourKit .NET Profiler](https://www.yourkit.com/.net/profiler/),\nand [YourKit YouMonitor](https://www.yourkit.com/youmonitor/).\n"
  },
  {
    "path": "SECURITY.md",
    "content": "# Security Policy\n\nThis project implements the Eclipse Foundation Security Policy\n\n* https://www.eclipse.org/security\n\n## Supported Versions\n\nThe Eclipse Kura project provides security updates for the last two major releases.\nThe fixes are applied to the latest minor release available for the given major and will produce a new service release.\n\n| Version | Last Release | Supported          | \n| ------- | ------------ | ------------------ | \n| 5.6.x   | 2025-12-09   | :white_check_mark: |\n| 5.5.x   | 2024-07-08   | :x:                |\n| 5.4.x   | 2023-11-30   | :x:                |\n| 5.3.x   | 2023-07-07   | :x:                |\n| 5.2.x   | 2023-05-12   | :x:                |\n| 5.1.x   | 2022-06-30   | :x:                | \n| 5.0.x   | 2021-12-22   | :x:                | \n| 4.1.x   | 2021-12-22   | :white_check_mark: | \n| < 4.0.0 | 2018-10-19   | :x:                | \n\n## Reporting a Vulnerability\n\nIf you think you have found a vulnerability in Eclipse Kura you can report it using one of the following ways:\n\n* [Report a Vulnerability](https://github.com/eclipse-kura/kura/security/advisories/new)\n* Contact the [Eclipse Foundation Security Team](mailto:security@eclipse-foundation.org)\n\nYou can find more information about reporting and disclosure at the [Eclipse Foundation Security page](https://www.eclipse.org/security/).\n"
  },
  {
    "path": "build-all.sh",
    "content": "#!/usr/bin/env bash\n\n#\n#  Copyright (c) 2016, 2026 Red Hat and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#     Red Hat\n#     Eurotech\n#\n\n# activate batch mode by default\n\nMAVEN_PROPS=\"-B\"\n\n# allow running tests\n\n[ -z \"$RUN_TESTS\" ] && MAVEN_PROPS=\"$MAVEN_PROPS -Dmaven.test.skip=true\"\n\nmvn \"$@\" --color=always -f target-platform/pom.xml clean install $MAVEN_PROPS &&\nmvn \"$@\" --color=always -f kura/pom.xml clean install $MAVEN_PROPS &&\nmvn \"$@\" --color=always -f kura/distrib/pom.xml clean install $MAVEN_PROPS\n\n"
  },
  {
    "path": "checkstyle_checks.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\" \"http://www.puppycrawl.com/dtds/configuration_1_3.dtd\">\n<module name=\"Checker\">\n    <!--\n      If you set the basedir property below, then all reported file\n      names will be relative to the specified directory. See\n      http://checkstyle.sourceforge.net/config.html#Checker\n\n      <property name=\"basedir\" value=\"${basedir}\"/>\n  -->\n    <property name=\"severity\" value=\"error\"/>\n    <!-- Filters -->\n    <module name=\"SeverityMatchFilter\">\n        <!-- report all violations except ignore -->\n        <property name=\"severity\" value=\"ignore\"/>\n        <property name=\"acceptOnMatch\" value=\"false\"/>\n    </module>\n    <module name=\"RegexpMultiline\">\n        <property name=\"format\" value=\"(?s:\\r\\n.*)\"/>\n        <property name=\"fileExtensions\" value=\"java\"/>\n        <property name=\"message\" value=\"Do not use Windows line endings\"/>\n    </module>\n\n    <!-- Checks whether files end with a new line.                        -->\n    <!-- See https://checkstyle.org/config_misc.html#NewlineAtEndOfFile -->\n    <!--<module name=\"NewlineAtEndOfFile\"/>-->\n\n    <!-- Checks that property files contain the same keys.         -->\n    <!-- See https://checkstyle.org/config_misc.html#Translation -->\n    <module name=\"Translation\"/>\n\n    <!-- Checks for Size Violations.                    -->\n    <!-- See https://checkstyle.org/config_sizes.html -->\n    <module name=\"FileLength\"/>\n\n    <!-- Checks for whitespace                               -->\n    <!-- See https://checkstyle.org/config_whitespace.html -->\n    <module name=\"FileTabCharacter\"/>\n\n    <!-- Miscellaneous other checks.                   -->\n    <!-- See https://checkstyle.org/config_misc.html -->\n    <module name=\"RegexpSingleline\">\n        <property name=\"format\" value=\"\\*\\s\\s+$\"/>\n        <property name=\"minimum\" value=\"0\"/>\n        <property name=\"maximum\" value=\"0\"/>\n        <property name=\"message\" value=\"Line has trailing spaces.\"/>\n    </module>\n\n    <!-- Checks for Headers                                -->\n    <!-- See https://checkstyle.org/config_header.html   -->\n    <!-- <module name=\"RegexpHeader\"> -->\n    <!--     <property name=\"headerFile\" value=\"header.txt\"/> -->\n    <!--     <property name=\"fileExtensions\" value=\"java\"/> -->\n    <!-- </module> -->\n\n    <module name=\"SuppressWarningsFilter\"/>\n\n    <module name=\"TreeWalker\">\n        <module name=\"SuppressWarningsHolder\" />\n\n        <!-- Checks for Javadoc comments.                     -->\n        <!-- See https://checkstyle.org/config_javadoc.html -->\n        <!--<module name=\"InvalidJavadocPosition\"/>\n        <module name=\"JavadocMethod\"/>\n        <module name=\"JavadocType\"/>\n        <module name=\"JavadocVariable\"/>\n        <module name=\"JavadocStyle\"/>\n        <module name=\"MissingJavadocMethod\"/>\n        -->\n        <!-- Checks for Naming Conventions.                  -->\n        <!-- See https://checkstyle.org/config_naming.html -->\n        <module name=\"ConstantName\">\n            <property name=\"format\" value=\"^auditLogger|log(ger)?|[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$\"/>\n        </module>\n        <module name=\"LocalFinalVariableName\"/>\n        <module name=\"LocalVariableName\"/>\n        <module name=\"MemberName\"/>\n        <module name=\"MethodName\"/>\n        <module name=\"PackageName\"/>\n        <module name=\"ParameterName\"/>\n        <module name=\"StaticVariableName\"/>\n        <module name=\"TypeName\"/>\n\n        <!-- Checks for imports                              -->\n        <!-- See https://checkstyle.org/config_import.html -->\n        <module name=\"AvoidStarImport\"/>\n        <module name=\"IllegalImport\"/>\n        <!-- defaults to sun.* packages -->\n        <module name=\"RedundantImport\"/>\n        <module name=\"UnusedImports\">\n            <property name=\"processJavadoc\" value=\"false\"/>\n        </module>\n\n        <!-- Checks for Size Violations.                    -->\n        <!-- See https://checkstyle.org/config_sizes.html -->\n        <module name=\"LineLength\">\n            <property name=\"max\" value=\"150\"/>\n        </module>\n        <module name=\"MethodLength\"/>\n        <module name=\"ParameterNumber\"/>\n\n        <!-- Checks for whitespace                               -->\n        <!-- See https://checkstyle.org/config_whitespace.html -->\n        <module name=\"EmptyForIteratorPad\"/>\n        <module name=\"GenericWhitespace\"/>\n        <module name=\"MethodParamPad\"/>\n        <module name=\"NoWhitespaceAfter\">\n            <property name=\"tokens\" value=\"INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR\"/>\n        </module>\n        <module name=\"NoWhitespaceBefore\"/>\n        <module name=\"OperatorWrap\"/>\n        <module name=\"ParenPad\"/>\n        <module name=\"TypecastParenPad\"/>\n        <module name=\"WhitespaceAfter\"/>\n        <module name=\"WhitespaceAround\"/>\n\n        <!-- Modifier Checks                                    -->\n        <!-- See https://checkstyle.org/config_modifiers.html -->\n        <module name=\"ModifierOrder\"/>\n        <!--<module name=\"RedundantModifier\"/>-->\n\n        <!-- Checks for blocks. You know, those {}'s         -->\n        <!-- See https://checkstyle.org/config_blocks.html -->\n        <module name=\"AvoidNestedBlocks\"/>\n        <module name=\"EmptyBlock\"/>\n        <module name=\"LeftCurly\"/>\n        <module name=\"NeedBraces\"/>\n        <module name=\"RightCurly\"/>\n\n        <!-- Checks for common coding problems               -->\n        <!-- See https://checkstyle.org/config_coding.html -->\n        <module name=\"EmptyStatement\"/>\n        <module name=\"EqualsHashCode\"/>\n        <module name=\"HiddenField\" >\n            <property name=\"ignoreSetter\" value=\"true\" />\n            <property name=\"ignoreConstructorParameter\" value=\"true\" />\n            <property name=\"tokens\" value=\"VARIABLE_DEF\"/>\n        </module>\n        <module name=\"IllegalInstantiation\"/>\n        <module name=\"InnerAssignment\"/>\n        <!--\n        <module name=\"MagicNumber\"/>\n        -->\n        <module name=\"MissingSwitchDefault\"/>\n        <module name=\"MultipleVariableDeclarations\"/>\n        <module name=\"SimplifyBooleanExpression\"/>\n        <module name=\"SimplifyBooleanReturn\"/>\n\n        <!-- Checks for class design                         -->\n        <!-- See https://checkstyle.org/config_design.html -->\n        <!--<module name=\"DesignForExtension\"/>-->\n        <!--\n        <module name=\"FinalClass\"/>\n        -->\n        <module name=\"HideUtilityClassConstructor\"/>\n        <module name=\"InterfaceIsType\"/>\n        <module name=\"VisibilityModifier\">\n            <property name=\"packageAllowed\" value=\"true\" />\n            <property name=\"protectedAllowed\" value=\"true\" />\n        </module>\n\n        <!-- Miscellaneous other checks.                   -->\n        <!-- See https://checkstyle.org/config_misc.html -->\n        <module name=\"ArrayTypeStyle\"/>\n        <!--\n        <module name=\"FinalParameters\"/>\n        -->\n        <module name=\"TodoComment\"/>\n        <module name=\"UpperEll\"/>\n    </module>\n</module>\n"
  },
  {
    "path": "kura/distrib/.gitignore",
    "content": "build.properties\n!bin\nRELEASE_INFO\n"
  },
  {
    "path": "kura/distrib/RELEASE_NOTES.txt",
    "content": "Eclipse Kura - 4.1.1   - May 2020\n-------------------------------------------------------------------------\nDescription:\nEclipse Kura 4.1.1 is a service release to address various discovered bugs and functional issues.\n\n\nChanges:\n  * Enhancements\n    * Enhanced the modem support with Huawei MS2372, Zte ME3630, SimTech SIM7000 LTE NB-IOT, Quectel EG25\n\n  * Target Platform Updates\n    * Jetty 9.4.19.v20190610\n    * H2DB 1.4.199\n    * Paho 1.2.1.k2\n\n  * Bug fixes and cleanups\n    * Fixed modem reset issue when the value is configured to 0 (no reset)\n    * Fixed issue with multiple cloud connections\n    * Fixed issue with parsing of ip route command\n    * Fixed issue where assets with only write channels still can call driver.read() method\n    * Fixed issue with token bucket where a change of system type can inpact with the token bucket functionality\n    * Fixed issue where a change in system tyme could impact the Wires Timer\n    * Fixed issue with Asset channel restore functionality\n    * Fixed issue with DEPLOY-V2 failure message publishing\n    * Fixed issue with Paho overriding SSL settings\n    * Fixed issue in CanConnection service with multiple can interfaces\n    * Fixed issue with modem switching from data mode to command mode\n    * Fixed issues with modem reset\n\n\nCompatibility:\n  * Eclipse Kura v4.1.1 does not introduce API breakage with previous releases.\n  * Kura 4.1.1 introduces H2DB v.1.4.199 that requires to delete/upgrade the existing persisted database to be \n    compatible with this new version. Please refer to http://www.h2database.com/html/tutorial.html#upgrade_backup_restore\n\n\nTarget Environments:\n  * Kura is released as pre-compiled binary installers for the following platforms:\n    * Raspberry Pi 2/3 based on Raspbian\n    * Intel Up Squared board running Ubuntu 18  \n    * Intel Up Squared board running Centos 7 (Experimental)\n    * Rock960 ARM_64 running Ubuntu 16 (NN version only)\n  * Kura is also available as a pre-built Docker container \n\n\nBug Fixes :\n  * Fixed github issues:\n    * #2831: ModemMonitorServiceImpl should use monotonic clock\n    * #2828: Improve modem help section\n    * #2827: Entering wrong dial string and APN can cause a reset loop\n    * #2825: Kura 4.1.x SupportedUsbModems isAttached method can fail\n    * #2822: CommConnectionImpl constructor does not close the serial port on failure\n    * #2820: Modem reset can lead to SIM card not ready\n    * #2811: CanConnection service with multiple can interfaces\n    * #2809: Unescaped loop on modem reset failure\n    * #2800: Switching from data mode to command mode does not work in pppd chat script\n    * #2793: Paho 1.2.1 overrides Kura SSL configuration\n    * #2759: [DEPLOY-V2] Failure status reported by a verifier script is not published\n    * #2679: One of two CloudConnections sometimes fails to connect and never tries to reconnect\n    * #2639: Asset configuration reseted after uploading new channels\n    * #2626: Asset with only write channels still calls driver.read() method\n    * #2605: Wires Timer stop ticking if system time is set in the past\n    * #2581: [DataService] Use System.nanoTime for token bucket \n    * #2580: Setting modem reset timeout to 0 causes the modem to reset indefinitely\n    * #2540: Default gateway is not correctly parsed\n    * #2437: Add support for Huawei modem MS2372\n\n  * Merged no issue-related Pull Requests:\n    * #2805: Added policies to iptables\n    * #2804: Fixed DB bundle reference in dev-env.\n    * #2665: Added support for Quectel EG25\n    * #2622: Support for SimTech SIM7000 LTE NB-IOT modem\n    * #2611: Zte ME3630 LTE modem support \n    * #2558: udhcpc pid file parameter fix\n    * #2511: Updating jetty to 9.4.19.v20190610\n    * #2484: Fixed H2db invocation in config.ini file. \n    * #2466: Updated H2DB to version 1.4.199\n    * #2404: HostapdManager: use absolute path to pid file instead of relative\n    \n    \nKnow Issues :\n  * The implementation of the CryptoService performs encryption using a\n    password that is hardcoded and published.\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE also tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was\n    \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\".\n    Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease)\n    (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on\n    gatttool and the BLE connection will encounter a failure.\n  * WiFi on Raspberry Pi 2 has only been tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * #2414: Rock 960: cannot get client id\n  * #2038: [Kura 3.2.0 QA] Package uninstallation log\n  * #2013: Unsaved changes dialog triggers incorrectly\n  * #1993: Search Domains Are Not Supported\n  * #1932: SystemAdminService.getUptime() returns SystemAdminService#UNKNOWN on MacOS when locale is not English\n  * #1663: Authentication Issue with Deploy V2\n  * #1572: serial modbus has errors on some hardware\n  * #1533: MqttDataTransport client-id illegal character\n  * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0\n  * #1201: Wifi password incorrectly read from snapshot in Access Point mode\n  * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot\n  * #1161: Incorrectly configuring a component can be irreversable.\n  * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services\n  * #1016: ConfigurationServiceImpl creates duplicate instances\n  * #797:  Design of ServiceUtil is broken\n  * #771:  Web UI fails with INTERNAL_ERROR when WireHelperService is not registered\n  * #654:  Clean up static initialization around \"modem\" functionality\n  * #645:  Clean up internal dependencies in Kura\n  * #522:  [Net] Modem monitor should monitor interfaces, not modems\n  * #486:  Build environment broken on Windows\n  * #406:  Replace System.get* with calls to SystemService.getProperties\n  * #348:  WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set\n  * #329:  [DEPLOY-V2] Review/refactoring needed\n  * #297:  [Status led] What connection instance controls the status led?\n  * #253:  Check if bundle contexes correctly unget services after invoking getService\n  * #222:  CloudConnectionStatusServiceImpl does not cancel workers on component deactivation\n\n\nEclipse Kura - 4.1.0\n-------------------------------------------------------------------------\nDescription:\nEclipse Kura 4.1.0 is a minor release dedicated to introduce several new features and continue the process of overall usability improvement.\nThe development team spent also a lot of effort trying to refactor and improve the overall code quality.\n\n\nNew and Noteworthy:\n  * APIs\n    * New APIs for KuraBirthPayload, KuraDeviceProfile, KuraDisconnectPayload\n  \n  * Features and Enhancements\n    * Enhanced the JSON Service with JSON Message marshalling/unmarshalling\n    * Added timestamp to Lifecycle Messages\n\n  * Target Platform Updates\n    * Google Guava 25.0-jre\n    * Eclipse Milo 0.2.4\n    * Apache Fileupload 1.3.3\n    * Apache Artemis 2.6.4\n    * Eclipse Paho 1.2.1\n\n  * Bug fixes and cleanups\n    * Fixed unnecessary escaping in Drivers and Assets UI\n    * Fixed issue where asset failure messages were not displayed\n    * Fixed a bug where the user could not set cellular attempts option to 0\n    * Fixed incompatibility with systems without iwlist\n    * Solved a possible OSGi framework refresh when a dp is uninstalled or reinstalled \n    * DEPLOY-V2 cloudlet fixes for GET calls\n\n\nDeprecated APIs:\n  * Deprecated old Bluetooth APIs not based on tinyB\n\n\nCompatibility:\n  * Eclipse Kura v4.1.0 does not introduce API breakage with previous releases.\n  * The Command Service is now disabled by default. To use it, the user needs to opt-in to this feature, enabling the service\n    from configuration.\n\n\nTarget Environments:\n  * Kura is released as pre-compiled binary installers for the following platforms:\n    * Raspberry Pi 2/3 based on Raspbian\n    * Intel Up Squared board running Ubuntu 16  \n    * Intel Up Squared board running Centos 7 (Experimental)\n    * Rock960 ARM_64 running Ubuntu 16 (NN version only)\n  * Kura is also available as a pre-built Docker container \n  \n\nSecurity Fixes:\n  * CVE-2016-1000031\n  * CVE-2018-10237\n  * CVE-2019-10242\n  * CVE-2019-10243\n  * CVE-2019-10244\n\n\nBug Fixes :\n  * Fixed github issues:\n    * #2423: [Kura QA 4.1.0] Emulator in Oomph installer\n    * #2421: Artemis Server manager NullPointer exception\n    * #2418: Kura does not support systems without iwlist\n    * #2417: [Kura 4.1.0 QA] Asset configuration radio buttons\n    * #2412: Paho issue with WS broker\n    * #2407: Can't set cellular connection attempts to 0\n    * #2399: Update Paho to latest version available\n    * #2389: Unnecessary escaping in Drivers and Assets data UI\n    * #2388: Update Artemis to 2.6.4\n    * #2382: Asset operation failure messages are not always shown\n    * #2372: Add Timestamp to Lifecycle Messages\n    * #2353: [ConfigurationService] Loading unencrypted snapshots discards line breaks\n    * #2352: Guava CVE-2018-10237\n    * #2334: The old Bluetooth APIs should be deprecated\n    * #2330: BLE Beacon data assembly overflow\n    * #2324: Possible OSGi framework refresh when a dp is reinstalled\n    * #2313: Typos in ExamplePublisher metric name and descriptions\n    * #2301: kura.data.dir unused\n    * #2300: Drivers and Assets description is appended\n    * #2296: The BluetoothLE example fails when the cloudPublisher is undefined\n    * #2290: [Kura 4.0.0 QA] Shutdown issue when started multiple times\n    * #2256: Deploy-V2 cloudlet GET status stops responding\n    * #2069: Marketplace install when LAN-only\n    * #362:  Uninstaller leaves most of the files\n\n  * Merged no issue-related Pull Requests:\n    * #2432: Fix GPS enable when PPP is not configured\n    * #2429: Fixed NPE on DhcpClientLeaseBlock\n    * #2416: Fixed issues for Kura on Intel UP2 Ubuntu\n    * #2395: Removed wrong if section in emulator position.\n    * #2394: Fixed lint issues\n    * #2387: CentOS/RPM uninstallation cleanup\n    * #2386: OPCUA Driver updates\n    * #2385: Solved some new lint issues.\n    * #2380: Fixed lint issues\n    * #2379: Moved KuraBirthPayload, KuraDeviceProfile and KuraDisconnectPayload to APIs\n    * #2377: Added missing byte array conversion in optimiser library\n    * #2376: Changes to expose simple message creation in corresponding JSON service\n    * #2373: Added support for null notification publisher in deploy-v2.\n    * #2370: Cleanup Kura folders\n    * #2368: Implemented fixes for possible XXE attacks to XML parsers.\n    * #2366: Changed joint shapes file to default and applied corresponding changes in wires_composer.js file.\n    * #2362: Fixed regression when saving empty wire graph\n    * #2358: Fixed few more lint issues.\n    * #2357: Fixed notification publisher topic.\n    * #2355: Fixed regression in CloudService tab ordering\n    * #2349: Added check for resolv.conf symlink\n    * #2348: Improved Web UI configuration loading\n    * #2347: Solved some blocking lint issues\n    * #2346: Changes to solve lint issues in CloudConnectionStatus.\n    * #2345: Fixed lint issue\n    * #2344: Solved some major lint issues in MqttDataTransport.java\n    * #2343: Removed stale cmpn references. \n    * #2342: Refactored console code in web2 bundle.\n    * #2333: Another tentative fix to solve lint issue in file check\n    * #2331: Removed osgi.cmpn api bundle.\n    * #2329: Updated retrieving of system parameters on Windows\n    * #2328: Solved some more lint issues\n    * #2327: Changes to fix possible path injection attack in skinServlet.\n    * #2325: Few lint issues fixes\n    * #2309: Always use double as GainOffset return type\n    * #2305: Remove the Jetty version from Server reply.\n    * #2306: Removed unnecessary jaxb imports \n    * #2302: Provide class to LogManager.getLogger()\n    \n    \nKnow Issues :\n  * The implementation of the CryptoService performs encryption using a\n    password that is hardcoded and published.\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE also tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was\n    \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\".\n    Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease)\n    (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on\n    gatttool and the BLE connection will encounter a failure.\n  * WiFi on Raspberry Pi 2 has only been tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * #2414: Rock 960: cannot get client id\n  * #2038: [Kura 3.2.0 QA] Package uninstallation log\n  * #2013: Unsaved changes dialog triggers incorrectly\n  * #1993: Search Domains Are Not Supported\n  * #1932: SystemAdminService.getUptime() returns SystemAdminService#UNKNOWN on MacOS when locale is not English\n  * #1663: Authentication Issue with Deploy V2\n  * #1572: serial modbus has errors on some hardware\n  * #1533: MqttDataTransport client-id illegal character\n  * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0\n  * #1201: Wifi password incorrectly read from snapshot in Access Point mode\n  * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot\n  * #1161: Incorrectly configuring a component can be irreversable.\n  * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services\n  * #1016: ConfigurationServiceImpl creates duplicate instances\n  * #797:  Design of ServiceUtil is broken\n  * #771:  Web UI fails with INTERNAL_ERROR when WireHelperService is not registered\n  * #654:  Clean up static initialization around \"modem\" functionality\n  * #645:  Clean up internal dependencies in Kura\n  * #522:  [Net] Modem monitor should monitor interfaces, not modems\n  * #486:  Build environment broken on Windows\n  * #406:  Replace System.get* with calls to SystemService.getProperties\n  * #348:  WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set\n  * #329:  [DEPLOY-V2] Review/refactoring needed\n  * #297:  [Status led] What connection instance controls the status led?\n  * #253:  Check if bundle contexes correctly unget services after invoking getService\n  * #222:  CloudConnectionStatusServiceImpl does not cancel workers on component deactivation\n\n\nEclipse Kura - 4.0.0\n-------------------------------------------------------------------------\nDescription:\nEclipse Kura 4.0.0, compatible with Java 9 and OSGi R6, introduces a new model that simplifies plugging new cloud connection implementations.\nIt brings up a restructuring of the networking part to make it more pluggable and expandable, new drivers and supported platforms, as well as \nimprovements to usability and bug fixes.\nBeing a major release, it also includes breaking changes and removes support for code and platforms no longer maintained by the original contributors.\n\n\nNew and Noteworthy:\n  * APIs\n    * Cloud Connections: New Cloud Connections APIs that simplify the integration of third party cloud providers, simplifying the development of \n      user applications  \n    * Alerts: New Alerting model for special type of messages generated from the device\n    * New Bluetooth LE APIs to leverage new TinyB features: updated the TinyB library and updated Kura APIs to leverage the new changes provided \n      by the referenced library \n  \n  * Features\n    * Eclipse IoT WG Cloud Connection: A new Cloud Connection provider that leverages the new Cloud Connections APIs and enables Kura to connect \n      with remote providers that support the new Eclipse IoT WG Namespace. E.g. this provider supports the integration with Eclipse Hono through \n      the MQTT Adapter \n    * Kura Docker container: New Docker Container that wraps in a Centos 7 environment a Kura No Network installation. \n    * Upload of Asset channels from CSV file: In the Asset view, the user can now download and upload channel descriptions as CSV files.\n\n  * Enhancements\n  \t* Non-blocking assets configuration updates\n  \t* Wires Graph Blinking rate limit \n  \t* Added fix validity, latitude and longitude hemisphere fields to GPS NMEA Position \n  \t* Reduced CPU usage by Kura Wires\n\n  * Refactor and Cleanup\n    * Modular support of new platforms: Refactoring of framework structure to support, in a pluggable way, different operating systems and \n      service managers (SysV, Systemd)\n    * SSL Manager Service: Service refactoring and cleanup. By default, Kura uses for secure communications its own cacerts.ks keystore instead \n      of the one provided by the Java VM. The default installation provides a cacerts.ks keystore that contains only the Eclipse leaf certificate. \n      To connect to a different provider or broker, the user must install the corresponding certificate in the cacerts.ks keystore, for example \n      using the Kura web UI.  \n    * New framework folder structure: The framework folder structure has been redesigned to simplify the user interaction.\n\n  * Drivers\n    * New drivers available also in the Eclipse Kura Marketplace:\n      * iBeacon Scanner\n      * Eddystone Scanner\n      * Dummy Driver\n\n  * New Hardware Platforms and Distributions\n    * Intel UP Square Boards running Ubuntu and CentOS\n    * Rockchip Rock960 AARCH 64 running Ubuntu\n\n  * Target Platform Updates\n    * Eclipse Equinox 3.12.50 (Oxygen)\n    * Eclipse Milo 0.2.1\n    * Apache Log4j2 2.8.2\n    * SLF4J 1.7.25\n    * Apache Artemis 2.5.0\n    * Apache Camel 2.21.1\n    * Intel Tinyb 0.5.1\n    * Eclipse Paho 1.2.0\n    * GWT 1.8.2\n\n  * Breaking Changes:\n    * Removed APIs and implementation supporting HSQLDB\n    * org.eclipse.kura.net package cleanup and removal of deprecated APIs\n    * Removed deprecated newWireSupport as causing invocation loop\n    * Removed SslManagerServiceOptions class and modified SSLManagerService APIs\n    * Modified \"verifySignature\" method in Certificates APIs to accept, as first argument, KuraApplicationTopic instead of KuraTopic\n    * Removed WireService API and references\n\n  * Deprecated APIs\n    * KuraTopic\n    * CloudCallService\n    * CloudClient\n    * CloudClientListener\n    * Cloudlet\n    * CloudletTopic\n    * CloudService\n    * CloudServiceFactory\n \n  * Discontinued Hardware Platforms and Distributions:\n    * Intel Edison\n    * TI BeagleBone Black\n    * PC Engines APU\n    * Fedora distribution for the Raspberry Pi\n    * Raspberry Pi B+\n    * AARCH64\n\n  * Unmaintained Code\n    * Karaf\n\n\nCompatibility:\n  * Eclipse Kura v4.0.0 introduces API breakage with previous releases.\n  * Containing a folder restructuring, a cleanup of the destination filesystem is required before installing the new version of Kura\n  * The Command Service is now disabled by default. To use it, the user needs to opt-in to this feature, enabling the service\n    from configuration.\n\n\nTarget Environments:\n  * Kura is released as pre-compiled binary installers for the following platforms:\n    * Raspberry Pi 2/3 based on Raspbian\n    * Intel Up Squared board running Ubuntu 16  \n    * Intel Up Squared board running Centos 7 (Experimental)\n    * Rock960 ARM_64 running Ubuntu 16 (NN version only)\n  * Kura is also available as a pre-built Docker container \n\n\nBug Fixes :\n  * Fixed github issues:\n    * #2279: [Kura 4.0.0 QA] Service disappears from menu when reconfigured\n    * #2278: Firewall, \"Open port\" dialog validation\n    * #2272: Asset CSV upload/download issues if AD name and id differs\n    * #2271: [Kura 4.0.0 QA] Adding wires components in IE/Edge\n    * #2264: [Cellular] PDP Auth failed using context #1 in 4G network (Telit LE910-EU1 and LE910-V2 EU, possibly NA versions)\n    * #2263: Cloud connections table refresh\n    * #2262: Cloud connection PID validation\n    * #2243: [Security] Possible XML External Entity (XXE) attack\n    * #2239: WireAsset Configuration UI check box status can not be saved\n    * #2233: Create CloudServiceFromFactory and Delete CloudServiceFromFactory cause null reference\n    * #2232: Linker issue with tinyb\n    * #2224: Wire Publisher can't initialize properly at kura start\n    * #2219: Update Jetty to version 9.4.12\n    * #2215: NPE during package installation via cloud\n    * #2213: Update TinyB and Bluetooth API\n    * #2210: Remove HSQL db support from code and implementation\n    * #2205: [OPC-UA Driver] Authentication not working\n    * #2202: [DhcpClientLeaseBlock] Failed to add a lease block due to an error parsing dhclient lease file\n    * #2199: BLE iBeacon scanner configuration not synched with code\n    * #2196: BLE provider logging failure\n    * #2189: HTTPS redirects to HTTP\n    * #2185: [Test] Cleanup tycho-surefire-plugin configurations a bit\n    * #2184: [ConfigurationService] XML Marshaling Providers need to be started before\n    * #2181: H2DB file fragmentation\n    * #2169: H2DB file corruption\n    * #2164: [Asset] Make configuration updates non-blocking\n    * #2163: [Paho] WSS connection break silently after a few hours\n    * #2162: [Wires] Implement rate limit in servlet for wires blinking\n    * #2158: [GPS] Add missing fields in NMEA Position\n    * #2153: [DEPLOY-V2] intallVerificationDir is never initialized\n    * #2149: Cloud zip file upload\n    * #2145: Remove libmatthew-java\n    * #2143: Camel XML router service missing\n    * #2138: Cloud service selection in examples\n    * #2125: Impossible to upload device key pair\n    * #2120: BeaconScanner example publishes with qos 2\n    * #2117: Remove Windows bundles\n    * #2115: Artemis 2.5.0 and dev-env\n    * #2114: Review supported platforms\n    * #2110: Add Dummy Driver\n    * #2108: Create a new Cloud Stack for the new D2C Messaging\n    * #2107: Integrate Device to Cloud (D2C) Interaction Type\n    * #2102: emitAllReadChannels method doesn't handle Runtime exceptions\n    * #2101: [Web UI | Driver and Assets]: Show the Asset Read Error Message\n    * #2096: [NetAdmin] Issues using GPS if modem has never been enabled\n    * #2091: version `GLIBCXX_3.4.20' not found \n    * #2089: [NetAdmin] Some state of the logic that manages modems persists across resets\n    * #2087: [NetAdmin] Race condition between NetAdmin and PositionService after modem reset\n    * #2085: [NetAdmin] Fix AT escape sequence timings in TelitModem\n    * #2079: Empty channel descriptor\n    * #2078: Native Support for UP Development Kit\n    * #2072: Weird behaviour on webUI when click on CloudServices\n    * #2070: Icon not working for factory components\n    * #2068: The duration of Beacon scan should be in seconds\n    * #2067: DataService enable.recovery.on.connection.failure is causing a reboot systematic on first boot\n    * #2065: [Web2] AlertDialog causes duplicate ids\n    * #2057: Upgrade Camel version to 2.21.1\n    * #2055: DefaultCloudServiceFactory manages all CloudServiceImpl instances\n    * #2050: Modem monitor in Not connected state does not trigger reset\n    * #2045: Add support for CloudConnectionStatus with inverted gpio LED\n    * #2040: [Kura 3.2.0 QA] PositionService does not switch between GPS and static position\n    * #2037: The interface number for usb tty devices should be retrieved by the native library\n    * #1999: Connection refresh sometimes causes duplicate entries\n    * #1957: [Wires] Allow using the component name as label\n    * #1933: Support SCR/Declarative Services 1.3+\n    * #1921: Consider using EquinoxLauncher instead of the EclipseStarter\n    * #1911: [Artemis] Upgrade to version 2.5.0\n    * #1849: SSL Configuration - Keystore path change doesn't work\n    * #1644: [Artemis] MQTT clients fail to reconnect after the broker is restarted \n    * #1358: [GPS] With a USB GPS device, the position service keeps reporting the old position\n    * #1255: Switch away from log4j 1.x\n    * #1186: Get ready for Java 9\n    * #689:  Upgrade to Camel 2.18.x\n    * #673:  CloudServiceFactory deleteConfiguration\n    * #651:  Call to \"exit()\" in native code\n    * #520:  [Net] PppFactory is not a factory and its design is wrong\n    * #518:  [Net] Modem monitor concurrency issue with multiple modems\n    * #208:  Include camel-amqp component jar in base distribution\n    * #181:  [GPS] position service: code review\n\n  * Merged no issue-related Pull Requests:\n    * #2288: Changes to prevent usage of the same db table between different cloud connections\n    * #2285: Changes to the binary parser library\n    * #2276: Changed validity checks for RMC strings\n    * #2273: Fixed dev-env launch configs.\n    * #2270: Updated Eclipse SSL cert to enable connection to Eclipse Mqtt broker. \n    * #2269: Set the command service as disabled per default.\n    * #2266: Disabled apparmor at framework installation.\n    * #2260: Fixed modem monitor\n    * #2259: Fix wrong reference to certificate servlet.\n    * #2257: Update to equinox wireadmin 1.0.800\n    * #2255: Added the interfaceName as argument in monitor listeners; fixed NPE\n    * #2251: Fixed old wireService reference.\n    * #2231: Avoid saving snapshot at shutdown\n    * #2230: Fixed cloud connection status url linux path parsing\n    * #2229: Add another type converter for Wires/Camel integration\n    * #2228: Fix a typo in the log message\n    * #2221: Fixed notification publisher topic.\n    * #2222: Fixed change in asset configuration property types\n    * #2216: Implemented forcing endpoint URL in OPCUA driver\n    * #2212: Improved subscription management in default CloudEndpoint\n    * #2198: Synchronized BLE iBeacon scanner configuration with code\n    * #2194: Updated configuration label in BLE example\n    * #2192: Stop default H2 db service\n    * #2191: Set payload timestamp in BLE scanner examples\n    * #2188: Use log4j2 in emulator and tests\n    * #2175: NMEAParser class cleanup\n    * #2173: Implemented nonblocking config update for s7 driver\n    * #2126: Updated wires devel components to use new API \n    * #2112: Fix the creating of a random topic\n    * #2099: Save two process forks when writing the config files\n    * #2094: Sort interfaces alphabetically\n    * #2083: Improve debug output of known wires\n    * #2081: Fix Wire component labels\n    * #2071: Simplify ifcfg config\n    * #2063: Fix a NPE and provide proper cause of error\n    * #2061: Fixed lint issues\n    * #2053: Update to Eclipse Milo 0.2.1\n    * #2041: Started fixing archetype\n    * #1978: Modbus TCP incorrectly reads frame length\n    * #1940: Solved some possible NPEs in web2 bundle.\n    * #820:  Upgrade to GWT 2.8.2\n    \n    \nKnow Issues :\n  * The implementation of the CryptoService performs encryption using a\n    password that is hardcoded and published.\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE also tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was\n    \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\".\n    Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease)\n    (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on\n    gatttool and the BLE connection will encounter a failure.\n  * WiFi on Raspberry Pi 2 has only been tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * #2069: Marketplace install when LAN-only\n  * #2038: [Kura 3.2.0 QA] Package uninstallation log\n  * #2013: Unsaved changes dialog triggers incorrectly\n  * #1993: Search Domains Are Not Supported\n  * #1932: SystemAdminService.getUptime() returns SystemAdminService#UNKNOWN on MacOS when locale is not English\n  * #1663: Authentication Issue with Deploy V2\n  * #1572: serial modbus has errors on some hardware\n  * #1533: MqttDataTransport client-id illegal character\n  * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0\n  * #1201: Wifi password incorrectly read from snapshot in Access Point mode\n  * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot\n  * #1161: Incorrectly configuring a component can be irreversable.\n  * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services\n  * #1016: ConfigurationServiceImpl creates duplicate instances\n  * #797:  Design of ServiceUtil is broken\n  * #771:  Web UI fails with INTERNAL_ERROR when WireHelperService is not registered\n  * #654:  Clean up static initialization around \"modem\" functionality\n  * #645:  Clean up internal dependencies in Kura\n  * #522:  [Net] Modem monitor should monitor interfaces, not modems\n  * #486:  Build environment broken on Windows\n  * #406:  Replace System.get* with calls to SystemService.getProperties\n  * #362:  Uninstaller leaves most of the files\n  * #348:  WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set\n  * #329:  [DEPLOY-V2] Review/refactoring needed\n  * #297:  [Status led] What connection instance controls the status led?\n  * #253:  Check if bundle contexes correctly unget services after invoking getService\n  * #222:  CloudConnectionStatusServiceImpl does not cancel workers on component deactivation\n\n\nEclipse Kura - 3.2.0\n-------------------------------------------------------------------------\nAdded Features :\n  * Multiport Wires Components: Add Wires components with multiple input/output ports to allow \n    for better routing of data through the Wire Graph. With the addition of new arithmetic and conditional \n    Components, this will allow more flexibility and usability in creating logical flows through the Graph.\n  * Wires Conditional Component: Add Wires component that facilitates if/then/else logic.\n  * Wire Arithmetic Component: Add Wires component that facilitates basic arithmetic functions. \n    This bundle is available as an example project.\n  * Wires Statistical Component: Add Wires component that performs basic statistical analysis. \n    This bundle is available as an example project.\n  * Wires Join Component: Add Wires component that performs join operations.\n  * Wire Publisher Position: Add support for device position in published messages. The user can decide \n    whether or not having the position included in messages published to the cloud and also the verbosity \n    of the position information included.\n  * Wire Graph export: Add support, in the wire composer, to export only a working wire graph.\n  * Assets: Add support for event driven Drivers\n  * Assets: Channels can now be individually enabled and disabled. \n  * Drivers: To further extend the usability of Kura, new Drivers for GPIO, Raspberry Pi SenseHAT, \n    and Event Driven Drivers will be introduced.\n\nCompatibility:\n  * Eclipse Kura v3.2.0 does not introduce API breakage with previous releases.\n\nTarget Environments:\n  * Kura is released as pre-compiled binary installers for the following platforms:\n    * Raspberry Pi based on Raspbian: Raspberry Pi, Raspberry Pi B+, Raspberry Pi 2/3\n    * BeagleBone Black based on Debian\n    * Fedora on ARM (Experimental) \n    * Intel Edison (Experimental)\n    * APU Debian (Experimental)\n    * ARM_64 Debian (Experimental)\n\nBug Fixes :\n  * Fixed github issues:\n    * #2042: Switching network interface status from 'L2Only' to 'Unmanaged' doesn't work.\n    * #2022: Factories don't get removed from creation dialog\n    * #2020: Wrong column content in assert/driver view\n    * #2015: New Factory Component - drop-down-list item missing for a installed package\n    * #2014: Deleting a component keeps tab open\n    * #2012: DB-H2-012 fails\n    * #2010: Exception when disabling watchdog\n    * #2009: DATA-LIMIT-001 fails\n    * #2007: Array validation doesn't work properly\n    * #2002: DEN-DEPLOY-005 failed\n    * #1997: Improve dhcpd shutdown logic\n    * #1853: SensorTagDriver sometimes fails to connect to the SensorTag\n    * #1975: [Kura 3.2.0 QA] Warning logged uploading and old Asset snapshot\n    * #1973: [Kura 3.2.0 QA] Wire graph snapshot includes the Meta Type OCD\n    * #1971: EthernetMonitor can't monitor more than two ethernet interfaces\n    * #1970: [Kura 3.2.0 QA] Multiple handling of PositionLocked\n    * #1959: [Web] Escaping doesn't seem to work properly\n    * #1956: [Wires] Creating a component named \")\" is possible\n    * #1955: [Wires] New Wire Component name entry field is broken\n    * #1941: [DbDataStore] Stale messages not purged with timezone other than UTC\n    * #1936: [Driver] Improve the way Driver instances are shared between consumers\n    * #1928: Removing and reinstalling the Script Filter dp causes a lot of components to be restarted\n    * #1924: [Wires] Script Filter and Conditional use different syntax\n    * #1914: User should be able to set PDP context number for setting APN.\n    * #1907: [WireAsset] Implement Driver generated single timestamp\n    * #1906: [Wires] Download graph as a (partial) configuration snapshot\n    * #1905: [WirePublisher] Add option to publish the geographic position\n    * #1902: Allow to enable/disable channels in asset configuration\n    * #1894: Show Wire Component description in the Web Ui\n    * #1892: Add SenseHat Driver\n    * #1886: Package unistall error\n    * #1878: Add support for \"Unmanaged\" mode for network interfaces.\n    * #1876: Packages URL downloader does not use Kura's SSLContext\n    * #1874: Change the reboot cause string\n    * #1870: Develop a GPIO Driver for Kura Wires\n    * #1863: IBeacon decoder index out of bounds\n    * #1861: Implement a WireAsset reacting to channel changes\n    * #1859: [Drivers and Assets] The channels names and labels in dropdown lists aren't sorted\n    * #1856: DEPLOY-V2: download always uses the defalut java keystore\n    * #1843: BaseChannelDescriptor contains some inconsistencies\n    * #1840: [OPC-UA] Improve type conversions in OPC-UA driver\n    * #1836: Jetty security issue\n    * #1835: [Documentation] AWS connection needs TLSv1.2\n    * #1834: [OPC-UA] The OPC-UA driver should not specify timestamps on write requests\n    * #1826: LE910 V1 doesn't turn back on at modem reset.\n    * #1823: Failure to submit Wifi configuration when wifi password (PSK) ends with the $.\n    * #1822: [Wires] Faulty refresh in Chrome\n    * #1821: [Wires] New Wires features don't work in IE\n    * #1816: [Emulator] NumberFormatException while installing new packages\n    * #1815: [Wires] Channel timestamp should be optional\n    * #1813: Marketplace dp installation popup drop-zone\n    * #1812: [PortFwd] Fields for internal and external ports mixed up\n    * #1811: Wires: Multi-port components and graph execution model\n    * #1809: [Wires] Drag and drop should respect canvas grid\n    * #1808: Define the JSON WireService persistence form\n    * #1807: [Wires] Add Component Multi Port support\n    * #1802: [Wires Refactoring] Wires WebUi refactoring\n    * #1801: Refactor Wires js code. GWT client should be the orchestrator.\n    * #1800: Modify Client code so GWT client prepares wire component configuration from GwtWireGraphConfiguration\n    * #1799: Modify code so GWT client calls jointjs to build graph from GwtWireGraph\n    * #1798: Move Wires-related code out of the GWT Server part\n    * #1797: [Wires Refactoring] Implement new Wires APIs\n    * #1796: [Wires Refactoring] Review APIs\n    * #1795: Refactor WireServiceImpl to also implement WireGraphService\n    * #1793: Update ConfigurationService API with new methods to handle factory OCDs\n    * #1792: Define WireGraphService and deprecate WireService\n    * #1786: Wire publisher do not include a timestamp in the message\n    * #1778: [Wires] Web Ui error when deleting a not saved component\n    * #1777: [Wires] Drag and drop glitch\n    * #1776: [Wires] Add a refresh button in Wire Composer\n    * #1773: Kura DB Store Query\n    * #1772: Remove the icons from the \"new component\" dialog\n    * #1770: CloudService instance hint should be persistent while the user writes\n    * #1761: NetworkAdminServiceImpl: submitFirewallConfiguration blocks for 30 seconds\n    * #1758: [Web UI] Initial page view on a narrow screen\n    * #1757: Remove GpsClockSyncProvider in Clock Service\n    * #1753: Typo in Eddystone provider component definition\n    * #1737: CloudClient subscribes to more topics than requested\n    * #1734: Display of asset channel data in WebUI in case of failures\n    * #1703: [Kura 3.1.0 QA] Wires page jumping up and down\n    * #1700: [Kura 3.1.0 QA] Rollback doesn't restore deleted services\n    * #1689: Instaling a dp can cause the WebUI to restart\n    * #1657: Bluetooth notifications do not work\n    * #1632: Cleanup old scripts in distrib/resources folder\n    * #1268: [WebUI] Usability Improvements\n    * #1213: [Wires] Should DB Filter clean the cache on empty result set?\n    * #1193: [Wires] Component avoidance during initial placement\n    * #1188: [Wires] Components can be hidden outside the graph area\n    * #1092: Possible NPE and non-working check\n    * #890: [Kura 2.1.0 QA] Snapshot management in web UI\n    * #590: [Cloud] CloudConfigurationHandler casts to ComponentConfigurationImpl without type check\n    * #520: [Net] PppFactory is not a factory and its design is wrong\n\n\n  * Merged no issue-related Pull Requests:\n    * #2044: Fixed dhclient issue after Raspbian fresh install\n    * #2039: Fixed rotation issue in sensehat driver\n    * #2036: Fix for modem serial ports detection and ppp\n    * #2035: Fixed possible NPE in sensehat driver\n    * #2034: Added stop watchdogd step to WatchdogService\n    * #2028: Removed localisation from o.e.k.w.provider bundle\n    * #2023: Removed 'Search Domains' field\n    * #2016: Modified wrong reference to internal modem\n    * #1996: Added dp for gpio driver\n    * #1992: Re-enable plain Fedora installer in addition to RPMs\n    * #1988: Backport maintenance fixes\n    * #1985: DIO: fix unsafe casts in native code for 64 bits architectures\n    * #1984: Changed gpio bundle defaults, removing the hardcoded gpio 1.\n    * #1974: Fixed wrong pid reference in configuration upgrade class.\n    * #1968: Fixed too strict package imports\n    * #1966: Added missing since in APIs for modem management.\n    * #1963: Prevent getters from creating new object instances\n    * #1954: Fixed possible NPE in OPCUA driver\n    * #1949: Added notifications on SensorTagDriver and fix several bugs in SensorTagExample\n    * #1947: Fixed modem reset functionality.\n    * #1944: Fix a possible NPE\n    * #1943: o.e.k.w.c.provider: fix Import-Package version range\n    * #1931: WireAsset: do not log errors if they are emitted\n    * #1925: Changed exists plugin default. Now it's disabled.\n    * #1917: Improve the description of a few settings\n    * #1915: [H2] Updated service description \n    * #1913: Wires composer robustness and usability improvements\n    * #1891: Fixed potential malfunction of Eddystone-UID advertiser with some hcitool versions\n    * #1888: Added tcp socket connection timeout\n    * #1848: Disabled the kura.primary.network.interface property.\n    * #1847: HTML IDs\n    * #1829: URL.openStream() creates a new connection without SslContextFactory set\n    * #1755: Modified the success notification in order to not being executed in a different thread.\n    * #1738: Modified localization.resources fragment to reference the host with a version range.\n    * #1432: Remove Intel Edison Profile\n    \n\nKnow Issues :\n  * The implementation of the CryptoService performs encryption using a\n    password that is hardcoded and published.\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was\n    \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\".\n    Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease)\n    (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on\n    gatttool and the BLE connection will encounter a failure.\n  * The TinyB library used by the Bluetooth LE API implementation sometimes cause a JVM crash.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network\n    interface which happened even if network configuration hasn't been modified.\n  * #2050: Modem monitor in Not connected state does not trigger reset\n  * #2040: [Kura 3.2.0 QA] PositionService does not switch between GPS and static position\n  * #2013: Unsaved changes dialog triggers incorrectly\n  * #1999: Connection refresh sometimes causes duplicate entries\n  * #1995: Failed NET-WIFI-003 on Fedora\n  * #1993: NET-ETH0-003 failed\n  * #1932: SystemAdminService.getUptime() returns SystemAdminService#UNKNOWN on MacOS when locale is not English\n  * #1788: Maven Archetype does not work - or can someone show me how to use it?\n  * #1663: Authentication Issue with Deploy V2\n  * #1644: [Artemis] MQTT clients fail to reconnect after the broker is restarted\n  * #1572: serial modbus has errors on some hardware\n  * #1533: MqttDataTransport client-id illegal character\n  * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0\n  * #1414: SCR exception running Kura Wires in Karaf\n  * #1373: [Kura 3.0.0 QA] Configuration service: mixing configurable services with factory components\n  * #1358: [GPS] With a USB GPS device, the position service keeps reporting the old position\n  * #1201: Wifi password incorrectly read from snapshot in Access Point mode\n  * #1161: Incorrectly configuring a component can be irreversable.\n  * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services\n  * #1016: ConfigurationServiceImpl creates duplicate instances\n  * #924:  [Kura 2.1.0 QA enh] Non-trimmed values of configuration parameters\n  * #923:  [Kura 2.1.0 QA] eth0 search domain configuration and storage\n  * #797:  Design of ServiceUtil is broken\n  * #771:  Web UI fails with INTERNAL_ERROR when WireHelperService is not registered\n  * #654:  Clean up static initialization around \"modem\" functionality\n  * #651:  Call to \"exit()\" in native code\n  * #650:  Possible bug in \"LinuxUdev.c\"\n  * #645:  Clean up internal dependencies in Kura\n  * #522:  [Net] Modem monitor should monitor interfaces, not modems\n  * #520:  [Net] PppFactory is not a factory and its design is wrong\n  * #518:  [Net] Modem monitor concurrency issue with multiple modems\n  * #486:  Build environment broken on Windows\n  * #406:  Replace System.get* with calls to SystemService.getProperties\n  * #362:  Uninstaller leaves most of the files\n  * #348:  WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set\n  * #329:  [DEPLOY-V2] Review/refactoring needed\n  * #297:  [Status led] What connection instance controls the status led?\n  * #253:  Check if bundle contexes correctly unget services after invoking getService\n  * #222:  CloudConnectionStatusServiceImpl does not cancel workers on component deactivation\n\n\nEclipse Kura - 3.1.0\n-------------------------------------------------------------------------\nAdded Features :\n  * H2 Databases: This release will see the switch from HSQLDB to H2. This migration will allow\n    for a number of performance improvements as well the ability to maintain multiple database instances.\n  * REST API for Kura Drivers and Assets: To allow more flexibility, REST endpoints will be\n    added to Kura for interacting with the Kura Drivers and Assets instances.\n  * Embedded Artemis Broker: The addition of the Apache Artemis Broker will extend Kura's\n    messaging functionality.\n  * BLE via TinyB: To improve the reliability of BLE, Kura will switch to the TinyB library\n    to support BLE via Bluez.\n  * Kura Wires Functional Logic: To extend the usability of Kura Wires, this release will\n    include Functional Logic Wire Components. This will allow the use of plain JavaScript\n    inside a Wire component.\n  * Kura Web UI Update: A new UI element will be added for managing and editing Drivers and Assets.\n  * S7 Industrial Protocol: A new driver will be added to the Eclipse Marketplace to support S7.\n  * BLE/SensorTag: A new driver will be added to the Eclipse Marketplace to support BLE on\n    the TI SensorTag.\n  * MQTT publish rate improvement: A limit parameter will be added to the MQTT transport service\n    to allow throttling of MQTT messages to prevent unnecessary congestion on the MQTT broker.\n  * Connection Monitor: A connection monitor will be introduced to the DataService to further\n    improve connectivity reliability.\n  * RPMs: This release will provide RPM packaging for Fedora based distributions.\n\nCompatibility:\n  * Eclipse Kura v3.1.0 does not introduce API breakage with previous releases.\n  * This release does introduce a new set of APIs for TinyB for interacting with BLE devices.\n    Support for previous BLE APIs will still be present and functional.\n  * In Kura v3.1.0 it is possible to instantiate a Driver instance from the Drivers and Assets\n    section or from Wire Composer only if the following requirements are met:\n      - the Driver implementation class must implement the following interfaces:\n        - Driver\n        - ConfigurableComponent or SelfConfigurableComponent\n      - the Driver must provide a component definition xml file that advertises that\n        the interfaces mentioned above are provided and that sets \"required\" as configuration policy.\n    It is advisable to update the deployment packages of non compliant drivers if needed.\n    It is still possible to instantiate non compliant drivers using the \"+\" button under \"Services\".\n\nTarget Environments:\n  * Kura is released as pre-compiled binary installers for the following platforms:\n    * Raspberry Pi based on Raspbian: Raspberry Pi, Raspberry Pi B+, Raspberry Pi 2/3\n    * BeagleBone Black based on Debian\n    * Fedora on ARM (Experimental) \n    * Intel Edison (Experimental)\n    * APU Debian (Experimental)\n    * ARM_64 Debian (Experimental)\n\nBug Fixes :\n  * Fixed github issues:\n    * #1725: [Kura 3.1.0 QA] Cloud Services GUI crashes\n    * #1724: [Kura 3.1.0 QA] WiFi DHCP: Gateway IP wrong in GUI\n    * #1720: [Kura 3.1.0 QA] SensorTagDriver NPE if wrong address\n    * #1707: [Kura 3.1.0 QA] BLE iBeacon* only react to company code 004c\n    * #1702: [Kura 3.1.0 QA] Artemis in emulator\n    * #1685: [WebUi] Security policy fingerprint UI does not expand\n    * #1680: getKuraMarketplaceCompatibilityVersion() always returns kura.version\n    * #1665: Create rpm installer for Fedora\n    * #1661: The driver configuration is not applied\n    * #1645: Development environment needs to be updated\n    * #1641: Oomph installer needs to be updated\n    * #1630: Wifi password check failing\n    * #1590: [Assets and Drivers] Byte arrays are not displayed properly\n    * #1588: Password arrays are not well managed by ConfigurationService\n    * #1585: [Messaging] Share cloud connection with external applications\n    * #1575: [Watchdog Service] Write the last reboot cause to a persistent file\n    * #1564: [MqttDataTransport] wss connections without hostname verification do not work\n    * #1558: CommandCloudApp doesn't use received working directory parameter\n    * #1556: connect.retry-interval=0 causes DataService activation failure\n    * #1541: Add support for polling to GPIO example\n    * #1531: Create \"Drivers and Assets\" tab\n    * #1530: Modify the wire composer to allow driver management\n    * #1517: Verify compatibility of the old Bluetooth implementation with Bluez 5.43\n    * #1513: H2 DB: Web app and TCP server are mutually exclusive\n    * #1511: Add Artemis broker to Kura core\n    * #1506: H2 DB: Changing the db user does not work\n    * #1502: H2 DB: Default service can be deleted\n    * #1501: H2 DB: invalid service configuration not indicated\n    * #1471: [Wires] Deleting a Timer instance might stop all other Timers\n    * #1462: Wire Components list has no scrollbar\n    * #1455: Wiki page documenting H2 use cases\n    * #1453: Remove unused lib directory from org.eclipse.kura.linux.usb\n    * #1447: New BLE beacon/advertisement API\n    * #1442: Add TinyB host and fragment bundles in target-platform\n    * #1435: Snapshot problem on wires\n    * #1429: Support arm 64 bits platform\n    * #1421: Replace HSQLDB with H2\n    * #1420: Promote Assets and Drivers like Cloud Services in the Web UI\n    * #1417: Implement DataService connection monitor as a CriticalComponent\n    * #1416: Limit the rate of messages published by the DataService\n    * #1413: Implementation of a SensorTag Kura Driver\n    * #1412: Beacon/advertisement implementation of the new BLE API\n    * #1411: GATT Implementation of the new Bluetooth Low Energy API\n    * #1409: New Bluetooth Low Energy API\n    * #1405: Fix trivial Sonar Lint problems in the network bundles\n    * #1396: [Beaglebone Black] Log4j log level set to DEBUG\n    * #1391: [Wires] Fifo is really FIFO only while it's full\n    * #1386: [Wires] Null properties in channel configuration are not properly handled\n    * #1384: OPC UA Driver channel descriptor property ids shouldn't be localised\n    * #1383: OPC UA Driver only supports string node ids\n    * #1378: [Wires] DB store primary key\n    * #1376: [Wires] Asset configuration is not updated after a ChannelDescriptor change.\n    * #1369: WiFi password (PSK) can't contain '&'\n    * #1363: [Documentation] Add tutorial on Eclipse Kapua connection\n    * #1362: [Documentation] Kura documentation improvements\n    * #1361: [Documentation] Improve Kura wires documentation\n    * #1360: [Documentation] Add Administration section in Kura documentation\n    * #1359: [Documentation] Add Configuration section in Kura documentation\n    * #1354: Document default tracking of services registering Configurable/SelfConfiguringComponent\n    * #1338: [Kura 3.0.0] camel.aggregation and camel.quickstart examples should be \"normalized\"\n    * #1325: [Wires] Exception if an Channel Descriptor contains in Option of Integer type\n    * #1321: 64bit Linux version broken\n    * #1288: Clean up JavaDoc of KuraPayload\n    * #1250: Drag and drop of Marketplace listing should send back a successful install count\n    * #1243: Distribute publishing over time\n    * #1207: [Driver] Contribute Siemens S7 Driver\n    * #1196: [Net] PPP password is not a (MetaType) Password\n    * #1032: Eclipse Drag and Drop Review\n    * #864:  [Web UI] Settings pages\n    * #752:  [DbDataStore] repair is very slow on big tables\n    * #751:  [DbDataStore] defrag and checkpoint are not per-table operations\n    * #572:  Unreadable errors in Web UI\n    * #308:  Add a BLE example for advertising as an Eddystone (Google) beacon\n    * #307:  CloudCallService overrides client ID\n    * #153:  Add JAX-RS to target platform\n    * #108:  CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device\n\n  * Merged no issue-related Pull Requests:\n    * #1731: Swapped commands in modem initialization\n    * #1729: Aligned dev-env kura.properties file to the one used in devices.\n    * #1728: Fixed a bug in the parseDhclientLeaseBlock() method.\n    * #1719: Changes to dp generation for examples and drivers.\n    * #1718: Disabled h2 log file by default\n    * #1717: Fixed firewall init script\n    * #1716: Fixed \"watchdog did not stop\" messages in syslog\n    * #1713: Refreshed kuraHome variable after loading from kura.properties file.\n    * #1711: Fixed component definition for can example\n    * #1699: Setting an higher value for the GPIO pins.\n    * #1697: Fixes a possible NPE in cloud services when a dp is removed.\n    * #1688: Added custom auth request command for Ublox modems\n    * #1687: Updated mapping between services and Ui icons.\n    * #1682: Reduced maximum size for custom icons to 14x14 to match the other build-in icons.\n    * #1676: Removed Karaf dependency from examples.\n    * #1675: Implemented DEPLOY-V2 hook support\n    * #1673: Added fallback into status bundle.\n    * #1671: Removed the dependency existing between examples and distrib.\n    * #1659: Fixed Telit LE 910 v2 reset\n    * #1640: Enhanced core.status bundle.\n    * #1624: Added basic support for Telit 910 LE v2\n    * #1599: Fixed startup scripts and WatchdogService\n    * #1598: Enabled snaphsot dp builds\n    * #1589: Added css to rotate the wires image properly.\n    * #1496: Updated for Windows build\n    * #1483: Added data transfer optimisation library for Drivers\n    * #1480: Changes in Device tab.\n    * #1460: [Testing][Refactoring] NetworkAdminServiceImpl tests, refactoring, fix\n    * #1459: [Refactoring] Linux.position refactoring\n    * #1458: [Testing][Refactoring] Added Camel unit tests\n    * #1454: Cleanup org eclipse kura linux net wifi\n    * #1450: Added exists-maven-plugin.\n    * #1445: Added protection code to prevent null pointer in GwtWireServiceUtil.\n    * #1443: Remove customizers\n    * #1375: Fixed Karaf native libs loading.\n    * #1371: Fixed regression in configuration service\n    * #1370: Fixed connection status icon at page load.\n    * #1368: Wires Web Ui fixes\n    * #1318: Code Cleanups in Localization Bundle\n\nKnow Issues :\n  * The implementation of the CryptoService performs encryption using a\n    password that is hardcoded and published.\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was\n    \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\".\n    Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease)\n    (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on\n    gatttool and the BLE connection will encounter a failure.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network\n    interface which happened even if network configuration hasn't been modified.\n  * #1703: [Kura 3.1.0 QA] Wires page jumping up and down\n  * #1700: [Kura 3.1.0 QA] Rollback doesn't restore deleted services\n  * #1689: Instaling a dp can cause the WebUI to restart\n  * #1663: Authentication Issue with Deploy V2\n  * #1657: Bluetooth notifications do not work\n  * #1644: [Artemis] MQTT clients fail to reconnect after the broker is restarted\n  * #1638: Kura does not support Consistent Network Device Naming\n  * #1572: serial modbus has errors on some hardware\n  * #1558: CommandCloudApp doesn't use received working directory parameter\n  * #1533: MqttDataTransport client-id illegal character\n  * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0\n  * #1451: PppAuthSecrets entry removal\n  * #1414: SCR exception running Kura Wires in Karaf\n  * #1373: [Kura 3.0.0 QA] Configuration service: mixing configurable services with factory components\n  * #1358: [GPS] With a USB GPS device, the position service keeps reporting the old position\n  * #1201: Wifi password incorrectly read from snapshot in Access Point mode\n  * #1197: [Net] Network configuration cannot be restored purely from snapshot\n  * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot\n  * #1193: [Wires] Component avoidance during initial placement\n  * #1161: Incorrectly configuring a component can be irreversable.\n  * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services\n  * #1092: Possible NPE and non-working check\n  * #1016: ConfigurationServiceImpl creates duplicate instances\n  * #924:  [Kura 2.1.0 QA enh] Non-trimmed values of configuration parameters\n  * #923:  [Kura 2.1.0 QA] eth0 search domain configuration and storage\n  * #890:  [Kura 2.1.0 QA] Snapshot management in web UI\n  * #797:  Design of ServiceUtil is broken\n  * #771:  Web UI fails with INTERNAL_ERROR when WireHelperService is not registered\n  * #654:  Clean up static initialization around \"modem\" functionality\n  * #651:  Call to \"exit()\" in native code\n  * #650:  Possible bug in \"LinuxUdev.c\"\n  * #645:  Clean up internal dependencies in Kura\n  * #558:  Update of DPs seems not to work\n  * #547:  [Configuration] Configuration Service may miss configuration-policy=optional components\n  * #522:  [Net] Modem monitor should monitor interfaces, not modems\n  * #520:  [Net] PppFactory is not a factory and its design is wrong\n  * #518:  [Net] Modem monitor concurrency issue with multiple modems\n  * #486:  Build environment broken on Windows\n  * #406:  Replace System.get* with calls to SystemService.getProperties\n  * #362:  Uninstaller leaves most of the files\n  * #348:  WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set\n  * #329:  [DEPLOY-V2] Review/refactoring needed\n  * #311:  [Multiple Cloud Connections] Spurious component reactivations upon configuration change\n  * #297:  [Status led] What connection instance controls the status led?\n  * #253:  Check if bundle contexes correctly unget services after invoking getService\n  * #222:  CloudConnectionStatusServiceImpl does not cancel workers on component deactivation\n\n\nEclipse Kura - 3.0.0\n-------------------------------------------------------------------------\nAdded Features :\n  * Eclipse Kura Wires\n    https://github.com/eclipse/kura/wiki/Kura-Wires:-introduction-and-references\n  * Eclipse Kura Drivers and Assets APIs and implementations\n  * Contributed Eclipse Kura OPC UA driver based on Eclipse Milo\n  * Improvements to local Web Console's usability and appearance\n  * Added support for MQTT over Websockets\n  * Added support for AWS IoT and Azure IoT platforms\n  * Simple JSON is now a supported encoding option in Eclipse Kura Cloud Service\n  * Introduced official support to Oomph installer\n  * Added support for Fedora 25 ARM based systems\n\nCompatibility Changes:\n  * Switched to Equinox 3.11.1\n  * Added support for Java 8. It is now the minimal JVM requirement to run Eclipse Kura\n  * Dropped support for all the native libraries but ARMv6 HF and x86_64 architectures\n  * Dropped support for Fedberry 24 systems\n  * The configuration service will only track so called \"Relevant services\" so the ones that, in their component\n    description files, will provide the ConfigurableComponent interface. The old behavior can be restored by setting the\n    \"org.eclipse.kura.core.configuration.legacyServiceTracking\" property to true.\n\nBug Fixes :\n  * Fixed github issues:\n    * #1335: [Kura 3.0.0 QA] User workspace plugins BREE\n    * #1329: Need to respect /etc/network/interfaces command options\n    * #1295: [Wires] Wires DataType lacks the KuraPayload float type\n    * #1294: [Wires] Remove ByteValue and ShortValue as they do not map to KuraPayload metric types\n    * #1282: Apache FileUpload Upgrade\n    * #1277: PR #1126 breaks changes to wire graph that were not saved\n    * #1269: [Wires] Column names in DB Store\n    * #1246: [Wires] MQTT namespace\n    * #1241: Changes to the heater publisher\n    * #1240: Add JSON/Protobuf encoding option in CloudService\n    * #1239: Change wire publisher to remove the JSON/Kura payload serialization\n    * #1222: Commit aa2913dc1031e783d09779dae503018da55889f6 breaks asset persistent storage\n    * #1220: [Driver] DriverRecord and AssetRecord. Clean code vs efficiency\n    * #1216: [Wires] Sub-second Timer\n    * #1212: [Wires] DB WireComponent improvements\n    * #1211: [Wires] Implement regex filter WireComponent\n    * #1210: [Wires] Implement FIFO WireComponent\n    * #1208: [Asset] Driver read method should return void\n    * #1206: [Driver] Driver API optimizations\n    * #1203: [Asset] Document ASSET-V1 topic namespace\n    * #1202: [Asset] Drop channel ID and use unique name\n    * #1176: Kura Wires: Inconsistent design of DbServiceHelper class\n    * #1166: Wrong order of operations in WireAsset\n    * #1160: ClockService should ignore updates with long 'getDelay'\n    * #1139: Factory Components Configurations not deleted from the snapshot\n    * #1131: ConfigurableComponentTracker calls bundleContext.getService(ref) when it shouldn't\n    * #1125: [Kura 3.0.0 M1 QA] Wires: Unexpected component configuration is shown\n    * #1123: [Kura 3.0.0 M1 QA] Bugs in camel example publisher\n    * #1121: [Kura 3.0.0 M1 QA] Wires: cannot add component after deleting one\n    * #1119: [Kura 3.0.0 M1 QA] Wires DB Store partial cleanup\n    * #1118: [Kura 3.0.0 M1 QA] Wires: dirty Component instances warning\n    * #1116: [Kura 3.0.0 M1 QA] Wires: wire components selection\n    * #1113: [Kura 3.0.0 M1 QA] Kura Wires doesn't work on Internet Explorer\n    * #1107: [Kura 3.0.0 M1 QA] Issue with modal confirmation dialog(s)\n    * #1105: [Kura 3.0.0 M1 QA] Issue with binding services\n    * #1104: [Kura 3.0.0 M1 QA] RPi 2/3 installation package contains unwanted files\n    * #1100: Inconsistent use of installation status strings in deployment impl\n    * #1091: Kura doesn't properly report \"ALREADY_DONE\" state to Kapua\n    * #1069: Change Package Infos in API Bundle that contain @since annotation\n    * #1057: Kura Wires BaseAsset write issue\n    * #1056: Kura Wires severity level based filtering issue\n    * #1053: dhclient is not being killed if interface is switched from DHCP to static\n    * #1041: Restructure Wire Envelope to make compatible with Kura Payload\n    * #1033: Rename org.eclipse.kura.asset.provider.default to org.eclipse.kura.asset.utility.provider\n    * #1026: Dragging a wire component onto the wire graphs pops up the install dialog\n    * #1024: PR #1007 broke distribution for assets\n    * #1022: Move AssetComponent.xml to Asset Provider\n    * #1015: Fix Fedora target to use libudev.so.1\n    * #1013: Drop support for ARMv5 SF/soft float\n    * #1003: Switch to Fedora 25\n    * #1000: Memory leak and concurrency issue in 'EventHandlerServlet'\n    * #999:  Refactoring: PropertiesUi must extend AbstractServicesUi\n    * #990:  Script error in installer\n    * #959:  Replace Preconditions references with Objects\n    * #954:  Fix output of properties\n    * #932:  org.eclipse.kura.asset.provider provides API and service implementation\n    * #918:  [Kura 2.1.0 QA] DEN-POS-002 Position service keeps reporting old position\n    * #916:  DEN-CONF-005 Wrong range limit for \"long\"\n    * #915:  [Kura 2.1.0 QA] DEN-CONF-005: Internal message when a \"too big\" number is entered\n    * #914:  [Web UI] Fixed fields can be edited\n    * #911:  [Kura 2.1.0 QA] SSID selection not always shows all SSIDs\n    * #908:  Web UI shows its own WLAN for connecting\n    * #889:  [Kura 2.1.0 QA] Denali Configuration ExamplePublisher error descriptions\n    * #861:  Kura's WEB bundles detection\n    * #846:  Replace INTERNAL_ERROR with suitable error code in Kura Wires\n    * #841:  Add Discouraged Access in Javadoc for INTERNAL_ERROR error code\n    * #824:  SelfConfiguringComponent are not registered properly\n    * #817:  Fix Exception Javadoc\n    * #786:  Services Search throws Exception\n    * #770:  Following the Eclipse versioning schema for OSGi\n    * #736:  Kura installer continues despite errors occurred\n    * #725:  Serial receive timeout is not forwarded to javax.comm.CommPort\n    * #721:  Unnecessary toggles eth0 interface when wlan0 interface is disabled on Raspberry Pi.\n    * #696:  FileServlet fails with NPE when there is no MetaTypeInformation\n    * #688:  Modify Kura Wires Web Copyright Header\n    * #664:  Misconfiguration of eth0 (as dhcp server) filling /var/log directory and finally crashing kura\n    * #657:  No ability to set security level with Bluetooth API\n    * #556:  Add WebSocket as alternative mqtt transport\n    * #555:  CAN bus bundle only supports 11-bit identifiers\n    * #553:  [Modbus] Refactoring of Modbus example\n    * #550:  [Modbus] String evaluation returns false\n    * #476:  Kura makes use of system properties when filtering for native code libraries which is not supported\n    * #460:  Upgrade Equinox to 3.11 and use Java 8 a minimum requirement\n    * #372:  [BLE] BluetoothGattImpl.getCharacteristics(String startHandle, String endHandle) and getServices() methods return empty list\n    * #352:  [Semantic Versioning] Enable analysis through bnd-baseline-maven-plugin\n    * #288:  [Modbus] Implement the MBAP header for TCP/IP communication\n    * #244:  [Web UI] Alphabetical ordering of metatype labels option in ListBoxes\n\n  * Merged no issue-related Pull Requests:\n    * #1370: Fixed connection status icon at page load.\n    * #1365: Fixed deleted factory components not always being removed from snapshot (see also #1371)\n    * #1364: Fixed factory components not being created from uploaded snapshot\n    * #1352: Minor Wires fixes\n    * #1350: Set security level to low\n    * #1349: Changes to the emulator launch profiles used when cloning directly the repo\n    * #1347: Modified emulator position.\n    * #1344: Minor fixes regarding emulator.position and osgi.annotation.\n    * #1343: Hidden export to CSV buttons from Wires Web UI\n    * #1341: Modified Asset Cloudlet protocol\n    * #1340: Fixed selinux check in kura-install.sh file.\n    * #1339: Changes to have dev-env working.\n    * #1337: Fixed watchdog service deactivate method\n    * #1331: Switched equinox mirror.\n    * #1323: Fixed handling of special characters in Wires DB\n    * #1319: Moved Asset configuration constants and documentation out of the APIs.\n    * #1311: Set the wire publisher qos metatype value to 0.\n    * #1307: Add Everyware Cloud broker URL\n    * #1302: Added opcua dp build step.\n    * #1300: Fix modem driver code\n    * #1289: Cleanup the payload encoder a bit\n    * #1276: Asset cloudlet now starts immediately.\n    * #1273: Watchdog code refactor and improvements\n    * #1272: Improved performance of WireSupportImpl.emit()\n    * #1266: Fixed unnecessary allocations by WireAsset\n    * #1264: Heater demo example using Maven/BND.\n    * #1256: Make private method static\n    * #1238: Remove registration of service implementation classes\n    * #1234: [Developer workspace] Updated project setup\n    * #1227: Relax null handling, fix possible NPE, improve javadoc\n    * #1226: Allow providing an input stream for reading XML content\n    * #1224: Make it a functional interface\n    * #1200: Add feature for Camel API\n    * #1198: Changed wires component selection.\n    * #1194: Fix iptables-restore run in background\n    * #1192: WireEmitter/Receiver are ConsumerTypeS\n    * #1184: Partially revert net.wifi breaking change\n    * #1182: Removed timeout based on magic number.\n    * #1179: Drop support for \"fedorapi\"\n    * #1174: Switch default behavior to only track relevant services\n    * #1173: OPC-UA Driver: Minor Fixes and Cleanup\n    * #1168: Modified emulator launch.\n    * #1154: Use window.parent instead of top in wires js and GWT parts\n    * #1148: Enable JMX by default, allow overriding using system properties\n    * #1144: [Developer workspace] Added 2 plugins and worspaces\n    * #1143: Added support for enabling serial rx timeout\n    * #1140: Improve separation of concerns for camel java example\n    * #1136: Implement Kapua's applicationFramework/applicationFrameworkVersion\n    * #1127: Changes to prevent exception of wires panel refresh.\n    * #1122: Implement new Cloud Client API\n    * #1115: Few more fixes in wires:\n    * #1103: Added drag and drop support to the Wire Composer.\n    * #1102: Improved drag and drop for Eclipse Marketplace.\n    * #1099: Set of changes in EventHandlerServlet to prevent memory leak.\n    * #1097: Check modem up in resetModem method\n    * #1094: Modified jvm dependency.\n    * #1090: Modified interval check in GwtNetworkServiceImpl.java.\n    * #1088: Fixed Web Ui services search bar\n    * #1086: OPC-UA Driver\n    * #1085: Wires refactor 2\n    * #1084: Wire Service Implementation and Wire Configuration Refactoring\n    * #1083: Removing ThrowableUtil Reference\n    * #1076: Wire publisher can publish control messages.\n    * #1075: Fixed a few cases in Configuration Service where NPE could be thrown\n    * #1074: Minor Code Fixes in PropertiesUi for Wires\n    * #1073: Renamed asset cloudlet APP_ID to ASSET-V1.\n    * #1070: Modified log message in ConfigurationServiceImpl.java\n    * #1058: Wires related Web2 enhancements\n    * #1047: Extracted WireHelperService and WireSupport together to a new bundle\n    * #1043: Modified certificates policy in Cloud Service.\n    * #1036: Solved graphical glitch in Assets' channel definition.\n    * #1034: Fix a bunch of C code issues\n    * #1031: Fix wire component provider\n    * #1029: Fix a possible NPE in the Web UI\n    * #1028: Work around Kura sending empty string instead of null for Camel deps\n    * #1019: Fix private members\n    * #1010: Updates and fixes for Karaf\n    * #1005: Fix possible exception and service leak\n    * #1002: Fix M2E errors when directly importing Karaf projects\n    * #998:  Fix wires nulls\n    * #988:  Removed references to windows bundles in 2.1.0.\n    * #987:  Modified web2 bundle packaging.\n    * #986:  Add Eclipse Kura Nexus repository in order to fix the build\n    * #985:  Switch version of SODA Comm to 1.2.4-SNAPSHOT\n    * #982:  Activate maven batch mode by default and reduce console log\n    * #978:  Uniformed build steps, corrected some typos.\n    * #976:  Changed deb dependency requiring java 8.\n    * #953:  Convert P2 repository to Maven 2 repository\n    * #869:  Clean up and document IOUtil\n    * #868:  Fix concurrency issue in command service\n    * #803:  add pcengine-nn profile\n\n\nKnow Issues :\n  * The implementation of the CryptoService performs encryption using a\n    password that is hardcoded and published.\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was\n    \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\".\n    Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease)\n    (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on\n    gatttool and the BLE connection failes.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network\n    interface which happened even if network configuration hasn't been modified.\n  * #1338: [Kura 3.0.0] camel.aggregation and camel.quickstart examples should be normalized\n  * #1325: [Wires] Exception if an Channel Descriptor contains in Option of Integer type\n  * #1201: Wifi password incorrectly read from snapshot in Access Point mode\n  * #1197: [Net] Network configuration cannot be restored purely from snapshot\n  * #1196: [Net] PPP password is not a (MetaType) Password\n  * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot\n  * #1193: [Wires] Component avoidance during initial placement\n  * #1161: Incorrectly configuring a component can be irreversable.\n  * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services\n  * #1092: Possible NPE and non-working check\n  * #1016: ConfigurationServiceImpl creates duplicate instances\n  * #948:  [Kura 2.1.0 QA] NET-ETH0-014 Wrong lease time in DHCP mode\n  * #923:  [Kura 2.1.0 QA] eth0 search domain configuration and storage\n  * #910:  [Kura 2.1.0 QA] Unable to use WLAN as WAN interface\n  * #890:  [Kura 2.1.0 QA] Snapshot management in web UI\n  * #797:  Design of ServiceUtil is broken\n  * #771:  Web UI fails with INTERNAL_ERROR when WireHelperService is not registered\n  * #752:  [DbDataStore] repair is very slow on big tables\n  * #751:  [DbDataStore] defrag and checkpoint are not per-table operations\n  * #654:  Clean up static initialization around \"modem\" functionality\n  * #651:  Call to \"exit()\" in native code\n  * #650:  Possible bug in \"LinuxUdev.c\"\n  * #645:  Clean up internal dependencies in Kura\n  * #572:  Unreadable errors in Web UI\n  * #558:  Update of DPs seems not to work\n  * #547:  [Configuration] Configuration Service may miss configuration-policy=optional components\n  * #522:  [Net] Modem monitor should monitor interfaces, not modems\n  * #520:  [Net] PppFactory is not a factory and its design is wrong\n  * #518:  [Net] Modem monitor concurrency issue with multiple modems\n  * #486:  Build environment broken on Windows\n  * #406:  Replace System.get* with calls to SystemService.getProperties\n  * #362:  Uninstaller leaves most of the files\n  * #329:  [DEPLOY-V2] Review/refactoring needed\n  * #311:  [Multiple Cloud Connections] Spurious component reactivations upon configuration change\n  * #307:  CloudCallService overrides client ID\n  * #297:  [Status led] What connection instance controls the status led?\n  * #253:  Check if bundle contexes correctly unget services after invoking getService\n  * #222:  CloudConnectionStatusServiceImpl does not cancel workers on component deactivation\n  * #108:  CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device\n\n\nEclipse Kura - 2.1.0\n-------------------------------------------------------------------------\nAdded Features :\n  * Apache Camel Integration\n  * New UI for Cloud Services\n  * Support for Raspbian on Raspberry Pi 3\n  * Support for Fedora on Raspberry Pi 2 and 3\n\nBug Fixes :\n  * Fixed github issues:\n    * #958: [Kura 2.1.0 QA] Wrong labels in UI's DHCP&NAT configuration\n    * #956: [Sec] Kura firewall rules bypassed with IPv6\n    * #941: [Kura 2.1.0 QA] Raspberry Pi 3 no-net installer\n    * #930: [Kura 2.1.0 QA] Problems with installation of Kura on BeagleBone Black\n    * #917: [Kura 2.1.0 QA] Wrong range messages\n    * #912: [Kura 2.1.0 QA] Exceptions while deploying example service\n    * #909: [Kura 2.1.0 QA] SSID selection dialog too small\n    * #903: [Kura 2.1.0 QA] Impossible to enter multiple DNS servers\n    * #901: [Kura 2.1.0 QA] changing username/password locks out admin access\n    * #900: [Kura 2.1.0 QA] usbutils missing in fedberry README\n    * #895: [Kura 2.1.0 QA] Refreshing configuration in web UI\n    * #893: [Kura 2.1.0 QA] GPIO example bundle configuration\n    * #883: Invalid field validation state when switching from WAN to LAN\n    * #879: [Kura 2.1.0 QA] Raspberry Pi 3 nameserver\n    * #877: [Kura 2.1.0 QA] eth0 netmask configuration\n    * #876: [Kura 2.1.0 QA] Disabling eth0 interface doesn't work properly\n    * #874: [Kura 2.1.0 QA] eth0 DNS server configuration\n    * #867: [Kura 2.1.0 QA] Ethernet interface gateway configuration on Raspberry Pi 3\n    * #860: [Kura 2.1.0 QA] JUnit in Raspberry Pi 3's installation package\n    * #859: [Kura 2.1.0 QA] Installation warnings/errors on Raspberry Pi 3\n    * #851: [Web-UI] Label is sent instead of value for metatype parameters with options\n    * #835: [Kura 2.1.0] Bind/Named service doesn't work properly on Fedora\n    * #793: [Kura 2.1.0] QA for the User Workspace\n    * #776: Serialization issue in cloud window\n    * #767: Change Housekeeping schedule from scheduleAtFixedRate to scheduleWithFixedDelay\n    * #753: libhidapi not correctly compiled for armv5\n    * #743: WLAN not detected as WLAN on Fedberry\n    * #742: Unable to establish stable network connection on Fedberry\n    * #732: Unable to configure CloudService instance when component gets unregistered\n    * #724: [Release 2.1.0] Check API packages\n    * #716: Create a simple Camel Java DSL based example publisher\n    * #692: Drop default to 255 characters on data entry\n    * #691: NPE when CloudService isn't configured\n    * #683: Control Prefix in Request/Response\n    * #660: [kura-build] jdk.dio deployment fails in Hudson\n    * #649: Missing copyright headers\n    * #642: Raspbian Pi3\n    * #641: [Camel] KuraCloudConsumer - Failed to subscribe exception\n    * #640: [Modem] NoClassDefFoundError: Could not initialize class org.eclipse.kura.linux.net.modem.SupportedUsbModems\n    * #635: ExecCommand in org.eclipse.kura.linux.bluetooth.BluetoothAdapterImpl Index Out Of Bounds\n    * #627: Fix Bundle-Vendor to \"Eclipse Kura\"\n    * #619: Duplicate version of maven-antrun-plugin\n    * #618: Recent CR/LF fix causes 182 file modification pending\n    * #613: Recent addition of checkstyle fails the build\n    * #603: Can \"json 20090211\" be removed?\n    * #599: WebUI fails completely is `PositionService` is not registered\n    * #596: Replace all calls to ConfigurationAdmin.getConfiguration(String)\n    * #595: ComponentMetaTypeBundleTracker is processing every bundle twice on startup\n    * #592: Again Java 7 code in BREE 6 bundle\n    * #589: [Camel] Camel related exceptions on Kura startup\n    * #581: Missing Package Info in few packages in API Bundle\n    * #573: Commit 41c3180 breaks data entry\n    * #571: Convert files from dos 2 unix format\n    * #564: [Configuration] ConfigurationService doesn't set properly the kura.service.pid\n    * #562: Services UI not getting updated with new properties\n    * #557: Add SLF4J jcl-over-slf4j\n    * #548: Kura 2 Webui on BeagleboneBlack Problem\n    * #544: Web UI shows red-connector although state is CONNECTED\n    * #540: [Web UI] Empty Integer field in a configuration (not required) is causing a NumberFormatException\n    * #539: [Cloud] Required changes in CloudServiceFactory\n    * #521: Device -> Threads shows empty list\n    * #515: [Web UI] Implement Cloud Services UI\n    * #511: Upgrade SLF4J to 1.7.21\n    * #509: [Web 2] ServicesUi validation\n    * #497: SystemServiceImpl uses method from Java 7 but declares a BREE of Java 6\n    * #496: mToolkit Eclipse Plugin does not work under Eclipse Neon\n    * #488: Command cloud App Null Pointer Exception\n    * #485: Change b02bc9a7615ca559349f2b05485ea84fd80d6e77 breaks deployment of \"sun.misc\" bundles\n    * #473: org.eclipse.kura.linux.net.modem.ModemDriver uses Java 7 API but has BREE of Java 6\n    * #467: Web UI cannot handle Integer with cardinality 0/optional\n    * #465: CloudService.isConnected not shown in Web UI\n    * #461: Registering a component which has a PID without dot crashes the Web UI 2\n    * #451: setting a payload metric to null should throw an exception immediately\n    * #444: Multiple Cloud Support - Web UI does not allow to select new installed cloud service\n    * #419: Migrate ASF camel-kura code to Eclipse\n    * #403: Fix javadoc for the getKuraVersion() method of the SystemService.\n    * #396: iwScanTool fails to parse scan results\n    * #343: [Web2]: Setting the \"name\" property to anything different than the \"id\" sets an empty value\n    * #342: [Configuration] Support multiple configurations for SelfConfiguringComponentS\n    * #339: [Web UI] The Disconnect button in the Status menu disconnects all connections\n    * #337: [Web2]: Field validation errors not shown\n    * #326: org.eclipse.kura.web2 is missing about.html\n    * #321: No support for systemd based systems\n    * #318: There should be Oomph based setups for Kura\n    * #315: The Kura documentation should mention the default login credentials admin/admin\n    * #314: The Camel Quickstart example is not working\n    * #281: Add XML routes configuration per Camel CloudService\n    * #265: Camel Examples: review\n    * #262: Maven failure when dev-env isn't built\n    * #257: KuraComponent can't resolve its collaborators\n    * #234: [Web UI] web2 network configuration glitch\n    * #231: Create Maven plugin capable of wrapping regular bundles in DP packages\n    * #221: [Camel] Do we need a Camel API in the org.eclipse.kura.api bundle?\n    * #216: [Test] Test Kura on RaspberryPi 3\n    * #205: All languages from Camel Core should be loaded by CamelRouter\n    * #204: All data formats from Camel Core should be loaded by CamelRouter\n    * #189: [Camel] Camel integration in the Kura CloudService\n    * #119: [Camel] Migrate CamelRouter tests from Rhiot to Kura\n\n  * Merged no issue-related Pull Requests:\n    * #962: Added libudev for rhel based devices\n    * #928: [Web-Ui] Fixed typo in the network config section\n    * #898: Solved modem reset failure.\n    * #855: Modified wrong entry in snapshot 0s\n\t* #816: Set the 'kura.ui.service.hide' property\n    * #810: Remaining changes to Camel Web UI\n    * #805: Prepend kura- to modem log files.\n    * #802: Try a fix for the startup exception, missing \"kura-cloud\"\n    * #798: Add Fedora 24 based ARM7 native library\n    * #765: Reverts change in commit 7704d180296551b0acb68044f7cd6b4c3e77f56a\n    * #761: Allow camel component to be initialized\n    * #756: Allow Camel modules to gracefully handle missing dependencies\n    * #755: Allow automatic conversion from Map to KuraPayload\n    * #745: Solved possible IllegalArgumentException due to null pid\n    * #744: Fixed wifi scan in AP mode\n    * #739: Solved possible 404 error when downloading snapshot\n    * #730: WiFi switching between Station and Access Point is unreliable\n    * #720: Fix wifi issues 2.1.0\n    * #717: Lower camel imports to 2.17.0\n    * #700: Fix Watchdog disabling bug in WatchdogService.\n    * #699: Add DependencyManagement to Camel Examples\n    * #698: Fix ble process leak\n    * #697: Export ConfigurableComponent in service xml\n    * #694: Fix Camel imports\n    * #662: Implement a workaround for issue #590\n    * #643: Clean up imports for Camel\n    * #630: Minor cleanups to the Linux ClockServiceImpl\n    * #625: Kura should not publish modified artifacts under \"org.eclipse\" namespace\n    * #624: Let example services export ConfigurableComponent\n    * #607: Start the Web UI component immediately\n    * #605: Fix a few resource leaks\n    * #602: Initial support for building a version for PC Engines APU / Debian 8\n    * #594: Implement missing method 'unsetSystemService'\n    * #578: Cleanup dead code\n    * #563: clean up some source code issues\n    * #560: Fixed bug on ConfigurationService about kura.service.pid\n    * #552: Support for RPi running Fedora via Fedberry, Pidora, etc.\n    * #546: Minor fixes for the startup scripts\n    * #542: Re-use existing code to parse kura.properties\n    * #530: Fix service leak in ComponentUtil\n    * #528: Fix the lookup of the default value, now done by id.\n    * #513: Follow Eclipse trademark guidelines\n    * #508: Refactor Camel router\n    * #501: Enh build deploy\n\n\nKnow Issues :\n  * The implementation of the CryptoService performs encryption using a\n    password that is hardcoded and published.\n  * Kura can be run in a Java 8 VM, but current OSGi container does not support bundles with manifests that specify\n    a \"Bundle-RequiredExecutionEnvironment\" equal to \"JavaSE-1.8\".\n  * The old GPS position will continue to be shown in the status overview even after the disabling of the static position reporting.\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was\n    \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\".\n    Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease)\n    (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on\n    gatttool and the BLE connection failes.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network\n    interface which happened even if network configuration hasn't been modified.\n  * #948: [Kura 2.1.0 QA] NET-ETH0-014 Wrong lease time in DHCP mode\n  * #923: [Kura 2.1.0 QA] eth0 search domain configuration and storage\n  * #918: [Kura 2.1.0 QA] DEN-POS-002 Position service keeps reporting old position\n  * #916: [Kura 2.1.0 QA] DEN-CONF-005 Wrong range limit for \"long\"\n  * #915: [Kura 2.1.0 QA] DEN-CONF-005: Internal message when a \"too big\" number is entered\n  * #914: [Web UI] Fixed fields can be edited\n  * #911: [Kura 2.1.0 QA] SSID selection not always shows all SSIDs\n  * #910: [Kura 2.1.0 QA] Unable to use WLAN as WAN interface\n  * #908: [Kura 2.1.0 QA] Web UI shows its own WLAN for connecting\n  * #890: [Kura 2.1.0 QA] Snapshot management in web UI\n  * #889: [Kura 2.1.0 QA] Denali Configuration ExamplePublisher error descriptions\n  * #778: [Net] Refactor needed in org.eclipse.kura.core.net\n  * #752: [DbDataStore] repair is very slow on big tables\n  * #751: [DbDataStore] defrag and checkpoint are not per-table operations\n  * #737: Fedora distribution fails to start up\n  * #736: Kura installer continues despite errors occurred\n  * #725: Serial receive timeout is not forwarded to javax.comm.CommPort\n  * #721: Unnecessary toggles eth0 interface when wlan0 interface is disabled on Raspberry Pi.\n  * #696: FileServlet fails with NPE when there is no MetaTypeInformation\n  * #664: Misconfiguration of eth0 (as dhcp server) filling /var/log directory and finally crashing kura\n  * #654: Clean up static initialization around \"modem\" functionality\n  * #651: Call to \"exit()\" in native code\n  * #650: Possible bug in \"LinuxUdev.c\"\n  * #645: Clean up internal dependencies in Kura\n  * #572: Unreadable errors in Web UI\n  * #558: Update of DPs seems not to work\n  * #553: [Modbus] Refactoring of Modbus example\n  * #550: [Modbus] String evaluation returns false\n  * #547: [Configuration] Configuration Service may miss configuration-policy=optional components\n  * #522: [Net] Modem monitor should monitor interfaces, not modems\n  * #520: [Net] PppFactory is not a factory and its design is wrong\n  * #518: [Net] Modem monitor concurrency issue with multiple modems\n  * #406: Replace System.get* with calls to SystemService.getProperties\n  * #362: Uninstaller leaves most of the files\n  * #329: [DEPLOY-V2] Review/refactoring needed\n  * #311: [Multiple Cloud Connections] Spurious component reactivations upon configuration change\n  * #307: CloudCallService overrides client ID\n  * #297: [Status led] What connection instance controls the status led?\n  * #288: [Modbus] Implement the MBAP header for TCP/IP communication\n  * #253: Check if bundle contexes correctly unget services after invoking getService\n  * #235: LinuxNetworkUtil#toolExists() should check for tool's existence in PATH\n  * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation\n  * #172: Modem: manually killing pppd with Kura running never triggers a modem reset\n  * #108: CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device\n  * #104: org.eclipse.kura.linux.net.ConnectionInfoImpl is IPv4 only\n\n\nEclipse Kura - 2.0.2\n-------------------------------------------------------------------------\nBug Fixes :\n  * Merged no issue-related Pull Requests:\n    * #653: Hotfixes for WiFi for the 2.0.2 service release. This addresses\n\t        Kura not restarting hostapd if the service has stopped for some reason.\n\t* #652: This is a hotfix for a process leak in Bluetooth LE when calling hcidump.\n\nKnow Issues :\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was\n    \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\".\n    Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease)\n    (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on\n    gatttool and the BLE connection failes.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network\n    interface which happened even if network configuration hasn't been modified.\n  * #467: Web UI cannot handle Integer with cardinality 0/optional\n  * #465: CloudService.isConnected not shown in Web UI\n  * #462: ConfigurationServiceImpl cannot handle cardinality >1 for SelfConfiguringComponent\n  * #461: Registering a component which has a PID without dot crashes the Web UI 2\n  * #444: Multiple Cloud Support - Web UI does not allow to select new installed cloud service\n  * #396: iwScanTool fails to parse scan results\n  * #362: Uninstaller leaves most of the files\n  * #355: [Semantic Versioning] org.eclipse.kura.net.wifi version should be increased from 1.2.0 to 1.3.0\n  * #343: [Web2]: Setting the \"name\" property to anything different than the \"id\" sets an empty value\n  * #339: [Web UI] The Disconnect button in the Status menu disconnects all connections\n  * #337: [Web2]: Field validation errors not shown\n  * #329: [DEPLOY-V2] Review/refactoring needed\n  * #314: The Camel Quickstart example is not working\n  * #311: [Multiple Cloud Connections] Spurious component reactivations upon configuration change\n  * #307: CloudCallService overrides client ID\n  * #299: On Red Hat Fedora, network-scripts can contain double quotes\n  * #297: [Status led] What connection instance controls the status led?\n  * #288: [Modbus] Implement the MBAP header for TCP/IP communication\n  * #262: Maven failure when dev-env isn't built\n  * #257: KuraComponent can't resolve its collaborators\n  * #253: Check if bundle contexes correctly unget services after invoking getService\n  * #235: LinuxNetworkUtil#toolExists() should check for tool's existence in PATH\n  * #234: [Web UI] web2 network configuration glitch\n  * #224: Fixed modem reset and kura restart issues for gps\n  * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation\n  * #174: Networking: check why sometimes eth0 is toggled on wlan0 reconfiguration\n  * #172: Modem: manually killing pppd with Kura running never triggers a modem reset\n  * #108: CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device\n  * #104: org.eclipse.kura.linux.net.ConnectionInfoImpl is IPv4 only\n  * #77: Data Service will not connect for other locale than an english one\n\n\nEclipse Kura - 2.0.1\n-------------------------------------------------------------------------\n\nBug Fixes :\n  * Fixed github issues:\n    * #473: org.eclipse.kura.linux.net.modem.ModemDriver uses Java 7 API but has BREE of Java 6\n    * #468: [Web] NPE in GwtNetworkServiceImpl\n    * #464: Beaglebone install script not creating /etc/sysconfig\n    * #393: [NN] NN profiles are broken in Kura 2.0.0\n    * #373: Kura 2.0.0 distribution for Raspberry-Pi includes emulator.gpio instead of linux.gpio\n    * #340: [Configuration] Metatype not updated in the Web UI\n    * #338: [Web2]: String input forced to a maximum length of 255\n    * #316: Debian package should declare dependency on java\n    * #296: [Web UI] Status | Connection: if the connection username is not set, \"null\" is shown\n    * #290: [Web UI] Refresh button in network configuration deselects the currently selected interface\n    * #289: [Web UI] Wireless Password disappears after verification\n    * #275: [Dev Env] Add org.eclipse.kura.linux.bluetooth to the target-platform.\n    * #242: [Web UI] Help is not always visible in the new web ui\n\n  * Merged no issue-related Pull Requests:\n    * #489: Modified check for crypto value in isDefaultPassword.\n    * #484: Modified wrong references in some snapshots, modified sslManager service to perform a\n            different check for the default password and the password change.\n    * #483: Modified launch configurations.\n    * #480: Fix firewall issues\n    * #475: Hotfix ble fixes\n    * #441: JDK DIO: disable verbose logging from armv5_sf and x86_64 libraries.\n    * #440: Modified the configuration service to prevent the generation of empty snapshots.\n    * #439: Refactored code, modified behavior with gpio calculation from base address + offset.\n    * #438: Added more checks in ServicesUI to prevent possible exception. Removed servicesUi refresh at every click in status section.\n    * #431: Fix missing license headers\n    * #428: Fix missing camel bundle in dev workspace\n    * #417: Fix logging of exceptions and clean up other logging calls\n    * #404: Fix a possible NPE followed by a NCDFE when system property is missing\n    * #402: Fix two NullPointerExceptions and improve the error output\n    * #400: Fix build warnings\n    * #395: Remove dependency on slf4j-log4j12\n    * #388: Modified snapshot_0s in order to have memory persistance for in-flight messages.\n    * #382: Use a copy-on-write list in order to support concurrent modifications\n    * #361: Use Import-Package in preference of Require-Bundle\n    * #351: Pom cleanup\n    * #347: Reset the original state of the accessible flag\n    * #346: Clean up the error output to actually print out stack traces\n    * #336: Corrected jacoco version due to build failure in JDK8\n    * #328: Fix output of executed commands\n    * #325: Fix a possible Context Class Loader leak\n    * #320: Provide Oomph setup and clean up build issue\n\n\n\nKnow Issues :\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was\n    \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\".\n    Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease)\n    (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on\n    gatttool and the BLE connection failes.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network\n    interface which happened even if network configuration hasn't been modified.\n  * #467: Web UI cannot handle Integer with cardinality 0/optional\n  * #465: CloudService.isConnected not shown in Web UI\n  * #462: ConfigurationServiceImpl cannot handle cardinality >1 for SelfConfiguringComponent\n  * #461: Registering a component which has a PID without dot crashes the Web UI 2\n  * #444: Multiple Cloud Support - Web UI does not allow to select new installed cloud service\n  * #396: iwScanTool fails to parse scan results\n  * #362: Uninstaller leaves most of the files\n  * #355: [Semantic Versioning] org.eclipse.kura.net.wifi version should be increased from 1.2.0 to 1.3.0\n  * #343: [Web2]: Setting the \"name\" property to anything different than the \"id\" sets an empty value\n  * #339: [Web UI] The Disconnect button in the Status menu disconnects all connections\n  * #337: [Web2]: Field validation errors not shown\n  * #329: [DEPLOY-V2] Review/refactoring needed\n  * #314: The Camel Quickstart example is not working\n  * #311: [Multiple Cloud Connections] Spurious component reactivations upon configuration change\n  * #307: CloudCallService overrides client ID\n  * #299: On Red Hat Fedora, network-scripts can contain double quotes\n  * #297: [Status led] What connection instance controls the status led?\n  * #288: [Modbus] Implement the MBAP header for TCP/IP communication\n  * #262: Maven failure when dev-env isn't built\n  * #257: KuraComponent can't resolve its collaborators\n  * #253: Check if bundle contexes correctly unget services after invoking getService\n  * #235: LinuxNetworkUtil#toolExists() should check for tool's existence in PATH\n  * #234: [Web UI] web2 network configuration glitch\n  * #224: Fixed modem reset and kura restart issues for gps\n  * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation\n  * #174: Networking: check why sometimes eth0 is toggled on wlan0 reconfiguration\n  * #172: Modem: manually killing pppd with Kura running never triggers a modem reset\n  * #108: CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device\n  * #104: org.eclipse.kura.linux.net.ConnectionInfoImpl is IPv4 only\n  * #77: Data Service will not connect for other locale than an english one\n\n\nEclipse Kura - 2.0.0\n-------------------------------------------------------------------------\n\nAdded Features :\n  * Added support for multiple connections\n  * Added support for Wi-Fi Multi Mode\n  * Created a new web UI bundle named org.eclipse.kura.web2 that integrates GWT 2.7 and GwtBootstrap 3 technologies\n  * Updated bluetooth APIs and added support for Bluez 5.x\n  * Initial integration of RedHat's Camel stack\n  * Created a Kura applications section inside the Eclipse marketplace and added support in the local web UI for the application\n    install via drag-and-drop\n  * Created SenseHat example project\n  * Updated the SensorTag Example project exposing buzzer and leds\n  * Created the beacon.scanner project\n  * Native libraries now support x86_64\n  * Reviewed/refactored the GPS position service\n\nBug Fixes :\n  * Fixed github issues #78, #82, #96, #98, #112, #113, #114, #116, #120, #121, #127, #128, #129, #131,\n    #134, #138, #139, #141, #143, #167, #169, #177, #179, #182, #184, #187, #188, #193, #198, #199, #201,\n    #202, #203, #209, #212, #214, #215, #218, #227, #228, #229, #230, #233, #238, #241, #250, #252, #254,\n    #255, #256, #258, #260, #267, #270, #271, #272, #279, #284, #302, #309\n\n\nKnow Issues :\n  * Multiple connections: updating a service (e.g. MqttDataTransport) of a connection\n    has the effect to cause the unwanted reactivation of the next higher layer service (i.e. DataService)\n    of the other connection(s). This in turn will cause the reactivation of all dependent components.\n    This is not desired and not yet understood (Equinox bug?). See also Github issue #311.\n  * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required.\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\". Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on gatttool and the BLE connection failes.\n    The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it\n    must be compiled from sources.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipset.\n  * The reference JVMs are Oracle Java SE Embedded version 7 Update 40 and Java SE Embedded version 8 Update 65.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by\n    ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin.\n  * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network interface which happened even if network configuration hasn't been modified.\n\n\n\nEclipse Kura - 1.4.0\n-------------------------------------------------------------------------\n\nAdded Features :\n  * Grouped Web UI SSL configuration in a single place under 'Settings'\n  * Modified the Web UI adding a check in order to block SSIDs longer than 32 characters\n  * Rolled-back Web UI filtering of SSID\n  * Added some security headers to the Web UI\n  * Refactored security related tabs in the Web UI\n  * Added property to the WatchdogService to specify the watchdog device\n  * Modified build in order to include checks for Java 8 compact 2 compliance\n  * Introduced new deployment application (named DEPLOY-V2) that improves updates download from the cloud platform\n  * New firewall management, now based on iptables-save and iptables-restore\n  * Firewall: allowed open port entries for tcp and udp on the same port\n  * Firewall: enabled the support for port ranges when defining open port entries\n  * Added support for Ublox SARA-U2 modem\n  * Added support to switch between AP and station mode on radios supported by the 'bcmdhd' kernel module\n  * Emulator bundle split into 6 separate bundles, one for each function\n  * Reviewed no-network profiles: removed net.admin bundle and linux.net. Now those bundles are replaced by emulator.net\n  * Linux build date/version is now published in the birth certificate as part of the os.version metric\n  * Improvements to the Development Environment\n  * ConfigurationService: treat an OSGi ManagedService as a ConfigurableComponent\n  * Updated documentation\n\nBug Fixes :\n  * Fixed github issue #80\n  * Fixed github issue #84\n  * Fixed github issue #85\n  * Fixed github issue #87\n  * Fixed configuration rollback to snapshot 0\n  * Fixed toggling WiFi interface when Ethernet interface is reconfigured\n  * Better Web UI exception handling when manually (dis)connecting to the Cloud\n  * Added various null pointer checks\n  * Started work to fix warnings emitted by Sonar\n  * Fixed JUnit tests\n  * Fixed GPIO example\n  * Fixed bug when image in metatype has no size\n  * Fixed and improved the BLE TI SensorTag example\n\nKnow Issues :\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was \"Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux\". Note that on the kernel \"Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015\" has a bug on gatttool and the BLE connection failes.\n    The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it\n    must be compiled from sources.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipest.\n  * The reference JVMs are Oracle Java SE Embedded version 7 Update 40 and Java SE Embedded version 8 Update 65.\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by\n    ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin.\n  * Web UI may hang when configuration snapshot is apploaded. This happens because HTTP connection is lost due to toogling of the network interface which happened even if network configuration hasn't been mo\t   dified.\n\n\n\nEclipse Kura - 1.3.0\n-------------------------------------------------------------------------\n\nAdded Features :\n  * API updates (Security, GPIOService)\n  * Enhanced web UI security, which includes:\n    * XSRF protection in all servlets\n    * Different management of user sessions\n    * Arbitrary file writes protection in file servlet for zip uploads\n    * XSS on wireless SSID in network servlet\n    * Command injection on network servlet\n    * Password protection in client UI, in order to prevent access to secrets by unauthorized users\n    * Sanitization of user and system strings in order to prevent malicious attacks\n  * Ability to configure pairwise ciphers in AP mode in web UI.\n  * Ability to stop/start bundles from web UI.\n  * Ability to embed ConfigurableComponent icon within bundle, instead for requiring https location.\n  * Added support for Telit LE910 modems.\n  * Added test code for XML marshalling/unmarshalling.\n  * Removed Xss option from start scripts. This JVM option has a know bug in OpenJDK.\n  * Improvements to usability of Emulator.\n  * Improvements to the Development Environment.\n\nKnow Issues :\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag.\n    The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it\n    must be compiled from sources.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipest.\n  * The reference JVM is Oracle Java SE Embedded version 7 Update 40.\n    Later versions (including Oracle Java SE Embedded version 8 Update 33)\n    may be affected by a ProcessBuilder memory leak [1]\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by\n    ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin.\n  * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud.\n\n[1] https://bugs.openjdk.java.net/browse/JDK-8054841\n\nEclipse Kura - 1.2.2\n-------------------------------------------------------------------------\n\nAdded Features :\n  * Added support for Ubuntu 14.04. Note, this is just the initial support for Ubuntu, there are no installation files in this\n    release.\n\nKnown Issues :\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag.\n    The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it\n    must be compiled from sources.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipest.\n  * The reference JVM is Oracle Java SE Embedded version 7 Update 40.\n    Later versions (including Oracle Java SE Embedded version 8 Update 33)\n    may be affected by a ProcessBuilder memory leak [1]\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by\n    ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin.\n  * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud.\n\n[1] https://bugs.openjdk.java.net/browse/JDK-8054841\n\nEclipse Kura - 1.2.1\n-------------------------------------------------------------------------\n\nAdded Features :\n  * Added Bluetooth LE Beacon Service\n    * Example: org.eclipse.kura.example.beacon\n  * Reduced number of dependencies for Bluetooth LE bundle\n  * Added support for non cfg80211 wifi modules\n  * Added support for wifi on Raspberry Pi\n  * Added support for Oracle Java 8 SE Compact 2 Profile runtime\n  * Replaced IBM javax.usb implementation with usb4java\n  * Refactor and optimization of SSL Manager\n    * Improved security during keystore loading in SSL Manager\n  * Refactor of ConfigurationService\n  * Replace JAXB XML Parser with a custom one\n  * Startup time improvements due to various code optimizations and uncompressed jars\n  * Web UI: added the possibility to specify a custom web interface user\n  * Web UI: split certificate management in two separate tabs\n\nBug Fixes :\n  * Web UI: fixed wrong units for memory\n\nKnown Issues :\n  * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag.\n    The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it\n    must be compiled from sources.\n  * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset).\n    AccessPoint WiFi mode not working for Broadcom chipest.\n  * The reference JVM is Oracle Java SE Embedded version 7 Update 40.\n    Later versions (including Oracle Java SE Embedded version 8 Update 33)\n    may be affected by a ProcessBuilder memory leak [1]\n  * Hardware watchdog: not implemented on all platforms\n  * Only one WAN interface is currently supported. A warning in displayed\n    in the WEB UI if the user attempts to enable more than one WAN interface\n  * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by\n    ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin.\n  * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud.\n\n[1] https://bugs.openjdk.java.net/browse/JDK-8054841\n\nEclipse Kura - 1.2.0\n-------------------------------------------------------------------------\n\nAdded Features:\n   * Added support for securing Kura\n     * Revised org.eclipse.kura.crypto API.\n     * New org.eclipse.kura.certificate API to enable validation of\n       signed requests from the cloud.\n     * Minimal implementation of the org.eclipse.kura.crypto API.\n     * Implementation of the org.eclipse.kura.certificate API.\n     * Encryption of passwords in snapshot files.\n     * Snapshot encryption.\n     * Improved management and security of the keystore used for the MQTT\n       SSL connection.\n   * Added support for the Raspberry Pi B+ and the Raspberry Pi 2.\n   * Added support for Bluetooth Low Energy (see Known Issues section below).\n     * API: org.eclipse.kura.bluetooth\n     * Example: org.eclipse.kura.example.ble.tisensortag\n   * Added OSGi console commands (get/setkuraloglevel) to control the Kura logger.\n\nBug Fixes:\n   * Web UI: fixed wrong time units in the DHCP lease interval.\n   * Web UI: filter 5GHz channels when displaying WiFi scan results.\n   * Upgrade Deployment Package: remove the old Kura installation directory.\n   * MqttDataTransport configuration: changed default MQTT protocol version to 3.1.1.\n   * CloudService: even if gzip compression is enabled, publish the uncompressed\n     MQtt payload if its size is less than the compressed payload size.\n   * Network: Reduced executions of external ifconfig processes.\n   * Network: Fixed WiFi background scan configuration.\n\nKnown Issues:\n   * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag.\n     The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it\n     must be compiled from sources.\n   * The Intel Edison platform is still a work in progress.\n   * The reference JVM is Oracle Java SE Embedded version 7 Update 40.\n     Later versions (including Oracle Java SE Embedded version 8 Update 33)\n     may be affected by a ProcessBuilder memory leak [1]\n   * Hardware watchdog: not implemented on all platforms\n   * Only one WAN interface is currently supported. A warning in displayed\n     in the WEB UI if the user attempts to enable more than one WAN interface\n   * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by\n     ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin.\n   * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud.\n\n[1] https://bugs.openjdk.java.net/browse/JDK-8054841\n\n\nEclipse Kura - 1.1.2\n-------------------------------------------------------------------------\nBug Fixes:\n   * Fixed JVM memory leak by making sure all stream are closed and\n     the streams associated to the stdout and stderr of external processes\n     are consumed asynchronously\n   * Overall optimization of the network related bundles by removing\n     unnecessary executions of external processes\n   * Fixed MANIFESTs removing unused imports and fixing Import-Package version\n     ranges to comply with OSGi Semantic Versioning\n   * Ppp0 connection not starting after a fresh install\n   * Modem did not recover the connection when the antenna is unplugged\n   * Avoid starting two Kura instances\n   * Rolling back to snapshot 0 does not change the modem configuration on the Minigateway\n   * Don't allow to set the gateway on LAN interfaces\n   * When reconfiguring Wifi from Station to Access Point, DHCP&NAT tab gets enabled only\n     after clicking on the 'Wireless' tab\n   * Since we don't support 802.11a, do not allow this in configuration\n   * Poweroff command fails at 'Stopping Kura'\n   * Disable snmpd to avoid excessive flash writes on raw-flash devices\n\nKnown Issues:\n   * The reference JVM is Oracle Java SE Embedded version 7 Update 40.\n     Later versions (including Oracle Java SE Embedded version 8 Update 33)\n     may be affected by a ProcessBuilder memory leak [1]\n   * Hardware watchdog: not implemented on all platforms\n   * Only one WAN interface is currently supported. A warning in displayed\n     in the WEB UI if the user attempts to enable more than one WAN interface\n   * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by\n     ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin.\n   * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud.\n\n[1] https://bugs.openjdk.java.net/browse/JDK-8054841\n\n\nEclipse Kura - 1.1.1\n-------------------------------------------------------------------------\n\nAdded Features:\n   * Added configurable CommandService to password-protect command execution\n   * Added support to reset WiFi if it cannot be enabled\n   * Added selection of the MQTT protocol version to the MqttDataTransport configuration\n\nBug Fixes:\n   * Fixed ppp0 interface disappeared from Web UI\n   * Improved tips in the cellular modem advanced options and changed default values\n   * Fixed bug 452499: Kura Debian package name should be lower case\n   * Fixed org.eclipse.kura.linux.position not setting the track heading parameter\n   * Fixed org.eclipse.kura.linux.position to correctly select the GPS receiver\n   * Fixed org.eclipse.kura.linux.usb to better handle removal of USB devices\n   * Fixed org.eclipse.kura.linux.net to properly track USB add/remove events and stale devices\n   * Fixed org.eclipse.kura.net.admin to properly track modems\n   * Fixed org.eclipse.kura.net.admin to keep resetting the modem if PPP link cannot be established\n   * Fixed minor issues\n\nKnown Issues:\n   * Hardware watchdog: not implemented on all platforms\n   * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface\n\n\nEclipse Kura - 1.1.0\n-------------------------------------------------------------------------\n\nAdded Features:\n   * OpenJDK Device I/O integration\n   * Added org.eclipse.kura.example.gpio example using OpenJDK Device I/O\n   * Added RPI B+ distribution\n   * Display warning in the WEB UI if the user attempts to enable more than one WAN interface\n   * Modem IMEI and SIM IMSI/ICCID published in the birth certificate\n   * Improved documentation on the Eclipse Kura Wiki\n   * Upgraded to Google Protocol Buffers 2.6.0 (adding union types)\n   * Display client ID in the WEB UI Status page\n\nBug Fixes:\n   * Upticked API package versions to 1.0.0\n   * Fixed DNS issue when DNS servers are provided in the configuration\n   * Fixed 'iw' scan problem (IBSS capability)\n   * Fixed a MetaTypeBundleTracker issue slowing down the Kura startup\n   * Added a minimum value of two minutes for the modem reset interval\n   * Improved robustness of the Kura upgrade scripts\n   * Upgraded to Paho 1.0.1 (many bug fixes)\n   * Fixed uncaught exception preventing network interfaces being displayed in the WEB UI\n   * Set Paho client callback to null before terminating the client\n   * Removed 'old' native library directories\n   * Fixed WEB UI username/password lost for the in-memory configuration of HSQLDB\n   * Fixed HIDAPI bundle\n   * Fixed HSQLDB exception due to large system time adjustments\n   * Merged pull requests and contributions sent in the form o diff files to the mailing list\n   * Added 'telnet' to the list of 'apt' dependencies\n\nKnown Issues:\n   * Hardware watchdog: not implemented on all platforms\n   * Reliagate 50-21: Using eth1 and Windows 7 to access the webui does not work over some network topologies - OSX or Linux are recommended to access the webui in this rare case\n   * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface\n\n\nEclipse Kura - Initial Version\n-------------------------------------------------------------------------\n\nFeatures:\n   * Runs on Java SE 7 Embedded and OpenJDK 7\n   * Core OSGi runtime using Eclipse Equinox v3.8.1\n   * API support including:\n\t* Clock (both system clock syncing via NTP and hardware clock sync)\n\t* Cloud connections (MQTT) with local store and forward capabilities to handle disconnected states as well as Google Protobuf message packing\n\t* Service configuration locally and remotely via OSGi ConfigAdmin with Metatype support\n\t* Network status including IP address, netmask, DNS, gateway, and hardware types\n\t* Network administration: modifying network configuration including IP address, netmask, DNS, gateway, DHPC servers, Nat/Masq,\n\t\t\t\t  firewall, wifi AP, wifi station, SSID, wifi security types, wifi channel, and cellular modems, and\n\t\t\t\t  routing tables.\n\t* GPS configuration\n\t* USB devices including dynamic detection\n   * OSGi Deployment Package support\n   * Local configuration web UI\n   * Eclipse based emulator for local host PC development/testing including support for OSX and Linux\n   * Remote configuration and device management capabilities when connected to Eurotech's Everyware Cloud\n   * Support for remote OSGi console and bundle deployment from Eclipse\n\nKnown Issues:\n   * Hardware watchdog: not implemented on all platforms\n   * Reliagate 50-21: Using eth1 and Windows 7 to access the webui does not work over some network topologies - OSX or Linux are recommended to access the webui in this rare case\n   * Only one WAN interface is currently supported.  Make sure you never have multiple WAN interfaces defined or it could result in network connectivity issues\n"
  },
  {
    "path": "kura/distrib/aarch64-core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <artifactId>distrib</artifactId>\n        <groupId>org.eclipse.kura</groupId>\n        <version>6.0.0-SNAPSHOT</version>\n        <relativePath>..</relativePath>\n    </parent>\n\n    <artifactId>aarch64-core</artifactId>\n\n    <packaging>pom</packaging>\n\n    <properties>\n        <kura.basedir>../</kura.basedir>\n        <kura.arch>aarch64</kura.arch>\n        <target.device>${kura.arch}</target.device>\n        <arch>${kura.arch}</arch>\n        <deb.name>kura-core</deb.name>\n        <deb.architecture>arm64</deb.architecture>\n        <skip.resource.copy>false</skip.resource.copy>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <artifactId>maven-resources-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.vafer</groupId>\n                <artifactId>jdeb</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/distrib/core-dp/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <artifactId>distrib</artifactId>\n        <groupId>org.eclipse.kura</groupId>\n        <version>6.0.0-SNAPSHOT</version>\n        <relativePath>..</relativePath>\n    </parent>\n\n    <artifactId>core-dp</artifactId>\n\n    <packaging>pom</packaging>\n\n    <properties>\n        <kura.basedir>../</kura.basedir>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>core-dp</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <includeArtifactIds>\n                                org.eclipse.kura.protocol.modbus,\n                                org.eclipse.kura.driver.s7plc,\n                                org.eclipse.kura.driver.eddystone,\n                                org.eclipse.kura.driver.ibeacon,\n                                org.eclipse.kura.driver.gpio,\n                                org.eclipse.kura.driver.ble.xdk,\n                                org.eclipse.kura.db.sqlite.provider,\n                                org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider,\n                                org.eclipse.kura.cloudconnection.raw.mqtt.provider\n                            </includeArtifactIds>\n                            <includeTypes>dp</includeTypes>\n                            <outputDirectory>${project.build.directory}</outputDirectory>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/distrib/eclipse_license.txt",
    "content": "Copyright (c) ${dates} ${owner}\n \n This program and the accompanying materials are made\n available under the terms of the Eclipse Public License 2.0\n which is available at https://www.eclipse.org/legal/epl-2.0/\n \n SPDX-License-Identifier: EPL-2.0\n  \nContributors:\n  ${contributor}\n"
  },
  {
    "path": "kura/distrib/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/distrib/notice.html",
    "content": "\n<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>Eclipse Foundation Software User Agreement</title>\n</head>\n\n<body lang=\"EN-US\">\n<h2>Eclipse Foundation Software User Agreement</h2>\n<p>November 22, 2017</p>\n\n<h3>Usage Of Content</h3>\n\n<p>THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION,\n    INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS\n    (COLLECTIVELY &quot;CONTENT&quot;). USE OF THE CONTENT IS GOVERNED BY\n    THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND\n    CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n    BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS\n    GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY\n    APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED\n    BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS\n    AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE\n    AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT\n    USE THE CONTENT.</p>\n\n<h3>Applicable Licenses</h3>\n\n<p>\n    Unless otherwise indicated, all Content made available by the Eclipse\n    Foundation is provided to you under the terms and conditions of the\n    Eclipse Public License Version 2.0 (&quot;EPL&quot;). A copy of the\n    EPL is provided with this Content and is also available at <a\n        href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>Content includes, but is not limited to, source code, object\n    code, documentation and other files maintained in the Eclipse\n    Foundation source code repository (&quot;Repository&quot;) in software\n    modules (&quot;Modules&quot;) and made available as downloadable\n    archives (&quot;Downloads&quot;).</p>\n\n<ul>\n    <li>Content may be structured and packaged into modules to\n        facilitate delivering, extending, and upgrading the Content. Typical\n        modules may include plug-ins (&quot;Plug-ins&quot;), plug-in\n        fragments (&quot;Fragments&quot;), and features\n        (&quot;Features&quot;).</li>\n    <li>Each Plug-in or Fragment may be packaged as a sub-directory\n        or JAR (Java&trade; ARchive) in a directory named\n        &quot;plugins&quot;.</li>\n    <li>A Feature is a bundle of one or more Plug-ins and/or\n        Fragments and associated material. Each Feature may be packaged as a\n        sub-directory in a directory named &quot;features&quot;. Within a\n        Feature, files named &quot;feature.xml&quot; may contain a list of\n        the names and version numbers of the Plug-ins and/or Fragments\n        associated with that Feature.</li>\n    <li>Features may also include other Features (&quot;Included\n        Features&quot;). Within a Feature, files named\n        &quot;feature.xml&quot; may contain a list of the names and version\n        numbers of Included Features.</li>\n</ul>\n\n<p>The terms and conditions governing Plug-ins and Fragments should\n    be contained in files named &quot;about.html&quot;\n    (&quot;Abouts&quot;). The terms and conditions governing Features and\n    Included Features should be contained in files named\n    &quot;license.html&quot; (&quot;Feature Licenses&quot;). Abouts and\n    Feature Licenses may be located in any directory of a Download or\n    Module including, but not limited to the following locations:</p>\n\n<ul>\n    <li>The top-level (root) directory</li>\n    <li>Plug-in and Fragment directories</li>\n    <li>Inside Plug-ins and Fragments packaged as JARs</li>\n    <li>Sub-directories of the directory named &quot;src&quot; of\n        certain Plug-ins</li>\n    <li>Feature directories</li>\n</ul>\n\n<p>Note: if a Feature made available by the Eclipse Foundation is\n    installed using the Provisioning Technology (as defined below), you\n    must agree to a license (&quot;Feature Update License&quot;) during\n    the installation process. If the Feature contains Included Features,\n    the Feature Update License should either provide you with the terms\n    and conditions governing the Included Features or inform you where you\n    can locate them. Feature Update Licenses may be found in the\n    &quot;license&quot; property of files named\n    &quot;feature.properties&quot; found within a Feature. Such Abouts,\n    Feature Licenses, and Feature Update Licenses contain the terms and\n    conditions (or references to such terms and conditions) that govern\n    your use of the associated Content in that directory.</p>\n\n<p>THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY\n    REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND\n    CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT\n    ARE NOT LIMITED TO):</p>\n\n<ul>\n    <li>Eclipse Public License Version 1.0 (available at <a\n            href=\"http://www.eclipse.org/legal/epl-v10.html\">http://www.eclipse.org/legal/epl-v10.html</a>)\n    </li>\n    <li>Eclipse Distribution License Version 1.0 (available at <a\n            href=\"http://www.eclipse.org/licenses/edl-v10.html\">http://www.eclipse.org/licenses/edl-v1.0.html</a>)\n    </li>\n    <li>Common Public License Version 1.0 (available at <a\n            href=\"http://www.eclipse.org/legal/cpl-v10.html\">http://www.eclipse.org/legal/cpl-v10.html</a>)\n    </li>\n    <li>Apache Software License 1.1 (available at <a\n            href=\"http://www.apache.org/licenses/LICENSE\">http://www.apache.org/licenses/LICENSE</a>)\n    </li>\n    <li>Apache Software License 2.0 (available at <a\n            href=\"http://www.apache.org/licenses/LICENSE-2.0\">http://www.apache.org/licenses/LICENSE-2.0</a>)\n    </li>\n    <li>Mozilla Public License Version 1.1 (available at <a\n            href=\"http://www.mozilla.org/MPL/MPL-1.1.html\">http://www.mozilla.org/MPL/MPL-1.1.html</a>)\n    </li>\n</ul>\n\n<p>IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND\n    CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License,\n    or Feature Update License is provided, please contact the Eclipse\n    Foundation to determine what terms and conditions govern that\n    particular Content.</p>\n\n\n<h3>Use of Provisioning Technology</h3>\n\n<p>\n    The Eclipse Foundation makes available provisioning software, examples\n    of which include, but are not limited to, p2 and the Eclipse Update\n    Manager (&quot;Provisioning Technology&quot;) for the purpose of\n    allowing users to install software, documentation, information and/or\n    other materials (collectively &quot;Installable Software&quot;). This\n    capability is provided with the intent of allowing such users to\n    install, extend and update Eclipse-based products. Information about\n    packaging Installable Software is available at <a\n        href=\"http://eclipse.org/equinox/p2/repository_packaging.html\">http://eclipse.org/equinox/p2/repository_packaging.html</a>\n    (&quot;Specification&quot;).\n</p>\n\n<p>You may use Provisioning Technology to allow other parties to\n    install Installable Software. You shall be responsible for enabling\n    the applicable license agreements relating to the Installable Software\n    to be presented to, and accepted by, the users of the Provisioning\n    Technology in accordance with the Specification. By using Provisioning\n    Technology in such a manner and making it available in accordance with\n    the Specification, you further acknowledge your agreement to, and the\n    acquisition of all necessary rights to permit the following:</p>\n\n<ol>\n    <li>A series of actions may occur (&quot;Provisioning\n        Process&quot;) in which a user may execute the Provisioning\n        Technology on a machine (&quot;Target Machine&quot;) with the intent\n        of installing, extending or updating the functionality of an\n        Eclipse-based product.</li>\n    <li>During the Provisioning Process, the Provisioning Technology\n        may cause third party Installable Software or a portion thereof to be\n        accessed and copied to the Target Machine.</li>\n    <li>Pursuant to the Specification, you will provide to the user\n        the terms and conditions that govern the use of the Installable\n        Software (&quot;Installable Software Agreement&quot;) and such\n        Installable Software Agreement shall be accessed from the Target\n        Machine in accordance with the Specification. Such Installable\n        Software Agreement must inform the user of the terms and conditions\n        that govern the Installable Software and must solicit acceptance by\n        the end user in the manner prescribed in such Installable Software\n        Agreement. Upon such indication of agreement by the user, the\n        provisioning Technology will complete installation of the Installable\n        Software.</li>\n</ol>\n\n<h3>Cryptography</h3>\n\n<p>Content may contain encryption software. The country in which\n    you are currently may have restrictions on the import, possession, and\n    use, and/or re-export to another country, of encryption software.\n    BEFORE using any encryption software, please check the country's laws,\n    regulations and policies concerning the import, possession, or use,\n    and re-export of encryption software, to see if this is permitted.</p>\n\n<p>\n    <small>Java and all Java-based trademarks are trademarks of\n        Oracle Corporation in the United States, other countries, or both.</small>\n</p>\n</body>\n</html>"
  },
  {
    "path": "kura/distrib/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n     Red Hat Inc\n     Kevin Read, Om7Sense GmbH\n     John Read, Om7Sense GmbH\n     Amit Kumar Mondal\n     Cavium\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>org.eclipse.kura</groupId>\n    <artifactId>distrib</artifactId>\n    <version>6.0.0-SNAPSHOT</version>\n\n    <packaging>pom</packaging>\n\n    <name>distrib</name>\n    <url>https://eclipse.dev/kura/</url>\n\n    <modules>\n        <module>aarch64-core</module>\n        <module>x86_64-core</module>\n    </modules>\n\n    <properties>\n        <jdeb-version>1.14</jdeb-version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\n        <kura.basedir>${project.basedir}</kura.basedir>\n        <kura.build.version>${maven.build.timestamp}</kura.build.version>\n\n        <kura.install.dir>/opt/eclipse</kura.install.dir>\n        <kura.symlink>kura</kura.symlink>\n\n        <!-- properties used for repository upload on artifactory -->\n        <kura.repo.distribution>kura-6</kura.repo.distribution>\n        <kura.repo.module>base</kura.repo.module>\n\n        <org.eclipse.equinox.launcher.version>1.6.900</org.eclipse.equinox.launcher.version>\n\n        <kura.version>KURA_${project.version}</kura.version>\n        <kura.marketplace.compatibility.version>${kura.version}</kura.marketplace.compatibility.version>\n        <kura.home>${kura.install.dir}/${kura.symlink}</kura.home>\n        <kura.framework.config>${kura.home}/framework</kura.framework.config>\n        <kura.user.config>${kura.home}/user</kura.user.config>\n        <kura.plugins>${kura.home}/plugins</kura.plugins>\n        <kura.packages>${kura.home}/packages</kura.packages>\n        <kura.data>${kura.home}/data</kura.data>\n        <kura.snapshots>${kura.home}/snapshots</kura.snapshots>\n        <kura.style.dir>${kura.home}/console.skin</kura.style.dir>\n\n        <kura.project>generic-${project.name}</kura.project>\n        <kura.have.net.admin>false</kura.have.net.admin>\n\n        <skip.resource.copy>true</skip.resource.copy>\n\n        <device.name>device_name</device.name>\n        <os.distribution>Linux</os.distribution>\n        <os.distribution.version>N/A</os.distribution.version>\n        <kura.primary.network.interface>kura.primary.network.interface=eth0</kura.primary.network.interface>\n        <kura.serialNumber.provider>cat /proc/cpuinfo | grep Serial | cut -d ' ' -f 2</kura.serialNumber.provider>\n        <kura.serialNumber></kura.serialNumber>\n        <deb.name>kura-core</deb.name>\n        <deb.dependencies>\n            setserial, zip, gzip, unzip, procps, usbutils, socat, gawk, sed, inetutils-telnet,\n            polkit | policykit-1 | polkitd,\n            ssh | openssh, openssl, busybox, libpam-modules,\n            python3,\n            openjdk-21-jre-headless | temurin-21-jdk | java-runtime-headless (= 21),\n            dos2unix, libtirpc3, chrony, chronyc | chrony, iputils-ping\n        </deb.dependencies>\n        <deb.recommendations></deb.recommendations>\n        <deb.provides></deb.provides>\n        <deb.architecture>unset</deb.architecture>\n        <kura.mem.size>1024m</kura.mem.size>\n        <kura.os.version>debian</kura.os.version>\n        <buildNumber>buildNumber</buildNumber>\n        <build.name>generic_debian</build.name>\n        <target.device>generic</target.device>\n        <kura.os.version>debian</kura.os.version>\n        <native.tag>${kura.arch}</native.tag>\n    </properties>\n\n    <distributionManagement>\n        <repository>\n            <id>repo.eclipse.org</id>\n            <name>Eclipse Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </repository>\n        <snapshotRepository>\n            <id>repo.eclipse.org</id>\n            <name>Eclipse Kura Repository - Snapshots</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </snapshotRepository>\n    </distributionManagement>\n\n    <organization>\n        <name>Eclipse Kura</name>\n        <url>http://www.eclipse.org/kura/</url>\n    </organization>\n    <inceptionYear>2017</inceptionYear>\n    <description>Kura is a Java/OSGI-based framework for IoT gateways. Kura APIs offer access to the underlying hardware (serial ports, GPS, watchdog, GPIOs, I2C, etc.), management of network configurations, communications with M2M/IoT Integration Platforms, and gateway management.</description>\n\n    <repositories>\n        <repository>\n            <id>kura-addons</id>\n            <name>Eclipse Kura Addons Maven Repository</name>\n            <url>https://artifactory.dev.everyware.io/artifactory/kura-addons</url>\n            <snapshots>\n                <enabled>true</enabled>\n                <updatePolicy>always</updatePolicy>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>eclipse-releases</id>\n            <url>https://repo.eclipse.org/content/groups/releases/</url>\n        </repository>\n        <repository>\n            <id>kura-releases</id>\n            <name>Eclipse Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </repository>\n        <repository>\n            <id>kura-snapshots</id>\n            <name>Eclipse Kura Repository - Snapshots</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </repository>\n        <repository>\n            <!-- moquette-broker -->\n            <id>jitpack.io</id>\n            <url>https://jitpack.io</url>\n        </repository>\n    </repositories>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>target-platform-pde-deps</artifactId>\n            <version>6.0.0-SNAPSHOT</version>\n            <type>pom</type>\n            <exclusions>\n                <!-- exclude Kura's usb4java transitive deps -->\n                <exclusion>\n                    <groupId>javax.usb</groupId>\n                    <artifactId>usb-api</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.usb4java</groupId>\n                    <artifactId>usb4java-javax</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.usb4java</groupId>\n                    <artifactId>usb4java</artifactId>\n                </exclusion>\n                <exclusion>\n                    <groupId>org.usb4java</groupId>\n                    <artifactId>libusb4java</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>kura-pde-deps</artifactId>\n            <version>6.0.0-SNAPSHOT</version>\n            <type>pom</type>\n        </dependency>\n        \n    </dependencies>\n\n    <build>\n\n        <extensions>\n            <extension>\n                <groupId>org.apache.maven.wagon</groupId>\n                <artifactId>wagon-ssh</artifactId>\n                <version>1.0-beta-6</version>\n            </extension>\n            <extension>\n                <groupId>org.apache.maven.wagon</groupId>\n                <artifactId>wagon-webdav-jackrabbit</artifactId>\n                <version>2.2</version>\n            </extension>\n        </extensions>\n\n        <plugins>\n\n            <!-- Responsible for removing the \"-SNAPSHOT\" from the project.version -->\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>build-helper-maven-plugin</artifactId>\n                <version>3.6.0</version>\n                <executions>\n                    <execution>\n                        <id>regex-property</id>\n                        <goals>\n                            <goal>regex-property</goal>\n                        </goals>\n                        <configuration>\n                            <name>release.version</name>\n                            <value>${project.version}</value>\n                            <regex>-SNAPSHOT</regex>\n                            <replacement></replacement>\n                            <failIfNoMatch>false</failIfNoMatch>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <!-- Responsible for retrieving the short git commit (defaults to length 7)-->\n            <plugin>\n                <groupId>io.github.git-commit-id</groupId>\n                <artifactId>git-commit-id-maven-plugin</artifactId>\n                <version>9.0.1</version>\n                <executions>\n                    <execution>\n                        <id>get-the-git-infos</id>\n                        <goals>\n                            <goal>revision</goal>\n                        </goals>\n                        <phase>initialize</phase>\n                    </execution>\n                </executions>\n                <configuration>\n                    <injectAllReactorProjects>true</injectAllReactorProjects>\n                    <generateGitPropertiesFile>false</generateGitPropertiesFile>\n                    <skipPoms>false</skipPoms>\n                    <includeOnlyProperties>\n                        <includeOnlyProperty>^git.commit.id.abbrev$</includeOnlyProperty>\n                    </includeOnlyProperties>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>build-helper-maven-plugin</artifactId>\n                <version>1.9</version>\n                <executions>\n                    <execution>\n                        <id>set-deployment-package-version</id>\n                        <goals>\n                            <goal>regex-property</goal>\n                        </goals>\n                        <configuration>\n                            <name>deployment.package.version</name>\n                            <value>${project.version}</value>\n                            <regex>-SNAPSHOT</regex>\n                            <replacement>.qualifier</replacement>\n                            <failIfNoMatch>false</failIfNoMatch>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>verify-if-snapshot</id>\n                        <phase>install</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <exportAntProperties>true</exportAntProperties>\n                            <target name=\"is-snapshot-check\">\n                                <condition property=\"is.not.snapshot\">\n                                    <not>\n                                        <contains string=\"${project.version}\" substring=\"-SNAPSHOT\" />\n                                    </not>\n                                </condition>\n                            </target>\n                        </configuration>\n                    </execution>\n                    <execution>\n                        <id>calc-checksums</id>\n                        <phase>install</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <failOnError>false</failOnError>\n                            <target name=\"checksum\">\n                                <checksum algorithm=\"MD5\">\n                                    <fileset dir=\"${basedir}/target\">\n                                        <include name=\"*.deb\" />\n                                        <include name=\"*.dp\" />\n                                    </fileset>\n                                </checksum>\n                                <checksum algorithm=\"SHA-1\">\n                                    <fileset dir=\"${basedir}/target\">\n                                        <include name=\"*.deb\" />\n                                        <include name=\"*.dp\" />\n                                    </fileset>\n                                </checksum>\n                            </target>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <artifactId>maven-resources-plugin</artifactId>\n                    <executions>\n                        <execution>\n                            <id>copy-common-resources</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-resources</goal>\n                            </goals>\n                            <configuration>\n                                <resources>\n                                    <resource>\n                                        <directory>../../../../src/main/resources/filtered</directory>\n                                        <filtering>true</filtering>\n                                    </resource>\n                                    <resource>\n                                        <directory>../../../src/main/resources/filtered</directory>\n                                        <filtering>true</filtering>\n                                    </resource>\n                                    <resource>\n                                        <directory>../../src/main/resources/filtered</directory>\n                                        <filtering>true</filtering>\n                                    </resource>\n                                    <resource>\n                                        <directory>../src/main/resources/filtered</directory>\n                                        <filtering>true</filtering>\n                                    </resource>\n                                    <resource>\n                                        <directory>../../../../src/main/resources/unfiltered</directory>\n                                        <filtering>false</filtering>\n                                    </resource>\n                                    <resource>\n                                        <directory>../../../src/main/resources/unfiltered</directory>\n                                        <filtering>false</filtering>\n                                    </resource>\n                                    <resource>\n                                        <directory>../../src/main/resources/unfiltered</directory>\n                                        <filtering>false</filtering>\n                                    </resource>\n                                    <resource>\n                                        <directory>../src/main/resources/unfiltered</directory>\n                                        <filtering>false</filtering>\n                                    </resource>\n                                </resources>\n                                <overwrite>true</overwrite>\n                                <skip>${skip.resource.copy}</skip>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>copy-project-resources</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-resources</goal>\n                            </goals>\n                            <configuration>\n                                <resources>\n                                    <resource>\n                                        <directory>src/main/resources/filtered</directory>\n                                        <filtering>true</filtering>\n                                    </resource>\n                                    <resource>\n                                        <directory>src/main/resources/unfiltered</directory>\n                                        <filtering>false</filtering>\n                                    </resource>\n                                </resources>\n                            </configuration>\n                        </execution>\n                    </executions>\n                    <configuration>\n                        <overwrite>true</overwrite>\n                        <outputDirectory>${project.build.directory}</outputDirectory>\n                        <escapeString>\\</escapeString>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-dependency-plugin</artifactId>\n                    <executions>\n                        <execution>\n                            <id>core-launcher</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins</outputDirectory>\n                                <includeArtifactIds>\n                                    org.eclipse.osgi,\n                                    org.eclipse.equinox.launcher\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-1</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/1</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- osgi-base-plugins -->\n                                    asm, org.eclipse.equinox.console, asm-tree,\n                                    asm-util, log4j2-api-config, asm-analysis, asm-commons\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-1s</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/1s</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- osgi-base-plugins -->\n                                    org.apache.aries.spifly.dynamic.bundle,\n                                    log4j-slf4j2-impl, org.eclipse.equinox.common,\n                                    org.eclipse.equinox.cm, org.eclipse.equinox.event,\n                                    jcl-over-slf4j, log4j-api, log4j-core,\n                                    org.eclipse.equinox.metatype, org.eclipse.equinox.util,\n                                    org.eclipse.equinox.registry, slf4j-api, org.eclipse.equinox.io,\n                                    jul-to-slf4j, org.apache.felix.scr, org.eclipse.kura.jul.to.slf4j.configuration\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-2</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/2</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- osgi-base-plugins -->\n                                    jakarta.xml.bind-api, jakarta.xml.soap-api,\n                                    org.osgi.util.function, org.osgi.service.prefs,\n                                    jakarta.annotation-api, org.osgi.service.event,\n                                    org.osgi.service.coordinator, org.osgi.service.device,\n                                    org.osgi.util.measurement, jakarta.xml.ws-api,\n                                    org.osgi.service.metatype, jakarta.activation-api,\n                                    org.osgi.service.component, org.osgi.service.log.stream,\n                                    org.osgi.util.pushstream, org.eclipse.kura.sun.misc,\n                                    org.osgi.service.wireadmin, org.osgi.util.promise,\n                                    org.osgi.util.xml, org.osgi.service.upnp,\n                                    org.osgi.service.provisioning, org.osgi.service.cm,\n                                    org.osgi.util.position, org.osgi.service.useradmin\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-2s</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/2s</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- osgi-base-plugins -->\n                                    osgi-resource-locator,\n                                    org.osgi.service.http.whiteboard, org.osgi.service.servlet,\n                                    org.eclipse.osgi.util, jaxb-osgi\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-3</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/3</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- osgi-base-plugins -->\n                                    bcutil-jdk18on,\n                                    jakarta.validation-api, hk2-locator, bcpg-jdk18on,\n                                    com.codeminders.hidapi.${native.tag}, hk2-utils,\n                                    org.apache.servicemix.bundles.c3p0, jersey-media-multipart,\n                                    HikariCP, quartz, jersey-hk2, jersey-common,\n                                    jersey-server, jakarta.inject-api, bctls-jdk18on,\n                                    jersey-container-servlet, mimepull,\n                                    org.eclipse.soda.dk.comm.${native.tag}, jersey-client, hk2-api,\n                                    javassist, jersey-media-sse, protobuf-java, bcpkix-jdk18on,\n                                    jersey-entity-filtering,\n                                    jersey-media-jaxb, commons-csv, gson, aopalliance-repackaged,\n                                    bcprov-jdk18on, jersey-container-servlet-core, \n                                    <!-- netty-plugins --> \n                                    netty-common, netty-codec-http, netty-codec, netty-transport, netty-buffer,\n                                    netty-transport-classes-epoll, netty-resolver, netty-handler,\n                                    netty-transport-classes-kqueue, netty-transport-native-epoll,\n                                    netty-codec-mqtt, netty-transport-native-kqueue,\n                                    netty-transport-native-unix-common,\n                                    netty-codec-socks,\n                                    netty-handler-proxy,\n                                    <!-- api-plugins -->\n                                    failureaccess, guava,\n                                    <!-- Jackson core -->\n                                    jackson-databind, jackson-annotations, jackson-core,\n                                    <!-- artemis and camel common plugins -->\n                                    geronimo-jms_2.0_spec\n                                </includeArtifactIds>\n                                <excludeClassifiers>\n                                    sources,linux-x86_64,linux-aarch_64,osx-x86_64,osx-aarch_64\n                                </excludeClassifiers>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-3s</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/3s</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- core.crypto-plugins -->\n                                     org.eclipse.kura.core.crypto, \n                                    <!-- api-plugins -->\n                                    org.eclipse.kura.api,\n                                    <!-- osgi-base-plugins -->\n                                    org.eclipse.kura.useradmin.store,\n                                    org.eclipse.soda.dk.comm, commons-fileupload2-jakarta-servlet5,\n                                    org.apache.felix.deploymentadmin, org.apache.felix.useradmin,\n                                    org.apache.felix.dependencymanager, commons-net, h2,\n                                    commons-fileupload2-core, com.codeminders.hidapi, commons-io,\n                                    monitoradmin,\n                                    <!-- marshallers-plugins -->\n                                    org.eclipse.kura.xml.marshaller.unmarshaller.provider,\n                                    org.eclipse.kura.json.marshaller.unmarshaller.provider\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-4</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/4</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- core.status-plugins -->\n                                     org.eclipse.kura.core.status,\n                                    <!-- h2db-plugins -->\n                                     org.eclipse.kura.db.h2db.provider, \n                                    <!-- linux.clock-plugins -->\n                                     org.eclipse.kura.linux.clock,\n                                    <!-- rest-plugins -->\n                                    org.eclipse.kura.request.handler.jaxrs\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-4s</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/4s</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- driver-plugins -->\n                                    org.eclipse.kura.driver.helper.provider,\n                                    <!-- core.certificates-plugins -->\n                                    org.eclipse.kura.core.certificates,\n                                    <!-- util-plugins -->\n                                    org.eclipse.kura.util,\n                                    <!-- configuration.change.manager-plugins -->\n                                    org.eclipse.kura.configuration.change.manager,\n                                    <!-- cloud.mqtt.raw-plugins -->\n                                    org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider,\n                                    <!-- cloud.mqtt.kapua-plugins -->\n                                    org.eclipse.kura.cloudconnection.kapua.mqtt.provider,\n                                    <!-- filesystem-logprovider-plugins -->\n                                    org.eclipse.kura.log.filesystem.provider,\n                                    <!-- rest-plugins -->\n                                    org.eclipse.kura.rest.keystore.provider,\n                                    org.eclipse.kura.rest.inventory.provider,\n                                    org.eclipse.kura.rest.configuration.provider,\n                                    org.eclipse.kura.rest.system.provider,\n                                    org.eclipse.kura.rest.provider,\n                                    org.eclipse.kura.rest.security.provider,\n                                    org.eclipse.kura.rest.identity.provider,\n                                    org.eclipse.kura.rest.service.listing.provider,\n                                    org.eclipse.kura.rest.cloudconnection.provider,\n                                    <!-- core.identity-plugins -->\n                                    org.eclipse.kura.core.identity, \n                                    <!-- core-plugins -->\n                                    org.eclipse.kura.core, \n                                    <!-- misc-plugins -->\n                                    org.eclipse.kura.misc.cloudcat,\n                                    <!-- keystore-management-plugins -->\n                                    org.eclipse.kura.core.keystore,\n                                    <!-- osgi-base-plugins --> \n                                    commons-lang3, usb4java-javax,\n                                    org.usb4java,\n                                    <!-- core.system-plugins -->\n                                    org.eclipse.kura.core.system,\n                                    <!-- core.cloud-plugins -->\n                                    org.eclipse.kura.core.cloud.factory,\n                                    org.eclipse.kura.cloud.base.provider,\n                                    <!-- core.configuration-plugins -->\n                                    org.eclipse.kura.core.configuration,\n                                    <!-- core.inventory-plugins -->\n                                    org.eclipse.kura.core.inventory, \n                                    <!-- core.comm-plugins -->\n                                    org.eclipse.kura.core.comm\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-5</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/5</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- osgi-base-plugins -->\n                                    org.apache.felix.gogo.shell, jetty-security,\n                                    org.apache.felix.http.proxy, org.apache.felix.http.wrappers,\n                                    jetty-server, jetty-util, jetty-http,\n                                    org.eclipse.osgitech.rest.sse, org.apache.felix.gogo.command,\n                                    org.apache.felix.gogo.runtime, jetty-session, jetty-io,\n                                    org.apache.felix.http.servlet-api\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-5s</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/5s</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- event-publisher-plugins -->\n                                    org.eclipse.kura.event.publisher,\n                                    <!-- http.server.manager-plugin -->\n                                    org.eclipse.kura.http.server.manager,\n                                    <!-- osgi-base-plugins -->\n                                    org.eclipse.osgitech.rest, jakarta.ws.rs-api,\n                                    jetty-ee10-servlet, org.apache.felix.http.bridge,\n                                    org.osgi.service.jakartars,\n                                    org.eclipse.osgitech.rest.servlet.whiteboard\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>core-plugins-6</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/6</outputDirectory>\n                                <includeArtifactIds>\n                                    <!-- osgi-base-plugins -->\n                                    minimal-json, commons-exec\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n\n                        <!-- Linux Plugins -->\n                        <execution>\n                            <id>linux-plugins-4</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/4</outputDirectory>\n                                <skip>${exclude.linux.plugins}</skip>\n                                <includeArtifactIds>\n                                    <!-- linux.watchdog-plugins --> \n                                    org.eclipse.kura.linux.watchdog,\n                                    <!-- linux.usb-plugins -->\n                                    org.eclipse.kura.linux.usb,\n                                    org.eclipse.kura.linux.usb.${native.tag}\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                        <execution>\n                            <id>linux-plugins-4s</id>\n                            <phase>generate-sources</phase>\n                            <goals>\n                                <goal>copy-dependencies</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${project.build.directory}/pkg/plugins/4s</outputDirectory>\n                                <skip>${exclude.linux.plugins}</skip>\n                                <includeArtifactIds>\n                                    <!-- container-orchestrator-plugins -->\n                                    org.eclipse.kura.container.provider,\n                                    org.eclipse.kura.container.orchestration.provider\n                                </includeArtifactIds>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <plugin>\n                    <groupId>org.vafer</groupId>\n                    <artifactId>jdeb</artifactId>\n                    <version>${jdeb-version}</version>\n                    <executions>\n                        <execution>\n                            <id>deb</id>\n                            <phase>package</phase>\n                            <goals>\n                                <goal>jdeb</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                    <configuration>\n                        <verbose>true</verbose>\n                        <deb>\n                            ${project.build.directory}/${deb.name}_${package.version}-${package.revision}_${deb.architecture}.deb</deb>\n                        <snapshotExpand>true</snapshotExpand>\n                        <snapshotTemplate>${package.snapshot}</snapshotTemplate>\n                        <controlDir>${project.build.directory}/deb/control</controlDir>\n                        <skipPOMs>false</skipPOMs>\n                        <dataSet>\n                            <data>\n                                <type>template</type>\n                                <paths>\n                                    <path>${kura.install.dir}</path>\n                                    <path>${kura.install.dir}/${kura.symlink}</path>\n                                    <path>${kura.install.dir}/${kura.symlink}/.data</path>\n                                </paths>\n                                <mapper>\n                                    <type>perm</type>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>600</filemode>\n                                </mapper>\n                            </data>\n                            <data>\n                                <type>template</type>\n                                <conffile>true</conffile>\n                                <paths>\n                                    <path>${kura.install.dir}/${kura.symlink}/data</path>\n                                    <path>${kura.install.dir}/${kura.symlink}/packages</path>\n                                </paths>\n                                <mapper>\n                                    <type>perm</type>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>600</filemode>\n                                </mapper>\n                            </data>\n                            <data>\n                                <src>${project.build.directory}/pkg/bin/</src>\n                                <type>directory</type>\n                                <mapper>\n                                    <type>perm</type>\n                                    <prefix>${kura.install.dir}/${kura.symlink}/bin</prefix>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>700</filemode>\n                                </mapper>\n                            </data>\n                            <data>\n                                <src>${project.build.directory}/pkg/framework/</src>\n                                <type>directory</type>\n                                <mapper>\n                                    <type>perm</type>\n                                    <prefix>${kura.install.dir}/${kura.symlink}/framework</prefix>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>600</filemode>\n                                </mapper>\n                            </data>\n                            <data>\n                                <src>${project.build.directory}/pkg/packages/</src>\n                                <type>directory</type>\n                                <mapper>\n                                    <type>perm</type>\n                                    <prefix>${kura.install.dir}/${kura.symlink}/packages</prefix>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>600</filemode>\n                                </mapper>\n                            </data>\n                            <data>\n                                <src>${project.build.directory}/pkg/plugins/</src>\n                                <type>directory</type>\n                                <mapper>\n                                    <type>perm</type>\n                                    <prefix>${kura.install.dir}/${kura.symlink}/plugins</prefix>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>600</filemode>\n                                </mapper>\n                            </data>\n                            <data>\n                                <src>${project.build.directory}/pkg/user/</src>\n                                <type>directory</type>\n                                <conffile>true</conffile>\n                                <mapper>\n                                    <type>perm</type>\n                                    <prefix>${kura.install.dir}/${kura.symlink}/user</prefix>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>600</filemode>\n                                </mapper>\n                            </data>\n                            <data>\n                                <src>${project.build.directory}/pkg/log4j/</src>\n                                <type>directory</type>\n                                <conffile>true</conffile>\n                                <mapper>\n                                    <type>perm</type>\n                                    <prefix>${kura.install.dir}/${kura.symlink}/log4j</prefix>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>600</filemode>\n                                </mapper>\n                            </data>\n                            <data>\n                                <src>${project.build.directory}/pkg/install/</src>\n                                <type>directory</type>\n                                <mapper>\n                                    <type>perm</type>\n                                    <prefix>${kura.install.dir}/${kura.symlink}/install</prefix>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>600</filemode>\n                                </mapper>\n                            </data>\n                            <data>\n                                <type>template</type>\n                                <conffile>true</conffile>\n                                <paths>\n                                    <path>${kura.install.dir}/${kura.symlink}/data</path>\n                                    <path>${kura.install.dir}/${kura.symlink}/packages</path>\n                                </paths>\n                                <mapper>\n                                    <type>perm</type>\n                                    <user>root</user>\n                                    <group>root</group>\n                                    <filemode>600</filemode>\n                                </mapper>\n                            </data>\n                        </dataSet>\n                    </configuration>\n                </plugin>\n                <!--This\n                plugin's configuration is used to store Eclipse m2e settings\n                    only. It has no influence on the Maven build itself. -->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>1.0.0</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.codehaus.mojo</groupId>\n                                        <artifactId>properties-maven-plugin</artifactId>\n                                        <versionRange>[1.2.1,)</versionRange>\n                                        <goals>\n                                            <goal>read-project-properties</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.codehaus.mojo</groupId>\n                                        <artifactId>buildnumber-maven-plugin</artifactId>\n                                        <versionRange>[1.0,)</versionRange>\n                                        <goals>\n                                            <goal>create-timestamp</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.apache.maven.plugins</groupId>\n                                        <artifactId>maven-dependency-plugin\n                                        </artifactId>\n                                        <versionRange>[1.0,)</versionRange>\n                                        <goals>\n                                            <goal>copy</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.apache.maven.plugins</groupId>\n                                        <artifactId>maven-antrun-plugin</artifactId>\n                                        <versionRange>[1.0,)</versionRange>\n                                        <goals>\n                                            <goal>run</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.codehaus.mojo</groupId>\n                                        <artifactId>build-helper-maven-plugin</artifactId>\n                                        <versionRange>[1.9,)</versionRange>\n                                        <goals>\n                                            <goal>regex-property</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n\n    <profiles>\n        <!-- Internal profile: FOR INTERNAL USE ONLY - active if -DreleaseBuild is *not* specified. -->\n        <profile>\n            <id>debugBuild</id>\n            <activation>\n                <property>\n                    <name>!releaseBuild</name>\n                </property>\n            </activation>\n            <properties>\n                <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>\n                <package.snapshot>git${maven.build.timestamp}.${git.commit.id.abbrev}</package.snapshot>\n\n                <package.version>${release.version}~${package.snapshot}</package.version>\n                <package.revision>1</package.revision>\n            </properties>\n        </profile>\n        <!-- Internal profile: FOR INTERNAL USE ONLY - active if -DreleaseBuild *is* specified. -->\n        <profile>\n            <id>releaseBuild</id>\n            <activation>\n                <property>\n                    <name>releaseBuild</name>\n                </property>\n            </activation>\n            <properties>\n                <package.version>${release.version}</package.version>\n                <package.revision>1</package.revision>\n            </properties>\n            <build>\n                <plugins>\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-enforcer-plugin</artifactId>\n                        <version>3.5.0</version>\n                        <executions>\n                            <execution>\n                                <id>enforce-no-snapshots</id>\n                                <goals>\n                                    <goal>enforce</goal>\n                                </goals>\n                                <configuration>\n                                    <rules>\n                                        <requireReleaseVersion>\n                                            <message>No snapshots allowed for release builds!</message>\n                                        </requireReleaseVersion>\n                                    </rules>\n                                    <fail>true</fail>\n                                </configuration>\n                            </execution>\n                        </executions>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n\n        <!-- dp -->\n        <!-- TODO: this will be removed, DPs are deprecated -->\n        <profile>\n            <id>core-dp</id>\n            <modules>\n                <module>core-dp</module>\n            </modules>\n        </profile>\n    </profiles>\n\n</project>\n"
  },
  {
    "path": "kura/distrib/src/main/resources/filtered/pkg/bin/start_kura.sh",
    "content": "#!/bin/bash\n#\n#  Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n# Kura should be installed to the \\${kura.install.dir} directory.\nexport PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/opt/jvm/bin:/usr/java/bin:$PATH\nexport MALLOC_ARENA_MAX=1\n\nKURA_RUNNING=$(pgrep -f \".*java.*org\\.eclipse\\.equinox\\..*\")\n\nif [ -n \"$KURA_RUNNING\" ] ; then\n    echo \"Failed to start Kura. It is already running ...\"\n    exit 1\nfi\n\nDIR=$(cd $(dirname $0)/..; pwd)\ncd \"$DIR\" || exit 1\n\nIS_DEBUG_MODE=\"false\"\nIS_DETACHED_MODE=\"false\"\n\nwhile [[ $# -gt 0 ]]; do\n    key=\"$1\"\n\n    case $key in\n    -d | --detached)\n        IS_DETACHED_MODE=\"true\"\n        ;;\n    -x | --debug)\n        IS_DEBUG_MODE=\"true\"\n        ;;\n    -h | --help)\n        echo\n        echo \"Options:\"\n        echo \"    -d | --detached    run Kura in detached mode\"\n        echo \"    -x | --debug       run Kura in debug mode\"\n        exit 0\n        ;;\n    *)\n        echo \"Unknown option.\"\n        exit 1\n        ;;\n    esac\n    shift # past argument or value\ndone\n\n# set up the configuration area\nmkdir -p /tmp/.kura/configuration\n\\${DIR}/bin/gen_config_ini.sh \\${DIR}/framework/config.ini \\${DIR}/plugins > /tmp/.kura/configuration/config.ini\n\nif [[ -n \"${KURA_DEBUG_MODE}\" && \"${KURA_DEBUG_MODE}\" == \"true\" ]]; then\n    IS_DEBUG_MODE=\"true\"\nfi\n\nDEBUG_OPTS=\"\"\nEQUINOX_DEBUG_OPTS=\"\"\nif [[ $IS_DEBUG_MODE == \"true\" ]]; then\n    DEBUG_OPTS=\"-Xdebug \\\n        -Xrunjdwp:server=y,transport=dt_socket,address=*:8000,suspend=n \\\n        -Xlog:gc=info:file=/var/log/kura-gc.log:time:filecount=10,filesize=10m \\\n        -XX:+HeapDumpOnOutOfMemoryError \\\n        -XX:HeapDumpPath=/var/log/kura-heapdump.hprof \\\n        -XX:ErrorFile=/var/log/kura-error.log\"\n\n    EQUINOX_DEBUG_OPTS=\"-console 5002 \\\n    -consoleLog\"\nfi\n\nKURA_LAUNCH_COMMAND=\"exec java\"\n\nif [[ $IS_DETACHED_MODE == \"true\" ]]; then\n    KURA_LAUNCH_COMMAND=\"nohup java\"\nfi\n\nKURA_CMD=\"${KURA_LAUNCH_COMMAND} -Xms${kura.mem.size} -Xmx${kura.mem.size} \\\n    $DEBUG_OPTS \\\n    -XX:+IgnoreUnrecognizedVMOptions \\\n    --add-opens java.base/java.lang=ALL-UNNAMED \\\n    --add-opens java.base/java.util=ALL-UNNAMED \\\n    --add-modules=ALL-SYSTEM \\\n    -Dkura.os.version=${kura.os.version} \\\n    -Dkura.arch=${kura.arch} \\\n    -Dtarget.device=${target.device} \\\n    -Declipse.ignoreApp=true \\\n    -Dkura.home=\\${DIR} \\\n    -Dkura.configuration=file:\\${DIR}/framework/kura.properties \\\n    -Dkura.custom.configuration=file:\\${DIR}/user/kura_custom.properties \\\n    -Ddpa.configuration=\\${DIR}/packages/dpa.properties \\\n    -Dlog4j.configurationFile=file:\\${DIR}/log4j/log4j.xml \\\n    -Dlog4j2.disable.jmx=true \\\n    -Djdk.tls.trustNameService=true \\\n    -Declipse.consoleLog=true \\\n    -jar \\${DIR}/plugins/org.eclipse.equinox.launcher-${org.eclipse.equinox.launcher.version}.jar \\\n    -configuration /tmp/.kura/configuration \\\n    $EQUINOX_DEBUG_OPTS\"\n\nif [[ $IS_DETACHED_MODE == \"true\" ]]; then\n    eval \"$KURA_CMD &\"\n\n    #Save the PID\n    KURA_PID=$!\n    echo \"Kura Started (pid=$KURA_PID) ...\"\n    echo $KURA_PID > /var/run/kura.pid\nelse\n    eval \"$KURA_CMD\"\nfi\n"
  },
  {
    "path": "kura/distrib/src/main/resources/filtered/pkg/framework/kura.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\n## -----------------------------------------------------------------------------\n##  Kura Properties\n## -----------------------------------------------------------------------------\nkura.name=Eclipse Kura\nkura.version=${kura.version}\nkura.marketplace.compatibility.version=${kura.marketplace.compatibility.version}\nkura.company=Eclipse\nkura.platform=kura_platform\nkura.project=${kura.project}\nkura.device.name=${device.name}\nkura.model.id=${device.name}\nkura.model.name=${device.name}\nkura.partNumber=${device.name}\n${kura.serialNumber}\n${kura.serialNumber.provider}\nkura.bios.version=N/A\nkura.firmware.version=N/A\n${kura.primary.network.interface}\n# kura.mac.address= Fetch from Java\nkura.home=${kura.install.dir}/${kura.symlink}\nkura.framework.config=${kura.install.dir}/${kura.symlink}/framework\nkura.user.config=${kura.install.dir}/${kura.symlink}/user\nkura.plugins=${kura.install.dir}/${kura.symlink}/plugins\nkura.packages=${kura.install.dir}/${kura.symlink}/packages\nkura.data=${kura.install.dir}/${kura.symlink}/data\nkura.tmp=/tmp/.kura\nkura.snapshots=${kura.install.dir}/${kura.symlink}/user/snapshots\nkura.style.dir=${kura.install.dir}/${kura.symlink}/console/skin\nkura.have.net.admin=${kura.have.net.admin}\nkura.net.virtual.devices.config=unmanaged\nkura.log.download.sources=/var/log\nkura.log.download.journal.fields=SYSLOG_IDENTIFIER,PRIORITY,MESSAGE,STACKTRACE\n# os.arch= Fetch from Java\n# os.name= Fetch from Java\n# os.version= Fetch from Java\nos.distribution=${os.distribution}\nos.distribution.version=${os.distribution.version}\n# java.version= Fetch from Java\n# java.vendor= Fetch from Java\n# java.vm.name= Fetch from Java\n# java.vm.version= Fetch from Java\n# java.home= Fetch from Java\n# file.separator= Fetch from Java\nkura.command.user=kura\nkura.legacy.bluetooth.beacon.scan=false\nkura.legacy.ppp.logging.enabled=true\nkura.default.log.manager=filesystem-kura-log\n\n\n## -----------------------------------------------------------------------------\n##  Remote Configuration Properties\n## -----------------------------------------------------------------------------\nconsole.device.management.service.ignore=org.eclipse.kura.net.admin.NetworkConfigurationService,org.eclipse.kura.net.admin.FirewallConfigurationService\n\n## -----------------------------------------------------------------------------\n## File upload settings\n## -----------------------------------------------------------------------------\n# default 10240\nfile.upload.in.memory.size.threshold=10240\n# -1: unlimited (default)\nfile.upload.size.max=-1\nfile.command.zip.max.size=100\nfile.command.zip.max.number=1024\n\n\n## -----------------------------------------------------------------------------\n## Deployment Agent settings\n## -----------------------------------------------------------------------------\n# see copyURLToFile() http://commons.apache.org/proper/commons-io/javadocs/api-2.4/index.html\ndpa.connection.timeout = 60000\ndpa.read.timeout = 60000\n\n## -----------------------------------------------------------------------------\n## Cloud Connection Status settings\n## -----------------------------------------------------------------------------\n\n#1. Cloud Connection Status on system log\n#The Cloud Connection Status will be indicated in the log files, and nowere else\nccs.status.notification.url=ccs:log\n\n#2. Cloud Connection Status on LED\n#The Cloud Connection Status will be indicated by a blinking LED connected to the system GPIOs\n#The URL should identify the GPIO to be used, either by name or by terminal index as defined by Kura GpioService.\n# Syntax for using GPIO terminal index:\n#ccs.status.notification.url=ccs:led:16\n#ccs.status.notification.url=ccs:led:terminal:16\n# Syntax for using GPIO name:\n#ccs.status.notification.url=ccs:led:name:LED_1\n\n#3. Cloud Connection Status disabled\n#Disables the Cloud Connection Status service\n#ccs.status.notification.url=ccs:none\n\nversion=${kura.version}\nbuild.version=${buildNumber}\nbuild.number=${build.name}-${buildNumber}"
  },
  {
    "path": "kura/distrib/src/main/resources/filtered/pkg/install/kura.service",
    "content": "[Unit]\nDescription=Kura\nWants=dbus.service,docker.service\nAfter=dbus.service,docker.service\n\n[Service]\nUser=kurad\nGroup=kurad\nType=forking\nExecStart=/bin/bash ${kura.install.dir}/kura/bin/start_kura.sh --detached\nExecStopPost=/bin/bash -c 'if [ -f /tmp/watchdog ]; then echo w > `cat /tmp/watchdog`; fi'\nPIDFile=/var/run/kura.pid\nRestart=on-failure\nRestartSec=5\nSuccessExitStatus=143\nKillMode=process\nAmbientCapabilities=cap_dac_override cap_dac_read_search cap_net_bind_service cap_sys_boot cap_kill cap_sys_module cap_sys_time cap_sys_tty_config cap_syslog\n\n[Install]\nWantedBy=multi-user.target\n"
  },
  {
    "path": "kura/distrib/src/main/resources/filtered/pkg/install/kura_install.sh",
    "content": "#!/bin/sh\n#\n# Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n#\n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n# SPDX-License-Identifier: EPL-2.0\n#\n# Contributors:\n#  Eurotech\n#\n\nbackup_files() {\n    SUFFIX=\"\\${1}\"\n\n    shift\n\n    for file in \"\\${@}\"\n    do\n        if [ -f \"\\${file}\" ]\n        then\n            mv \"\\${file}\" \"\\${file}.\\${SUFFIX}\"\n        fi\n    done\n}\n\nINSTALL_DIR=${kura.install.dir}\n\n# set up kura init\ncp \\${INSTALL_DIR}/kura/install/kura.service /lib/systemd/system/kura.service\nsystemctl daemon-reload\nsystemctl enable kura\nchmod +x \\${INSTALL_DIR}/kura/bin/*.sh\n\n# setup snapshot_0 recovery folder\nif [ ! -d \\${INSTALL_DIR}/kura/.data ]; then\n    mkdir \\${INSTALL_DIR}/kura/.data\nfi\n\nmkdir -p \\${INSTALL_DIR}/kura/data\n\n# manage running services\nsystemctl daemon-reload\nsystemctl stop systemd-timesyncd\nsystemctl disable systemd-timesyncd\nsystemctl stop chrony\nsystemctl disable chrony\n\n# set up users and grant permissions\ncp \\${INSTALL_DIR}/kura/install/manage_kura_users.sh \\${INSTALL_DIR}/kura/.data/manage_kura_users.sh\nchmod 700 \\${INSTALL_DIR}/kura/.data/manage_kura_users.sh\n\\${INSTALL_DIR}/kura/.data/manage_kura_users.sh -i -nn\n\nbash \"\\${INSTALL_DIR}/kura/install/customize-installation.sh\"\n\n# copy snapshot_0.xml\ncp \\${INSTALL_DIR}/kura/user/snapshots/snapshot_0.xml \\${INSTALL_DIR}/kura/.data/snapshot_0.xml\n\n# copy network_tools.py\ncp \\${INSTALL_DIR}/kura/install/network_tools.py \\${INSTALL_DIR}/kura/.data/network_tools.py\n\n# disable NTP service\nif command -v timedatectl > /dev/null ;\n  then\n    timedatectl set-ntp false\nfi\n\n# set up systemd-tmpfiles\ncp \\${INSTALL_DIR}/kura/install/kura-tmpfiles.conf /etc/tmpfiles.d/kura.conf\n\n# set up kura files permissions\nchmod 700 \\${INSTALL_DIR}/kura/bin/*.sh\nchown -R kurad:kurad /opt/eclipse\nchmod -R go-rwx /opt/eclipse\nchmod a+rx /opt/eclipse\nfind /opt/eclipse/kura -type d -exec chmod u+x \"{}\" \\;\n\nkeytool -genkey -alias localhost -keyalg RSA -keysize 2048 -keystore /opt/eclipse/kura/user/security/httpskeystore.ks -deststoretype pkcs12 -dname \"CN=Kura, OU=Kura, O=Eclipse Foundation, L=Ottawa, S=Ontario, C=CA\" -ext ku=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign -ext eku=serverAuth,clientAuth,codeSigning,timeStamping -validity 1000 -storepass changeit -keypass changeit\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/deb/control/control",
    "content": "#\n# Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n#\n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n# SPDX-License-Identifier: EPL-2.0\n#\n# Contributors:\n#  Eurotech\n#\nPackage: [[deb.name]]\nVersion: [[version]]-[[package.revision]]\nSection: admin\nPriority: optional\nProvides: [[deb.provides]]\nDepends: [[deb.dependencies]]\nRecommends: [[deb.recommendations]]\nArchitecture: [[deb.architecture]]\nMaintainer: Eclipse Kura Developers <kura-dev@eclipse.org>\nHomepage: https://eclipse-kura.github.io/kura/\nDescription: Open-source IoT edge framework based on Java/OSGi\n  Kura is an inclusive software framework that puts a layer\n  between the operating system and the customer application, with industry\n  standard interfaces that shorten custom development time, simplified coding\n  and software that can be easily ported from one hardware platform\n  to another.\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/deb/control/postinst",
    "content": "#!/bin/bash\n#\n# Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n#\n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n# SPDX-License-Identifier: EPL-2.0\n#\n# Contributors:\n#  Eurotech\n#\n\nINSTALL_DIR=/opt/eclipse\nTIMESTAMP=`date +%Y%m%d%H%M%S`\nLOG=/tmp/kura_install_${TIMESTAMP}.log\nWD_TMP_FILE=/tmp/watchdog\nREFRESH_TIME=5\nTIMEOUT_TIME=300\n\n##############################################\n# UTILITY FUNCTIONS\n##############################################\n# Run postInstall function and start watchdog if needed\nfunction runPostInstall {\n    if [ -f \"${WD_TMP_FILE}\" ]; then\n        WATCHDOG_DEVICE=`cat ${WD_TMP_FILE}`\n        echo \"Got watchdog ${WATCHDOG_DEVICE}\" >> $LOG 2>&1\n        postInstall &\n        PID=$!\n        START=$(date +%s)\n        \n        while [ -d \"/proc/$PID\" ]; do\n            echo w > ${WATCHDOG_DEVICE}\n            DELTA=$(($(date +%s) - $START))\n            if [ \"$DELTA\" -ge \"$TIMEOUT_TIME\" ]; then\n                echo \"The installation process is not responding. It'll be stopped.\"\n                kill -9 $PID >> /dev/null 2>&1\n            fi\n            sleep $REFRESH_TIME\n        done\n        stopWatchdog\n    else\n        postInstall &\n        PID=$!\n        START=$(date +%s)\n        \n        while [ -d \"/proc/$PID\" ]; do\n            DELTA=$(($(date +%s) - $START))\n            if [ \"$DELTA\" -ge \"$TIMEOUT_TIME\" ]; then\n                echo \"The installation process is not responding. It'll be stopped.\"\n                kill -9 $PID >> /dev/null 2>&1\n            fi\n            sleep $REFRESH_TIME\n        done\n    fi\n}\n\n# Deactivate watchdog device if possible\nfunction stopWatchdog {\n    if [ -n \"${WATCHDOG_DEVICE}\" ]; then\n        echo V > ${WATCHDOG_DEVICE}\n    fi\n}\n\n# Post-install script\nfunction postInstall {\n    \n    #install KURA files\n    sh ${INSTALL_DIR}/kura/install/kura_install.sh >> ${LOG} 2>&1\n    \n    #clean up\n    rm -rf ${INSTALL_DIR}/kura/install >> ${LOG} 2>&1\n    \n    #move the log file\n    mkdir -p ${INSTALL_DIR}/kura/log\n    mv ${LOG} ${INSTALL_DIR}/kura/log/\n    \n    #flush all cached filesystem to disk\n    sync\n    \n    echo \"\"\n    echo \"Finished. KURA has been installed to ${INSTALL_DIR}/kura and will start automatically after a reboot\"\n    echo \"\"\n    echo \"****************************************************************\"\n    echo \"WARNING: Set the crypto service encryption key as explained in Eclipse Kura\"\n    echo \"documentation before rebooting to have snapshot encryption enabled.\"\n    echo \"****************************************************************\"\n}\n##############################################\n# END UTILITY FUNCTIONS\n##############################################\n\n##############################################\n# POST INSTALL SCRIPT\n##############################################\n\n# Handle abort-upgrade case\nif [ \"$1\" = \"abort-upgrade\" ]; then\n    echo \"postinst called with abort-upgrade: nothing to do.\"\n    exit 0\nfi\n\nrunPostInstall\nexit 0\n#############################################\n# END POST INSTALL SCRIPT\n##############################################\n\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/deb/control/preinst",
    "content": "#!/bin/bash\n#\n# Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n#\n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n# SPDX-License-Identifier: EPL-2.0\n#\n# Contributors:\n#  Eurotech\n#\n\nINSTALL_DIR=/opt/eclipse\nWD_TMP_FILE=/tmp/watchdog\nREFRESH_TIME=5\nTIMEOUT_TIME=300\nSYSTEMD_WATCHDOG_CONFIG=\"[Manager]\nRuntimeWatchdogSec=0\nRebootWatchdogSec=0\nKExecWatchdogSec=0\n\"\n\n##############################################\n# UTILITY FUNCTIONS\n##############################################\n# Run preInstall function and start watchdog if needed\nfunction runPreInstall {\n    if [ -f \"${WD_TMP_FILE}\" ]; then\n        WATCHDOG_DEVICE=`cat ${WD_TMP_FILE}`\n        preInstall &\n        PID=$!\n        START=$(date +%s)\n        \n        while [ -d \"/proc/$PID\" ]; do\n            echo w > ${WATCHDOG_DEVICE}\n            DELTA=$(($(date +%s) - $START))\n            if [ \"$DELTA\" -ge \"$TIMEOUT_TIME\" ]; then\n                echo \"The installation process is not responding. It'll be stopped.\"\n                kill -9 $PID >> /dev/null 2>&1\n            fi\n            sleep $REFRESH_TIME\n        done\n        stopWatchdog\n    else\n        preInstall &\n        PID=$!\n        START=$(date +%s)\n        \n        while [ -d \"/proc/$PID\" ]; do\n            DELTA=$(($(date +%s) - $START))\n            if [ \"$DELTA\" -ge \"$TIMEOUT_TIME\" ]; then\n                echo \"The installation process is not responding. It'll be stopped.\"\n                kill -9 $PID >> /dev/null 2>&1\n            fi\n            sleep $REFRESH_TIME\n        done\n    fi\n}\n\n# Deactivate watchdog device if possible\nfunction stopWatchdog {\n    if [ -n \"${WATCHDOG_DEVICE}\" ]; then\n        echo V > ${WATCHDOG_DEVICE}\n    fi\n}\n\nfunction disable_systemd_watchdog() {\n    # disable systemd watchdog\n    # https://manpages.debian.org/testing/systemd/systemd-system.conf.5.en.html\n    #\n    # Order of application of conf files:\n    # 1. /usr/lib/systemd/system.conf.d/\n    # 2. /usr/local/lib/systemd/system.conf.d/\n    # 3. /etc/systemd/system.conf.d/\n    # docs suggest to use 10-40 priority for drop-ins in /usr/, and 50-90 for /etc/\n    # we use zz since some OSs do not respect that convention (raspbian, ubuntu jammy)\n    #\n    path=\"\"\n    if [ -d /usr/lib/systemd/system.conf.d/ ]; then\n        path=\"/usr/lib/systemd/system.conf.d\"\n    elif [ -d /usr/local/lib/systemd/system.conf.d/ ]; then\n        path=\"/usr/local/lib/systemd/system.conf.d\"\n    elif [ -d /etc/systemd/system.conf.d/ ]; then\n        path=\"/etc/systemd/system.conf.d\"        \n    fi\n\n    if [ ! -z \"${path}\" ]; then\n        echo \"Installing $path/zz-kura-disable-watchdog.conf\"\n        echo -e \"${SYSTEMD_WATCHDOG_CONFIG}\" > ${path}/zz-kura-disable-watchdog.conf\n        chmod 644 ${path}/zz-kura-disable-watchdog.conf\n        systemctl daemon-reload\n    else\n        echo \"No systemd drop-in directory found, watchdog not disabled\"\n    fi\n}\n\n# Pre-install script\nfunction preInstall {\n    #clean up old installation if present\n    rm -fr /opt/eclipse/kura* >> /tmp/kura_install.log 2>&1\n    rm -fr ${INSTALL_DIR}/kura* >> /tmp/kura_install.log 2>&1\n    rm -fr /tmp/.kura/ >> /tmp/kura_install.log 2>&1\n    rm /var/log/kura.log >> /tmp/kura_install.log 2>&1\n    rm -f kura-*.zip >> /tmp/kura_install.log 2>&1\n    rm -f kura_*.zip >> /tmp/kura_install.log 2>&1\n    echo \"\"\n}\n##############################################\n# END UTILITY FUNCTIONS\n##############################################\n\n##############################################\n# PRE-INSTALL SCRIPT\n##############################################\nPIDS=`pgrep java`\n\necho \"\"\necho \"Installing Kura...\"\necho \"Installing Kura...\" > /tmp/kura_install.log 2>&1\n\n#Kill JVM and monit for installation\nif [ -f \"/var/run/kura.pid\" ] ; then\n  KURA_PID=`cat /var/run/kura.pid`\n\n  for pid in \"${PIDS[@]}\"\n  do\n    if [ \"$KURA_PID\" == \"$pid\" ] ; then\n      `kill $pid` >> /tmp/kura_install.log 2>&1\n    fi\n  done\nfi\n\ndisable_systemd_watchdog\nrunPreInstall\n##############################################\n# END PRE-INSTALL SCRIPT\n##############################################\n\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/deb/control/prerm",
    "content": "#!/bin/bash\n#\n# Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n#\n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n# SPDX-License-Identifier: EPL-2.0\n#\n# Contributors:\n#  Eurotech\n#\n\nINSTALL_DIR=/opt/eclipse\nWD_TMP_FILE=/tmp/watchdog\nREFRESH_TIME=5\nTIMEOUT_TIME=300\nTIMESTAMP=$(date +%Y%m%d%H%M)\nLOG=/tmp/kura_uninstall_${TIMESTAMP}.log\n\n##############################################\n# UTILITY FUNCTIONS\n##############################################\n# Run preRemove function and start watchdog if needed\nfunction runPreRemove {\n    if [ -f \"${WD_TMP_FILE}\" ]; then\n        WATCHDOG_DEVICE=`cat ${WD_TMP_FILE}`\n        preRemove &\n        PID=$!\n        START=$(date +%s)\n        \n        while [ -d \"/proc/$PID\" ]; do\n            echo w > ${WATCHDOG_DEVICE}\n            DELTA=$(($(date +%s) - $START))\n            if [ \"$DELTA\" -ge \"$TIMEOUT_TIME\" ]; then\n                echo \"The installation process is not responding. It'll be stopped.\"\n                kill -9 $PID >> /dev/null 2>&1\n            fi\n            sleep $REFRESH_TIME\n        done\n        stopWatchdog\n    else\n        preRemove &\n        PID=$!\n        START=$(date +%s)\n        \n        while [ -d \"/proc/$PID\" ]; do\n            DELTA=$(($(date +%s) - $START))\n            if [ \"$DELTA\" -ge \"$TIMEOUT_TIME\" ]; then\n                echo \"The installation process is not responding. It'll be stopped.\"\n                kill -9 $PID >> /dev/null 2>&1\n            fi\n            sleep $REFRESH_TIME\n        done\n    fi\n}\n\n# Deactivate watchdog device if possible\nfunction stopWatchdog {\n    if [ -n \"${WATCHDOG_DEVICE}\" ]; then\n        echo V > ${WATCHDOG_DEVICE}\n    fi\n}\n\nfunction restore_systemd_watchdog() {\n    file_to_restore=\"\"\n\n    if [ -f /usr/lib/systemd/system.conf.d/zz-kura-disable-watchdog.conf ]; then\n        file_to_restore=\"/usr/lib/systemd/system.conf.d/zz-kura-disable-watchdog.conf\"\n    fi\n    if [ -f /usr/local/lib/systemd/system.conf.d/zz-kura-disable-watchdog.conf ]; then\n        file_to_restore=\"/usr/local/lib/systemd/system.conf.d/zz-kura-disable-watchdog.conf\"\n    fi\n    if [ -f /etc/systemd/system.conf.d/zz-kura-disable-watchdog.conf ]; then\n        file_to_restore=\"/etc/systemd/system.conf.d/zz-kura-disable-watchdog.conf\"\n    fi\n\n    if [ ! -z \"${file_to_restore}\" ]; then\n        echo \"Restoring systemd watchdog configuration: removing ${file_to_restore}\"\n        rm \"${file_to_restore}\"\n        systemctl daemon-reload\n    fi\n}\n\nfunction restore_backup_files {\n    SUFFIX=\"${1}\"\n\n    shift\n\n    for file in \"${@}\"\n    do\n        if [ -f \"${file}\" ] && expr \"${file}\" : \".*[.]${SUFFIX}$\" > /dev/null; then\n            mv \"${file}\" \"${file%.\"${SUFFIX}\"}\"\n        fi\n    done\n}\n\n# Pre-remove script\nfunction preRemove {\n    #Remove INIT scripts\n    if [ -f /etc/init.d/kura ] ; then\n        rm /etc/init.d/kura\n        update-rc.d kura remove\n    fi\n    if [ -f /lib/systemd/system/kura.service ] ; then\n        systemctl disable kura\n        rm /lib/systemd/system/kura.service\n    fi\n\n    rm -f  /var/log/kura*.log\n    rm -f  /var/log/kura*.gz\n    rm -rf /tmp/.kura\n    rm -rf /tmp/kura\n\n    if [ -d \"${INSTALL_DIR}/kura\" ] ; then\n      ${INSTALL_DIR}/kura/.data/manage_kura_users.sh -u\n      PARENT=`readlink -f ${INSTALL_DIR}/kura`\n      rm -rf ${INSTALL_DIR}/kura\n      rm -rf $PARENT\n    fi\n\n    restore_systemd_watchdog\n}\n##############################################\n# END UTILITY FUNCTIONS\n##############################################\n\n##############################################\n# PRE-REMOVE SCRIPT\n##############################################\n\n# Fail if the first argument is 'upgrade' or 'failed-upgrade'\nif [ \"$1\" == \"upgrade\" ]; then\n    echo \"\"\n    echo \"#####################################################################\"\n    echo \"#                                                                   #\"\n    echo \"#  ERROR: KURA upgrade is NOT supported!                            #\"\n    echo \"#  Please uninstall the existing version before upgrading.          #\"\n    echo \"#                                                                   #\"\n    echo \"#  To prevent accidental upgrades, you can hold this package with:  #\"\n    echo \"#      sudo apt-mark hold kura                                      #\"\n    echo \"#                                                                   #\"\n    echo \"#####################################################################\"\n    echo \"\"\n    exit 1\nfi\n\nif [ \"$1\" == \"failed-upgrade\" ]; then\n    echo \"This package cannot be upgraded. Please uninstall the existing version before installing a new one.\"\n    exit 1\nfi\n\necho \"\"\necho \"Uninstalling KURA...\"\n\nPIDS=`pgrep java`\n\n#Kill JVM and monit for installation\nif [ -f \"/var/run/kura.pid\" ] ; then\n  KURA_PID=`cat /var/run/kura.pid`\n\n  for pid in \"${PIDS[@]}\"\n  do\n    if [ \"$KURA_PID\" == \"$pid\" ] ; then\n      `kill $pid` >> \"$LOG\" 2>&1\n    fi\n  done\nfi\n\nrunPreRemove >> \"$LOG\" 2>&1\n\nmkdir -p /opt/eclipse/kura/log/\nmv \"$LOG\" /opt/eclipse/kura/log/\n\necho \"\"\necho \"Uninstalling KURA... Done!\"\n##############################################\n# END PRE-REMOVE SCRIPT\n##############################################\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/bin/gen_config_ini.sh",
    "content": "#!/bin/sh\n\nTEMPLATE=$1\nROOT=$2\n\nusage() {\n    >&2 echo \"Usage: gen_config_ini.sh <config.ini template> <plugin root directory>\"\n}\n\nabspath() {\n    cd \"${1}\" || exit 1\n    RESULT=\"${PWD}\"\n    cd \"${OLDPWD}\" || exit 1\n    echo \"${RESULT}\"\n}\n\nif ! [ -e \"${TEMPLATE}\" ]\nthen\n    >&2 echo \"config.ini template not found\"\n    usage\n    exit 1\nfi\n\nif ! [ -d \"${ROOT}\" ]\nthen\n    >&2 echo \"plugin root directory not found\"\n    usage\n    exit 1\nfi\n\nROOT=$(abspath \"${ROOT}\")\n\nOSGI_BUNDLES=\n\nfor DIR_PATH in \"${ROOT}\"/*\ndo\n    DIR_NAME=$(basename -- \"${DIR_PATH}\")\n\n    if [ \"${#DIR_NAME}\" = 0 ] || [ \"${#DIR_NAME}\" -gt 2 ] || ! [ -d \"${DIR_PATH}\" ]\n    then\n        continue\n    fi\n\n    if ! expr \"${DIR_NAME}\" : '[0-9]\\{1,\\}s\\{0,1\\}$' > /dev/null\n    then\n        continue\n    fi\n\n    START_LEVEL=\"${DIR_NAME%s}\"\n    \n    if [ \"${#DIR_NAME}\" = \"${#START_LEVEL}\" ]\n    then\n        START=\n    else\n        START=\"\\:start\"\n    fi\n\n    for JAR in \"${DIR_PATH}\"/*.jar\n    do\n        if [ -n \"${OSGI_BUNDLES}\" ]\n        then\n            OSGI_BUNDLES=\"${OSGI_BUNDLES},\"\n        fi\n        \n        OSGI_BUNDLES=\"${OSGI_BUNDLES}reference\\:file\\:${JAR}@${START_LEVEL}${START}\"\n    done\n\ndone\n\ncat \"${TEMPLATE}\"\necho\necho \"osgi.bundles=${OSGI_BUNDLES}\""
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/framework/config.ini",
    "content": "#Configuration File\nosgi.framework=file\\:plugins/org.eclipse.osgi-3.21.0.jar\nequinox.use.ds=true\nosgi.nl=en_us\nosgi.clean=true\nosgi.noShutdown=true\nosgi.bundles.defaultStartLevel=5\nosgi.framework.extensions=\nosgi.instance.area=/tmp/.kura/data\norg.osgi.service.http.port=80\nosgi.configuration.cascaded=false\neclipse.ignoreApp=true\niagent.controller=false\nds.lock.timeout.milliseconds=60000"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/install/customize-installation.sh",
    "content": "#!/bin/bash\n#\n#  Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsetup_libudev() {\n    # create soft link for libudev.so.0 to make it retrocompatible\n    # https://unix.stackexchange.com/questions/156776/arch-ubuntu-so-whats-the-deal-with-libudev-so-0\n    if [ ! -f /lib/libudev.so.0 ] && [ -f /lib/libudev.so.1 ]; then\n        ln -sf /lib/libudev.so.1 /lib/libudev.so.0\n    fi\n\n    if uname -m | grep -q arm ; then\n        destination=\"/usr/lib/arm-linux-gnueabihf/libudev.so.1\"\n        link_name=\"/usr/lib/arm-linux-gnueabihf/libudev.so.0\"\n    fi\n    if uname -m | grep -q aarch ; then\n        destination=\"/usr/lib/aarch64-linux-gnu/libudev.so.1\"\n        link_name=\"/usr/lib/aarch64-linux-gnu/libudev.so.0\"\n    fi\n    if uname -m | grep -q x86_64 ; then\n         destination=\"/usr/lib/x86_64-linux-gnu/libudev.so.1\"\n        link_name=\"/usr/lib/x86_64-linux-gnu/libudev.so.0\"\n    fi\n\n    if [ -f \"${destination}\" ] && [ ! -f \"${link_name}\" ]; then\n        echo \"Setting up symlink ${link_name} -> ${destination}\"\n        ln -sf \"${destination}\" \"${link_name}\"\n    fi\n}\n\ninstall_snapshot() {\n    if [ ! -d \"/opt/eclipse/kura/user/snapshots/\" ]; then\n        mkdir /opt/eclipse/kura/user/snapshots/\n    fi\n\n    mv \"/opt/eclipse/kura/install/snapshot_0.xml\" \"/opt/eclipse/kura/user/snapshots/snapshot_0.xml\"\n}\n\ncustomize_kura_properties() {\n    local BOARD=$1\n    \n    KURA_PLATFORM=$( uname -m )\n    sed -i \"s/kura_platform/${KURA_PLATFORM}/g\" \"/opt/eclipse/kura/framework/kura.properties\"\n\n    python3 \"/opt/eclipse/kura/install/customize_kura_properties.py\" \"${BOARD}\"\n}\n\ncustomize_ram() {\n    local BOARD=$1\n    \n    if [ ${BOARD} = \"generic-device\" ]; then    \n        # dynamic RAM assignment\n        RAM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')\n        RAM_MB=$(expr $RAM_KB / 1024)\n        RAM_MB_FOR_KURA=$(expr $RAM_MB / 4)\n    \n        if [ \"$RAM_MB\" -lt 1024 ]; then\n            RAM_MB_FOR_KURA=\"256\"\n        fi\n    \n        echo \"Setting kura RAM to ${RAM_MB_FOR_KURA}\"\n    \n        RAM_REPLACEMENT_STRING=\"-Xms${RAM_MB_FOR_KURA}m -Xmx${RAM_MB_FOR_KURA}m\"\n\n        echo \"Updating RAM values for start_kura.sh\"\n        sed -i \"s/-Xms[0-9]*m -Xmx[0-9]*m/$RAM_REPLACEMENT_STRING/g\" \"/opt/eclipse/kura/bin/start_kura.sh\"\n\n    fi\n}\n\nsetup_libudev\n\nBOARD=\"generic-device\"\nif uname -a | grep -q 'raspberry' > /dev/null 2>&1\nthen\n    BOARD=\"raspberry\"\n    echo \"Customizing installation for Raspberry PI\"\nfi\n\ninstall_snapshot\ncustomize_kura_properties \"${BOARD}\"\ncustomize_ram \"${BOARD}\"\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/install/customize_kura_properties.py",
    "content": "#!/usr/bin/env python3\n#\n# Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n#\n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n# SPDX-License-Identifier: EPL-2.0\n#\n# Contributors:\n#  Eurotech\n#\nimport sys\nimport logging\nimport argparse\n\nsys.path.append(\"/opt/eclipse/kura/.data\")\n\nfrom network_tools import get_eth_wlan_interfaces_names\n\ndef main():\n    logging.basicConfig(\n        format='[customize_kura_properties.py] %(asctime)s %(levelname)s %(message)s',\n        level=logging.INFO,\n        datefmt='%Y-%m-%d %H:%M:%S',\n        handlers=[\n            logging.StreamHandler()\n        ]\n    )\n    \n    parser = argparse.ArgumentParser(description=\"Customize kura properties file\", usage='%(prog)s device_name')\n    parser.add_argument('device_name', help='The name of the device')\n    args = parser.parse_args()\n       \n    KURA_PROPERTIES_FILENAME = \"/opt/eclipse/kura/framework/kura.properties\"\n    \n    (eth_names, wlan_names) = get_eth_wlan_interfaces_names()\n    \n    if len(eth_names) == 0:\n        logging.info(\"ERROR: no ethernet interface found\")\n        exit(1)\n    \n    logging.info(\"%s : starting editing\", KURA_PROPERTIES_FILENAME)\n    with open(KURA_PROPERTIES_FILENAME, 'r', encoding='utf-8') as kura_properties:\n        kura_properties_content = kura_properties.read()\n        \n    kura_properties_content = kura_properties_content.replace('device_name', args.device_name)\n    kura_properties_content = kura_properties_content.replace('eth0', eth_names[0])\n    \n    with open(KURA_PROPERTIES_FILENAME, 'w', encoding='utf-8') as kura_properties:\n        kura_properties.write(kura_properties_content)\n        \n    logging.info(\"%s : successfully edited\", KURA_PROPERTIES_FILENAME)\n            \nif __name__ == \"__main__\":\n    main()"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/install/kura-tmpfiles.conf",
    "content": "# Kura specific file. Do not edit!\n\nx /tmp/.kura\nx /tmp/kura\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/install/manage_kura_users.sh",
    "content": "#!/bin/bash\n#\n#  Copyright (c) 2020, 2024 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nfunction create_users {\n    # create kura user without home directory\n    useradd -M kura\n    # disable login for kura user\n    passwd -l kura\n\n    # create kurad system user without home directory\n    useradd -r -M kurad\n    # disable login for kurad user\n    KURAD_USER_ENTRY=$(cat /etc/passwd | grep kurad:)\n    sed -i \"s@${KURAD_USER_ENTRY}@${KURAD_USER_ENTRY%:*}:/sbin/nologin@\" /etc/passwd\n    passwd -l kurad\n    # add kurad to dialout group (for managing serial ports)\n    gpasswd -a kurad dialout\n\n    # get polkit package version\n    POLKIT=$(apt list --installed | grep libpolkit)\n    IFS=\" \" POLKIT_ARRAY=($POLKIT)\n    POLKIT_VERSION=${POLKIT_ARRAY[1]}\n\n    # add polkit policy\n    if [[ ${POLKIT_VERSION} < 0.106 ]]; then\n        if [ ! -f /etc/polkit-1/localauthority/50-local.d/51-org.freedesktop.systemd1.pkla ]; then\n            echo \"[No password prompt for kurad user]\nIdentity=unix-user:kurad\nAction=org.freedesktop.systemd1.*\nResultInactive=no\nResultActive=no\nResultAny=yes\" >/etc/polkit-1/localauthority/50-local.d/51-org.freedesktop.systemd1.pkla\n        fi\n        if [[ $NN == \"NO\" ]]; then\n            if [ ! -f /etc/polkit-1/localauthority/50-local.d/52-org.freedesktop.networkmanager.pkla ]; then\n                echo \"[No password prompt for kurad user when using NetworkManager]\nIdentity=unix-user:kurad\nAction=org.freedesktop.NetworkManager.*\nResultInactive=no\nResultActive=no\nResultAny=yes\" >/etc/polkit-1/localauthority/50-local.d/52-org.freedesktop.networkmanager.pkla\n            fi\n            if [ ! -f /etc/polkit-1/localauthority/50-local.d/53-org.freedesktop.modemmanager.pkla ]; then\n                echo \"[No password prompt for kurad user when using ModemManager]\nIdentity=unix-user:kurad\nAction=org.freedesktop.ModemManager1.*\nResultInactive=no\nResultActive=no\nResultAny=yes\" >/etc/polkit-1/localauthority/50-local.d/53-org.freedesktop.modemmanager.pkla\n            fi\n            if [ ! -f /etc/polkit-1/localauthority/50-local.d/54-fi.w1.wpa_supplicant1.pkla ]; then\n                echo \"[No password prompt for kurad user when using Wpa Supplicant]\nIdentity=unix-user:kurad\nAction=fi.w1.wpa_supplicant1.*\nResultInactive=no\nResultActive=no\nResultAny=yes\" >/etc/polkit-1/localauthority/50-local.d/54-fi.w1.wpa_supplicant1.pkla\n            fi\n        fi\n    else\n        if [[ $NN == \"NO\" ]]; then\n            if [ ! -f /usr/share/polkit-1/rules.d/kura.rules ]; then\n                echo \"polkit.addRule(function(action, subject) {\n        if (action.id == \\\"org.freedesktop.systemd1.manage-units\\\" &&\n            subject.user == \\\"kurad\\\" &&\n            (action.lookup(\\\"unit\\\") == \\\"named.service\\\" ||\n            action.lookup(\\\"unit\\\") == \\\"chrony.service\\\" ||\n            action.lookup(\\\"unit\\\") == \\\"chronyd.service\\\" )) {\n            return polkit.Result.YES;\n        }\n        if (action.id == \\\"org.freedesktop.systemd1.manage-unit-files\\\" &&\n            subject.user == \\\"kurad\\\") {\n            return polkit.Result.YES;\n        }\n        if ((action.id == \\\"org.freedesktop.login1.reboot-multiple-sessions\\\" ||\n            action.id == \\\"org.freedesktop.login1.suspend-multiple-sessions\\\" ||\n            action.id == \\\"org.freedesktop.login1.power-off-multiple-sessions\\\") &&\n            subject.user == \\\"kurad\\\") {\n            return polkit.Result.YES;\n        }\n    });\" >/usr/share/polkit-1/rules.d/kura.rules\n            fi\n            if [ ! -f /usr/share/polkit-1/rules.d/kura-nm.rules ]; then\n                echo \"polkit.addRule(function(action, subject) {\n        if ((action.id.indexOf(\\\"org.freedesktop.NetworkManager.\\\") == 0 ||\n            action.id.indexOf(\\\"org.freedesktop.ModemManager1.\\\") == 0 ||\n            action.id.indexOf(\\\"fi.w1.wpa_supplicant1.\\\") == 0) &&\n            subject.user == \\\"kurad\\\") {\n            return polkit.Result.YES;\n        }\n    });\" >/usr/share/polkit-1/rules.d/kura-nm.rules\n            fi\n        else\n            echo \"polkit.addRule(function(action, subject) {\nif (action.id == \\\"org.freedesktop.systemd1.manage-units\\\" &&\n    subject.user == \\\"kurad\\\" &&\n    (action.lookup(\\\"unit\\\") == \\\"chrony.service\\\" ||\n    action.lookup(\\\"unit\\\") == \\\"chronyd.service\\\" )) {\n    return polkit.Result.YES;\n}\nif (action.id == \\\"org.freedesktop.systemd1.manage-unit-files\\\" &&\n    subject.user == \\\"kurad\\\") {\n    return polkit.Result.YES;\n}\nif ((action.id == \\\"org.freedesktop.login1.reboot-multiple-sessions\\\" ||\n    action.id == \\\"org.freedesktop.login1.suspend-multiple-sessions\\\" ||\n    action.id == \\\"org.freedesktop.login1.power-off-multiple-sessions\\\") &&\n    subject.user == \\\"kurad\\\") {\n    return polkit.Result.YES;\n}\n});\" >/usr/share/polkit-1/rules.d/kura.rules\n        fi\n    fi\n\n    # modify pam policy\n    if [ -f /etc/pam.d/su ]; then\n        sed -i '/^auth       sufficient pam_rootok.so/a auth       [success=ignore default=1] pam_succeed_if.so user = kura\\nauth       sufficient                 pam_succeed_if.so use_uid user = kurad' /etc/pam.d/su\n    fi\n\n    # grant kurad user the privileges to manage wpa supplicant via dbus\n    if ! grep -lR kurad /etc/dbus-1/system.d/wpa_supplicant.conf && [ $NN == \"NO\" ]; then\n        cp /etc/dbus-1/system.d/wpa_supplicant.conf /etc/dbus-1/system.d/wpa_supplicant.conf.save\n        awk 'done != 1 && /^<\\/busconfig>/ {\n            print \"    <policy user=\\\"kurad\\\">\"\n            print \"        <allow own=\\\"fi.w1.wpa_supplicant1\\\"/>\"\n            print \"        <allow send_destination=\\\"fi.w1.wpa_supplicant1\\\"/>\"\n            print \"        <allow send_interface=\\\"fi.w1.wpa_supplicant1\\\"/>\"\n            print \"        <allow receive_sender=\\\"fi.w1.wpa_supplicant1\\\" receive_type=\\\"signal\\\"/>\"\n            print \"    </policy>\\n\"\n            done = 1\n        } 1' /etc/dbus-1/system.d/wpa_supplicant.conf >tempfile && mv tempfile /etc/dbus-1/system.d/wpa_supplicant.conf\n    fi\n\n    # Change kura folder ownership and permission\n    chown -R kurad:kurad /opt/eclipse\n    chmod -R +X /opt/eclipse\n}\n\nfunction delete_users {\n    # delete kura user\n    userdel kura\n\n    # we cannot delete kurad system user because there should be several process owned by this user,\n    # so only try to remove it from sudoers.\n    if [ -f /etc/sudoers.d/kurad ]; then\n        rm -f /etc/sudoers.d/kurad\n    fi\n    # remove kurad from dialout group\n    gpasswd -d kurad dialout\n\n    # remove polkit policy\n    if [ -f /usr/share/polkit-1/rules.d/kura.rules ]; then\n        rm -f /usr/share/polkit-1/rules.d/kura.rules\n    fi\n    if [ -f /etc/polkit-1/localauthority/50-local.d/51-org.freedesktop.systemd1.pkla ]; then\n        rm -f /etc/polkit-1/localauthority/50-local.d/51-org.freedesktop.systemd1.pkla\n    fi\n    if [ -f /etc/polkit-1/localauthority/50-local.d/52-org.freedesktop.networkmanager.pkla ]; then\n        rm -f /etc/polkit-1/localauthority/50-local.d/52-org.freedesktop.networkmanager.pkla\n    fi\n    if [ -f /etc/polkit-1/localauthority/50-local.d/53-org.freedesktop.modemmanager.pkla ]; then\n        rm -f /etc/polkit-1/localauthority/50-local.d/53-org.freedesktop.modemmanager.pkla\n    fi\n    if [ -f /etc/polkit-1/localauthority/50-local.d/54-fi.w1.wpa_supplicant1.pkla ]; then\n        rm -f /etc/polkit-1/localauthority/50-local.d/54-fi.w1.wpa_supplicant1.pkla\n    fi\n\n    # recover pam policy\n    if [ -f /etc/pam.d/su ]; then\n        sed -i '/^auth       sufficient pam_rootok.so/ {n;d}' /etc/pam.d/su\n        sed -i '/^auth       sufficient pam_rootok.so/ {n;d}' /etc/pam.d/su\n    fi\n\n    # recover old configs\n    mv /etc/dbus-1/system.d/wpa_supplicant.conf.save /etc/dbus-1/system.d/wpa_supplicant.conf\n}\n\nINSTALL=YES\nNN=NO\n\nwhile [[ $# > 0 ]]; do\n    key=\"$1\"\n\n    case $key in\n    -i | --install)\n        INSTALL=YES\n        ;;\n    -u | --uninstall)\n        INSTALL=NO\n        ;;\n    -nn)\n        NN=YES\n        ;;\n    -h | --help)\n        echo\n        echo \"Options:\"\n        echo \"    -i | --install    create kura default users\"\n        echo \"    -u | --uninstall  delete kura default users\"\n        echo \"    -nn               set kura no network version\"\n        echo \"Default: --install\"\n        exit 0\n        ;;\n    *)\n        echo \"Unknown option.\"\n        exit 1\n        ;;\n    esac\n    shift # past argument or value\ndone\n\nif [[ $INSTALL == \"YES\" ]]; then\n    create_users\nelse\n    delete_users\nfi\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/install/network_tools.py",
    "content": "#!/usr/bin/env python3\n#\n# Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n#\n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n# SPDX-License-Identifier: EPL-2.0\n#\n# Contributors:\n#  Eurotech\n#\nimport sys\nimport logging\nimport os\n\ndef get_interface_names():\n    if not os.path.exists(\"/sys/class/net\"):\n        logging.error(\"'/sys/class/net' does not exists, unable to read interface names. Exiting.\")\n        sys.exit(1)\n\n    return os.listdir(\"/sys/class/net\")\n\ndef get_eth_wlan_interfaces_names():\n    \"\"\"Reads the network interface names present on the device.\n\n    It is assumed that at least one ethernet interface is present.\n\n    Requirements:\n        \"/sys/class/net\" directory must exist\n\n    Returns:\n        tuple of lists (eth_names, wlan_names) where:\n            'eth_names' are the found ethernet interface names sorted by name;\n            'wlan_names' are the found wireless interface names sorted by name, might be an empty list.\n    \"\"\"\n    ethernet_interface_names = list()\n    wireless_interface_names = list()\n\n    interface_names = get_interface_names()\n    \n    for ifname in interface_names:\n        if ifname.startswith(\"en\") or ifname.startswith(\"et\"):\n            ethernet_interface_names.append(ifname)\n        if ifname.startswith(\"wl\"):\n            wireless_interface_names.append(ifname)\n\n    ethernet_interface_names.sort()\n    wireless_interface_names.sort()\n\n    if len(ethernet_interface_names) < 1:\n        logging.error(\"No ethernet interfaces found, exiting.\")\n        sys.exit(1)\n\n    logging.info(\"Found ethernet interfaces: %s\", ethernet_interface_names)\n    logging.info(\"Found wireless interfaces: %s\", wireless_interface_names)\n    return (ethernet_interface_names, wireless_interface_names)\n    "
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/install/snapshot_0.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<!--\n\n    Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<esf:configurations xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" xmlns:esf=\"http://eurotech.com/esf/2.0\">\n    <esf:configuration pid=\"org.eclipse.kura.watchdog.WatchdogService\">\n        <esf:properties>\n            <esf:property name=\"enabled\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property name=\"service.pid\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>org.eclipse.kura.watchdog.WatchdogService</esf:value>\n            </esf:property>\n            <esf:property name=\"pingInterval\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>10000</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.clock.ClockService\">\n        <esf:properties>\n            <esf:property name=\"enabled\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.ntp.port\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>123</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.ntp.refresh-interval\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>3600</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.provider\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>java-ntp</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.set.hwclock\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.ntp.timeout\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>10000</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.ntp.host\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>0.pool.ntp.org</esf:value>\n            </esf:property>\n            <esf:property name=\"service.pid\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>org.eclipse.kura.clock.ClockService</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.db.H2DbService\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.user\" type=\"String\">\n                <esf:value>SA</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.connection.pool.max.size\" type=\"Integer\">\n                <esf:value>10</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.connector.url\" type=\"String\">\n                <esf:value>jdbc:h2:mem:kuradb</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.db.H2DbService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.checkpoint.interval.seconds\" type=\"Integer\">\n                <esf:value>900</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.db.H2DbService</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"in-flight.persistence\" type=\"String\">\n                <esf:value>memory</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"clean-session\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"lwt.retain\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"protocol-version\" type=\"Integer\">\n                <esf:value>4</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"timeout\" type=\"Integer\">\n                <esf:value>20</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"broker-url\" type=\"String\">\n                <esf:value>mqtt://broker-url:1883/</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"keep-alive\" type=\"Integer\">\n                <esf:value>30</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"topic.context.account-name\" type=\"String\">\n                <esf:value>account-name</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"lwt.topic\" type=\"String\">\n                <esf:value>$EDC/#account-name/#client-id/MQTT/LWT</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"lwt.qos\" type=\"Integer\">\n                <esf:value>0</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"ssl.hostname.verification\" type=\"String\">\n                <esf:value>use-ssl-service-config</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.cloud.service.factory.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"username\" type=\"String\">\n                <esf:value>username</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.data.DataService\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"store.purge-age\" type=\"Integer\">\n                <esf:value>60</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"in-flight-messages.congestion-timeout\" type=\"Integer\">\n                <esf:value>0</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"enable.rate.limit\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"in-flight-messages.max-number\" type=\"Integer\">\n                <esf:value>9</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.data.DataService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"connection.recovery.max.failures\" type=\"Integer\">\n                <esf:value>10</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"disconnect.quiesce-timeout\" type=\"Integer\">\n                <esf:value>10</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.data.DataService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"store.housekeeper-interval\" type=\"Integer\">\n                <esf:value>900</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"connect.auto-on-startup\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"rate.limit.time.unit\" type=\"String\">\n                <esf:value>SECONDS</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"rate.limit.average\" type=\"Integer\">\n                <esf:value>1</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"store.db.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.db.H2DbService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"DataTransportService.target\" type=\"String\">\n                <esf:value>(kura.service.pid=org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport)</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"connect.retry-interval\" type=\"Integer\">\n                <esf:value>60</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"enable.recovery.on.connection.failure\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"rate.limit.burst.size\" type=\"Integer\">\n                <esf:value>1</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.cloud.service.factory.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"in-flight-messages.republish-on-new-session\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"store.capacity\" type=\"Integer\">\n                <esf:value>1000</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.cloud.CloudService\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"topic.control-prefix\" type=\"String\">\n                <esf:value>$EDC</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"device.custom-name\" type=\"String\">\n                <esf:value>Unknown Generic Device</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"device.display-name\" type=\"String\">\n                <esf:value>device-name</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"payload.encoding\" type=\"String\">\n                <esf:value>kura-protobuf</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.cloud.CloudService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.cloud.CloudService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"enable.default.subscriptions\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"republish.mqtt.birth.cert.on.gps.lock\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"encode.gzip\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"DataService.target\" type=\"String\">\n                <esf:value>(kura.service.pid=org.eclipse.kura.data.DataService)</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.cloud.service.factory.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.ssl.SslManagerService\">\n        <esf:properties>\n            <esf:property name=\"ssl.default.protocol\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>TLSv1.2</esf:value>\n            </esf:property>\n            <esf:property name=\"ssl.hostname.verification\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"KeystoreService.target\" type=\"String\">\n                <esf:value>(kura.service.pid=SSLKeystore)</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.ssl.SslManagerService</esf:value>\n            </esf:property>\n            <esf:property name=\"service.ranking\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>100</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.http.server.manager.HttpService\">\n        <esf:properties>\n            <esf:property array=\"true\" encrypted=\"false\" name=\"https.ports\" type=\"Integer\">\n                <esf:value>443</esf:value>\n            </esf:property>\n            <esf:property array=\"true\" encrypted=\"false\" name=\"https.client.auth.ports\" type=\"Integer\">\n                <esf:value>4443</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"KeystoreService.target\" type=\"String\">\n                <esf:value>(kura.service.pid=HttpsKeystore)</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.http.server.manager.HttpService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.http.server.manager.HttpService</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"users.config\" type=\"String\">\n                <esf:value>[{\"name\":\"kura.user.admin\",\"credentials\":{\"kura.password\":\"jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg=\"},\"properties\":{\"kura.need.password.change\":\"true\"}}]</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"groups.config\" type=\"String\">\n                <esf:value>[{\"name\":\"kura.permission.kura.admin\",\"basicMembers\":[\"kura.user.admin\"]},{\"name\":\"kura.permission.kura.cloud.connection.admin\"},{\"name\":\"kura.permission.kura.device\"},{\"name\":\"kura.permission.kura.maintenance\"},{\"name\":\"kura.permission.kura.network.admin\"},{\"name\":\"kura.permission.kura.packages.admin\"},{\"name\":\"kura.permission.kura.wires.admin\"},{\"name\":\"kura.permission.rest.assets\"},{\"name\":\"kura.permission.rest.cloudconnection\"},{\"name\":\"kura.permission.rest.command\"},{\"name\":\"kura.permission.rest.configuration\"},{\"name\":\"kura.permission.rest.deploy\"},{\"name\":\"kura.permission.rest.identity\"},{\"name\":\"kura.permission.rest.inventory\"},{\"name\":\"kura.permission.rest.keystores\"},{\"name\":\"kura.permission.rest.network.configuration\"},{\"name\":\"kura.permission.rest.network.status\"},{\"name\":\"kura.permission.rest.position\"},{\"name\":\"kura.permission.rest.security\"},{\"name\":\"kura.permission.rest.system\"},{\"name\":\"kura.permission.rest.tamper.detection\"},{\"name\":\"kura.permission.rest.wires.admin\"}]</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"HttpsKeystore\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"keystore.path\" type=\"String\">\n                <esf:value>/opt/eclipse/kura/user/security/httpskeystore.ks</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"true\" name=\"keystore.password\" type=\"Password\">\n                <esf:value>Y2hhbmdlaXQ=</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"randomize.password\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>HttpsKeystore</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"SSLKeystore\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"keystore.path\" type=\"String\">\n                <esf:value>/opt/eclipse/kura/user/security/cacerts.ks</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"true\" name=\"keystore.password\" type=\"Password\">\n                <esf:value>Y2hhbmdlaXQ=</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"randomize.password\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>SSLKeystore</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"filesystem-kura-log\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"logFilePath\" type=\"String\">\n                <esf:value>/var/log/kura.log</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>filesystem-kura-log</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider-1636726365743-7</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"filesystem-kura-audit-log\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"logFilePath\" type=\"String\">\n                <esf:value>/var/log/kura-audit.log</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>filesystem-kura-audit-log</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider-1636726365743-8</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.internal.rest.provider.RestService\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"auth.basic.enabled\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"auth.certificate.stateless.enabled\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.internal.rest.provider.RestService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.internal.rest.provider.RestService</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n</esf:configurations>\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/log4j/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2018, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<Configuration status=\"warn\" strict=\"true\" name=\"KuraConfig\" monitorInterval=\"30\">\n\n    <Properties>\n        <Property name=\"log_dir\">/var/log</Property>\n        <Property name=\"log_name\">kura</Property>\n    </Properties>\n    <Filter type=\"ThresholdFilter\" level=\"trace\" />\n\n    <Appenders>\n        <RollingFile name=\"RollingFile\" fileName=\"${log_dir}/${log_name}.log\"\n            filePattern=\"${log_dir}/${log_name}-%i.log.gz\">\n            <PatternLayout>\n                <Pattern>%d{ISO8601} [%t] %-5p %c{1.} - %m%n%throwable{full}</Pattern>\n            </PatternLayout>\n            <Policies>\n                <SizeBasedTriggeringPolicy size=\"10 MB\" />\n            </Policies>\n            <DefaultRolloverStrategy max=\"7\" />\n        </RollingFile>\n        <RollingFile name=\"audit\" fileName=\"${log_dir}/${log_name}-audit.log\"\n            filePattern=\"${log_dir}/${log_name}-audit-%i.log.gz\">\n            <Rfc5424Layout enterpriseNumber=\"28392\" includeMDC=\"true\" mdcId=\"RequestContext\"\n                appName=\"EclipseKura\" mdcPrefix=\"\" includeNL=\"true\">\n                <LoggerFields>\n                    <KeyValuePair key=\"thread\" value=\"%t\" />\n                    <KeyValuePair key=\"priority\" value=\"%p\" />\n                    <KeyValuePair key=\"category\" value=\"%c\" />\n                    <KeyValuePair key=\"exception\" value=\"%ex\" />\n                </LoggerFields>\n            </Rfc5424Layout>\n            <Policies>\n                <SizeBasedTriggeringPolicy size=\"10 MB\" />\n            </Policies>\n            <DefaultRolloverStrategy max=\"7\" />\n        </RollingFile>\n    </Appenders>\n\n    <Loggers>\n        <Logger name=\"org.eclipse\" level=\"info\" additivity=\"false\">\n            <AppenderRef ref=\"RollingFile\" />\n        </Logger>\n        <Logger name=\"org.glassfish.jersey.internal\" level=\"error\" additivity=\"false\">\n            <AppenderRef ref=\"RollingFile\" />\n        </Logger>\n        <Logger name=\"AuditLogger\" level=\"trace\" additivity=\"false\">\n            <AppenderRef ref=\"audit\" />\n        </Logger>\n        <Root level=\"info\">\n            <AppenderRef ref=\"RollingFile\" />\n        </Root>\n    </Loggers>\n\n</Configuration>\n"
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/packages/.gitkeep",
    "content": ""
  },
  {
    "path": "kura/distrib/src/main/resources/unfiltered/pkg/user/kura_custom.properties",
    "content": "#\n# Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n# Contributors:\n#  Eurotech\n#\n\n#  Do not edit the kura.properties file directly, as any changes there may be\n#  lost in subsequent Kura upgrades.  Instead, place those changes in this\n#  file to override the value in kura.properties, and they will be carried\n#  across any upgrades.\n\n## -----------------------------------------------------------------------------\n##  Kura Custom Properties\n## -----------------------------------------------------------------------------\n\n"
  },
  {
    "path": "kura/distrib/x86_64-core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <artifactId>distrib</artifactId>\n        <groupId>org.eclipse.kura</groupId>\n        <version>6.0.0-SNAPSHOT</version>\n        <relativePath>..</relativePath>\n    </parent>\n\n    <artifactId>x86_64-core</artifactId>\n\n    <packaging>pom</packaging>\n\n    <properties>\n        <kura.basedir>../</kura.basedir>\n        <kura.arch>x86_64</kura.arch>\n        <target.device>${kura.arch}</target.device>\n        <arch>${kura.arch}</arch>\n        <deb.name>kura-core</deb.name>\n        <deb.provides></deb.provides>\n        <deb.architecture>amd64</deb.architecture>\n        <skip.resource.copy>false</skip.resource.copy>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <artifactId>maven-resources-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.vafer</groupId>\n                <artifactId>jdeb</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator\nBundle-SymbolicName: org.eclipse.kura.emulator;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura.emulator; version=\"1.0.0\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.apache.commons.io;version=\"2.4.0\",\n org.apache.commons.lang3;version=\"3.4.0\",\n org.osgi.framework;version=\"1.7.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.7.25\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/OSGI-INF/emulator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" name=\"org.eclipse.kura.emulator.Emulator\">\n   <implementation class=\"org.eclipse.kura.emulator.Emulator\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.emulator.Emulator\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\noutput.. = target/classes/\nsource.. = src/main/java/,\\\n           src/main/resources/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nadditional.bundles = org.eclipse.osgi,\\\n                     slf4j.api\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n      Red Hat Inc - fix issue #603\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>emulator</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.emulator</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../../test/org.eclipse.kura.emulator.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\t\t\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/src/main/java/org/eclipse/kura/emulator/Emulator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.StringReader;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.commons.io.IOUtils;\nimport org.apache.commons.lang3.RandomStringUtils;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class Emulator {\n\n    private static final Logger logger = LoggerFactory.getLogger(Emulator.class);\n\n    private static final String KURA_SNAPSHOTS_PATH = \"kura.snapshots\";\n\n    private static final String EMULATOR = \"emulator\";\n\n    private static final String KURA_MODE = \"org.eclipse.kura.mode\";\n\n    private static final String SNAPSHOT_0_NAME = \"snapshot_0.xml\";\n\n    private static final String CLIENT_ID_PLACEHOLDER = \"{{client-id-placeholder}}\";\n\n    private ComponentContext componentContext;\n\n    protected void activate(ComponentContext componentContext) {\n        this.componentContext = componentContext;\n\n        try {\n            String mode = System.getProperty(KURA_MODE);\n\n            if (EMULATOR.equals(mode)) {\n                logger.info(\"Framework is running in emulation mode\");\n                final String snapshotFolderPath = System.getProperty(KURA_SNAPSHOTS_PATH);\n                if (snapshotFolderPath == null || snapshotFolderPath.isEmpty()) {\n                    throw new IllegalStateException(\"System property 'kura.snapshots' is not set\");\n                }\n                final File snapshotFolder = new File(snapshotFolderPath);\n                if (!snapshotFolder.exists() || snapshotFolder.list().length == 0) {\n                    snapshotFolder.mkdirs();\n                    copySnapshot(snapshotFolderPath);\n                }\n            } else {\n                logger.info(\"Framework is not running in emulation mode\");\n            }\n\n        } catch (Exception e) {\n            logger.info(\"Framework is not running in emulation mode or initialization failed!: {}\", e.getMessage());\n        }\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        this.componentContext = null;\n    }\n\n    private void copySnapshot(String snapshotFolderPath) throws IOException {\n        URL internalSnapshotURL = this.componentContext.getBundleContext().getBundle().getResource(SNAPSHOT_0_NAME);\n\n        try (InputStream fileInput = internalSnapshotURL.openStream();\n                OutputStream fileOutput = new FileOutputStream(snapshotFolderPath + File.separator + SNAPSHOT_0_NAME)) {\n\n            String generatedClientId = generateRandomClientId();\n\n            String newSnapshot0Content = IOUtils.toString(fileInput, StandardCharsets.UTF_8)\n                    .replace(CLIENT_ID_PLACEHOLDER, generatedClientId);\n\n            logger.info(\"generated new client-id: {}\", generatedClientId);\n\n            IOUtils.copy(new StringReader(newSnapshot0Content), fileOutput);\n        }\n    }\n\n    private String generateRandomClientId() {\n        return \"kura-emulator-\" + RandomStringUtils.randomNumeric(6);\n    }\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/src/main/resources/kura.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\n## -----------------------------------------------------------------------------\n##  Kura Properties\n## -----------------------------------------------------------------------------\nkura.name=Kura\nkura.version=kura_emulator\nkura.marketplace.compatibility.version=\nkura.company=Eclipse\nkura.project=Dev\nkura.platform=DevPlatform\nkura.device.name=DevEmulator\nkura.model.id=DevModelId\nkura.model.name=DevModelName\nkura.partNumber=DevPartNumber\nkura.serialNumber=DevSerialNumber\nkura.bios.version=DevBiosVersion\nkura.firmware.version=DevFirmwareVersion\n\n# Use this in Linux Emulator if your system support Predictable Network Interface Names\n# kura.primary.network.interface=eth0\n\n# kura.mac.address= Fetch from Java\nkura.home=/tmp/kura\nkura.framework.config=/tmp/kura/framework\nkura.user.config=/tmp/kura/user\nkura.plugins=/tmp/kura/plugins\nkura.packages=/tmp/kura/data/packages\nkura.data=/tmp/kura/data\nkura.tmp=/tmp/kura/tmp\nkura.snapshots=/tmp/kura/user/snapshots\nkura.snapshots.count=10\nkura.have.net.admin=false\n# os.arch= Fetch from Java\n# os.name= Fetch from Java\n# os.version= Fetch from Java\nos.distribution=DevOsDitribution\nos.distribution.version=DevOsDitributionVersion\n# java.version= Fetch from Java\n# java.vendor= Fetch from Java\n# java.vm.name= Fetch from Java\n# java.vm.version= Fetch from Java\n# java.home= Fetch from Java\n# file.separator= Fetch from Java\n\n## -----------------------------------------------------------------------------\n## File upload settings\n## -----------------------------------------------------------------------------\n# default 10240\nfile.upload.in.memory.size.threshold=10240\n# -1: unlimited (default)\nfile.upload.size.max=-1\nfile.command.zip.max.size=100\nfile.command.zip.max.number=1024\n\n\n\n## -----------------------------------------------------------------------------\n## Deployment Agent settings\n## -----------------------------------------------------------------------------\n# see copyURLToFile() http://commons.apache.org/proper/commons-io/javadocs/api-2.4/index.html\ndpa.connection.timeout = 60000\ndpa.read.timeout = 60000\n\n\n## -----------------------------------------------------------------------------\n## Cloud Connection Status settings\n## -----------------------------------------------------------------------------\n\n#1. Cloud Connection Status on system log\n#The Cloud Connection Status will be indicated in the log files, and nowere else\nccs.status.notification.url=ccs:log\n\n#2. Cloud Connection Status on LED\n#The Cloud Connection Status will be indicated by a blinking LED connected to the system GPIOs\n#The URL should identify the GPIO to be used, either by name or by terminal index as defined by Kura GpioService.\n# Syntax for using GPIO terminal index:\n#ccs.status.notification.url=ccs:led:16\n#ccs.status.notification.url=ccs:led:terminal:16\n# Syntax for using GPIO name:\n#ccs.status.notification.url=ccs:led:name:LED_1\n\n#3. Cloud Connection Status disabled\n#Disables the Cloud Connection Status service\n#ccs.status.notification.url=ccs:none\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/src/main/resources/log4j.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2018, 2025 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Eurotech\n     \n-->\n<Configuration status=\"warn\" strict=\"true\" name=\"KuraConfig\" monitorInterval=\"30\">\n\n    <Filter type=\"ThresholdFilter\" level=\"trace\"/>\n\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\">\n          <PatternLayout>\n              <Pattern>%d{ISO8601} [%t] %-5p %c{1.} - %m%n%throwable{full}</Pattern>\n          </PatternLayout>\n        </Console>\n    </Appenders>\n\n    <Loggers>\n        <Logger name=\"org.eclipse\" level=\"info\" additivity=\"false\">\n            <AppenderRef ref=\"Console\"/>\n        </Logger>\n        <Logger name=\"org.glassfish.jersey.internal\" level=\"error\" additivity=\"false\">\n            <AppenderRef ref=\"Console\"/>\n        </Logger>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\"/>\n        </Root>\n    </Loggers>\n\n</Configuration>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator/src/main/resources/snapshot_0.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<esf:configurations xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\"\n    xmlns:esf=\"http://eurotech.com/esf/2.0\">\n    <esf:configuration pid=\"org.eclipse.kura.watchdog.WatchdogService\">\n        <esf:properties>\n            <esf:property name=\"enabled\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property name=\"service.pid\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>org.eclipse.kura.watchdog.WatchdogService</esf:value>\n            </esf:property>\n            <esf:property name=\"pingInterval\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>10000</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.clock.ClockService\">\n        <esf:properties>\n            <esf:property name=\"enabled\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.ntp.port\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>123</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.ntp.refresh-interval\" array=\"false\" encrypted=\"false\"\n                type=\"Integer\">\n                <esf:value>3600</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.provider\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>java-ntp</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.set.hwclock\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.ntp.timeout\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>10000</esf:value>\n            </esf:property>\n            <esf:property name=\"clock.ntp.host\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>0.pool.ntp.org</esf:value>\n            </esf:property>\n            <esf:property name=\"service.pid\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>org.eclipse.kura.clock.ClockService</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\">\n        <esf:properties>\n            <esf:property name=\"clean-session\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"username\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>username</esf:value>\n            </esf:property>\n            <esf:property name=\"client-id\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>{{client-id-placeholder}}</esf:value>\n            </esf:property>\n            <esf:property name=\"topic.context.account-name\" array=\"false\" encrypted=\"false\"\n                type=\"String\">\n                <esf:value>account-name</esf:value>\n            </esf:property>\n            <esf:property name=\"broker-url\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>mqtt://broker-url:1883/</esf:value>\n            </esf:property>\n            <esf:property name=\"lwt.retain\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property name=\"in-flight.persistence\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>file</esf:value>\n            </esf:property>\n            <esf:property name=\"lwt.topic\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>$EDC/#account-name/#client-id/MQTT/LWT</esf:value>\n            </esf:property>\n            <esf:property name=\"keep-alive\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>30</esf:value>\n            </esf:property>\n            <esf:property name=\"service.pid\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</esf:value>\n            </esf:property>\n            <esf:property name=\"password\" array=\"false\" encrypted=\"false\" type=\"Password\">\n                <esf:value>password</esf:value>\n            </esf:property>\n            <esf:property name=\"timeout\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>20</esf:value>\n            </esf:property>\n            <esf:property name=\"lwt.qos\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>0</esf:value>\n            </esf:property>\n            <esf:property name=\"protocol-version\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>4</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.data.DataService\">\n        <esf:properties>\n            <esf:property name=\"in-flight-messages.congestion-timeout\" array=\"false\"\n                encrypted=\"false\" type=\"Integer\">\n                <esf:value>0</esf:value>\n            </esf:property>\n            <esf:property name=\"store.purge-age\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>60</esf:value>\n            </esf:property>\n            <esf:property name=\"in-flight-messages.republish-on-new-session\" array=\"false\"\n                encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"store.capacity\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>1000</esf:value>\n            </esf:property>\n            <esf:property name=\"disconnect.quiesce-timeout\" array=\"false\" encrypted=\"false\"\n                type=\"Integer\">\n                <esf:value>10</esf:value>\n            </esf:property>\n            <esf:property name=\"connect.auto-on-startup\" array=\"false\" encrypted=\"false\"\n                type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property name=\"connect.retry-interval\" array=\"false\" encrypted=\"false\"\n                type=\"Integer\">\n                <esf:value>60</esf:value>\n            </esf:property>\n            <esf:property name=\"service.pid\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>org.eclipse.kura.data.DataService</esf:value>\n            </esf:property>\n            <esf:property name=\"in-flight-messages.max-number\" array=\"false\" encrypted=\"false\"\n                type=\"Integer\">\n                <esf:value>9</esf:value>\n            </esf:property>\n            <esf:property name=\"store.housekeeper-interval\" array=\"false\" encrypted=\"false\"\n                type=\"Integer\">\n                <esf:value>900</esf:value>\n            </esf:property>\n            <esf:property name=\"DataTransportService.target\" array=\"false\" encrypted=\"false\"\n                type=\"String\">\n                <esf:value>\n                    (kura.service.pid=org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport)</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.cloud.CloudService\">\n        <esf:properties>\n            <esf:property name=\"encode.gzip\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"device.display-name\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>Kura Emulator</esf:value>\n            </esf:property>\n            <esf:property name=\"DataService.target\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>(kura.service.pid=org.eclipse.kura.data.DataService)</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"heaterPublisher\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"app.topic\" type=\"String\">\n                <esf:value>data</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"message.type\" type=\"String\">\n                <esf:value>data</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"qos\" type=\"Integer\">\n                <esf:value>0</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"appId\" type=\"String\">\n                <esf:value>HEATER</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"retain\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"priority\" type=\"Integer\">\n                <esf:value>7</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.cloud.publisher.CloudPublisher</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"cloud.endpoint.service.pid\"\n                type=\"String\">\n                <esf:value>org.eclipse.kura.cloud.CloudService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>heaterPublisher</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.cloud.publisher.CloudPublisher-1587372517474-4</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.demo.heater.Heater\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"CloudPublisher.target\" type=\"String\">\n                <esf:value>(kura.service.pid=heaterPublisher)</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.ssl.SslManagerService\">\n        <esf:properties>\n            <esf:property name=\"ssl.default.protocol\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>TLSv1.2</esf:value>\n            </esf:property>\n            <esf:property name=\"ssl.hostname.verification\" array=\"false\" encrypted=\"false\"\n                type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"KeystoreService.target\"\n                type=\"String\">\n                <esf:value>(kura.service.pid=SSLKeystore)</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.ssl.SslManagerService</esf:value>\n            </esf:property>\n            <esf:property name=\"service.ranking\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>100</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.http.server.manager.HttpService\">\n        <esf:properties>\n            <esf:property array=\"true\" encrypted=\"false\" name=\"http.ports\" type=\"Integer\">\n                <esf:value>8080</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"users.config\" type=\"String\">\n                <esf:value>\n                    [{\"name\":\"kura.user.admin\",\"credentials\":{\"kura.password\":\"jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg=\"}}]</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"groups.config\" type=\"String\">\n                <esf:value>[{\"name\":\"kura.permission.kura.admin\",\"basicMembers\":[\"kura.user.admin\"]},{\"name\":\"kura.permission.kura.cloud.connection.admin\"},{\"name\":\"kura.permission.kura.device\"},{\"name\":\"kura.permission.kura.maintenance\"},{\"name\":\"kura.permission.kura.packages.admin\"},{\"name\":\"kura.permission.kura.wires.admin\"},{\"name\":\"kura.permission.rest.assets\"},{\"name\":\"kura.permission.rest.cloudconnection\"},{\"name\":\"kura.permission.rest.command\"},{\"name\":\"kura.permission.rest.configuration\"},{\"name\":\"kura.permission.rest.deploy\"},{\"name\":\"kura.permission.rest.identity\"},{\"name\":\"kura.permission.rest.inventory\"},{\"name\":\"kura.permission.rest.keystores\"},{\"name\":\"kura.permission.rest.position\"},{\"name\":\"kura.permission.rest.security\"},{\"name\":\"kura.permission.rest.system\"},{\"name\":\"kura.permission.rest.tamper.detection\"},{\"name\":\"kura.permission.rest.wires.admin\"}]</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"SSLKeystore\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"keystore.path\" type=\"String\">\n                <esf:value>org.eclipse.kura.emulator/src/main/resources/cacerts.ks</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"true\" name=\"keystore.password\" type=\"Password\">\n                <esf:value>Y2hhbmdlaXQ=</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"randomize.password\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>SSLKeystore</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.db.H2DbService\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.user\" type=\"String\">\n                <esf:value>SA</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.connection.pool.max.size\"\n                type=\"Integer\">\n                <esf:value>10</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.connector.url\" type=\"String\">\n                <esf:value>jdbc:h2:mem:kuradb</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.db.H2DbService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.checkpoint.interval.seconds\"\n                type=\"Integer\">\n                <esf:value>900</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.db.H2DbService</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n</esf:configurations>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.clock/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator.clock\nBundle-SymbolicName: org.eclipse.kura.emulator.clock;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura.emulator.clock; version=\"1.0.0\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.clock;version=\"[1.0,1.1)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.3.0\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.clock/OSGI-INF/clock.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n \n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.clock.ClockService\">\n   <implementation class=\"org.eclipse.kura.emulator.clock.ClockServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.clock.ClockService\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.clock.ClockService\"/>\n   <reference name=\"EventAdmin\" \n              cardinality=\"1..1\" \n              policy=\"static\"\n              bind=\"setEventAdmin\"\n              unbind=\"unsetEventAdmin\"\n              interface=\"org.osgi.service.event.EventAdmin\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.clock/OSGI-INF/metatype/org.eclipse.kura.clock.ClockService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.clock.ClockService\" \n         name=\"ClockService\" \n         description=\"Emulated implementation of the ClockService\">\n        \n        <Icon resource=\"ClockService\" size=\"32\"/>\n        \n       \t<AD id=\"enabled\"\n            name=\"enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"The emulated ClockService is always disabled.\"/>\n\n    </OCD>\n    <Designate pid=\"org.eclipse.kura.clock.ClockService\">\n        <Object ocdref=\"org.eclipse.kura.clock.ClockService\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.clock/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.clock/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.clock/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#   Red Hat Inc\n#\n\noutput.. = target/classes/\nsource.. = src/main/java/,\\\n           src/main/resources/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nadditional.bundles = org.eclipse.osgi,\\\n                     slf4j.api,\\\n                     org.eclipse.kura.api\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.clock/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n      Red Hat Inc - Fix issue #603\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>emulator</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.emulator.clock</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.clock/src/main/java/org/eclipse/kura/emulator/clock/ClockServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator.clock;\n\nimport java.util.Date;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.clock.ClockService;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.EventAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ClockServiceImpl implements ConfigurableComponent, ClockService {\n\n    private static final Logger logger = LoggerFactory.getLogger(ClockServiceImpl.class);\n\n    @SuppressWarnings(\"unused\")\n    private ComponentContext ctx;\n    @SuppressWarnings(\"unused\")\n    private EventAdmin eventAdmin;\n    @SuppressWarnings(\"unused\")\n    private Map<String, Object> properties;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    public void unsetEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) {\n        logger.info(\"Activate. Current Time: {}\", new Date());\n\n        // save the bundle context\n        this.ctx = componentContext;\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.info(\"Deactivate...\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"Updated...\");\n        try {\n\n            // save the properties\n            this.properties = properties;\n        } catch (Throwable t) {\n            logger.error(\"Error updating ClockService Configuration\", t);\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Master Client Management APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public Date getLastSync() throws KuraException {\n        return new Date();\n    }\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.gpio/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator.gpio\nBundle-SymbolicName: org.eclipse.kura.emulator.gpio;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura.emulator.gpio; version=\"1.0.0\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.gpio; version=\"[1.2,1.3)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.gpio/OSGI-INF/gpio.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n \n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" immediate=\"true\" name=\"org.eclipse.kura.gpio.GPIOService\">\n   <implementation class=\"org.eclipse.kura.emulator.gpio.GpioServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.gpio.GPIOService\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.gpio.GPIOService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.gpio/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.gpio/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.gpio/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#   Red Hat Inc \n#\n\noutput.. = target/classes/\nsource.. = src/main/java/,\\\n           src/main/resources/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nadditional.bundles = org.eclipse.osgi,\\\n                     slf4j.api,\\\n                     org.eclipse.equinox.metatype\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.gpio/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n      Red Hat Inc - fix issue #603\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>emulator</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.emulator.gpio</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.gpio/src/main/java/org/eclipse/kura/emulator/gpio/EmulatedPin.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.emulator.gpio;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.gpio.KuraClosedDeviceException;\nimport org.eclipse.kura.gpio.KuraGPIODescription;\nimport org.eclipse.kura.gpio.KuraGPIODeviceException;\nimport org.eclipse.kura.gpio.KuraGPIODirection;\nimport org.eclipse.kura.gpio.KuraGPIOMode;\nimport org.eclipse.kura.gpio.KuraGPIOPin;\nimport org.eclipse.kura.gpio.KuraGPIOTrigger;\nimport org.eclipse.kura.gpio.KuraUnavailableDeviceException;\nimport org.eclipse.kura.gpio.PinStatusListener;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class EmulatedPin implements KuraGPIOPin {\n\n    private static final Logger logger = LoggerFactory.getLogger(EmulatedPin.class);\n    private static final String UNKNOWN = \"unknown\";\n    \n    private boolean internalValue = false;\n    private String pinName = null;\n    private int pinController = -1;\n    private int pinLine = -1;\n\n    private KuraGPIODirection direction = KuraGPIODirection.OUTPUT;\n    private KuraGPIOMode mode = KuraGPIOMode.OUTPUT_OPEN_DRAIN;\n    private KuraGPIOTrigger trigger = KuraGPIOTrigger.NONE;\n\n    public EmulatedPin(String pinName) {\n        super();\n        this.pinName = pinName;\n        this.pinController = 0;\n        this.pinLine = 0;\n    }\n\n    public EmulatedPin(int pinIndex) {\n        super();\n        this.pinName = UNKNOWN;\n        this.pinController = pinIndex / 1000;\n        this.pinLine = pinIndex % 1000;\n    }\n    \n    public EmulatedPin(String pinName, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger) {\n        super();\n        this.pinName = pinName;\n        this.pinController = 0;\n        this.pinLine = 0;\n        this.direction = direction;\n        this.mode = mode;\n        this.trigger = trigger;\n    }\n\n    public EmulatedPin(int pinIndex, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger) {\n        super();\n        this.pinName = UNKNOWN;\n        this.pinController = pinIndex / 1000;\n        this.pinLine = pinIndex % 1000;\n        this.direction = direction;\n        this.mode = mode;\n        this.trigger = trigger;\n    }\n\n    @Override\n    public void setValue(boolean active) throws KuraUnavailableDeviceException, KuraClosedDeviceException, IOException {\n        this.internalValue = active;\n\n        logger.debug(\"Emulated GPIO Pin {}:{}:{} changed to {}\",\n                this.pinName, this.pinController, this.pinLine, active ? \"on\" : \"off\");\n    }\n\n    @Override\n    public boolean getValue() throws KuraUnavailableDeviceException, KuraClosedDeviceException, IOException {\n        return this.internalValue;\n    }\n\n    @Override\n    public void addPinStatusListener(PinStatusListener listener) throws KuraClosedDeviceException, IOException {\n        // Do nothing\n    }\n\n    @Override\n    public void removePinStatusListener(PinStatusListener listener) throws KuraClosedDeviceException, IOException {\n        // Do nothing\n    }\n\n    @Override\n    public void open() throws KuraGPIODeviceException, KuraUnavailableDeviceException, IOException {\n        logger.info(\"Emulated GPIO Pin {}:{}:{} open.\", this.pinName, this.pinController, this.pinLine);\n    }\n\n    @Override\n    public void close() throws IOException {\n        logger.info(\"Emulated GPIO Pin {}:{}:{} closed.\", this.pinName, this.pinController, this.pinLine);\n    }\n\n    @Override\n    public String toString() {\n        return \"GPIO Pin Name \" + this.pinName + \" Controller #\" + this.pinController + \" Line #\" + this.pinLine;\n    }\n\n    @Override\n    public KuraGPIODirection getDirection() {\n        return this.direction;\n    }\n\n    @Override\n    public KuraGPIOMode getMode() {\n        return this.mode;\n    }\n\n    @Override\n    public KuraGPIOTrigger getTrigger() {\n        return this.trigger;\n    }\n\n    @Override\n    public String getName() {\n        return this.pinName;\n    }\n\n    @Override\n    public int getIndex() {\n        return this.pinController * 1000 + this.pinLine;\n    }\n\n    @Override\n    public boolean isOpen() {\n        return true;\n    }\n\n    @Override\n    public KuraGPIODescription getDescription() {\n        Map<String, String> properties = new HashMap<>();\n        properties.put(\"controller\", Integer.toString(this.pinController));\n        properties.put(\"line\", Integer.toString(this.pinLine));\n        properties.put(\"name\", this.pinName);\n        properties.put(KuraGPIODescription.DISPLAY_NAME_PROPERTY, this.pinName + \":\" + this.pinController + \":\" + this.pinLine);\n        return new KuraGPIODescription(properties);\n    }\n\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.gpio/src/main/java/org/eclipse/kura/emulator/gpio/GpioServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.emulator.gpio;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.gpio.GPIOService;\nimport org.eclipse.kura.gpio.KuraGPIODescription;\nimport org.eclipse.kura.gpio.KuraGPIODirection;\nimport org.eclipse.kura.gpio.KuraGPIOMode;\nimport org.eclipse.kura.gpio.KuraGPIOPin;\nimport org.eclipse.kura.gpio.KuraGPIOTrigger;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class GpioServiceImpl implements GPIOService {\n\n    private static final Logger logger = LoggerFactory.getLogger(GpioServiceImpl.class);\n\n    private final HashMap<Integer, String> pins = new HashMap<>();\n    private final List<KuraGPIODescription> pinDescriptions = new ArrayList<>();\n\n    protected void activate(ComponentContext componentContext) {\n        logger.debug(\"activating emulated GPIOService\");\n        for (int chip = 0; chip < 2; chip++) {\n            for (int line = 0; line < 5; line++) {\n                String name = \"GPIOchip\" + chip + \"line\" + line;\n                Map<String, String> properties = new HashMap<>();\n                properties.put(\"controller\", String.valueOf(chip));\n                properties.put(\"line\", String.valueOf(line));\n                properties.put(KuraGPIODescription.DISPLAY_NAME_PROPERTY, name + \":\" + chip + \":\" + line);\n                KuraGPIODescription desc = new KuraGPIODescription(properties);\n                this.pinDescriptions.add(desc);\n                \n                this.pins.put(chip * 1000 + line, name);\n            }\n        }\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.debug(\"deactivating emulated GPIOService\");\n    }\n\n    @Override\n    public KuraGPIOPin getPinByName(String pinName) {\n        if (pinName == null || pinName.isEmpty()) {\n            throw new IllegalArgumentException(\"pinName cannot be null\");\n        }\n        return new EmulatedPin(pinName);\n    }\n\n    @Override\n    public KuraGPIOPin getPinByName(String pinName, KuraGPIODirection direction, KuraGPIOMode mode,\n            KuraGPIOTrigger trigger) {\n        if (pinName == null || pinName.isEmpty()) {\n            throw new IllegalArgumentException(\"pinName cannot be null\");\n        }\n        return new EmulatedPin(pinName, direction, mode, trigger);\n    }\n\n    @Override\n    public KuraGPIOPin getPinByTerminal(int terminal) {\n        if (terminal < 0) {\n            throw new IllegalArgumentException(\"terminal cannot be negative\");\n        }\n        return new EmulatedPin(terminal);\n    }\n\n    @Override\n    public KuraGPIOPin getPinByTerminal(int terminal, KuraGPIODirection direction, KuraGPIOMode mode,\n            KuraGPIOTrigger trigger) {\n        if (terminal < 0) {\n            throw new IllegalArgumentException(\"terminal cannot be negative\");\n        }\n        return new EmulatedPin(terminal, direction, mode, trigger);\n    }\n\n    @Override\n    public Map<Integer, String> getAvailablePins() {\n        return Collections.unmodifiableMap(this.pins);\n    }\n\n    @Override\n    public List<KuraGPIOPin> getPins(Map<String, String> description) {\n        if (description == null || description.isEmpty() || !description.containsKey(\"name\")) {\n            throw new IllegalArgumentException(\"description cannot be null or empty and must contain 'name' key\");\n        }\n        return Arrays.asList(new EmulatedPin(description.get(\"name\")));\n    }\n\n    @Override\n    public List<KuraGPIOPin> getPins(Map<String, String> description, KuraGPIODirection direction, KuraGPIOMode mode,\n            KuraGPIOTrigger trigger) {\n        if (description == null || description.isEmpty() || !description.containsKey(\"name\")) {\n            throw new IllegalArgumentException(\"description cannot be null or empty and must contain 'name' key\");\n        }\n        return Arrays.asList(new EmulatedPin(description.get(\"name\"), direction, mode, trigger));\n    }\n\n    @Override\n    public List<KuraGPIODescription> getAvailablePinDescriptions() {\n        return Collections.unmodifiableList(this.pinDescriptions);\n    }\n\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator.net\nBundle-SymbolicName: org.eclipse.kura.emulator.net;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura.emulator.net; version=\"1.0.0\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.emulator;version=\"[1.0,2.0)\",\n org.eclipse.kura.net;version=\"[2.0,3.0)\",\n org.eclipse.kura.net.modem;version=\"[2.0,3.0)\",\n org.eclipse.kura.net.wifi;version=\"[2.0,3.0)\",\n org.eclipse.kura.usb;version=\"[1.3,2.0)\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/OSGI-INF/network.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" immediate=\"true\" name=\"org.eclipse.kura.net.NetworkService\">\n   <implementation class=\"org.eclipse.kura.emulator.net.EmulatedNetworkServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.net.NetworkService\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.net.NetworkService\"/>\n   \n   <reference name=\"Emulator\" \n              interface=\"org.eclipse.kura.emulator.Emulator\" \n              bind=\"setEmulator\" \n              unbind=\"unsetEmulator\"\n              cardinality=\"1..1\" \n              policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#   Red Hat Inc\n#\n\noutput.. = target/classes/\nsource.. = src/main/java/,\\\n           src/main/resources/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nadditional.bundles = org.eclipse.osgi,\\\n                     slf4j.api,\\\n                     org.eclipse.kura.api\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n      Red Hat Inc - Fix issue #603\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>emulator</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.emulator.net</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/src/main/java/org/eclipse/kura/emulator/net/AbstractNetInterface.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator.net;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.net.NetConfig;\nimport org.eclipse.kura.net.NetConfigIP4;\nimport org.eclipse.kura.net.NetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.eclipse.kura.net.NetInterfaceAddressConfig;\nimport org.eclipse.kura.net.NetInterfaceState;\nimport org.eclipse.kura.net.NetInterfaceStatus;\nimport org.eclipse.kura.usb.UsbDevice;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class AbstractNetInterface<T extends NetInterfaceAddress> implements NetInterface<T> {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractNetInterface.class);\n\n    private String name;\n    private byte[] hardwareAddress;\n    private boolean loopback;\n    private boolean pointToPoint;\n    private boolean virtual;\n    private boolean supportsMulticast;\n    private boolean up;\n    private int mtu;\n    private UsbDevice usbDevice;\n    private String driver;\n    private String driverVersion;\n    private String firmwareVersion;\n    private NetInterfaceState state;\n    private boolean autoConnect;\n    private List<T> interfaceAddresses;\n\n    protected AbstractNetInterface(String name) {\n        super();\n        this.name = name;\n        this.interfaceAddresses = new ArrayList<>();\n    }\n\n    protected AbstractNetInterface(NetInterface<? extends NetInterfaceAddress> other) {\n        super();\n        this.name = other.getName();\n        this.hardwareAddress = other.getHardwareAddress();\n        this.loopback = other.isLoopback();\n        this.pointToPoint = other.isPointToPoint();\n        this.virtual = other.isVirtual();\n        this.supportsMulticast = other.supportsMulticast();\n        this.up = other.isUp();\n        this.mtu = other.getMTU();\n        this.usbDevice = other.getUsbDevice();\n        this.driver = other.getDriver();\n        this.driverVersion = other.getDriverVersion();\n        this.firmwareVersion = other.getFirmwareVersion();\n        this.state = other.getState();\n        this.autoConnect = other.isAutoConnect();\n        this.interfaceAddresses = new ArrayList<>();\n        // note - copying of interfaceAddresses are handled in the subclasses\n    }\n\n    @Override\n    public String getName() {\n        return this.name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public byte[] getHardwareAddress() {\n        return this.hardwareAddress;\n    }\n\n    @Override\n    public boolean isLoopback() {\n        return this.loopback;\n    }\n\n    @Override\n    public boolean isPointToPoint() {\n        return this.pointToPoint;\n    }\n\n    @Override\n    public boolean isVirtual() {\n        return this.virtual;\n    }\n\n    @Override\n    public boolean supportsMulticast() {\n        return this.supportsMulticast;\n    }\n\n    @Override\n    public boolean isUp() {\n        return this.up;\n    }\n\n    @Override\n    public int getMTU() {\n        return this.mtu;\n    }\n\n    public void setMTU(int mtu) {\n        this.mtu = mtu;\n    }\n\n    @Override\n    public String getDriver() {\n        return this.driver;\n    }\n\n    public void setDriver(String driver) {\n        this.driver = driver;\n    }\n\n    @Override\n    public String getDriverVersion() {\n        return this.driverVersion;\n    }\n\n    public void setDriverVersion(String driverVersion) {\n        this.driverVersion = driverVersion;\n    }\n\n    @Override\n    public String getFirmwareVersion() {\n        return this.firmwareVersion;\n    }\n\n    public void setFirmwareVersion(String firmwareVersion) {\n        this.firmwareVersion = firmwareVersion;\n    }\n\n    @Override\n    public NetInterfaceState getState() {\n        return this.state;\n    }\n\n    public void setState(NetInterfaceState state) {\n        this.state = state;\n    }\n\n    @Override\n    public UsbDevice getUsbDevice() {\n        return this.usbDevice;\n    }\n\n    public void setHardwareAddress(byte[] hardwareAddress) {\n        this.hardwareAddress = hardwareAddress;\n    }\n\n    public void setLoopback(boolean loopback) {\n        this.loopback = loopback;\n    }\n\n    public void setPointToPoint(boolean pointToPoint) {\n        this.pointToPoint = pointToPoint;\n    }\n\n    public void setVirtual(boolean virtual) {\n        this.virtual = virtual;\n    }\n\n    public void setSupportsMulticast(boolean supportsMulticast) {\n        this.supportsMulticast = supportsMulticast;\n    }\n\n    public void setUp(boolean up) {\n        this.up = up;\n    }\n\n    public void setUsbDevice(UsbDevice usbDevice) {\n        this.usbDevice = usbDevice;\n    }\n\n    @Override\n    public boolean isAutoConnect() {\n        return this.autoConnect;\n    }\n\n    public void setAutoConnect(boolean autoConnect) {\n        this.autoConnect = autoConnect;\n    }\n\n    @Override\n    public List<T> getNetInterfaceAddresses() {\n        if (this.interfaceAddresses != null) {\n            return Collections.unmodifiableList(this.interfaceAddresses);\n        }\n        return Collections.emptyList();\n    }\n\n    public void setNetInterfaceAddresses(List<T> interfaceAddresses) {\n        this.interfaceAddresses = interfaceAddresses;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"name=\").append(this.name);\n        if (this.hardwareAddress != null && this.hardwareAddress.length == 6) {\n            sb.append(\" :: hardwareAddress=\").append(macToString(this.hardwareAddress));\n        }\n        sb.append(\" :: loopback=\").append(this.loopback).append(\" :: pointToPoint=\").append(this.pointToPoint)\n                .append(\" :: virtual=\").append(this.virtual).append(\" :: supportsMulticast=\")\n                .append(this.supportsMulticast).append(\" :: up=\").append(this.up).append(\" :: mtu=\").append(this.mtu);\n        if (this.usbDevice != null) {\n            sb.append(\" :: usbDevice=\").append(this.usbDevice);\n        }\n        sb.append(\" :: driver=\").append(this.driver).append(\" :: driverVersion=\").append(this.driverVersion)\n                .append(\" :: firmwareVersion=\").append(this.firmwareVersion).append(\" :: state=\").append(this.state)\n                .append(\" :: autoConnect=\").append(this.autoConnect);\n        if (this.interfaceAddresses != null && !this.interfaceAddresses.isEmpty()) {\n            sb.append(\" :: InterfaceAddress=\");\n            for (T interfaceAddress : this.interfaceAddresses) {\n                sb.append(interfaceAddress).append(\" \");\n            }\n        }\n\n        return sb.toString();\n    }\n\n    private static String macToString(byte[] mac) {\n        if (mac == null || mac.length != 6) {\n            throw new IllegalArgumentException(\"mac is null or invalid\");\n        }\n\n        String[] items = new String[6];\n        for (int i = 0; i < 6; i++) {\n            String octet = Integer.toHexString(mac[i] & 0xFF).toUpperCase();\n            if (octet.length() == 1) {\n                octet = \"0\" + octet;\n            }\n\n            items[i] = octet;\n        }\n\n        return String.join(\":\", items);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.autoConnect ? 1231 : 1237);\n        result = prime * result + (this.driver == null ? 0 : this.driver.hashCode());\n        result = prime * result + (this.driverVersion == null ? 0 : this.driverVersion.hashCode());\n        result = prime * result + (this.firmwareVersion == null ? 0 : this.firmwareVersion.hashCode());\n        result = prime * result + Arrays.hashCode(this.hardwareAddress);\n        result = prime * result + (this.interfaceAddresses == null ? 0 : this.interfaceAddresses.hashCode());\n        result = prime * result + (this.loopback ? 1231 : 1237);\n        result = prime * result + this.mtu;\n        result = prime * result + (this.name == null ? 0 : this.name.hashCode());\n        result = prime * result + (this.pointToPoint ? 1231 : 1237);\n        result = prime * result + (this.state == null ? 0 : this.state.hashCode());\n        result = prime * result + (this.supportsMulticast ? 1231 : 1237);\n        result = prime * result + (this.up ? 1231 : 1237);\n        result = prime * result + (this.usbDevice == null ? 0 : this.usbDevice.hashCode());\n        result = prime * result + (this.virtual ? 1231 : 1237);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof AbstractNetInterface)) {\n            return false;\n        }\n        AbstractNetInterface<?> other = (AbstractNetInterface<?>) obj;\n        if (this.autoConnect != other.autoConnect) {\n            return false;\n        }\n        if (this.driver == null) {\n            if (other.driver != null) {\n                return false;\n            }\n        } else if (!this.driver.equals(other.driver)) {\n            return false;\n        }\n        if (this.driverVersion == null) {\n            if (other.driverVersion != null) {\n                return false;\n            }\n        } else if (!this.driverVersion.equals(other.driverVersion)) {\n            return false;\n        }\n        if (this.firmwareVersion == null) {\n            if (other.firmwareVersion != null) {\n                return false;\n            }\n        } else if (!this.firmwareVersion.equals(other.firmwareVersion)) {\n            return false;\n        }\n        if (!Arrays.equals(this.hardwareAddress, other.hardwareAddress)) {\n            return false;\n        }\n        if (this.interfaceAddresses == null) {\n            if (other.interfaceAddresses != null) {\n                return false;\n            }\n        } else if (!this.interfaceAddresses.equals(other.interfaceAddresses)) {\n            return false;\n        }\n        if (this.loopback != other.loopback) {\n            return false;\n        }\n        if (this.mtu != other.mtu) {\n            return false;\n        }\n        if (this.name == null) {\n            if (other.name != null) {\n                return false;\n            }\n        } else if (!this.name.equals(other.name)) {\n            return false;\n        }\n        if (this.pointToPoint != other.pointToPoint) {\n            return false;\n        }\n        if (this.state != other.state) {\n            return false;\n        }\n        if (this.supportsMulticast != other.supportsMulticast) {\n            return false;\n        }\n        if (this.up != other.up) {\n            return false;\n        }\n        if (this.usbDevice == null) {\n            if (other.usbDevice != null) {\n                return false;\n            }\n        } else if (!this.usbDevice.equals(other.usbDevice)) {\n            return false;\n        }\n        if (this.virtual != other.virtual) {\n            return false;\n        }\n        return true;\n    }\n\n    public NetInterfaceAddressConfig getNetInterfaceAddressConfig() throws KuraException {\n        if (this.getNetInterfaceAddresses() == null || this.getNetInterfaceAddresses().isEmpty()) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, \"Empty NetInterfaceAddressConfig list\");\n        }\n        return (NetInterfaceAddressConfig) this.getNetInterfaceAddresses().get(0);\n    }\n\n    /**\n     * Returns a list of network configurations\n     *\n     * @return list of network configurations as {@link List<NetConfig>}\n     */\n    public List<NetConfig> getNetConfigs() {\n        List<NetConfig> ret = new ArrayList<>();\n        try {\n            List<NetConfig> netConfigs = getNetInterfaceAddressConfig().getConfigs();\n            if (netConfigs != null) {\n                ret = netConfigs;\n            }\n        } catch (KuraException e) {\n            logger.error(\"Failed to obtain NetConfigs\", e);\n        }\n        return ret;\n    }\n\n    /**\n     * Reports interface status\n     *\n     * @return interface status as {@link NetInterfaceStatus}\n     */\n    public NetInterfaceStatus getInterfaceStatus() {\n        List<NetConfig> netConfigs = getNetConfigs();\n        if (netConfigs == null) {\n            return NetInterfaceStatus.netIPv4StatusUnknown;\n        }\n        NetInterfaceStatus status = NetInterfaceStatus.netIPv4StatusUnknown;\n        for (NetConfig netConfig : netConfigs) {\n            if (netConfig instanceof NetConfigIP4) {\n                status = ((NetConfigIP4) netConfig).getStatus();\n                break;\n            }\n        }\n        return status;\n    }\n\n    /**\n     * Reports IPv4 configuration\n     *\n     * @return IPv4 configuration as {@link NetConfigIP4}\n     */\n    public NetConfigIP4 getIP4config() {\n        NetConfigIP4 netConfigIP4 = null;\n        List<NetConfig> netConfigs = getNetConfigs();\n        for (NetConfig netConfig : netConfigs) {\n            if (netConfig instanceof NetConfigIP4) {\n                netConfigIP4 = (NetConfigIP4) netConfig;\n                break;\n            }\n        }\n        return netConfigIP4;\n    }\n\n    /**\n     * Reports if interface is managed by the NetAdmin\n     *\n     * @return boolean\n     */\n    public boolean isInterfaceManaged() {\n        NetInterfaceStatus status = getInterfaceStatus();\n        return status != NetInterfaceStatus.netIPv4StatusUnmanaged && status != NetInterfaceStatus.netIPv4StatusUnknown;\n    }\n\n    /**\n     * Reports if interface is enabled in configuration\n     *\n     * @return boolean\n     */\n    public boolean isInterfaceEnabled() {\n        NetInterfaceStatus status = getInterfaceStatus();\n        return status == NetInterfaceStatus.netIPv4StatusL2Only || status == NetInterfaceStatus.netIPv4StatusEnabledLAN\n                || status == NetInterfaceStatus.netIPv4StatusEnabledWAN;\n    }\n\n    /**\n     * Reports if interface status is unknown\n     *\n     * @return boolean\n     */\n    public boolean isInterfaceUnknown() {\n        return getInterfaceStatus() == NetInterfaceStatus.netIPv4StatusUnknown;\n    }\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/src/main/java/org/eclipse/kura/emulator/net/EmulatedNetworkServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator.net;\n\nimport java.net.SocketException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.emulator.Emulator;\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.eclipse.kura.net.NetInterfaceState;\nimport org.eclipse.kura.net.NetworkService;\nimport org.eclipse.kura.net.NetworkState;\nimport org.eclipse.kura.net.modem.ModemDevice;\nimport org.eclipse.kura.net.wifi.WifiAccessPoint;\nimport org.eclipse.kura.usb.UsbNetDevice;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class EmulatedNetworkServiceImpl implements NetworkService {\n\n    private static final Logger logger = LoggerFactory.getLogger(EmulatedNetworkServiceImpl.class);\n\n    @SuppressWarnings(\"unused\")\n    private Emulator emulator;\n\n    @SuppressWarnings(\"unused\")\n    private ComponentContext ctx;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setEmulator(Emulator emulator) {\n        this.emulator = emulator;\n    }\n\n    public void unsetEmulator(Emulator emulator) {\n        this.emulator = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) {\n        //\n        // save the bundle context\n        this.ctx = componentContext;\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        this.ctx = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public NetworkState getState() {\n        java.net.InetAddress jnAddress = getFirstActiveInetAddress();\n        if (jnAddress == null) {\n            return NetworkState.DISCONNECTED;\n        } else if (jnAddress.isLoopbackAddress() || jnAddress.isLinkLocalAddress()) {\n            return NetworkState.CONNECTED_LOCAL;\n        } else if (jnAddress.isSiteLocalAddress()) {\n            return NetworkState.CONNECTED_SITE;\n        } else {\n            return NetworkState.CONNECTED_GLOBAL;\n        }\n    }\n\n    @Override\n    public NetInterfaceState getState(String interfaceName) {\n        // Returned unknown state for the emulated network service.\n        return NetInterfaceState.UNKNOWN;\n    }\n\n    @Override\n    public List<String> getAllNetworkInterfaceNames() throws KuraException {\n        List<String> interfaceNames = new ArrayList<>();\n\n        java.net.NetworkInterface jnInterface = null;\n        Enumeration<java.net.NetworkInterface> interfaces = null;\n        try {\n            interfaces = java.net.NetworkInterface.getNetworkInterfaces();\n            while (interfaces.hasMoreElements()) {\n                jnInterface = interfaces.nextElement();\n                interfaceNames.add(jnInterface.getName());\n            }\n        } catch (SocketException e) {\n            throw new KuraException(KuraErrorCode.IO_ERROR, e);\n        }\n\n        return interfaceNames;\n    }\n\n    @SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n    @Override\n    public List<NetInterface<? extends NetInterfaceAddress>> getNetworkInterfaces() throws KuraException {\n        IPAddress netAddress = null;\n        NetInterfaceAddressImpl addressImpl = null;\n        List<NetInterfaceAddress> addresses = null;\n        List<NetInterface<? extends NetInterfaceAddress>> interfaces = new ArrayList<>();\n\n        EthernetInterfaceImpl ethInterface = null;\n        java.net.NetworkInterface jnInterface = null;\n        List<java.net.InterfaceAddress> jnInterfaceAddresses = null;\n        Enumeration<java.net.NetworkInterface> jnInterfaces = null;\n        try {\n            jnInterfaces = java.net.NetworkInterface.getNetworkInterfaces();\n            while (jnInterfaces.hasMoreElements()) {\n\n                jnInterface = jnInterfaces.nextElement();\n                ethInterface = new EthernetInterfaceImpl(jnInterface.getName());\n                ethInterface.setVirtual(jnInterface.isVirtual());\n                ethInterface.setState(NetInterfaceState.ACTIVATED);\n                ethInterface.setAutoConnect(true);\n\n                byte[] hwAddr = null;\n                boolean isUp = false;\n                boolean isLoop = false;\n                int mtu = 0;\n                boolean isP2p = false;\n                boolean multi = false;\n                try {\n                    hwAddr = jnInterface.getHardwareAddress();\n                    isUp = jnInterface.isUp();\n                    isLoop = jnInterface.isLoopback();\n                    mtu = jnInterface.getMTU();\n                    isP2p = jnInterface.isPointToPoint();\n                    multi = jnInterface.supportsMulticast();\n                } catch (Exception e) {\n                    logger.warn(\"Exception while getting information for interface {}:{}\", jnInterface.getName(),\n                            e.getMessage());\n                }\n                ethInterface.setHardwareAddress(hwAddr);\n                ethInterface.setLinkUp(isUp);\n                ethInterface.setLoopback(isLoop);\n                ethInterface.setMTU(mtu);\n                ethInterface.setPointToPoint(isP2p);\n                ethInterface.setSupportsMulticast(multi);\n                ethInterface.setUp(isUp);\n\n                addresses = new ArrayList<>();\n                jnInterfaceAddresses = jnInterface.getInterfaceAddresses();\n                for (java.net.InterfaceAddress jnInterfaceAddress : jnInterfaceAddresses) {\n\n                    netAddress = IPAddress.getByAddress(jnInterfaceAddress.getAddress().getAddress());\n                    addressImpl = new NetInterfaceAddressImpl();\n                    addressImpl.setAddress(netAddress);\n                    if (jnInterfaceAddress.getBroadcast() != null) {\n                        addressImpl\n                                .setBroadcast(IPAddress.getByAddress(jnInterfaceAddress.getBroadcast().getAddress()));\n                    }\n                    addressImpl.setNetworkPrefixLength(jnInterfaceAddress.getNetworkPrefixLength());\n\n                    addresses.add(addressImpl);\n                }\n                ethInterface.setNetInterfaceAddresses(addresses);\n                interfaces.add(ethInterface);\n            }\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.IO_ERROR, e);\n        }\n        return interfaces;\n    }\n\n    @Override\n    public List<WifiAccessPoint> getAllWifiAccessPoints() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<WifiAccessPoint> getWifiAccessPoints(String wifiInterfaceName) {\n        return Collections.emptyList();\n    }\n\n    @SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n    @Override\n    public List<NetInterface<? extends NetInterfaceAddress>> getActiveNetworkInterfaces() throws KuraException {\n        IPAddress netAddress = null;\n        NetInterfaceAddressImpl addressImpl = null;\n        List<NetInterfaceAddress> addresses = null;\n        List<NetInterface<? extends NetInterfaceAddress>> interfaces = new ArrayList<>();\n\n        EthernetInterfaceImpl ethInterface = null;\n        java.net.NetworkInterface jnInterface = null;\n        List<java.net.InterfaceAddress> jnInterfaceAddresses = null;\n        Enumeration<java.net.NetworkInterface> jnInterfaces = null;\n        try {\n            jnInterfaces = java.net.NetworkInterface.getNetworkInterfaces();\n            while (jnInterfaces.hasMoreElements()) {\n\n                try {\n                    jnInterface = jnInterfaces.nextElement();\n                    if (jnInterface.isUp() && !jnInterface.isVirtual() && !jnInterface.isLoopback()\n                            && !jnInterface.isPointToPoint() && jnInterface.getHardwareAddress() != null\n                            && !jnInterface.getInterfaceAddresses().isEmpty()) {\n\n                        ethInterface = new EthernetInterfaceImpl(jnInterface.getName());\n                        ethInterface.setVirtual(jnInterface.isVirtual());\n                        ethInterface.setState(NetInterfaceState.ACTIVATED);\n                        ethInterface.setAutoConnect(true);\n\n                        byte[] hwAddr = null;\n                        boolean isUp = false;\n                        boolean isLoop = false;\n                        int mtu = 0;\n                        boolean isP2p = false;\n                        boolean multi = false;\n                        try {\n                            hwAddr = jnInterface.getHardwareAddress();\n                            isUp = jnInterface.isUp();\n                            isLoop = jnInterface.isLoopback();\n                            mtu = jnInterface.getMTU();\n                            isP2p = jnInterface.isPointToPoint();\n                            multi = jnInterface.supportsMulticast();\n                        } catch (Exception e) {\n                            logger.warn(\"Exception while getting information for interface \" + jnInterface.getName(),\n                                    e);\n                        }\n                        ethInterface.setHardwareAddress(hwAddr);\n                        ethInterface.setLinkUp(isUp);\n                        ethInterface.setLoopback(isLoop);\n                        ethInterface.setMTU(mtu);\n                        ethInterface.setPointToPoint(isP2p);\n                        ethInterface.setSupportsMulticast(multi);\n                        ethInterface.setUp(isUp);\n\n                        addresses = new ArrayList<>();\n                        jnInterfaceAddresses = jnInterface.getInterfaceAddresses();\n                        for (java.net.InterfaceAddress jnInterfaceAddress : jnInterfaceAddresses) {\n\n                            netAddress = IPAddress.getByAddress(jnInterfaceAddress.getAddress().getAddress());\n                            addressImpl = new NetInterfaceAddressImpl();\n                            addressImpl.setAddress(netAddress);\n                            if (jnInterfaceAddress.getBroadcast() != null) {\n                                addressImpl.setBroadcast(\n                                        IPAddress.getByAddress(jnInterfaceAddress.getBroadcast().getAddress()));\n                            }\n                            addressImpl.setNetworkPrefixLength(jnInterfaceAddress.getNetworkPrefixLength());\n\n                            addresses.add(addressImpl);\n                        }\n                        ethInterface.setNetInterfaceAddresses(addresses);\n                        interfaces.add(ethInterface);\n                    }\n                } catch (SocketException se) {\n                    logger.warn(\"Exception while getting information for interface \" + jnInterface.getName(), se);\n                }\n            }\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.IO_ERROR, e);\n        }\n        return interfaces;\n    }\n\n    // ---------------------------------------------------------\n    //\n    // Private methods\n    //\n    // ---------------------------------------------------------\n\n    private java.net.InetAddress getFirstActiveInetAddress() {\n        java.net.InetAddress jnAddress = null;\n        java.net.NetworkInterface jnInterface = null;\n        try {\n\n            Enumeration<java.net.NetworkInterface> interfaces = null;\n\n            // search for a non loopback interface\n            interfaces = java.net.NetworkInterface.getNetworkInterfaces();\n            while (interfaces.hasMoreElements()) {\n\n                jnInterface = interfaces.nextElement();\n                if (jnInterface.isUp() && !jnInterface.isLoopback() && !jnInterface.isVirtual()) {\n\n                    Enumeration<java.net.InetAddress> addresses = null;\n                    addresses = jnInterface.getInetAddresses();\n                    while (addresses.hasMoreElements()) {\n\n                        java.net.InetAddress address = addresses.nextElement();\n                        if (address instanceof java.net.Inet4Address && !address.isLoopbackAddress()) {\n                            jnAddress = address;\n                            break;\n                        }\n                    }\n                }\n                if (jnAddress != null) {\n                    break;\n                }\n\n                // get a loopback interface\n                interfaces = java.net.NetworkInterface.getNetworkInterfaces();\n                while (interfaces.hasMoreElements()) {\n\n                    jnInterface = interfaces.nextElement();\n                    if (jnInterface.isUp() && !jnInterface.isVirtual()) {\n\n                        Enumeration<java.net.InetAddress> addresses = null;\n                        addresses = jnInterface.getInetAddresses();\n                        while (addresses.hasMoreElements()) {\n\n                            java.net.InetAddress address = addresses.nextElement();\n                            if (address instanceof java.net.Inet4Address) {\n                                jnAddress = address;\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n        } catch (SocketException e) {\n            logger.error(\"Error getting IP address\", e);\n        }\n        return jnAddress;\n    }\n\n    @Override\n    public String getModemUsbPort(String interfaceName) {\n        return null;\n    }\n\n    @Override\n    public String getModemPppPort(ModemDevice modemDevice) throws KuraException {\n        return null;\n    }\n\n    @Override\n    public String getModemPppInterfaceName(String usbPath) {\n        return null;\n    }\n\n    @Override\n    public Optional<ModemDevice> getModemDevice(String usbPath) {\n        return Optional.empty();\n    }\n\n    @Override\n    public Optional<UsbNetDevice> getUsbNetDevice(String interfaceName) {\n        return Optional.empty();\n    }\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/src/main/java/org/eclipse/kura/emulator/net/EthernetInterfaceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator.net;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.eclipse.kura.net.EthernetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.eclipse.kura.net.NetInterfaceType;\n\npublic class EthernetInterfaceImpl<T extends NetInterfaceAddress> extends AbstractNetInterface<T>\n        implements EthernetInterface<T> {\n\n    private boolean linkUp;\n\n    public EthernetInterfaceImpl(String name) {\n        super(name);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public EthernetInterfaceImpl(EthernetInterface<? extends NetInterfaceAddress> other) {\n        super(other);\n        this.linkUp = other.isLinkUp();\n\n        // Copy the NetInterfaceAddresses\n        List<? extends NetInterfaceAddress> otherNetInterfaceAddresses = other.getNetInterfaceAddresses();\n        ArrayList<T> interfaceAddresses = new ArrayList<>();\n\n        if (otherNetInterfaceAddresses != null) {\n            for (NetInterfaceAddress netInterfaceAddress : otherNetInterfaceAddresses) {\n                NetInterfaceAddressImpl copiedInterfaceAddressImpl = new NetInterfaceAddressImpl(netInterfaceAddress);\n                interfaceAddresses.add((T) copiedInterfaceAddressImpl);\n            }\n        }\n        setNetInterfaceAddresses(interfaceAddresses);\n    }\n\n    @Override\n    public NetInterfaceType getType() {\n        return NetInterfaceType.ETHERNET;\n    }\n\n    @Override\n    public boolean isLinkUp() {\n        return this.linkUp;\n    }\n\n    public void setLinkUp(boolean linkUp) {\n        this.linkUp = linkUp;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(super.toString()).append(\" :: linkUp=\").append(this.linkUp);\n        return sb.toString();\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + (this.linkUp ? 1231 : 1237);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj)) {\n            return false;\n        }\n        if (!(obj instanceof EthernetInterfaceImpl)) {\n            return false;\n        }\n        EthernetInterfaceImpl other = (EthernetInterfaceImpl) obj;\n        if (this.linkUp != other.linkUp) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.net/src/main/java/org/eclipse/kura/emulator/net/NetInterfaceAddressImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator.net;\n\nimport java.util.List;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetInterfaceAddress;\n\npublic class NetInterfaceAddressImpl implements NetInterfaceAddress {\n\n    private IPAddress address;\n    private short networkPrefixLength;\n    private IPAddress netmask;\n    private IPAddress gateway;\n    private IPAddress broadcast;\n    private List<? extends IPAddress> dnsAddresses;\n\n    public NetInterfaceAddressImpl() {\n    }\n\n    public NetInterfaceAddressImpl(NetInterfaceAddress other) {\n        super();\n        this.address = other.getAddress();\n        this.networkPrefixLength = other.getNetworkPrefixLength();\n        this.netmask = other.getNetmask();\n        this.gateway = other.getGateway();\n        this.broadcast = other.getBroadcast();\n        this.dnsAddresses = other.getDnsServers();\n    }\n\n    @Override\n    public IPAddress getAddress() {\n        return this.address;\n    }\n\n    public void setAddress(IPAddress address) {\n        this.address = address;\n    }\n\n    @Override\n    public short getNetworkPrefixLength() {\n        return this.networkPrefixLength;\n    }\n\n    public void setNetworkPrefixLength(short networkPrefixLength) {\n        this.networkPrefixLength = networkPrefixLength;\n    }\n\n    @Override\n    public IPAddress getNetmask() {\n        return this.netmask;\n    }\n\n    public void setNetmask(IPAddress netmask) {\n        this.netmask = netmask;\n    }\n\n    @Override\n    public IPAddress getGateway() {\n        return this.gateway;\n    }\n\n    public void setGateway(IPAddress gateway) {\n        this.gateway = gateway;\n    }\n\n    @Override\n    public IPAddress getBroadcast() {\n        return this.broadcast;\n    }\n\n    public void setBroadcast(IPAddress broadcast) {\n        this.broadcast = broadcast;\n    }\n\n    @Override\n    public List<? extends IPAddress> getDnsServers() {\n        return this.dnsAddresses;\n    }\n\n    public void setDnsServers(List<? extends IPAddress> dnsAddresses) {\n        this.dnsAddresses = dnsAddresses;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof NetInterfaceAddress)) {\n            return false;\n        }\n\n        NetInterfaceAddress other = (NetInterfaceAddress) obj;\n\n        return this.networkPrefixLength == other.getNetworkPrefixLength() && compare(this.address, other.getAddress())\n                && compare(this.netmask, other.getNetmask()) && compare(this.gateway, other.getGateway())\n                && compare(this.broadcast, other.getBroadcast()) && compare(this.dnsAddresses, other.getDnsServers());\n    }\n\n    protected boolean compare(Object obj1, Object obj2) {\n        return obj1 == null ? obj2 == null : obj1.equals(obj2);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.address == null ? 0 : this.address.hashCode());\n        result = prime * result + (this.broadcast == null ? 0 : this.broadcast.hashCode());\n        result = prime * result + (this.dnsAddresses == null ? 0 : this.dnsAddresses.hashCode());\n        result = prime * result + (this.gateway == null ? 0 : this.gateway.hashCode());\n        result = prime * result + (this.netmask == null ? 0 : this.netmask.hashCode());\n        result = prime * result + this.networkPrefixLength;\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator.position\nBundle-SymbolicName: org.eclipse.kura.emulator.position;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura.emulator.position; version=\"1.0.0\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: javax.xml.parsers,\n javax.xml.stream,\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.position;version=\"[1.4,1.5)\",\n org.osgi.framework;version=\"1.7.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.3.0\",\n org.osgi.util.measurement;version=\"1.0.1\",\n org.osgi.util.position;version=\"1.0.1\",\n org.slf4j;version=\"1.6.4\",\n org.xml.sax,\n org.xml.sax.helpers\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/OSGI-INF/metatype/org.eclipse.kura.position.PositionService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.position.PositionService\"\n         name=\"PositionService\" \n         description=\"Emulated implementation of the PositionService.\">\n        \n        <Icon resource=\"PositionService\" size=\"32\"/>\n        \n        <AD id=\"enabled\"\n            name=\"enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"The emulated PositionService is always enabled and using sample GPS positions.\"/>\n        \n        <AD id=\"useGpsd\"\n            name=\"useGpsd\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"If true uses the gpsd service daemon. This implies that this daemon must be installed and active first.\"/>\n            \n         <AD id=\"source\"\n            name=\"source\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"boston\"\n            description=\"Select the data source file to use.\">\n            <Option label=\"Boston\" value=\"boston\" />\n            <Option label=\"Denver\" value=\"denver\" />\n            <Option label=\"Paris\" value=\"paris\" />\n            <Option label=\"Test\" value=\"test\" />\n         </AD>\n                \n    </OCD>\n    <Designate pid=\"org.eclipse.kura.position.PositionService\">\n        <Object ocdref=\"org.eclipse.kura.position.PositionService\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/OSGI-INF/position.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.position.PositionService\">\n   <implementation class=\"org.eclipse.kura.emulator.position.PositionServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.position.PositionService\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <!--\n      <provide interface=\"org.osgi.service.event.EventHandler\"/>\n      -->\n   </service>\n   <reference name=\"EventAdmin\" \n              cardinality=\"1..1\" \n              policy=\"static\"\n              bind=\"setEventAdmin\"\n              unbind=\"unsetEventAdmin\"\n              interface=\"org.osgi.service.event.EventAdmin\"/> \n</scr:component>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\noutput.. = target/classes/\nsource.. = src/main/java/,\\\n           src/main/resources/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nadditional.bundles = org.eclipse.osgi,\\\n                     slf4j.api,\\\n                     org.eclipse.kura.api\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>emulator</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.emulator.position</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../../test/org.eclipse.kura.emulator.position.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/src/main/java/org/eclipse/kura/emulator/position/GpsPoint.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator.position;\n\npublic class GpsPoint {\n\n    private final double latitude;\n    private final double longitude;\n    private final double altitude;\n    private final String time;\n\n    public GpsPoint(double latitude, double longitude, double altitude, String time) {\n        this.latitude = latitude;\n        this.longitude = longitude;\n        this.altitude = altitude;\n        this.time = time;\n    }\n\n    public double getLatitude() {\n        return this.latitude;\n    }\n\n    public double getLongitude() {\n        return this.longitude;\n    }\n\n    public double getAltitude() {\n        return this.altitude;\n    }\n\n    public String getTime() {\n        return this.time;\n    }\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/src/main/java/org/eclipse/kura/emulator/position/GpsXmlHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.emulator.position;\n\nimport java.util.ArrayList;\n\nimport org.xml.sax.Attributes;\nimport org.xml.sax.helpers.DefaultHandler;\n\npublic class GpsXmlHandler extends DefaultHandler {\n\n    private static final String LABEL = \"org.eclipse.kura.app.demo.kura.training.console.GpsXmlHandler: \";\n\n    // Valid Elements in the xml file\n    private static final String TAG_TRACK_POINT = \"trkpt\";\n    private static final String TAG_ELEVATION = \"ele\";\n    private static final String TAG_TIME = \"time\";\n\n    private final ArrayList<GpsPoint> gpsPoints;\n    private String latitude;\n    private String longitude;\n    private String elevation;\n    private String time;\n\n    private boolean foundTrackPoint = false;\n    private boolean foundElevation = false;\n    private boolean foundTime = false;\n\n    public GpsXmlHandler() {\n        this.gpsPoints = new ArrayList<GpsPoint>();\n        this.latitude = null;\n        this.longitude = null;\n        this.elevation = null;\n        this.time = null;\n    }\n\n    @Override\n    public void startElement(String uri, String localName, String elementName, Attributes attributes) {\n\n        if (TAG_TRACK_POINT.equals(elementName)) {\n            this.foundTrackPoint = true;\n\n            if (attributes.getLength() == 2) {\n                for (int i = 0; i < attributes.getLength(); i++) {\n                    if (attributes.getQName(i).compareTo(\"lat\") == 0) {\n                        this.latitude = attributes.getValue(i);\n                    } else if (attributes.getQName(i).compareTo(\"lon\") == 0) {\n                        this.longitude = attributes.getValue(i);\n                    } else {\n                        System.out.println(LABEL + \"invalid attribute in trkpt element: \" + attributes.getQName(i));\n                    }\n                }\n            } else {\n                System.out.println(LABEL + \"there must be two attributes (lat and lon) in the trkpt element\");\n            }\n\n            this.elevation = null;\n            this.time = null;\n        } else if (TAG_ELEVATION.equals(elementName)) {\n            this.foundElevation = true;\n        } else if (TAG_TIME.equals(elementName)) {\n            this.foundTime = true;\n        }\n    }\n\n    @Override\n    public void endElement(String uri, String localName, String elementName) {\n\n        if (TAG_TRACK_POINT.equals(elementName)) {\n            this.foundTrackPoint = false;\n\n            if (this.latitude != null && this.longitude != null && this.elevation != null && this.time != null) {\n                this.gpsPoints.add(new GpsPoint(Double.parseDouble(this.latitude), Double.parseDouble(this.longitude),\n                        Double.parseDouble(this.elevation), this.time));\n            } else {\n                System.out.println(LABEL + \"the XML file is malformed\");\n            }\n        } else if (TAG_ELEVATION.equals(elementName)) {\n            this.foundElevation = false;\n        } else if (TAG_TIME.equals(elementName)) {\n            this.foundTime = false;\n        }\n    }\n\n    @Override\n    public void characters(char[] buf, int offset, int length) {\n        String tag = new String(buf).substring(offset, offset + length).trim();\n\n        if (!this.foundTrackPoint && !this.foundElevation && !this.foundTime) {\n            return;\n        }\n\n        if (this.foundElevation) {\n            if (this.elevation == null) {\n                this.elevation = new String(buf, offset, length);\n                return;\n            } else {\n                this.elevation = this.elevation + new String(buf, offset, length);\n                return;\n            }\n        }\n\n        if (this.foundTime) {\n            if (this.time == null) {\n                this.time = new String(buf, offset, length);\n                return;\n            } else {\n                this.time = this.time + new String(buf, offset, length);\n                return;\n            }\n        }\n\n        System.out.println(LABEL + \"found some odd data in services.xml\");\n        logDump(tag.getBytes());\n    }\n\n    public GpsPoint[] getGpsPoints() {\n        GpsPoint[] data = new GpsPoint[this.gpsPoints.size()];\n\n        for (int i = 0; i < this.gpsPoints.size(); i++) {\n            data[i] = this.gpsPoints.get(i);\n        }\n\n        return data;\n    }\n\n    private void logDump(byte[] message) {\n        for (int i = 0; i < message.length; i++) {\n            if (i % 16 == 0) {\n                if (i > 0) {\n                    System.out.println();\n                }\n                System.out.print('\\t');\n            }\n            if (message[i] < 0x10) {\n                System.out.print(\"0x0\" + Integer.toHexString(message[i] & 0x0ff) + \" \");\n            } else {\n                System.out.print(\"0x\" + Integer.toHexString(message[i] & 0x0ff) + \" \");\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/src/main/java/org/eclipse/kura/emulator/position/PositionServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.emulator.position;\n\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.time.LocalDateTime;\nimport java.time.ZoneId;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.position.GNSSType;\nimport org.eclipse.kura.position.NmeaPosition;\nimport org.eclipse.kura.position.PositionListener;\nimport org.eclipse.kura.position.PositionLockedEvent;\nimport org.eclipse.kura.position.PositionService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.EventAdmin;\nimport org.osgi.util.measurement.Measurement;\nimport org.osgi.util.measurement.Unit;\nimport org.osgi.util.position.Position;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class PositionServiceImpl implements PositionService, ConfigurableComponent {\n\n    private static final String USE_GPSD_PROPERTY_NAME = \"useGpsd\";\n\n    private static final Logger logger = LoggerFactory.getLogger(PositionServiceImpl.class);\n\n    private static final String SOURCE_KEY = \"source\";\n\n    private static final String BOSTON = \"boston\";\n\n    private ComponentContext ctx;\n    private EventAdmin eventAdmin;\n\n    private ScheduledExecutorService worker;\n    private ScheduledFuture<?> handle;\n\n    private GpsPoint[] gpsPoints;\n    private Position currentPosition;\n    private NmeaPosition currentNmeaPosition;\n    private Date currentTime;\n    private int index = 0;\n    private boolean useGpsd;\n    private String source;\n\n    public void setEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    public void unsetEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        //\n        // save the bundle context\n        this.ctx = componentContext;\n        this.useGpsd = false;\n        doUpdate(properties);\n\n        start();\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"Updating position service\");\n        stop();\n        doUpdate(properties);\n        start();\n        logger.info(\"Updating position service. Done.\");\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.info(\"Stopping position service\");\n        stop();\n    }\n\n    private void doUpdate(Map<String, Object> properties) {\n        if (properties == null) {\n            return;\n        }\n        if (properties.get(USE_GPSD_PROPERTY_NAME) != null) {\n            this.useGpsd = (Boolean) properties.get(USE_GPSD_PROPERTY_NAME);\n        }\n        if (this.useGpsd) {\n            logger.info(\"USE GPSD\");\n        }\n        this.source = (String) properties.getOrDefault(SOURCE_KEY, BOSTON);\n    }\n\n    @Override\n    public Position getPosition() {\n        return this.currentPosition;\n    }\n\n    @Override\n    public NmeaPosition getNmeaPosition() {\n        return this.currentNmeaPosition;\n    }\n\n    @Override\n    public String getNmeaTime() {\n        return this.currentTime.toString();\n    }\n\n    @Override\n    public String getNmeaDate() {\n        return this.currentTime.toString();\n    }\n\n    @Override\n    public boolean isLocked() {\n        // Always return true\n        return true;\n    }\n\n    @Override\n    public String getLastSentence() {\n        // Not supported in emulator mode since this is not NMEA\n        return null;\n    }\n\n    public void start() {\n\n        this.index = 0;\n\n        String fileName = null;\n        if (BOSTON.equals(this.source)) {\n            fileName = \"boston.gpx\";\n        } else if (\"denver\".equals(this.source)) {\n            fileName = \"denver.gpx\";\n        } else if (\"paris\".equals(this.source)) {\n            fileName = \"paris.gpx\";\n        } else if (\"test\".equals(this.source)) {\n            fileName = \"test.gpx\";\n        }\n\n        GpsXmlHandler handler = new GpsXmlHandler();\n        SAXParserFactory factory = SAXParserFactory.newInstance();\n        try {\n            factory.setFeature(\"http://xml.org/sax/features/external-general-entities\", false);\n            factory.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", true);\n            factory.setValidating(false);\n\n            // Create the builder and parse the file\n            SAXParser parser = factory.newSAXParser();\n            logger.debug(\"Parsing: {}\", fileName);\n\n            BundleContext bundleContext = this.ctx.getBundleContext();\n            URL url = bundleContext.getBundle().getResource(fileName);\n            InputStream is = url.openStream();\n\n            parser.parse(is, handler);\n            this.gpsPoints = handler.getGpsPoints();\n        } catch (Exception e) {\n            logger.warn(\"Exception while parsing the position file\", e);\n        }\n\n        // schedule a new worker based on the properties of the service\n        this.worker = Executors.newSingleThreadScheduledExecutor();\n        this.handle = this.worker.scheduleAtFixedRate(this::updateGps, 0, 5, TimeUnit.SECONDS);\n\n        logger.debug(\"posting event\");\n        this.eventAdmin.postEvent(new PositionLockedEvent(new HashMap<String, Object>()));\n    }\n\n    public void stop() {\n        if (this.handle != null) {\n            this.handle.cancel(true);\n            this.handle = null;\n        }\n\n        this.worker = null;\n    }\n\n    private void updateGps() {\n        logger.debug(\"GPS Emulator index: {}\", this.index);\n        if (this.index + 1 == this.gpsPoints.length) {\n            logger.debug(\"GPS Emulator - wrapping index\");\n            this.index = 0;\n        }\n\n        Measurement latitude = new Measurement(java.lang.Math.toRadians(this.gpsPoints[this.index].getLatitude()),\n                Unit.rad);\n        Measurement longitude = new Measurement(java.lang.Math.toRadians(this.gpsPoints[this.index].getLongitude()),\n                Unit.rad);\n        Measurement altitude = new Measurement(this.gpsPoints[this.index].getAltitude(), Unit.m);\n\n        logger.debug(\"Updating latitude: {}\", latitude);\n        logger.debug(\"Updating longitude: {}\", longitude);\n        logger.debug(\"Updating altitude: {}\", altitude);\n\n        // Measurement lat, Measurement lon, Measurement alt, Measurement speed, Measurement track\n        this.currentTime = new Date();\n        this.currentPosition = new Position(latitude, longitude, altitude, null, null);\n        this.currentNmeaPosition = new NmeaPosition(this.gpsPoints[this.index].getLatitude(),\n                this.gpsPoints[this.index].getLongitude(), this.gpsPoints[this.index].getAltitude(), 0, 0);\n\n        this.index++;\n    }\n\n    @Override\n    public void registerListener(String listenerId, PositionListener positionListener) {\n        // Not supported\n    }\n\n    @Override\n    public void unregisterListener(String listenerId) {\n        // Not supported\n    }\n\n    @Override\n    public LocalDateTime getDateTime() {\n        return LocalDateTime.ofInstant(this.currentTime.toInstant(), ZoneId.systemDefault());\n    }\n\n    @Override\n    public Set<GNSSType> getGnssTypes() {\n        return new HashSet<>(Arrays.asList(GNSSType.GPS));\n    }\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/boston.gpx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<gpx version=\"1.1\" creator=\"GPS Runner\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/1\" schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\"><trk><number>1</number><trkseg><trkpt lat=\"42.229664\" lon=\"-71.518378\"><ele>149.6</ele><time>2005-04-18T18:01:13Z</time></trkpt><trkpt lat=\"42.229707\" lon=\"-71.518314\"><ele>149.1</ele><time>2005-04-18T18:01:15Z</time></trkpt><trkpt lat=\"42.230029\" lon=\"-71.517777\"><ele>148.7</ele><time>2005-04-18T18:01:31Z</time></trkpt><trkpt lat=\"42.230415\" lon=\"-71.517434\"><ele>146.7</ele><time>2005-04-18T18:01:44Z</time></trkpt><trkpt lat=\"42.230973\" lon=\"-71.517026\"><ele>143.9</ele><time>2005-04-18T18:02:02Z</time></trkpt><trkpt lat=\"42.23151\" lon=\"-71.516705\"><ele>141.5</ele><time>2005-04-18T18:02:19Z</time></trkpt><trkpt lat=\"42.231832\" lon=\"-71.51634\"><ele>139</ele><time>2005-04-18T18:02:32Z</time></trkpt><trkpt lat=\"42.232068\" lon=\"-71.515932\"><ele>134.7</ele><time>2005-04-18T18:02:44Z</time></trkpt><trkpt lat=\"42.232325\" lon=\"-71.515331\"><ele>130.9</ele><time>2005-04-18T18:02:58Z</time></trkpt><trkpt lat=\"42.23254\" lon=\"-71.514773\"><ele>131.4</ele><time>2005-04-18T18:03:10Z</time></trkpt><trkpt lat=\"42.232797\" lon=\"-71.514173\"><ele>126.1</ele><time>2005-04-18T18:03:24Z</time></trkpt><trkpt lat=\"42.23299\" lon=\"-71.51355\"><ele>123.7</ele><time>2005-04-18T18:03:37Z</time></trkpt><trkpt lat=\"42.233205\" lon=\"-71.512885\"><ele>120.3</ele><time>2005-04-18T18:03:52Z</time></trkpt><trkpt lat=\"42.233441\" lon=\"-71.512156\"><ele>119.8</ele><time>2005-04-18T18:04:09Z</time></trkpt><trkpt lat=\"42.233655\" lon=\"-71.511533\"><ele>118.4</ele><time>2005-04-18T18:04:23Z</time></trkpt><trkpt lat=\"42.233891\" lon=\"-71.510975\"><ele>114.5</ele><time>2005-04-18T18:04:36Z</time></trkpt><trkpt lat=\"42.234213\" lon=\"-71.510267\"><ele>111.2</ele><time>2005-04-18T18:04:53Z</time></trkpt><trkpt lat=\"42.234535\" lon=\"-71.509409\"><ele>110.7</ele><time>2005-04-18T18:05:13Z</time></trkpt><trkpt lat=\"42.234814\" lon=\"-71.508915\"><ele>108.3</ele><time>2005-04-18T18:05:26Z</time></trkpt><trkpt lat=\"42.235157\" lon=\"-71.508336\"><ele>107.3</ele><time>2005-04-18T18:05:41Z</time></trkpt><trkpt lat=\"42.235501\" lon=\"-71.507843\"><ele>107.8</ele><time>2005-04-18T18:05:55Z</time></trkpt><trkpt lat=\"42.235887\" lon=\"-71.507199\"><ele>108.3</ele><time>2005-04-18T18:06:13Z</time></trkpt><trkpt lat=\"42.236145\" lon=\"-71.506748\"><ele>110.2</ele><time>2005-04-18T18:06:26Z</time></trkpt><trkpt lat=\"42.236338\" lon=\"-71.50619\"><ele>114.1</ele><time>2005-04-18T18:06:40Z</time></trkpt><trkpt lat=\"42.236423\" lon=\"-71.505632\"><ele>116.5</ele><time>2005-04-18T18:06:52Z</time></trkpt><trkpt lat=\"42.236466\" lon=\"-71.50516\"><ele>116</ele><time>2005-04-18T18:07:01Z</time></trkpt><trkpt lat=\"42.236509\" lon=\"-71.504474\"><ele>116</ele><time>2005-04-18T18:07:15Z</time></trkpt><trkpt lat=\"42.236552\" lon=\"-71.503894\"><ele>116.9</ele><time>2005-04-18T18:07:28Z</time></trkpt><trkpt lat=\"42.236595\" lon=\"-71.503551\"><ele>116.5</ele><time>2005-04-18T18:07:36Z</time></trkpt><trkpt lat=\"42.236595\" lon=\"-71.502972\"><ele>118.4</ele><time>2005-04-18T18:07:48Z</time></trkpt><trkpt lat=\"42.236531\" lon=\"-71.502349\"><ele>117.4</ele><time>2005-04-18T18:08:01Z</time></trkpt><trkpt lat=\"42.236509\" lon=\"-71.502113\"><ele>116.9</ele><time>2005-04-18T18:08:06Z</time></trkpt><trkpt lat=\"42.236466\" lon=\"-71.501813\"><ele>115.5</ele><time>2005-04-18T18:08:12Z</time></trkpt><trkpt lat=\"42.236381\" lon=\"-71.501126\"><ele>114.1</ele><time>2005-04-18T18:08:26Z</time></trkpt><trkpt lat=\"42.236338\" lon=\"-71.500397\"><ele>111.2</ele><time>2005-04-18T18:08:41Z</time></trkpt><trkpt lat=\"42.236338\" lon=\"-71.499667\"><ele>109.7</ele><time>2005-04-18T18:08:56Z</time></trkpt><trkpt lat=\"42.236445\" lon=\"-71.499002\"><ele>107.8</ele><time>2005-04-18T18:09:10Z</time></trkpt><trkpt lat=\"42.236574\" lon=\"-71.498401\"><ele>105.4</ele><time>2005-04-18T18:09:23Z</time></trkpt><trkpt lat=\"42.236702\" lon=\"-71.497736\"><ele>108.3</ele><time>2005-04-18T18:09:37Z</time></trkpt><trkpt lat=\"42.236874\" lon=\"-71.496985\"><ele>104.9</ele><time>2005-04-18T18:09:53Z</time></trkpt><trkpt lat=\"42.237067\" lon=\"-71.496234\"><ele>105.9</ele><time>2005-04-18T18:10:09Z</time></trkpt><trkpt lat=\"42.237196\" lon=\"-71.495633\"><ele>104.9</ele><time>2005-04-18T18:10:22Z</time></trkpt><trkpt lat=\"42.237368\" lon=\"-71.495011\"><ele>103.5</ele><time>2005-04-18T18:10:36Z</time></trkpt><trkpt lat=\"42.237561\" lon=\"-71.494453\"><ele>105.4</ele><time>2005-04-18T18:10:49Z</time></trkpt><trkpt lat=\"42.237689\" lon=\"-71.493895\"><ele>104.4</ele><time>2005-04-18T18:11:01Z</time></trkpt><trkpt lat=\"42.237797\" lon=\"-71.493359\"><ele>102</ele><time>2005-04-18T18:11:12Z</time></trkpt><trkpt lat=\"42.238054\" lon=\"-71.492651\"><ele>103</ele><time>2005-04-18T18:11:28Z</time></trkpt><trkpt lat=\"42.238312\" lon=\"-71.492093\"><ele>103</ele><time>2005-04-18T18:11:42Z</time></trkpt><trkpt lat=\"42.238612\" lon=\"-71.491621\"><ele>104</ele><time>2005-04-18T18:11:55Z</time></trkpt><trkpt lat=\"42.238934\" lon=\"-71.491148\"><ele>104.4</ele><time>2005-04-18T18:12:09Z</time></trkpt><trkpt lat=\"42.239213\" lon=\"-71.490676\"><ele>107.8</ele><time>2005-04-18T18:12:22Z</time></trkpt><trkpt lat=\"42.239385\" lon=\"-71.49029\"><ele>107.8</ele><time>2005-04-18T18:12:31Z</time></trkpt><trkpt lat=\"42.239642\" lon=\"-71.489775\"><ele>107.3</ele><time>2005-04-18T18:12:43Z</time></trkpt><trkpt lat=\"42.239943\" lon=\"-71.489217\"><ele>104.9</ele><time>2005-04-18T18:12:56Z</time></trkpt><trkpt lat=\"42.240157\" lon=\"-71.488767\"><ele>103</ele><time>2005-04-18T18:13:06Z</time></trkpt><trkpt lat=\"42.240458\" lon=\"-71.488166\"><ele>100.6</ele><time>2005-04-18T18:13:20Z</time></trkpt><trkpt lat=\"42.240758\" lon=\"-71.487522\"><ele>103</ele><time>2005-04-18T18:13:36Z</time></trkpt><trkpt lat=\"42.24108\" lon=\"-71.486814\"><ele>102</ele><time>2005-04-18T18:13:54Z</time></trkpt><trkpt lat=\"42.24123\" lon=\"-71.486299\"><ele>100.6</ele><time>2005-04-18T18:14:05Z</time></trkpt><trkpt lat=\"42.241509\" lon=\"-71.48572\"><ele>100.1</ele><time>2005-04-18T18:14:19Z</time></trkpt><trkpt lat=\"42.241831\" lon=\"-71.485033\"><ele>98.7</ele><time>2005-04-18T18:14:35Z</time></trkpt><trkpt lat=\"42.242002\" lon=\"-71.484647\"><ele>99.2</ele><time>2005-04-18T18:14:44Z</time></trkpt><trkpt lat=\"42.242088\" lon=\"-71.484411\"><ele>99.6</ele><time>2005-04-18T18:14:49Z</time></trkpt><trkpt lat=\"42.242496\" lon=\"-71.483746\"><ele>105.4</ele><time>2005-04-18T18:15:06Z</time></trkpt><trkpt lat=\"42.242882\" lon=\"-71.48308\"><ele>103</ele><time>2005-04-18T18:15:23Z</time></trkpt><trkpt lat=\"42.243161\" lon=\"-71.482458\"><ele>101.6</ele><time>2005-04-18T18:15:38Z</time></trkpt><trkpt lat=\"42.243419\" lon=\"-71.48175\"><ele>99.6</ele><time>2005-04-18T18:15:54Z</time></trkpt><trkpt lat=\"42.243526\" lon=\"-71.481514\"><ele>99.2</ele><time>2005-04-18T18:16:00Z</time></trkpt><trkpt lat=\"42.243655\" lon=\"-71.481407\"><ele>98.7</ele><time>2005-04-18T18:16:03Z</time></trkpt><trkpt lat=\"42.243676\" lon=\"-71.481364\"><ele>98.7</ele><time>2005-04-18T18:16:04Z</time></trkpt><trkpt lat=\"42.243783\" lon=\"-71.481063\"><ele>96.3</ele><time>2005-04-18T18:16:10Z</time></trkpt><trkpt lat=\"42.243848\" lon=\"-71.480806\"><ele>97.2</ele><time>2005-04-18T18:16:16Z</time></trkpt><trkpt lat=\"42.244062\" lon=\"-71.480291\"><ele>95.3</ele><time>2005-04-18T18:16:29Z</time></trkpt><trkpt lat=\"42.244341\" lon=\"-71.47969\"><ele>100.1</ele><time>2005-04-18T18:16:44Z</time></trkpt><trkpt lat=\"42.244599\" lon=\"-71.479218\"><ele>101.6</ele><time>2005-04-18T18:16:57Z</time></trkpt><trkpt lat=\"42.244771\" lon=\"-71.478703\"><ele>101.6</ele><time>2005-04-18T18:17:09Z</time></trkpt><trkpt lat=\"42.244964\" lon=\"-71.478102\"><ele>102</ele><time>2005-04-18T18:17:23Z</time></trkpt><trkpt lat=\"42.245178\" lon=\"-71.477458\"><ele>104</ele><time>2005-04-18T18:17:38Z</time></trkpt><trkpt lat=\"42.2455\" lon=\"-71.476579\"><ele>103.5</ele><time>2005-04-18T18:17:59Z</time></trkpt><trkpt lat=\"42.245758\" lon=\"-71.47615\"><ele>102</ele><time>2005-04-18T18:18:10Z</time></trkpt><trkpt lat=\"42.246358\" lon=\"-71.47557\"><ele>100.1</ele><time>2005-04-18T18:18:28Z</time></trkpt><trkpt lat=\"42.246809\" lon=\"-71.475205\"><ele>97.2</ele><time>2005-04-18T18:18:40Z</time></trkpt><trkpt lat=\"42.24756\" lon=\"-71.474605\"><ele>89.1</ele><time>2005-04-18T18:19:03Z</time></trkpt><trkpt lat=\"42.248054\" lon=\"-71.47439\"><ele>88.1</ele><time>2005-04-18T18:19:16Z</time></trkpt><trkpt lat=\"42.248697\" lon=\"-71.473961\"><ele>86.2</ele><time>2005-04-18T18:19:34Z</time></trkpt><trkpt lat=\"42.249362\" lon=\"-71.473403\"><ele>83.3</ele><time>2005-04-18T18:19:55Z</time></trkpt><trkpt lat=\"42.24977\" lon=\"-71.473017\"><ele>81.4</ele><time>2005-04-18T18:20:09Z</time></trkpt><trkpt lat=\"42.250221\" lon=\"-71.472695\"><ele>80.9</ele><time>2005-04-18T18:20:23Z</time></trkpt><trkpt lat=\"42.250671\" lon=\"-71.472394\"><ele>80.4</ele><time>2005-04-18T18:20:37Z</time></trkpt><trkpt lat=\"42.251079\" lon=\"-71.472094\"><ele>80.9</ele><time>2005-04-18T18:20:49Z</time></trkpt><trkpt lat=\"42.25153\" lon=\"-71.471815\"><ele>81.8</ele><time>2005-04-18T18:21:02Z</time></trkpt><trkpt lat=\"42.251959\" lon=\"-71.47145\"><ele>84.3</ele><time>2005-04-18T18:21:15Z</time></trkpt><trkpt lat=\"42.252023\" lon=\"-71.471386\"><ele>84.7</ele><time>2005-04-18T18:21:17Z</time></trkpt><trkpt lat=\"42.252431\" lon=\"-71.470807\"><ele>82.8</ele><time>2005-04-18T18:21:33Z</time></trkpt><trkpt lat=\"42.252903\" lon=\"-71.47012\"><ele>79.4</ele><time>2005-04-18T18:21:52Z</time></trkpt><trkpt lat=\"42.253289\" lon=\"-71.469605\"><ele>76.6</ele><time>2005-04-18T18:22:06Z</time></trkpt><trkpt lat=\"42.253633\" lon=\"-71.469197\"><ele>77</ele><time>2005-04-18T18:22:18Z</time></trkpt><trkpt lat=\"42.254019\" lon=\"-71.46879\"><ele>76.1</ele><time>2005-04-18T18:22:31Z</time></trkpt><trkpt lat=\"42.254491\" lon=\"-71.468339\"><ele>73.7</ele><time>2005-04-18T18:22:47Z</time></trkpt><trkpt lat=\"42.254856\" lon=\"-71.46791\"><ele>70.8</ele><time>2005-04-18T18:23:00Z</time></trkpt><trkpt lat=\"42.25522\" lon=\"-71.467459\"><ele>70.3</ele><time>2005-04-18T18:23:13Z</time></trkpt><trkpt lat=\"42.255435\" lon=\"-71.467009\"><ele>68.9</ele><time>2005-04-18T18:23:23Z</time></trkpt><trkpt lat=\"42.255607\" lon=\"-71.466429\"><ele>67.9</ele><time>2005-04-18T18:23:35Z</time></trkpt><trkpt lat=\"42.25565\" lon=\"-71.465936\"><ele>66.5</ele><time>2005-04-18T18:23:44Z</time></trkpt><trkpt lat=\"42.255735\" lon=\"-71.465399\"><ele>67.9</ele><time>2005-04-18T18:23:55Z</time></trkpt><trkpt lat=\"42.255864\" lon=\"-71.464841\"><ele>68.9</ele><time>2005-04-18T18:24:07Z</time></trkpt><trkpt lat=\"42.255971\" lon=\"-71.464305\"><ele>67.4</ele><time>2005-04-18T18:24:18Z</time></trkpt><trkpt lat=\"42.256122\" lon=\"-71.463661\"><ele>66</ele><time>2005-04-18T18:24:32Z</time></trkpt><trkpt lat=\"42.256336\" lon=\"-71.462996\"><ele>65.5</ele><time>2005-04-18T18:24:46Z</time></trkpt><trkpt lat=\"42.256508\" lon=\"-71.462417\"><ele>63.1</ele><time>2005-04-18T18:24:59Z</time></trkpt><trkpt lat=\"42.256637\" lon=\"-71.461923\"><ele>61.7</ele><time>2005-04-18T18:25:10Z</time></trkpt><trkpt lat=\"42.256787\" lon=\"-71.461473\"><ele>62.6</ele><time>2005-04-18T18:25:20Z</time></trkpt><trkpt lat=\"42.256958\" lon=\"-71.460915\"><ele>62.1</ele><time>2005-04-18T18:25:32Z</time></trkpt><trkpt lat=\"42.25713\" lon=\"-71.460378\"><ele>61.2</ele><time>2005-04-18T18:25:43Z</time></trkpt><trkpt lat=\"42.257345\" lon=\"-71.459734\"><ele>61.7</ele><time>2005-04-18T18:25:57Z</time></trkpt><trkpt lat=\"42.257538\" lon=\"-71.459155\"><ele>62.1</ele><time>2005-04-18T18:26:10Z</time></trkpt><trkpt lat=\"42.257667\" lon=\"-71.458619\"><ele>63.1</ele><time>2005-04-18T18:26:21Z</time></trkpt><trkpt lat=\"42.25786\" lon=\"-71.458018\"><ele>63.1</ele><time>2005-04-18T18:26:33Z</time></trkpt><trkpt lat=\"42.258053\" lon=\"-71.45731\"><ele>61.2</ele><time>2005-04-18T18:26:48Z</time></trkpt><trkpt lat=\"42.258224\" lon=\"-71.456666\"><ele>61.7</ele><time>2005-04-18T18:27:02Z</time></trkpt><trkpt lat=\"42.258332\" lon=\"-71.456108\"><ele>61.7</ele><time>2005-04-18T18:27:14Z</time></trkpt><trkpt lat=\"42.258461\" lon=\"-71.455443\"><ele>60.7</ele><time>2005-04-18T18:27:28Z</time></trkpt><trkpt lat=\"42.258589\" lon=\"-71.454778\"><ele>58.8</ele><time>2005-04-18T18:27:42Z</time></trkpt><trkpt lat=\"42.258589\" lon=\"-71.454713\"><ele>58.8</ele><time>2005-04-18T18:27:43Z</time></trkpt><trkpt lat=\"42.258697\" lon=\"-71.454198\"><ele>59.3</ele><time>2005-04-18T18:27:54Z</time></trkpt><trkpt lat=\"42.258804\" lon=\"-71.453748\"><ele>60.7</ele><time>2005-04-18T18:28:04Z</time></trkpt><trkpt lat=\"42.259061\" lon=\"-71.453211\"><ele>63.6</ele><time>2005-04-18T18:28:17Z</time></trkpt><trkpt lat=\"42.259319\" lon=\"-71.452718\"><ele>63.1</ele><time>2005-04-18T18:28:29Z</time></trkpt><trkpt lat=\"42.259598\" lon=\"-71.452267\"><ele>63.1</ele><time>2005-04-18T18:28:41Z</time></trkpt><trkpt lat=\"42.259877\" lon=\"-71.451817\"><ele>62.6</ele><time>2005-04-18T18:28:53Z</time></trkpt><trkpt lat=\"42.26007\" lon=\"-71.451516\"><ele>63.1</ele><time>2005-04-18T18:29:01Z</time></trkpt><trkpt lat=\"42.260392\" lon=\"-71.451023\"><ele>64.1</ele><time>2005-04-18T18:29:15Z</time></trkpt><trkpt lat=\"42.260671\" lon=\"-71.450615\"><ele>63.6</ele><time>2005-04-18T18:29:27Z</time></trkpt><trkpt lat=\"42.261035\" lon=\"-71.450186\"><ele>63.6</ele><time>2005-04-18T18:29:41Z</time></trkpt><trkpt lat=\"42.2614\" lon=\"-71.449864\"><ele>63.6</ele><time>2005-04-18T18:29:54Z</time></trkpt><trkpt lat=\"42.261937\" lon=\"-71.449521\"><ele>62.1</ele><time>2005-04-18T18:30:11Z</time></trkpt><trkpt lat=\"42.262387\" lon=\"-71.449349\"><ele>64.5</ele><time>2005-04-18T18:30:25Z</time></trkpt><trkpt lat=\"42.262795\" lon=\"-71.449113\"><ele>66</ele><time>2005-04-18T18:30:37Z</time></trkpt><trkpt lat=\"42.263074\" lon=\"-71.448834\"><ele>68.4</ele><time>2005-04-18T18:30:47Z</time></trkpt><trkpt lat=\"42.263374\" lon=\"-71.448491\"><ele>69.8</ele><time>2005-04-18T18:30:58Z</time></trkpt><trkpt lat=\"42.263696\" lon=\"-71.448212\"><ele>72.7</ele><time>2005-04-18T18:31:09Z</time></trkpt><trkpt lat=\"42.264168\" lon=\"-71.44789\"><ele>73.2</ele><time>2005-04-18T18:31:24Z</time></trkpt><trkpt lat=\"42.264619\" lon=\"-71.447546\"><ele>74.6</ele><time>2005-04-18T18:31:38Z</time></trkpt><trkpt lat=\"42.265048\" lon=\"-71.447096\"><ele>73.2</ele><time>2005-04-18T18:31:54Z</time></trkpt><trkpt lat=\"42.265391\" lon=\"-71.446753\"><ele>72.7</ele><time>2005-04-18T18:32:06Z</time></trkpt><trkpt lat=\"42.266099\" lon=\"-71.446195\"><ele>75.1</ele><time>2005-04-18T18:32:28Z</time></trkpt><trkpt lat=\"42.266657\" lon=\"-71.445916\"><ele>73.2</ele><time>2005-04-18T18:32:44Z</time></trkpt><trkpt lat=\"42.267087\" lon=\"-71.445744\"><ele>73.7</ele><time>2005-04-18T18:32:56Z</time></trkpt><trkpt lat=\"42.267559\" lon=\"-71.445572\"><ele>74.6</ele><time>2005-04-18T18:33:09Z</time></trkpt><trkpt lat=\"42.268095\" lon=\"-71.445358\"><ele>74.2</ele><time>2005-04-18T18:33:24Z</time></trkpt><trkpt lat=\"42.268567\" lon=\"-71.445186\"><ele>74.6</ele><time>2005-04-18T18:33:37Z</time></trkpt><trkpt lat=\"42.269061\" lon=\"-71.445014\"><ele>71.8</ele><time>2005-04-18T18:33:50Z</time></trkpt><trkpt lat=\"42.269661\" lon=\"-71.444821\"><ele>72.2</ele><time>2005-04-18T18:34:06Z</time></trkpt><trkpt lat=\"42.270026\" lon=\"-71.444585\"><ele>68.4</ele><time>2005-04-18T18:34:17Z</time></trkpt><trkpt lat=\"42.270241\" lon=\"-71.444392\"><ele>66.9</ele><time>2005-04-18T18:34:24Z</time></trkpt><trkpt lat=\"42.270455\" lon=\"-71.444199\"><ele>66.9</ele><time>2005-04-18T18:34:31Z</time></trkpt><trkpt lat=\"42.270713\" lon=\"-71.443963\"><ele>66.5</ele><time>2005-04-18T18:34:40Z</time></trkpt><trkpt lat=\"42.271142\" lon=\"-71.443577\"><ele>66.5</ele><time>2005-04-18T18:34:55Z</time></trkpt><trkpt lat=\"42.271593\" lon=\"-71.443169\"><ele>67.4</ele><time>2005-04-18T18:35:10Z</time></trkpt><trkpt lat=\"42.271807\" lon=\"-71.442847\"><ele>65.5</ele><time>2005-04-18T18:35:19Z</time></trkpt><trkpt lat=\"42.271914\" lon=\"-71.442568\"><ele>66.5</ele><time>2005-04-18T18:35:25Z</time></trkpt><trkpt lat=\"42.272172\" lon=\"-71.441967\"><ele>67.9</ele><time>2005-04-18T18:35:38Z</time></trkpt><trkpt lat=\"42.272387\" lon=\"-71.441453\"><ele>64.1</ele><time>2005-04-18T18:35:49Z</time></trkpt><trkpt lat=\"42.272623\" lon=\"-71.441023\"><ele>63.6</ele><time>2005-04-18T18:35:59Z</time></trkpt><trkpt lat=\"42.272859\" lon=\"-71.440487\"><ele>63.6</ele><time>2005-04-18T18:36:11Z</time></trkpt><trkpt lat=\"42.273073\" lon=\"-71.439972\"><ele>63.6</ele><time>2005-04-18T18:36:23Z</time></trkpt><trkpt lat=\"42.273309\" lon=\"-71.439521\"><ele>63.1</ele><time>2005-04-18T18:36:34Z</time></trkpt><trkpt lat=\"42.273588\" lon=\"-71.439092\"><ele>63.6</ele><time>2005-04-18T18:36:46Z</time></trkpt><trkpt lat=\"42.273889\" lon=\"-71.43862\"><ele>65</ele><time>2005-04-18T18:36:58Z</time></trkpt><trkpt lat=\"42.274103\" lon=\"-71.438084\"><ele>62.6</ele><time>2005-04-18T18:37:10Z</time></trkpt><trkpt lat=\"42.274253\" lon=\"-71.437547\"><ele>63.6</ele><time>2005-04-18T18:37:22Z</time></trkpt><trkpt lat=\"42.274275\" lon=\"-71.436925\"><ele>66</ele><time>2005-04-18T18:37:35Z</time></trkpt><trkpt lat=\"42.274275\" lon=\"-71.436646\"><ele>66.5</ele><time>2005-04-18T18:37:41Z</time></trkpt><trkpt lat=\"42.274189\" lon=\"-71.436388\"><ele>66.5</ele><time>2005-04-18T18:37:47Z</time></trkpt><trkpt lat=\"42.274146\" lon=\"-71.436152\"><ele>66</ele><time>2005-04-18T18:37:52Z</time></trkpt><trkpt lat=\"42.273996\" lon=\"-71.435573\"><ele>66</ele><time>2005-04-18T18:38:04Z</time></trkpt><trkpt lat=\"42.27391\" lon=\"-71.43508\"><ele>66</ele><time>2005-04-18T18:38:14Z</time></trkpt><trkpt lat=\"42.273781\" lon=\"-71.434414\"><ele>65.5</ele><time>2005-04-18T18:38:28Z</time></trkpt><trkpt lat=\"42.273695\" lon=\"-71.433921\"><ele>64.5</ele><time>2005-04-18T18:38:38Z</time></trkpt><trkpt lat=\"42.273567\" lon=\"-71.433277\"><ele>62.6</ele><time>2005-04-18T18:38:52Z</time></trkpt><trkpt lat=\"42.273374\" lon=\"-71.432462\"><ele>63.1</ele><time>2005-04-18T18:39:10Z</time></trkpt><trkpt lat=\"42.273202\" lon=\"-71.431711\"><ele>63.1</ele><time>2005-04-18T18:39:26Z</time></trkpt><trkpt lat=\"42.272987\" lon=\"-71.431088\"><ele>66</ele><time>2005-04-18T18:39:40Z</time></trkpt><trkpt lat=\"42.272666\" lon=\"-71.430552\"><ele>65.5</ele><time>2005-04-18T18:39:54Z</time></trkpt><trkpt lat=\"42.272322\" lon=\"-71.430016\"><ele>64.1</ele><time>2005-04-18T18:40:08Z</time></trkpt><trkpt lat=\"42.272129\" lon=\"-71.429565\"><ele>63.1</ele><time>2005-04-18T18:40:19Z</time></trkpt><trkpt lat=\"42.272086\" lon=\"-71.429179\"><ele>63.6</ele><time>2005-04-18T18:40:27Z</time></trkpt><trkpt lat=\"42.272172\" lon=\"-71.428986\"><ele>63.6</ele><time>2005-04-18T18:40:31Z</time></trkpt><trkpt lat=\"42.272408\" lon=\"-71.428599\"><ele>63.1</ele><time>2005-04-18T18:40:40Z</time></trkpt><trkpt lat=\"42.272666\" lon=\"-71.428192\"><ele>62.6</ele><time>2005-04-18T18:40:50Z</time></trkpt><trkpt lat=\"42.272816\" lon=\"-71.427913\"><ele>61.7</ele><time>2005-04-18T18:40:57Z</time></trkpt><trkpt lat=\"42.272966\" lon=\"-71.427612\"><ele>63.1</ele><time>2005-04-18T18:41:04Z</time></trkpt><trkpt lat=\"42.273245\" lon=\"-71.427076\"><ele>62.1</ele><time>2005-04-18T18:41:17Z</time></trkpt><trkpt lat=\"42.273459\" lon=\"-71.426604\"><ele>61.2</ele><time>2005-04-18T18:41:28Z</time></trkpt><trkpt lat=\"42.273674\" lon=\"-71.426153\"><ele>59.3</ele><time>2005-04-18T18:41:38Z</time></trkpt><trkpt lat=\"42.273932\" lon=\"-71.42566\"><ele>59.7</ele><time>2005-04-18T18:41:50Z</time></trkpt><trkpt lat=\"42.274125\" lon=\"-71.425252\"><ele>59.3</ele><time>2005-04-18T18:42:00Z</time></trkpt><trkpt lat=\"42.274404\" lon=\"-71.424737\"><ele>57.8</ele><time>2005-04-18T18:42:13Z</time></trkpt><trkpt lat=\"42.274554\" lon=\"-71.424243\"><ele>56.9</ele><time>2005-04-18T18:42:24Z</time></trkpt><trkpt lat=\"42.274683\" lon=\"-71.423793\"><ele>56.4</ele><time>2005-04-18T18:42:34Z</time></trkpt><trkpt lat=\"42.274854\" lon=\"-71.423256\"><ele>58.3</ele><time>2005-04-18T18:42:45Z</time></trkpt><trkpt lat=\"42.275047\" lon=\"-71.422698\"><ele>58.8</ele><time>2005-04-18T18:42:57Z</time></trkpt><trkpt lat=\"42.275198\" lon=\"-71.422162\"><ele>57.8</ele><time>2005-04-18T18:43:09Z</time></trkpt><trkpt lat=\"42.275369\" lon=\"-71.421626\"><ele>57.8</ele><time>2005-04-18T18:43:21Z</time></trkpt><trkpt lat=\"42.275541\" lon=\"-71.421003\"><ele>59.3</ele><time>2005-04-18T18:43:34Z</time></trkpt><trkpt lat=\"42.275691\" lon=\"-71.420424\"><ele>57.3</ele><time>2005-04-18T18:43:47Z</time></trkpt><trkpt lat=\"42.275884\" lon=\"-71.419802\"><ele>57.8</ele><time>2005-04-18T18:44:01Z</time></trkpt><trkpt lat=\"42.276056\" lon=\"-71.419265\"><ele>57.3</ele><time>2005-04-18T18:44:13Z</time></trkpt><trkpt lat=\"42.276206\" lon=\"-71.418707\"><ele>58.3</ele><time>2005-04-18T18:44:25Z</time></trkpt><trkpt lat=\"42.276335\" lon=\"-71.418214\"><ele>58.8</ele><time>2005-04-18T18:44:36Z</time></trkpt><trkpt lat=\"42.276464\" lon=\"-71.417634\"><ele>58.8</ele><time>2005-04-18T18:44:48Z</time></trkpt><trkpt lat=\"42.276592\" lon=\"-71.417205\"><ele>58.3</ele><time>2005-04-18T18:44:57Z</time></trkpt><trkpt lat=\"42.276764\" lon=\"-71.416626\"><ele>57.3</ele><time>2005-04-18T18:45:10Z</time></trkpt><trkpt lat=\"42.276914\" lon=\"-71.41609\"><ele>57.3</ele><time>2005-04-18T18:45:21Z</time></trkpt><trkpt lat=\"42.277043\" lon=\"-71.415532\"><ele>56.9</ele><time>2005-04-18T18:45:33Z</time></trkpt><trkpt lat=\"42.277193\" lon=\"-71.415017\"><ele>57.3</ele><time>2005-04-18T18:45:44Z</time></trkpt><trkpt lat=\"42.277322\" lon=\"-71.414394\"><ele>57.3</ele><time>2005-04-18T18:45:57Z</time></trkpt><trkpt lat=\"42.277429\" lon=\"-71.413815\"><ele>57.3</ele><time>2005-04-18T18:46:09Z</time></trkpt><trkpt lat=\"42.277558\" lon=\"-71.413236\"><ele>55.9</ele><time>2005-04-18T18:46:21Z</time></trkpt><trkpt lat=\"42.277665\" lon=\"-71.412656\"><ele>54.9</ele><time>2005-04-18T18:46:33Z</time></trkpt><trkpt lat=\"42.277794\" lon=\"-71.412098\"><ele>53.5</ele><time>2005-04-18T18:46:45Z</time></trkpt><trkpt lat=\"42.27788\" lon=\"-71.411541\"><ele>53</ele><time>2005-04-18T18:46:57Z</time></trkpt><trkpt lat=\"42.277987\" lon=\"-71.411004\"><ele>53.5</ele><time>2005-04-18T18:47:09Z</time></trkpt><trkpt lat=\"42.278094\" lon=\"-71.410446\"><ele>53</ele><time>2005-04-18T18:47:21Z</time></trkpt><trkpt lat=\"42.278202\" lon=\"-71.409931\"><ele>54.5</ele><time>2005-04-18T18:47:32Z</time></trkpt><trkpt lat=\"42.27833\" lon=\"-71.409309\"><ele>54.5</ele><time>2005-04-18T18:47:45Z</time></trkpt><trkpt lat=\"42.278416\" lon=\"-71.408944\"><ele>54.9</ele><time>2005-04-18T18:47:53Z</time></trkpt><trkpt lat=\"42.278502\" lon=\"-71.408601\"><ele>54.9</ele><time>2005-04-18T18:48:00Z</time></trkpt><trkpt lat=\"42.278588\" lon=\"-71.408172\"><ele>54.5</ele><time>2005-04-18T18:48:09Z</time></trkpt><trkpt lat=\"42.278717\" lon=\"-71.407657\"><ele>54</ele><time>2005-04-18T18:48:20Z</time></trkpt><trkpt lat=\"42.278845\" lon=\"-71.407185\"><ele>53.5</ele><time>2005-04-18T18:48:30Z</time></trkpt><trkpt lat=\"42.278953\" lon=\"-71.406648\"><ele>52</ele><time>2005-04-18T18:48:41Z</time></trkpt><trkpt lat=\"42.279081\" lon=\"-71.406069\"><ele>52</ele><time>2005-04-18T18:48:53Z</time></trkpt><trkpt lat=\"42.279189\" lon=\"-71.405683\"><ele>54</ele><time>2005-04-18T18:49:01Z</time></trkpt><trkpt lat=\"42.279253\" lon=\"-71.405168\"><ele>53</ele><time>2005-04-18T18:49:11Z</time></trkpt><trkpt lat=\"42.279425\" lon=\"-71.404502\"><ele>54.9</ele><time>2005-04-18T18:49:25Z</time></trkpt><trkpt lat=\"42.279532\" lon=\"-71.403944\"><ele>55.4</ele><time>2005-04-18T18:49:37Z</time></trkpt><trkpt lat=\"42.279682\" lon=\"-71.403387\"><ele>54.5</ele><time>2005-04-18T18:49:49Z</time></trkpt><trkpt lat=\"42.279789\" lon=\"-71.402872\"><ele>54.5</ele><time>2005-04-18T18:50:00Z</time></trkpt><trkpt lat=\"42.27994\" lon=\"-71.402206\"><ele>53</ele><time>2005-04-18T18:50:14Z</time></trkpt><trkpt lat=\"42.280068\" lon=\"-71.401627\"><ele>53.5</ele><time>2005-04-18T18:50:26Z</time></trkpt><trkpt lat=\"42.280154\" lon=\"-71.401262\"><ele>53.5</ele><time>2005-04-18T18:50:34Z</time></trkpt><trkpt lat=\"42.280262\" lon=\"-71.40079\"><ele>54</ele><time>2005-04-18T18:50:44Z</time></trkpt><trkpt lat=\"42.280347\" lon=\"-71.400404\"><ele>53.5</ele><time>2005-04-18T18:50:52Z</time></trkpt><trkpt lat=\"42.280455\" lon=\"-71.399953\"><ele>53</ele><time>2005-04-18T18:51:02Z</time></trkpt><trkpt lat=\"42.280583\" lon=\"-71.399374\"><ele>52</ele><time>2005-04-18T18:51:14Z</time></trkpt><trkpt lat=\"42.280734\" lon=\"-71.398709\"><ele>53.5</ele><time>2005-04-18T18:51:28Z</time></trkpt><trkpt lat=\"42.280841\" lon=\"-71.398172\"><ele>54.9</ele><time>2005-04-18T18:51:40Z</time></trkpt><trkpt lat=\"42.280948\" lon=\"-71.397679\"><ele>54.9</ele><time>2005-04-18T18:51:51Z</time></trkpt><trkpt lat=\"42.281077\" lon=\"-71.397121\"><ele>55.9</ele><time>2005-04-18T18:52:03Z</time></trkpt><trkpt lat=\"42.281184\" lon=\"-71.396585\"><ele>53.5</ele><time>2005-04-18T18:52:14Z</time></trkpt><trkpt lat=\"42.281313\" lon=\"-71.395962\"><ele>55.9</ele><time>2005-04-18T18:52:28Z</time></trkpt><trkpt lat=\"42.281442\" lon=\"-71.395447\"><ele>58.3</ele><time>2005-04-18T18:52:40Z</time></trkpt><trkpt lat=\"42.281442\" lon=\"-71.395361\"><ele>57.8</ele><time>2005-04-18T18:52:42Z</time></trkpt><trkpt lat=\"42.281485\" lon=\"-71.395276\"><ele>57.3</ele><time>2005-04-18T18:52:44Z</time></trkpt><trkpt lat=\"42.281528\" lon=\"-71.39504\"><ele>58.8</ele><time>2005-04-18T18:52:49Z</time></trkpt><trkpt lat=\"42.281592\" lon=\"-71.394589\"><ele>60.7</ele><time>2005-04-18T18:52:59Z</time></trkpt><trkpt lat=\"42.281721\" lon=\"-71.393924\"><ele>59.3</ele><time>2005-04-18T18:53:13Z</time></trkpt><trkpt lat=\"42.281764\" lon=\"-71.393259\"><ele>60.7</ele><time>2005-04-18T18:53:27Z</time></trkpt><trkpt lat=\"42.281785\" lon=\"-71.392636\"><ele>57.8</ele><time>2005-04-18T18:53:39Z</time></trkpt><trkpt lat=\"42.281828\" lon=\"-71.391971\"><ele>56.4</ele><time>2005-04-18T18:53:52Z</time></trkpt><trkpt lat=\"42.281871\" lon=\"-71.391392\"><ele>56.4</ele><time>2005-04-18T18:54:03Z</time></trkpt><trkpt lat=\"42.281892\" lon=\"-71.391134\"><ele>56.9</ele><time>2005-04-18T18:54:08Z</time></trkpt><trkpt lat=\"42.281914\" lon=\"-71.390791\"><ele>55.4</ele><time>2005-04-18T18:54:15Z</time></trkpt><trkpt lat=\"42.281935\" lon=\"-71.390254\"><ele>54.9</ele><time>2005-04-18T18:54:26Z</time></trkpt><trkpt lat=\"42.281957\" lon=\"-71.389997\"><ele>54</ele><time>2005-04-18T18:54:32Z</time></trkpt><trkpt lat=\"42.281978\" lon=\"-71.389761\"><ele>53.5</ele><time>2005-04-18T18:54:37Z</time></trkpt><trkpt lat=\"42.282\" lon=\"-71.389482\"><ele>53</ele><time>2005-04-18T18:54:43Z</time></trkpt><trkpt lat=\"42.282043\" lon=\"-71.388903\"><ele>54.9</ele><time>2005-04-18T18:54:55Z</time></trkpt><trkpt lat=\"42.282064\" lon=\"-71.388259\"><ele>55.9</ele><time>2005-04-18T18:55:08Z</time></trkpt><trkpt lat=\"42.282107\" lon=\"-71.38768\"><ele>55.9</ele><time>2005-04-18T18:55:20Z</time></trkpt><trkpt lat=\"42.28215\" lon=\"-71.387014\"><ele>55.9</ele><time>2005-04-18T18:55:34Z</time></trkpt><trkpt lat=\"42.282171\" lon=\"-71.386349\"><ele>55.9</ele><time>2005-04-18T18:55:48Z</time></trkpt><trkpt lat=\"42.282214\" lon=\"-71.385748\"><ele>56.9</ele><time>2005-04-18T18:56:00Z</time></trkpt><trkpt lat=\"42.282257\" lon=\"-71.385126\"><ele>57.8</ele><time>2005-04-18T18:56:12Z</time></trkpt><trkpt lat=\"42.282321\" lon=\"-71.384482\"><ele>56.4</ele><time>2005-04-18T18:56:25Z</time></trkpt><trkpt lat=\"42.282364\" lon=\"-71.383924\"><ele>54.9</ele><time>2005-04-18T18:56:36Z</time></trkpt><trkpt lat=\"42.282407\" lon=\"-71.383324\"><ele>54.5</ele><time>2005-04-18T18:56:48Z</time></trkpt><trkpt lat=\"42.282407\" lon=\"-71.38268\"><ele>54</ele><time>2005-04-18T18:57:01Z</time></trkpt><trkpt lat=\"42.28245\" lon=\"-71.382015\"><ele>55.9</ele><time>2005-04-18T18:57:15Z</time></trkpt><trkpt lat=\"42.282472\" lon=\"-71.381478\"><ele>56.9</ele><time>2005-04-18T18:57:26Z</time></trkpt><trkpt lat=\"42.282493\" lon=\"-71.380835\"><ele>56.9</ele><time>2005-04-18T18:57:39Z</time></trkpt><trkpt lat=\"42.282515\" lon=\"-71.380148\"><ele>56.9</ele><time>2005-04-18T18:57:53Z</time></trkpt><trkpt lat=\"42.282557\" lon=\"-71.37944\"><ele>56.9</ele><time>2005-04-18T18:58:07Z</time></trkpt><trkpt lat=\"42.282557\" lon=\"-71.378796\"><ele>54.9</ele><time>2005-04-18T18:58:20Z</time></trkpt><trkpt lat=\"42.282536\" lon=\"-71.378195\"><ele>58.3</ele><time>2005-04-18T18:58:32Z</time></trkpt><trkpt lat=\"42.282515\" lon=\"-71.37753\"><ele>54</ele><time>2005-04-18T18:58:46Z</time></trkpt><trkpt lat=\"42.282557\" lon=\"-71.376951\"><ele>54.5</ele><time>2005-04-18T18:58:58Z</time></trkpt><trkpt lat=\"42.282536\" lon=\"-71.376328\"><ele>52.5</ele><time>2005-04-18T18:59:11Z</time></trkpt><trkpt lat=\"42.282557\" lon=\"-71.375685\"><ele>52.5</ele><time>2005-04-18T18:59:24Z</time></trkpt><trkpt lat=\"42.282643\" lon=\"-71.374998\"><ele>51.6</ele><time>2005-04-18T18:59:38Z</time></trkpt><trkpt lat=\"42.282751\" lon=\"-71.374311\"><ele>52.5</ele><time>2005-04-18T18:59:52Z</time></trkpt><trkpt lat=\"42.282879\" lon=\"-71.373668\"><ele>51.6</ele><time>2005-04-18T19:00:06Z</time></trkpt><trkpt lat=\"42.282987\" lon=\"-71.373045\"><ele>52</ele><time>2005-04-18T19:00:19Z</time></trkpt><trkpt lat=\"42.283094\" lon=\"-71.372402\"><ele>52.5</ele><time>2005-04-18T19:00:32Z</time></trkpt><trkpt lat=\"42.283158\" lon=\"-71.37193\"><ele>53</ele><time>2005-04-18T19:00:42Z</time></trkpt><trkpt lat=\"42.28318\" lon=\"-71.371737\"><ele>53.5</ele><time>2005-04-18T19:00:46Z</time></trkpt><trkpt lat=\"42.283223\" lon=\"-71.371479\"><ele>53.5</ele><time>2005-04-18T19:00:51Z</time></trkpt><trkpt lat=\"42.283309\" lon=\"-71.370943\"><ele>53</ele><time>2005-04-18T19:01:02Z</time></trkpt><trkpt lat=\"42.283437\" lon=\"-71.370299\"><ele>51.1</ele><time>2005-04-18T19:01:15Z</time></trkpt><trkpt lat=\"42.283523\" lon=\"-71.369805\"><ele>50.6</ele><time>2005-04-18T19:01:25Z</time></trkpt><trkpt lat=\"42.283587\" lon=\"-71.369355\"><ele>50.6</ele><time>2005-04-18T19:01:34Z</time></trkpt><trkpt lat=\"42.283673\" lon=\"-71.368883\"><ele>49.6</ele><time>2005-04-18T19:01:44Z</time></trkpt><trkpt lat=\"42.283759\" lon=\"-71.368303\"><ele>49.6</ele><time>2005-04-18T19:01:56Z</time></trkpt><trkpt lat=\"42.283823\" lon=\"-71.367724\"><ele>51.1</ele><time>2005-04-18T19:02:08Z</time></trkpt><trkpt lat=\"42.283802\" lon=\"-71.367188\"><ele>50.6</ele><time>2005-04-18T19:02:19Z</time></trkpt><trkpt lat=\"42.283673\" lon=\"-71.366673\"><ele>50.6</ele><time>2005-04-18T19:02:30Z</time></trkpt><trkpt lat=\"42.283459\" lon=\"-71.365986\"><ele>52</ele><time>2005-04-18T19:02:46Z</time></trkpt><trkpt lat=\"42.283244\" lon=\"-71.365321\"><ele>53</ele><time>2005-04-18T19:03:01Z</time></trkpt><trkpt lat=\"42.283137\" lon=\"-71.364784\"><ele>52</ele><time>2005-04-18T19:03:12Z</time></trkpt><trkpt lat=\"42.282944\" lon=\"-71.364183\"><ele>52</ele><time>2005-04-18T19:03:25Z</time></trkpt><trkpt lat=\"42.282579\" lon=\"-71.363068\"><ele>51.6</ele><time>2005-04-18T19:03:50Z</time></trkpt><trkpt lat=\"42.282085\" lon=\"-71.361179\"><ele>52.5</ele><time>2005-04-18T19:04:32Z</time></trkpt><trkpt lat=\"42.282214\" lon=\"-71.359141\"><ele>56.9</ele><time>2005-04-18T19:05:14Z</time></trkpt><trkpt lat=\"42.282236\" lon=\"-71.358883\"><ele>63.1</ele><time>2005-04-18T19:05:20Z</time></trkpt><trkpt lat=\"42.282386\" lon=\"-71.35824\"><ele>63.6</ele><time>2005-04-18T19:05:34Z</time></trkpt><trkpt lat=\"42.282515\" lon=\"-71.357467\"><ele>61.2</ele><time>2005-04-18T19:05:50Z</time></trkpt><trkpt lat=\"42.2826\" lon=\"-71.356802\"><ele>65</ele><time>2005-04-18T19:06:04Z</time></trkpt><trkpt lat=\"42.282686\" lon=\"-71.356008\"><ele>65.5</ele><time>2005-04-18T19:06:21Z</time></trkpt><trkpt lat=\"42.282794\" lon=\"-71.355472\"><ele>66.5</ele><time>2005-04-18T19:06:32Z</time></trkpt><trkpt lat=\"42.282858\" lon=\"-71.354721\"><ele>64.5</ele><time>2005-04-18T19:06:48Z</time></trkpt><trkpt lat=\"42.282879\" lon=\"-71.354527\"><ele>64.1</ele><time>2005-04-18T19:06:52Z</time></trkpt><trkpt lat=\"42.282879\" lon=\"-71.354334\"><ele>64.1</ele><time>2005-04-18T19:06:56Z</time></trkpt><trkpt lat=\"42.282879\" lon=\"-71.354291\"><ele>64.1</ele><time>2005-04-18T19:06:57Z</time></trkpt><trkpt lat=\"42.282922\" lon=\"-71.353712\"><ele>63.6</ele><time>2005-04-18T19:07:08Z</time></trkpt><trkpt lat=\"42.283008\" lon=\"-71.353111\"><ele>63.6</ele><time>2005-04-18T19:07:20Z</time></trkpt><trkpt lat=\"42.283094\" lon=\"-71.352575\"><ele>64.5</ele><time>2005-04-18T19:07:31Z</time></trkpt><trkpt lat=\"42.283223\" lon=\"-71.35191\"><ele>61.7</ele><time>2005-04-18T19:07:45Z</time></trkpt><trkpt lat=\"42.283373\" lon=\"-71.351137\"><ele>62.1</ele><time>2005-04-18T19:08:01Z</time></trkpt><trkpt lat=\"42.28348\" lon=\"-71.350515\"><ele>60.7</ele><time>2005-04-18T19:08:15Z</time></trkpt><trkpt lat=\"42.283545\" lon=\"-71.349785\"><ele>61.2</ele><time>2005-04-18T19:08:31Z</time></trkpt><trkpt lat=\"42.28363\" lon=\"-71.349034\"><ele>62.6</ele><time>2005-04-18T19:08:47Z</time></trkpt><trkpt lat=\"42.283673\" lon=\"-71.348476\"><ele>63.1</ele><time>2005-04-18T19:08:59Z</time></trkpt><trkpt lat=\"42.283781\" lon=\"-71.347768\"><ele>63.1</ele><time>2005-04-18T19:09:14Z</time></trkpt><trkpt lat=\"42.283823\" lon=\"-71.347103\"><ele>59.7</ele><time>2005-04-18T19:09:28Z</time></trkpt><trkpt lat=\"42.283931\" lon=\"-71.346459\"><ele>60.2</ele><time>2005-04-18T19:09:42Z</time></trkpt><trkpt lat=\"42.284081\" lon=\"-71.345794\"><ele>61.2</ele><time>2005-04-18T19:09:56Z</time></trkpt><trkpt lat=\"42.284188\" lon=\"-71.345172\"><ele>61.2</ele><time>2005-04-18T19:10:09Z</time></trkpt><trkpt lat=\"42.284274\" lon=\"-71.344657\"><ele>61.7</ele><time>2005-04-18T19:10:19Z</time></trkpt><trkpt lat=\"42.284467\" lon=\"-71.343884\"><ele>65</ele><time>2005-04-18T19:10:34Z</time></trkpt><trkpt lat=\"42.284575\" lon=\"-71.343262\"><ele>64.5</ele><time>2005-04-18T19:10:47Z</time></trkpt><trkpt lat=\"42.284682\" lon=\"-71.342511\"><ele>64.5</ele><time>2005-04-18T19:11:02Z</time></trkpt><trkpt lat=\"42.284768\" lon=\"-71.341996\"><ele>64.5</ele><time>2005-04-18T19:11:13Z</time></trkpt><trkpt lat=\"42.284875\" lon=\"-71.341438\"><ele>65.5</ele><time>2005-04-18T19:11:25Z</time></trkpt><trkpt lat=\"42.285004\" lon=\"-71.340666\"><ele>65</ele><time>2005-04-18T19:11:41Z</time></trkpt><trkpt lat=\"42.285154\" lon=\"-71.340151\"><ele>66.5</ele><time>2005-04-18T19:11:53Z</time></trkpt><trkpt lat=\"42.285368\" lon=\"-71.33955\"><ele>66.5</ele><time>2005-04-18T19:12:07Z</time></trkpt><trkpt lat=\"42.285733\" lon=\"-71.338542\"><ele>66.9</ele><time>2005-04-18T19:12:31Z</time></trkpt><trkpt lat=\"42.285948\" lon=\"-71.338005\"><ele>66</ele><time>2005-04-18T19:12:43Z</time></trkpt><trkpt lat=\"42.286227\" lon=\"-71.33734\"><ele>67.9</ele><time>2005-04-18T19:12:59Z</time></trkpt><trkpt lat=\"42.28642\" lon=\"-71.336739\"><ele>66.9</ele><time>2005-04-18T19:13:13Z</time></trkpt><trkpt lat=\"42.286656\" lon=\"-71.336138\"><ele>66.5</ele><time>2005-04-18T19:13:27Z</time></trkpt><trkpt lat=\"42.28687\" lon=\"-71.335516\"><ele>66.9</ele><time>2005-04-18T19:13:41Z</time></trkpt><trkpt lat=\"42.287021\" lon=\"-71.335065\"><ele>66.5</ele><time>2005-04-18T19:13:51Z</time></trkpt><trkpt lat=\"42.287192\" lon=\"-71.334636\"><ele>68.9</ele><time>2005-04-18T19:14:01Z</time></trkpt><trkpt lat=\"42.287257\" lon=\"-71.334465\"><ele>68.4</ele><time>2005-04-18T19:14:05Z</time></trkpt><trkpt lat=\"42.287493\" lon=\"-71.333885\"><ele>68.9</ele><time>2005-04-18T19:14:19Z</time></trkpt><trkpt lat=\"42.287729\" lon=\"-71.333306\"><ele>67.9</ele><time>2005-04-18T19:14:33Z</time></trkpt><trkpt lat=\"42.288051\" lon=\"-71.332598\"><ele>69.4</ele><time>2005-04-18T19:14:51Z</time></trkpt><trkpt lat=\"42.288351\" lon=\"-71.331761\"><ele>77.5</ele><time>2005-04-18T19:15:12Z</time></trkpt><trkpt lat=\"42.288952\" lon=\"-71.330495\"><ele>77.5</ele><time>2005-04-18T19:15:45Z</time></trkpt><trkpt lat=\"42.289381\" lon=\"-71.329722\"><ele>76.1</ele><time>2005-04-18T19:16:05Z</time></trkpt><trkpt lat=\"42.289939\" lon=\"-71.328821\"><ele>72.7</ele><time>2005-04-18T19:16:28Z</time></trkpt><trkpt lat=\"42.290432\" lon=\"-71.328027\"><ele>72.2</ele><time>2005-04-18T19:16:48Z</time></trkpt><trkpt lat=\"42.291098\" lon=\"-71.326954\"><ele>73.2</ele><time>2005-04-18T19:17:15Z</time></trkpt><trkpt lat=\"42.291806\" lon=\"-71.325753\"><ele>74.6</ele><time>2005-04-18T19:17:45Z</time></trkpt><trkpt lat=\"42.291999\" lon=\"-71.325302\"><ele>70.8</ele><time>2005-04-18T19:17:56Z</time></trkpt><trkpt lat=\"42.293243\" lon=\"-71.322856\"><ele>66</ele><time>2005-04-18T19:18:57Z</time></trkpt><trkpt lat=\"42.293351\" lon=\"-71.322556\"><ele>68.9</ele><time>2005-04-18T19:19:06Z</time></trkpt><trkpt lat=\"42.293544\" lon=\"-71.321955\"><ele>64.5</ele><time>2005-04-18T19:19:19Z</time></trkpt><trkpt lat=\"42.293758\" lon=\"-71.321332\"><ele>61.2</ele><time>2005-04-18T19:19:32Z</time></trkpt><trkpt lat=\"42.29393\" lon=\"-71.320732\"><ele>58.3</ele><time>2005-04-18T19:19:45Z</time></trkpt><trkpt lat=\"42.294166\" lon=\"-71.320131\"><ele>58.8</ele><time>2005-04-18T19:19:58Z</time></trkpt><trkpt lat=\"42.294402\" lon=\"-71.319337\"><ele>54.9</ele><time>2005-04-18T19:20:14Z</time></trkpt><trkpt lat=\"42.294531\" lon=\"-71.3188\"><ele>52</ele><time>2005-04-18T19:20:25Z</time></trkpt><trkpt lat=\"42.294617\" lon=\"-71.318285\"><ele>49.6</ele><time>2005-04-18T19:20:35Z</time></trkpt><trkpt lat=\"42.294681\" lon=\"-71.318092\"><ele>49.2</ele><time>2005-04-18T19:20:39Z</time></trkpt><trkpt lat=\"42.29481\" lon=\"-71.317663\"><ele>48.7</ele><time>2005-04-18T19:20:48Z</time></trkpt><trkpt lat=\"42.29511\" lon=\"-71.316869\"><ele>50.6</ele><time>2005-04-18T19:21:05Z</time></trkpt><trkpt lat=\"42.295282\" lon=\"-71.316354\"><ele>51.1</ele><time>2005-04-18T19:21:17Z</time></trkpt><trkpt lat=\"42.295432\" lon=\"-71.315861\"><ele>52</ele><time>2005-04-18T19:21:28Z</time></trkpt><trkpt lat=\"42.295561\" lon=\"-71.31526\"><ele>53</ele><time>2005-04-18T19:21:41Z</time></trkpt><trkpt lat=\"42.29569\" lon=\"-71.314702\"><ele>54.9</ele><time>2005-04-18T19:21:53Z</time></trkpt><trkpt lat=\"42.295754\" lon=\"-71.314187\"><ele>56.4</ele><time>2005-04-18T19:22:05Z</time></trkpt><trkpt lat=\"42.295818\" lon=\"-71.313715\"><ele>55.9</ele><time>2005-04-18T19:22:16Z</time></trkpt><trkpt lat=\"42.295969\" lon=\"-71.312857\"><ele>56.9</ele><time>2005-04-18T19:22:35Z</time></trkpt><trkpt lat=\"42.296054\" lon=\"-71.312256\"><ele>57.8</ele><time>2005-04-18T19:22:47Z</time></trkpt><trkpt lat=\"42.296226\" lon=\"-71.311097\"><ele>58.3</ele><time>2005-04-18T19:23:11Z</time></trkpt><trkpt lat=\"42.296419\" lon=\"-71.309016\"><ele>56.9</ele><time>2005-04-18T19:23:51Z</time></trkpt><trkpt lat=\"42.296398\" lon=\"-71.308458\"><ele>56.9</ele><time>2005-04-18T19:24:01Z</time></trkpt><trkpt lat=\"42.296333\" lon=\"-71.308329\"><ele>57.3</ele><time>2005-04-18T19:24:05Z</time></trkpt><trkpt lat=\"42.296119\" lon=\"-71.307385\"><ele>57.3</ele><time>2005-04-18T19:24:24Z</time></trkpt><trkpt lat=\"42.296226\" lon=\"-71.306248\"><ele>58.3</ele><time>2005-04-18T19:24:45Z</time></trkpt><trkpt lat=\"42.296247\" lon=\"-71.305196\"><ele>58.3</ele><time>2005-04-18T19:25:06Z</time></trkpt><trkpt lat=\"42.296205\" lon=\"-71.30408\"><ele>58.3</ele><time>2005-04-18T19:25:29Z</time></trkpt><trkpt lat=\"42.296119\" lon=\"-71.303394\"><ele>58.3</ele><time>2005-04-18T19:25:44Z</time></trkpt><trkpt lat=\"42.296076\" lon=\"-71.302707\"><ele>58.3</ele><time>2005-04-18T19:25:58Z</time></trkpt><trkpt lat=\"42.296076\" lon=\"-71.301913\"><ele>54.9</ele><time>2005-04-18T19:26:14Z</time></trkpt><trkpt lat=\"42.296011\" lon=\"-71.301012\"><ele>51.1</ele><time>2005-04-18T19:26:33Z</time></trkpt><trkpt lat=\"42.296011\" lon=\"-71.300132\"><ele>53.5</ele><time>2005-04-18T19:26:51Z</time></trkpt><trkpt lat=\"42.295904\" lon=\"-71.299553\"><ele>54</ele><time>2005-04-18T19:27:04Z</time></trkpt><trkpt lat=\"42.295904\" lon=\"-71.298931\"><ele>54</ele><time>2005-04-18T19:27:17Z</time></trkpt><trkpt lat=\"42.295904\" lon=\"-71.298866\"><ele>54</ele><time>2005-04-18T19:27:18Z</time></trkpt><trkpt lat=\"42.295926\" lon=\"-71.298308\"><ele>54</ele><time>2005-04-18T19:27:29Z</time></trkpt><trkpt lat=\"42.295969\" lon=\"-71.297665\"><ele>52</ele><time>2005-04-18T19:27:42Z</time></trkpt><trkpt lat=\"42.296033\" lon=\"-71.296978\"><ele>50.6</ele><time>2005-04-18T19:27:56Z</time></trkpt><trkpt lat=\"42.296097\" lon=\"-71.29627\"><ele>50.6</ele><time>2005-04-18T19:28:10Z</time></trkpt><trkpt lat=\"42.296205\" lon=\"-71.295669\"><ele>51.6</ele><time>2005-04-18T19:28:22Z</time></trkpt><trkpt lat=\"42.296312\" lon=\"-71.294918\"><ele>51.1</ele><time>2005-04-18T19:28:37Z</time></trkpt><trkpt lat=\"42.296398\" lon=\"-71.294339\"><ele>52</ele><time>2005-04-18T19:28:49Z</time></trkpt><trkpt lat=\"42.296526\" lon=\"-71.293738\"><ele>50.6</ele><time>2005-04-18T19:29:02Z</time></trkpt><trkpt lat=\"42.296634\" lon=\"-71.293137\"><ele>49.6</ele><time>2005-04-18T19:29:14Z</time></trkpt><trkpt lat=\"42.296741\" lon=\"-71.292515\"><ele>48.2</ele><time>2005-04-18T19:29:27Z</time></trkpt><trkpt lat=\"42.296891\" lon=\"-71.291957\"><ele>46.3</ele><time>2005-04-18T19:29:39Z</time></trkpt><trkpt lat=\"42.29702\" lon=\"-71.291614\"><ele>46.3</ele><time>2005-04-18T19:29:47Z</time></trkpt><trkpt lat=\"42.297235\" lon=\"-71.29112\"><ele>47.2</ele><time>2005-04-18T19:29:59Z</time></trkpt><trkpt lat=\"42.297556\" lon=\"-71.290455\"><ele>49.2</ele><time>2005-04-18T19:30:14Z</time></trkpt><trkpt lat=\"42.297943\" lon=\"-71.289532\"><ele>49.6</ele><time>2005-04-18T19:30:35Z</time></trkpt><trkpt lat=\"42.298779\" lon=\"-71.28818\"><ele>49.6</ele><time>2005-04-18T19:31:12Z</time></trkpt><trkpt lat=\"42.299531\" lon=\"-71.287279\"><ele>49.6</ele><time>2005-04-18T19:31:43Z</time></trkpt><trkpt lat=\"42.301033\" lon=\"-71.287236\"><ele>49.6</ele><time>2005-04-18T19:32:16Z</time></trkpt><trkpt lat=\"42.301548\" lon=\"-71.286871\"><ele>49.6</ele><time>2005-04-18T19:32:32Z</time></trkpt><trkpt lat=\"42.302148\" lon=\"-71.286399\"><ele>49.6</ele><time>2005-04-18T19:32:51Z</time></trkpt><trkpt lat=\"42.302685\" lon=\"-71.285949\"><ele>49.6</ele><time>2005-04-18T19:33:08Z</time></trkpt><trkpt lat=\"42.303371\" lon=\"-71.285348\"><ele>49.6</ele><time>2005-04-18T19:33:30Z</time></trkpt><trkpt lat=\"42.30423\" lon=\"-71.284575\"><ele>49.6</ele><time>2005-04-18T19:33:58Z</time></trkpt><trkpt lat=\"42.304788\" lon=\"-71.284039\"><ele>50.6</ele><time>2005-04-18T19:34:17Z</time></trkpt><trkpt lat=\"42.305388\" lon=\"-71.283245\"><ele>49.2</ele><time>2005-04-18T19:34:41Z</time></trkpt><trkpt lat=\"42.306397\" lon=\"-71.281829\"><ele>48.7</ele><time>2005-04-18T19:35:22Z</time></trkpt><trkpt lat=\"42.307405\" lon=\"-71.280284\"><ele>50.1</ele><time>2005-04-18T19:36:06Z</time></trkpt><trkpt lat=\"42.307727\" lon=\"-71.279705\"><ele>51.1</ele><time>2005-04-18T19:36:21Z</time></trkpt><trkpt lat=\"42.308285\" lon=\"-71.278803\"><ele>53.5</ele><time>2005-04-18T19:36:46Z</time></trkpt><trkpt lat=\"42.308714\" lon=\"-71.278203\"><ele>54</ele><time>2005-04-18T19:37:03Z</time></trkpt><trkpt lat=\"42.309573\" lon=\"-71.277215\"><ele>54.9</ele><time>2005-04-18T19:37:34Z</time></trkpt><trkpt lat=\"42.310216\" lon=\"-71.276507\"><ele>54.9</ele><time>2005-04-18T19:37:58Z</time></trkpt><trkpt lat=\"42.310967\" lon=\"-71.275799\"><ele>54.9</ele><time>2005-04-18T19:38:23Z</time></trkpt><trkpt lat=\"42.311954\" lon=\"-71.274877\"><ele>54.9</ele><time>2005-04-18T19:38:56Z</time></trkpt><trkpt lat=\"42.312491\" lon=\"-71.274319\"><ele>55.4</ele><time>2005-04-18T19:39:16Z</time></trkpt><trkpt lat=\"42.312984\" lon=\"-71.273847\"><ele>55.9</ele><time>2005-04-18T19:39:34Z</time></trkpt><trkpt lat=\"42.313521\" lon=\"-71.27331\"><ele>56.4</ele><time>2005-04-18T19:39:54Z</time></trkpt><trkpt lat=\"42.314165\" lon=\"-71.272452\"><ele>55.4</ele><time>2005-04-18T19:40:20Z</time></trkpt><trkpt lat=\"42.314444\" lon=\"-71.271915\"><ele>56.9</ele><time>2005-04-18T19:40:34Z</time></trkpt><trkpt lat=\"42.314894\" lon=\"-71.271272\"><ele>57.8</ele><time>2005-04-18T19:40:52Z</time></trkpt><trkpt lat=\"42.315559\" lon=\"-71.270392\"><ele>55.9</ele><time>2005-04-18T19:41:18Z</time></trkpt><trkpt lat=\"42.315967\" lon=\"-71.269727\"><ele>56.9</ele><time>2005-04-18T19:41:36Z</time></trkpt><trkpt lat=\"42.316611\" lon=\"-71.26874\"><ele>58.3</ele><time>2005-04-18T19:42:03Z</time></trkpt><trkpt lat=\"42.317362\" lon=\"-71.267753\"><ele>57.8</ele><time>2005-04-18T19:42:32Z</time></trkpt><trkpt lat=\"42.317727\" lon=\"-71.267238\"><ele>57.3</ele><time>2005-04-18T19:42:47Z</time></trkpt><trkpt lat=\"42.318327\" lon=\"-71.266358\"><ele>57.3</ele><time>2005-04-18T19:43:13Z</time></trkpt><trkpt lat=\"42.319357\" lon=\"-71.264899\"><ele>55.4</ele><time>2005-04-18T19:43:57Z</time></trkpt><trkpt lat=\"42.320302\" lon=\"-71.263869\"><ele>55.4</ele><time>2005-04-18T19:44:31Z</time></trkpt><trkpt lat=\"42.32116\" lon=\"-71.263182\"><ele>55.4</ele><time>2005-04-18T19:44:58Z</time></trkpt><trkpt lat=\"42.322876\" lon=\"-71.262753\"><ele>55.4</ele><time>2005-04-18T19:45:37Z</time></trkpt><trkpt lat=\"42.32352\" lon=\"-71.262388\"><ele>52.5</ele><time>2005-04-18T19:45:57Z</time></trkpt><trkpt lat=\"42.324121\" lon=\"-71.261938\"><ele>46.8</ele><time>2005-04-18T19:46:16Z</time></trkpt><trkpt lat=\"42.324915\" lon=\"-71.261101\"><ele>42</ele><time>2005-04-18T19:46:45Z</time></trkpt><trkpt lat=\"42.325215\" lon=\"-71.260543\"><ele>35.7</ele><time>2005-04-18T19:46:59Z</time></trkpt><trkpt lat=\"42.325344\" lon=\"-71.259942\"><ele>29.9</ele><time>2005-04-18T19:47:11Z</time></trkpt><trkpt lat=\"42.325408\" lon=\"-71.259105\"><ele>25.1</ele><time>2005-04-18T19:47:27Z</time></trkpt><trkpt lat=\"42.325408\" lon=\"-71.258998\"><ele>25.1</ele><time>2005-04-18T19:47:29Z</time></trkpt><trkpt lat=\"42.325387\" lon=\"-71.258376\"><ele>25.1</ele><time>2005-04-18T19:47:42Z</time></trkpt><trkpt lat=\"42.32543\" lon=\"-71.257753\"><ele>23.2</ele><time>2005-04-18T19:47:55Z</time></trkpt><trkpt lat=\"42.325516\" lon=\"-71.25711\"><ele>23.2</ele><time>2005-04-18T19:48:09Z</time></trkpt><trkpt lat=\"42.325623\" lon=\"-71.256766\"><ele>23.2</ele><time>2005-04-18T19:48:17Z</time></trkpt><trkpt lat=\"42.325838\" lon=\"-71.256208\"><ele>23.7</ele><time>2005-04-18T19:48:31Z</time></trkpt><trkpt lat=\"42.326031\" lon=\"-71.255629\"><ele>25.1</ele><time>2005-04-18T19:48:45Z</time></trkpt><trkpt lat=\"42.326224\" lon=\"-71.255157\"><ele>28</ele><time>2005-04-18T19:48:57Z</time></trkpt><trkpt lat=\"42.326245\" lon=\"-71.255114\"><ele>28</ele><time>2005-04-18T19:48:58Z</time></trkpt><trkpt lat=\"42.326245\" lon=\"-71.255007\"><ele>28.5</ele><time>2005-04-18T19:49:01Z</time></trkpt><trkpt lat=\"42.326267\" lon=\"-71.254964\"><ele>28.5</ele><time>2005-04-18T19:49:02Z</time></trkpt><trkpt lat=\"42.326374\" lon=\"-71.254663\"><ele>29</ele><time>2005-04-18T19:49:10Z</time></trkpt><trkpt lat=\"42.326546\" lon=\"-71.254342\"><ele>28</ele><time>2005-04-18T19:49:20Z</time></trkpt><trkpt lat=\"42.327039\" lon=\"-71.253655\"><ele>30.4</ele><time>2005-04-18T19:49:41Z</time></trkpt><trkpt lat=\"42.327404\" lon=\"-71.253119\"><ele>31.9</ele><time>2005-04-18T19:49:57Z</time></trkpt><trkpt lat=\"42.327919\" lon=\"-71.252367\"><ele>32.8</ele><time>2005-04-18T19:50:19Z</time></trkpt><trkpt lat=\"42.32837\" lon=\"-71.251745\"><ele>34.3</ele><time>2005-04-18T19:50:39Z</time></trkpt><trkpt lat=\"42.328842\" lon=\"-71.251101\"><ele>36.2</ele><time>2005-04-18T19:51:00Z</time></trkpt><trkpt lat=\"42.3294\" lon=\"-71.250286\"><ele>39.6</ele><time>2005-04-18T19:51:25Z</time></trkpt><trkpt lat=\"42.329807\" lon=\"-71.249492\"><ele>41.5</ele><time>2005-04-18T19:51:48Z</time></trkpt><trkpt lat=\"42.330022\" lon=\"-71.248677\"><ele>43.9</ele><time>2005-04-18T19:52:07Z</time></trkpt><trkpt lat=\"42.330344\" lon=\"-71.248119\"><ele>42.4</ele><time>2005-04-18T19:52:23Z</time></trkpt><trkpt lat=\"42.331138\" lon=\"-71.247175\"><ele>43.4</ele><time>2005-04-18T19:52:55Z</time></trkpt><trkpt lat=\"42.33191\" lon=\"-71.246488\"><ele>43.4</ele><time>2005-04-18T19:53:22Z</time></trkpt><trkpt lat=\"42.332618\" lon=\"-71.246016\"><ele>43.9</ele><time>2005-04-18T19:53:41Z</time></trkpt><trkpt lat=\"42.333047\" lon=\"-71.245651\"><ele>44.8</ele><time>2005-04-18T19:53:54Z</time></trkpt><trkpt lat=\"42.333584\" lon=\"-71.245093\"><ele>44.8</ele><time>2005-04-18T19:54:12Z</time></trkpt><trkpt lat=\"42.33397\" lon=\"-71.2446\"><ele>46.3</ele><time>2005-04-18T19:54:27Z</time></trkpt><trkpt lat=\"42.334206\" lon=\"-71.244299\"><ele>46.8</ele><time>2005-04-18T19:54:36Z</time></trkpt><trkpt lat=\"42.334378\" lon=\"-71.244063\"><ele>45.3</ele><time>2005-04-18T19:54:43Z</time></trkpt><trkpt lat=\"42.334721\" lon=\"-71.243613\"><ele>43.4</ele><time>2005-04-18T19:54:56Z</time></trkpt><trkpt lat=\"42.334957\" lon=\"-71.243291\"><ele>42.9</ele><time>2005-04-18T19:55:06Z</time></trkpt><trkpt lat=\"42.335279\" lon=\"-71.242862\"><ele>42</ele><time>2005-04-18T19:55:18Z</time></trkpt><trkpt lat=\"42.335751\" lon=\"-71.242282\"><ele>41.5</ele><time>2005-04-18T19:55:36Z</time></trkpt><trkpt lat=\"42.336202\" lon=\"-71.241853\"><ele>42</ele><time>2005-04-18T19:55:52Z</time></trkpt><trkpt lat=\"42.336717\" lon=\"-71.241488\"><ele>42</ele><time>2005-04-18T19:56:09Z</time></trkpt><trkpt lat=\"42.338047\" lon=\"-71.240587\"><ele>42</ele><time>2005-04-18T19:56:53Z</time></trkpt><trkpt lat=\"42.33897\" lon=\"-71.240029\"><ele>42.4</ele><time>2005-04-18T19:57:23Z</time></trkpt><trkpt lat=\"42.339764\" lon=\"-71.239579\"><ele>41.5</ele><time>2005-04-18T19:57:50Z</time></trkpt><trkpt lat=\"42.340386\" lon=\"-71.239278\"><ele>41.5</ele><time>2005-04-18T19:58:07Z</time></trkpt><trkpt lat=\"42.340944\" lon=\"-71.238828\"><ele>40.5</ele><time>2005-04-18T19:58:25Z</time></trkpt><trkpt lat=\"42.34103\" lon=\"-71.238656\"><ele>38.6</ele><time>2005-04-18T19:58:29Z</time></trkpt><trkpt lat=\"42.340944\" lon=\"-71.23842\"><ele>36.7</ele><time>2005-04-18T19:58:34Z</time></trkpt><trkpt lat=\"42.340729\" lon=\"-71.238077\"><ele>35.2</ele><time>2005-04-18T19:58:42Z</time></trkpt><trkpt lat=\"42.340343\" lon=\"-71.237476\"><ele>34.7</ele><time>2005-04-18T19:58:58Z</time></trkpt><trkpt lat=\"42.34\" lon=\"-71.236982\"><ele>31.4</ele><time>2005-04-18T19:59:12Z</time></trkpt><trkpt lat=\"42.339742\" lon=\"-71.236382\"><ele>35.2</ele><time>2005-04-18T19:59:27Z</time></trkpt><trkpt lat=\"42.339506\" lon=\"-71.235759\"><ele>37.1</ele><time>2005-04-18T19:59:43Z</time></trkpt><trkpt lat=\"42.339313\" lon=\"-71.234965\"><ele>36.7</ele><time>2005-04-18T20:00:02Z</time></trkpt><trkpt lat=\"42.339249\" lon=\"-71.234515\"><ele>38.6</ele><time>2005-04-18T20:00:14Z</time></trkpt><trkpt lat=\"42.339206\" lon=\"-71.233957\"><ele>39.1</ele><time>2005-04-18T20:00:27Z</time></trkpt><trkpt lat=\"42.339227\" lon=\"-71.233399\"><ele>42.9</ele><time>2005-04-18T20:00:41Z</time></trkpt><trkpt lat=\"42.33927\" lon=\"-71.232862\"><ele>45.3</ele><time>2005-04-18T20:00:54Z</time></trkpt><trkpt lat=\"42.339292\" lon=\"-71.232262\"><ele>47.2</ele><time>2005-04-18T20:01:09Z</time></trkpt><trkpt lat=\"42.339356\" lon=\"-71.231661\"><ele>49.6</ele><time>2005-04-18T20:01:23Z</time></trkpt><trkpt lat=\"42.339356\" lon=\"-71.230974\"><ele>51.6</ele><time>2005-04-18T20:01:38Z</time></trkpt><trkpt lat=\"42.339356\" lon=\"-71.230803\"><ele>51.1</ele><time>2005-04-18T20:01:42Z</time></trkpt><trkpt lat=\"42.339313\" lon=\"-71.230309\"><ele>51.6</ele><time>2005-04-18T20:01:52Z</time></trkpt><trkpt lat=\"42.33927\" lon=\"-71.229644\"><ele>51.6</ele><time>2005-04-18T20:02:05Z</time></trkpt><trkpt lat=\"42.339184\" lon=\"-71.229043\"><ele>49.6</ele><time>2005-04-18T20:02:17Z</time></trkpt><trkpt lat=\"42.339034\" lon=\"-71.228228\"><ele>46.3</ele><time>2005-04-18T20:02:33Z</time></trkpt><trkpt lat=\"42.338841\" lon=\"-71.227584\"><ele>44.8</ele><time>2005-04-18T20:02:48Z</time></trkpt><trkpt lat=\"42.338605\" lon=\"-71.226962\"><ele>47.7</ele><time>2005-04-18T20:03:04Z</time></trkpt><trkpt lat=\"42.338262\" lon=\"-71.226296\"><ele>48.7</ele><time>2005-04-18T20:03:22Z</time></trkpt><trkpt lat=\"42.33794\" lon=\"-71.225846\"><ele>47.7</ele><time>2005-04-18T20:03:36Z</time></trkpt><trkpt lat=\"42.337596\" lon=\"-71.225352\"><ele>48.2</ele><time>2005-04-18T20:03:51Z</time></trkpt><trkpt lat=\"42.337232\" lon=\"-71.224859\"><ele>48.2</ele><time>2005-04-18T20:04:05Z</time></trkpt><trkpt lat=\"42.336953\" lon=\"-71.224301\"><ele>43.4</ele><time>2005-04-18T20:04:19Z</time></trkpt><trkpt lat=\"42.336717\" lon=\"-71.223593\"><ele>44.8</ele><time>2005-04-18T20:04:35Z</time></trkpt><trkpt lat=\"42.336695\" lon=\"-71.223443\"><ele>44.4</ele><time>2005-04-18T20:04:38Z</time></trkpt><trkpt lat=\"42.336695\" lon=\"-71.223292\"><ele>45.3</ele><time>2005-04-18T20:04:41Z</time></trkpt><trkpt lat=\"42.336674\" lon=\"-71.223121\"><ele>45.3</ele><time>2005-04-18T20:04:44Z</time></trkpt><trkpt lat=\"42.336695\" lon=\"-71.222863\"><ele>45.3</ele><time>2005-04-18T20:04:49Z</time></trkpt><trkpt lat=\"42.336738\" lon=\"-71.222219\"><ele>44.8</ele><time>2005-04-18T20:05:02Z</time></trkpt><trkpt lat=\"42.336802\" lon=\"-71.221383\"><ele>43.9</ele><time>2005-04-18T20:05:20Z</time></trkpt><trkpt lat=\"42.336845\" lon=\"-71.220889\"><ele>43.9</ele><time>2005-04-18T20:05:31Z</time></trkpt><trkpt lat=\"42.337039\" lon=\"-71.220331\"><ele>44.8</ele><time>2005-04-18T20:05:45Z</time></trkpt><trkpt lat=\"42.337296\" lon=\"-71.219859\"><ele>48.2</ele><time>2005-04-18T20:05:57Z</time></trkpt><trkpt lat=\"42.337575\" lon=\"-71.219215\"><ele>47.7</ele><time>2005-04-18T20:06:14Z</time></trkpt><trkpt lat=\"42.337575\" lon=\"-71.218636\"><ele>46.8</ele><time>2005-04-18T20:06:26Z</time></trkpt><trkpt lat=\"42.337468\" lon=\"-71.217992\"><ele>44.4</ele><time>2005-04-18T20:06:40Z</time></trkpt><trkpt lat=\"42.337253\" lon=\"-71.217477\"><ele>42.9</ele><time>2005-04-18T20:06:52Z</time></trkpt><trkpt lat=\"42.337039\" lon=\"-71.216877\"><ele>41</ele><time>2005-04-18T20:07:06Z</time></trkpt><trkpt lat=\"42.336888\" lon=\"-71.216233\"><ele>41</ele><time>2005-04-18T20:07:20Z</time></trkpt><trkpt lat=\"42.336888\" lon=\"-71.215739\"><ele>41</ele><time>2005-04-18T20:07:30Z</time></trkpt><trkpt lat=\"42.337017\" lon=\"-71.215096\"><ele>39.1</ele><time>2005-04-18T20:07:44Z</time></trkpt><trkpt lat=\"42.337253\" lon=\"-71.214559\"><ele>42</ele><time>2005-04-18T20:07:56Z</time></trkpt><trkpt lat=\"42.337554\" lon=\"-71.214023\"><ele>41.5</ele><time>2005-04-18T20:08:10Z</time></trkpt><trkpt lat=\"42.337897\" lon=\"-71.213336\"><ele>41</ele><time>2005-04-18T20:08:27Z</time></trkpt><trkpt lat=\"42.337983\" lon=\"-71.2131\"><ele>40.5</ele><time>2005-04-18T20:08:32Z</time></trkpt><trkpt lat=\"42.338047\" lon=\"-71.212842\"><ele>39.1</ele><time>2005-04-18T20:08:38Z</time></trkpt><trkpt lat=\"42.338133\" lon=\"-71.212285\"><ele>37.1</ele><time>2005-04-18T20:08:49Z</time></trkpt><trkpt lat=\"42.338176\" lon=\"-71.211534\"><ele>34.7</ele><time>2005-04-18T20:09:03Z</time></trkpt><trkpt lat=\"42.338111\" lon=\"-71.210847\"><ele>33.3</ele><time>2005-04-18T20:09:16Z</time></trkpt><trkpt lat=\"42.338026\" lon=\"-71.210139\"><ele>34.3</ele><time>2005-04-18T20:09:30Z</time></trkpt><trkpt lat=\"42.337983\" lon=\"-71.209495\"><ele>31.9</ele><time>2005-04-18T20:09:43Z</time></trkpt><trkpt lat=\"42.338047\" lon=\"-71.208851\"><ele>30.9</ele><time>2005-04-18T20:09:56Z</time></trkpt><trkpt lat=\"42.338197\" lon=\"-71.208315\"><ele>31.4</ele><time>2005-04-18T20:10:08Z</time></trkpt><trkpt lat=\"42.338455\" lon=\"-71.207693\"><ele>30.4</ele><time>2005-04-18T20:10:22Z</time></trkpt><trkpt lat=\"42.338626\" lon=\"-71.207199\"><ele>29.5</ele><time>2005-04-18T20:10:33Z</time></trkpt><trkpt lat=\"42.338734\" lon=\"-71.206641\"><ele>31.4</ele><time>2005-04-18T20:10:45Z</time></trkpt><trkpt lat=\"42.338777\" lon=\"-71.20604\"><ele>33.8</ele><time>2005-04-18T20:10:58Z</time></trkpt><trkpt lat=\"42.338734\" lon=\"-71.20544\"><ele>33.8</ele><time>2005-04-18T20:11:12Z</time></trkpt><trkpt lat=\"42.338626\" lon=\"-71.20486\"><ele>34.3</ele><time>2005-04-18T20:11:26Z</time></trkpt><trkpt lat=\"42.338476\" lon=\"-71.204302\"><ele>34.3</ele><time>2005-04-18T20:11:40Z</time></trkpt><trkpt lat=\"42.338283\" lon=\"-71.203766\"><ele>35.2</ele><time>2005-04-18T20:11:54Z</time></trkpt><trkpt lat=\"42.33809\" lon=\"-71.203272\"><ele>40.5</ele><time>2005-04-18T20:12:07Z</time></trkpt><trkpt lat=\"42.33794\" lon=\"-71.202693\"><ele>42.9</ele><time>2005-04-18T20:12:21Z</time></trkpt><trkpt lat=\"42.337854\" lon=\"-71.202049\"><ele>44.8</ele><time>2005-04-18T20:12:36Z</time></trkpt><trkpt lat=\"42.337832\" lon=\"-71.201427\"><ele>46.3</ele><time>2005-04-18T20:12:50Z</time></trkpt><trkpt lat=\"42.337854\" lon=\"-71.200762\"><ele>44.8</ele><time>2005-04-18T20:13:05Z</time></trkpt><trkpt lat=\"42.337918\" lon=\"-71.200075\"><ele>45.3</ele><time>2005-04-18T20:13:20Z</time></trkpt><trkpt lat=\"42.337983\" lon=\"-71.199389\"><ele>46.3</ele><time>2005-04-18T20:13:35Z</time></trkpt><trkpt lat=\"42.337961\" lon=\"-71.198852\"><ele>49.6</ele><time>2005-04-18T20:13:47Z</time></trkpt><trkpt lat=\"42.337897\" lon=\"-71.198251\"><ele>52.5</ele><time>2005-04-18T20:14:00Z</time></trkpt><trkpt lat=\"42.337725\" lon=\"-71.197715\"><ele>53</ele><time>2005-04-18T20:14:13Z</time></trkpt><trkpt lat=\"42.337575\" lon=\"-71.197436\"><ele>52</ele><time>2005-04-18T20:14:20Z</time></trkpt><trkpt lat=\"42.337253\" lon=\"-71.196921\"><ele>52.5</ele><time>2005-04-18T20:14:33Z</time></trkpt><trkpt lat=\"42.336824\" lon=\"-71.196363\"><ele>50.6</ele><time>2005-04-18T20:14:49Z</time></trkpt><trkpt lat=\"42.336438\" lon=\"-71.196041\"><ele>50.6</ele><time>2005-04-18T20:15:02Z</time></trkpt><trkpt lat=\"42.336094\" lon=\"-71.195655\"><ele>51.1</ele><time>2005-04-18T20:15:15Z</time></trkpt><trkpt lat=\"42.335815\" lon=\"-71.195226\"><ele>52</ele><time>2005-04-18T20:15:27Z</time></trkpt><trkpt lat=\"42.335815\" lon=\"-71.195183\"><ele>52</ele><time>2005-04-18T20:15:28Z</time></trkpt><trkpt lat=\"42.335708\" lon=\"-71.194689\"><ele>51.1</ele><time>2005-04-18T20:15:38Z</time></trkpt><trkpt lat=\"42.335751\" lon=\"-71.194067\"><ele>50.6</ele><time>2005-04-18T20:15:51Z</time></trkpt><trkpt lat=\"42.335944\" lon=\"-71.193552\"><ele>51.6</ele><time>2005-04-18T20:16:03Z</time></trkpt><trkpt lat=\"42.336116\" lon=\"-71.192908\"><ele>50.6</ele><time>2005-04-18T20:16:18Z</time></trkpt><trkpt lat=\"42.336245\" lon=\"-71.192329\"><ele>50.6</ele><time>2005-04-18T20:16:31Z</time></trkpt><trkpt lat=\"42.336309\" lon=\"-71.191728\"><ele>51.6</ele><time>2005-04-18T20:16:44Z</time></trkpt><trkpt lat=\"42.336309\" lon=\"-71.191192\"><ele>52</ele><time>2005-04-18T20:16:56Z</time></trkpt><trkpt lat=\"42.336287\" lon=\"-71.190548\"><ele>50.1</ele><time>2005-04-18T20:17:10Z</time></trkpt><trkpt lat=\"42.336287\" lon=\"-71.189818\"><ele>52</ele><time>2005-04-18T20:17:25Z</time></trkpt><trkpt lat=\"42.336287\" lon=\"-71.18926\"><ele>48.2</ele><time>2005-04-18T20:17:38Z</time></trkpt><trkpt lat=\"42.336287\" lon=\"-71.18866\"><ele>48.2</ele><time>2005-04-18T20:17:51Z</time></trkpt><trkpt lat=\"42.336309\" lon=\"-71.188016\"><ele>48.7</ele><time>2005-04-18T20:18:05Z</time></trkpt><trkpt lat=\"42.336373\" lon=\"-71.187479\"><ele>50.1</ele><time>2005-04-18T20:18:17Z</time></trkpt><trkpt lat=\"42.336395\" lon=\"-71.186857\"><ele>51.6</ele><time>2005-04-18T20:18:31Z</time></trkpt><trkpt lat=\"42.336438\" lon=\"-71.186428\"><ele>51.1</ele><time>2005-04-18T20:18:42Z</time></trkpt><trkpt lat=\"42.336481\" lon=\"-71.185935\"><ele>51.6</ele><time>2005-04-18T20:18:54Z</time></trkpt><trkpt lat=\"42.336545\" lon=\"-71.185398\"><ele>53</ele><time>2005-04-18T20:19:06Z</time></trkpt><trkpt lat=\"42.336631\" lon=\"-71.184797\"><ele>54</ele><time>2005-04-18T20:19:20Z</time></trkpt><trkpt lat=\"42.336695\" lon=\"-71.184368\"><ele>55.4</ele><time>2005-04-18T20:19:31Z</time></trkpt><trkpt lat=\"42.336695\" lon=\"-71.18381\"><ele>59.7</ele><time>2005-04-18T20:19:46Z</time></trkpt><trkpt lat=\"42.336652\" lon=\"-71.183252\"><ele>63.6</ele><time>2005-04-18T20:20:00Z</time></trkpt><trkpt lat=\"42.336588\" lon=\"-71.182737\"><ele>64.5</ele><time>2005-04-18T20:20:13Z</time></trkpt><trkpt lat=\"42.336566\" lon=\"-71.182287\"><ele>66</ele><time>2005-04-18T20:20:25Z</time></trkpt><trkpt lat=\"42.336502\" lon=\"-71.181707\"><ele>69.4</ele><time>2005-04-18T20:20:39Z</time></trkpt><trkpt lat=\"42.336438\" lon=\"-71.181321\"><ele>70.8</ele><time>2005-04-18T20:20:49Z</time></trkpt><trkpt lat=\"42.336373\" lon=\"-71.180849\"><ele>72.2</ele><time>2005-04-18T20:21:02Z</time></trkpt><trkpt lat=\"42.336287\" lon=\"-71.180205\"><ele>73.7</ele><time>2005-04-18T20:21:18Z</time></trkpt><trkpt lat=\"42.336245\" lon=\"-71.17954\"><ele>73.2</ele><time>2005-04-18T20:21:35Z</time></trkpt><trkpt lat=\"42.33618\" lon=\"-71.179025\"><ele>75.1</ele><time>2005-04-18T20:21:47Z</time></trkpt><trkpt lat=\"42.336137\" lon=\"-71.178403\"><ele>77</ele><time>2005-04-18T20:22:01Z</time></trkpt><trkpt lat=\"42.336202\" lon=\"-71.177909\"><ele>78</ele><time>2005-04-18T20:22:12Z</time></trkpt><trkpt lat=\"42.336352\" lon=\"-71.177394\"><ele>78.5</ele><time>2005-04-18T20:22:24Z</time></trkpt><trkpt lat=\"42.336588\" lon=\"-71.176944\"><ele>78</ele><time>2005-04-18T20:22:36Z</time></trkpt><trkpt lat=\"42.336845\" lon=\"-71.176536\"><ele>78</ele><time>2005-04-18T20:22:47Z</time></trkpt><trkpt lat=\"42.337017\" lon=\"-71.176236\"><ele>77.5</ele><time>2005-04-18T20:22:55Z</time></trkpt><trkpt lat=\"42.337167\" lon=\"-71.175935\"><ele>77.5</ele><time>2005-04-18T20:23:03Z</time></trkpt><trkpt lat=\"42.337317\" lon=\"-71.175377\"><ele>78</ele><time>2005-04-18T20:23:16Z</time></trkpt><trkpt lat=\"42.337382\" lon=\"-71.174798\"><ele>77.5</ele><time>2005-04-18T20:23:29Z</time></trkpt><trkpt lat=\"42.337317\" lon=\"-71.174133\"><ele>76.6</ele><time>2005-04-18T20:23:43Z</time></trkpt><trkpt lat=\"42.337189\" lon=\"-71.173403\"><ele>75.1</ele><time>2005-04-18T20:23:59Z</time></trkpt><trkpt lat=\"42.337167\" lon=\"-71.172888\"><ele>75.1</ele><time>2005-04-18T20:24:10Z</time></trkpt><trkpt lat=\"42.33721\" lon=\"-71.172416\"><ele>75.1</ele><time>2005-04-18T20:24:20Z</time></trkpt><trkpt lat=\"42.337382\" lon=\"-71.171923\"><ele>75.1</ele><time>2005-04-18T20:24:32Z</time></trkpt><trkpt lat=\"42.337639\" lon=\"-71.171536\"><ele>75.6</ele><time>2005-04-18T20:24:43Z</time></trkpt><trkpt lat=\"42.33809\" lon=\"-71.171086\"><ele>76.6</ele><time>2005-04-18T20:24:58Z</time></trkpt><trkpt lat=\"42.338455\" lon=\"-71.170678\"><ele>75.6</ele><time>2005-04-18T20:25:10Z</time></trkpt><trkpt lat=\"42.338884\" lon=\"-71.170142\"><ele>71.8</ele><time>2005-04-18T20:25:26Z</time></trkpt><trkpt lat=\"42.339163\" lon=\"-71.169584\"><ele>66.9</ele><time>2005-04-18T20:25:39Z</time></trkpt><trkpt lat=\"42.339399\" lon=\"-71.168983\"><ele>64.1</ele><time>2005-04-18T20:25:52Z</time></trkpt><trkpt lat=\"42.339592\" lon=\"-71.168275\"><ele>60.2</ele><time>2005-04-18T20:26:07Z</time></trkpt><trkpt lat=\"42.339699\" lon=\"-71.167738\"><ele>58.3</ele><time>2005-04-18T20:26:18Z</time></trkpt><trkpt lat=\"42.339807\" lon=\"-71.167181\"><ele>56.4</ele><time>2005-04-18T20:26:29Z</time></trkpt><trkpt lat=\"42.339892\" lon=\"-71.166515\"><ele>54</ele><time>2005-04-18T20:26:42Z</time></trkpt><trkpt lat=\"42.34\" lon=\"-71.165786\"><ele>53.5</ele><time>2005-04-18T20:26:57Z</time></trkpt><trkpt lat=\"42.340064\" lon=\"-71.165099\"><ele>54</ele><time>2005-04-18T20:27:12Z</time></trkpt><trkpt lat=\"42.340107\" lon=\"-71.164455\"><ele>54.9</ele><time>2005-04-18T20:27:26Z</time></trkpt><trkpt lat=\"42.340107\" lon=\"-71.16364\"><ele>54.5</ele><time>2005-04-18T20:27:43Z</time></trkpt><trkpt lat=\"42.340086\" lon=\"-71.163146\"><ele>54</ele><time>2005-04-18T20:27:54Z</time></trkpt><trkpt lat=\"42.340107\" lon=\"-71.162632\"><ele>54</ele><time>2005-04-18T20:28:05Z</time></trkpt><trkpt lat=\"42.340064\" lon=\"-71.161902\"><ele>51.6</ele><time>2005-04-18T20:28:20Z</time></trkpt><trkpt lat=\"42.340021\" lon=\"-71.161387\"><ele>51.6</ele><time>2005-04-18T20:28:31Z</time></trkpt><trkpt lat=\"42.339978\" lon=\"-71.160722\"><ele>51.1</ele><time>2005-04-18T20:28:45Z</time></trkpt><trkpt lat=\"42.339978\" lon=\"-71.160228\"><ele>51.1</ele><time>2005-04-18T20:28:56Z</time></trkpt><trkpt lat=\"42.339935\" lon=\"-71.159692\"><ele>51.1</ele><time>2005-04-18T20:29:08Z</time></trkpt><trkpt lat=\"42.339871\" lon=\"-71.158855\"><ele>52.5</ele><time>2005-04-18T20:29:27Z</time></trkpt><trkpt lat=\"42.339721\" lon=\"-71.158168\"><ele>53</ele><time>2005-04-18T20:29:43Z</time></trkpt><trkpt lat=\"42.339528\" lon=\"-71.157589\"><ele>53</ele><time>2005-04-18T20:29:56Z</time></trkpt><trkpt lat=\"42.339313\" lon=\"-71.156924\"><ele>51.6</ele><time>2005-04-18T20:30:11Z</time></trkpt><trkpt lat=\"42.339056\" lon=\"-71.156344\"><ele>52.5</ele><time>2005-04-18T20:30:25Z</time></trkpt><trkpt lat=\"42.338734\" lon=\"-71.155636\"><ele>51.6</ele><time>2005-04-18T20:30:42Z</time></trkpt><trkpt lat=\"42.338476\" lon=\"-71.155078\"><ele>52</ele><time>2005-04-18T20:30:56Z</time></trkpt><trkpt lat=\"42.33824\" lon=\"-71.154585\"><ele>50.6</ele><time>2005-04-18T20:31:08Z</time></trkpt><trkpt lat=\"42.338047\" lon=\"-71.154091\"><ele>48.7</ele><time>2005-04-18T20:31:20Z</time></trkpt><trkpt lat=\"42.337897\" lon=\"-71.153491\"><ele>49.2</ele><time>2005-04-18T20:31:33Z</time></trkpt><trkpt lat=\"42.337768\" lon=\"-71.152976\"><ele>48.7</ele><time>2005-04-18T20:31:44Z</time></trkpt><trkpt lat=\"42.337511\" lon=\"-71.152568\"><ele>47.2</ele><time>2005-04-18T20:31:55Z</time></trkpt><trkpt lat=\"42.33706\" lon=\"-71.152096\"><ele>45.3</ele><time>2005-04-18T20:32:10Z</time></trkpt><trkpt lat=\"42.336631\" lon=\"-71.151559\"><ele>43.4</ele><time>2005-04-18T20:32:25Z</time></trkpt><trkpt lat=\"42.336202\" lon=\"-71.151087\"><ele>42.9</ele><time>2005-04-18T20:32:39Z</time></trkpt><trkpt lat=\"42.335858\" lon=\"-71.150594\"><ele>40.5</ele><time>2005-04-18T20:32:53Z</time></trkpt><trkpt lat=\"42.335815\" lon=\"-71.150422\"><ele>39.6</ele><time>2005-04-18T20:32:57Z</time></trkpt><trkpt lat=\"42.335923\" lon=\"-71.149993\"><ele>38.6</ele><time>2005-04-18T20:33:06Z</time></trkpt><trkpt lat=\"42.335987\" lon=\"-71.14965\"><ele>38.1</ele><time>2005-04-18T20:33:13Z</time></trkpt><trkpt lat=\"42.336094\" lon=\"-71.14922\"><ele>39.6</ele><time>2005-04-18T20:33:22Z</time></trkpt><trkpt lat=\"42.336245\" lon=\"-71.148663\"><ele>40</ele><time>2005-04-18T20:33:34Z</time></trkpt><trkpt lat=\"42.336416\" lon=\"-71.14804\"><ele>36.7</ele><time>2005-04-18T20:33:48Z</time></trkpt><trkpt lat=\"42.336566\" lon=\"-71.147332\"><ele>37.1</ele><time>2005-04-18T20:34:04Z</time></trkpt><trkpt lat=\"42.336738\" lon=\"-71.146581\"><ele>36.7</ele><time>2005-04-18T20:34:20Z</time></trkpt><trkpt lat=\"42.33691\" lon=\"-71.145787\"><ele>35.2</ele><time>2005-04-18T20:34:38Z</time></trkpt><trkpt lat=\"42.336996\" lon=\"-71.145272\"><ele>35.7</ele><time>2005-04-18T20:34:50Z</time></trkpt><trkpt lat=\"42.337103\" lon=\"-71.144757\"><ele>35.7</ele><time>2005-04-18T20:35:02Z</time></trkpt><trkpt lat=\"42.337253\" lon=\"-71.144221\"><ele>33.8</ele><time>2005-04-18T20:35:15Z</time></trkpt><trkpt lat=\"42.337382\" lon=\"-71.143513\"><ele>35.7</ele><time>2005-04-18T20:35:32Z</time></trkpt><trkpt lat=\"42.337554\" lon=\"-71.142654\"><ele>36.7</ele><time>2005-04-18T20:35:52Z</time></trkpt><trkpt lat=\"42.337682\" lon=\"-71.141989\"><ele>34.3</ele><time>2005-04-18T20:36:08Z</time></trkpt><trkpt lat=\"42.33779\" lon=\"-71.141431\"><ele>34.3</ele><time>2005-04-18T20:36:21Z</time></trkpt><trkpt lat=\"42.337897\" lon=\"-71.140873\"><ele>36.7</ele><time>2005-04-18T20:36:35Z</time></trkpt><trkpt lat=\"42.337897\" lon=\"-71.140831\"><ele>36.7</ele><time>2005-04-18T20:36:36Z</time></trkpt><trkpt lat=\"42.338004\" lon=\"-71.140294\"><ele>37.6</ele><time>2005-04-18T20:36:49Z</time></trkpt><trkpt lat=\"42.338133\" lon=\"-71.139693\"><ele>39.6</ele><time>2005-04-18T20:37:05Z</time></trkpt><trkpt lat=\"42.338262\" lon=\"-71.139221\"><ele>40</ele><time>2005-04-18T20:37:17Z</time></trkpt><trkpt lat=\"42.338498\" lon=\"-71.13847\"><ele>38.6</ele><time>2005-04-18T20:37:35Z</time></trkpt><trkpt lat=\"42.338605\" lon=\"-71.137912\"><ele>38.6</ele><time>2005-04-18T20:37:48Z</time></trkpt><trkpt lat=\"42.338734\" lon=\"-71.137419\"><ele>40</ele><time>2005-04-18T20:38:00Z</time></trkpt><trkpt lat=\"42.338841\" lon=\"-71.136947\"><ele>41.5</ele><time>2005-04-18T20:38:11Z</time></trkpt><trkpt lat=\"42.338927\" lon=\"-71.136496\"><ele>40</ele><time>2005-04-18T20:38:21Z</time></trkpt><trkpt lat=\"42.339034\" lon=\"-71.136003\"><ele>37.6</ele><time>2005-04-18T20:38:32Z</time></trkpt><trkpt lat=\"42.339184\" lon=\"-71.135359\"><ele>35.7</ele><time>2005-04-18T20:38:46Z</time></trkpt><trkpt lat=\"42.339334\" lon=\"-71.134758\"><ele>36.2</ele><time>2005-04-18T20:38:59Z</time></trkpt><trkpt lat=\"42.33942\" lon=\"-71.134157\"><ele>33.3</ele><time>2005-04-18T20:39:12Z</time></trkpt><trkpt lat=\"42.339528\" lon=\"-71.133106\"><ele>32.3</ele><time>2005-04-18T20:39:36Z</time></trkpt><trkpt lat=\"42.339528\" lon=\"-71.132526\"><ele>31.9</ele><time>2005-04-18T20:39:50Z</time></trkpt><trkpt lat=\"42.339485\" lon=\"-71.131968\"><ele>34.3</ele><time>2005-04-18T20:40:04Z</time></trkpt><trkpt lat=\"42.339506\" lon=\"-71.131411\"><ele>36.7</ele><time>2005-04-18T20:40:17Z</time></trkpt><trkpt lat=\"42.339549\" lon=\"-71.130745\"><ele>35.2</ele><time>2005-04-18T20:40:33Z</time></trkpt><trkpt lat=\"42.339635\" lon=\"-71.130166\"><ele>32.8</ele><time>2005-04-18T20:40:46Z</time></trkpt><trkpt lat=\"42.339764\" lon=\"-71.129265\"><ele>28.5</ele><time>2005-04-18T20:41:05Z</time></trkpt><trkpt lat=\"42.339892\" lon=\"-71.128621\"><ele>29</ele><time>2005-04-18T20:41:19Z</time></trkpt><trkpt lat=\"42.340086\" lon=\"-71.127999\"><ele>28.5</ele><time>2005-04-18T20:41:33Z</time></trkpt><trkpt lat=\"42.340322\" lon=\"-71.127377\"><ele>29.9</ele><time>2005-04-18T20:41:48Z</time></trkpt><trkpt lat=\"42.340558\" lon=\"-71.126754\"><ele>29.5</ele><time>2005-04-18T20:42:03Z</time></trkpt><trkpt lat=\"42.340815\" lon=\"-71.126132\"><ele>31.9</ele><time>2005-04-18T20:42:18Z</time></trkpt><trkpt lat=\"42.34103\" lon=\"-71.125467\"><ele>31.4</ele><time>2005-04-18T20:42:33Z</time></trkpt><trkpt lat=\"42.341158\" lon=\"-71.124887\"><ele>29.5</ele><time>2005-04-18T20:42:46Z</time></trkpt><trkpt lat=\"42.34133\" lon=\"-71.124201\"><ele>25.1</ele><time>2005-04-18T20:43:02Z</time></trkpt><trkpt lat=\"42.34148\" lon=\"-71.123536\"><ele>23.7</ele><time>2005-04-18T20:43:17Z</time></trkpt><trkpt lat=\"42.341588\" lon=\"-71.122892\"><ele>22.2</ele><time>2005-04-18T20:43:31Z</time></trkpt><trkpt lat=\"42.341716\" lon=\"-71.122377\"><ele>22.7</ele><time>2005-04-18T20:43:42Z</time></trkpt><trkpt lat=\"42.341738\" lon=\"-71.122184\"><ele>21.8</ele><time>2005-04-18T20:43:46Z</time></trkpt><trkpt lat=\"42.341845\" lon=\"-71.121819\"><ele>19.8</ele><time>2005-04-18T20:43:54Z</time></trkpt><trkpt lat=\"42.342017\" lon=\"-71.121283\"><ele>19.4</ele><time>2005-04-18T20:44:06Z</time></trkpt><trkpt lat=\"42.342188\" lon=\"-71.120725\"><ele>19.4</ele><time>2005-04-18T20:44:19Z</time></trkpt><trkpt lat=\"42.342446\" lon=\"-71.119823\"><ele>18.4</ele><time>2005-04-18T20:44:39Z</time></trkpt><trkpt lat=\"42.342618\" lon=\"-71.119266\"><ele>16.5</ele><time>2005-04-18T20:44:51Z</time></trkpt><trkpt lat=\"42.342789\" lon=\"-71.118622\"><ele>13.1</ele><time>2005-04-18T20:45:04Z</time></trkpt><trkpt lat=\"42.343004\" lon=\"-71.117892\"><ele>14.1</ele><time>2005-04-18T20:45:19Z</time></trkpt><trkpt lat=\"42.343154\" lon=\"-71.117291\"><ele>12.6</ele><time>2005-04-18T20:45:31Z</time></trkpt><trkpt lat=\"42.343304\" lon=\"-71.116734\"><ele>11.2</ele><time>2005-04-18T20:45:43Z</time></trkpt><trkpt lat=\"42.343454\" lon=\"-71.116176\"><ele>8.3</ele><time>2005-04-18T20:45:56Z</time></trkpt><trkpt lat=\"42.343669\" lon=\"-71.115425\"><ele>8.8</ele><time>2005-04-18T20:46:14Z</time></trkpt><trkpt lat=\"42.343841\" lon=\"-71.114845\"><ele>6.4</ele><time>2005-04-18T20:46:29Z</time></trkpt><trkpt lat=\"42.343948\" lon=\"-71.11433\"><ele>8.8</ele><time>2005-04-18T20:46:42Z</time></trkpt><trkpt lat=\"42.344098\" lon=\"-71.113772\"><ele>4</ele><time>2005-04-18T20:46:56Z</time></trkpt><trkpt lat=\"42.344184\" lon=\"-71.113214\"><ele>4.5</ele><time>2005-04-18T20:47:09Z</time></trkpt><trkpt lat=\"42.344248\" lon=\"-71.112828\"><ele>5.9</ele><time>2005-04-18T20:47:18Z</time></trkpt><trkpt lat=\"42.344441\" lon=\"-71.112313\"><ele>8.3</ele><time>2005-04-18T20:47:30Z</time></trkpt><trkpt lat=\"42.344592\" lon=\"-71.111777\"><ele>6.4</ele><time>2005-04-18T20:47:43Z</time></trkpt><trkpt lat=\"42.344763\" lon=\"-71.11124\"><ele>5.9</ele><time>2005-04-18T20:47:56Z</time></trkpt><trkpt lat=\"42.344956\" lon=\"-71.110618\"><ele>5.4</ele><time>2005-04-18T20:48:11Z</time></trkpt><trkpt lat=\"42.34515\" lon=\"-71.109931\"><ele>8.8</ele><time>2005-04-18T20:48:28Z</time></trkpt><trkpt lat=\"42.345386\" lon=\"-71.109374\"><ele>10.7</ele><time>2005-04-18T20:48:42Z</time></trkpt><trkpt lat=\"42.345557\" lon=\"-71.108751\"><ele>7.8</ele><time>2005-04-18T20:48:57Z</time></trkpt><trkpt lat=\"42.345665\" lon=\"-71.108215\"><ele>6.4</ele><time>2005-04-18T20:49:10Z</time></trkpt><trkpt lat=\"42.345793\" lon=\"-71.1077\"><ele>8.3</ele><time>2005-04-18T20:49:23Z</time></trkpt><trkpt lat=\"42.345943\" lon=\"-71.107142\"><ele>6.4</ele><time>2005-04-18T20:49:37Z</time></trkpt><trkpt lat=\"42.346115\" lon=\"-71.10652\"><ele>5.4</ele><time>2005-04-18T20:49:52Z</time></trkpt><trkpt lat=\"42.346244\" lon=\"-71.106048\"><ele>3.5</ele><time>2005-04-18T20:50:04Z</time></trkpt><trkpt lat=\"42.346394\" lon=\"-71.105533\"><ele>3</ele><time>2005-04-18T20:50:17Z</time></trkpt><trkpt lat=\"42.346587\" lon=\"-71.104953\"><ele>3</ele><time>2005-04-18T20:50:32Z</time></trkpt><trkpt lat=\"42.346759\" lon=\"-71.104503\"><ele>0.6</ele><time>2005-04-18T20:50:43Z</time></trkpt><trkpt lat=\"42.346888\" lon=\"-71.104031\"><ele>1.6</ele><time>2005-04-18T20:50:55Z</time></trkpt><trkpt lat=\"42.346931\" lon=\"-71.103945\"><ele>1.1</ele><time>2005-04-18T20:50:57Z</time></trkpt><trkpt lat=\"42.347102\" lon=\"-71.103344\"><ele>-0.3</ele><time>2005-04-18T20:51:12Z</time></trkpt><trkpt lat=\"42.347167\" lon=\"-71.102915\"><ele>6.4</ele><time>2005-04-18T20:51:22Z</time></trkpt><trkpt lat=\"42.347317\" lon=\"-71.1024\"><ele>10.2</ele><time>2005-04-18T20:51:34Z</time></trkpt><trkpt lat=\"42.347467\" lon=\"-71.101863\"><ele>12.6</ele><time>2005-04-18T20:51:48Z</time></trkpt><trkpt lat=\"42.347574\" lon=\"-71.101456\"><ele>14.1</ele><time>2005-04-18T20:51:58Z</time></trkpt><trkpt lat=\"42.347703\" lon=\"-71.100984\"><ele>13.6</ele><time>2005-04-18T20:52:10Z</time></trkpt><trkpt lat=\"42.347875\" lon=\"-71.100533\"><ele>14.6</ele><time>2005-04-18T20:52:22Z</time></trkpt><trkpt lat=\"42.347939\" lon=\"-71.100383\"><ele>12.6</ele><time>2005-04-18T20:52:26Z</time></trkpt><trkpt lat=\"42.347982\" lon=\"-71.100233\"><ele>12.2</ele><time>2005-04-18T20:52:30Z</time></trkpt><trkpt lat=\"42.348046\" lon=\"-71.100061\"><ele>12.2</ele><time>2005-04-18T20:52:34Z</time></trkpt><trkpt lat=\"42.348068\" lon=\"-71.099975\"><ele>11.2</ele><time>2005-04-18T20:52:36Z</time></trkpt><trkpt lat=\"42.348218\" lon=\"-71.099524\"><ele>12.2</ele><time>2005-04-18T20:52:47Z</time></trkpt><trkpt lat=\"42.348368\" lon=\"-71.098859\"><ele>13.6</ele><time>2005-04-18T20:53:02Z</time></trkpt><trkpt lat=\"42.348475\" lon=\"-71.098323\"><ele>13.6</ele><time>2005-04-18T20:53:14Z</time></trkpt><trkpt lat=\"42.348647\" lon=\"-71.097765\"><ele>15.5</ele><time>2005-04-18T20:53:27Z</time></trkpt><trkpt lat=\"42.348754\" lon=\"-71.097143\"><ele>10.7</ele><time>2005-04-18T20:53:41Z</time></trkpt><trkpt lat=\"42.348819\" lon=\"-71.096499\"><ele>10.2</ele><time>2005-04-18T20:53:55Z</time></trkpt><trkpt lat=\"42.348819\" lon=\"-71.095898\"><ele>10.7</ele><time>2005-04-18T20:54:08Z</time></trkpt><trkpt lat=\"42.348819\" lon=\"-71.095297\"><ele>10.2</ele><time>2005-04-18T20:54:21Z</time></trkpt><trkpt lat=\"42.348776\" lon=\"-71.094718\"><ele>9.8</ele><time>2005-04-18T20:54:34Z</time></trkpt><trkpt lat=\"42.348797\" lon=\"-71.09416\"><ele>11.7</ele><time>2005-04-18T20:54:47Z</time></trkpt><trkpt lat=\"42.348797\" lon=\"-71.093516\"><ele>11.7</ele><time>2005-04-18T20:55:02Z</time></trkpt><trkpt lat=\"42.348797\" lon=\"-71.09298\"><ele>10.2</ele><time>2005-04-18T20:55:14Z</time></trkpt><trkpt lat=\"42.348797\" lon=\"-71.0921\"><ele>10.2</ele><time>2005-04-18T20:55:33Z</time></trkpt><trkpt lat=\"42.348819\" lon=\"-71.091499\"><ele>9.8</ele><time>2005-04-18T20:55:46Z</time></trkpt><trkpt lat=\"42.34884\" lon=\"-71.090534\"><ele>8.3</ele><time>2005-04-18T20:56:07Z</time></trkpt><trkpt lat=\"42.348862\" lon=\"-71.08989\"><ele>8.3</ele><time>2005-04-18T20:56:22Z</time></trkpt><trkpt lat=\"42.348883\" lon=\"-71.089246\"><ele>8.8</ele><time>2005-04-18T20:56:38Z</time></trkpt><trkpt lat=\"42.348862\" lon=\"-71.088731\"><ele>8.3</ele><time>2005-04-18T20:56:50Z</time></trkpt><trkpt lat=\"42.348926\" lon=\"-71.088152\"><ele>4.5</ele><time>2005-04-18T20:57:04Z</time></trkpt><trkpt lat=\"42.349033\" lon=\"-71.087766\"><ele>8.3</ele><time>2005-04-18T20:57:14Z</time></trkpt><trkpt lat=\"42.349226\" lon=\"-71.087186\"><ele>9.8</ele><time>2005-04-18T20:57:28Z</time></trkpt><trkpt lat=\"42.349334\" lon=\"-71.086714\"><ele>10.2</ele><time>2005-04-18T20:57:39Z</time></trkpt><trkpt lat=\"42.349527\" lon=\"-71.086156\"><ele>7.8</ele><time>2005-04-18T20:57:53Z</time></trkpt><trkpt lat=\"42.348883\" lon=\"-71.085448\"><ele>6.9</ele><time>2005-04-18T20:58:19Z</time></trkpt><trkpt lat=\"42.348561\" lon=\"-71.085191\"><ele>6.9</ele><time>2005-04-18T20:58:30Z</time></trkpt><trkpt lat=\"42.348025\" lon=\"-71.085255\"><ele>6.9</ele><time>2005-04-18T20:58:43Z</time></trkpt><trkpt lat=\"42.348583\" lon=\"-71.083195\"><ele>6.4</ele><time>2005-04-18T20:59:27Z</time></trkpt><trkpt lat=\"42.348711\" lon=\"-71.082852\"><ele>6.9</ele><time>2005-04-18T20:59:34Z</time></trkpt><trkpt lat=\"42.348819\" lon=\"-71.082423\"><ele>6.9</ele><time>2005-04-18T20:59:43Z</time></trkpt><trkpt lat=\"42.348862\" lon=\"-71.082337\"><ele>6.9</ele><time>2005-04-18T20:59:45Z</time></trkpt><trkpt lat=\"42.348926\" lon=\"-71.082273\"><ele>6.9</ele><time>2005-04-18T20:59:47Z</time></trkpt><trkpt lat=\"42.349098\" lon=\"-71.081779\"><ele>7.3</ele><time>2005-04-18T20:59:58Z</time></trkpt><trkpt lat=\"42.349141\" lon=\"-71.081522\"><ele>7.3</ele><time>2005-04-18T21:00:03Z</time></trkpt><trkpt lat=\"42.349291\" lon=\"-71.080792\"><ele>5.4</ele><time>2005-04-18T21:00:18Z</time></trkpt><trkpt lat=\"42.349548\" lon=\"-71.079719\"><ele>5.4</ele><time>2005-04-18T21:00:40Z</time></trkpt><trkpt lat=\"42.349699\" lon=\"-71.079569\"><ele>5.4</ele><time>2005-04-18T21:00:44Z</time></trkpt><trkpt lat=\"42.349892\" lon=\"-71.078882\"><ele>6.9</ele><time>2005-04-18T21:00:58Z</time></trkpt></trkseg></trk></gpx>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/denver.gpx",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xalan=\"http://xml.apache.org/xalan\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" creator=\"MotionX Live\" version=\"1.1\">\n  <trk>\n    <name>Track 002</name>\n    <desc>Mar 25, 2010 10:19 am</desc>\n    <trkseg>\n      <trkpt lat=\"39.757509\" lon=\"-104.902044\">\n        <ele>1602.000000</ele>\n        <time>2010-03-25T16:19:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757484\" lon=\"-104.902000\">\n        <ele>1605.000000</ele>\n        <time>2010-03-25T16:19:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757424\" lon=\"-104.901952\">\n        <ele>1606.000000</ele>\n        <time>2010-03-25T16:19:25Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757336\" lon=\"-104.901900\">\n        <ele>1608.000000</ele>\n        <time>2010-03-25T16:19:27Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757266\" lon=\"-104.901870\">\n        <ele>1608.000000</ele>\n        <time>2010-03-25T16:19:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757215\" lon=\"-104.901857\">\n        <ele>1607.000000</ele>\n        <time>2010-03-25T16:19:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757112\" lon=\"-104.901898\">\n        <ele>1607.000000</ele>\n        <time>2010-03-25T16:19:34Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757058\" lon=\"-104.902024\">\n        <ele>1607.000000</ele>\n        <time>2010-03-25T16:19:37Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757033\" lon=\"-104.902128\">\n        <ele>1608.000000</ele>\n        <time>2010-03-25T16:19:39Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757035\" lon=\"-104.902465\">\n        <ele>1609.000000</ele>\n        <time>2010-03-25T16:19:41Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757070\" lon=\"-104.902841\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:19:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757109\" lon=\"-104.903020\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:19:46Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757125\" lon=\"-104.903049\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:19:48Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757136\" lon=\"-104.903147\">\n        <ele>1609.000000</ele>\n        <time>2010-03-25T16:20:00Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757182\" lon=\"-104.903329\">\n        <ele>1609.000000</ele>\n        <time>2010-03-25T16:20:03Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757324\" lon=\"-104.903434\">\n        <ele>1609.000000</ele>\n        <time>2010-03-25T16:20:06Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757858\" lon=\"-104.903452\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:20:09Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758390\" lon=\"-104.903485\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:20:12Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758770\" lon=\"-104.903476\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:20:14Z</time>\n      </trkpt>\n      <trkpt lat=\"39.759124\" lon=\"-104.903450\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:20:16Z</time>\n      </trkpt>\n      <trkpt lat=\"39.759446\" lon=\"-104.903386\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:20:18Z</time>\n      </trkpt>\n      <trkpt lat=\"39.759743\" lon=\"-104.903212\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:20:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760028\" lon=\"-104.903071\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:20:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760313\" lon=\"-104.902947\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:20:24Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760608\" lon=\"-104.902876\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:20:26Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760931\" lon=\"-104.902853\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:20:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761267\" lon=\"-104.902855\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:20:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761527\" lon=\"-104.902851\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:20:33Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761769\" lon=\"-104.902855\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:20:36Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761964\" lon=\"-104.902866\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:20:38Z</time>\n      </trkpt>\n      <trkpt lat=\"39.762122\" lon=\"-104.902989\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:20:40Z</time>\n      </trkpt>\n      <trkpt lat=\"39.762051\" lon=\"-104.903268\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:20:43Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761864\" lon=\"-104.903486\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:20:46Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761700\" lon=\"-104.903558\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:20:48Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761646\" lon=\"-104.903576\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:20:50Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761549\" lon=\"-104.903554\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:21:03Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761395\" lon=\"-104.903555\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:21:05Z</time>\n      </trkpt>\n      <trkpt lat=\"39.761157\" lon=\"-104.903561\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:21:07Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760899\" lon=\"-104.903571\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:21:09Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760583\" lon=\"-104.903578\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:21:12Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760263\" lon=\"-104.903588\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:21:14Z</time>\n      </trkpt>\n      <trkpt lat=\"39.759937\" lon=\"-104.903596\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:21:16Z</time>\n      </trkpt>\n      <trkpt lat=\"39.759608\" lon=\"-104.903603\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:21:18Z</time>\n      </trkpt>\n      <trkpt lat=\"39.759181\" lon=\"-104.903587\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:21:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758748\" lon=\"-104.903560\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:21:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758352\" lon=\"-104.903544\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:21:25Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757973\" lon=\"-104.903544\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:21:27Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757615\" lon=\"-104.903542\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:21:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757248\" lon=\"-104.903539\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:21:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.756862\" lon=\"-104.903540\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:21:34Z</time>\n      </trkpt>\n      <trkpt lat=\"39.756371\" lon=\"-104.903537\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:21:37Z</time>\n      </trkpt>\n      <trkpt lat=\"39.755914\" lon=\"-104.903532\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:21:39Z</time>\n      </trkpt>\n      <trkpt lat=\"39.755457\" lon=\"-104.903526\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:21:42Z</time>\n      </trkpt>\n      <trkpt lat=\"39.755106\" lon=\"-104.903537\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:21:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.754636\" lon=\"-104.903554\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:21:47Z</time>\n      </trkpt>\n      <trkpt lat=\"39.754276\" lon=\"-104.903554\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:21:49Z</time>\n      </trkpt>\n      <trkpt lat=\"39.753752\" lon=\"-104.903541\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:21:53Z</time>\n      </trkpt>\n      <trkpt lat=\"39.753350\" lon=\"-104.903531\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:21:55Z</time>\n      </trkpt>\n      <trkpt lat=\"39.752965\" lon=\"-104.903529\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:21:58Z</time>\n      </trkpt>\n      <trkpt lat=\"39.752577\" lon=\"-104.903526\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:22:00Z</time>\n      </trkpt>\n      <trkpt lat=\"39.752184\" lon=\"-104.903515\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:22:03Z</time>\n      </trkpt>\n      <trkpt lat=\"39.751782\" lon=\"-104.903510\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:22:05Z</time>\n      </trkpt>\n      <trkpt lat=\"39.751373\" lon=\"-104.903508\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:22:08Z</time>\n      </trkpt>\n      <trkpt lat=\"39.750967\" lon=\"-104.903503\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:22:11Z</time>\n      </trkpt>\n      <trkpt lat=\"39.750566\" lon=\"-104.903503\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:22:13Z</time>\n      </trkpt>\n      <trkpt lat=\"39.750174\" lon=\"-104.903499\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:22:16Z</time>\n      </trkpt>\n      <trkpt lat=\"39.749787\" lon=\"-104.903496\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:22:18Z</time>\n      </trkpt>\n      <trkpt lat=\"39.749458\" lon=\"-104.903495\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:22:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.749140\" lon=\"-104.903496\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:22:23Z</time>\n      </trkpt>\n      <trkpt lat=\"39.748812\" lon=\"-104.903499\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:22:25Z</time>\n      </trkpt>\n      <trkpt lat=\"39.748478\" lon=\"-104.903502\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:22:27Z</time>\n      </trkpt>\n      <trkpt lat=\"39.748153\" lon=\"-104.903509\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:22:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747833\" lon=\"-104.903517\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:22:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747526\" lon=\"-104.903514\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:22:33Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747233\" lon=\"-104.903507\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:22:35Z</time>\n      </trkpt>\n      <trkpt lat=\"39.746908\" lon=\"-104.903513\">\n        <ele>1620.000000</ele>\n        <time>2010-03-25T16:22:38Z</time>\n      </trkpt>\n      <trkpt lat=\"39.746632\" lon=\"-104.903531\">\n        <ele>1620.000000</ele>\n        <time>2010-03-25T16:22:40Z</time>\n      </trkpt>\n      <trkpt lat=\"39.746338\" lon=\"-104.903546\">\n        <ele>1620.000000</ele>\n        <time>2010-03-25T16:22:42Z</time>\n      </trkpt>\n      <trkpt lat=\"39.746025\" lon=\"-104.903555\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:22:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.745701\" lon=\"-104.903553\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:22:46Z</time>\n      </trkpt>\n      <trkpt lat=\"39.745338\" lon=\"-104.903557\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:22:49Z</time>\n      </trkpt>\n      <trkpt lat=\"39.745041\" lon=\"-104.903542\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:22:51Z</time>\n      </trkpt>\n      <trkpt lat=\"39.744774\" lon=\"-104.903539\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:22:53Z</time>\n      </trkpt>\n      <trkpt lat=\"39.744530\" lon=\"-104.903528\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:22:55Z</time>\n      </trkpt>\n      <trkpt lat=\"39.744308\" lon=\"-104.903525\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:22:57Z</time>\n      </trkpt>\n      <trkpt lat=\"39.744085\" lon=\"-104.903527\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:22:59Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743778\" lon=\"-104.903521\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:23:02Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743562\" lon=\"-104.903519\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:23:04Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743235\" lon=\"-104.903511\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:23:07Z</time>\n      </trkpt>\n      <trkpt lat=\"39.742889\" lon=\"-104.903506\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:23:10Z</time>\n      </trkpt>\n      <trkpt lat=\"39.742546\" lon=\"-104.903497\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:23:13Z</time>\n      </trkpt>\n      <trkpt lat=\"39.742288\" lon=\"-104.903492\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:23:15Z</time>\n      </trkpt>\n      <trkpt lat=\"39.741945\" lon=\"-104.903486\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:23:18Z</time>\n      </trkpt>\n      <trkpt lat=\"39.741454\" lon=\"-104.903481\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:23:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.741155\" lon=\"-104.903482\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:23:24Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740856\" lon=\"-104.903485\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:23:26Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740501\" lon=\"-104.903493\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:23:28Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740264\" lon=\"-104.903501\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:23:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740127\" lon=\"-104.903628\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:23:34Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740112\" lon=\"-104.903809\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:23:36Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740119\" lon=\"-104.904130\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:23:39Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740132\" lon=\"-104.904616\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:23:41Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740140\" lon=\"-104.904995\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:23:43Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740149\" lon=\"-104.905544\">\n        <ele>1625.000000</ele>\n        <time>2010-03-25T16:23:46Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740155\" lon=\"-104.905976\">\n        <ele>1627.000000</ele>\n        <time>2010-03-25T16:23:48Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740159\" lon=\"-104.906382\">\n        <ele>1627.000000</ele>\n        <time>2010-03-25T16:23:51Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740157\" lon=\"-104.906782\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:23:53Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740158\" lon=\"-104.907183\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:23:55Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740158\" lon=\"-104.907729\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:23:58Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740156\" lon=\"-104.908155\">\n        <ele>1629.000000</ele>\n        <time>2010-03-25T16:24:00Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740151\" lon=\"-104.908655\">\n        <ele>1629.000000</ele>\n        <time>2010-03-25T16:24:02Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740159\" lon=\"-104.909104\">\n        <ele>1629.000000</ele>\n        <time>2010-03-25T16:24:05Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740170\" lon=\"-104.909731\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:24:07Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740177\" lon=\"-104.910187\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:24:09Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740180\" lon=\"-104.910685\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:24:12Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740185\" lon=\"-104.911317\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:24:14Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740195\" lon=\"-104.911940\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:24:18Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740202\" lon=\"-104.912238\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:24:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740210\" lon=\"-104.912492\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:24:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740214\" lon=\"-104.912546\">\n        <ele>1629.000000</ele>\n        <time>2010-03-25T16:24:25Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740300\" lon=\"-104.912465\">\n        <ele>1630.000000</ele>\n        <time>2010-03-25T16:24:37Z</time>\n      </trkpt>\n      <trkpt lat=\"39.740661\" lon=\"-104.912478\">\n        <ele>1629.000000</ele>\n        <time>2010-03-25T16:24:39Z</time>\n      </trkpt>\n      <trkpt lat=\"39.741089\" lon=\"-104.912493\">\n        <ele>1629.000000</ele>\n        <time>2010-03-25T16:24:41Z</time>\n      </trkpt>\n      <trkpt lat=\"39.741511\" lon=\"-104.912495\">\n        <ele>1629.000000</ele>\n        <time>2010-03-25T16:24:43Z</time>\n      </trkpt>\n      <trkpt lat=\"39.741880\" lon=\"-104.912497\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:24:45Z</time>\n      </trkpt>\n      <trkpt lat=\"39.742227\" lon=\"-104.912490\">\n        <ele>1628.000000</ele>\n        <time>2010-03-25T16:24:48Z</time>\n      </trkpt>\n      <trkpt lat=\"39.742538\" lon=\"-104.912474\">\n        <ele>1627.000000</ele>\n        <time>2010-03-25T16:24:50Z</time>\n      </trkpt>\n      <trkpt lat=\"39.742812\" lon=\"-104.912459\">\n        <ele>1627.000000</ele>\n        <time>2010-03-25T16:24:52Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743025\" lon=\"-104.912464\">\n        <ele>1627.000000</ele>\n        <time>2010-03-25T16:24:54Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743190\" lon=\"-104.912477\">\n        <ele>1626.000000</ele>\n        <time>2010-03-25T16:24:56Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743325\" lon=\"-104.912490\">\n        <ele>1626.000000</ele>\n        <time>2010-03-25T16:24:58Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743383\" lon=\"-104.912489\">\n        <ele>1626.000000</ele>\n        <time>2010-03-25T16:25:00Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743403\" lon=\"-104.912487\">\n        <ele>1626.000000</ele>\n        <time>2010-03-25T16:25:03Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743400\" lon=\"-104.912484\">\n        <ele>1626.000000</ele>\n        <time>2010-03-25T16:25:03Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743443\" lon=\"-104.912469\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:25:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743690\" lon=\"-104.912443\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:25:25Z</time>\n      </trkpt>\n      <trkpt lat=\"39.743971\" lon=\"-104.912447\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:25:27Z</time>\n      </trkpt>\n      <trkpt lat=\"39.744267\" lon=\"-104.912457\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:25:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.744599\" lon=\"-104.912458\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:25:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.744947\" lon=\"-104.912451\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:25:33Z</time>\n      </trkpt>\n      <trkpt lat=\"39.745313\" lon=\"-104.912444\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:25:36Z</time>\n      </trkpt>\n      <trkpt lat=\"39.745678\" lon=\"-104.912441\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:25:38Z</time>\n      </trkpt>\n      <trkpt lat=\"39.746037\" lon=\"-104.912442\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:25:40Z</time>\n      </trkpt>\n      <trkpt lat=\"39.746380\" lon=\"-104.912457\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:25:42Z</time>\n      </trkpt>\n      <trkpt lat=\"39.746711\" lon=\"-104.912471\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:25:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.746944\" lon=\"-104.912469\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:25:47Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747123\" lon=\"-104.912465\">\n        <ele>1625.000000</ele>\n        <time>2010-03-25T16:25:49Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747302\" lon=\"-104.912459\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:25:51Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747450\" lon=\"-104.912437\">\n        <ele>1624.000000</ele>\n        <time>2010-03-25T16:25:53Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747543\" lon=\"-104.912326\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:25:55Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747507\" lon=\"-104.912047\">\n        <ele>1623.000000</ele>\n        <time>2010-03-25T16:25:57Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747480\" lon=\"-104.911673\">\n        <ele>1622.000000</ele>\n        <time>2010-03-25T16:26:00Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747465\" lon=\"-104.911244\">\n        <ele>1621.000000</ele>\n        <time>2010-03-25T16:26:02Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747464\" lon=\"-104.910810\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:26:04Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747464\" lon=\"-104.910390\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:26:06Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747459\" lon=\"-104.909984\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:26:08Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747455\" lon=\"-104.909591\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:26:11Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747455\" lon=\"-104.909203\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:26:13Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747452\" lon=\"-104.908792\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:26:15Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747453\" lon=\"-104.908389\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:26:17Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747458\" lon=\"-104.907988\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:26:19Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747457\" lon=\"-104.907592\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:26:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747453\" lon=\"-104.907204\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:26:24Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747449\" lon=\"-104.906805\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:26:26Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747449\" lon=\"-104.906404\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:26:28Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747453\" lon=\"-104.906004\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:26:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747449\" lon=\"-104.905613\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:26:33Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747454\" lon=\"-104.905258\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:26:35Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747452\" lon=\"-104.904906\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:26:37Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747444\" lon=\"-104.904577\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:26:39Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747435\" lon=\"-104.904270\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:26:42Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747425\" lon=\"-104.904014\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:26:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747417\" lon=\"-104.903880\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:26:46Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747414\" lon=\"-104.903807\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:26:48Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747414\" lon=\"-104.903799\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:26:49Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747391\" lon=\"-104.903680\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:27:28Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747392\" lon=\"-104.903395\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:27:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747392\" lon=\"-104.902957\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:27:34Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747390\" lon=\"-104.902597\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:27:36Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747388\" lon=\"-104.902221\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:27:38Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747387\" lon=\"-104.901833\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:27:40Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747389\" lon=\"-104.901246\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:27:43Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747394\" lon=\"-104.900852\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:27:45Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747394\" lon=\"-104.900450\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:27:47Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747400\" lon=\"-104.900032\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:27:50Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747410\" lon=\"-104.899623\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:27:52Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747418\" lon=\"-104.899213\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:27:54Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747422\" lon=\"-104.898812\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:27:56Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747422\" lon=\"-104.898422\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:27:58Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747417\" lon=\"-104.898034\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:28:00Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747415\" lon=\"-104.897662\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:28:03Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747413\" lon=\"-104.897173\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:05Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747413\" lon=\"-104.896798\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:07Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747415\" lon=\"-104.896431\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:10Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747416\" lon=\"-104.896052\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:12Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747414\" lon=\"-104.895632\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:14Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747415\" lon=\"-104.895104\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:28:17Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747424\" lon=\"-104.894549\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:28:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747422\" lon=\"-104.894083\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747420\" lon=\"-104.893707\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:24Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747422\" lon=\"-104.893223\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:27Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747415\" lon=\"-104.892739\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747412\" lon=\"-104.892294\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:32Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747409\" lon=\"-104.891842\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:35Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747400\" lon=\"-104.891427\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:28:37Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747393\" lon=\"-104.890889\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:28:40Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747402\" lon=\"-104.890341\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:28:43Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747412\" lon=\"-104.889916\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:28:45Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747414\" lon=\"-104.889483\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:28:47Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747411\" lon=\"-104.888996\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:28:50Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747408\" lon=\"-104.888580\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:28:52Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747410\" lon=\"-104.888223\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:28:54Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747403\" lon=\"-104.887836\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:28:57Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747399\" lon=\"-104.887542\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:28:59Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747425\" lon=\"-104.887225\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:29:01Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747449\" lon=\"-104.886896\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:29:03Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747453\" lon=\"-104.886542\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:29:06Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747445\" lon=\"-104.886181\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:29:08Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747421\" lon=\"-104.885833\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:29:10Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747420\" lon=\"-104.885489\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:29:12Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747422\" lon=\"-104.885176\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:29:14Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747423\" lon=\"-104.884868\">\n        <ele>1619.000000</ele>\n        <time>2010-03-25T16:29:17Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747428\" lon=\"-104.884748\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:29:19Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747432\" lon=\"-104.884702\">\n        <ele>1618.000000</ele>\n        <time>2010-03-25T16:29:21Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747435\" lon=\"-104.884637\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:29:23Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747464\" lon=\"-104.884546\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:29:26Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747656\" lon=\"-104.884470\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:29:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.747906\" lon=\"-104.884577\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:29:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.748128\" lon=\"-104.884733\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:29:33Z</time>\n      </trkpt>\n      <trkpt lat=\"39.748339\" lon=\"-104.884907\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:29:35Z</time>\n      </trkpt>\n      <trkpt lat=\"39.748553\" lon=\"-104.885116\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:29:38Z</time>\n      </trkpt>\n      <trkpt lat=\"39.748764\" lon=\"-104.885362\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:29:40Z</time>\n      </trkpt>\n      <trkpt lat=\"39.748984\" lon=\"-104.885646\">\n        <ele>1617.000000</ele>\n        <time>2010-03-25T16:29:42Z</time>\n      </trkpt>\n      <trkpt lat=\"39.749193\" lon=\"-104.885957\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:29:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.749541\" lon=\"-104.886439\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:29:48Z</time>\n      </trkpt>\n      <trkpt lat=\"39.749833\" lon=\"-104.886834\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:29:50Z</time>\n      </trkpt>\n      <trkpt lat=\"39.750056\" lon=\"-104.887142\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:29:52Z</time>\n      </trkpt>\n      <trkpt lat=\"39.750273\" lon=\"-104.887462\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:29:55Z</time>\n      </trkpt>\n      <trkpt lat=\"39.750479\" lon=\"-104.887757\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:29:57Z</time>\n      </trkpt>\n      <trkpt lat=\"39.750677\" lon=\"-104.888052\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:29:59Z</time>\n      </trkpt>\n      <trkpt lat=\"39.750873\" lon=\"-104.888343\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:30:01Z</time>\n      </trkpt>\n      <trkpt lat=\"39.751136\" lon=\"-104.888712\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:30:04Z</time>\n      </trkpt>\n      <trkpt lat=\"39.751327\" lon=\"-104.888981\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:30:06Z</time>\n      </trkpt>\n      <trkpt lat=\"39.751513\" lon=\"-104.889252\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:30:08Z</time>\n      </trkpt>\n      <trkpt lat=\"39.751693\" lon=\"-104.889523\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:30:11Z</time>\n      </trkpt>\n      <trkpt lat=\"39.751835\" lon=\"-104.889738\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:30:13Z</time>\n      </trkpt>\n      <trkpt lat=\"39.751906\" lon=\"-104.889857\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:30:15Z</time>\n      </trkpt>\n      <trkpt lat=\"39.751934\" lon=\"-104.889908\">\n        <ele>1609.000000</ele>\n        <time>2010-03-25T16:30:19Z</time>\n      </trkpt>\n      <trkpt lat=\"39.752094\" lon=\"-104.890106\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:30:32Z</time>\n      </trkpt>\n      <trkpt lat=\"39.752285\" lon=\"-104.890288\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:30:34Z</time>\n      </trkpt>\n      <trkpt lat=\"39.752540\" lon=\"-104.890509\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:30:37Z</time>\n      </trkpt>\n      <trkpt lat=\"39.753119\" lon=\"-104.890627\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:30:41Z</time>\n      </trkpt>\n      <trkpt lat=\"39.753617\" lon=\"-104.890615\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:30:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.754066\" lon=\"-104.890590\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:30:47Z</time>\n      </trkpt>\n      <trkpt lat=\"39.754430\" lon=\"-104.890554\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:30:49Z</time>\n      </trkpt>\n      <trkpt lat=\"39.754749\" lon=\"-104.890541\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:30:52Z</time>\n      </trkpt>\n      <trkpt lat=\"39.755137\" lon=\"-104.890538\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:30:54Z</time>\n      </trkpt>\n      <trkpt lat=\"39.755656\" lon=\"-104.890536\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:30:58Z</time>\n      </trkpt>\n      <trkpt lat=\"39.756021\" lon=\"-104.890531\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:01Z</time>\n      </trkpt>\n      <trkpt lat=\"39.756348\" lon=\"-104.890522\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:03Z</time>\n      </trkpt>\n      <trkpt lat=\"39.756699\" lon=\"-104.890516\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:06Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757009\" lon=\"-104.890508\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:08Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757293\" lon=\"-104.890503\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:10Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757539\" lon=\"-104.890500\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:12Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757727\" lon=\"-104.890501\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:14Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757880\" lon=\"-104.890494\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:17Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757948\" lon=\"-104.890491\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:19Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758014\" lon=\"-104.890473\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758104\" lon=\"-104.890460\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:31:24Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758189\" lon=\"-104.890458\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:26Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758170\" lon=\"-104.890457\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:31:28Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758217\" lon=\"-104.890639\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:31:32Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758241\" lon=\"-104.890834\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:31:36Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758203\" lon=\"-104.891245\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:31:38Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758185\" lon=\"-104.891572\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:31:40Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758177\" lon=\"-104.891905\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:31:43Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758174\" lon=\"-104.892251\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:31:45Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758172\" lon=\"-104.892593\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:31:47Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758165\" lon=\"-104.892926\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:31:49Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758165\" lon=\"-104.893260\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:31:51Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758162\" lon=\"-104.893607\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:31:53Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758160\" lon=\"-104.893963\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:31:56Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758160\" lon=\"-104.894326\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:31:58Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758158\" lon=\"-104.894693\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:32:00Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758154\" lon=\"-104.895059\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:32:02Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758145\" lon=\"-104.895427\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:32:05Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758140\" lon=\"-104.895807\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:32:07Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758136\" lon=\"-104.896199\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:32:09Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758133\" lon=\"-104.896593\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:32:11Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758132\" lon=\"-104.896986\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:32:13Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758131\" lon=\"-104.897373\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:32:16Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758133\" lon=\"-104.897747\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:32:18Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758138\" lon=\"-104.898103\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:32:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758145\" lon=\"-104.898377\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:32:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758147\" lon=\"-104.898485\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:25Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758167\" lon=\"-104.898562\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:27Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758215\" lon=\"-104.898645\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758282\" lon=\"-104.898742\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758384\" lon=\"-104.898908\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:32:34Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758394\" lon=\"-104.898906\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:32:35Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758406\" lon=\"-104.899072\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:32:39Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758403\" lon=\"-104.899273\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:41Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758404\" lon=\"-104.899692\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758402\" lon=\"-104.900017\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:47Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758393\" lon=\"-104.900269\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:49Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758381\" lon=\"-104.900442\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:51Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758381\" lon=\"-104.900456\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:52Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758323\" lon=\"-104.900566\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:55Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758192\" lon=\"-104.900600\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:32:57Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758023\" lon=\"-104.900596\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:00Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757883\" lon=\"-104.900586\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:33:02Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757798\" lon=\"-104.900574\">\n        <ele>1616.000000</ele>\n        <time>2010-03-25T16:33:04Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757737\" lon=\"-104.900574\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:33:06Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757631\" lon=\"-104.900577\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:33:08Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757454\" lon=\"-104.900579\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:33:11Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757267\" lon=\"-104.900569\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:13Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757098\" lon=\"-104.900553\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:15Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757030\" lon=\"-104.900628\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:18Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757024\" lon=\"-104.900715\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757043\" lon=\"-104.900889\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757053\" lon=\"-104.901147\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:24Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757068\" lon=\"-104.901403\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:26Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757081\" lon=\"-104.901614\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757080\" lon=\"-104.901716\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757153\" lon=\"-104.901788\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:33Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757280\" lon=\"-104.901830\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:35Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757459\" lon=\"-104.901849\">\n        <ele>1615.000000</ele>\n        <time>2010-03-25T16:33:37Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757636\" lon=\"-104.901859\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:33:39Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757747\" lon=\"-104.901902\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:33:42Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757800\" lon=\"-104.901993\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:33:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757800\" lon=\"-104.902119\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:33:46Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757759\" lon=\"-104.902223\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:33:48Z</time>\n      </trkpt>\n    </trkseg>\n  </trk>\n</gpx>\n\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/paris.gpx",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<gpx version=\"1.1\" creator=\"GPS Runner\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/1\" schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\"><trk><number>1</number><trkseg><trkpt lat=\"48.8723487854004\" lon=\"2.29986023902893\"><ele>62.0776</ele><time>2007-04-15T08:53:30Z</time></trkpt><trkpt lat=\"48.8723068237305\" lon=\"2.2999861240387\"><ele>61.7964</ele><time>2007-04-15T08:53:31Z</time></trkpt><trkpt lat=\"48.8722686767578\" lon=\"2.3001344203949\"><ele>61.8929</ele><time>2007-04-15T08:53:32Z</time></trkpt><trkpt lat=\"48.8722381591797\" lon=\"2.3003101348877\"><ele>61.9837</ele><time>2007-04-15T08:53:33Z</time></trkpt><trkpt lat=\"48.8721351623535\" lon=\"2.3004777431488\"><ele>61.5251</ele><time>2007-04-15T08:53:34Z</time></trkpt><trkpt lat=\"48.8720893859863\" lon=\"2.30063438415527\"><ele>61.1653</ele><time>2007-04-15T08:53:35Z</time></trkpt><trkpt lat=\"48.872013092041\" lon=\"2.30082821846008\"><ele>60.3324</ele><time>2007-04-15T08:53:36Z</time></trkpt><trkpt lat=\"48.8719024658203\" lon=\"2.30098080635071\"><ele>58.8597</ele><time>2007-04-15T08:53:37Z</time></trkpt><trkpt lat=\"48.871883392334\" lon=\"2.30100584030151\"><ele>58.6127</ele><time>2007-04-15T08:53:38Z</time></trkpt><trkpt lat=\"48.8717994689941\" lon=\"2.30117106437683\"><ele>57.3998</ele><time>2007-04-15T08:53:39Z</time></trkpt><trkpt lat=\"48.8717575073242\" lon=\"2.30130171775818\"><ele>56.6867</ele><time>2007-04-15T08:53:40Z</time></trkpt><trkpt lat=\"48.871711730957\" lon=\"2.30152010917664\"><ele>55.7398</ele><time>2007-04-15T08:53:41Z</time></trkpt><trkpt lat=\"48.8716697692871\" lon=\"2.30173563957214\"><ele>55.0242</ele><time>2007-04-15T08:53:42Z</time></trkpt><trkpt lat=\"48.8716278076172\" lon=\"2.30187392234802\"><ele>54.8717</ele><time>2007-04-15T08:53:43Z</time></trkpt><trkpt lat=\"48.8716011047363\" lon=\"2.30205392837524\"><ele>54.8005</ele><time>2007-04-15T08:53:44Z</time></trkpt><trkpt lat=\"48.8715896606445\" lon=\"2.30224180221558\"><ele>54.7866</ele><time>2007-04-15T08:53:45Z</time></trkpt><trkpt lat=\"48.8714981079102\" lon=\"2.30245757102966\"><ele>54.5852</ele><time>2007-04-15T08:53:46Z</time></trkpt><trkpt lat=\"48.8714294433594\" lon=\"2.30264925956726\"><ele>54.7889</ele><time>2007-04-15T08:53:47Z</time></trkpt><trkpt lat=\"48.8714027404785\" lon=\"2.3028461933136\"><ele>55.1974</ele><time>2007-04-15T08:53:48Z</time></trkpt><trkpt lat=\"48.871395111084\" lon=\"2.30305695533752\"><ele>55.685</ele><time>2007-04-15T08:53:49Z</time></trkpt><trkpt lat=\"48.8713760375977\" lon=\"2.30333876609802\"><ele>56.3067</ele><time>2007-04-15T08:53:50Z</time></trkpt><trkpt lat=\"48.8713150024414\" lon=\"2.30353450775146\"><ele>56.2955</ele><time>2007-04-15T08:53:51Z</time></trkpt><trkpt lat=\"48.8712615966797\" lon=\"2.30371379852295\"><ele>56.2625</ele><time>2007-04-15T08:53:52Z</time></trkpt><trkpt lat=\"48.8712043762207\" lon=\"2.30398011207581\"><ele>56.2361</ele><time>2007-04-15T08:53:53Z</time></trkpt><trkpt lat=\"48.8711471557617\" lon=\"2.30423498153687\"><ele>55.8838</ele><time>2007-04-15T08:53:54Z</time></trkpt><trkpt lat=\"48.8711090087891\" lon=\"2.30440974235535\"><ele>55.1174</ele><time>2007-04-15T08:53:55Z</time></trkpt><trkpt lat=\"48.8710250854492\" lon=\"2.30458950996399\"><ele>54.1681</ele><time>2007-04-15T08:53:56Z</time></trkpt><trkpt lat=\"48.8709259033203\" lon=\"2.30483794212341\"><ele>52.9167</ele><time>2007-04-15T08:53:57Z</time></trkpt><trkpt lat=\"48.8708000183106\" lon=\"2.30502724647522\"><ele>51.9234</ele><time>2007-04-15T08:53:58Z</time></trkpt><trkpt lat=\"48.870719909668\" lon=\"2.30520534515381\"><ele>51.5169</ele><time>2007-04-15T08:53:59Z</time></trkpt><trkpt lat=\"48.8706703186035\" lon=\"2.3053765296936\"><ele>51.0874</ele><time>2007-04-15T08:54:00Z</time></trkpt><trkpt lat=\"48.8706169128418\" lon=\"2.30560851097107\"><ele>50.4412</ele><time>2007-04-15T08:54:01Z</time></trkpt><trkpt lat=\"48.8705711364746\" lon=\"2.30584454536438\"><ele>49.7492</ele><time>2007-04-15T08:54:02Z</time></trkpt><trkpt lat=\"48.8705253601074\" lon=\"2.30603861808777\"><ele>49.7306</ele><time>2007-04-15T08:54:03Z</time></trkpt><trkpt lat=\"48.8704605102539\" lon=\"2.30619883537292\"><ele>49.753</ele><time>2007-04-15T08:54:04Z</time></trkpt><trkpt lat=\"48.8703804016113\" lon=\"2.30642080307007\"><ele>50.0368</ele><time>2007-04-15T08:54:05Z</time></trkpt><trkpt lat=\"48.8703384399414\" lon=\"2.30663371086121\"><ele>50.516</ele><time>2007-04-15T08:54:06Z</time></trkpt><trkpt lat=\"48.870246887207\" lon=\"2.30685210227966\"><ele>50.3494</ele><time>2007-04-15T08:54:07Z</time></trkpt><trkpt lat=\"48.8701782226562\" lon=\"2.30710005760193\"><ele>50.0436</ele><time>2007-04-15T08:54:08Z</time></trkpt><trkpt lat=\"48.8701477050781\" lon=\"2.30732297897339\"><ele>49.756</ele><time>2007-04-15T08:54:09Z</time></trkpt><trkpt lat=\"48.8700942993164\" lon=\"2.30757093429565\"><ele>49.2172</ele><time>2007-04-15T08:54:10Z</time></trkpt><trkpt lat=\"48.8700256347656\" lon=\"2.30778956413269\"><ele>47.8977</ele><time>2007-04-15T08:54:11Z</time></trkpt><trkpt lat=\"48.869945526123\" lon=\"2.30793976783752\"><ele>46.5831</ele><time>2007-04-15T08:54:12Z</time></trkpt><trkpt lat=\"48.8698387145996\" lon=\"2.30811786651611\"><ele>45.0576</ele><time>2007-04-15T08:54:13Z</time></trkpt><trkpt lat=\"48.869701385498\" lon=\"2.30820965766907\"><ele>44.213</ele><time>2007-04-15T08:54:14Z</time></trkpt><trkpt lat=\"48.8696060180664\" lon=\"2.30830454826355\"><ele>43.6365</ele><time>2007-04-15T08:54:15Z</time></trkpt><trkpt lat=\"48.8695106506348\" lon=\"2.3084614276886\"><ele>43.3493</ele><time>2007-04-15T08:54:16Z</time></trkpt><trkpt lat=\"48.8694152832031\" lon=\"2.30865859985352\"><ele>43.1819</ele><time>2007-04-15T08:54:17Z</time></trkpt><trkpt lat=\"48.8693313598633\" lon=\"2.30887341499329\"><ele>43.0695</ele><time>2007-04-15T08:54:18Z</time></trkpt><trkpt lat=\"48.8692512512207\" lon=\"2.30908060073853\"><ele>43.0105</ele><time>2007-04-15T08:54:19Z</time></trkpt><trkpt lat=\"48.8691787719727\" lon=\"2.30924391746521\"><ele>43.0967</ele><time>2007-04-15T08:54:20Z</time></trkpt><trkpt lat=\"48.8691215515137\" lon=\"2.30933380126953\"><ele>43.0489</ele><time>2007-04-15T08:54:21Z</time></trkpt><trkpt lat=\"48.8690643310547\" lon=\"2.30941772460938\"><ele>42.9077</ele><time>2007-04-15T08:54:22Z</time></trkpt><trkpt lat=\"48.8690528869629\" lon=\"2.30945086479187\"><ele>42.8817</ele><time>2007-04-15T08:54:23Z</time></trkpt><trkpt lat=\"48.8690490722656\" lon=\"2.30944752693176\"><ele>42.8646</ele><time>2007-04-15T08:54:24Z</time></trkpt><trkpt lat=\"48.8690414428711\" lon=\"2.30944085121155\"><ele>42.8307</ele><time>2007-04-15T08:54:25Z</time></trkpt><trkpt lat=\"48.8689613342285\" lon=\"2.30954074859619\"><ele>42.5137</ele><time>2007-04-15T08:54:26Z</time></trkpt><trkpt lat=\"48.8689384460449\" lon=\"2.30955934524536\"><ele>42.4073</ele><time>2007-04-15T08:54:27Z</time></trkpt><trkpt lat=\"48.8689117431641\" lon=\"2.30958604812622\"><ele>42.2756</ele><time>2007-04-15T08:54:28Z</time></trkpt><trkpt lat=\"48.8689651489258\" lon=\"2.30955600738525\"><ele>42.5316</ele><time>2007-04-15T08:54:29Z</time></trkpt><trkpt lat=\"48.8689613342285\" lon=\"2.30945682525635\"><ele>42.5122</ele><time>2007-04-15T08:54:30Z</time></trkpt><trkpt lat=\"48.868968963623\" lon=\"2.30945897102356\"><ele>42.5434</ele><time>2007-04-15T08:54:31Z</time></trkpt><trkpt lat=\"48.868968963623\" lon=\"2.30946397781372\"><ele>42.5437</ele><time>2007-04-15T08:54:32Z</time></trkpt><trkpt lat=\"48.8689651489258\" lon=\"2.30947375297546\"><ele>42.5284</ele><time>2007-04-15T08:54:33Z</time></trkpt><trkpt lat=\"48.8689460754394\" lon=\"2.30951476097107\"><ele>42.446</ele><time>2007-04-15T08:54:34Z</time></trkpt><trkpt lat=\"48.8689079284668\" lon=\"2.30960202217102\"><ele>42.2526</ele><time>2007-04-15T08:54:35Z</time></trkpt><trkpt lat=\"48.8689002990723\" lon=\"2.30962300300598\"><ele>42.2082</ele><time>2007-04-15T08:54:36Z</time></trkpt><trkpt lat=\"48.8688812255859\" lon=\"2.30966520309448\"><ele>42.0935</ele><time>2007-04-15T08:54:37Z</time></trkpt><trkpt lat=\"48.8690071105957\" lon=\"2.30954170227051\"><ele>42.7224</ele><time>2007-04-15T08:54:38Z</time></trkpt><trkpt lat=\"48.8690452575684\" lon=\"2.30949020385742\"><ele>42.8706</ele><time>2007-04-15T08:54:39Z</time></trkpt><trkpt lat=\"48.8690376281738\" lon=\"2.30958080291748\"><ele>42.8795</ele><time>2007-04-15T08:54:40Z</time></trkpt><trkpt lat=\"48.8690147399902\" lon=\"2.30966091156006\"><ele>42.796</ele><time>2007-04-15T08:54:41Z</time></trkpt><trkpt lat=\"48.8689651489258\" lon=\"2.30989336967468\"><ele>42.5449</ele><time>2007-04-15T08:54:42Z</time></trkpt><trkpt lat=\"48.8689270019531\" lon=\"2.31004071235657\"><ele>42.2182</ele><time>2007-04-15T08:54:43Z</time></trkpt><trkpt lat=\"48.8688430786133\" lon=\"2.31030416488647\"><ele>41.1032</ele><time>2007-04-15T08:54:44Z</time></trkpt><trkpt lat=\"48.8687744140625\" lon=\"2.31054639816284\"><ele>39.9413</ele><time>2007-04-15T08:54:45Z</time></trkpt><trkpt lat=\"48.8687210083008\" lon=\"2.31071925163269\"><ele>38.9449</ele><time>2007-04-15T08:54:46Z</time></trkpt><trkpt lat=\"48.8686599731445\" lon=\"2.31089401245117\"><ele>37.8212</ele><time>2007-04-15T08:54:47Z</time></trkpt><trkpt lat=\"48.8685760498047\" lon=\"2.31118011474609\"><ele>36.6015</ele><time>2007-04-15T08:54:48Z</time></trkpt><trkpt lat=\"48.8684883117676\" lon=\"2.3114230632782\"><ele>35.7778</ele><time>2007-04-15T08:54:49Z</time></trkpt><trkpt lat=\"48.8684043884277\" lon=\"2.31162548065186\"><ele>35.3169</ele><time>2007-04-15T08:54:50Z</time></trkpt><trkpt lat=\"48.868350982666\" lon=\"2.31179285049438\"><ele>34.624</ele><time>2007-04-15T08:54:51Z</time></trkpt><trkpt lat=\"48.8683166503906\" lon=\"2.31190514564514\"><ele>34.253</ele><time>2007-04-15T08:54:52Z</time></trkpt><trkpt lat=\"48.868293762207\" lon=\"2.31198287010193\"><ele>34.1351</ele><time>2007-04-15T08:54:53Z</time></trkpt><trkpt lat=\"48.8682441711426\" lon=\"2.31217312812805\"><ele>33.8418</ele><time>2007-04-15T08:54:54Z</time></trkpt><trkpt lat=\"48.8681869506836\" lon=\"2.31234192848206\"><ele>33.732</ele><time>2007-04-15T08:54:55Z</time></trkpt><trkpt lat=\"48.8681221008301\" lon=\"2.31259369850159\"><ele>34.0262</ele><time>2007-04-15T08:54:56Z</time></trkpt><trkpt lat=\"48.8680686950684\" lon=\"2.31279397010803\"><ele>34.9452</ele><time>2007-04-15T08:54:57Z</time></trkpt><trkpt lat=\"48.8680076599121\" lon=\"2.31299567222595\"><ele>35.8227</ele><time>2007-04-15T08:54:58Z</time></trkpt><trkpt lat=\"48.8679542541504\" lon=\"2.31315994262695\"><ele>36.4793</ele><time>2007-04-15T08:54:59Z</time></trkpt><trkpt lat=\"48.8678855895996\" lon=\"2.31334114074707\"><ele>37.1471</ele><time>2007-04-15T08:55:00Z</time></trkpt><trkpt lat=\"48.8678283691406\" lon=\"2.31350493431091\"><ele>37.2929</ele><time>2007-04-15T08:55:01Z</time></trkpt><trkpt lat=\"48.867790222168\" lon=\"2.31363224983215\"><ele>37.2804</ele><time>2007-04-15T08:55:02Z</time></trkpt><trkpt lat=\"48.8677406311035\" lon=\"2.31380748748779\"><ele>37.1238</ele><time>2007-04-15T08:55:03Z</time></trkpt><trkpt lat=\"48.8676605224609\" lon=\"2.31405830383301\"><ele>36.6251</ele><time>2007-04-15T08:55:04Z</time></trkpt><trkpt lat=\"48.867618560791\" lon=\"2.31419110298157\"><ele>36.2845</ele><time>2007-04-15T08:55:05Z</time></trkpt><trkpt lat=\"48.867546081543\" lon=\"2.31440830230713\"><ele>36.1106</ele><time>2007-04-15T08:55:06Z</time></trkpt><trkpt lat=\"48.8674697875977\" lon=\"2.31467604637146\"><ele>36.0161</ele><time>2007-04-15T08:55:07Z</time></trkpt><trkpt lat=\"48.8674125671387\" lon=\"2.31484317779541\"><ele>36.1309</ele><time>2007-04-15T08:55:08Z</time></trkpt><trkpt lat=\"48.8673324584961\" lon=\"2.31509137153626\"><ele>36.4462</ele><time>2007-04-15T08:55:09Z</time></trkpt><trkpt lat=\"48.8672904968262\" lon=\"2.31522941589355\"><ele>36.6412</ele><time>2007-04-15T08:55:10Z</time></trkpt><trkpt lat=\"48.8672409057617\" lon=\"2.3153703212738\"><ele>36.8982</ele><time>2007-04-15T08:55:11Z</time></trkpt><trkpt lat=\"48.8671875\" lon=\"2.31559300422668\"><ele>37.2837</ele><time>2007-04-15T08:55:12Z</time></trkpt><trkpt lat=\"48.8670959472656\" lon=\"2.31584787368774\"><ele>37.9558</ele><time>2007-04-15T08:55:13Z</time></trkpt><trkpt lat=\"48.8670196533203\" lon=\"2.31605505943298\"><ele>38.6531</ele><time>2007-04-15T08:55:14Z</time></trkpt><trkpt lat=\"48.8669624328613\" lon=\"2.3162100315094\"><ele>39.2947</ele><time>2007-04-15T08:55:15Z</time></trkpt><trkpt lat=\"48.8668937683106\" lon=\"2.31637978553772\"><ele>40.1623</ele><time>2007-04-15T08:55:16Z</time></trkpt><trkpt lat=\"48.8668403625488\" lon=\"2.31654405593872\"><ele>41.0138</ele><time>2007-04-15T08:55:17Z</time></trkpt><trkpt lat=\"48.866771697998\" lon=\"2.31673359870911\"><ele>41.5003</ele><time>2007-04-15T08:55:18Z</time></trkpt><trkpt lat=\"48.8667068481445\" lon=\"2.31694555282593\"><ele>40.3846</ele><time>2007-04-15T08:55:19Z</time></trkpt><trkpt lat=\"48.8666458129883\" lon=\"2.31714200973511\"><ele>38.9749</ele><time>2007-04-15T08:55:20Z</time></trkpt><trkpt lat=\"48.8666000366211\" lon=\"2.31731629371643\"><ele>37.4903</ele><time>2007-04-15T08:55:21Z</time></trkpt><trkpt lat=\"48.8665542602539\" lon=\"2.31744837760925\"><ele>36.4086</ele><time>2007-04-15T08:55:22Z</time></trkpt><trkpt lat=\"48.8664932250977\" lon=\"2.3176109790802\"><ele>36.2332</ele><time>2007-04-15T08:55:23Z</time></trkpt><trkpt lat=\"48.8664093017578\" lon=\"2.31781077384949\"><ele>36.4277</ele><time>2007-04-15T08:55:24Z</time></trkpt><trkpt lat=\"48.8663711547852\" lon=\"2.31798458099365\"><ele>36.5072</ele><time>2007-04-15T08:55:25Z</time></trkpt><trkpt lat=\"48.8663024902344\" lon=\"2.31818771362305\"><ele>36.3119</ele><time>2007-04-15T08:55:26Z</time></trkpt><trkpt lat=\"48.8662643432617\" lon=\"2.3183217048645\"><ele>36.1018</ele><time>2007-04-15T08:55:27Z</time></trkpt><trkpt lat=\"48.8662033081055\" lon=\"2.31849765777588\"><ele>35.7735</ele><time>2007-04-15T08:55:28Z</time></trkpt><trkpt lat=\"48.8661346435547\" lon=\"2.3187050819397\"><ele>35.4542</ele><time>2007-04-15T08:55:29Z</time></trkpt><trkpt lat=\"48.8660888671875\" lon=\"2.3188591003418\"><ele>35.2773</ele><time>2007-04-15T08:55:30Z</time></trkpt><trkpt lat=\"48.866039276123\" lon=\"2.31902670860291\"><ele>35.1092</ele><time>2007-04-15T08:55:31Z</time></trkpt><trkpt lat=\"48.8659820556641\" lon=\"2.31920504570007\"><ele>34.8249</ele><time>2007-04-15T08:55:32Z</time></trkpt><trkpt lat=\"48.8659324645996\" lon=\"2.31938910484314\"><ele>34.1562</ele><time>2007-04-15T08:55:33Z</time></trkpt><trkpt lat=\"48.8658561706543\" lon=\"2.31959390640259\"><ele>33.1538</ele><time>2007-04-15T08:55:34Z</time></trkpt><trkpt lat=\"48.8658447265625\" lon=\"2.31963014602661\"><ele>32.9788</ele><time>2007-04-15T08:55:35Z</time></trkpt><trkpt lat=\"48.8657913208008\" lon=\"2.31981897354126\"><ele>32.4016</ele><time>2007-04-15T08:55:36Z</time></trkpt><trkpt lat=\"48.8657493591309\" lon=\"2.31996607780457\"><ele>32.0691</ele><time>2007-04-15T08:55:37Z</time></trkpt><trkpt lat=\"48.8656997680664\" lon=\"2.32011437416077\"><ele>32.1592</ele><time>2007-04-15T08:55:38Z</time></trkpt><trkpt lat=\"48.8656349182129\" lon=\"2.32030367851257\"><ele>32.4512</ele><time>2007-04-15T08:55:39Z</time></trkpt><trkpt lat=\"48.8656120300293\" lon=\"2.32035756111145\"><ele>32.543</ele><time>2007-04-15T08:55:40Z</time></trkpt><trkpt lat=\"48.865478515625\" lon=\"2.32042765617371\"><ele>32.7317</ele><time>2007-04-15T08:55:41Z</time></trkpt><trkpt lat=\"48.8653335571289\" lon=\"2.32043051719666\"><ele>32.8265</ele><time>2007-04-15T08:55:42Z</time></trkpt><trkpt lat=\"48.8652305603027\" lon=\"2.32044553756714\"><ele>32.9214</ele><time>2007-04-15T08:55:43Z</time></trkpt><trkpt lat=\"48.8651275634766\" lon=\"2.32046175003052\"><ele>33.0234</ele><time>2007-04-15T08:55:44Z</time></trkpt><trkpt lat=\"48.8650093078613\" lon=\"2.32045292854309\"><ele>33.081</ele><time>2007-04-15T08:55:45Z</time></trkpt><trkpt lat=\"48.8649139404297\" lon=\"2.32045269012451\"><ele>32.936</ele><time>2007-04-15T08:55:46Z</time></trkpt><trkpt lat=\"48.8647880554199\" lon=\"2.32053565979004\"><ele>32.9404</ele><time>2007-04-15T08:55:47Z</time></trkpt><trkpt lat=\"48.8647613525391\" lon=\"2.32058262825012\"><ele>33.0258</ele><time>2007-04-15T08:55:48Z</time></trkpt><trkpt lat=\"48.8647308349609\" lon=\"2.32080268859863\"><ele>33.5916</ele><time>2007-04-15T08:55:49Z</time></trkpt><trkpt lat=\"48.8647613525391\" lon=\"2.32099533081055\"><ele>34.4355</ele><time>2007-04-15T08:55:50Z</time></trkpt><trkpt lat=\"48.8648262023926\" lon=\"2.32113456726074\"><ele>35.162</ele><time>2007-04-15T08:55:51Z</time></trkpt><trkpt lat=\"48.8649215698242\" lon=\"2.32129096984863\"><ele>36.0509</ele><time>2007-04-15T08:55:52Z</time></trkpt><trkpt lat=\"48.8650093078613\" lon=\"2.32141971588135\"><ele>36.7877</ele><time>2007-04-15T08:55:53Z</time></trkpt><trkpt lat=\"48.865119934082\" lon=\"2.32153367996216\"><ele>36.9758</ele><time>2007-04-15T08:55:54Z</time></trkpt><trkpt lat=\"48.8652191162109\" lon=\"2.32164907455444\"><ele>37.1378</ele><time>2007-04-15T08:55:55Z</time></trkpt><trkpt lat=\"48.8653373718262\" lon=\"2.321772813797\"><ele>36.6338</ele><time>2007-04-15T08:55:56Z</time></trkpt><trkpt lat=\"48.8654441833496\" lon=\"2.32187366485596\"><ele>36.1689</ele><time>2007-04-15T08:55:57Z</time></trkpt><trkpt lat=\"48.865550994873\" lon=\"2.32196617126465\"><ele>35.7729</ele><time>2007-04-15T08:55:58Z</time></trkpt><trkpt lat=\"48.8656806945801\" lon=\"2.32204341888428\"><ele>35.3839</ele><time>2007-04-15T08:55:59Z</time></trkpt><trkpt lat=\"48.8658065795898\" lon=\"2.32209706306458\"><ele>35.0632</ele><time>2007-04-15T08:56:00Z</time></trkpt><trkpt lat=\"48.8659210205078\" lon=\"2.32212257385254\"><ele>35.6889</ele><time>2007-04-15T08:56:01Z</time></trkpt><trkpt lat=\"48.8660163879394\" lon=\"2.3221321105957\"><ele>36.4407</ele><time>2007-04-15T08:56:02Z</time></trkpt><trkpt lat=\"48.8661155700684\" lon=\"2.32213830947876\"><ele>37.2238</ele><time>2007-04-15T08:56:03Z</time></trkpt><trkpt lat=\"48.8661613464356\" lon=\"2.32213544845581\"><ele>37.5831</ele><time>2007-04-15T08:56:04Z</time></trkpt><trkpt lat=\"48.8662796020508\" lon=\"2.32210922241211\"><ele>38.4975</ele><time>2007-04-15T08:56:05Z</time></trkpt><trkpt lat=\"48.8663444519043\" lon=\"2.32209086418152\"><ele>38.9923</ele><time>2007-04-15T08:56:06Z</time></trkpt><trkpt lat=\"48.866455078125\" lon=\"2.32219123840332\"><ele>39.9462</ele><time>2007-04-15T08:56:07Z</time></trkpt><trkpt lat=\"48.8664207458496\" lon=\"2.32244300842285\"><ele>39.8861</ele><time>2007-04-15T08:56:08Z</time></trkpt><trkpt lat=\"48.866397857666\" lon=\"2.32262849807739\"><ele>39.8415</ele><time>2007-04-15T08:56:09Z</time></trkpt><trkpt lat=\"48.8663787841797\" lon=\"2.32290410995483\"><ele>39.9168</ele><time>2007-04-15T08:56:10Z</time></trkpt><trkpt lat=\"48.8663711547852\" lon=\"2.32310461997986\"><ele>40.0323</ele><time>2007-04-15T08:56:11Z</time></trkpt><trkpt lat=\"48.8663673400879\" lon=\"2.32326626777649\"><ele>40.1462</ele><time>2007-04-15T08:56:12Z</time></trkpt><trkpt lat=\"48.8663597106934\" lon=\"2.32346248626709\"><ele>40.4111</ele><time>2007-04-15T08:56:13Z</time></trkpt><trkpt lat=\"48.8663558959961\" lon=\"2.32368731498718\"><ele>40.8265</ele><time>2007-04-15T08:56:14Z</time></trkpt><trkpt lat=\"48.8663482666016\" lon=\"2.32394576072693\"><ele>41.2786</ele><time>2007-04-15T08:56:15Z</time></trkpt><trkpt lat=\"48.8663101196289\" lon=\"2.32413768768311\"><ele>41.3782</ele><time>2007-04-15T08:56:16Z</time></trkpt><trkpt lat=\"48.8662338256836\" lon=\"2.32438158988953\"><ele>41.5433</ele><time>2007-04-15T08:56:17Z</time></trkpt><trkpt lat=\"48.8661727905273\" lon=\"2.32457375526428\"><ele>41.8011</ele><time>2007-04-15T08:56:18Z</time></trkpt><trkpt lat=\"48.8661041259766\" lon=\"2.32477116584778\"><ele>42.1441</ele><time>2007-04-15T08:56:19Z</time></trkpt><trkpt lat=\"48.8660659790039\" lon=\"2.32494974136353\"><ele>42.6468</ele><time>2007-04-15T08:56:20Z</time></trkpt><trkpt lat=\"48.8659706115723\" lon=\"2.3251781463623\"><ele>42.8865</ele><time>2007-04-15T08:56:21Z</time></trkpt><trkpt lat=\"48.8659057617188\" lon=\"2.32539129257202\"><ele>43.159</ele><time>2007-04-15T08:56:22Z</time></trkpt><trkpt lat=\"48.8658561706543\" lon=\"2.32559156417847\"><ele>43.4825</ele><time>2007-04-15T08:56:23Z</time></trkpt><trkpt lat=\"48.8657913208008\" lon=\"2.32577347755432\"><ele>43.5611</ele><time>2007-04-15T08:56:24Z</time></trkpt><trkpt lat=\"48.8657417297363\" lon=\"2.32594156265259\"><ele>43.6145</ele><time>2007-04-15T08:56:25Z</time></trkpt><trkpt lat=\"48.8656768798828\" lon=\"2.32609629631042\"><ele>43.5639</ele><time>2007-04-15T08:56:26Z</time></trkpt><trkpt lat=\"48.8656272888184\" lon=\"2.32623100280762\"><ele>43.5889</ele><time>2007-04-15T08:56:27Z</time></trkpt><trkpt lat=\"48.8655853271484\" lon=\"2.32641696929932\"><ele>43.8235</ele><time>2007-04-15T08:56:28Z</time></trkpt><trkpt lat=\"48.8655586242676\" lon=\"2.32659721374512\"><ele>44.1576</ele><time>2007-04-15T08:56:29Z</time></trkpt><trkpt lat=\"48.8655281066894\" lon=\"2.32675623893738\"><ele>44.4624</ele><time>2007-04-15T08:56:30Z</time></trkpt><trkpt lat=\"48.8654747009277\" lon=\"2.32693791389465\"><ele>44.7794</ele><time>2007-04-15T08:56:31Z</time></trkpt><trkpt lat=\"48.8653984069824\" lon=\"2.32714200019836\"><ele>45.1266</ele><time>2007-04-15T08:56:32Z</time></trkpt><trkpt lat=\"48.8653297424316\" lon=\"2.32726907730103\"><ele>45.2979</ele><time>2007-04-15T08:56:33Z</time></trkpt><trkpt lat=\"48.8652420043945\" lon=\"2.32743883132935\"><ele>45.6202</ele><time>2007-04-15T08:56:34Z</time></trkpt><trkpt lat=\"48.8651657104492\" lon=\"2.3276674747467\"><ele>45.7176</ele><time>2007-04-15T08:56:35Z</time></trkpt><trkpt lat=\"48.865119934082\" lon=\"2.32792663574219\"><ele>45.7964</ele><time>2007-04-15T08:56:36Z</time></trkpt><trkpt lat=\"48.8650894165039\" lon=\"2.32805943489075\"><ele>45.8492</ele><time>2007-04-15T08:56:37Z</time></trkpt><trkpt lat=\"48.865047454834\" lon=\"2.32824397087097\"><ele>45.9619</ele><time>2007-04-15T08:56:38Z</time></trkpt><trkpt lat=\"48.8649940490723\" lon=\"2.32839870452881\"><ele>45.9852</ele><time>2007-04-15T08:56:39Z</time></trkpt><trkpt lat=\"48.8649291992188\" lon=\"2.32859539985657\"><ele>45.8034</ele><time>2007-04-15T08:56:40Z</time></trkpt><trkpt lat=\"48.8648796081543\" lon=\"2.328777551651\"><ele>45.634</ele><time>2007-04-15T08:56:41Z</time></trkpt><trkpt lat=\"48.8648300170898\" lon=\"2.32893466949463\"><ele>45.4448</ele><time>2007-04-15T08:56:42Z</time></trkpt><trkpt lat=\"48.8647880554199\" lon=\"2.32910394668579\"><ele>45.2561</ele><time>2007-04-15T08:56:43Z</time></trkpt><trkpt lat=\"48.8646850585938\" lon=\"2.32929158210754\"><ele>44.9595</ele><time>2007-04-15T08:56:44Z</time></trkpt><trkpt lat=\"48.8646202087402\" lon=\"2.32941746711731\"><ele>44.7966</ele><time>2007-04-15T08:56:45Z</time></trkpt><trkpt lat=\"48.8645286560059\" lon=\"2.32965731620789\"><ele>44.5589</ele><time>2007-04-15T08:56:46Z</time></trkpt><trkpt lat=\"48.8644561767578\" lon=\"2.32981276512146\"><ele>44.3116</ele><time>2007-04-15T08:56:47Z</time></trkpt><trkpt lat=\"48.8644180297852\" lon=\"2.32995367050171\"><ele>44.1898</ele><time>2007-04-15T08:56:48Z</time></trkpt><trkpt lat=\"48.8643417358398\" lon=\"2.33019542694092\"><ele>44.2601</ele><time>2007-04-15T08:56:49Z</time></trkpt><trkpt lat=\"48.8642539978027\" lon=\"2.33034992218018\"><ele>44.215</ele><time>2007-04-15T08:56:50Z</time></trkpt><trkpt lat=\"48.8641929626465\" lon=\"2.33051323890686\"><ele>44.3386</ele><time>2007-04-15T08:56:51Z</time></trkpt><trkpt lat=\"48.8641548156738\" lon=\"2.3307363986969\"><ele>44.7171</ele><time>2007-04-15T08:56:52Z</time></trkpt><trkpt lat=\"48.8641128540039\" lon=\"2.33087682723999\"><ele>44.6861</ele><time>2007-04-15T08:56:53Z</time></trkpt><trkpt lat=\"48.8640632629394\" lon=\"2.33108496665955\"><ele>44.1642</ele><time>2007-04-15T08:56:54Z</time></trkpt><trkpt lat=\"48.8640213012695\" lon=\"2.33126187324524\"><ele>43.6983</ele><time>2007-04-15T08:56:55Z</time></trkpt><trkpt lat=\"48.863941192627\" lon=\"2.3314197063446\"><ele>43.0237</ele><time>2007-04-15T08:56:56Z</time></trkpt><trkpt lat=\"48.8638458251953\" lon=\"2.33163118362427\"><ele>42.1339</ele><time>2007-04-15T08:56:57Z</time></trkpt><trkpt lat=\"48.8638076782227\" lon=\"2.33184719085693\"><ele>42.6826</ele><time>2007-04-15T08:56:58Z</time></trkpt><trkpt lat=\"48.8637542724609\" lon=\"2.3320484161377\"><ele>43.3533</ele><time>2007-04-15T08:56:59Z</time></trkpt><trkpt lat=\"48.863712310791\" lon=\"2.33222150802612\"><ele>43.9973</ele><time>2007-04-15T08:57:00Z</time></trkpt><trkpt lat=\"48.8635902404785\" lon=\"2.33239960670471\"><ele>44.3968</ele><time>2007-04-15T08:57:01Z</time></trkpt><trkpt lat=\"48.8635101318359\" lon=\"2.33255743980408\"><ele>44.8683</ele><time>2007-04-15T08:57:02Z</time></trkpt><trkpt lat=\"48.8634643554688\" lon=\"2.33277106285095\"><ele>45.6194</ele><time>2007-04-15T08:57:03Z</time></trkpt><trkpt lat=\"48.8633804321289\" lon=\"2.33288979530334\"><ele>45.9613</ele><time>2007-04-15T08:57:04Z</time></trkpt><trkpt lat=\"48.8633270263672\" lon=\"2.33302402496338\"><ele>46.5039</ele><time>2007-04-15T08:57:05Z</time></trkpt><trkpt lat=\"48.8632507324219\" lon=\"2.33319973945618\"><ele>47.1249</ele><time>2007-04-15T08:57:06Z</time></trkpt><trkpt lat=\"48.8630714416504\" lon=\"2.33329772949219\"><ele>46.94</ele><time>2007-04-15T08:57:07Z</time></trkpt><trkpt lat=\"48.8630905151367\" lon=\"2.33351230621338\"><ele>47.4573</ele><time>2007-04-15T08:57:08Z</time></trkpt><trkpt lat=\"48.863151550293\" lon=\"2.33370447158813\"><ele>48.1959</ele><time>2007-04-15T08:57:09Z</time></trkpt><trkpt lat=\"48.8630676269531\" lon=\"2.33386468887329\"><ele>47.9398</ele><time>2007-04-15T08:57:10Z</time></trkpt><trkpt lat=\"48.8630180358887\" lon=\"2.33392238616943\"><ele>47.6483</ele><time>2007-04-15T08:57:11Z</time></trkpt><trkpt lat=\"48.8629722595215\" lon=\"2.33402109146118\"><ele>47.3881</ele><time>2007-04-15T08:57:12Z</time></trkpt><trkpt lat=\"48.8628768920898\" lon=\"2.3341691493988\"><ele>46.6158</ele><time>2007-04-15T08:57:13Z</time></trkpt><trkpt lat=\"48.8628540039062\" lon=\"2.334388256073\"><ele>46.2125</ele><time>2007-04-15T08:57:14Z</time></trkpt><trkpt lat=\"48.862922668457\" lon=\"2.33461141586304\"><ele>46.5085</ele><time>2007-04-15T08:57:15Z</time></trkpt><trkpt lat=\"48.8628921508789\" lon=\"2.33474516868591\"><ele>46.1521</ele><time>2007-04-15T08:57:16Z</time></trkpt><trkpt lat=\"48.8628463745117\" lon=\"2.33498859405518\"><ele>45.6717</ele><time>2007-04-15T08:57:17Z</time></trkpt><trkpt lat=\"48.8628425598144\" lon=\"2.33521318435669\"><ele>46.1418</ele><time>2007-04-15T08:57:18Z</time></trkpt><trkpt lat=\"48.862720489502\" lon=\"2.33535289764404\"><ele>46.192</ele><time>2007-04-15T08:57:19Z</time></trkpt><trkpt lat=\"48.8627166748047\" lon=\"2.3354754447937\"><ele>46.5805</ele><time>2007-04-15T08:57:20Z</time></trkpt><trkpt lat=\"48.862678527832\" lon=\"2.33564782142639\"><ele>47.1338</ele><time>2007-04-15T08:57:21Z</time></trkpt><trkpt lat=\"48.8625640869141\" lon=\"2.33586740493774\"><ele>47.8759</ele><time>2007-04-15T08:57:22Z</time></trkpt><trkpt lat=\"48.8625259399414\" lon=\"2.33610200881958\"><ele>47.6264</ele><time>2007-04-15T08:57:23Z</time></trkpt><trkpt lat=\"48.8625144958496\" lon=\"2.33637356758118\"><ele>47.3118</ele><time>2007-04-15T08:57:24Z</time></trkpt><trkpt lat=\"48.862491607666\" lon=\"2.3365752696991\"><ele>47.1478</ele><time>2007-04-15T08:57:25Z</time></trkpt><trkpt lat=\"48.8625221252441\" lon=\"2.33690595626831\"><ele>46.6332</ele><time>2007-04-15T08:57:26Z</time></trkpt><trkpt lat=\"48.8624954223633\" lon=\"2.3371160030365\"><ele>46.4739</ele><time>2007-04-15T08:57:27Z</time></trkpt><trkpt lat=\"48.8624382019043\" lon=\"2.33729696273804\"><ele>46.372</ele><time>2007-04-15T08:57:28Z</time></trkpt><trkpt lat=\"48.8623542785644\" lon=\"2.3374457359314\"><ele>46.2741</ele><time>2007-04-15T08:57:29Z</time></trkpt><trkpt lat=\"48.8623237609863\" lon=\"2.33766674995422\"><ele>45.8844</ele><time>2007-04-15T08:57:30Z</time></trkpt><trkpt lat=\"48.8622055053711\" lon=\"2.33779883384705\"><ele>45.6146</ele><time>2007-04-15T08:57:31Z</time></trkpt><trkpt lat=\"48.8620071411133\" lon=\"2.33791589736938\"><ele>45.2068</ele><time>2007-04-15T08:57:32Z</time></trkpt><trkpt lat=\"48.8617935180664\" lon=\"2.33801174163818\"><ele>44.6719</ele><time>2007-04-15T08:57:33Z</time></trkpt><trkpt lat=\"48.8617362976074\" lon=\"2.33821797370911\"><ele>43.6861</ele><time>2007-04-15T08:57:34Z</time></trkpt><trkpt lat=\"48.8616943359375\" lon=\"2.33841443061829\"><ele>43.2643</ele><time>2007-04-15T08:57:35Z</time></trkpt><trkpt lat=\"48.8616523742676\" lon=\"2.33853507041931\"><ele>43.6391</ele><time>2007-04-15T08:57:36Z</time></trkpt><trkpt lat=\"48.8615798950195\" lon=\"2.33880138397217\"><ele>44.9306</ele><time>2007-04-15T08:57:37Z</time></trkpt><trkpt lat=\"48.8615798950195\" lon=\"2.33902788162231\"><ele>45.361</ele><time>2007-04-15T08:57:38Z</time></trkpt><trkpt lat=\"48.8615455627441\" lon=\"2.33921670913696\"><ele>46.0423</ele><time>2007-04-15T08:57:39Z</time></trkpt><trkpt lat=\"48.8614273071289\" lon=\"2.33934736251831\"><ele>47.0925</ele><time>2007-04-15T08:57:40Z</time></trkpt><trkpt lat=\"48.8613548278809\" lon=\"2.33954572677612\"><ele>47.703</ele><time>2007-04-15T08:57:41Z</time></trkpt><trkpt lat=\"48.8614082336426\" lon=\"2.33978462219238\"><ele>47.9872</ele><time>2007-04-15T08:57:42Z</time></trkpt><trkpt lat=\"48.8613777160644\" lon=\"2.33997774124146\"><ele>48.2738</ele><time>2007-04-15T08:57:43Z</time></trkpt><trkpt lat=\"48.8611869812012\" lon=\"2.34010004997253\"><ele>47.7796</ele><time>2007-04-15T08:57:44Z</time></trkpt><trkpt lat=\"48.8611335754394\" lon=\"2.34025549888611\"><ele>47.5244</ele><time>2007-04-15T08:57:45Z</time></trkpt><trkpt lat=\"48.8610954284668\" lon=\"2.34036254882812\"><ele>47.3308</ele><time>2007-04-15T08:57:46Z</time></trkpt><trkpt lat=\"48.8610496520996\" lon=\"2.34056353569031\"><ele>47.0185</ele><time>2007-04-15T08:57:47Z</time></trkpt><trkpt lat=\"48.861011505127\" lon=\"2.3407666683197\"><ele>46.7043</ele><time>2007-04-15T08:57:48Z</time></trkpt><trkpt lat=\"48.8609275817871\" lon=\"2.34092736244202\"><ele>46.5522</ele><time>2007-04-15T08:57:49Z</time></trkpt><trkpt lat=\"48.8608245849609\" lon=\"2.34108567237854\"><ele>46.6203</ele><time>2007-04-15T08:57:50Z</time></trkpt><trkpt lat=\"48.8607978820801\" lon=\"2.34127140045166\"><ele>47.0917</ele><time>2007-04-15T08:57:51Z</time></trkpt><trkpt lat=\"48.8607559204102\" lon=\"2.34139919281006\"><ele>47.4177</ele><time>2007-04-15T08:57:52Z</time></trkpt><trkpt lat=\"48.8607215881348\" lon=\"2.34149312973022\"><ele>47.6394</ele><time>2007-04-15T08:57:53Z</time></trkpt><trkpt lat=\"48.8606491088867\" lon=\"2.34168863296509\"><ele>48.0205</ele><time>2007-04-15T08:57:54Z</time></trkpt><trkpt lat=\"48.8605690002441\" lon=\"2.34189081192017\"><ele>48.1837</ele><time>2007-04-15T08:57:55Z</time></trkpt><trkpt lat=\"48.8605079650879\" lon=\"2.34199738502502\"><ele>48.2419</ele><time>2007-04-15T08:57:56Z</time></trkpt><trkpt lat=\"48.8604469299316\" lon=\"2.34216070175171\"><ele>48.318</ele><time>2007-04-15T08:57:57Z</time></trkpt><trkpt lat=\"48.8604469299316\" lon=\"2.34225988388062\"><ele>48.3818</ele><time>2007-04-15T08:57:58Z</time></trkpt><trkpt lat=\"48.8604164123535\" lon=\"2.34242987632751\"><ele>48.4576</ele><time>2007-04-15T08:57:59Z</time></trkpt><trkpt lat=\"48.8603019714356\" lon=\"2.34259986877441\"><ele>48.8313</ele><time>2007-04-15T08:58:00Z</time></trkpt><trkpt lat=\"48.8602180480957\" lon=\"2.34269690513611\"><ele>49.2576</ele><time>2007-04-15T08:58:01Z</time></trkpt><trkpt lat=\"48.8601379394531\" lon=\"2.34286570549011\"><ele>50.1418</ele><time>2007-04-15T08:58:02Z</time></trkpt><trkpt lat=\"48.8600616455078\" lon=\"2.34309911727905\"><ele>51.5091</ele><time>2007-04-15T08:58:03Z</time></trkpt><trkpt lat=\"48.8600769042969\" lon=\"2.34328079223633\"><ele>52.5176</ele><time>2007-04-15T08:58:04Z</time></trkpt><trkpt lat=\"48.8600692749023\" lon=\"2.34342670440674\"><ele>52.9272</ele><time>2007-04-15T08:58:05Z</time></trkpt><trkpt lat=\"48.8600654602051\" lon=\"2.34346222877502\"><ele>52.9733</ele><time>2007-04-15T08:58:06Z</time></trkpt><trkpt lat=\"48.8600006103516\" lon=\"2.34362149238586\"><ele>53.3438</ele><time>2007-04-15T08:58:07Z</time></trkpt><trkpt lat=\"48.8599586486816\" lon=\"2.34387397766113\"><ele>53.5844</ele><time>2007-04-15T08:58:08Z</time></trkpt><trkpt lat=\"48.8599510192871\" lon=\"2.34391498565674\"><ele>53.6159</ele><time>2007-04-15T08:58:09Z</time></trkpt><trkpt lat=\"48.8599662780762\" lon=\"2.34410977363586\"><ele>53.8563</ele><time>2007-04-15T08:58:10Z</time></trkpt><trkpt lat=\"48.8599319458008\" lon=\"2.3442120552063\"><ele>53.7822</ele><time>2007-04-15T08:58:11Z</time></trkpt><trkpt lat=\"48.8598442077637\" lon=\"2.34442806243896\"><ele>53.3124</ele><time>2007-04-15T08:58:12Z</time></trkpt><trkpt lat=\"48.8597602844238\" lon=\"2.34459066390991\"><ele>52.9159</ele><time>2007-04-15T08:58:13Z</time></trkpt><trkpt lat=\"48.8596687316894\" lon=\"2.34476518630981\"><ele>52.4867</ele><time>2007-04-15T08:58:14Z</time></trkpt><trkpt lat=\"48.8596496582031\" lon=\"2.34495234489441\"><ele>52.2164</ele><time>2007-04-15T08:58:15Z</time></trkpt><trkpt lat=\"48.8595695495606\" lon=\"2.34506440162659\"><ele>51.8175</ele><time>2007-04-15T08:58:16Z</time></trkpt><trkpt lat=\"48.8595199584961\" lon=\"2.34524703025818\"><ele>51.3452</ele><time>2007-04-15T08:58:17Z</time></trkpt><trkpt lat=\"48.8594436645508\" lon=\"2.34540581703186\"><ele>51.0173</ele><time>2007-04-15T08:58:18Z</time></trkpt><trkpt lat=\"48.8594284057617\" lon=\"2.34558391571045\"><ele>50.7479</ele><time>2007-04-15T08:58:19Z</time></trkpt><trkpt lat=\"48.8594017028809\" lon=\"2.34579515457153\"><ele>50.4876</ele><time>2007-04-15T08:58:20Z</time></trkpt><trkpt lat=\"48.8593215942383\" lon=\"2.3459312915802\"><ele>50.1798</ele><time>2007-04-15T08:58:21Z</time></trkpt><trkpt lat=\"48.8593063354492\" lon=\"2.3459575176239\"><ele>50.0937</ele><time>2007-04-15T08:58:22Z</time></trkpt><trkpt lat=\"48.8591804504394\" lon=\"2.34617018699646\"><ele>49.3567</ele><time>2007-04-15T08:58:23Z</time></trkpt><trkpt lat=\"48.8591270446777\" lon=\"2.34631276130676\"><ele>48.7535</ele><time>2007-04-15T08:58:24Z</time></trkpt><trkpt lat=\"48.859130859375\" lon=\"2.34651160240173\"><ele>47.8143</ele><time>2007-04-15T08:58:25Z</time></trkpt><trkpt lat=\"48.8590660095215\" lon=\"2.3466477394104\"><ele>47.3269</ele><time>2007-04-15T08:58:26Z</time></trkpt><trkpt lat=\"48.858959197998\" lon=\"2.34684753417969\"><ele>46.9008</ele><time>2007-04-15T08:58:27Z</time></trkpt><trkpt lat=\"48.8588752746582\" lon=\"2.34712171554565\"><ele>46.2521</ele><time>2007-04-15T08:58:28Z</time></trkpt><trkpt lat=\"48.8588256835938\" lon=\"2.34732818603516\"><ele>45.7617</ele><time>2007-04-15T08:58:29Z</time></trkpt><trkpt lat=\"48.858757019043\" lon=\"2.34751558303833\"><ele>45.522</ele><time>2007-04-15T08:58:30Z</time></trkpt><trkpt lat=\"48.858715057373\" lon=\"2.34766101837158\"><ele>46.0845</ele><time>2007-04-15T08:58:31Z</time></trkpt><trkpt lat=\"48.8586463928223\" lon=\"2.3478319644928\"><ele>46.7203</ele><time>2007-04-15T08:58:32Z</time></trkpt><trkpt lat=\"48.8586349487305\" lon=\"2.34786152839661\"><ele>46.8191</ele><time>2007-04-15T08:58:33Z</time></trkpt><trkpt lat=\"48.858585357666\" lon=\"2.34805822372437\"><ele>47.3703</ele><time>2007-04-15T08:58:34Z</time></trkpt><trkpt lat=\"48.858512878418\" lon=\"2.34826135635376\"><ele>47.8578</ele><time>2007-04-15T08:58:35Z</time></trkpt><trkpt lat=\"48.8584403991699\" lon=\"2.34845280647278\"><ele>48</ele><time>2007-04-15T08:58:36Z</time></trkpt><trkpt lat=\"48.8583831787109\" lon=\"2.34865784645081\"><ele>48</ele><time>2007-04-15T08:58:37Z</time></trkpt><trkpt lat=\"48.8582916259766\" lon=\"2.34885478019714\"><ele>47.5935</ele><time>2007-04-15T08:58:38Z</time></trkpt><trkpt lat=\"48.8582534790039\" lon=\"2.34903407096863\"><ele>47.2835</ele><time>2007-04-15T08:58:39Z</time></trkpt><trkpt lat=\"48.8581733703613\" lon=\"2.34918403625488\"><ele>46.6675</ele><time>2007-04-15T08:58:40Z</time></trkpt><trkpt lat=\"48.8581008911133\" lon=\"2.34935307502747\"><ele>46.3229</ele><time>2007-04-15T08:58:41Z</time></trkpt><trkpt lat=\"48.8580551147461\" lon=\"2.34957957267761\"><ele>46.4909</ele><time>2007-04-15T08:58:42Z</time></trkpt><trkpt lat=\"48.858024597168\" lon=\"2.34974050521851\"><ele>46.7589</ele><time>2007-04-15T08:58:43Z</time></trkpt><trkpt lat=\"48.8580207824707\" lon=\"2.34996008872986\"><ele>47.2793</ele><time>2007-04-15T08:58:44Z</time></trkpt><trkpt lat=\"48.8580284118652\" lon=\"2.35018348693848\"><ele>47.4034</ele><time>2007-04-15T08:58:45Z</time></trkpt><trkpt lat=\"48.8579292297363\" lon=\"2.35037040710449\"><ele>47.2962</ele><time>2007-04-15T08:58:46Z</time></trkpt><trkpt lat=\"48.8577995300293\" lon=\"2.35056972503662\"><ele>46.8182</ele><time>2007-04-15T08:58:47Z</time></trkpt><trkpt lat=\"48.8576812744141\" lon=\"2.3507604598999\"><ele>46.0373</ele><time>2007-04-15T08:58:48Z</time></trkpt><trkpt lat=\"48.8576622009277\" lon=\"2.35093474388123\"><ele>45.3629</ele><time>2007-04-15T08:58:49Z</time></trkpt><trkpt lat=\"48.8575782775879\" lon=\"2.35113263130188\"><ele>44.0403</ele><time>2007-04-15T08:58:50Z</time></trkpt><trkpt lat=\"48.8575401306152\" lon=\"2.35132050514221\"><ele>42.9387</ele><time>2007-04-15T08:58:51Z</time></trkpt><trkpt lat=\"48.8574066162109\" lon=\"2.35153865814209\"><ele>41.287</ele><time>2007-04-15T08:58:52Z</time></trkpt><trkpt lat=\"48.857292175293\" lon=\"2.35167598724365\"><ele>40.5655</ele><time>2007-04-15T08:58:53Z</time></trkpt><trkpt lat=\"48.8572387695312\" lon=\"2.35186147689819\"><ele>41.7618</ele><time>2007-04-15T08:58:54Z</time></trkpt><trkpt lat=\"48.8572158813477\" lon=\"2.35205984115601\"><ele>43.1597</ele><time>2007-04-15T08:58:55Z</time></trkpt><trkpt lat=\"48.8572235107422\" lon=\"2.35228705406189\"><ele>44.7998</ele><time>2007-04-15T08:58:56Z</time></trkpt><trkpt lat=\"48.8572311401367\" lon=\"2.3523850440979\"><ele>45.4994</ele><time>2007-04-15T08:58:57Z</time></trkpt><trkpt lat=\"48.8571891784668\" lon=\"2.35261249542236\"><ele>46.9312</ele><time>2007-04-15T08:58:58Z</time></trkpt><trkpt lat=\"48.8571472167969\" lon=\"2.35281562805176\"><ele>47.8942</ele><time>2007-04-15T08:58:59Z</time></trkpt><trkpt lat=\"48.8570899963379\" lon=\"2.35299181938171\"><ele>48.5812</ele><time>2007-04-15T08:59:00Z</time></trkpt><trkpt lat=\"48.8570327758789\" lon=\"2.35317635536194\"><ele>49.1552</ele><time>2007-04-15T08:59:01Z</time></trkpt><trkpt lat=\"48.8569869995117\" lon=\"2.35324668884277\"><ele>49.2338</ele><time>2007-04-15T08:59:02Z</time></trkpt><trkpt lat=\"48.8568992614746\" lon=\"2.35345792770386\"><ele>48.7514</ele><time>2007-04-15T08:59:03Z</time></trkpt><trkpt lat=\"48.8568572998047\" lon=\"2.35369086265564\"><ele>47.8242</ele><time>2007-04-15T08:59:04Z</time></trkpt><trkpt lat=\"48.8568992614746\" lon=\"2.35391163825989\"><ele>47.4219</ele><time>2007-04-15T08:59:05Z</time></trkpt><trkpt lat=\"48.8568916320801\" lon=\"2.35412073135376\"><ele>46.7554</ele><time>2007-04-15T08:59:06Z</time></trkpt><trkpt lat=\"48.8568572998047\" lon=\"2.3543210029602\"><ele>46.4464</ele><time>2007-04-15T08:59:07Z</time></trkpt><trkpt lat=\"48.8567962646484\" lon=\"2.35455369949341\"><ele>46.3564</ele><time>2007-04-15T08:59:08Z</time></trkpt><trkpt lat=\"48.8567581176758\" lon=\"2.35482168197632\"><ele>46.6267</ele><time>2007-04-15T08:59:09Z</time></trkpt><trkpt lat=\"48.8567314147949\" lon=\"2.35503816604614\"><ele>46.8765</ele><time>2007-04-15T08:59:10Z</time></trkpt><trkpt lat=\"48.8566665649414\" lon=\"2.35521960258484\"><ele>46.7357</ele><time>2007-04-15T08:59:11Z</time></trkpt><trkpt lat=\"48.8566017150879\" lon=\"2.35545420646667\"><ele>46.0438</ele><time>2007-04-15T08:59:12Z</time></trkpt><trkpt lat=\"48.856559753418\" lon=\"2.35559606552124\"><ele>45.7172</ele><time>2007-04-15T08:59:13Z</time></trkpt><trkpt lat=\"48.8565216064453\" lon=\"2.35578179359436\"><ele>45.4858</ele><time>2007-04-15T08:59:14Z</time></trkpt><trkpt lat=\"48.8564796447754\" lon=\"2.35594248771667\"><ele>45.3561</ele><time>2007-04-15T08:59:15Z</time></trkpt><trkpt lat=\"48.8564224243164\" lon=\"2.35612082481384\"><ele>45.2218</ele><time>2007-04-15T08:59:16Z</time></trkpt><trkpt lat=\"48.8563346862793\" lon=\"2.3563756942749\"><ele>45.0641</ele><time>2007-04-15T08:59:17Z</time></trkpt><trkpt lat=\"48.8563232421875\" lon=\"2.35659980773926\"><ele>45.1427</ele><time>2007-04-15T08:59:18Z</time></trkpt><trkpt lat=\"48.8562660217285\" lon=\"2.35680913925171\"><ele>45.2982</ele><time>2007-04-15T08:59:19Z</time></trkpt><trkpt lat=\"48.8562316894531\" lon=\"2.35699987411499\"><ele>45.547</ele><time>2007-04-15T08:59:20Z</time></trkpt><trkpt lat=\"48.8562088012695\" lon=\"2.35723233222961\"><ele>45.8858</ele><time>2007-04-15T08:59:21Z</time></trkpt><trkpt lat=\"48.8561172485352\" lon=\"2.35743975639343\"><ele>45.9252</ele><time>2007-04-15T08:59:22Z</time></trkpt><trkpt lat=\"48.8560409545898\" lon=\"2.357661485672\"><ele>45.8929</ele><time>2007-04-15T08:59:23Z</time></trkpt><trkpt lat=\"48.8560066223144\" lon=\"2.35782551765442\"><ele>45.9332</ele><time>2007-04-15T08:59:24Z</time></trkpt><trkpt lat=\"48.8559608459473\" lon=\"2.35804486274719\"><ele>46.0128</ele><time>2007-04-15T08:59:25Z</time></trkpt><trkpt lat=\"48.8559303283691\" lon=\"2.35822606086731\"><ele>46.119</ele><time>2007-04-15T08:59:26Z</time></trkpt><trkpt lat=\"48.8558921813965\" lon=\"2.35834670066834\"><ele>46.1378</ele><time>2007-04-15T08:59:27Z</time></trkpt><trkpt lat=\"48.8558654785156\" lon=\"2.35847306251526\"><ele>46.0577</ele><time>2007-04-15T08:59:28Z</time></trkpt><trkpt lat=\"48.8558387756348\" lon=\"2.35870385169983\"><ele>46.0043</ele><time>2007-04-15T08:59:29Z</time></trkpt><trkpt lat=\"48.8558082580566\" lon=\"2.35899686813354\"><ele>45.9214</ele><time>2007-04-15T08:59:30Z</time></trkpt><trkpt lat=\"48.855785369873\" lon=\"2.3591616153717\"><ele>45.8838</ele><time>2007-04-15T08:59:31Z</time></trkpt><trkpt lat=\"48.8557052612305\" lon=\"2.35930442810059\"><ele>45.718</ele><time>2007-04-15T08:59:32Z</time></trkpt><trkpt lat=\"48.855583190918\" lon=\"2.35952115058899\"><ele>45.5273</ele><time>2007-04-15T08:59:33Z</time></trkpt><trkpt lat=\"48.8555145263672\" lon=\"2.35967564582825\"><ele>45.4685</ele><time>2007-04-15T08:59:34Z</time></trkpt><trkpt lat=\"48.8554916381836\" lon=\"2.35977792739868\"><ele>45.4807</ele><time>2007-04-15T08:59:35Z</time></trkpt><trkpt lat=\"48.8554801940918\" lon=\"2.35986757278442\"><ele>45.5089</ele><time>2007-04-15T08:59:36Z</time></trkpt><trkpt lat=\"48.8554573059082\" lon=\"2.35999870300293\"><ele>45.5481</ele><time>2007-04-15T08:59:37Z</time></trkpt><trkpt lat=\"48.8554496765137\" lon=\"2.36021184921265\"><ele>45.2854</ele><time>2007-04-15T08:59:38Z</time></trkpt><trkpt lat=\"48.8553886413574\" lon=\"2.36035323143005\"><ele>45.0425</ele><time>2007-04-15T08:59:39Z</time></trkpt><trkpt lat=\"48.855339050293\" lon=\"2.36055612564087\"><ele>44.7395</ele><time>2007-04-15T08:59:40Z</time></trkpt><trkpt lat=\"48.8552780151367\" lon=\"2.36075711250305\"><ele>44.4251</ele><time>2007-04-15T08:59:41Z</time></trkpt><trkpt lat=\"48.8552436828613\" lon=\"2.3609607219696\"><ele>44.3112</ele><time>2007-04-15T08:59:42Z</time></trkpt><trkpt lat=\"48.8552513122559\" lon=\"2.36100244522095\"><ele>44.3209</ele><time>2007-04-15T08:59:43Z</time></trkpt><trkpt lat=\"48.855224609375\" lon=\"2.36123013496399\"><ele>44.3607</ele><time>2007-04-15T08:59:44Z</time></trkpt><trkpt lat=\"48.8551940917969\" lon=\"2.36145758628845\"><ele>44.4586</ele><time>2007-04-15T08:59:45Z</time></trkpt><trkpt lat=\"48.8551635742188\" lon=\"2.36159873008728\"><ele>44.5739</ele><time>2007-04-15T08:59:46Z</time></trkpt><trkpt lat=\"48.855110168457\" lon=\"2.36183619499207\"><ele>44.3556</ele><time>2007-04-15T08:59:47Z</time></trkpt><trkpt lat=\"48.85498046875\" lon=\"2.36197733879089\"><ele>44.1869</ele><time>2007-04-15T08:59:48Z</time></trkpt><trkpt lat=\"48.8549118041992\" lon=\"2.36214327812195\"><ele>43.6144</ele><time>2007-04-15T08:59:49Z</time></trkpt><trkpt lat=\"48.8548431396484\" lon=\"2.36228895187378\"><ele>43.1753</ele><time>2007-04-15T08:59:50Z</time></trkpt><trkpt lat=\"48.8547821044922\" lon=\"2.36244654655457\"><ele>42.8165</ele><time>2007-04-15T08:59:51Z</time></trkpt><trkpt lat=\"48.8547248840332\" lon=\"2.36262822151184\"><ele>42.8223</ele><time>2007-04-15T08:59:52Z</time></trkpt><trkpt lat=\"48.8546600341797\" lon=\"2.36275625228882\"><ele>42.9684</ele><time>2007-04-15T08:59:53Z</time></trkpt><trkpt lat=\"48.8545951843262\" lon=\"2.36294436454773\"><ele>43.2913</ele><time>2007-04-15T08:59:54Z</time></trkpt><trkpt lat=\"48.8545532226562\" lon=\"2.36312246322632\"><ele>43.6653</ele><time>2007-04-15T08:59:55Z</time></trkpt><trkpt lat=\"48.8544769287109\" lon=\"2.36328625679016\"><ele>44.149</ele><time>2007-04-15T08:59:56Z</time></trkpt><trkpt lat=\"48.8544044494629\" lon=\"2.36347055435181\"><ele>44.5</ele><time>2007-04-15T08:59:57Z</time></trkpt><trkpt lat=\"48.8543891906738\" lon=\"2.36365914344788\"><ele>44.6481</ele><time>2007-04-15T08:59:58Z</time></trkpt><trkpt lat=\"48.8543128967285\" lon=\"2.363844871521\"><ele>45.0475</ele><time>2007-04-15T08:59:59Z</time></trkpt><trkpt lat=\"48.8542098999023\" lon=\"2.36411380767822\"><ele>45.7356</ele><time>2007-04-15T09:00:00Z</time></trkpt><trkpt lat=\"48.8540687561035\" lon=\"2.36432695388794\"><ele>45.7102</ele><time>2007-04-15T09:00:01Z</time></trkpt><trkpt lat=\"48.8540229797363\" lon=\"2.36443448066711\"><ele>45.4743</ele><time>2007-04-15T09:00:02Z</time></trkpt><trkpt lat=\"48.853946685791\" lon=\"2.3645658493042\"><ele>45.1795</ele><time>2007-04-15T09:00:03Z</time></trkpt><trkpt lat=\"48.8539009094238\" lon=\"2.3647952079773\"><ele>44.5699</ele><time>2007-04-15T09:00:04Z</time></trkpt><trkpt lat=\"48.853889465332\" lon=\"2.36497068405151\"><ele>44.0821</ele><time>2007-04-15T09:00:05Z</time></trkpt><trkpt lat=\"48.8538932800293\" lon=\"2.36516809463501\"><ele>43.7289</ele><time>2007-04-15T09:00:06Z</time></trkpt><trkpt lat=\"48.8538284301758\" lon=\"2.36539745330811\"><ele>43.4333</ele><time>2007-04-15T09:00:07Z</time></trkpt><trkpt lat=\"48.8537788391113\" lon=\"2.36560320854187\"><ele>43.226</ele><time>2007-04-15T09:00:08Z</time></trkpt><trkpt lat=\"48.853759765625\" lon=\"2.36578488349915\"><ele>43.0361</ele><time>2007-04-15T09:00:09Z</time></trkpt><trkpt lat=\"48.8536834716797\" lon=\"2.36600971221924\"><ele>43.181</ele><time>2007-04-15T09:00:10Z</time></trkpt><trkpt lat=\"48.8536262512207\" lon=\"2.36617040634155\"><ele>43.1989</ele><time>2007-04-15T09:00:11Z</time></trkpt><trkpt lat=\"48.8535804748535\" lon=\"2.36633467674255\"><ele>43.0957</ele><time>2007-04-15T09:00:12Z</time></trkpt><trkpt lat=\"48.853515625\" lon=\"2.36654853820801\"><ele>42.7847</ele><time>2007-04-15T09:00:13Z</time></trkpt><trkpt lat=\"48.8535079956055\" lon=\"2.36674118041992\"><ele>43.0571</ele><time>2007-04-15T09:00:14Z</time></trkpt><trkpt lat=\"48.8535385131836\" lon=\"2.36695051193237\"><ele>44.3579</ele><time>2007-04-15T09:00:15Z</time></trkpt><trkpt lat=\"48.8535423278809\" lon=\"2.36719250679016\"><ele>45.7492</ele><time>2007-04-15T09:00:16Z</time></trkpt><trkpt lat=\"48.853515625\" lon=\"2.36740684509277\"><ele>46.903</ele><time>2007-04-15T09:00:17Z</time></trkpt><trkpt lat=\"48.8535041809082\" lon=\"2.36761689186096\"><ele>47.464</ele><time>2007-04-15T09:00:18Z</time></trkpt><trkpt lat=\"48.853443145752\" lon=\"2.36778855323792\"><ele>47.4729</ele><time>2007-04-15T09:00:19Z</time></trkpt><trkpt lat=\"48.8533782958984\" lon=\"2.36795878410339\"><ele>47.5693</ele><time>2007-04-15T09:00:20Z</time></trkpt><trkpt lat=\"48.853328704834\" lon=\"2.36809992790222\"><ele>47.6777</ele><time>2007-04-15T09:00:21Z</time></trkpt><trkpt lat=\"48.8533134460449\" lon=\"2.36823844909668\"><ele>47.6849</ele><time>2007-04-15T09:00:22Z</time></trkpt><trkpt lat=\"48.8532867431641\" lon=\"2.36840391159058\"><ele>47.1207</ele><time>2007-04-15T09:00:23Z</time></trkpt><trkpt lat=\"48.8531837463379\" lon=\"2.36855316162109\"><ele>45.539</ele><time>2007-04-15T09:00:24Z</time></trkpt><trkpt lat=\"48.853141784668\" lon=\"2.36859893798828\"><ele>45.0703</ele><time>2007-04-15T09:00:25Z</time></trkpt><trkpt lat=\"48.8530311584473\" lon=\"2.36875081062317\"><ele>44.0482</ele><time>2007-04-15T09:00:26Z</time></trkpt><trkpt lat=\"48.8530120849609\" lon=\"2.36879396438599\"><ele>43.8976</ele><time>2007-04-15T09:00:27Z</time></trkpt><trkpt lat=\"48.8530426025391\" lon=\"2.36888360977173\"><ele>43.8622</ele><time>2007-04-15T09:00:28Z</time></trkpt><trkpt lat=\"48.8530502319336\" lon=\"2.36887884140015\"><ele>43.8933</ele><time>2007-04-15T09:00:29Z</time></trkpt><trkpt lat=\"48.8529930114746\" lon=\"2.36893963813782\"><ele>43.658</ele><time>2007-04-15T09:00:30Z</time></trkpt><trkpt lat=\"48.8529396057129\" lon=\"2.36911416053772\"><ele>43.4898</ele><time>2007-04-15T09:00:31Z</time></trkpt><trkpt lat=\"48.8529472351074\" lon=\"2.36920833587646\"><ele>43.5755</ele><time>2007-04-15T09:00:32Z</time></trkpt><trkpt lat=\"48.8529663085938\" lon=\"2.36924266815186\"><ele>43.6304</ele><time>2007-04-15T09:00:33Z</time></trkpt><trkpt lat=\"48.8529663085938\" lon=\"2.36933422088623\"><ele>43.8592</ele><time>2007-04-15T09:00:34Z</time></trkpt><trkpt lat=\"48.852970123291\" lon=\"2.36933493614197\"><ele>43.85</ele><time>2007-04-15T09:00:35Z</time></trkpt><trkpt lat=\"48.8529739379883\" lon=\"2.36934161186218\"><ele>43.8551</ele><time>2007-04-15T09:00:36Z</time></trkpt><trkpt lat=\"48.8530120849609\" lon=\"2.36940336227417\"><ele>43.8679</ele><time>2007-04-15T09:00:37Z</time></trkpt><trkpt lat=\"48.8530960083008\" lon=\"2.36955189704895\"><ele>43.7441</ele><time>2007-04-15T09:00:38Z</time></trkpt><trkpt lat=\"48.8531875610352\" lon=\"2.3697521686554\"><ele>43.3327</ele><time>2007-04-15T09:00:39Z</time></trkpt><trkpt lat=\"48.8532485961914\" lon=\"2.36992120742798\"><ele>42.8407</ele><time>2007-04-15T09:00:40Z</time></trkpt><trkpt lat=\"48.8532867431641\" lon=\"2.37008285522461\"><ele>42.4361</ele><time>2007-04-15T09:00:41Z</time></trkpt><trkpt lat=\"48.8532981872559\" lon=\"2.37018346786499\"><ele>42.3188</ele><time>2007-04-15T09:00:42Z</time></trkpt><trkpt lat=\"48.8532943725586\" lon=\"2.37023401260376\"><ele>42.3478</ele><time>2007-04-15T09:00:43Z</time></trkpt><trkpt lat=\"48.8532867431641\" lon=\"2.37023711204529\"><ele>42.4155</ele><time>2007-04-15T09:00:44Z</time></trkpt><trkpt lat=\"48.8532867431641\" lon=\"2.37024116516113\"><ele>42.4149</ele><time>2007-04-15T09:00:45Z</time></trkpt><trkpt lat=\"48.853199005127\" lon=\"2.37039470672607\"><ele>43.1369</ele><time>2007-04-15T09:00:46Z</time></trkpt><trkpt lat=\"48.8531303405762\" lon=\"2.3705723285675\"><ele>43.6141</ele><time>2007-04-15T09:00:47Z</time></trkpt><trkpt lat=\"48.8529472351074\" lon=\"2.37073063850403\"><ele>44.8941</ele><time>2007-04-15T09:00:48Z</time></trkpt><trkpt lat=\"48.8529281616211\" lon=\"2.37076187133789\"><ele>45.0006</ele><time>2007-04-15T09:00:49Z</time></trkpt><trkpt lat=\"48.8528327941894\" lon=\"2.37091302871704\"><ele>45.2592</ele><time>2007-04-15T09:00:50Z</time></trkpt><trkpt lat=\"48.8526992797852\" lon=\"2.37108826637268\"><ele>45.1686</ele><time>2007-04-15T09:00:51Z</time></trkpt><trkpt lat=\"48.8525543212891\" lon=\"2.37131357192993\"><ele>44.3766</ele><time>2007-04-15T09:00:52Z</time></trkpt><trkpt lat=\"48.852466583252\" lon=\"2.37151002883911\"><ele>43.4184</ele><time>2007-04-15T09:00:53Z</time></trkpt><trkpt lat=\"48.8524131774902\" lon=\"2.37175178527832\"><ele>42.759</ele><time>2007-04-15T09:00:54Z</time></trkpt><trkpt lat=\"48.8523445129394\" lon=\"2.37196493148804\"><ele>43.0252</ele><time>2007-04-15T09:00:55Z</time></trkpt><trkpt lat=\"48.8522644042969\" lon=\"2.37222099304199\"><ele>42.9453</ele><time>2007-04-15T09:00:56Z</time></trkpt><trkpt lat=\"48.8521919250488\" lon=\"2.37248134613037\"><ele>42.4276</ele><time>2007-04-15T09:00:57Z</time></trkpt><trkpt lat=\"48.8521041870117\" lon=\"2.37278819084167\"><ele>42.8208</ele><time>2007-04-15T09:00:58Z</time></trkpt><trkpt lat=\"48.8520317077637\" lon=\"2.3731210231781\"><ele>43.3072</ele><time>2007-04-15T09:00:59Z</time></trkpt><trkpt lat=\"48.8519744873047\" lon=\"2.3734233379364\"><ele>43.6705</ele><time>2007-04-15T09:01:00Z</time></trkpt><trkpt lat=\"48.8519287109375\" lon=\"2.37369227409363\"><ele>43.821</ele><time>2007-04-15T09:01:01Z</time></trkpt><trkpt lat=\"48.8518676757812\" lon=\"2.37398886680603\"><ele>43.9485</ele><time>2007-04-15T09:01:02Z</time></trkpt><trkpt lat=\"48.8517532348633\" lon=\"2.37422299385071\"><ele>43.9789</ele><time>2007-04-15T09:01:03Z</time></trkpt><trkpt lat=\"48.8516731262207\" lon=\"2.3744637966156\"><ele>43.9917</ele><time>2007-04-15T09:01:04Z</time></trkpt><trkpt lat=\"48.8516120910644\" lon=\"2.37473464012146\"><ele>43.9554</ele><time>2007-04-15T09:01:05Z</time></trkpt><trkpt lat=\"48.8515319824219\" lon=\"2.37498664855957\"><ele>43.841</ele><time>2007-04-15T09:01:06Z</time></trkpt><trkpt lat=\"48.8514785766602\" lon=\"2.37523245811462\"><ele>44.1162</ele><time>2007-04-15T09:01:07Z</time></trkpt><trkpt lat=\"48.8514251708984\" lon=\"2.3754711151123\"><ele>44.4394</ele><time>2007-04-15T09:01:08Z</time></trkpt><trkpt lat=\"48.8513565063477\" lon=\"2.37573981285095\"><ele>44.846</ele><time>2007-04-15T09:01:09Z</time></trkpt><trkpt lat=\"48.8513031005859\" lon=\"2.37604713439941\"><ele>45.2239</ele><time>2007-04-15T09:01:10Z</time></trkpt><trkpt lat=\"48.8512382507324\" lon=\"2.37632465362549\"><ele>45.6062</ele><time>2007-04-15T09:01:11Z</time></trkpt><trkpt lat=\"48.8511924743652\" lon=\"2.37653541564941\"><ele>45.9588</ele><time>2007-04-15T09:01:12Z</time></trkpt><trkpt lat=\"48.851131439209\" lon=\"2.37683081626892\"><ele>45.6376</ele><time>2007-04-15T09:01:13Z</time></trkpt><trkpt lat=\"48.8510093688965\" lon=\"2.37718415260315\"><ele>44.3559</ele><time>2007-04-15T09:01:14Z</time></trkpt><trkpt lat=\"48.8509407043457\" lon=\"2.37744355201721\"><ele>43.2535</ele><time>2007-04-15T09:01:15Z</time></trkpt><trkpt lat=\"48.8509101867676\" lon=\"2.37772798538208\"><ele>42.7769</ele><time>2007-04-15T09:01:16Z</time></trkpt><trkpt lat=\"48.850830078125\" lon=\"2.37805080413818\"><ele>42.339</ele><time>2007-04-15T09:01:17Z</time></trkpt><trkpt lat=\"48.8507270812988\" lon=\"2.37834000587463\"><ele>41.992</ele><time>2007-04-15T09:01:18Z</time></trkpt><trkpt lat=\"48.8506851196289\" lon=\"2.37850785255432\"><ele>41.7906</ele><time>2007-04-15T09:01:19Z</time></trkpt><trkpt lat=\"48.8506278991699\" lon=\"2.37879300117493\"><ele>41.4484</ele><time>2007-04-15T09:01:20Z</time></trkpt><trkpt lat=\"48.8505706787109\" lon=\"2.37900280952454\"><ele>41.1966</ele><time>2007-04-15T09:01:21Z</time></trkpt><trkpt lat=\"48.8505363464356\" lon=\"2.37911009788513\"><ele>41.0679</ele><time>2007-04-15T09:01:22Z</time></trkpt><trkpt lat=\"48.8504981994629\" lon=\"2.37930154800415\"><ele>40.9032</ele><time>2007-04-15T09:01:23Z</time></trkpt><trkpt lat=\"48.8504676818848\" lon=\"2.37948322296143\"><ele>40.7868</ele><time>2007-04-15T09:01:24Z</time></trkpt><trkpt lat=\"48.850456237793\" lon=\"2.37961840629578\"><ele>40.7032</ele><time>2007-04-15T09:01:25Z</time></trkpt><trkpt lat=\"48.8504333496094\" lon=\"2.37978577613831\"><ele>40.6137</ele><time>2007-04-15T09:01:26Z</time></trkpt><trkpt lat=\"48.8503875732422\" lon=\"2.38002967834473\"><ele>40.6252</ele><time>2007-04-15T09:01:27Z</time></trkpt><trkpt lat=\"48.8503684997559\" lon=\"2.38017058372498\"><ele>41.0814</ele><time>2007-04-15T09:01:28Z</time></trkpt><trkpt lat=\"48.8503913879394\" lon=\"2.38038873672485\"><ele>41.7107</ele><time>2007-04-15T09:01:29Z</time></trkpt><trkpt lat=\"48.8503761291504\" lon=\"2.38062310218811\"><ele>42.4543</ele><time>2007-04-15T09:01:30Z</time></trkpt><trkpt lat=\"48.850399017334\" lon=\"2.38087701797485\"><ele>43.015</ele><time>2007-04-15T09:01:31Z</time></trkpt><trkpt lat=\"48.850399017334\" lon=\"2.38109159469604\"><ele>42.8808</ele><time>2007-04-15T09:01:32Z</time></trkpt><trkpt lat=\"48.8503952026367\" lon=\"2.38117861747742\"><ele>42.8337</ele><time>2007-04-15T09:01:33Z</time></trkpt><trkpt lat=\"48.850399017334\" lon=\"2.38152050971985\"><ele>42.6126</ele><time>2007-04-15T09:01:34Z</time></trkpt><trkpt lat=\"48.8503723144531\" lon=\"2.38177347183228\"><ele>42.5259</ele><time>2007-04-15T09:01:35Z</time></trkpt><trkpt lat=\"48.8503646850586\" lon=\"2.38199043273926\"><ele>42.4654</ele><time>2007-04-15T09:01:36Z</time></trkpt><trkpt lat=\"48.8503761291504\" lon=\"2.38217306137085\"><ele>42.4304</ele><time>2007-04-15T09:01:37Z</time></trkpt><trkpt lat=\"48.8504028320312\" lon=\"2.38236284255981\"><ele>42.4611</ele><time>2007-04-15T09:01:38Z</time></trkpt><trkpt lat=\"48.8504371643066\" lon=\"2.38261890411377\"><ele>42.3025</ele><time>2007-04-15T09:01:39Z</time></trkpt><trkpt lat=\"48.8504295349121\" lon=\"2.3828444480896\"><ele>41.7452</ele><time>2007-04-15T09:01:40Z</time></trkpt><trkpt lat=\"48.8504180908203\" lon=\"2.38300204277039\"><ele>41.3043</ele><time>2007-04-15T09:01:41Z</time></trkpt><trkpt lat=\"48.8504066467285\" lon=\"2.38315200805664\"><ele>40.8615</ele><time>2007-04-15T09:01:42Z</time></trkpt><trkpt lat=\"48.8504028320312\" lon=\"2.3833475112915\"><ele>40.4195</ele><time>2007-04-15T09:01:43Z</time></trkpt><trkpt lat=\"48.8503761291504\" lon=\"2.38348031044006\"><ele>40.5637</ele><time>2007-04-15T09:01:44Z</time></trkpt><trkpt lat=\"48.8503723144531\" lon=\"2.38351321220398\"><ele>40.6281</ele><time>2007-04-15T09:01:45Z</time></trkpt><trkpt lat=\"48.8503913879394\" lon=\"2.38370299339294\"><ele>41.2556</ele><time>2007-04-15T09:01:46Z</time></trkpt><trkpt lat=\"48.8503952026367\" lon=\"2.38381958007812\"><ele>41.5769</ele><time>2007-04-15T09:01:47Z</time></trkpt><trkpt lat=\"48.8503837585449\" lon=\"2.38408708572388\"><ele>42.2469</ele><time>2007-04-15T09:01:48Z</time></trkpt><trkpt lat=\"48.8503684997559\" lon=\"2.38431167602539\"><ele>42.8103</ele><time>2007-04-15T09:01:49Z</time></trkpt><trkpt lat=\"48.8503303527832\" lon=\"2.38450407981873\"><ele>43.2901</ele><time>2007-04-15T09:01:50Z</time></trkpt><trkpt lat=\"48.8502769470215\" lon=\"2.38475751876831\"><ele>43.9881</ele><time>2007-04-15T09:01:51Z</time></trkpt><trkpt lat=\"48.8502311706543\" lon=\"2.38493728637695\"><ele>44.5386</ele><time>2007-04-15T09:01:52Z</time></trkpt><trkpt lat=\"48.8501968383789\" lon=\"2.3850998878479\"><ele>45.0318</ele><time>2007-04-15T09:01:53Z</time></trkpt><trkpt lat=\"48.8501625061035\" lon=\"2.3852436542511\"><ele>45.4468</ele><time>2007-04-15T09:01:54Z</time></trkpt><trkpt lat=\"48.8501167297363\" lon=\"2.38542079925537\"><ele>45.9406</ele><time>2007-04-15T09:01:55Z</time></trkpt><trkpt lat=\"48.8500633239746\" lon=\"2.38557553291321\"><ele>46.3578</ele><time>2007-04-15T09:01:56Z</time></trkpt><trkpt lat=\"48.8499908447266\" lon=\"2.38574910163879\"><ele>46.7353</ele><time>2007-04-15T09:01:57Z</time></trkpt><trkpt lat=\"48.8499221801758\" lon=\"2.38592600822449\"><ele>46.3493</ele><time>2007-04-15T09:01:58Z</time></trkpt><trkpt lat=\"48.8498916625977\" lon=\"2.38612985610962\"><ele>45.9567</ele><time>2007-04-15T09:01:59Z</time></trkpt><trkpt lat=\"48.8498840332031\" lon=\"2.38627767562866\"><ele>45.7802</ele><time>2007-04-15T09:02:00Z</time></trkpt><trkpt lat=\"48.8498764038086\" lon=\"2.38631796836853\"><ele>45.7011</ele><time>2007-04-15T09:02:01Z</time></trkpt><trkpt lat=\"48.8498497009277\" lon=\"2.3865385055542\"><ele>45.3769</ele><time>2007-04-15T09:02:02Z</time></trkpt><trkpt lat=\"48.8498306274414\" lon=\"2.38665246963501\"><ele>45.1971</ele><time>2007-04-15T09:02:03Z</time></trkpt><trkpt lat=\"48.8498306274414\" lon=\"2.38686609268188\"><ele>45.3329</ele><time>2007-04-15T09:02:04Z</time></trkpt><trkpt lat=\"48.8498268127441\" lon=\"2.38707518577576\"><ele>45.4743</ele><time>2007-04-15T09:02:05Z</time></trkpt><trkpt lat=\"48.8498344421387\" lon=\"2.38730382919312\"><ele>45.661</ele><time>2007-04-15T09:02:06Z</time></trkpt><trkpt lat=\"48.8498306274414\" lon=\"2.38752722740173\"><ele>45.7707</ele><time>2007-04-15T09:02:07Z</time></trkpt><trkpt lat=\"48.849781036377\" lon=\"2.38771867752075\"><ele>45.5438</ele><time>2007-04-15T09:02:08Z</time></trkpt><trkpt lat=\"48.8497352600098\" lon=\"2.3879280090332\"><ele>45.3319</ele><time>2007-04-15T09:02:09Z</time></trkpt><trkpt lat=\"48.8497047424316\" lon=\"2.3881356716156\"><ele>45.1532</ele><time>2007-04-15T09:02:10Z</time></trkpt><trkpt lat=\"48.8496856689453\" lon=\"2.38826084136963\"><ele>45.0542</ele><time>2007-04-15T09:02:11Z</time></trkpt><trkpt lat=\"48.8496780395508\" lon=\"2.38847637176514\"><ele>45.5149</ele><time>2007-04-15T09:02:12Z</time></trkpt><trkpt lat=\"48.8496551513672\" lon=\"2.38866186141968\"><ele>46.1827</ele><time>2007-04-15T09:02:13Z</time></trkpt><trkpt lat=\"48.8496513366699\" lon=\"2.38870525360107\"><ele>46.3389</ele><time>2007-04-15T09:02:14Z</time></trkpt><trkpt lat=\"48.8496513366699\" lon=\"2.38871693611145\"><ele>46.381</ele><time>2007-04-15T09:02:15Z</time></trkpt><trkpt lat=\"48.8496513366699\" lon=\"2.38874006271362\"><ele>46.4642</ele><time>2007-04-15T09:02:16Z</time></trkpt><trkpt lat=\"48.8496398925781\" lon=\"2.38889169692993\"><ele>47.0101</ele><time>2007-04-15T09:02:17Z</time></trkpt><trkpt lat=\"48.8496170043945\" lon=\"2.38910341262817\"><ele>47.7723</ele><time>2007-04-15T09:02:18Z</time></trkpt><trkpt lat=\"48.8496131896973\" lon=\"2.38926339149475\"><ele>48.2488</ele><time>2007-04-15T09:02:19Z</time></trkpt><trkpt lat=\"48.8495826721191\" lon=\"2.38940739631653\"><ele>48.5768</ele><time>2007-04-15T09:02:20Z</time></trkpt><trkpt lat=\"48.8495483398438\" lon=\"2.38957929611206\"><ele>48.9071</ele><time>2007-04-15T09:02:21Z</time></trkpt><trkpt lat=\"48.849536895752\" lon=\"2.38961958885193\"><ele>48.9659</ele><time>2007-04-15T09:02:22Z</time></trkpt><trkpt lat=\"48.8495063781738\" lon=\"2.38980674743652\"><ele>49.2525</ele><time>2007-04-15T09:02:23Z</time></trkpt><trkpt lat=\"48.8494911193848\" lon=\"2.38987922668457\"><ele>49.3317</ele><time>2007-04-15T09:02:24Z</time></trkpt><trkpt lat=\"48.8494491577148\" lon=\"2.39009642601013\"><ele>49.4344</ele><time>2007-04-15T09:02:25Z</time></trkpt><trkpt lat=\"48.8494071960449\" lon=\"2.39035534858704\"><ele>49.4007</ele><time>2007-04-15T09:02:26Z</time></trkpt><trkpt lat=\"48.8493728637695\" lon=\"2.39055776596069\"><ele>49.321</ele><time>2007-04-15T09:02:27Z</time></trkpt><trkpt lat=\"48.8493347167969\" lon=\"2.39074492454529\"><ele>49.1672</ele><time>2007-04-15T09:02:28Z</time></trkpt><trkpt lat=\"48.8493156433106\" lon=\"2.39090609550476\"><ele>49.2317</ele><time>2007-04-15T09:02:29Z</time></trkpt><trkpt lat=\"48.8492851257324\" lon=\"2.39110541343689\"><ele>49.4595</ele><time>2007-04-15T09:02:30Z</time></trkpt><trkpt lat=\"48.8492813110352\" lon=\"2.39114117622376\"><ele>49.5134</ele><time>2007-04-15T09:02:31Z</time></trkpt><trkpt lat=\"48.8492774963379\" lon=\"2.39117050170898\"><ele>49.5534</ele><time>2007-04-15T09:02:32Z</time></trkpt><trkpt lat=\"48.8492279052734\" lon=\"2.39155006408691\"><ele>50.0979</ele><time>2007-04-15T09:02:33Z</time></trkpt><trkpt lat=\"48.8492126464844\" lon=\"2.39170169830322\"><ele>50.3156</ele><time>2007-04-15T09:02:34Z</time></trkpt><trkpt lat=\"48.8491821289062\" lon=\"2.39185333251953\"><ele>50.3126</ele><time>2007-04-15T09:02:35Z</time></trkpt><trkpt lat=\"48.8491477966309\" lon=\"2.39202260971069\"><ele>50.4561</ele><time>2007-04-15T09:02:36Z</time></trkpt><trkpt lat=\"48.8491058349609\" lon=\"2.39218401908874\"><ele>50.7568</ele><time>2007-04-15T09:02:37Z</time></trkpt><trkpt lat=\"48.8490295410156\" lon=\"2.39235401153564\"><ele>51.232</ele><time>2007-04-15T09:02:38Z</time></trkpt><trkpt lat=\"48.848991394043\" lon=\"2.39247798919678\"><ele>51.5879</ele><time>2007-04-15T09:02:39Z</time></trkpt><trkpt lat=\"48.8489570617676\" lon=\"2.39264869689941\"><ele>52.6457</ele><time>2007-04-15T09:02:40Z</time></trkpt><trkpt lat=\"48.8489418029785\" lon=\"2.39283204078674\"><ele>53.7701</ele><time>2007-04-15T09:02:41Z</time></trkpt><trkpt lat=\"48.8488998413086\" lon=\"2.39306855201721\"><ele>55.1803</ele><time>2007-04-15T09:02:42Z</time></trkpt><trkpt lat=\"48.8488540649414\" lon=\"2.39325642585754\"><ele>56.2096</ele><time>2007-04-15T09:02:43Z</time></trkpt><trkpt lat=\"48.848819732666\" lon=\"2.39344692230225\"><ele>56.6632</ele><time>2007-04-15T09:02:44Z</time></trkpt><trkpt lat=\"48.8487930297852\" lon=\"2.39360737800598\"><ele>56.733</ele><time>2007-04-15T09:02:45Z</time></trkpt><trkpt lat=\"48.848747253418\" lon=\"2.39376664161682\"><ele>56.755</ele><time>2007-04-15T09:02:46Z</time></trkpt><trkpt lat=\"48.8487167358398\" lon=\"2.39396619796753\"><ele>56.8095</ele><time>2007-04-15T09:02:47Z</time></trkpt><trkpt lat=\"48.8486785888672\" lon=\"2.39412689208984\"><ele>56.8088</ele><time>2007-04-15T09:02:48Z</time></trkpt><trkpt lat=\"48.8486518859863\" lon=\"2.39431953430176\"><ele>55.8473</ele><time>2007-04-15T09:02:49Z</time></trkpt><trkpt lat=\"48.8486099243164\" lon=\"2.39449334144592\"><ele>54.7038</ele><time>2007-04-15T09:02:50Z</time></trkpt><trkpt lat=\"48.8485641479492\" lon=\"2.39468741416931\"><ele>53.4295</ele><time>2007-04-15T09:02:51Z</time></trkpt><trkpt lat=\"48.8485374450684\" lon=\"2.39487075805664\"><ele>52.2653</ele><time>2007-04-15T09:02:52Z</time></trkpt><trkpt lat=\"48.8484840393066\" lon=\"2.39501881599426\"><ele>51.3658</ele><time>2007-04-15T09:02:53Z</time></trkpt><trkpt lat=\"48.8484077453613\" lon=\"2.39515018463135\"><ele>51.1947</ele><time>2007-04-15T09:02:54Z</time></trkpt><trkpt lat=\"48.8483200073242\" lon=\"2.39531826972961\"><ele>51.1058</ele><time>2007-04-15T09:02:55Z</time></trkpt><trkpt lat=\"48.8482246398926\" lon=\"2.39542603492737\"><ele>51.8463</ele><time>2007-04-15T09:02:56Z</time></trkpt><trkpt lat=\"48.8481101989746\" lon=\"2.39553904533386\"><ele>52.7011</ele><time>2007-04-15T09:02:57Z</time></trkpt><trkpt lat=\"48.8480415344238\" lon=\"2.39566993713379\"><ele>53.1696</ele><time>2007-04-15T09:02:58Z</time></trkpt><trkpt lat=\"48.8480072021484\" lon=\"2.395840883255\"><ele>53.3501</ele><time>2007-04-15T09:02:59Z</time></trkpt><trkpt lat=\"48.8480072021484\" lon=\"2.39602541923523\"><ele>53.3982</ele><time>2007-04-15T09:03:00Z</time></trkpt><trkpt lat=\"48.8480415344238\" lon=\"2.39623093605042\"><ele>53.2439</ele><time>2007-04-15T09:03:01Z</time></trkpt><trkpt lat=\"48.8480834960938\" lon=\"2.39639639854431\"><ele>53.0694</ele><time>2007-04-15T09:03:02Z</time></trkpt><trkpt lat=\"48.8481369018555\" lon=\"2.39661812782288\"><ele>52.9121</ele><time>2007-04-15T09:03:03Z</time></trkpt><trkpt lat=\"48.8481903076172\" lon=\"2.39680790901184\"><ele>53.3063</ele><time>2007-04-15T09:03:04Z</time></trkpt><trkpt lat=\"48.8481941223144\" lon=\"2.39684081077576\"><ele>53.4343</ele><time>2007-04-15T09:03:05Z</time></trkpt><trkpt lat=\"48.8482093811035\" lon=\"2.3970205783844\"><ele>54.1674</ele><time>2007-04-15T09:03:06Z</time></trkpt><trkpt lat=\"48.8482055664062\" lon=\"2.39718198776245\"><ele>54.8972</ele><time>2007-04-15T09:03:07Z</time></trkpt><trkpt lat=\"48.8481979370117\" lon=\"2.39733862876892\"><ele>55.6133</ele><time>2007-04-15T09:03:08Z</time></trkpt><trkpt lat=\"48.848201751709\" lon=\"2.39755654335022\"><ele>56.4515</ele><time>2007-04-15T09:03:09Z</time></trkpt><trkpt lat=\"48.8482055664062\" lon=\"2.39782238006592\"><ele>57.0804</ele><time>2007-04-15T09:03:10Z</time></trkpt><trkpt lat=\"48.8481979370117\" lon=\"2.39796590805054\"><ele>57.4431</ele><time>2007-04-15T09:03:11Z</time></trkpt><trkpt lat=\"48.8481903076172\" lon=\"2.39821720123291\"><ele>58.0645</ele><time>2007-04-15T09:03:12Z</time></trkpt><trkpt lat=\"48.8481903076172\" lon=\"2.39839267730713\"><ele>58.0217</ele><time>2007-04-15T09:03:13Z</time></trkpt><trkpt lat=\"48.8481712341309\" lon=\"2.3985435962677\"><ele>57.2325</ele><time>2007-04-15T09:03:14Z</time></trkpt><trkpt lat=\"48.8481483459473\" lon=\"2.39880514144897\"><ele>55.8022</ele><time>2007-04-15T09:03:15Z</time></trkpt><trkpt lat=\"48.8481101989746\" lon=\"2.399080991745\"><ele>54.2261</ele><time>2007-04-15T09:03:16Z</time></trkpt><trkpt lat=\"48.8480911254883\" lon=\"2.39931654930115\"><ele>53.9415</ele><time>2007-04-15T09:03:17Z</time></trkpt><trkpt lat=\"48.8480796813965\" lon=\"2.39956855773926\"><ele>54.3247</ele><time>2007-04-15T09:03:18Z</time></trkpt><trkpt lat=\"48.8480644226074\" lon=\"2.39987468719482\"><ele>54.8011</ele><time>2007-04-15T09:03:19Z</time></trkpt><trkpt lat=\"48.8480491638184\" lon=\"2.40018486976624\"><ele>55.595</ele><time>2007-04-15T09:03:20Z</time></trkpt><trkpt lat=\"48.848014831543\" lon=\"2.40040302276611\"><ele>56.3369</ele><time>2007-04-15T09:03:21Z</time></trkpt><trkpt lat=\"48.8479843139648\" lon=\"2.40059375762939\"><ele>57.0219</ele><time>2007-04-15T09:03:22Z</time></trkpt><trkpt lat=\"48.8479423522949\" lon=\"2.40091133117676\"><ele>57.8944</ele><time>2007-04-15T09:03:23Z</time></trkpt><trkpt lat=\"48.8479042053223\" lon=\"2.40112709999084\"><ele>57.8484</ele><time>2007-04-15T09:03:24Z</time></trkpt><trkpt lat=\"48.8478851318359\" lon=\"2.40136742591858\"><ele>57.731</ele><time>2007-04-15T09:03:25Z</time></trkpt><trkpt lat=\"48.8478622436523\" lon=\"2.40163660049438\"><ele>57.5857</ele><time>2007-04-15T09:03:26Z</time></trkpt><trkpt lat=\"48.8478507995606\" lon=\"2.40183234214783\"><ele>57.4117</ele><time>2007-04-15T09:03:27Z</time></trkpt><trkpt lat=\"48.8478202819824\" lon=\"2.40213918685913\"><ele>57.1798</ele><time>2007-04-15T09:03:28Z</time></trkpt><trkpt lat=\"48.8478012084961\" lon=\"2.40232181549072\"><ele>57.0702</ele><time>2007-04-15T09:03:29Z</time></trkpt><trkpt lat=\"48.847785949707\" lon=\"2.40249228477478\"><ele>56.9769</ele><time>2007-04-15T09:03:30Z</time></trkpt><trkpt lat=\"48.8477516174316\" lon=\"2.40273332595825\"><ele>57.9342</ele><time>2007-04-15T09:03:31Z</time></trkpt><trkpt lat=\"48.8477478027344\" lon=\"2.40300464630127\"><ele>58.9246</ele><time>2007-04-15T09:03:32Z</time></trkpt><trkpt lat=\"48.8477325439453\" lon=\"2.40327501296997\"><ele>59.9529</ele><time>2007-04-15T09:03:33Z</time></trkpt><trkpt lat=\"48.8477210998535\" lon=\"2.40352177619934\"><ele>59.5856</ele><time>2007-04-15T09:03:34Z</time></trkpt><trkpt lat=\"48.8477058410644\" lon=\"2.40372586250305\"><ele>58.9622</ele><time>2007-04-15T09:03:35Z</time></trkpt><trkpt lat=\"48.8477058410644\" lon=\"2.40398597717285\"><ele>58.1029</ele><time>2007-04-15T09:03:36Z</time></trkpt><trkpt lat=\"48.8476905822754\" lon=\"2.40418410301208\"><ele>57.4763</ele><time>2007-04-15T09:03:37Z</time></trkpt><trkpt lat=\"48.8476829528809\" lon=\"2.40443444252014\"><ele>56.5186</ele><time>2007-04-15T09:03:38Z</time></trkpt><trkpt lat=\"48.8476638793945\" lon=\"2.40461707115173\"><ele>55.7546</ele><time>2007-04-15T09:03:39Z</time></trkpt><trkpt lat=\"48.8476371765137\" lon=\"2.4048330783844\"><ele>54.7254</ele><time>2007-04-15T09:03:40Z</time></trkpt><trkpt lat=\"48.8476104736328\" lon=\"2.40503764152527\"><ele>53.8346</ele><time>2007-04-15T09:03:41Z</time></trkpt><trkpt lat=\"48.8475875854492\" lon=\"2.40526103973389\"><ele>53.9109</ele><time>2007-04-15T09:03:42Z</time></trkpt><trkpt lat=\"48.8475379943848\" lon=\"2.40549612045288\"><ele>53.8418</ele><time>2007-04-15T09:03:43Z</time></trkpt><trkpt lat=\"48.8475227355957\" lon=\"2.40555953979492\"><ele>53.8168</ele><time>2007-04-15T09:03:44Z</time></trkpt><trkpt lat=\"48.8475227355957\" lon=\"2.40578627586365\"><ele>54.0815</ele><time>2007-04-15T09:03:45Z</time></trkpt><trkpt lat=\"48.8475036621094\" lon=\"2.40594410896301\"><ele>53.7544</ele><time>2007-04-15T09:03:46Z</time></trkpt><trkpt lat=\"48.8474731445312\" lon=\"2.40614199638367\"><ele>53.3356</ele><time>2007-04-15T09:03:47Z</time></trkpt><trkpt lat=\"48.8474578857422\" lon=\"2.40639281272888\"><ele>52.7923</ele><time>2007-04-15T09:03:48Z</time></trkpt><trkpt lat=\"48.8474388122559\" lon=\"2.40662813186646\"><ele>52.3094</ele><time>2007-04-15T09:03:49Z</time></trkpt><trkpt lat=\"48.8474082946777\" lon=\"2.40680861473084\"><ele>52.4442</ele><time>2007-04-15T09:03:50Z</time></trkpt><trkpt lat=\"48.8473739624023\" lon=\"2.40704822540283\"><ele>52.7039</ele><time>2007-04-15T09:03:51Z</time></trkpt><trkpt lat=\"48.8473472595215\" lon=\"2.4072699546814\"><ele>52.8757</ele><time>2007-04-15T09:03:52Z</time></trkpt><trkpt lat=\"48.8473320007324\" lon=\"2.40754151344299\"><ele>52.99</ele><time>2007-04-15T09:03:53Z</time></trkpt><trkpt lat=\"48.8473320007324\" lon=\"2.40771007537842\"><ele>52.9492</ele><time>2007-04-15T09:03:54Z</time></trkpt><trkpt lat=\"48.8473167419434\" lon=\"2.40791058540344\"><ele>52.8917</ele><time>2007-04-15T09:03:55Z</time></trkpt><trkpt lat=\"48.8472938537598\" lon=\"2.40815377235413\"><ele>52.8059</ele><time>2007-04-15T09:03:56Z</time></trkpt><trkpt lat=\"48.8472709655762\" lon=\"2.40832448005676\"><ele>52.7281</ele><time>2007-04-15T09:03:57Z</time></trkpt><trkpt lat=\"48.8472366333008\" lon=\"2.408527135849\"><ele>53.5286</ele><time>2007-04-15T09:03:58Z</time></trkpt><trkpt lat=\"48.8472061157227\" lon=\"2.40870356559753\"><ele>54.2935</ele><time>2007-04-15T09:03:59Z</time></trkpt><trkpt lat=\"48.8471717834473\" lon=\"2.40895485877991\"><ele>55.4311</ele><time>2007-04-15T09:04:00Z</time></trkpt><trkpt lat=\"48.8471641540527\" lon=\"2.4092583656311\"><ele>56.1172</ele><time>2007-04-15T09:04:01Z</time></trkpt><trkpt lat=\"48.8471527099609\" lon=\"2.409428358078\"><ele>55.6055</ele><time>2007-04-15T09:04:02Z</time></trkpt><trkpt lat=\"48.8471336364746\" lon=\"2.40958070755005\"><ele>55.1675</ele><time>2007-04-15T09:04:03Z</time></trkpt><trkpt lat=\"48.8471336364746\" lon=\"2.40973877906799\"><ele>54.6819</ele><time>2007-04-15T09:04:04Z</time></trkpt><trkpt lat=\"48.8471145629883\" lon=\"2.40993332862854\"><ele>54.1281</ele><time>2007-04-15T09:04:05Z</time></trkpt><trkpt lat=\"48.8471031188965\" lon=\"2.41013383865356\"><ele>54.0443</ele><time>2007-04-15T09:04:06Z</time></trkpt><trkpt lat=\"48.847095489502\" lon=\"2.41028213500977\"><ele>54.1549</ele><time>2007-04-15T09:04:07Z</time></trkpt><trkpt lat=\"48.8470840454102\" lon=\"2.41037511825562\"><ele>54.2245</ele><time>2007-04-15T09:04:08Z</time></trkpt><trkpt lat=\"48.8470649719238\" lon=\"2.41052746772766\"><ele>54.3187</ele><time>2007-04-15T09:04:09Z</time></trkpt><trkpt lat=\"48.847038269043\" lon=\"2.41071724891663\"><ele>54.3989</ele><time>2007-04-15T09:04:10Z</time></trkpt><trkpt lat=\"48.8469467163086\" lon=\"2.41084098815918\"><ele>54.3422</ele><time>2007-04-15T09:04:11Z</time></trkpt><trkpt lat=\"48.8468055725098\" lon=\"2.41095185279846\"><ele>54.2141</ele><time>2007-04-15T09:04:12Z</time></trkpt><trkpt lat=\"48.8466758728027\" lon=\"2.41099762916565\"><ele>54.0154</ele><time>2007-04-15T09:04:13Z</time></trkpt><trkpt lat=\"48.846549987793\" lon=\"2.41096425056458\"><ele>54.324</ele><time>2007-04-15T09:04:14Z</time></trkpt><trkpt lat=\"48.8464012145996\" lon=\"2.41091108322144\"><ele>54.6965</ele><time>2007-04-15T09:04:15Z</time></trkpt><trkpt lat=\"48.8462753295898\" lon=\"2.41086864471436\"><ele>54.979</ele><time>2007-04-15T09:04:16Z</time></trkpt><trkpt lat=\"48.8461837768555\" lon=\"2.4108304977417\"><ele>55.1604</ele><time>2007-04-15T09:04:17Z</time></trkpt><trkpt lat=\"48.8460807800293\" lon=\"2.41081142425537\"><ele>55.4139</ele><time>2007-04-15T09:04:18Z</time></trkpt><trkpt lat=\"48.8460311889648\" lon=\"2.41079688072205\"><ele>55.5355</ele><time>2007-04-15T09:04:19Z</time></trkpt><trkpt lat=\"48.8460235595703\" lon=\"2.4107928276062\"><ele>55.5546</ele><time>2007-04-15T09:04:20Z</time></trkpt><trkpt lat=\"48.8460083007812\" lon=\"2.41078448295593\"><ele>55.5924</ele><time>2007-04-15T09:04:21Z</time></trkpt><trkpt lat=\"48.8459320068359\" lon=\"2.41075897216797\"><ele>55.7738</ele><time>2007-04-15T09:04:22Z</time></trkpt><trkpt lat=\"48.8458099365234\" lon=\"2.41074681282043\"><ele>55.9778</ele><time>2007-04-15T09:04:23Z</time></trkpt><trkpt lat=\"48.8457183837891\" lon=\"2.41075825691223\"><ele>55.8869</ele><time>2007-04-15T09:04:24Z</time></trkpt><trkpt lat=\"48.845573425293\" lon=\"2.41076326370239\"><ele>55.7406</ele><time>2007-04-15T09:04:25Z</time></trkpt><trkpt lat=\"48.845458984375\" lon=\"2.41075205802917\"><ele>55.6384</ele><time>2007-04-15T09:04:26Z</time></trkpt><trkpt lat=\"48.8453025817871\" lon=\"2.41072177886963\"><ele>55.5336</ele><time>2007-04-15T09:04:27Z</time></trkpt><trkpt lat=\"48.8451805114746\" lon=\"2.41068005561829\"><ele>55.5048</ele><time>2007-04-15T09:04:28Z</time></trkpt><trkpt lat=\"48.8450584411621\" lon=\"2.41063952445984\"><ele>55.5027</ele><time>2007-04-15T09:04:29Z</time></trkpt><trkpt lat=\"48.8449249267578\" lon=\"2.41059422492981\"><ele>55.4579</ele><time>2007-04-15T09:04:30Z</time></trkpt><trkpt lat=\"48.8447685241699\" lon=\"2.41056180000305\"><ele>55.2834</ele><time>2007-04-15T09:04:31Z</time></trkpt><trkpt lat=\"48.8446807861328\" lon=\"2.41049575805664\"><ele>55.2719</ele><time>2007-04-15T09:04:32Z</time></trkpt><trkpt lat=\"48.844554901123\" lon=\"2.4104585647583\"><ele>55.1251</ele><time>2007-04-15T09:04:33Z</time></trkpt><trkpt lat=\"48.8444519042969\" lon=\"2.41043901443481\"><ele>54.9774</ele><time>2007-04-15T09:04:34Z</time></trkpt><trkpt lat=\"48.8443260192871\" lon=\"2.41041207313538\"><ele>54.7934</ele><time>2007-04-15T09:04:35Z</time></trkpt><trkpt lat=\"48.8442077636719\" lon=\"2.41032314300537\"><ele>54.6917</ele><time>2007-04-15T09:04:36Z</time></trkpt><trkpt lat=\"48.844066619873\" lon=\"2.41020894050598\"><ele>55.1395</ele><time>2007-04-15T09:04:37Z</time></trkpt><trkpt lat=\"48.8439025878906\" lon=\"2.4101710319519\"><ele>55.8105</ele><time>2007-04-15T09:04:38Z</time></trkpt><trkpt lat=\"48.8437194824219\" lon=\"2.41009330749512\"><ele>56.558</ele><time>2007-04-15T09:04:39Z</time></trkpt><trkpt lat=\"48.8435897827148\" lon=\"2.41004681587219\"><ele>57.0595</ele><time>2007-04-15T09:04:40Z</time></trkpt><trkpt lat=\"48.8434600830078\" lon=\"2.40999341011047\"><ele>57.5382</ele><time>2007-04-15T09:04:41Z</time></trkpt><trkpt lat=\"48.8433303833008\" lon=\"2.4099428653717\"><ele>57.9314</ele><time>2007-04-15T09:04:42Z</time></trkpt><trkpt lat=\"48.8431816101074\" lon=\"2.4098756313324\"><ele>57.8508</ele><time>2007-04-15T09:04:43Z</time></trkpt><trkpt lat=\"48.8430328369141\" lon=\"2.40984201431274\"><ele>57.8104</ele><time>2007-04-15T09:04:44Z</time></trkpt><trkpt lat=\"48.8428802490234\" lon=\"2.40982007980347\"><ele>57.7841</ele><time>2007-04-15T09:04:45Z</time></trkpt><trkpt lat=\"48.8427238464356\" lon=\"2.40985894203186\"><ele>57.8307</ele><time>2007-04-15T09:04:46Z</time></trkpt><trkpt lat=\"48.8425750732422\" lon=\"2.40982007980347\"><ele>57.7841</ele><time>2007-04-15T09:04:47Z</time></trkpt><trkpt lat=\"48.8424758911133\" lon=\"2.40978169441223\"><ele>57.6237</ele><time>2007-04-15T09:04:48Z</time></trkpt><trkpt lat=\"48.84228515625\" lon=\"2.40975165367126\"><ele>56.7202</ele><time>2007-04-15T09:04:49Z</time></trkpt><trkpt lat=\"48.8422317504883\" lon=\"2.40973353385925\"><ele>56.4825</ele><time>2007-04-15T09:04:50Z</time></trkpt><trkpt lat=\"48.8422241210938\" lon=\"2.40972805023193\"><ele>56.4505</ele><time>2007-04-15T09:04:51Z</time></trkpt><trkpt lat=\"48.842212677002\" lon=\"2.4097170829773\"><ele>56.4048</ele><time>2007-04-15T09:04:52Z</time></trkpt><trkpt lat=\"48.8421096801758\" lon=\"2.40964531898499\"><ele>56.0299</ele><time>2007-04-15T09:04:53Z</time></trkpt><trkpt lat=\"48.8419609069824\" lon=\"2.40954899787903\"><ele>55.6247</ele><time>2007-04-15T09:04:54Z</time></trkpt><trkpt lat=\"48.8417739868164\" lon=\"2.40946650505066\"><ele>55.2347</ele><time>2007-04-15T09:04:55Z</time></trkpt><trkpt lat=\"48.8416481018066\" lon=\"2.40940618515015\"><ele>55.1091</ele><time>2007-04-15T09:04:56Z</time></trkpt><trkpt lat=\"48.8415222167969\" lon=\"2.40934801101685\"><ele>55.1361</ele><time>2007-04-15T09:04:57Z</time></trkpt><trkpt lat=\"48.8413772583008\" lon=\"2.40929174423218\"><ele>55.1503</ele><time>2007-04-15T09:04:58Z</time></trkpt><trkpt lat=\"48.8412551879883\" lon=\"2.40924119949341\"><ele>55.1937</ele><time>2007-04-15T09:04:59Z</time></trkpt><trkpt lat=\"48.8411331176758\" lon=\"2.40917944908142\"><ele>55.3039</ele><time>2007-04-15T09:05:00Z</time></trkpt><trkpt lat=\"48.8410034179688\" lon=\"2.40913081169128\"><ele>55.1874</ele><time>2007-04-15T09:05:01Z</time></trkpt><trkpt lat=\"48.8408737182617\" lon=\"2.40911269187927\"><ele>54.9931</ele><time>2007-04-15T09:05:02Z</time></trkpt><trkpt lat=\"48.8407135009766\" lon=\"2.40910696983337\"><ele>54.0965</ele><time>2007-04-15T09:05:03Z</time></trkpt><trkpt lat=\"48.8405494689941\" lon=\"2.40908026695251\"><ele>52.9585</ele><time>2007-04-15T09:05:04Z</time></trkpt><trkpt lat=\"48.8404083251953\" lon=\"2.40906000137329\"><ele>52.0078</ele><time>2007-04-15T09:05:05Z</time></trkpt><trkpt lat=\"48.8402633666992\" lon=\"2.40901494026184\"><ele>51.0878</ele><time>2007-04-15T09:05:06Z</time></trkpt><trkpt lat=\"48.8401336669922\" lon=\"2.40900659561157\"><ele>50.2541</ele><time>2007-04-15T09:05:07Z</time></trkpt><trkpt lat=\"48.8400115966797\" lon=\"2.4089777469635\"><ele>49.5274</ele><time>2007-04-15T09:05:08Z</time></trkpt><trkpt lat=\"48.8398590087891\" lon=\"2.40894246101379\"><ele>49.3363</ele><time>2007-04-15T09:05:09Z</time></trkpt><trkpt lat=\"48.8396911621094\" lon=\"2.4088888168335\"><ele>49.2963</ele><time>2007-04-15T09:05:10Z</time></trkpt><trkpt lat=\"48.8395614624023\" lon=\"2.40883612632751\"><ele>49.367</ele><time>2007-04-15T09:05:11Z</time></trkpt><trkpt lat=\"48.8394088745117\" lon=\"2.40876770019531\"><ele>49.5576</ele><time>2007-04-15T09:05:12Z</time></trkpt><trkpt lat=\"48.8392601013184\" lon=\"2.40869903564453\"><ele>49.8413</ele><time>2007-04-15T09:05:13Z</time></trkpt><trkpt lat=\"48.8391036987305\" lon=\"2.40865969657898\"><ele>49.9663</ele><time>2007-04-15T09:05:14Z</time></trkpt><trkpt lat=\"48.8389511108398\" lon=\"2.408611536026\"><ele>50.0721</ele><time>2007-04-15T09:05:15Z</time></trkpt><trkpt lat=\"48.8388061523438\" lon=\"2.40855550765991\"><ele>50.2343</ele><time>2007-04-15T09:05:16Z</time></trkpt><trkpt lat=\"48.8386573791504\" lon=\"2.40851759910584\"><ele>50.2833</ele><time>2007-04-15T09:05:17Z</time></trkpt><trkpt lat=\"48.8385391235352\" lon=\"2.40847754478455\"><ele>50.3817</ele><time>2007-04-15T09:05:18Z</time></trkpt><trkpt lat=\"48.8385200500488\" lon=\"2.40846943855286\"><ele>50.4074</ele><time>2007-04-15T09:05:19Z</time></trkpt><trkpt lat=\"48.8383636474609\" lon=\"2.40839767456055\"><ele>50.6503</ele><time>2007-04-15T09:05:20Z</time></trkpt><trkpt lat=\"48.8381996154785\" lon=\"2.40832662582397\"><ele>51.4801</ele><time>2007-04-15T09:05:21Z</time></trkpt><trkpt lat=\"48.8380661010742\" lon=\"2.40827202796936\"><ele>51.9384</ele><time>2007-04-15T09:05:22Z</time></trkpt><trkpt lat=\"48.837947845459\" lon=\"2.40822505950928\"><ele>52.3277</ele><time>2007-04-15T09:05:23Z</time></trkpt><trkpt lat=\"48.837833404541\" lon=\"2.4081757068634\"><ele>52.6863</ele><time>2007-04-15T09:05:24Z</time></trkpt><trkpt lat=\"48.8377075195312\" lon=\"2.40816211700439\"><ele>53.0986</ele><time>2007-04-15T09:05:25Z</time></trkpt><trkpt lat=\"48.8375968933106\" lon=\"2.40816140174866\"><ele>53.4689</ele><time>2007-04-15T09:05:26Z</time></trkpt><trkpt lat=\"48.8374557495117\" lon=\"2.40815138816834\"><ele>53.6871</ele><time>2007-04-15T09:05:27Z</time></trkpt><trkpt lat=\"48.8373222351074\" lon=\"2.40806579589844\"><ele>53.3208</ele><time>2007-04-15T09:05:28Z</time></trkpt><trkpt lat=\"48.8371429443359\" lon=\"2.40807366371155\"><ele>52.965</ele><time>2007-04-15T09:05:29Z</time></trkpt><trkpt lat=\"48.8369827270508\" lon=\"2.40807104110718\"><ele>52.6392</ele><time>2007-04-15T09:05:30Z</time></trkpt><trkpt lat=\"48.8368835449219\" lon=\"2.40795063972473\"><ele>52.401</ele><time>2007-04-15T09:05:31Z</time></trkpt><trkpt lat=\"48.8368225097656\" lon=\"2.40787887573242\"><ele>52.272</ele><time>2007-04-15T09:05:32Z</time></trkpt><trkpt lat=\"48.8368110656738\" lon=\"2.4078574180603\"><ele>52.2476</ele><time>2007-04-15T09:05:33Z</time></trkpt><trkpt lat=\"48.8367805480957\" lon=\"2.40778803825378\"><ele>52.1839</ele><time>2007-04-15T09:05:34Z</time></trkpt><trkpt lat=\"48.8367729187012\" lon=\"2.40776300430298\"><ele>52.1677</ele><time>2007-04-15T09:05:35Z</time></trkpt><trkpt lat=\"48.8367691040039\" lon=\"2.4077627658844\"><ele>52.1617</ele><time>2007-04-15T09:05:36Z</time></trkpt><trkpt lat=\"48.8367004394531\" lon=\"2.40776038169861\"><ele>52.0532</ele><time>2007-04-15T09:05:37Z</time></trkpt><trkpt lat=\"48.8367080688477\" lon=\"2.40771865844727\"><ele>52.0627</ele><time>2007-04-15T09:05:38Z</time></trkpt><trkpt lat=\"48.8367118835449\" lon=\"2.40772104263306\"><ele>52.0687</ele><time>2007-04-15T09:05:39Z</time></trkpt><trkpt lat=\"48.8367118835449\" lon=\"2.40771508216858\"><ele>52.0683</ele><time>2007-04-15T09:05:40Z</time></trkpt><trkpt lat=\"48.8367118835449\" lon=\"2.40769696235657\"><ele>52.0671</ele><time>2007-04-15T09:05:41Z</time></trkpt><trkpt lat=\"48.8366889953613\" lon=\"2.40771675109863\"><ele>52.0338</ele><time>2007-04-15T09:05:42Z</time></trkpt><trkpt lat=\"48.8366394042969\" lon=\"2.40772080421448\"><ele>52.0674</ele><time>2007-04-15T09:05:43Z</time></trkpt><trkpt lat=\"48.836555480957\" lon=\"2.4076566696167\"><ele>52.2338</ele><time>2007-04-15T09:05:44Z</time></trkpt><trkpt lat=\"48.8365058898926\" lon=\"2.40761375427246\"><ele>52.2983</ele><time>2007-04-15T09:05:45Z</time></trkpt><trkpt lat=\"48.836483001709\" lon=\"2.40760278701782\"><ele>52.3291</ele><time>2007-04-15T09:05:46Z</time></trkpt><trkpt lat=\"48.8364791870117\" lon=\"2.40760016441345\"><ele>52.3331</ele><time>2007-04-15T09:05:47Z</time></trkpt><trkpt lat=\"48.8364105224609\" lon=\"2.40754675865173\"><ele>52.3764</ele><time>2007-04-15T09:05:48Z</time></trkpt><trkpt lat=\"48.8362617492676\" lon=\"2.40739130973816\"><ele>51.8374</ele><time>2007-04-15T09:05:49Z</time></trkpt><trkpt lat=\"48.8361358642578\" lon=\"2.40726327896118\"><ele>51.1388</ele><time>2007-04-15T09:05:50Z</time></trkpt><trkpt lat=\"48.8360176086426\" lon=\"2.40716361999512\"><ele>50.5355</ele><time>2007-04-15T09:05:51Z</time></trkpt><trkpt lat=\"48.8359298706055\" lon=\"2.40707087516785\"><ele>49.9138</ele><time>2007-04-15T09:05:52Z</time></trkpt><trkpt lat=\"48.8358573913574\" lon=\"2.407057762146\"><ele>49.8177</ele><time>2007-04-15T09:05:53Z</time></trkpt><trkpt lat=\"48.8357276916504\" lon=\"2.40700197219849\"><ele>49.5395</ele><time>2007-04-15T09:05:54Z</time></trkpt><trkpt lat=\"48.8355751037598\" lon=\"2.40695858001709\"><ele>49.4887</ele><time>2007-04-15T09:05:55Z</time></trkpt><trkpt lat=\"48.8354072570801\" lon=\"2.40691757202148\"><ele>49.5707</ele><time>2007-04-15T09:05:56Z</time></trkpt><trkpt lat=\"48.8352851867676\" lon=\"2.40696477890015\"><ele>49.9432</ele><time>2007-04-15T09:05:57Z</time></trkpt><trkpt lat=\"48.8352241516113\" lon=\"2.40708017349243\"><ele>50.3566</ele><time>2007-04-15T09:05:58Z</time></trkpt><trkpt lat=\"48.8351516723633\" lon=\"2.40727305412292\"><ele>50.8438</ele><time>2007-04-15T09:05:59Z</time></trkpt><trkpt lat=\"48.8350982666016\" lon=\"2.40742874145508\"><ele>51.0999</ele><time>2007-04-15T09:06:00Z</time></trkpt><trkpt lat=\"48.8350410461426\" lon=\"2.4075779914856\"><ele>51.2949</ele><time>2007-04-15T09:06:01Z</time></trkpt><trkpt lat=\"48.8349609375\" lon=\"2.40780735015869\"><ele>51.8733</ele><time>2007-04-15T09:06:02Z</time></trkpt><trkpt lat=\"48.8349342346191\" lon=\"2.40802955627441\"><ele>52.4362</ele><time>2007-04-15T09:06:03Z</time></trkpt><trkpt lat=\"48.8349227905273\" lon=\"2.40827226638794\"><ele>52.9665</ele><time>2007-04-15T09:06:04Z</time></trkpt><trkpt lat=\"48.8348922729492\" lon=\"2.40847373008728\"><ele>52.8955</ele><time>2007-04-15T09:06:05Z</time></trkpt><trkpt lat=\"48.834831237793\" lon=\"2.40871906280518\"><ele>52.4584</ele><time>2007-04-15T09:06:06Z</time></trkpt><trkpt lat=\"48.8347663879394\" lon=\"2.40888690948486\"><ele>52.0574</ele><time>2007-04-15T09:06:07Z</time></trkpt><trkpt lat=\"48.8346786499023\" lon=\"2.40913605690002\"><ele>51.308</ele><time>2007-04-15T09:06:08Z</time></trkpt><trkpt lat=\"48.8346099853516\" lon=\"2.40933632850647\"><ele>50.8604</ele><time>2007-04-15T09:06:09Z</time></trkpt><trkpt lat=\"48.8345603942871\" lon=\"2.40950202941895\"><ele>50.5425</ele><time>2007-04-15T09:06:10Z</time></trkpt><trkpt lat=\"48.8344955444336\" lon=\"2.40972495079041\"><ele>50.1194</ele><time>2007-04-15T09:06:11Z</time></trkpt><trkpt lat=\"48.8344459533691\" lon=\"2.40991306304932\"><ele>49.7746</ele><time>2007-04-15T09:06:12Z</time></trkpt><trkpt lat=\"48.834400177002\" lon=\"2.41008615493774\"><ele>49.3412</ele><time>2007-04-15T09:06:13Z</time></trkpt><trkpt lat=\"48.8343467712402\" lon=\"2.4102988243103\"><ele>48.7637</ele><time>2007-04-15T09:06:14Z</time></trkpt><trkpt lat=\"48.8343048095703\" lon=\"2.41047215461731\"><ele>48.3893</ele><time>2007-04-15T09:06:15Z</time></trkpt><trkpt lat=\"48.8342552185059\" lon=\"2.41064786911011\"><ele>48.1046</ele><time>2007-04-15T09:06:16Z</time></trkpt><trkpt lat=\"48.8341903686523\" lon=\"2.41088604927063\"><ele>48.0714</ele><time>2007-04-15T09:06:17Z</time></trkpt><trkpt lat=\"48.8341255187988\" lon=\"2.41113448143005\"><ele>48.6912</ele><time>2007-04-15T09:06:18Z</time></trkpt><trkpt lat=\"48.8340530395508\" lon=\"2.4113597869873\"><ele>49.2133</ele><time>2007-04-15T09:06:19Z</time></trkpt><trkpt lat=\"48.8340072631836\" lon=\"2.41150546073914\"><ele>49.5761</ele><time>2007-04-15T09:06:20Z</time></trkpt><trkpt lat=\"48.8339691162109\" lon=\"2.41168546676636\"><ele>50.0398</ele><time>2007-04-15T09:06:21Z</time></trkpt><trkpt lat=\"48.8339424133301\" lon=\"2.41183304786682\"><ele>50.3456</ele><time>2007-04-15T09:06:22Z</time></trkpt><trkpt lat=\"48.833911895752\" lon=\"2.41203713417053\"><ele>50.7532</ele><time>2007-04-15T09:06:23Z</time></trkpt><trkpt lat=\"48.8338737487793\" lon=\"2.41229295730591\"><ele>51.2389</ele><time>2007-04-15T09:06:24Z</time></trkpt><trkpt lat=\"48.8338394165039\" lon=\"2.41256928443909\"><ele>51.8241</ele><time>2007-04-15T09:06:25Z</time></trkpt><trkpt lat=\"48.8338165283203\" lon=\"2.41285705566406\"><ele>52.6852</ele><time>2007-04-15T09:06:26Z</time></trkpt><trkpt lat=\"48.8338165283203\" lon=\"2.41303420066834\"><ele>53.2336</ele><time>2007-04-15T09:06:27Z</time></trkpt><trkpt lat=\"48.8337860107422\" lon=\"2.4132285118103\"><ele>53.7665</ele><time>2007-04-15T09:06:28Z</time></trkpt><trkpt lat=\"48.8337593078613\" lon=\"2.41340827941895\"><ele>53.8445</ele><time>2007-04-15T09:06:29Z</time></trkpt><trkpt lat=\"48.8337554931641\" lon=\"2.41362476348877\"><ele>53.3184</ele><time>2007-04-15T09:06:30Z</time></trkpt><trkpt lat=\"48.8337516784668\" lon=\"2.4138286113739\"><ele>52.8178</ele><time>2007-04-15T09:06:31Z</time></trkpt><trkpt lat=\"48.8337326049805\" lon=\"2.41394138336182\"><ele>52.4685</ele><time>2007-04-15T09:06:32Z</time></trkpt><trkpt lat=\"48.8337249755859\" lon=\"2.41424441337585\"><ele>51.8967</ele><time>2007-04-15T09:06:33Z</time></trkpt><trkpt lat=\"48.8337211608887\" lon=\"2.41444325447083\"><ele>51.9305</ele><time>2007-04-15T09:06:34Z</time></trkpt><trkpt lat=\"48.833740234375\" lon=\"2.41465139389038\"><ele>51.994</ele><time>2007-04-15T09:06:35Z</time></trkpt><trkpt lat=\"48.8337516784668\" lon=\"2.41481828689575\"><ele>51.9986</ele><time>2007-04-15T09:06:36Z</time></trkpt><trkpt lat=\"48.8337669372559\" lon=\"2.41500449180603\"><ele>51.9622</ele><time>2007-04-15T09:06:37Z</time></trkpt><trkpt lat=\"48.8337707519531\" lon=\"2.41504168510437\"><ele>51.9765</ele><time>2007-04-15T09:06:38Z</time></trkpt><trkpt lat=\"48.833797454834\" lon=\"2.41522574424744\"><ele>52.037</ele><time>2007-04-15T09:06:39Z</time></trkpt><trkpt lat=\"48.8338203430176\" lon=\"2.41544389724731\"><ele>52.1425</ele><time>2007-04-15T09:06:40Z</time></trkpt><trkpt lat=\"48.8338203430176\" lon=\"2.41548228263855\"><ele>52.1694</ele><time>2007-04-15T09:06:41Z</time></trkpt><trkpt lat=\"48.8338623046875\" lon=\"2.41575384140015\"><ele>52.3047</ele><time>2007-04-15T09:06:42Z</time></trkpt><trkpt lat=\"48.8338928222656\" lon=\"2.41598463058472\"><ele>52.5127</ele><time>2007-04-15T09:06:43Z</time></trkpt><trkpt lat=\"48.8339576721191\" lon=\"2.4162495136261\"><ele>52.8739</ele><time>2007-04-15T09:06:44Z</time></trkpt><trkpt lat=\"48.8340034484863\" lon=\"2.41647791862488\"><ele>53.2884</ele><time>2007-04-15T09:06:45Z</time></trkpt><trkpt lat=\"48.8340759277344\" lon=\"2.41672706604004\"><ele>53.6531</ele><time>2007-04-15T09:06:46Z</time></trkpt><trkpt lat=\"48.834114074707\" lon=\"2.41691970825195\"><ele>53.3048</ele><time>2007-04-15T09:06:47Z</time></trkpt><trkpt lat=\"48.8341636657715\" lon=\"2.41709685325623\"><ele>52.9641</ele><time>2007-04-15T09:06:48Z</time></trkpt><trkpt lat=\"48.8342056274414\" lon=\"2.41726422309876\"><ele>52.6664</ele><time>2007-04-15T09:06:49Z</time></trkpt><trkpt lat=\"48.8342666625977\" lon=\"2.41747069358826\"><ele>52.4177</ele><time>2007-04-15T09:06:50Z</time></trkpt><trkpt lat=\"48.8342742919922\" lon=\"2.41750526428223\"><ele>52.3803</ele><time>2007-04-15T09:06:51Z</time></trkpt><trkpt lat=\"48.8343620300293\" lon=\"2.41767621040344\"><ele>52.4423</ele><time>2007-04-15T09:06:52Z</time></trkpt><trkpt lat=\"48.8344230651856\" lon=\"2.41784453392029\"><ele>52.3824</ele><time>2007-04-15T09:06:53Z</time></trkpt><trkpt lat=\"48.8344993591309\" lon=\"2.41800928115845\"><ele>52.3426</ele><time>2007-04-15T09:06:54Z</time></trkpt><trkpt lat=\"48.8345375061035\" lon=\"2.41814303398132\"><ele>52.22</ele><time>2007-04-15T09:06:55Z</time></trkpt><trkpt lat=\"48.8345794677734\" lon=\"2.41837620735168\"><ele>52.0941</ele><time>2007-04-15T09:06:56Z</time></trkpt><trkpt lat=\"48.8346290588379\" lon=\"2.41851472854614\"><ele>52.5212</ele><time>2007-04-15T09:06:57Z</time></trkpt><trkpt lat=\"48.8346900939941\" lon=\"2.41868662834167\"><ele>52.9955</ele><time>2007-04-15T09:06:58Z</time></trkpt><trkpt lat=\"48.834716796875\" lon=\"2.41875386238098\"><ele>53.1679</ele><time>2007-04-15T09:06:59Z</time></trkpt><trkpt lat=\"48.8347930908203\" lon=\"2.41900873184204\"><ele>53.7164</ele><time>2007-04-15T09:07:00Z</time></trkpt><trkpt lat=\"48.8348655700684\" lon=\"2.41924214363098\"><ele>54.0906</ele><time>2007-04-15T09:07:01Z</time></trkpt><trkpt lat=\"48.8349113464356\" lon=\"2.41944766044617\"><ele>54.3372</ele><time>2007-04-15T09:07:02Z</time></trkpt><trkpt lat=\"48.8349647521973\" lon=\"2.41962289810181\"><ele>54.5475</ele><time>2007-04-15T09:07:03Z</time></trkpt><trkpt lat=\"48.8350257873535\" lon=\"2.41983342170715\"><ele>54.8682</ele><time>2007-04-15T09:07:04Z</time></trkpt><trkpt lat=\"48.8350791931152\" lon=\"2.41999793052673\"><ele>55.1878</ele><time>2007-04-15T09:07:05Z</time></trkpt><trkpt lat=\"48.8351211547852\" lon=\"2.42013621330261\"><ele>55.1273</ele><time>2007-04-15T09:07:06Z</time></trkpt><trkpt lat=\"48.835205078125\" lon=\"2.42033672332764\"><ele>55.0881</ele><time>2007-04-15T09:07:07Z</time></trkpt><trkpt lat=\"48.8352813720703\" lon=\"2.42058491706848\"><ele>54.9734</ele><time>2007-04-15T09:07:08Z</time></trkpt><trkpt lat=\"48.8353271484375\" lon=\"2.42076516151428\"><ele>54.867</ele><time>2007-04-15T09:07:09Z</time></trkpt><trkpt lat=\"48.8354072570801\" lon=\"2.42103576660156\"><ele>55.3445</ele><time>2007-04-15T09:07:10Z</time></trkpt><trkpt lat=\"48.8354911804199\" lon=\"2.42126822471619\"><ele>55.915</ele><time>2007-04-15T09:07:11Z</time></trkpt><trkpt lat=\"48.8355598449707\" lon=\"2.42147636413574\"><ele>56.3685</ele><time>2007-04-15T09:07:12Z</time></trkpt><trkpt lat=\"48.8356323242188\" lon=\"2.42167735099792\"><ele>56.7234</ele><time>2007-04-15T09:07:13Z</time></trkpt><trkpt lat=\"48.8357086181641\" lon=\"2.42192459106445\"><ele>55.9681</ele><time>2007-04-15T09:07:14Z</time></trkpt><trkpt lat=\"48.8357925415039\" lon=\"2.42211389541626\"><ele>55.3673</ele><time>2007-04-15T09:07:15Z</time></trkpt><trkpt lat=\"48.8358573913574\" lon=\"2.42228364944458\"><ele>54.7852</ele><time>2007-04-15T09:07:16Z</time></trkpt><trkpt lat=\"48.8359451293945\" lon=\"2.42246723175049\"><ele>54.2363</ele><time>2007-04-15T09:07:17Z</time></trkpt><trkpt lat=\"48.8360214233398\" lon=\"2.42265224456787\"><ele>53.6776</ele><time>2007-04-15T09:07:18Z</time></trkpt><trkpt lat=\"48.8361053466797\" lon=\"2.42281746864319\"><ele>53.1835</ele><time>2007-04-15T09:07:19Z</time></trkpt><trkpt lat=\"48.8361778259277\" lon=\"2.4229633808136\"><ele>52.7452</ele><time>2007-04-15T09:07:20Z</time></trkpt><trkpt lat=\"48.8362655639648\" lon=\"2.42315697669983\"><ele>52.1536</ele><time>2007-04-15T09:07:21Z</time></trkpt><trkpt lat=\"48.8363418579102\" lon=\"2.42330026626587\"><ele>51.7293</ele><time>2007-04-15T09:07:22Z</time></trkpt><trkpt lat=\"48.8364295959473\" lon=\"2.42346501350403\"><ele>51.8054</ele><time>2007-04-15T09:07:23Z</time></trkpt><trkpt lat=\"48.8365058898926\" lon=\"2.42361211776733\"><ele>51.9362</ele><time>2007-04-15T09:07:24Z</time></trkpt><trkpt lat=\"48.8366088867188\" lon=\"2.42378950119019\"><ele>52.0066</ele><time>2007-04-15T09:07:25Z</time></trkpt><trkpt lat=\"48.836727142334\" lon=\"2.42399048805237\"><ele>51.8702</ele><time>2007-04-15T09:07:26Z</time></trkpt><trkpt lat=\"48.8368301391602\" lon=\"2.42417049407959\"><ele>51.6132</ele><time>2007-04-15T09:07:27Z</time></trkpt><trkpt lat=\"48.8369178771973\" lon=\"2.42435598373413\"><ele>51.6928</ele><time>2007-04-15T09:07:28Z</time></trkpt><trkpt lat=\"48.8370018005371\" lon=\"2.42449903488159\"><ele>51.7549</ele><time>2007-04-15T09:07:29Z</time></trkpt><trkpt lat=\"48.8370742797852\" lon=\"2.42465472221374\"><ele>51.8939</ele><time>2007-04-15T09:07:30Z</time></trkpt><trkpt lat=\"48.8371772766113\" lon=\"2.42478847503662\"><ele>51.9779</ele><time>2007-04-15T09:07:31Z</time></trkpt><trkpt lat=\"48.8372840881348\" lon=\"2.42495894432068\"><ele>52.1733</ele><time>2007-04-15T09:07:32Z</time></trkpt><trkpt lat=\"48.8373870849609\" lon=\"2.42514419555664\"><ele>52.2851</ele><time>2007-04-15T09:07:33Z</time></trkpt><trkpt lat=\"48.8375053405762\" lon=\"2.4253466129303\"><ele>52.394</ele><time>2007-04-15T09:07:34Z</time></trkpt><trkpt lat=\"48.8376045227051\" lon=\"2.42549991607666\"><ele>52.1484</ele><time>2007-04-15T09:07:35Z</time></trkpt><trkpt lat=\"48.8377304077148\" lon=\"2.42567038536072\"><ele>51.7526</ele><time>2007-04-15T09:07:36Z</time></trkpt><trkpt lat=\"48.837833404541\" lon=\"2.42584228515625\"><ele>51.3889</ele><time>2007-04-15T09:07:37Z</time></trkpt><trkpt lat=\"48.8379364013672\" lon=\"2.42601299285889\"><ele>50.6897</ele><time>2007-04-15T09:07:38Z</time></trkpt><trkpt lat=\"48.8380355834961\" lon=\"2.42618846893311\"><ele>50.003</ele><time>2007-04-15T09:07:39Z</time></trkpt><trkpt lat=\"48.8381500244141\" lon=\"2.42639851570129\"><ele>49.2017</ele><time>2007-04-15T09:07:40Z</time></trkpt><trkpt lat=\"48.8382225036621\" lon=\"2.42656230926514\"><ele>48.6572</ele><time>2007-04-15T09:07:41Z</time></trkpt><trkpt lat=\"48.8382377624512\" lon=\"2.42659401893616\"><ele>48.5459</ele><time>2007-04-15T09:07:42Z</time></trkpt><trkpt lat=\"48.8383255004883\" lon=\"2.42678332328796\"><ele>47.7589</ele><time>2007-04-15T09:07:43Z</time></trkpt><trkpt lat=\"48.8384132385254\" lon=\"2.42698216438293\"><ele>47.2791</ele><time>2007-04-15T09:07:44Z</time></trkpt><trkpt lat=\"48.8384971618652\" lon=\"2.42718410491943\"><ele>46.8802</ele><time>2007-04-15T09:07:45Z</time></trkpt><trkpt lat=\"48.8385734558106\" lon=\"2.42738366127014\"><ele>46.5271</ele><time>2007-04-15T09:07:46Z</time></trkpt><trkpt lat=\"48.8386421203613\" lon=\"2.42754197120666\"><ele>46.4022</ele><time>2007-04-15T09:07:47Z</time></trkpt><trkpt lat=\"48.8387145996094\" lon=\"2.42769932746887\"><ele>46.5873</ele><time>2007-04-15T09:07:48Z</time></trkpt><trkpt lat=\"48.8387680053711\" lon=\"2.42783236503601\"><ele>46.7124</ele><time>2007-04-15T09:07:49Z</time></trkpt><trkpt lat=\"48.8388366699219\" lon=\"2.42800641059876\"><ele>46.8446</ele><time>2007-04-15T09:07:50Z</time></trkpt><trkpt lat=\"48.8389167785644\" lon=\"2.42821335792542\"><ele>46.9568</ele><time>2007-04-15T09:07:51Z</time></trkpt><trkpt lat=\"48.8389778137207\" lon=\"2.42837381362915\"><ele>47.011</ele><time>2007-04-15T09:07:52Z</time></trkpt><trkpt lat=\"48.8390312194824\" lon=\"2.42854285240173\"><ele>47.0409</ele><time>2007-04-15T09:07:53Z</time></trkpt><trkpt lat=\"48.8390808105469\" lon=\"2.42871785163879\"><ele>47.0475</ele><time>2007-04-15T09:07:54Z</time></trkpt><trkpt lat=\"48.8391609191894\" lon=\"2.42895317077637\"><ele>47.0051</ele><time>2007-04-15T09:07:55Z</time></trkpt><trkpt lat=\"48.8392295837402\" lon=\"2.42915344238281\"><ele>47.0731</ele><time>2007-04-15T09:07:56Z</time></trkpt><trkpt lat=\"48.8392677307129\" lon=\"2.42934083938599\"><ele>47.1213</ele><time>2007-04-15T09:07:57Z</time></trkpt><trkpt lat=\"48.8393211364746\" lon=\"2.42955732345581\"><ele>47.1854</ele><time>2007-04-15T09:07:58Z</time></trkpt><trkpt lat=\"48.8393745422363\" lon=\"2.42977786064148\"><ele>47.2495</ele><time>2007-04-15T09:07:59Z</time></trkpt><trkpt lat=\"48.8394355773926\" lon=\"2.4300365447998\"><ele>47.2661</ele><time>2007-04-15T09:08:00Z</time></trkpt><trkpt lat=\"48.8395042419434\" lon=\"2.43028855323792\"><ele>46.844</ele><time>2007-04-15T09:08:01Z</time></trkpt><trkpt lat=\"48.8395729064941\" lon=\"2.43049573898315\"><ele>46.3275</ele><time>2007-04-15T09:08:02Z</time></trkpt><trkpt lat=\"48.8396224975586\" lon=\"2.43063545227051\"><ele>45.8786</ele><time>2007-04-15T09:08:03Z</time></trkpt><trkpt lat=\"48.839656829834\" lon=\"2.43079423904419\"><ele>45.3458</ele><time>2007-04-15T09:08:04Z</time></trkpt><trkpt lat=\"48.8397026062012\" lon=\"2.43101096153259\"><ele>45.4058</ele><time>2007-04-15T09:08:05Z</time></trkpt><trkpt lat=\"48.8397445678711\" lon=\"2.4311900138855\"><ele>45.6788</ele><time>2007-04-15T09:08:06Z</time></trkpt><trkpt lat=\"48.839786529541\" lon=\"2.43135738372803\"><ele>46.0107</ele><time>2007-04-15T09:08:07Z</time></trkpt><trkpt lat=\"48.8398284912109\" lon=\"2.43153142929077\"><ele>46.4409</ele><time>2007-04-15T09:08:08Z</time></trkpt><trkpt lat=\"48.8398704528809\" lon=\"2.43174457550049\"><ele>47.0025</ele><time>2007-04-15T09:08:09Z</time></trkpt><trkpt lat=\"48.8399200439453\" lon=\"2.43195366859436\"><ele>47.5268</ele><time>2007-04-15T09:08:10Z</time></trkpt><trkpt lat=\"48.839973449707\" lon=\"2.4321186542511\"><ele>48.0183</ele><time>2007-04-15T09:08:11Z</time></trkpt><trkpt lat=\"48.8400115966797\" lon=\"2.43228816986084\"><ele>48.5298</ele><time>2007-04-15T09:08:12Z</time></trkpt><trkpt lat=\"48.8400611877441\" lon=\"2.43246507644653\"><ele>49.1334</ele><time>2007-04-15T09:08:13Z</time></trkpt><trkpt lat=\"48.8401412963867\" lon=\"2.43272423744202\"><ele>49.6865</ele><time>2007-04-15T09:08:14Z</time></trkpt><trkpt lat=\"48.8401870727539\" lon=\"2.43290543556213\"><ele>49.9415</ele><time>2007-04-15T09:08:15Z</time></trkpt><trkpt lat=\"48.8402519226074\" lon=\"2.43312835693359\"><ele>50.2051</ele><time>2007-04-15T09:08:16Z</time></trkpt><trkpt lat=\"48.8402976989746\" lon=\"2.43336462974548\"><ele>50.3814</ele><time>2007-04-15T09:08:17Z</time></trkpt><trkpt lat=\"48.8403625488281\" lon=\"2.43362522125244\"><ele>50.6329</ele><time>2007-04-15T09:08:18Z</time></trkpt><trkpt lat=\"48.840404510498\" lon=\"2.43375611305237\"><ele>50.7465</ele><time>2007-04-15T09:08:19Z</time></trkpt><trkpt lat=\"48.8404693603516\" lon=\"2.43401598930359\"><ele>50.921</ele><time>2007-04-15T09:08:20Z</time></trkpt><trkpt lat=\"48.8405151367188\" lon=\"2.43423175811768\"><ele>51.0966</ele><time>2007-04-15T09:08:21Z</time></trkpt><trkpt lat=\"48.8405532836914\" lon=\"2.43443465232849\"><ele>51.427</ele><time>2007-04-15T09:08:22Z</time></trkpt><trkpt lat=\"48.8405494689941\" lon=\"2.43456602096558\"><ele>51.632</ele><time>2007-04-15T09:08:23Z</time></trkpt><trkpt lat=\"48.8405227661133\" lon=\"2.4347460269928\"><ele>51.8723</ele><time>2007-04-15T09:08:24Z</time></trkpt><trkpt lat=\"48.8404922485352\" lon=\"2.43494987487793\"><ele>52.1103</ele><time>2007-04-15T09:08:25Z</time></trkpt><trkpt lat=\"48.8404693603516\" lon=\"2.43515682220459\"><ele>51.7739</ele><time>2007-04-15T09:08:26Z</time></trkpt><trkpt lat=\"48.8404502868652\" lon=\"2.43537139892578\"><ele>51.2253</ele><time>2007-04-15T09:08:27Z</time></trkpt><trkpt lat=\"48.8404350280762\" lon=\"2.43558120727539\"><ele>50.6799</ele><time>2007-04-15T09:08:28Z</time></trkpt><trkpt lat=\"48.8404197692871\" lon=\"2.43579459190369\"><ele>50.1075</ele><time>2007-04-15T09:08:29Z</time></trkpt><trkpt lat=\"48.8404121398926\" lon=\"2.43597960472107\"><ele>50.1557</ele><time>2007-04-15T09:08:30Z</time></trkpt><trkpt lat=\"48.8404159545898\" lon=\"2.43617367744446\"><ele>50.4057</ele><time>2007-04-15T09:08:31Z</time></trkpt><trkpt lat=\"48.840461730957\" lon=\"2.43638563156128\"><ele>50.8074</ele><time>2007-04-15T09:08:32Z</time></trkpt><trkpt lat=\"48.8405113220215\" lon=\"2.43660473823547\"><ele>51.1697</ele><time>2007-04-15T09:08:33Z</time></trkpt><trkpt lat=\"48.8405418395996\" lon=\"2.43682479858398\"><ele>51.2434</ele><time>2007-04-15T09:08:34Z</time></trkpt><trkpt lat=\"48.8405418395996\" lon=\"2.4370424747467\"><ele>51.1649</ele><time>2007-04-15T09:08:35Z</time></trkpt><trkpt lat=\"48.8405227661133\" lon=\"2.43725752830505\"><ele>51.0741</ele><time>2007-04-15T09:08:36Z</time></trkpt><trkpt lat=\"48.8405113220215\" lon=\"2.43743205070496\"><ele>51.0185</ele><time>2007-04-15T09:08:37Z</time></trkpt><trkpt lat=\"48.8404922485352\" lon=\"2.43760538101196\"><ele>51.0518</ele><time>2007-04-15T09:08:38Z</time></trkpt><trkpt lat=\"48.8404731750488\" lon=\"2.43782353401184\"><ele>51.1678</ele><time>2007-04-15T09:08:39Z</time></trkpt><trkpt lat=\"48.8404541015625\" lon=\"2.43805122375488\"><ele>51.301</ele><time>2007-04-15T09:08:40Z</time></trkpt><trkpt lat=\"48.8404426574707\" lon=\"2.43827724456787\"><ele>51.4373</ele><time>2007-04-15T09:08:41Z</time></trkpt><trkpt lat=\"48.8404273986816\" lon=\"2.43853855133057\"><ele>51.4871</ele><time>2007-04-15T09:08:42Z</time></trkpt><trkpt lat=\"48.8404197692871\" lon=\"2.4387309551239\"><ele>51.4963</ele><time>2007-04-15T09:08:43Z</time></trkpt><trkpt lat=\"48.8404006958008\" lon=\"2.43898558616638\"><ele>51.5192</ele><time>2007-04-15T09:08:44Z</time></trkpt><trkpt lat=\"48.840389251709\" lon=\"2.4391667842865\"><ele>51.5329</ele><time>2007-04-15T09:08:45Z</time></trkpt><trkpt lat=\"48.8403701782227\" lon=\"2.43934464454651\"><ele>51.5081</ele><time>2007-04-15T09:08:46Z</time></trkpt><trkpt lat=\"48.8403663635254\" lon=\"2.43938040733337\"><ele>51.4984</ele><time>2007-04-15T09:08:47Z</time></trkpt><trkpt lat=\"48.8403472900391\" lon=\"2.43956184387207\"><ele>51.4253</ele><time>2007-04-15T09:08:48Z</time></trkpt><trkpt lat=\"48.8403358459473\" lon=\"2.43975210189819\"><ele>51.3244</ele><time>2007-04-15T09:08:49Z</time></trkpt><trkpt lat=\"48.8403205871582\" lon=\"2.43993306159973\"><ele>51.1912</ele><time>2007-04-15T09:08:50Z</time></trkpt><trkpt lat=\"48.8402976989746\" lon=\"2.44018983840942\"><ele>50.8439</ele><time>2007-04-15T09:08:51Z</time></trkpt><trkpt lat=\"48.8402976989746\" lon=\"2.44037818908691\"><ele>50.6179</ele><time>2007-04-15T09:08:52Z</time></trkpt><trkpt lat=\"48.8402900695801\" lon=\"2.44055891036987\"><ele>50.3736</ele><time>2007-04-15T09:08:53Z</time></trkpt><trkpt lat=\"48.8402671813965\" lon=\"2.44071102142334\"><ele>50.1086</ele><time>2007-04-15T09:08:54Z</time></trkpt><trkpt lat=\"48.8402328491211\" lon=\"2.44093990325928\"><ele>49.7104</ele><time>2007-04-15T09:08:55Z</time></trkpt><trkpt lat=\"48.8401908874512\" lon=\"2.44116306304932\"><ele>49.2915</ele><time>2007-04-15T09:08:56Z</time></trkpt><trkpt lat=\"48.8401756286621\" lon=\"2.44134497642517\"><ele>49.0183</ele><time>2007-04-15T09:08:57Z</time></trkpt><trkpt lat=\"48.8401718139648\" lon=\"2.44156908988953\"><ele>48.7356</ele><time>2007-04-15T09:08:58Z</time></trkpt><trkpt lat=\"48.840160369873\" lon=\"2.44175028800964\"><ele>48.558</ele><time>2007-04-15T09:08:59Z</time></trkpt><trkpt lat=\"48.840145111084\" lon=\"2.44201946258545\"><ele>48.4487</ele><time>2007-04-15T09:09:00Z</time></trkpt><trkpt lat=\"48.8401260375977\" lon=\"2.44220805168152\"><ele>48.3555</ele><time>2007-04-15T09:09:01Z</time></trkpt><trkpt lat=\"48.8401031494141\" lon=\"2.44240212440491\"><ele>48.2621</ele><time>2007-04-15T09:09:02Z</time></trkpt><trkpt lat=\"48.8400840759277\" lon=\"2.44266629219055\"><ele>48.3611</ele><time>2007-04-15T09:09:03Z</time></trkpt><trkpt lat=\"48.8400688171387\" lon=\"2.44289827346802\"><ele>48.5642</ele><time>2007-04-15T09:09:04Z</time></trkpt><trkpt lat=\"48.8400344848633\" lon=\"2.44316172599792\"><ele>48.8111</ele><time>2007-04-15T09:09:05Z</time></trkpt><trkpt lat=\"48.8400192260742\" lon=\"2.44339179992676\"><ele>49.204</ele><time>2007-04-15T09:09:06Z</time></trkpt><trkpt lat=\"48.8400077819824\" lon=\"2.4435818195343\"><ele>49.8834</ele><time>2007-04-15T09:09:07Z</time></trkpt><trkpt lat=\"48.8399848937988\" lon=\"2.44384145736694\"><ele>50.793</ele><time>2007-04-15T09:09:08Z</time></trkpt><trkpt lat=\"48.839973449707\" lon=\"2.44407415390015\"><ele>51.6032</ele><time>2007-04-15T09:09:09Z</time></trkpt><trkpt lat=\"48.839958190918\" lon=\"2.44430541992188\"><ele>52.0745</ele><time>2007-04-15T09:09:10Z</time></trkpt><trkpt lat=\"48.8399391174316\" lon=\"2.44452285766602\"><ele>52.3125</ele><time>2007-04-15T09:09:11Z</time></trkpt><trkpt lat=\"48.8399200439453\" lon=\"2.44472646713257\"><ele>52.5443</ele><time>2007-04-15T09:09:12Z</time></trkpt><trkpt lat=\"48.8398933410644\" lon=\"2.44492292404175\"><ele>52.7677</ele><time>2007-04-15T09:09:13Z</time></trkpt><trkpt lat=\"48.8398628234863\" lon=\"2.44517588615417\"><ele>52.5175</ele><time>2007-04-15T09:09:14Z</time></trkpt><trkpt lat=\"48.8398399353027\" lon=\"2.44539022445679\"><ele>52.1412</ele><time>2007-04-15T09:09:15Z</time></trkpt><trkpt lat=\"48.8398094177246\" lon=\"2.44565677642822\"><ele>51.7358</ele><time>2007-04-15T09:09:16Z</time></trkpt><trkpt lat=\"48.8398132324219\" lon=\"2.4458498954773\"><ele>51.4482</ele><time>2007-04-15T09:09:17Z</time></trkpt><trkpt lat=\"48.8397903442383\" lon=\"2.44602918624878\"><ele>51.5032</ele><time>2007-04-15T09:09:18Z</time></trkpt><trkpt lat=\"48.839771270752\" lon=\"2.44620895385742\"><ele>51.549</ele><time>2007-04-15T09:09:19Z</time></trkpt><trkpt lat=\"48.8397560119629\" lon=\"2.44643568992615\"><ele>51.5856</ele><time>2007-04-15T09:09:20Z</time></trkpt><trkpt lat=\"48.8397178649902\" lon=\"2.44674372673035\"><ele>51.5533</ele><time>2007-04-15T09:09:21Z</time></trkpt><trkpt lat=\"48.8397026062012\" lon=\"2.44697594642639\"><ele>51.2102</ele><time>2007-04-15T09:09:22Z</time></trkpt><trkpt lat=\"48.8396835327148\" lon=\"2.44715738296509\"><ele>50.947</ele><time>2007-04-15T09:09:23Z</time></trkpt><trkpt lat=\"48.839672088623\" lon=\"2.44732975959778\"><ele>50.6782</ele><time>2007-04-15T09:09:24Z</time></trkpt><trkpt lat=\"48.8396682739258\" lon=\"2.44747591018677\"><ele>50.4385</ele><time>2007-04-15T09:09:25Z</time></trkpt><trkpt lat=\"48.8396415710449\" lon=\"2.44768071174622\"><ele>50.3998</ele><time>2007-04-15T09:09:26Z</time></trkpt><trkpt lat=\"48.839599609375\" lon=\"2.44789433479309\"><ele>50.462</ele><time>2007-04-15T09:09:27Z</time></trkpt><trkpt lat=\"48.8395309448242\" lon=\"2.44810461997986\"><ele>50.6541</ele><time>2007-04-15T09:09:28Z</time></trkpt><trkpt lat=\"48.8394775390625\" lon=\"2.44828724861145\"><ele>50.8668</ele><time>2007-04-15T09:09:29Z</time></trkpt><trkpt lat=\"48.8394165039062\" lon=\"2.44846844673157\"><ele>51.3113</ele><time>2007-04-15T09:09:30Z</time></trkpt><trkpt lat=\"48.8393592834473\" lon=\"2.44859552383423\"><ele>51.6939</ele><time>2007-04-15T09:09:31Z</time></trkpt><trkpt lat=\"48.8392944335938\" lon=\"2.44872307777405\"><ele>52.0794</ele><time>2007-04-15T09:09:32Z</time></trkpt><trkpt lat=\"48.839241027832\" lon=\"2.44883251190186\"><ele>52.3848</ele><time>2007-04-15T09:09:33Z</time></trkpt><trkpt lat=\"48.839168548584\" lon=\"2.44896745681763\"><ele>52.7559</ele><time>2007-04-15T09:09:34Z</time></trkpt><trkpt lat=\"48.8390884399414\" lon=\"2.4490909576416\"><ele>53.0116</ele><time>2007-04-15T09:09:35Z</time></trkpt><trkpt lat=\"48.8390121459961\" lon=\"2.44922637939453\"><ele>53.1854</ele><time>2007-04-15T09:09:36Z</time></trkpt><trkpt lat=\"48.8389511108398\" lon=\"2.44931960105896\"><ele>53.2587</ele><time>2007-04-15T09:09:37Z</time></trkpt><trkpt lat=\"48.8388481140137\" lon=\"2.44952034950256\"><ele>53.3823</ele><time>2007-04-15T09:09:38Z</time></trkpt><trkpt lat=\"48.8387680053711\" lon=\"2.44965529441834\"><ele>53.4784</ele><time>2007-04-15T09:09:39Z</time></trkpt><trkpt lat=\"48.838680267334\" lon=\"2.44984173774719\"><ele>53.5837</ele><time>2007-04-15T09:09:40Z</time></trkpt><trkpt lat=\"48.8385963439941\" lon=\"2.45002293586731\"><ele>53.6931</ele><time>2007-04-15T09:09:41Z</time></trkpt><trkpt lat=\"48.8385162353516\" lon=\"2.45018267631531\"><ele>53.8286</ele><time>2007-04-15T09:09:42Z</time></trkpt><trkpt lat=\"48.8384437561035\" lon=\"2.4502899646759\"><ele>53.9136</ele><time>2007-04-15T09:09:43Z</time></trkpt><trkpt lat=\"48.8383445739746\" lon=\"2.4504382610321\"><ele>53.9936</ele><time>2007-04-15T09:09:44Z</time></trkpt><trkpt lat=\"48.8382568359375\" lon=\"2.45058751106262\"><ele>53.9353</ele><time>2007-04-15T09:09:45Z</time></trkpt><trkpt lat=\"48.8381729125977\" lon=\"2.45077013969421\"><ele>53.8221</ele><time>2007-04-15T09:09:46Z</time></trkpt><trkpt lat=\"48.838077545166\" lon=\"2.45094013214111\"><ele>53.6931</ele><time>2007-04-15T09:09:47Z</time></trkpt><trkpt lat=\"48.8379859924316\" lon=\"2.45111751556396\"><ele>53.5832</ele><time>2007-04-15T09:09:48Z</time></trkpt><trkpt lat=\"48.8378753662109\" lon=\"2.45130491256714\"><ele>53.4504</ele><time>2007-04-15T09:09:49Z</time></trkpt><trkpt lat=\"48.8377647399902\" lon=\"2.45150065422058\"><ele>53.3177</ele><time>2007-04-15T09:09:50Z</time></trkpt><trkpt lat=\"48.8376693725586\" lon=\"2.45168423652649\"><ele>53.2032</ele><time>2007-04-15T09:09:51Z</time></trkpt><trkpt lat=\"48.837589263916\" lon=\"2.45181250572205\"><ele>53.1071</ele><time>2007-04-15T09:09:52Z</time></trkpt><trkpt lat=\"48.837574005127\" lon=\"2.4518404006958\"><ele>53.0888</ele><time>2007-04-15T09:09:53Z</time></trkpt><trkpt lat=\"48.8374862670898\" lon=\"2.45195960998535\"><ele>52.9728</ele><time>2007-04-15T09:09:54Z</time></trkpt><trkpt lat=\"48.8373603820801\" lon=\"2.45208644866943\"><ele>52.7493</ele><time>2007-04-15T09:09:55Z</time></trkpt><trkpt lat=\"48.8372268676758\" lon=\"2.45216941833496\"><ele>52.5422</ele><time>2007-04-15T09:09:56Z</time></trkpt><trkpt lat=\"48.8370933532715\" lon=\"2.45226168632507\"><ele>52.3725</ele><time>2007-04-15T09:09:57Z</time></trkpt><trkpt lat=\"48.8369598388672\" lon=\"2.45234608650208\"><ele>52.2321</ele><time>2007-04-15T09:09:58Z</time></trkpt><trkpt lat=\"48.8368530273438\" lon=\"2.45241832733154\"><ele>52.1475</ele><time>2007-04-15T09:09:59Z</time></trkpt><trkpt lat=\"48.8367004394531\" lon=\"2.4525101184845\"><ele>52.0765</ele><time>2007-04-15T09:10:00Z</time></trkpt><trkpt lat=\"48.8365745544434\" lon=\"2.45258975028992\"><ele>52.5323</ele><time>2007-04-15T09:10:01Z</time></trkpt><trkpt lat=\"48.8364677429199\" lon=\"2.45266819000244\"><ele>53.0347</ele><time>2007-04-15T09:10:02Z</time></trkpt><trkpt lat=\"48.8363609313965\" lon=\"2.45275926589966\"><ele>53.553</ele><time>2007-04-15T09:10:03Z</time></trkpt><trkpt lat=\"48.8362312316894\" lon=\"2.45285248756409\"><ele>54.093</ele><time>2007-04-15T09:10:04Z</time></trkpt><trkpt lat=\"48.8361015319824\" lon=\"2.45293688774109\"><ele>54.5736</ele><time>2007-04-15T09:10:05Z</time></trkpt><trkpt lat=\"48.8359756469727\" lon=\"2.45303177833557\"><ele>55.0437</ele><time>2007-04-15T09:10:06Z</time></trkpt><trkpt lat=\"48.8358726501465\" lon=\"2.45308518409729\"><ele>55.3432</ele><time>2007-04-15T09:10:07Z</time></trkpt><trkpt lat=\"48.8358345031738\" lon=\"2.45308494567871\"><ele>55.402</ele><time>2007-04-15T09:10:08Z</time></trkpt><trkpt lat=\"48.8357772827148\" lon=\"2.45299863815308\"><ele>55.1295</ele><time>2007-04-15T09:10:09Z</time></trkpt><trkpt lat=\"48.8356895446777\" lon=\"2.45279312133789\"><ele>54.5309</ele><time>2007-04-15T09:10:10Z</time></trkpt><trkpt lat=\"48.8356246948242\" lon=\"2.4526252746582\"><ele>54.0503</ele><time>2007-04-15T09:10:11Z</time></trkpt><trkpt lat=\"48.8355560302734\" lon=\"2.45239353179932\"><ele>53.4542</ele><time>2007-04-15T09:10:12Z</time></trkpt><trkpt lat=\"48.835506439209\" lon=\"2.45220422744751\"><ele>53.0371</ele><time>2007-04-15T09:10:13Z</time></trkpt><trkpt lat=\"48.8354568481445\" lon=\"2.45204615592957\"><ele>52.705</ele><time>2007-04-15T09:10:14Z</time></trkpt><trkpt lat=\"48.8353881835938\" lon=\"2.45185232162476\"><ele>52.3266</ele><time>2007-04-15T09:10:15Z</time></trkpt><trkpt lat=\"48.8353462219238\" lon=\"2.45171093940735\"><ele>52.0752</ele><time>2007-04-15T09:10:16Z</time></trkpt><trkpt lat=\"48.8352928161621\" lon=\"2.45157361030579\"><ele>52.0785</ele><time>2007-04-15T09:10:17Z</time></trkpt><trkpt lat=\"48.8352317810059\" lon=\"2.4513783454895\"><ele>52.1925</ele><time>2007-04-15T09:10:18Z</time></trkpt><trkpt lat=\"48.8351669311523\" lon=\"2.45116639137268\"><ele>52.2405</ele><time>2007-04-15T09:10:19Z</time></trkpt><trkpt lat=\"48.8351135253906\" lon=\"2.45095777511597\"><ele>52.2318</ele><time>2007-04-15T09:10:20Z</time></trkpt><trkpt lat=\"48.8350601196289\" lon=\"2.4507749080658\"><ele>52.2043</ele><time>2007-04-15T09:10:21Z</time></trkpt><trkpt lat=\"48.8350143432617\" lon=\"2.45055723190308\"><ele>52.3543</ele><time>2007-04-15T09:10:22Z</time></trkpt><trkpt lat=\"48.8349494934082\" lon=\"2.45033669471741\"><ele>52.4748</ele><time>2007-04-15T09:10:23Z</time></trkpt><trkpt lat=\"48.8348922729492\" lon=\"2.450115442276\"><ele>52.6029</ele><time>2007-04-15T09:10:24Z</time></trkpt><trkpt lat=\"48.834831237793\" lon=\"2.44986510276794\"><ele>52.2405</ele><time>2007-04-15T09:10:25Z</time></trkpt><trkpt lat=\"48.834789276123\" lon=\"2.44969010353088\"><ele>51.7548</ele><time>2007-04-15T09:10:26Z</time></trkpt><trkpt lat=\"48.8347549438477\" lon=\"2.44952297210693\"><ele>51.3679</ele><time>2007-04-15T09:10:27Z</time></trkpt><trkpt lat=\"48.834716796875\" lon=\"2.44932460784912\"><ele>50.9906</ele><time>2007-04-15T09:10:28Z</time></trkpt><trkpt lat=\"48.8346633911133\" lon=\"2.44910955429077\"><ele>50.8079</ele><time>2007-04-15T09:10:29Z</time></trkpt><trkpt lat=\"48.8346138000488\" lon=\"2.44886493682861\"><ele>50.9269</ele><time>2007-04-15T09:10:30Z</time></trkpt><trkpt lat=\"48.8345680236816\" lon=\"2.44868206977844\"><ele>51.0367</ele><time>2007-04-15T09:10:31Z</time></trkpt><trkpt lat=\"48.8345108032227\" lon=\"2.44842314720154\"><ele>51.1741</ele><time>2007-04-15T09:10:32Z</time></trkpt><trkpt lat=\"48.8344612121582\" lon=\"2.44823145866394\"><ele>51.3363</ele><time>2007-04-15T09:10:33Z</time></trkpt><trkpt lat=\"48.8344192504883\" lon=\"2.44802522659302\"><ele>51.5059</ele><time>2007-04-15T09:10:34Z</time></trkpt><trkpt lat=\"48.8343887329102\" lon=\"2.4478132724762\"><ele>51.6333</ele><time>2007-04-15T09:10:35Z</time></trkpt><trkpt lat=\"48.8343544006348\" lon=\"2.44765567779541\"><ele>51.7326</ele><time>2007-04-15T09:10:36Z</time></trkpt><trkpt lat=\"48.8343238830566\" lon=\"2.44748902320862\"><ele>51.7982</ele><time>2007-04-15T09:10:37Z</time></trkpt><trkpt lat=\"48.8342895507812\" lon=\"2.44729232788086\"><ele>51.6033</ele><time>2007-04-15T09:10:38Z</time></trkpt><trkpt lat=\"48.8342437744141\" lon=\"2.4470522403717\"><ele>51.3702</ele><time>2007-04-15T09:10:39Z</time></trkpt><trkpt lat=\"48.8342132568359\" lon=\"2.44689226150513\"><ele>51.2148</ele><time>2007-04-15T09:10:40Z</time></trkpt><trkpt lat=\"48.8341903686523\" lon=\"2.44673585891724\"><ele>51.0546</ele><time>2007-04-15T09:10:41Z</time></trkpt><trkpt lat=\"48.8341522216797\" lon=\"2.44651484489441\"><ele>51.0205</ele><time>2007-04-15T09:10:42Z</time></trkpt><trkpt lat=\"48.8341178894043\" lon=\"2.44630646705627\"><ele>51.0838</ele><time>2007-04-15T09:10:43Z</time></trkpt><trkpt lat=\"48.8340759277344\" lon=\"2.44609427452087\"><ele>51.1837</ele><time>2007-04-15T09:10:44Z</time></trkpt><trkpt lat=\"48.8340606689453\" lon=\"2.44602489471436\"><ele>51.2252</ele><time>2007-04-15T09:10:45Z</time></trkpt><trkpt lat=\"48.8340492248535\" lon=\"2.4458315372467\"><ele>51.2797</ele><time>2007-04-15T09:10:46Z</time></trkpt><trkpt lat=\"48.8340072631836\" lon=\"2.44565010070801\"><ele>51.1627</ele><time>2007-04-15T09:10:47Z</time></trkpt><trkpt lat=\"48.833911895752\" lon=\"2.44556212425232\"><ele>51.286</ele><time>2007-04-15T09:10:48Z</time></trkpt><trkpt lat=\"48.8337707519531\" lon=\"2.44550371170044\"><ele>51.5546</ele><time>2007-04-15T09:10:49Z</time></trkpt><trkpt lat=\"48.8336143493652\" lon=\"2.44548773765564\"><ele>51.9108</ele><time>2007-04-15T09:10:50Z</time></trkpt><trkpt lat=\"48.83349609375\" lon=\"2.44563770294189\"><ele>52.3746</ele><time>2007-04-15T09:10:51Z</time></trkpt><trkpt lat=\"48.8334121704102\" lon=\"2.44578170776367\"><ele>52.7488</ele><time>2007-04-15T09:10:52Z</time></trkpt><trkpt lat=\"48.8333129882812\" lon=\"2.4459114074707\"><ele>52.8598</ele><time>2007-04-15T09:10:53Z</time></trkpt><trkpt lat=\"48.8332214355469\" lon=\"2.44608020782471\"><ele>52.475</ele><time>2007-04-15T09:10:54Z</time></trkpt><trkpt lat=\"48.8330917358398\" lon=\"2.4462423324585\"><ele>52.0717</ele><time>2007-04-15T09:10:55Z</time></trkpt><trkpt lat=\"48.8330116271973\" lon=\"2.44639229774475\"><ele>51.8161</ele><time>2007-04-15T09:10:56Z</time></trkpt><trkpt lat=\"48.8329277038574\" lon=\"2.44653820991516\"><ele>51.5924</ele><time>2007-04-15T09:10:57Z</time></trkpt><trkpt lat=\"48.8328056335449\" lon=\"2.44672679901123\"><ele>51.4125</ele><time>2007-04-15T09:10:58Z</time></trkpt><trkpt lat=\"48.8327140808106\" lon=\"2.44685363769531\"><ele>51.4236</ele><time>2007-04-15T09:10:59Z</time></trkpt><trkpt lat=\"48.8326606750488\" lon=\"2.44693326950073\"><ele>51.451</ele><time>2007-04-15T09:11:00Z</time></trkpt><trkpt lat=\"48.8326263427734\" lon=\"2.44698095321655\"><ele>51.4716</ele><time>2007-04-15T09:11:01Z</time></trkpt><trkpt lat=\"48.8325271606445\" lon=\"2.44713425636292\"><ele>51.5754</ele><time>2007-04-15T09:11:02Z</time></trkpt><trkpt lat=\"48.8324279785156\" lon=\"2.44729781150818\"><ele>51.7783</ele><time>2007-04-15T09:11:03Z</time></trkpt><trkpt lat=\"48.8323287963867\" lon=\"2.44746112823486\"><ele>51.9629</ele><time>2007-04-15T09:11:04Z</time></trkpt><trkpt lat=\"48.8322219848633\" lon=\"2.44761252403259\"><ele>51.7749</ele><time>2007-04-15T09:11:05Z</time></trkpt><trkpt lat=\"48.8321228027344\" lon=\"2.44777679443359\"><ele>51.3672</ele><time>2007-04-15T09:11:06Z</time></trkpt><trkpt lat=\"48.8320426940918\" lon=\"2.44790244102478\"><ele>50.987</ele><time>2007-04-15T09:11:07Z</time></trkpt><trkpt lat=\"48.8319435119629\" lon=\"2.4480242729187\"><ele>50.5306</ele><time>2007-04-15T09:11:08Z</time></trkpt><trkpt lat=\"48.8318481445312\" lon=\"2.44813585281372\"><ele>50.0433</ele><time>2007-04-15T09:11:09Z</time></trkpt><trkpt lat=\"48.8317604064941\" lon=\"2.44825959205627\"><ele>49.4705</ele><time>2007-04-15T09:11:10Z</time></trkpt><trkpt lat=\"48.831657409668\" lon=\"2.44839096069336\"><ele>49.321</ele><time>2007-04-15T09:11:11Z</time></trkpt><trkpt lat=\"48.8315467834473\" lon=\"2.44854593276978\"><ele>50.5959</ele><time>2007-04-15T09:11:12Z</time></trkpt><trkpt lat=\"48.8314018249512\" lon=\"2.44874262809753\"><ele>52.2359</ele><time>2007-04-15T09:11:13Z</time></trkpt><trkpt lat=\"48.8312835693359\" lon=\"2.4488742351532\"><ele>53.4352</ele><time>2007-04-15T09:11:14Z</time></trkpt><trkpt lat=\"48.8311920166016\" lon=\"2.44898390769958\"><ele>54.4011</ele><time>2007-04-15T09:11:15Z</time></trkpt><trkpt lat=\"48.8310775756836\" lon=\"2.44913530349731\"><ele>55.6771</ele><time>2007-04-15T09:11:16Z</time></trkpt><trkpt lat=\"48.8309516906738\" lon=\"2.44930624961853\"><ele>56.9582</ele><time>2007-04-15T09:11:17Z</time></trkpt><trkpt lat=\"48.8308334350586\" lon=\"2.44944167137146\"><ele>57.9896</ele><time>2007-04-15T09:11:18Z</time></trkpt><trkpt lat=\"48.8307456970215\" lon=\"2.4495632648468\"><ele>57.9121</ele><time>2007-04-15T09:11:19Z</time></trkpt><trkpt lat=\"48.830638885498\" lon=\"2.44972491264343\"><ele>57.6844</ele><time>2007-04-15T09:11:20Z</time></trkpt><trkpt lat=\"48.8305625915527\" lon=\"2.44984102249146\"><ele>57.4014</ele><time>2007-04-15T09:11:21Z</time></trkpt><trkpt lat=\"48.8305320739746\" lon=\"2.44987750053406\"><ele>57.241</ele><time>2007-04-15T09:11:22Z</time></trkpt><trkpt lat=\"48.8304557800293\" lon=\"2.44998168945312\"><ele>56.8025</ele><time>2007-04-15T09:11:23Z</time></trkpt><trkpt lat=\"48.8303527832031\" lon=\"2.4500629901886\"><ele>56.0301</ele><time>2007-04-15T09:11:24Z</time></trkpt><trkpt lat=\"48.8303070068359\" lon=\"2.45009112358093\"><ele>55.7055</ele><time>2007-04-15T09:11:25Z</time></trkpt><trkpt lat=\"48.8302764892578\" lon=\"2.45012521743774\"><ele>55.524</ele><time>2007-04-15T09:11:26Z</time></trkpt><trkpt lat=\"48.8302459716797\" lon=\"2.45016264915466\"><ele>55.3636</ele><time>2007-04-15T09:11:27Z</time></trkpt><trkpt lat=\"48.830207824707\" lon=\"2.45020508766174\"><ele>55.1772</ele><time>2007-04-15T09:11:28Z</time></trkpt><trkpt lat=\"48.8301963806152\" lon=\"2.45022487640381\"><ele>55.1412</ele><time>2007-04-15T09:11:29Z</time></trkpt><trkpt lat=\"48.830192565918\" lon=\"2.45023345947266\"><ele>55.1343</ele><time>2007-04-15T09:11:30Z</time></trkpt><trkpt lat=\"48.8301429748535\" lon=\"2.45032930374146\"><ele>55.0475</ele><time>2007-04-15T09:11:31Z</time></trkpt><trkpt lat=\"48.8300704956055\" lon=\"2.45041751861572\"><ele>54.8833</ele><time>2007-04-15T09:11:32Z</time></trkpt><trkpt lat=\"48.8299522399902\" lon=\"2.45055246353149\"><ele>54.8936</ele><time>2007-04-15T09:11:33Z</time></trkpt><trkpt lat=\"48.8298645019531\" lon=\"2.45064997673035\"><ele>55.0505</ele><time>2007-04-15T09:11:34Z</time></trkpt><trkpt lat=\"48.8297996520996\" lon=\"2.45073437690735\"><ele>55.1915</ele><time>2007-04-15T09:11:35Z</time></trkpt><trkpt lat=\"48.8297157287598\" lon=\"2.45084118843079\"><ele>55.3274</ele><time>2007-04-15T09:11:36Z</time></trkpt><trkpt lat=\"48.8296585083008\" lon=\"2.45094466209412\"><ele>55.3447</ele><time>2007-04-15T09:11:37Z</time></trkpt><trkpt lat=\"48.8295516967773\" lon=\"2.45106911659241\"><ele>55.3807</ele><time>2007-04-15T09:11:38Z</time></trkpt><trkpt lat=\"48.8294563293457\" lon=\"2.45121192932129\"><ele>55.5844</ele><time>2007-04-15T09:11:39Z</time></trkpt><trkpt lat=\"48.8293838500977\" lon=\"2.45131945610046\"><ele>55.8152</ele><time>2007-04-15T09:11:40Z</time></trkpt><trkpt lat=\"48.8292999267578\" lon=\"2.45144581794739\"><ele>56.1722</ele><time>2007-04-15T09:11:41Z</time></trkpt><trkpt lat=\"48.829174041748\" lon=\"2.45161700248718\"><ele>56.8139</ele><time>2007-04-15T09:11:42Z</time></trkpt><trkpt lat=\"48.8290710449219\" lon=\"2.45176243782043\"><ele>56.8984</ele><time>2007-04-15T09:11:43Z</time></trkpt><trkpt lat=\"48.8289527893066\" lon=\"2.45192694664001\"><ele>56.8235</ele><time>2007-04-15T09:11:44Z</time></trkpt><trkpt lat=\"48.8288688659668\" lon=\"2.45205330848694\"><ele>56.8084</ele><time>2007-04-15T09:11:45Z</time></trkpt><trkpt lat=\"48.8287658691406\" lon=\"2.45218300819397\"><ele>56.817</ele><time>2007-04-15T09:11:46Z</time></trkpt><trkpt lat=\"48.8286514282227\" lon=\"2.45234751701355\"><ele>56.8869</ele><time>2007-04-15T09:11:47Z</time></trkpt><trkpt lat=\"48.8285446166992\" lon=\"2.45248579978943\"><ele>56.9873</ele><time>2007-04-15T09:11:48Z</time></trkpt><trkpt lat=\"48.8284111022949\" lon=\"2.45265579223633\"><ele>57.339</ele><time>2007-04-15T09:11:49Z</time></trkpt><trkpt lat=\"48.8283195495606\" lon=\"2.452805519104\"><ele>57.6836</ele><time>2007-04-15T09:11:50Z</time></trkpt><trkpt lat=\"48.8282318115234\" lon=\"2.45293045043945\"><ele>57.6676</ele><time>2007-04-15T09:11:51Z</time></trkpt><trkpt lat=\"48.8281555175781\" lon=\"2.45304727554321\"><ele>57.6733</ele><time>2007-04-15T09:11:52Z</time></trkpt><trkpt lat=\"48.828067779541\" lon=\"2.45317125320435\"><ele>57.655</ele><time>2007-04-15T09:11:53Z</time></trkpt><trkpt lat=\"48.827938079834\" lon=\"2.45335841178894\"><ele>57.5771</ele><time>2007-04-15T09:11:54Z</time></trkpt><trkpt lat=\"48.8277854919434\" lon=\"2.45357418060303\"><ele>57.0278</ele><time>2007-04-15T09:11:55Z</time></trkpt><trkpt lat=\"48.8276824951172\" lon=\"2.45370435714722\"><ele>56.657</ele><time>2007-04-15T09:11:56Z</time></trkpt><trkpt lat=\"48.8275413513184\" lon=\"2.45388269424438\"><ele>56.1489</ele><time>2007-04-15T09:11:57Z</time></trkpt><trkpt lat=\"48.8274040222168\" lon=\"2.45404434204102\"><ele>55.7866</ele><time>2007-04-15T09:11:58Z</time></trkpt><trkpt lat=\"48.8273048400879\" lon=\"2.45418095588684\"><ele>55.5316</ele><time>2007-04-15T09:11:59Z</time></trkpt><trkpt lat=\"48.8272476196289\" lon=\"2.45423555374146\"><ele>55.3943</ele><time>2007-04-15T09:12:00Z</time></trkpt><trkpt lat=\"48.8271179199219\" lon=\"2.45415544509888\"><ele>55.0892</ele><time>2007-04-15T09:12:01Z</time></trkpt><trkpt lat=\"48.8270874023438\" lon=\"2.45390892028809\"><ele>55.1629</ele><time>2007-04-15T09:12:02Z</time></trkpt><trkpt lat=\"48.8270950317383\" lon=\"2.45372152328491\"><ele>55.2877</ele><time>2007-04-15T09:12:03Z</time></trkpt><trkpt lat=\"48.8270950317383\" lon=\"2.45352339744568\"><ele>55.4032</ele><time>2007-04-15T09:12:04Z</time></trkpt><trkpt lat=\"48.8271064758301\" lon=\"2.45329165458679\"><ele>55.475</ele><time>2007-04-15T09:12:05Z</time></trkpt><trkpt lat=\"48.8271102905273\" lon=\"2.45308995246887\"><ele>55.2214</ele><time>2007-04-15T09:12:06Z</time></trkpt><trkpt lat=\"48.8271293640137\" lon=\"2.45286583900452\"><ele>54.9323</ele><time>2007-04-15T09:12:07Z</time></trkpt><trkpt lat=\"48.8271293640137\" lon=\"2.45266366004944\"><ele>54.6629</ele><time>2007-04-15T09:12:08Z</time></trkpt><trkpt lat=\"48.8271369934082\" lon=\"2.45239853858948\"><ele>54.3669</ele><time>2007-04-15T09:12:09Z</time></trkpt><trkpt lat=\"48.8271598815918\" lon=\"2.45217275619507\"><ele>54.1757</ele><time>2007-04-15T09:12:10Z</time></trkpt><trkpt lat=\"48.8271636962891\" lon=\"2.45194602012634\"><ele>54.0071</ele><time>2007-04-15T09:12:11Z</time></trkpt><trkpt lat=\"48.8271713256836\" lon=\"2.45175313949585\"><ele>53.8517</ele><time>2007-04-15T09:12:12Z</time></trkpt><trkpt lat=\"48.8271713256836\" lon=\"2.45167446136475\"><ele>53.7945</ele><time>2007-04-15T09:12:13Z</time></trkpt><trkpt lat=\"48.8271713256836\" lon=\"2.45159864425659\"><ele>53.8061</ele><time>2007-04-15T09:12:14Z</time></trkpt><trkpt lat=\"48.8271751403809\" lon=\"2.45139956474304\"><ele>53.8503</ele><time>2007-04-15T09:12:15Z</time></trkpt><trkpt lat=\"48.8271865844727\" lon=\"2.45116519927978\"><ele>53.9013</ele><time>2007-04-15T09:12:16Z</time></trkpt><trkpt lat=\"48.8271980285644\" lon=\"2.45097947120666\"><ele>53.9517</ele><time>2007-04-15T09:12:17Z</time></trkpt><trkpt lat=\"48.8272171020508\" lon=\"2.45069265365601\"><ele>53.6655</ele><time>2007-04-15T09:12:18Z</time></trkpt><trkpt lat=\"48.8272323608398\" lon=\"2.45048356056213\"><ele>53.1452</ele><time>2007-04-15T09:12:19Z</time></trkpt><trkpt lat=\"48.827262878418\" lon=\"2.45025944709778\"><ele>52.5219</ele><time>2007-04-15T09:12:20Z</time></trkpt><trkpt lat=\"48.827278137207\" lon=\"2.45005750656128\"><ele>51.9506</ele><time>2007-04-15T09:12:21Z</time></trkpt><trkpt lat=\"48.8272705078125\" lon=\"2.4498450756073\"><ele>52.1468</ele><time>2007-04-15T09:12:22Z</time></trkpt><trkpt lat=\"48.8272857666016\" lon=\"2.4496488571167\"><ele>52.5057</ele><time>2007-04-15T09:12:23Z</time></trkpt><trkpt lat=\"48.8273048400879\" lon=\"2.4494948387146\"><ele>52.773</ele><time>2007-04-15T09:12:24Z</time></trkpt><trkpt lat=\"48.8273086547852\" lon=\"2.44928765296936\"><ele>53.2022</ele><time>2007-04-15T09:12:25Z</time></trkpt><trkpt lat=\"48.8273010253906\" lon=\"2.44908356666565\"><ele>53.5773</ele><time>2007-04-15T09:12:26Z</time></trkpt><trkpt lat=\"48.8273162841797\" lon=\"2.44884729385376\"><ele>53.8242</ele><time>2007-04-15T09:12:27Z</time></trkpt><trkpt lat=\"48.8273544311523\" lon=\"2.4486780166626\"><ele>53.9357</ele><time>2007-04-15T09:12:28Z</time></trkpt><trkpt lat=\"48.8273811340332\" lon=\"2.44849967956543\"><ele>54.0857</ele><time>2007-04-15T09:12:29Z</time></trkpt><trkpt lat=\"48.8273811340332\" lon=\"2.44834923744202\"><ele>54.2662</ele><time>2007-04-15T09:12:30Z</time></trkpt><trkpt lat=\"48.8273735046387\" lon=\"2.44815540313721\"><ele>54.6982</ele><time>2007-04-15T09:12:31Z</time></trkpt><trkpt lat=\"48.8273620605469\" lon=\"2.44795036315918\"><ele>55.1741</ele><time>2007-04-15T09:12:32Z</time></trkpt><trkpt lat=\"48.8273696899414\" lon=\"2.44773840904236\"><ele>55.6289</ele><time>2007-04-15T09:12:33Z</time></trkpt><trkpt lat=\"48.8273963928223\" lon=\"2.44760394096374\"><ele>55.8904</ele><time>2007-04-15T09:12:34Z</time></trkpt><trkpt lat=\"48.8274192810059\" lon=\"2.44735646247864\"><ele>56.1135</ele><time>2007-04-15T09:12:35Z</time></trkpt><trkpt lat=\"48.8274230957031\" lon=\"2.44718241691589\"><ele>56.1275</ele><time>2007-04-15T09:12:36Z</time></trkpt><trkpt lat=\"48.8274383544922\" lon=\"2.44693374633789\"><ele>56.1242</ele><time>2007-04-15T09:12:37Z</time></trkpt><trkpt lat=\"48.8274421691894\" lon=\"2.44686770439148\"><ele>56.1221</ele><time>2007-04-15T09:12:38Z</time></trkpt><trkpt lat=\"48.8274459838867\" lon=\"2.44673991203308\"><ele>56.1239</ele><time>2007-04-15T09:12:39Z</time></trkpt><trkpt lat=\"48.8273429870606\" lon=\"2.44663858413696\"><ele>56.3705</ele><time>2007-04-15T09:12:40Z</time></trkpt><trkpt lat=\"48.8272285461426\" lon=\"2.4465856552124\"><ele>56.6198</ele><time>2007-04-15T09:12:41Z</time></trkpt><trkpt lat=\"48.8271141052246\" lon=\"2.4465446472168\"><ele>56.8583</ele><time>2007-04-15T09:12:42Z</time></trkpt><trkpt lat=\"48.8269729614258\" lon=\"2.44651389122009\"><ele>57.1489</ele><time>2007-04-15T09:12:43Z</time></trkpt><trkpt lat=\"48.8268394470215\" lon=\"2.44649720191956\"><ele>57.4241</ele><time>2007-04-15T09:12:44Z</time></trkpt><trkpt lat=\"48.8267021179199\" lon=\"2.44650316238403\"><ele>57.7271</ele><time>2007-04-15T09:12:45Z</time></trkpt><trkpt lat=\"48.8265342712402\" lon=\"2.44647789001465\"><ele>57.5277</ele><time>2007-04-15T09:12:46Z</time></trkpt><trkpt lat=\"48.8264350891113\" lon=\"2.4464590549469\"><ele>57.3335</ele><time>2007-04-15T09:12:47Z</time></trkpt><trkpt lat=\"48.8262596130371\" lon=\"2.44645476341248\"><ele>57.0172</ele><time>2007-04-15T09:12:48Z</time></trkpt><trkpt lat=\"48.8261604309082\" lon=\"2.44645118713379\"><ele>56.8406</ele><time>2007-04-15T09:12:49Z</time></trkpt><trkpt lat=\"48.8260612487793\" lon=\"2.44642496109009\"><ele>56.6784</ele><time>2007-04-15T09:12:50Z</time></trkpt><trkpt lat=\"48.8259124755859\" lon=\"2.44639086723328\"><ele>56.458</ele><time>2007-04-15T09:12:51Z</time></trkpt><trkpt lat=\"48.8257675170898\" lon=\"2.44637036323547\"><ele>56.5697</ele><time>2007-04-15T09:12:52Z</time></trkpt><trkpt lat=\"48.825611114502\" lon=\"2.44635891914368\"><ele>57.0996</ele><time>2007-04-15T09:12:53Z</time></trkpt><trkpt lat=\"48.825439453125\" lon=\"2.44633340835571\"><ele>57.7233</ele><time>2007-04-15T09:12:54Z</time></trkpt><trkpt lat=\"48.825267791748\" lon=\"2.44629192352295\"><ele>58.4174</ele><time>2007-04-15T09:12:55Z</time></trkpt><trkpt lat=\"48.8251495361328\" lon=\"2.44628000259399\"><ele>58.8666</ele><time>2007-04-15T09:12:56Z</time></trkpt><trkpt lat=\"48.8250350952148\" lon=\"2.44626832008362\"><ele>59.3096</ele><time>2007-04-15T09:12:57Z</time></trkpt><trkpt lat=\"48.8249168395996\" lon=\"2.44627261161804\"><ele>59.4766</ele><time>2007-04-15T09:12:58Z</time></trkpt><trkpt lat=\"48.8248748779297\" lon=\"2.44626617431641\"><ele>59.5256</ele><time>2007-04-15T09:12:59Z</time></trkpt><trkpt lat=\"48.8247528076172\" lon=\"2.44624781608582\"><ele>59.6538</ele><time>2007-04-15T09:13:00Z</time></trkpt><trkpt lat=\"48.8247299194336\" lon=\"2.44624400138855\"><ele>59.6766</ele><time>2007-04-15T09:13:01Z</time></trkpt><trkpt lat=\"48.8246116638184\" lon=\"2.44622325897217\"><ele>59.7844</ele><time>2007-04-15T09:13:02Z</time></trkpt><trkpt lat=\"48.8244705200195\" lon=\"2.44619584083557\"><ele>59.8888</ele><time>2007-04-15T09:13:03Z</time></trkpt><trkpt lat=\"48.8243179321289\" lon=\"2.44617438316345\"><ele>59.9587</ele><time>2007-04-15T09:13:04Z</time></trkpt><trkpt lat=\"48.8242034912109\" lon=\"2.44615530967712\"><ele>59.993</ele><time>2007-04-15T09:13:05Z</time></trkpt><trkpt lat=\"48.8240776062012\" lon=\"2.44619035720825\"><ele>60.0611</ele><time>2007-04-15T09:13:06Z</time></trkpt><trkpt lat=\"48.8239593505859\" lon=\"2.44617652893066\"><ele>60.1463</ele><time>2007-04-15T09:13:07Z</time></trkpt><trkpt lat=\"48.8238639831543\" lon=\"2.44616723060608\"><ele>60.2177</ele><time>2007-04-15T09:13:08Z</time></trkpt><trkpt lat=\"48.8236846923828\" lon=\"2.44618248939514\"><ele>60.336</ele><time>2007-04-15T09:13:09Z</time></trkpt><trkpt lat=\"48.823543548584\" lon=\"2.44614362716675\"><ele>60.4693</ele><time>2007-04-15T09:13:10Z</time></trkpt><trkpt lat=\"48.8234252929688\" lon=\"2.44612836837769\"><ele>60.5747</ele><time>2007-04-15T09:13:11Z</time></trkpt><trkpt lat=\"48.8232612609863\" lon=\"2.446129322052\"><ele>60.7006</ele><time>2007-04-15T09:13:12Z</time></trkpt><trkpt lat=\"48.8231430053711\" lon=\"2.44610357284546\"><ele>60.83</ele><time>2007-04-15T09:13:13Z</time></trkpt><trkpt lat=\"48.8230285644531\" lon=\"2.44608211517334\"><ele>60.958</ele><time>2007-04-15T09:13:14Z</time></trkpt><trkpt lat=\"48.822883605957\" lon=\"2.44604730606079\"><ele>61.1443</ele><time>2007-04-15T09:13:15Z</time></trkpt><trkpt lat=\"48.8227577209473\" lon=\"2.44601225852966\"><ele>61.3277</ele><time>2007-04-15T09:13:16Z</time></trkpt><trkpt lat=\"48.8225936889648\" lon=\"2.44600510597229\"><ele>61.4985</ele><time>2007-04-15T09:13:17Z</time></trkpt><trkpt lat=\"48.8224678039551\" lon=\"2.44602179527283\"><ele>61.6162</ele><time>2007-04-15T09:13:18Z</time></trkpt><trkpt lat=\"48.822338104248\" lon=\"2.44600439071655\"><ele>61.9381</ele><time>2007-04-15T09:13:19Z</time></trkpt><trkpt lat=\"48.8221626281738\" lon=\"2.44598436355591\"><ele>62.3738</ele><time>2007-04-15T09:13:20Z</time></trkpt><trkpt lat=\"48.8220443725586\" lon=\"2.44595003128052\"><ele>62.7369</ele><time>2007-04-15T09:13:21Z</time></trkpt><trkpt lat=\"48.8218574523926\" lon=\"2.44593596458435\"><ele>63.2008</ele><time>2007-04-15T09:13:22Z</time></trkpt><trkpt lat=\"48.8217849731445\" lon=\"2.44592356681824\"><ele>63.4066</ele><time>2007-04-15T09:13:23Z</time></trkpt><trkpt lat=\"48.8217582702637\" lon=\"2.44591736793518\"><ele>63.4887</ele><time>2007-04-15T09:13:24Z</time></trkpt><trkpt lat=\"48.8216361999512\" lon=\"2.44588398933411\"><ele>63.9617</ele><time>2007-04-15T09:13:25Z</time></trkpt><trkpt lat=\"48.8215141296387\" lon=\"2.44586300849915\"><ele>64.6188</ele><time>2007-04-15T09:13:26Z</time></trkpt><trkpt lat=\"48.8213691711426\" lon=\"2.44582724571228\"><ele>65.4259</ele><time>2007-04-15T09:13:27Z</time></trkpt><trkpt lat=\"48.8212471008301\" lon=\"2.44579148292542\"><ele>66.0143</ele><time>2007-04-15T09:13:28Z</time></trkpt><trkpt lat=\"48.8211250305176\" lon=\"2.44574165344238\"><ele>66.6329</ele><time>2007-04-15T09:13:29Z</time></trkpt><trkpt lat=\"48.8209838867188\" lon=\"2.44567823410034\"><ele>67.3962</ele><time>2007-04-15T09:13:30Z</time></trkpt><trkpt lat=\"48.8208122253418\" lon=\"2.44558143615723\"><ele>68.3553</ele><time>2007-04-15T09:13:31Z</time></trkpt><trkpt lat=\"48.8207092285156\" lon=\"2.44551062583923\"><ele>68.661</ele><time>2007-04-15T09:13:32Z</time></trkpt><trkpt lat=\"48.8205947875977\" lon=\"2.44543170928955\"><ele>68.9268</ele><time>2007-04-15T09:13:33Z</time></trkpt><trkpt lat=\"48.8204803466797\" lon=\"2.44533157348633\"><ele>69.1077</ele><time>2007-04-15T09:13:34Z</time></trkpt><trkpt lat=\"48.8203277587891\" lon=\"2.44519734382629\"><ele>69.1942</ele><time>2007-04-15T09:13:35Z</time></trkpt><trkpt lat=\"48.8202285766602\" lon=\"2.4450945854187\"><ele>69.1336</ele><time>2007-04-15T09:13:36Z</time></trkpt><trkpt lat=\"48.8201560974121\" lon=\"2.44500541687012\"><ele>69.0093</ele><time>2007-04-15T09:13:37Z</time></trkpt><trkpt lat=\"48.8200645446777\" lon=\"2.44493937492371\"><ele>68.9216</ele><time>2007-04-15T09:13:38Z</time></trkpt><trkpt lat=\"48.8199806213379\" lon=\"2.44486451148987\"><ele>68.8022</ele><time>2007-04-15T09:13:39Z</time></trkpt><trkpt lat=\"48.8198776245117\" lon=\"2.44476938247681\"><ele>68.5515</ele><time>2007-04-15T09:13:40Z</time></trkpt><trkpt lat=\"48.819751739502\" lon=\"2.44463586807251\"><ele>68.3577</ele><time>2007-04-15T09:13:41Z</time></trkpt><trkpt lat=\"48.8196563720703\" lon=\"2.44452929496765\"><ele>68.3092</ele><time>2007-04-15T09:13:42Z</time></trkpt><trkpt lat=\"48.8195571899414\" lon=\"2.44441318511963\"><ele>68.3556</ele><time>2007-04-15T09:13:43Z</time></trkpt><trkpt lat=\"48.8194541931152\" lon=\"2.44429516792297\"><ele>68.5062</ele><time>2007-04-15T09:13:44Z</time></trkpt><trkpt lat=\"48.8193511962891\" lon=\"2.44419574737549\"><ele>68.732</ele><time>2007-04-15T09:13:45Z</time></trkpt><trkpt lat=\"48.8192329406738\" lon=\"2.44405198097229\"><ele>68.7938</ele><time>2007-04-15T09:13:46Z</time></trkpt><trkpt lat=\"48.8190879821777\" lon=\"2.44386577606201\"><ele>66.9734</ele><time>2007-04-15T09:13:47Z</time></trkpt><trkpt lat=\"48.8190002441406\" lon=\"2.44371819496155\"><ele>64.9746</ele><time>2007-04-15T09:13:48Z</time></trkpt><trkpt lat=\"48.818904876709\" lon=\"2.44354009628296\"><ele>62.8297</ele><time>2007-04-15T09:13:49Z</time></trkpt><trkpt lat=\"48.8188133239746\" lon=\"2.44334983825684\"><ele>60.8032</ele><time>2007-04-15T09:13:50Z</time></trkpt><trkpt lat=\"48.818733215332\" lon=\"2.44316458702087\"><ele>59.0523</ele><time>2007-04-15T09:13:51Z</time></trkpt><trkpt lat=\"48.8186569213867\" lon=\"2.44291496276855\"><ele>57.2941</ele><time>2007-04-15T09:13:52Z</time></trkpt><trkpt lat=\"48.8186302185059\" lon=\"2.44271945953369\"><ele>56.5822</ele><time>2007-04-15T09:13:53Z</time></trkpt><trkpt lat=\"48.8186302185059\" lon=\"2.44248867034912\"><ele>56.4127</ele><time>2007-04-15T09:13:54Z</time></trkpt><trkpt lat=\"48.8186378479004\" lon=\"2.4422869682312\"><ele>56.5775</ele><time>2007-04-15T09:13:55Z</time></trkpt><trkpt lat=\"48.8186492919922\" lon=\"2.44209098815918\"><ele>56.8247</ele><time>2007-04-15T09:13:56Z</time></trkpt><trkpt lat=\"48.818660736084\" lon=\"2.44188237190247\"><ele>57.0719</ele><time>2007-04-15T09:13:57Z</time></trkpt><trkpt lat=\"48.8186836242676\" lon=\"2.44169735908508\"><ele>57.5663</ele><time>2007-04-15T09:13:58Z</time></trkpt><trkpt lat=\"48.8187026977539\" lon=\"2.44151544570923\"><ele>57.7164</ele><time>2007-04-15T09:13:59Z</time></trkpt><trkpt lat=\"48.8187370300293\" lon=\"2.44130778312683\"><ele>58.0806</ele><time>2007-04-15T09:14:00Z</time></trkpt><trkpt lat=\"48.8187484741211\" lon=\"2.44116854667664\"><ele>58.0715</ele><time>2007-04-15T09:14:01Z</time></trkpt><trkpt lat=\"48.8187713623047\" lon=\"2.4409019947052\"><ele>58.0615</ele><time>2007-04-15T09:14:02Z</time></trkpt><trkpt lat=\"48.8187866210938\" lon=\"2.44071102142334\"><ele>57.9535</ele><time>2007-04-15T09:14:03Z</time></trkpt><trkpt lat=\"48.8188056945801\" lon=\"2.44052147865295\"><ele>57.8877</ele><time>2007-04-15T09:14:04Z</time></trkpt><trkpt lat=\"48.8188285827637\" lon=\"2.4403440952301\"><ele>57.9289</ele><time>2007-04-15T09:14:05Z</time></trkpt><trkpt lat=\"48.8188591003418\" lon=\"2.44013428688049\"><ele>58.0479</ele><time>2007-04-15T09:14:06Z</time></trkpt><trkpt lat=\"48.8188781738281\" lon=\"2.43995404243469\"><ele>58.0596</ele><time>2007-04-15T09:14:07Z</time></trkpt><trkpt lat=\"48.818920135498\" lon=\"2.4397087097168\"><ele>58.6212</ele><time>2007-04-15T09:14:08Z</time></trkpt><trkpt lat=\"48.8189659118652\" lon=\"2.43948125839233\"><ele>59.2821</ele><time>2007-04-15T09:14:09Z</time></trkpt><trkpt lat=\"48.8189926147461\" lon=\"2.43924021720886\"><ele>59.5376</ele><time>2007-04-15T09:14:10Z</time></trkpt><trkpt lat=\"48.819034576416\" lon=\"2.43905973434448\"><ele>60.177</ele><time>2007-04-15T09:14:11Z</time></trkpt><trkpt lat=\"48.8190765380859\" lon=\"2.43887782096863\"><ele>60.8148</ele><time>2007-04-15T09:14:12Z</time></trkpt><trkpt lat=\"48.8191032409668\" lon=\"2.43870735168457\"><ele>61.1549</ele><time>2007-04-15T09:14:13Z</time></trkpt><trkpt lat=\"48.8191413879394\" lon=\"2.43853569030762\"><ele>61.7271</ele><time>2007-04-15T09:14:14Z</time></trkpt><trkpt lat=\"48.8191719055176\" lon=\"2.43839240074158\"><ele>62.0947</ele><time>2007-04-15T09:14:15Z</time></trkpt><trkpt lat=\"48.8192253112793\" lon=\"2.43821501731873\"><ele>62.1595</ele><time>2007-04-15T09:14:16Z</time></trkpt><trkpt lat=\"48.8192710876465\" lon=\"2.43802905082703\"><ele>62.2276</ele><time>2007-04-15T09:14:17Z</time></trkpt><trkpt lat=\"48.8193206787109\" lon=\"2.43786096572876\"><ele>62.3819</ele><time>2007-04-15T09:14:18Z</time></trkpt><trkpt lat=\"48.8193626403809\" lon=\"2.43768429756165\"><ele>62.5281</ele><time>2007-04-15T09:14:19Z</time></trkpt><trkpt lat=\"48.8194198608398\" lon=\"2.43747138977051\"><ele>62.7409</ele><time>2007-04-15T09:14:20Z</time></trkpt><trkpt lat=\"48.8194885253906\" lon=\"2.43726062774658\"><ele>62.6775</ele><time>2007-04-15T09:14:21Z</time></trkpt><trkpt lat=\"48.8195419311523\" lon=\"2.43709635734558\"><ele>62.685</ele><time>2007-04-15T09:14:22Z</time></trkpt><trkpt lat=\"48.8196029663086\" lon=\"2.43689942359924\"><ele>62.7339</ele><time>2007-04-15T09:14:23Z</time></trkpt><trkpt lat=\"48.8196678161621\" lon=\"2.43673992156982\"><ele>62.969</ele><time>2007-04-15T09:14:24Z</time></trkpt><trkpt lat=\"48.8197135925293\" lon=\"2.43656635284424\"><ele>63.1715</ele><time>2007-04-15T09:14:25Z</time></trkpt><trkpt lat=\"48.8197822570801\" lon=\"2.43640637397766\"><ele>63.6789</ele><time>2007-04-15T09:14:26Z</time></trkpt><trkpt lat=\"48.8198509216309\" lon=\"2.43626856803894\"><ele>64.1766</ele><time>2007-04-15T09:14:27Z</time></trkpt><trkpt lat=\"48.8199043273926\" lon=\"2.43611431121826\"><ele>64.4948</ele><time>2007-04-15T09:14:28Z</time></trkpt><trkpt lat=\"48.8199615478516\" lon=\"2.43595480918884\"><ele>64.816</ele><time>2007-04-15T09:14:29Z</time></trkpt><trkpt lat=\"48.8200378417969\" lon=\"2.43575215339661\"><ele>65.1384</ele><time>2007-04-15T09:14:30Z</time></trkpt><trkpt lat=\"48.8201065063477\" lon=\"2.43558311462402\"><ele>65.3897</ele><time>2007-04-15T09:14:31Z</time></trkpt><trkpt lat=\"48.8201293945312\" lon=\"2.4355583190918\"><ele>65.434</ele><time>2007-04-15T09:14:32Z</time></trkpt><trkpt lat=\"48.8201942443848\" lon=\"2.43541240692139\"><ele>65.6205</ele><time>2007-04-15T09:14:33Z</time></trkpt><trkpt lat=\"48.8202209472656\" lon=\"2.43535137176514\"><ele>65.6901</ele><time>2007-04-15T09:14:34Z</time></trkpt><trkpt lat=\"48.8202667236328\" lon=\"2.43520927429199\"><ele>65.8292</ele><time>2007-04-15T09:14:35Z</time></trkpt><trkpt lat=\"48.8203506469727\" lon=\"2.43501234054565\"><ele>65.9914</ele><time>2007-04-15T09:14:36Z</time></trkpt><trkpt lat=\"48.8204612731934\" lon=\"2.43480062484741\"><ele>66.2136</ele><time>2007-04-15T09:14:37Z</time></trkpt><trkpt lat=\"48.8205604553223\" lon=\"2.43463444709778\"><ele>66.2873</ele><time>2007-04-15T09:14:38Z</time></trkpt><trkpt lat=\"48.8206367492676\" lon=\"2.43448305130005\"><ele>66.2927</ele><time>2007-04-15T09:14:39Z</time></trkpt><trkpt lat=\"48.8207359313965\" lon=\"2.43433785438538\"><ele>66.1857</ele><time>2007-04-15T09:14:40Z</time></trkpt><trkpt lat=\"48.8208274841309\" lon=\"2.43416523933411\"><ele>66.0141</ele><time>2007-04-15T09:14:41Z</time></trkpt><trkpt lat=\"48.820873260498\" lon=\"2.43407297134399\"><ele>65.9521</ele><time>2007-04-15T09:14:42Z</time></trkpt><trkpt lat=\"48.8209838867188\" lon=\"2.43391299247742\"><ele>65.8193</ele><time>2007-04-15T09:14:43Z</time></trkpt><trkpt lat=\"48.8210716247559\" lon=\"2.43383145332336\"><ele>65.7141</ele><time>2007-04-15T09:14:44Z</time></trkpt><trkpt lat=\"48.8211441040039\" lon=\"2.43371748924255\"><ele>65.6271</ele><time>2007-04-15T09:14:45Z</time></trkpt><trkpt lat=\"48.8211975097656\" lon=\"2.433598279953\"><ele>65.563</ele><time>2007-04-15T09:14:46Z</time></trkpt><trkpt lat=\"48.8212776184082\" lon=\"2.43351078033447\"><ele>65.4669</ele><time>2007-04-15T09:14:47Z</time></trkpt><trkpt lat=\"48.8213310241699\" lon=\"2.43342447280884\"><ele>65.4028</ele><time>2007-04-15T09:14:48Z</time></trkpt><trkpt lat=\"48.8213996887207\" lon=\"2.43331861495972\"><ele>65.3444</ele><time>2007-04-15T09:14:49Z</time></trkpt><trkpt lat=\"48.821475982666\" lon=\"2.4332332611084\"><ele>65.414</ele><time>2007-04-15T09:14:50Z</time></trkpt><trkpt lat=\"48.8216094970703\" lon=\"2.43310523033142\"><ele>65.5785</ele><time>2007-04-15T09:14:51Z</time></trkpt><trkpt lat=\"48.821720123291\" lon=\"2.43300533294678\"><ele>65.6726</ele><time>2007-04-15T09:14:52Z</time></trkpt><trkpt lat=\"48.8218040466309\" lon=\"2.43285989761353\"><ele>65.7841</ele><time>2007-04-15T09:14:53Z</time></trkpt><trkpt lat=\"48.8219261169434\" lon=\"2.43271207809448\"><ele>65.7155</ele><time>2007-04-15T09:14:54Z</time></trkpt><trkpt lat=\"48.8220291137695\" lon=\"2.43260979652405\"><ele>65.5463</ele><time>2007-04-15T09:14:55Z</time></trkpt><trkpt lat=\"48.8221244812012\" lon=\"2.43248200416565\"><ele>65.3756</ele><time>2007-04-15T09:14:56Z</time></trkpt><trkpt lat=\"48.8221778869629\" lon=\"2.43234324455261\"><ele>65.3904</ele><time>2007-04-15T09:14:57Z</time></trkpt><trkpt lat=\"48.8223037719727\" lon=\"2.43214559555054\"><ele>65.3567</ele><time>2007-04-15T09:14:58Z</time></trkpt><trkpt lat=\"48.8224258422852\" lon=\"2.43202352523804\"><ele>65.3087</ele><time>2007-04-15T09:14:59Z</time></trkpt><trkpt lat=\"48.8224983215332\" lon=\"2.43186664581299\"><ele>65.523</ele><time>2007-04-15T09:15:00Z</time></trkpt><trkpt lat=\"48.8225898742676\" lon=\"2.43171548843384\"><ele>65.5719</ele><time>2007-04-15T09:15:01Z</time></trkpt><trkpt lat=\"48.8226547241211\" lon=\"2.43151473999023\"><ele>65.1799</ele><time>2007-04-15T09:15:02Z</time></trkpt><trkpt lat=\"48.8227386474609\" lon=\"2.43138360977173\"><ele>64.7533</ele><time>2007-04-15T09:15:03Z</time></trkpt><trkpt lat=\"48.8228034973144\" lon=\"2.43121600151062\"><ele>64.4167</ele><time>2007-04-15T09:15:04Z</time></trkpt><trkpt lat=\"48.8228721618652\" lon=\"2.43111801147461\"><ele>64.2255</ele><time>2007-04-15T09:15:05Z</time></trkpt><trkpt lat=\"48.8229560852051\" lon=\"2.4309868812561\"><ele>64.066</ele><time>2007-04-15T09:15:06Z</time></trkpt><trkpt lat=\"48.8230743408203\" lon=\"2.43082022666931\"><ele>63.9902</ele><time>2007-04-15T09:15:07Z</time></trkpt><trkpt lat=\"48.8231582641602\" lon=\"2.43067836761475\"><ele>63.9219</ele><time>2007-04-15T09:15:08Z</time></trkpt><trkpt lat=\"48.8232002258301\" lon=\"2.43053984642029\"><ele>63.8875</ele><time>2007-04-15T09:15:09Z</time></trkpt><trkpt lat=\"48.8232727050781\" lon=\"2.43035244941711\"><ele>63.916</ele><time>2007-04-15T09:15:10Z</time></trkpt><trkpt lat=\"48.8233337402344\" lon=\"2.43018388748169\"><ele>64.0002</ele><time>2007-04-15T09:15:11Z</time></trkpt><trkpt lat=\"48.8234062194824\" lon=\"2.42999768257141\"><ele>64.0789</ele><time>2007-04-15T09:15:12Z</time></trkpt><trkpt lat=\"48.8234939575195\" lon=\"2.42986845970154\"><ele>63.6888</ele><time>2007-04-15T09:15:13Z</time></trkpt><trkpt lat=\"48.8235549926758\" lon=\"2.42966461181641\"><ele>62.9515</ele><time>2007-04-15T09:15:14Z</time></trkpt><trkpt lat=\"48.8235778808594\" lon=\"2.42946720123291\"><ele>62.1878</ele><time>2007-04-15T09:15:15Z</time></trkpt><trkpt lat=\"48.8236427307129\" lon=\"2.42926549911499\"><ele>61.3998</ele><time>2007-04-15T09:15:16Z</time></trkpt><trkpt lat=\"48.8236885070801\" lon=\"2.42908883094788\"><ele>61.0536</ele><time>2007-04-15T09:15:17Z</time></trkpt><trkpt lat=\"48.8237533569336\" lon=\"2.42892289161682\"><ele>61.1451</ele><time>2007-04-15T09:15:18Z</time></trkpt><trkpt lat=\"48.8238105773926\" lon=\"2.42875385284424\"><ele>61.2117</ele><time>2007-04-15T09:15:19Z</time></trkpt><trkpt lat=\"48.8238639831543\" lon=\"2.42858815193176\"><ele>61.2522</ele><time>2007-04-15T09:15:20Z</time></trkpt><trkpt lat=\"48.8238677978516\" lon=\"2.42835831642151\"><ele>61.3479</ele><time>2007-04-15T09:15:21Z</time></trkpt><trkpt lat=\"48.8239135742188\" lon=\"2.42808794975281\"><ele>60.4203</ele><time>2007-04-15T09:15:22Z</time></trkpt><trkpt lat=\"48.8239517211914\" lon=\"2.42786478996277\"><ele>59.5712</ele><time>2007-04-15T09:15:23Z</time></trkpt><trkpt lat=\"48.8239974975586\" lon=\"2.42763662338257\"><ele>58.6948</ele><time>2007-04-15T09:15:24Z</time></trkpt><trkpt lat=\"48.8240280151367\" lon=\"2.42744278907776\"><ele>58.0177</ele><time>2007-04-15T09:15:25Z</time></trkpt><trkpt lat=\"48.8240623474121\" lon=\"2.4272084236145\"><ele>57.3816</ele><time>2007-04-15T09:15:26Z</time></trkpt><trkpt lat=\"48.8240814208984\" lon=\"2.42697167396545\"><ele>56.7695</ele><time>2007-04-15T09:15:27Z</time></trkpt><trkpt lat=\"48.8241081237793\" lon=\"2.42675161361694\"><ele>56.211</ele><time>2007-04-15T09:15:28Z</time></trkpt><trkpt lat=\"48.8241348266602\" lon=\"2.42653560638428\"><ele>55.994</ele><time>2007-04-15T09:15:29Z</time></trkpt><trkpt lat=\"48.8241500854492\" lon=\"2.42639589309692\"><ele>55.9935</ele><time>2007-04-15T09:15:30Z</time></trkpt><trkpt lat=\"48.8241653442383\" lon=\"2.4261839389801\"><ele>55.9991</ele><time>2007-04-15T09:15:31Z</time></trkpt><trkpt lat=\"48.8241691589356\" lon=\"2.42598271369934\"><ele>56.003</ele><time>2007-04-15T09:15:32Z</time></trkpt><trkpt lat=\"48.8241729736328\" lon=\"2.42578315734863\"><ele>55.9478</ele><time>2007-04-15T09:15:33Z</time></trkpt><trkpt lat=\"48.8241882324219\" lon=\"2.42559576034546\"><ele>55.7482</ele><time>2007-04-15T09:15:34Z</time></trkpt><trkpt lat=\"48.8241996765137\" lon=\"2.42537546157837\"><ele>55.5119</ele><time>2007-04-15T09:15:35Z</time></trkpt><trkpt lat=\"48.8242073059082\" lon=\"2.42515134811401\"><ele>55.2703</ele><time>2007-04-15T09:15:36Z</time></trkpt><trkpt lat=\"48.8241996765137\" lon=\"2.42495322227478\"><ele>55.1309</ele><time>2007-04-15T09:15:37Z</time></trkpt><trkpt lat=\"48.8242073059082\" lon=\"2.42473721504211\"><ele>55.3821</ele><time>2007-04-15T09:15:38Z</time></trkpt><trkpt lat=\"48.8242111206055\" lon=\"2.42451214790344\"><ele>55.6297</ele><time>2007-04-15T09:15:39Z</time></trkpt><trkpt lat=\"48.8242073059082\" lon=\"2.42424917221069\"><ele>55.9106</ele><time>2007-04-15T09:15:40Z</time></trkpt><trkpt lat=\"48.8241996765137\" lon=\"2.42414093017578\"><ele>56.0309</ele><time>2007-04-15T09:15:41Z</time></trkpt><trkpt lat=\"48.8241882324219\" lon=\"2.42406296730042\"><ele>56.1244</ele><time>2007-04-15T09:15:42Z</time></trkpt><trkpt lat=\"48.8241653442383\" lon=\"2.42386054992676\"><ele>56.3653</ele><time>2007-04-15T09:15:43Z</time></trkpt><trkpt lat=\"48.8241767883301\" lon=\"2.42367625236511\"><ele>56.5885</ele><time>2007-04-15T09:15:44Z</time></trkpt><trkpt lat=\"48.8241767883301\" lon=\"2.4234766960144\"><ele>56.828</ele><time>2007-04-15T09:15:45Z</time></trkpt><trkpt lat=\"48.8241767883301\" lon=\"2.42324423789978\"><ele>56.8918</ele><time>2007-04-15T09:15:46Z</time></trkpt><trkpt lat=\"48.824161529541\" lon=\"2.4229850769043\"><ele>56.5847</ele><time>2007-04-15T09:15:47Z</time></trkpt><trkpt lat=\"48.8241691589356\" lon=\"2.42281794548035\"><ele>56.3797</ele><time>2007-04-15T09:15:48Z</time></trkpt><trkpt lat=\"48.8241539001465\" lon=\"2.42259240150452\"><ele>56.1245</ele><time>2007-04-15T09:15:49Z</time></trkpt><trkpt lat=\"48.8241348266602\" lon=\"2.42233800888062\"><ele>55.6643</ele><time>2007-04-15T09:15:50Z</time></trkpt><trkpt lat=\"48.8241081237793\" lon=\"2.42213726043701\"><ele>55.2608</ele><time>2007-04-15T09:15:51Z</time></trkpt><trkpt lat=\"48.8240966796875\" lon=\"2.42195701599121\"><ele>54.8903</ele><time>2007-04-15T09:15:52Z</time></trkpt><trkpt lat=\"48.8240776062012\" lon=\"2.42176008224487\"><ele>54.5209</ele><time>2007-04-15T09:15:53Z</time></trkpt><trkpt lat=\"48.8240547180176\" lon=\"2.42150497436523\"><ele>54.765</ele><time>2007-04-15T09:15:54Z</time></trkpt><trkpt lat=\"48.8240547180176\" lon=\"2.42130875587463\"><ele>55.2043</ele><time>2007-04-15T09:15:55Z</time></trkpt><trkpt lat=\"48.8240509033203\" lon=\"2.42112112045288\"><ele>55.6351</ele><time>2007-04-15T09:15:56Z</time></trkpt><trkpt lat=\"48.8240699768066\" lon=\"2.42098093032837\"><ele>55.8984</ele><time>2007-04-15T09:15:57Z</time></trkpt><trkpt lat=\"48.8240737915039\" lon=\"2.42069554328918\"><ele>56.2413</ele><time>2007-04-15T09:15:58Z</time></trkpt><trkpt lat=\"48.8240776062012\" lon=\"2.42041993141174\"><ele>56.2668</ele><time>2007-04-15T09:15:59Z</time></trkpt><trkpt lat=\"48.8240966796875\" lon=\"2.42023372650146\"><ele>56.2284</ele><time>2007-04-15T09:16:00Z</time></trkpt><trkpt lat=\"48.8241119384766\" lon=\"2.4200451374054\"><ele>56.1935</ele><time>2007-04-15T09:16:01Z</time></trkpt><trkpt lat=\"48.8241386413574\" lon=\"2.41980886459351\"><ele>56.0932</ele><time>2007-04-15T09:16:02Z</time></trkpt><trkpt lat=\"48.824161529541\" lon=\"2.41954040527344\"><ele>56.0151</ele><time>2007-04-15T09:16:03Z</time></trkpt><trkpt lat=\"48.8241844177246\" lon=\"2.41930985450745\"><ele>55.975</ele><time>2007-04-15T09:16:04Z</time></trkpt><trkpt lat=\"48.8242225646973\" lon=\"2.41903853416443\"><ele>55.6151</ele><time>2007-04-15T09:16:05Z</time></trkpt><trkpt lat=\"48.8242607116699\" lon=\"2.41884779930115\"><ele>55.0787</ele><time>2007-04-15T09:16:06Z</time></trkpt><trkpt lat=\"48.8243026733398\" lon=\"2.4186577796936\"><ele>54.5158</ele><time>2007-04-15T09:16:07Z</time></trkpt><trkpt lat=\"48.8243408203125\" lon=\"2.41845607757568\"><ele>53.9074</ele><time>2007-04-15T09:16:08Z</time></trkpt><trkpt lat=\"48.824390411377\" lon=\"2.41827249526978\"><ele>53.4434</ele><time>2007-04-15T09:16:09Z</time></trkpt><trkpt lat=\"48.8244285583496\" lon=\"2.41813111305237\"><ele>53.2952</ele><time>2007-04-15T09:16:10Z</time></trkpt><trkpt lat=\"48.8244743347168\" lon=\"2.41795015335083\"><ele>53.0918</ele><time>2007-04-15T09:16:11Z</time></trkpt><trkpt lat=\"48.8245391845703\" lon=\"2.41769933700562\"><ele>52.7659</ele><time>2007-04-15T09:16:12Z</time></trkpt><trkpt lat=\"48.8245544433594\" lon=\"2.4176299571991\"><ele>52.6766</ele><time>2007-04-15T09:16:13Z</time></trkpt><trkpt lat=\"48.8246040344238\" lon=\"2.41741943359375\"><ele>52.3288</ele><time>2007-04-15T09:16:14Z</time></trkpt><trkpt lat=\"48.824634552002\" lon=\"2.41727471351624\"><ele>52.0453</ele><time>2007-04-15T09:16:15Z</time></trkpt><trkpt lat=\"48.8246765136719\" lon=\"2.41707015037537\"><ele>51.6487</ele><time>2007-04-15T09:16:16Z</time></trkpt><trkpt lat=\"48.82470703125\" lon=\"2.41685700416565\"><ele>51.2831</ele><time>2007-04-15T09:16:17Z</time></trkpt><trkpt lat=\"48.8247375488281\" lon=\"2.41666865348816\"><ele>50.9472</ele><time>2007-04-15T09:16:18Z</time></trkpt><trkpt lat=\"48.8247566223144\" lon=\"2.41646027565002\"><ele>51.2268</ele><time>2007-04-15T09:16:19Z</time></trkpt><trkpt lat=\"48.8247718811035\" lon=\"2.41624808311462\"><ele>51.5508</ele><time>2007-04-15T09:16:20Z</time></trkpt><trkpt lat=\"48.8247947692871\" lon=\"2.41606044769287\"><ele>51.8354</ele><time>2007-04-15T09:16:21Z</time></trkpt><trkpt lat=\"48.8248062133789\" lon=\"2.41586542129517\"><ele>52.1734</ele><time>2007-04-15T09:16:22Z</time></trkpt><trkpt lat=\"48.8248176574707\" lon=\"2.41563558578491\"><ele>51.7961</ele><time>2007-04-15T09:16:23Z</time></trkpt><trkpt lat=\"48.824821472168\" lon=\"2.41540932655334\"><ele>51.3056</ele><time>2007-04-15T09:16:24Z</time></trkpt><trkpt lat=\"48.8248100280762\" lon=\"2.41521406173706\"><ele>50.9111</ele><time>2007-04-15T09:16:25Z</time></trkpt><trkpt lat=\"48.8248062133789\" lon=\"2.41503167152405\"><ele>50.5323</ele><time>2007-04-15T09:16:26Z</time></trkpt><trkpt lat=\"48.8247947692871\" lon=\"2.41480016708374\"><ele>50.1311</ele><time>2007-04-15T09:16:27Z</time></trkpt><trkpt lat=\"48.8247718811035\" lon=\"2.41449904441834\"><ele>49.6743</ele><time>2007-04-15T09:16:28Z</time></trkpt><trkpt lat=\"48.824779510498\" lon=\"2.4143533706665\"><ele>49.3879</ele><time>2007-04-15T09:16:29Z</time></trkpt><trkpt lat=\"48.8247756958008\" lon=\"2.41428327560425\"><ele>49.2812</ele><time>2007-04-15T09:16:30Z</time></trkpt><trkpt lat=\"48.8247604370117\" lon=\"2.41405868530273\"><ele>49.3346</ele><time>2007-04-15T09:16:31Z</time></trkpt><trkpt lat=\"48.8247604370117\" lon=\"2.41398334503174\"><ele>49.4634</ele><time>2007-04-15T09:16:32Z</time></trkpt><trkpt lat=\"48.824764251709\" lon=\"2.41381216049194\"><ele>49.7417</ele><time>2007-04-15T09:16:33Z</time></trkpt><trkpt lat=\"48.824764251709\" lon=\"2.41366839408874\"><ele>49.9891</ele><time>2007-04-15T09:16:34Z</time></trkpt><trkpt lat=\"48.8247528076172\" lon=\"2.41343545913696\"><ele>50.4209</ele><time>2007-04-15T09:16:35Z</time></trkpt><trkpt lat=\"48.8247566223144\" lon=\"2.41321539878845\"><ele>50.5841</ele><time>2007-04-15T09:16:36Z</time></trkpt><trkpt lat=\"48.8247718811035\" lon=\"2.41304659843445\"><ele>50.5475</ele><time>2007-04-15T09:16:37Z</time></trkpt><trkpt lat=\"48.824779510498\" lon=\"2.41286706924438\"><ele>50.5292</ele><time>2007-04-15T09:16:38Z</time></trkpt><trkpt lat=\"48.824779510498\" lon=\"2.41263890266418\"><ele>50.5292</ele><time>2007-04-15T09:16:39Z</time></trkpt><trkpt lat=\"48.8247985839844\" lon=\"2.41237854957581\"><ele>50.5138</ele><time>2007-04-15T09:16:40Z</time></trkpt><trkpt lat=\"48.8248100280762\" lon=\"2.41223669052124\"><ele>50.5001</ele><time>2007-04-15T09:16:41Z</time></trkpt><trkpt lat=\"48.8248176574707\" lon=\"2.41208028793335\"><ele>50.485</ele><time>2007-04-15T09:16:42Z</time></trkpt><trkpt lat=\"48.8248252868652\" lon=\"2.41192722320557\"><ele>50.4525</ele><time>2007-04-15T09:16:43Z</time></trkpt><trkpt lat=\"48.824836730957\" lon=\"2.41189646720886\"><ele>50.3771</ele><time>2007-04-15T09:16:44Z</time></trkpt><trkpt lat=\"48.8248519897461\" lon=\"2.41171026229858\"><ele>50.2491</ele><time>2007-04-15T09:16:45Z</time></trkpt><trkpt lat=\"48.824878692627\" lon=\"2.41145706176758\"><ele>50.6271</ele><time>2007-04-15T09:16:46Z</time></trkpt><trkpt lat=\"48.8249130249023\" lon=\"2.41129088401794\"><ele>50.8951</ele><time>2007-04-15T09:16:47Z</time></trkpt><trkpt lat=\"48.8249359130859\" lon=\"2.41107702255249\"><ele>51.4434</ele><time>2007-04-15T09:16:48Z</time></trkpt><trkpt lat=\"48.8249702453613\" lon=\"2.41082382202148\"><ele>52.1621</ele><time>2007-04-15T09:16:49Z</time></trkpt><trkpt lat=\"48.8249931335449\" lon=\"2.41071820259094\"><ele>52.7098</ele><time>2007-04-15T09:16:50Z</time></trkpt><trkpt lat=\"48.8250122070312\" lon=\"2.41064834594727\"><ele>53.0285</ele><time>2007-04-15T09:16:51Z</time></trkpt><trkpt lat=\"48.8250541687012\" lon=\"2.41047096252441\"><ele>53.8407</ele><time>2007-04-15T09:16:52Z</time></trkpt><trkpt lat=\"48.8251190185547\" lon=\"2.41031002998352\"><ele>54.4623</ele><time>2007-04-15T09:16:53Z</time></trkpt><trkpt lat=\"48.8251800537109\" lon=\"2.41013383865356\"><ele>55.2633</ele><time>2007-04-15T09:16:54Z</time></trkpt><trkpt lat=\"48.8252220153809\" lon=\"2.40995454788208\"><ele>55.8798</ele><time>2007-04-15T09:16:55Z</time></trkpt><trkpt lat=\"48.8252944946289\" lon=\"2.40975308418274\"><ele>55.2901</ele><time>2007-04-15T09:16:56Z</time></trkpt><trkpt lat=\"48.8253631591797\" lon=\"2.40959000587463\"><ele>54.7648</ele><time>2007-04-15T09:16:57Z</time></trkpt><trkpt lat=\"48.8254127502441\" lon=\"2.40946102142334\"><ele>54.372</ele><time>2007-04-15T09:16:58Z</time></trkpt><trkpt lat=\"48.8254241943359\" lon=\"2.40942740440369\"><ele>54.2768</ele><time>2007-04-15T09:16:59Z</time></trkpt><trkpt lat=\"48.8254737854004\" lon=\"2.40922594070435\"><ele>53.797</ele><time>2007-04-15T09:17:00Z</time></trkpt><trkpt lat=\"48.8255462646484\" lon=\"2.40904211997986\"><ele>53.177</ele><time>2007-04-15T09:17:01Z</time></trkpt><trkpt lat=\"48.8256072998047\" lon=\"2.40887331962585\"><ele>52.6375</ele><time>2007-04-15T09:17:02Z</time></trkpt><trkpt lat=\"48.8257102966309\" lon=\"2.40872287750244\"><ele>51.9794</ele><time>2007-04-15T09:17:03Z</time></trkpt><trkpt lat=\"48.8258247375488\" lon=\"2.40858244895935\"><ele>51.333</ele><time>2007-04-15T09:17:04Z</time></trkpt><trkpt lat=\"48.8258972167969\" lon=\"2.40843343734741\"><ele>51.025</ele><time>2007-04-15T09:17:05Z</time></trkpt><trkpt lat=\"48.8259811401367\" lon=\"2.40831780433655\"><ele>50.8599</ele><time>2007-04-15T09:17:06Z</time></trkpt><trkpt lat=\"48.8260383605957\" lon=\"2.40821409225464\"><ele>51.0401</ele><time>2007-04-15T09:17:07Z</time></trkpt><trkpt lat=\"48.8260841369629\" lon=\"2.40817880630493\"><ele>51.0699</ele><time>2007-04-15T09:17:08Z</time></trkpt><trkpt lat=\"48.826099395752\" lon=\"2.40815544128418\"><ele>51.1077</ele><time>2007-04-15T09:17:09Z</time></trkpt><trkpt lat=\"48.8261032104492\" lon=\"2.40814876556396\"><ele>51.1191</ele><time>2007-04-15T09:17:10Z</time></trkpt><trkpt lat=\"48.8262214660644\" lon=\"2.407958984375\"><ele>51.4327</ele><time>2007-04-15T09:17:11Z</time></trkpt><trkpt lat=\"48.8262519836426\" lon=\"2.40790247917175\"><ele>51.5317</ele><time>2007-04-15T09:17:12Z</time></trkpt><trkpt lat=\"48.8262901306152\" lon=\"2.40780115127563\"><ele>51.7291</ele><time>2007-04-15T09:17:13Z</time></trkpt><trkpt lat=\"48.8263168334961\" lon=\"2.40772271156311\"><ele>51.8853</ele><time>2007-04-15T09:17:14Z</time></trkpt><trkpt lat=\"48.8263626098633\" lon=\"2.40756130218506\"><ele>52.2177</ele><time>2007-04-15T09:17:15Z</time></trkpt><trkpt lat=\"48.8264503479004\" lon=\"2.40747690200806\"><ele>52.3427</ele><time>2007-04-15T09:17:16Z</time></trkpt><trkpt lat=\"48.8265266418457\" lon=\"2.40736269950867\"><ele>52.6623</ele><time>2007-04-15T09:17:17Z</time></trkpt><trkpt lat=\"48.8266258239746\" lon=\"2.40723204612732\"><ele>53.0136</ele><time>2007-04-15T09:17:18Z</time></trkpt><trkpt lat=\"48.8266983032227\" lon=\"2.4071536064148\"><ele>53.2312</ele><time>2007-04-15T09:17:19Z</time></trkpt><trkpt lat=\"48.826789855957\" lon=\"2.40706396102905\"><ele>53.4924</ele><time>2007-04-15T09:17:20Z</time></trkpt><trkpt lat=\"48.8268775939941\" lon=\"2.40697813034058\"><ele>53.7202</ele><time>2007-04-15T09:17:21Z</time></trkpt><trkpt lat=\"48.8269424438477\" lon=\"2.40689420700073\"><ele>53.9403</ele><time>2007-04-15T09:17:22Z</time></trkpt><trkpt lat=\"48.8270072937012\" lon=\"2.40678024291992\"><ele>54.2381</ele><time>2007-04-15T09:17:23Z</time></trkpt><trkpt lat=\"48.8270721435547\" lon=\"2.40665078163147\"><ele>54.5613</ele><time>2007-04-15T09:17:24Z</time></trkpt><trkpt lat=\"48.8271522521973\" lon=\"2.40655732154846\"><ele>54.7345</ele><time>2007-04-15T09:17:25Z</time></trkpt><trkpt lat=\"48.8272399902344\" lon=\"2.40645122528076\"><ele>54.9097</ele><time>2007-04-15T09:17:26Z</time></trkpt><trkpt lat=\"48.8273506164551\" lon=\"2.40633654594421\"><ele>55.0426</ele><time>2007-04-15T09:17:27Z</time></trkpt><trkpt lat=\"48.827465057373\" lon=\"2.40621089935303\"><ele>55.1587</ele><time>2007-04-15T09:17:28Z</time></trkpt><trkpt lat=\"48.8275718688965\" lon=\"2.40603923797607\"><ele>55.2471</ele><time>2007-04-15T09:17:29Z</time></trkpt><trkpt lat=\"48.8276519775391\" lon=\"2.40588974952698\"><ele>55.3175</ele><time>2007-04-15T09:17:30Z</time></trkpt><trkpt lat=\"48.827808380127\" lon=\"2.40578603744507\"><ele>54.9403</ele><time>2007-04-15T09:17:31Z</time></trkpt><trkpt lat=\"48.8279075622559\" lon=\"2.40565156936646\"><ele>54.649</ele><time>2007-04-15T09:17:32Z</time></trkpt><trkpt lat=\"48.827995300293\" lon=\"2.40551543235779\"><ele>54.2997</ele><time>2007-04-15T09:17:33Z</time></trkpt><trkpt lat=\"48.8280754089356\" lon=\"2.40536737442017\"><ele>53.8886</ele><time>2007-04-15T09:17:34Z</time></trkpt><trkpt lat=\"48.8282012939453\" lon=\"2.4051365852356\"><ele>53.0367</ele><time>2007-04-15T09:17:35Z</time></trkpt><trkpt lat=\"48.8282928466797\" lon=\"2.40503215789795\"><ele>52.3245</ele><time>2007-04-15T09:17:36Z</time></trkpt><trkpt lat=\"48.8284111022949\" lon=\"2.40489888191223\"><ele>52.2373</ele><time>2007-04-15T09:17:37Z</time></trkpt><trkpt lat=\"48.8285026550293\" lon=\"2.40471434593201\"><ele>52.6853</ele><time>2007-04-15T09:17:38Z</time></trkpt><trkpt lat=\"48.8285865783691\" lon=\"2.40459227561951\"><ele>53.0905</ele><time>2007-04-15T09:17:39Z</time></trkpt><trkpt lat=\"48.8286743164062\" lon=\"2.40445184707642\"><ele>53.6053</ele><time>2007-04-15T09:17:40Z</time></trkpt><trkpt lat=\"48.8287658691406\" lon=\"2.4042809009552\"><ele>54.2777</ele><time>2007-04-15T09:17:41Z</time></trkpt><trkpt lat=\"48.8288345336914\" lon=\"2.40414094924927\"><ele>54.7549</ele><time>2007-04-15T09:17:42Z</time></trkpt><trkpt lat=\"48.8289031982422\" lon=\"2.40395855903626\"><ele>54.631</ele><time>2007-04-15T09:17:43Z</time></trkpt><trkpt lat=\"48.8289566040039\" lon=\"2.40378451347351\"><ele>54.4422</ele><time>2007-04-15T09:17:44Z</time></trkpt><trkpt lat=\"48.8290138244629\" lon=\"2.40358591079712\"><ele>54.1838</ele><time>2007-04-15T09:17:45Z</time></trkpt><trkpt lat=\"48.8291053771973\" lon=\"2.40346789360046\"><ele>54.164</ele><time>2007-04-15T09:17:46Z</time></trkpt><trkpt lat=\"48.8291969299316\" lon=\"2.40329599380493\"><ele>54.0629</ele><time>2007-04-15T09:17:47Z</time></trkpt><trkpt lat=\"48.8292770385742\" lon=\"2.40315937995911\"><ele>54.099</ele><time>2007-04-15T09:17:48Z</time></trkpt><trkpt lat=\"48.8293533325195\" lon=\"2.4030065536499\"><ele>53.921</ele><time>2007-04-15T09:17:49Z</time></trkpt><trkpt lat=\"48.8294219970703\" lon=\"2.40281677246094\"><ele>53.4732</ele><time>2007-04-15T09:17:50Z</time></trkpt><trkpt lat=\"48.8294830322266\" lon=\"2.40265560150146\"><ele>52.9068</ele><time>2007-04-15T09:17:51Z</time></trkpt><trkpt lat=\"48.8295364379883\" lon=\"2.40248870849609\"><ele>52.1935</ele><time>2007-04-15T09:17:52Z</time></trkpt><trkpt lat=\"48.8295745849609\" lon=\"2.4022741317749\"><ele>51.3729</ele><time>2007-04-15T09:17:53Z</time></trkpt><trkpt lat=\"48.8296089172363\" lon=\"2.40205407142639\"><ele>50.4901</ele><time>2007-04-15T09:17:54Z</time></trkpt><trkpt lat=\"48.8296356201172\" lon=\"2.4018452167511\"><ele>49.6368</ele><time>2007-04-15T09:17:55Z</time></trkpt><trkpt lat=\"48.8296508789062\" lon=\"2.40164875984192\"><ele>48.9091</ele><time>2007-04-15T09:17:56Z</time></trkpt><trkpt lat=\"48.8296928405762\" lon=\"2.40141725540161\"><ele>48.3278</ele><time>2007-04-15T09:17:57Z</time></trkpt><trkpt lat=\"48.8297348022461\" lon=\"2.40111541748047\"><ele>47.8366</ele><time>2007-04-15T09:17:58Z</time></trkpt><trkpt lat=\"48.8297653198242\" lon=\"2.40092086791992\"><ele>47.6061</ele><time>2007-04-15T09:17:59Z</time></trkpt><trkpt lat=\"48.8298492431641\" lon=\"2.40071821212769\"><ele>47.6763</ele><time>2007-04-15T09:18:00Z</time></trkpt><trkpt lat=\"48.8299446105957\" lon=\"2.4005651473999\"><ele>48.0128</ele><time>2007-04-15T09:18:01Z</time></trkpt><trkpt lat=\"48.8300476074219\" lon=\"2.40041089057922\"><ele>48.4057</ele><time>2007-04-15T09:18:02Z</time></trkpt><trkpt lat=\"48.8301277160644\" lon=\"2.40031981468201\"><ele>48.5065</ele><time>2007-04-15T09:18:03Z</time></trkpt><trkpt lat=\"48.8302421569824\" lon=\"2.40016841888428\"><ele>48.6394</ele><time>2007-04-15T09:18:04Z</time></trkpt><trkpt lat=\"48.8303565979004\" lon=\"2.39999771118164\"><ele>48.7104</ele><time>2007-04-15T09:18:05Z</time></trkpt><trkpt lat=\"48.8304100036621\" lon=\"2.39990925788879\"><ele>48.3045</ele><time>2007-04-15T09:18:06Z</time></trkpt><trkpt lat=\"48.8304481506348\" lon=\"2.39985418319702\"><ele>48.0499</ele><time>2007-04-15T09:18:07Z</time></trkpt><trkpt lat=\"48.8305511474609\" lon=\"2.39968419075012\"><ele>47.3802</ele><time>2007-04-15T09:18:08Z</time></trkpt><trkpt lat=\"48.8306503295898\" lon=\"2.39951753616333\"><ele>46.8256</ele><time>2007-04-15T09:18:09Z</time></trkpt><trkpt lat=\"48.8307952880859\" lon=\"2.39931082725525\"><ele>46.2344</ele><time>2007-04-15T09:18:10Z</time></trkpt><trkpt lat=\"48.8309059143066\" lon=\"2.39915156364441\"><ele>46.1935</ele><time>2007-04-15T09:18:11Z</time></trkpt><trkpt lat=\"48.8309936523438\" lon=\"2.39902019500732\"><ele>45.9755</ele><time>2007-04-15T09:18:12Z</time></trkpt><trkpt lat=\"48.8310699462891\" lon=\"2.39887499809265\"><ele>45.7499</ele><time>2007-04-15T09:18:13Z</time></trkpt><trkpt lat=\"48.8311767578125\" lon=\"2.39870691299438\"><ele>45.7116</ele><time>2007-04-15T09:18:14Z</time></trkpt><trkpt lat=\"48.8312797546387\" lon=\"2.39855766296387\"><ele>45.8584</ele><time>2007-04-15T09:18:15Z</time></trkpt><trkpt lat=\"48.8313674926758\" lon=\"2.3984203338623\"><ele>46.0628</ele><time>2007-04-15T09:18:16Z</time></trkpt><trkpt lat=\"48.8314933776856\" lon=\"2.39824080467224\"><ele>46.373</ele><time>2007-04-15T09:18:17Z</time></trkpt><trkpt lat=\"48.831615447998\" lon=\"2.39805603027344\"><ele>46.592</ele><time>2007-04-15T09:18:18Z</time></trkpt><trkpt lat=\"48.8317031860352\" lon=\"2.39791703224182\"><ele>46.4356</ele><time>2007-04-15T09:18:19Z</time></trkpt><trkpt lat=\"48.8318023681641\" lon=\"2.39775848388672\"><ele>45.7172</ele><time>2007-04-15T09:18:20Z</time></trkpt><trkpt lat=\"48.8318901062012\" lon=\"2.39760756492615\"><ele>45.0845</ele><time>2007-04-15T09:18:21Z</time></trkpt><trkpt lat=\"48.8320007324219\" lon=\"2.39741778373718\"><ele>44.5205</ele><time>2007-04-15T09:18:22Z</time></trkpt><trkpt lat=\"48.8321075439453\" lon=\"2.39723682403564\"><ele>44.3406</ele><time>2007-04-15T09:18:23Z</time></trkpt><trkpt lat=\"48.832218170166\" lon=\"2.39708018302917\"><ele>44.3308</ele><time>2007-04-15T09:18:24Z</time></trkpt><trkpt lat=\"48.8323211669922\" lon=\"2.39692258834839\"><ele>44.4614</ele><time>2007-04-15T09:18:25Z</time></trkpt><trkpt lat=\"48.8324203491211\" lon=\"2.39676833152771\"><ele>44.7218</ele><time>2007-04-15T09:18:26Z</time></trkpt><trkpt lat=\"48.8325004577637\" lon=\"2.39664173126221\"><ele>44.944</ele><time>2007-04-15T09:18:27Z</time></trkpt><trkpt lat=\"48.8325958251953\" lon=\"2.39649224281311\"><ele>45.3622</ele><time>2007-04-15T09:18:28Z</time></trkpt><trkpt lat=\"48.8326988220215\" lon=\"2.39633965492249\"><ele>45.7917</ele><time>2007-04-15T09:18:29Z</time></trkpt><trkpt lat=\"48.8327751159668\" lon=\"2.39619708061218\"><ele>45.9979</ele><time>2007-04-15T09:18:30Z</time></trkpt><trkpt lat=\"48.8328475952148\" lon=\"2.39609527587891\"><ele>46.2625</ele><time>2007-04-15T09:18:31Z</time></trkpt><trkpt lat=\"48.8329544067383\" lon=\"2.39592862129211\"><ele>46.5628</ele><time>2007-04-15T09:18:32Z</time></trkpt><trkpt lat=\"48.8330764770508\" lon=\"2.3957736492157\"><ele>46.7155</ele><time>2007-04-15T09:18:33Z</time></trkpt><trkpt lat=\"48.8331680297852\" lon=\"2.39565443992615\"><ele>46.4349</ele><time>2007-04-15T09:18:34Z</time></trkpt><trkpt lat=\"48.8332672119141\" lon=\"2.39549398422241\"><ele>45.7703</ele><time>2007-04-15T09:18:35Z</time></trkpt><trkpt lat=\"48.833366394043\" lon=\"2.39533376693726\"><ele>44.9305</ele><time>2007-04-15T09:18:36Z</time></trkpt><trkpt lat=\"48.8334693908691\" lon=\"2.39517903327942\"><ele>44.238</ele><time>2007-04-15T09:18:37Z</time></trkpt><trkpt lat=\"48.8335762023926\" lon=\"2.395015001297\"><ele>43.8379</ele><time>2007-04-15T09:18:38Z</time></trkpt><trkpt lat=\"48.8336868286133\" lon=\"2.39487075805664\"><ele>44.2115</ele><time>2007-04-15T09:18:39Z</time></trkpt><trkpt lat=\"48.8337745666504\" lon=\"2.39474081993103\"><ele>44.5732</ele><time>2007-04-15T09:18:40Z</time></trkpt><trkpt lat=\"48.8338623046875\" lon=\"2.39461612701416\"><ele>45.0115</ele><time>2007-04-15T09:18:41Z</time></trkpt><trkpt lat=\"48.8339653015137\" lon=\"2.39445900917053\"><ele>45.5872</ele><time>2007-04-15T09:18:42Z</time></trkpt><trkpt lat=\"48.8340454101562\" lon=\"2.39433479309082\"><ele>46.0964</ele><time>2007-04-15T09:18:43Z</time></trkpt><trkpt lat=\"48.8341331481934\" lon=\"2.39420914649963\"><ele>46.7333</ele><time>2007-04-15T09:18:44Z</time></trkpt><trkpt lat=\"48.8342170715332\" lon=\"2.39409613609314\"><ele>47.3961</ele><time>2007-04-15T09:18:45Z</time></trkpt><trkpt lat=\"48.834300994873\" lon=\"2.3939938545227\"><ele>48.0507</ele><time>2007-04-15T09:18:46Z</time></trkpt><trkpt lat=\"48.8344306945801\" lon=\"2.39386630058289\"><ele>49.0613</ele><time>2007-04-15T09:18:47Z</time></trkpt><trkpt lat=\"48.8344535827637\" lon=\"2.39384984970093\"><ele>49.2541</ele><time>2007-04-15T09:18:48Z</time></trkpt><trkpt lat=\"48.8345489501953\" lon=\"2.39368891716003\"><ele>49.5373</ele><time>2007-04-15T09:18:49Z</time></trkpt><trkpt lat=\"48.8345756530762\" lon=\"2.39362645149231\"><ele>49.4994</ele><time>2007-04-15T09:18:50Z</time></trkpt><trkpt lat=\"48.8346633911133\" lon=\"2.3934690952301\"><ele>49.5486</ele><time>2007-04-15T09:18:51Z</time></trkpt><trkpt lat=\"48.834774017334\" lon=\"2.39336585998535\"><ele>50.033</ele><time>2007-04-15T09:18:52Z</time></trkpt><trkpt lat=\"48.8348731994629\" lon=\"2.39325547218323\"><ele>50.344</ele><time>2007-04-15T09:18:53Z</time></trkpt><trkpt lat=\"48.8349685668945\" lon=\"2.39314031600952\"><ele>50.5576</ele><time>2007-04-15T09:18:54Z</time></trkpt><trkpt lat=\"48.8350677490234\" lon=\"2.39301586151123\"><ele>49.7932</ele><time>2007-04-15T09:18:55Z</time></trkpt><trkpt lat=\"48.8351936340332\" lon=\"2.39290571212769\"><ele>48.7555</ele><time>2007-04-15T09:18:56Z</time></trkpt><trkpt lat=\"48.8353424072266\" lon=\"2.39275670051575\"><ele>47.7808</ele><time>2007-04-15T09:18:57Z</time></trkpt><trkpt lat=\"48.8354644775391\" lon=\"2.39262843132019\"><ele>47.2552</ele><time>2007-04-15T09:18:58Z</time></trkpt><trkpt lat=\"48.8355484008789\" lon=\"2.39254331588745\"><ele>47.0547</ele><time>2007-04-15T09:18:59Z</time></trkpt><trkpt lat=\"48.8356971740723\" lon=\"2.39242553710938\"><ele>46.7775</ele><time>2007-04-15T09:19:00Z</time></trkpt><trkpt lat=\"48.8357582092285\" lon=\"2.39233827590942\"><ele>46.5594</ele><time>2007-04-15T09:19:01Z</time></trkpt><trkpt lat=\"48.8358688354492\" lon=\"2.39226150512695\"><ele>46.2694</ele><time>2007-04-15T09:19:02Z</time></trkpt><trkpt lat=\"48.835994720459\" lon=\"2.39220142364502\"><ele>45.5781</ele><time>2007-04-15T09:19:03Z</time></trkpt><trkpt lat=\"48.8361015319824\" lon=\"2.39213061332703\"><ele>44.9688</ele><time>2007-04-15T09:19:04Z</time></trkpt><trkpt lat=\"48.8362007141113\" lon=\"2.39200663566589\"><ele>44.3135</ele><time>2007-04-15T09:19:05Z</time></trkpt><trkpt lat=\"48.8363227844238\" lon=\"2.39187598228455\"><ele>43.5928</ele><time>2007-04-15T09:19:06Z</time></trkpt><trkpt lat=\"48.83642578125\" lon=\"2.39178204536438\"><ele>43.0457</ele><time>2007-04-15T09:19:07Z</time></trkpt><trkpt lat=\"48.8365097045898\" lon=\"2.39171075820923\"><ele>42.6279</ele><time>2007-04-15T09:19:08Z</time></trkpt><trkpt lat=\"48.8366012573242\" lon=\"2.39161252975464\"><ele>42.2202</ele><time>2007-04-15T09:19:09Z</time></trkpt><trkpt lat=\"48.8367118835449\" lon=\"2.39150929450989\"><ele>42.088</ele><time>2007-04-15T09:19:10Z</time></trkpt><trkpt lat=\"48.8368225097656\" lon=\"2.39140701293945\"><ele>42.2575</ele><time>2007-04-15T09:19:11Z</time></trkpt><trkpt lat=\"48.8369483947754\" lon=\"2.39134168624878\"><ele>42.4125</ele><time>2007-04-15T09:19:12Z</time></trkpt><trkpt lat=\"48.8370361328125\" lon=\"2.39121341705322\"><ele>42.4044</ele><time>2007-04-15T09:19:13Z</time></trkpt><trkpt lat=\"48.8371849060059\" lon=\"2.39113211631775\"><ele>42.4459</ele><time>2007-04-15T09:19:14Z</time></trkpt><trkpt lat=\"48.837230682373\" lon=\"2.39110326766968\"><ele>42.4385</ele><time>2007-04-15T09:19:15Z</time></trkpt><trkpt lat=\"48.8372993469238\" lon=\"2.39105558395386\"><ele>42.405</ele><time>2007-04-15T09:19:16Z</time></trkpt><trkpt lat=\"48.8374328613281\" lon=\"2.39095139503479\"><ele>42.2605</ele><time>2007-04-15T09:19:17Z</time></trkpt><trkpt lat=\"48.837532043457\" lon=\"2.39080953598022\"><ele>42.0242</ele><time>2007-04-15T09:19:18Z</time></trkpt><trkpt lat=\"48.8375968933106\" lon=\"2.39063024520874\"><ele>41.8585</ele><time>2007-04-15T09:19:19Z</time></trkpt><trkpt lat=\"48.8376693725586\" lon=\"2.39052414894104\"><ele>41.9661</ele><time>2007-04-15T09:19:20Z</time></trkpt><trkpt lat=\"48.8377571105957\" lon=\"2.39040446281433\"><ele>42.2229</ele><time>2007-04-15T09:19:21Z</time></trkpt><trkpt lat=\"48.8378410339356\" lon=\"2.39029979705811\"><ele>42.586</ele><time>2007-04-15T09:19:22Z</time></trkpt><trkpt lat=\"48.8379096984863\" lon=\"2.3901572227478\"><ele>42.9561</ele><time>2007-04-15T09:19:23Z</time></trkpt><trkpt lat=\"48.8380165100098\" lon=\"2.39007997512817\"><ele>43.6729</ele><time>2007-04-15T09:19:24Z</time></trkpt><trkpt lat=\"48.8381195068359\" lon=\"2.39005064964294\"><ele>44.4013</ele><time>2007-04-15T09:19:25Z</time></trkpt><trkpt lat=\"48.8381729125977\" lon=\"2.39004135131836\"><ele>44.7839</ele><time>2007-04-15T09:19:26Z</time></trkpt><trkpt lat=\"48.8382377624512\" lon=\"2.38989949226379\"><ele>45.1913</ele><time>2007-04-15T09:19:27Z</time></trkpt><trkpt lat=\"48.8383102416992\" lon=\"2.38976359367371\"><ele>45.5501</ele><time>2007-04-15T09:19:28Z</time></trkpt><trkpt lat=\"48.8383903503418\" lon=\"2.38962411880493\"><ele>45.8468</ele><time>2007-04-15T09:19:29Z</time></trkpt><trkpt lat=\"48.8385391235352\" lon=\"2.38950109481812\"><ele>46.5857</ele><time>2007-04-15T09:19:30Z</time></trkpt><trkpt lat=\"48.8386688232422\" lon=\"2.38942766189575\"><ele>47.3505</ele><time>2007-04-15T09:19:31Z</time></trkpt><trkpt lat=\"48.8387985229492\" lon=\"2.38933873176575\"><ele>48.2101</ele><time>2007-04-15T09:19:32Z</time></trkpt><trkpt lat=\"48.8389053344727\" lon=\"2.38927483558655\"><ele>48.9809</ele><time>2007-04-15T09:19:33Z</time></trkpt><trkpt lat=\"48.839038848877\" lon=\"2.38918495178223\"><ele>50.0459</ele><time>2007-04-15T09:19:34Z</time></trkpt><trkpt lat=\"48.8391571044922\" lon=\"2.38909864425659\"><ele>50.5249</ele><time>2007-04-15T09:19:35Z</time></trkpt><trkpt lat=\"48.8392448425293\" lon=\"2.38902807235718\"><ele>50.0746</ele><time>2007-04-15T09:19:36Z</time></trkpt><trkpt lat=\"48.8394012451172\" lon=\"2.38892436027527\"><ele>49.2647</ele><time>2007-04-15T09:19:37Z</time></trkpt><trkpt lat=\"48.8395004272461\" lon=\"2.38876819610596\"><ele>48.2087</ele><time>2007-04-15T09:19:38Z</time></trkpt><trkpt lat=\"48.8395690917969\" lon=\"2.38863444328308\"><ele>47.3237</ele><time>2007-04-15T09:19:39Z</time></trkpt><trkpt lat=\"48.8395919799805\" lon=\"2.38861083984375\"><ele>47.1547</ele><time>2007-04-15T09:19:40Z</time></trkpt><trkpt lat=\"48.8398094177246\" lon=\"2.38855504989624\"><ele>46.559</ele><time>2007-04-15T09:19:41Z</time></trkpt><trkpt lat=\"48.8400230407715\" lon=\"2.38850355148315\"><ele>46.0597</ele><time>2007-04-15T09:19:42Z</time></trkpt><trkpt lat=\"48.8401412963867\" lon=\"2.38835048675537\"><ele>45.4316</ele><time>2007-04-15T09:19:43Z</time></trkpt><trkpt lat=\"48.8402252197266\" lon=\"2.38821578025818\"><ele>45.1936</ele><time>2007-04-15T09:19:44Z</time></trkpt><trkpt lat=\"48.8403396606445\" lon=\"2.3880820274353\"><ele>45.1563</ele><time>2007-04-15T09:19:45Z</time></trkpt><trkpt lat=\"48.8404273986816\" lon=\"2.38796281814575\"><ele>45.148</ele><time>2007-04-15T09:19:46Z</time></trkpt><trkpt lat=\"48.8405265808106\" lon=\"2.38784766197205\"><ele>45.2519</ele><time>2007-04-15T09:19:47Z</time></trkpt><trkpt lat=\"48.8406524658203\" lon=\"2.3877272605896\"><ele>45.5229</ele><time>2007-04-15T09:19:48Z</time></trkpt><trkpt lat=\"48.8407745361328\" lon=\"2.387610912323\"><ele>45.8696</ele><time>2007-04-15T09:19:49Z</time></trkpt><trkpt lat=\"48.8408813476562\" lon=\"2.38751101493835\"><ele>45.8388</ele><time>2007-04-15T09:19:50Z</time></trkpt><trkpt lat=\"48.8409957885742\" lon=\"2.38739013671875\"><ele>45.5727</ele><time>2007-04-15T09:19:51Z</time></trkpt><trkpt lat=\"48.8411293029785\" lon=\"2.3873393535614\"><ele>45.1958</ele><time>2007-04-15T09:19:52Z</time></trkpt><trkpt lat=\"48.8412780761719\" lon=\"2.3872652053833\"><ele>44.831</ele><time>2007-04-15T09:19:53Z</time></trkpt><trkpt lat=\"48.8413772583008\" lon=\"2.38714480400085\"><ele>44.7463</ele><time>2007-04-15T09:19:54Z</time></trkpt><trkpt lat=\"48.8414840698242\" lon=\"2.38704323768616\"><ele>44.6335</ele><time>2007-04-15T09:19:55Z</time></trkpt><trkpt lat=\"48.8415946960449\" lon=\"2.3869194984436\"><ele>44.5921</ele><time>2007-04-15T09:19:56Z</time></trkpt><trkpt lat=\"48.8416481018066\" lon=\"2.38690209388733\"><ele>44.4858</ele><time>2007-04-15T09:19:57Z</time></trkpt><trkpt lat=\"48.8417930603027\" lon=\"2.38675045967102\"><ele>44.9811</ele><time>2007-04-15T09:19:58Z</time></trkpt><trkpt lat=\"48.8418731689453\" lon=\"2.38662338256836\"><ele>45.1444</ele><time>2007-04-15T09:19:59Z</time></trkpt><trkpt lat=\"48.841911315918\" lon=\"2.38644504547119\"><ele>44.7153</ele><time>2007-04-15T09:20:00Z</time></trkpt><trkpt lat=\"48.841983795166\" lon=\"2.38631200790405\"><ele>44.3071</ele><time>2007-04-15T09:20:01Z</time></trkpt><trkpt lat=\"48.8420524597168\" lon=\"2.3861346244812\"><ele>43.6422</ele><time>2007-04-15T09:20:02Z</time></trkpt><trkpt lat=\"48.8421249389648\" lon=\"2.38601112365723\"><ele>43.0329</ele><time>2007-04-15T09:20:03Z</time></trkpt><trkpt lat=\"48.8421363830566\" lon=\"2.385986328125\"><ele>42.9066</ele><time>2007-04-15T09:20:04Z</time></trkpt><trkpt lat=\"48.8421745300293\" lon=\"2.38595271110535\"><ele>42.6642</ele><time>2007-04-15T09:20:05Z</time></trkpt><trkpt lat=\"48.8421859741211\" lon=\"2.38597536087036\"><ele>42.7258</ele><time>2007-04-15T09:20:06Z</time></trkpt><trkpt lat=\"48.8421859741211\" lon=\"2.38597345352173\"><ele>42.7178</ele><time>2007-04-15T09:20:07Z</time></trkpt><trkpt lat=\"48.8422546386719\" lon=\"2.38584160804749\"><ele>41.9213</ele><time>2007-04-15T09:20:08Z</time></trkpt><trkpt lat=\"48.8423156738281\" lon=\"2.38569116592407\"><ele>41.3798</ele><time>2007-04-15T09:20:09Z</time></trkpt><trkpt lat=\"48.8423614501953\" lon=\"2.3855197429657\"><ele>40.9348</ele><time>2007-04-15T09:20:10Z</time></trkpt><trkpt lat=\"48.8424491882324\" lon=\"2.38530111312866\"><ele>40.4274</ele><time>2007-04-15T09:20:11Z</time></trkpt><trkpt lat=\"48.8425140380859\" lon=\"2.38515520095825\"><ele>40.1663</ele><time>2007-04-15T09:20:12Z</time></trkpt><trkpt lat=\"48.8426246643066\" lon=\"2.38496160507202\"><ele>39.8435</ele><time>2007-04-15T09:20:13Z</time></trkpt><trkpt lat=\"48.8426780700684\" lon=\"2.38479018211365\"><ele>39.7325</ele><time>2007-04-15T09:20:14Z</time></trkpt><trkpt lat=\"48.8427619934082\" lon=\"2.38462376594543\"><ele>39.5437</ele><time>2007-04-15T09:20:15Z</time></trkpt><trkpt lat=\"48.8428497314453\" lon=\"2.38447856903076\"><ele>39.3177</ele><time>2007-04-15T09:20:16Z</time></trkpt><trkpt lat=\"48.8429412841797\" lon=\"2.38433313369751\"><ele>39.0467</ele><time>2007-04-15T09:20:17Z</time></trkpt><trkpt lat=\"48.8429870605469\" lon=\"2.38423347473145\"><ele>38.8779</ele><time>2007-04-15T09:20:18Z</time></trkpt><trkpt lat=\"48.8430480957031\" lon=\"2.38407206535339\"><ele>38.7562</ele><time>2007-04-15T09:20:19Z</time></trkpt><trkpt lat=\"48.843147277832\" lon=\"2.38388824462891\"><ele>38.8164</ele><time>2007-04-15T09:20:20Z</time></trkpt><trkpt lat=\"48.8432579040527\" lon=\"2.38371443748474\"><ele>39.0699</ele><time>2007-04-15T09:20:21Z</time></trkpt><trkpt lat=\"48.8433456420898\" lon=\"2.38355541229248\"><ele>39.4966</ele><time>2007-04-15T09:20:22Z</time></trkpt><trkpt lat=\"48.8434295654297\" lon=\"2.38341498374939\"><ele>40.035</ele><time>2007-04-15T09:20:23Z</time></trkpt><trkpt lat=\"48.8434982299805\" lon=\"2.38332724571228\"><ele>40.4163</ele><time>2007-04-15T09:20:24Z</time></trkpt><trkpt lat=\"48.8435821533203\" lon=\"2.38314056396484\"><ele>41.108</ele><time>2007-04-15T09:20:25Z</time></trkpt><trkpt lat=\"48.8436164855957\" lon=\"2.38308930397034\"><ele>41.2539</ele><time>2007-04-15T09:20:26Z</time></trkpt><trkpt lat=\"48.8436965942383\" lon=\"2.38288307189941\"><ele>41.6199</ele><time>2007-04-15T09:20:27Z</time></trkpt><trkpt lat=\"48.8437538146973\" lon=\"2.38275933265686\"><ele>41.679</ele><time>2007-04-15T09:20:28Z</time></trkpt><trkpt lat=\"48.8438186645508\" lon=\"2.38264942169189\"><ele>41.5798</ele><time>2007-04-15T09:20:29Z</time></trkpt><trkpt lat=\"48.8438720703125\" lon=\"2.38245892524719\"><ele>41.3503</ele><time>2007-04-15T09:20:30Z</time></trkpt><trkpt lat=\"48.8439140319824\" lon=\"2.38226079940796\"><ele>40.8126</ele><time>2007-04-15T09:20:31Z</time></trkpt><trkpt lat=\"48.8439445495606\" lon=\"2.38219857215881\"><ele>40.5356</ele><time>2007-04-15T09:20:32Z</time></trkpt><trkpt lat=\"48.8439826965332\" lon=\"2.3820960521698\"><ele>40.1276</ele><time>2007-04-15T09:20:33Z</time></trkpt><trkpt lat=\"48.8440856933594\" lon=\"2.38193106651306\"><ele>39.1559</ele><time>2007-04-15T09:20:34Z</time></trkpt><trkpt lat=\"48.8441963195801\" lon=\"2.38180661201477\"><ele>38.5434</ele><time>2007-04-15T09:20:35Z</time></trkpt><trkpt lat=\"48.8443336486816\" lon=\"2.38166928291321\"><ele>39.2079</ele><time>2007-04-15T09:20:36Z</time></trkpt><trkpt lat=\"48.8443984985352\" lon=\"2.38148641586304\"><ele>39.3325</ele><time>2007-04-15T09:20:37Z</time></trkpt><trkpt lat=\"48.8444862365723\" lon=\"2.38128995895386\"><ele>39.5021</ele><time>2007-04-15T09:20:38Z</time></trkpt><trkpt lat=\"48.8445625305176\" lon=\"2.38113451004028\"><ele>39.6049</ele><time>2007-04-15T09:20:39Z</time></trkpt><trkpt lat=\"48.8446731567383\" lon=\"2.38088178634644\"><ele>39.56</ele><time>2007-04-15T09:20:40Z</time></trkpt><trkpt lat=\"48.8447532653809\" lon=\"2.38068103790283\"><ele>39.5584</ele><time>2007-04-15T09:20:41Z</time></trkpt><trkpt lat=\"48.8448295593262\" lon=\"2.3805296421051\"><ele>39.6021</ele><time>2007-04-15T09:20:42Z</time></trkpt><trkpt lat=\"48.8448905944824\" lon=\"2.38039779663086\"><ele>39.5668</ele><time>2007-04-15T09:20:43Z</time></trkpt><trkpt lat=\"48.8449783325195\" lon=\"2.38020420074463\"><ele>39.4253</ele><time>2007-04-15T09:20:44Z</time></trkpt><trkpt lat=\"48.8450164794922\" lon=\"2.38015532493591\"><ele>39.3677</ele><time>2007-04-15T09:20:45Z</time></trkpt><trkpt lat=\"48.8450736999512\" lon=\"2.38003063201904\"><ele>38.9981</ele><time>2007-04-15T09:20:46Z</time></trkpt><trkpt lat=\"48.845100402832\" lon=\"2.37977838516235\"><ele>38.5815</ele><time>2007-04-15T09:20:47Z</time></trkpt><trkpt lat=\"48.845085144043\" lon=\"2.37951254844666\"><ele>38.2531</ele><time>2007-04-15T09:20:48Z</time></trkpt><trkpt lat=\"48.845100402832\" lon=\"2.3794846534729\"><ele>38.1866</ele><time>2007-04-15T09:20:49Z</time></trkpt><trkpt lat=\"48.8452682495117\" lon=\"2.3793580532074\"><ele>37.6598</ele><time>2007-04-15T09:20:50Z</time></trkpt><trkpt lat=\"48.845386505127\" lon=\"2.37922930717468\"><ele>37.1824</ele><time>2007-04-15T09:20:51Z</time></trkpt><trkpt lat=\"48.845458984375\" lon=\"2.3790807723999\"><ele>37.0687</ele><time>2007-04-15T09:20:52Z</time></trkpt><trkpt lat=\"48.845516204834\" lon=\"2.37890934944153\"><ele>37.3349</ele><time>2007-04-15T09:20:53Z</time></trkpt><trkpt lat=\"48.8455848693848\" lon=\"2.37875294685364\"><ele>37.6416</ele><time>2007-04-15T09:20:54Z</time></trkpt><trkpt lat=\"48.8456001281738\" lon=\"2.37866020202637\"><ele>37.8727</ele><time>2007-04-15T09:20:55Z</time></trkpt><trkpt lat=\"48.8457183837891\" lon=\"2.37845087051392\"><ele>38.4973</ele><time>2007-04-15T09:20:56Z</time></trkpt><trkpt lat=\"48.8457984924316\" lon=\"2.3783450126648\"><ele>38.9179</ele><time>2007-04-15T09:20:57Z</time></trkpt><trkpt lat=\"48.8458709716797\" lon=\"2.37818884849548\"><ele>39.5118</ele><time>2007-04-15T09:20:58Z</time></trkpt><trkpt lat=\"48.8459243774414\" lon=\"2.3780026435852\"><ele>40.144</ele><time>2007-04-15T09:20:59Z</time></trkpt><trkpt lat=\"48.8460311889648\" lon=\"2.37789487838745\"><ele>40.7522</ele><time>2007-04-15T09:21:00Z</time></trkpt><trkpt lat=\"48.8461265563965\" lon=\"2.37772297859192\"><ele>41.3569</ele><time>2007-04-15T09:21:01Z</time></trkpt><trkpt lat=\"48.8462219238281\" lon=\"2.37759304046631\"><ele>41.8134</ele><time>2007-04-15T09:21:02Z</time></trkpt><trkpt lat=\"48.8463134765625\" lon=\"2.37740802764893\"><ele>42.0888</ele><time>2007-04-15T09:21:03Z</time></trkpt><trkpt lat=\"48.8464241027832\" lon=\"2.37719798088074\"><ele>42.1609</ele><time>2007-04-15T09:21:04Z</time></trkpt><trkpt lat=\"48.8465118408203\" lon=\"2.37700986862183\"><ele>42.1495</ele><time>2007-04-15T09:21:05Z</time></trkpt><trkpt lat=\"48.8466033935547\" lon=\"2.37676215171814\"><ele>42.03</ele><time>2007-04-15T09:21:06Z</time></trkpt><trkpt lat=\"48.8467102050781\" lon=\"2.37660622596741\"><ele>41.9199</ele><time>2007-04-15T09:21:07Z</time></trkpt><trkpt lat=\"48.8467750549316\" lon=\"2.37648773193359\"><ele>41.7294</ele><time>2007-04-15T09:21:08Z</time></trkpt><trkpt lat=\"48.8468322753906\" lon=\"2.37631559371948\"><ele>41.4113</ele><time>2007-04-15T09:21:09Z</time></trkpt><trkpt lat=\"48.8469009399414\" lon=\"2.37614393234253\"><ele>41.02</ele><time>2007-04-15T09:21:10Z</time></trkpt><trkpt lat=\"48.8469772338867\" lon=\"2.37593126296997\"><ele>40.4597</ele><time>2007-04-15T09:21:11Z</time></trkpt><trkpt lat=\"48.8470611572266\" lon=\"2.37583327293396\"><ele>40.0533</ele><time>2007-04-15T09:21:12Z</time></trkpt><trkpt lat=\"48.8471794128418\" lon=\"2.37565875053406\"><ele>39.9306</ele><time>2007-04-15T09:21:13Z</time></trkpt><trkpt lat=\"48.8472366333008\" lon=\"2.37553000450134\"><ele>39.8622</ele><time>2007-04-15T09:21:14Z</time></trkpt><trkpt lat=\"48.8473205566406\" lon=\"2.37537789344788\"><ele>39.666</ele><time>2007-04-15T09:21:15Z</time></trkpt><trkpt lat=\"48.8473815917969\" lon=\"2.3752121925354\"><ele>39.496</ele><time>2007-04-15T09:21:16Z</time></trkpt><trkpt lat=\"48.8474731445312\" lon=\"2.37496471405029\"><ele>39.2095</ele><time>2007-04-15T09:21:17Z</time></trkpt><trkpt lat=\"48.8475646972656\" lon=\"2.37482523918152\"><ele>39.3418</ele><time>2007-04-15T09:21:18Z</time></trkpt><trkpt lat=\"48.8476638793945\" lon=\"2.37465643882751\"><ele>39.6279</ele><time>2007-04-15T09:21:19Z</time></trkpt><trkpt lat=\"48.8477249145508\" lon=\"2.37449145317078\"><ele>39.9506</ele><time>2007-04-15T09:21:20Z</time></trkpt><trkpt lat=\"48.8478317260742\" lon=\"2.37433052062988\"><ele>40.2087</ele><time>2007-04-15T09:21:21Z</time></trkpt><trkpt lat=\"48.8479347229004\" lon=\"2.37418246269226\"><ele>40.4404</ele><time>2007-04-15T09:21:22Z</time></trkpt><trkpt lat=\"48.8479843139648\" lon=\"2.37404656410217\"><ele>40.4792</ele><time>2007-04-15T09:21:23Z</time></trkpt><trkpt lat=\"48.8480682373047\" lon=\"2.37385821342468\"><ele>40.4359</ele><time>2007-04-15T09:21:24Z</time></trkpt><trkpt lat=\"48.8481559753418\" lon=\"2.37365436553955\"><ele>40.3437</ele><time>2007-04-15T09:21:25Z</time></trkpt><trkpt lat=\"48.8482284545898\" lon=\"2.37349629402161\"><ele>40.2271</ele><time>2007-04-15T09:21:26Z</time></trkpt><trkpt lat=\"48.8483123779297\" lon=\"2.37329745292664\"><ele>40.0072</ele><time>2007-04-15T09:21:27Z</time></trkpt><trkpt lat=\"48.8483772277832\" lon=\"2.37308955192566\"><ele>39.7293</ele><time>2007-04-15T09:21:28Z</time></trkpt><trkpt lat=\"48.8484268188477\" lon=\"2.37295389175415\"><ele>39.5547</ele><time>2007-04-15T09:21:29Z</time></trkpt><trkpt lat=\"48.8484916687012\" lon=\"2.37283420562744\"><ele>39.3634</ele><time>2007-04-15T09:21:30Z</time></trkpt><trkpt lat=\"48.848575592041\" lon=\"2.37258696556091\"><ele>38.8743</ele><time>2007-04-15T09:21:31Z</time></trkpt><trkpt lat=\"48.848690032959\" lon=\"2.37239646911621\"><ele>38.7851</ele><time>2007-04-15T09:21:32Z</time></trkpt><trkpt lat=\"48.8487739562988\" lon=\"2.37226986885071\"><ele>38.8617</ele><time>2007-04-15T09:21:33Z</time></trkpt><trkpt lat=\"48.8488616943359\" lon=\"2.37213134765625\"><ele>38.8517</ele><time>2007-04-15T09:21:34Z</time></trkpt><trkpt lat=\"48.8489379882812\" lon=\"2.37192225456238\"><ele>38.8452</ele><time>2007-04-15T09:21:35Z</time></trkpt><trkpt lat=\"48.8489608764648\" lon=\"2.37185168266296\"><ele>38.8233</ele><time>2007-04-15T09:21:36Z</time></trkpt><trkpt lat=\"48.8490371704102\" lon=\"2.37164950370789\"><ele>38.6912</ele><time>2007-04-15T09:21:37Z</time></trkpt><trkpt lat=\"48.8491287231445\" lon=\"2.37141442298889\"><ele>39.3378</ele><time>2007-04-15T09:21:38Z</time></trkpt><trkpt lat=\"48.8492240905762\" lon=\"2.37129926681519\"><ele>39.8102</ele><time>2007-04-15T09:21:39Z</time></trkpt><trkpt lat=\"48.8493270874023\" lon=\"2.37118744850159\"><ele>40.3531</ele><time>2007-04-15T09:21:40Z</time></trkpt><trkpt lat=\"48.8493461608887\" lon=\"2.37116146087646\"><ele>40.464</ele><time>2007-04-15T09:21:41Z</time></trkpt><trkpt lat=\"48.8494491577148\" lon=\"2.37104892730713\"><ele>40.8893</ele><time>2007-04-15T09:21:42Z</time></trkpt><trkpt lat=\"48.8495750427246\" lon=\"2.37091994285584\"><ele>41.247</ele><time>2007-04-15T09:21:43Z</time></trkpt><trkpt lat=\"48.8496856689453\" lon=\"2.37082982063293\"><ele>41.3951</ele><time>2007-04-15T09:21:44Z</time></trkpt><trkpt lat=\"48.8498001098633\" lon=\"2.37077283859253\"><ele>41.568</ele><time>2007-04-15T09:21:45Z</time></trkpt><trkpt lat=\"48.8499183654785\" lon=\"2.37065744400024\"><ele>42.1119</ele><time>2007-04-15T09:21:46Z</time></trkpt><trkpt lat=\"48.8500061035156\" lon=\"2.37053918838501\"><ele>42.7916</ele><time>2007-04-15T09:21:47Z</time></trkpt><trkpt lat=\"48.85009765625\" lon=\"2.37049794197083\"><ele>43.4339</ele><time>2007-04-15T09:21:48Z</time></trkpt><trkpt lat=\"48.8501968383789\" lon=\"2.37048554420471\"><ele>43.933</ele><time>2007-04-15T09:21:49Z</time></trkpt><trkpt lat=\"48.8503150939941\" lon=\"2.37052321434021\"><ele>44.2325</ele><time>2007-04-15T09:21:50Z</time></trkpt><trkpt lat=\"48.8504219055176\" lon=\"2.3704993724823\"><ele>44.826</ele><time>2007-04-15T09:21:51Z</time></trkpt><trkpt lat=\"48.8505477905273\" lon=\"2.37043046951294\"><ele>45.7288</ele><time>2007-04-15T09:21:52Z</time></trkpt><trkpt lat=\"48.8506393432617\" lon=\"2.37029433250427\"><ele>46.8066</ele><time>2007-04-15T09:21:53Z</time></trkpt><trkpt lat=\"48.8507118225098\" lon=\"2.37022018432617\"><ele>47.4671</ele><time>2007-04-15T09:21:54Z</time></trkpt><trkpt lat=\"48.8508720397949\" lon=\"2.37012100219727\"><ele>48.4267</ele><time>2007-04-15T09:21:55Z</time></trkpt><trkpt lat=\"48.8510055541992\" lon=\"2.37006068229675\"><ele>48.6225</ele><time>2007-04-15T09:21:56Z</time></trkpt><trkpt lat=\"48.8510513305664\" lon=\"2.37005805969238\"><ele>48.6055</ele><time>2007-04-15T09:21:57Z</time></trkpt><trkpt lat=\"48.851203918457\" lon=\"2.36991858482361\"><ele>48.045</ele><time>2007-04-15T09:21:58Z</time></trkpt><trkpt lat=\"48.8513031005859\" lon=\"2.36991858482361\"><ele>47.8678</ele><time>2007-04-15T09:21:59Z</time></trkpt><trkpt lat=\"48.8514060974121\" lon=\"2.36979222297668\"><ele>46.7078</ele><time>2007-04-15T09:22:00Z</time></trkpt><trkpt lat=\"48.8514938354492\" lon=\"2.3697566986084\"><ele>46.1745</ele><time>2007-04-15T09:22:01Z</time></trkpt><trkpt lat=\"48.8516883850098\" lon=\"2.36968970298767\"><ele>45.0927</ele><time>2007-04-15T09:22:02Z</time></trkpt><trkpt lat=\"48.8518562316894\" lon=\"2.36964106559753\"><ele>45.2051</ele><time>2007-04-15T09:22:03Z</time></trkpt><trkpt lat=\"48.8520011901856\" lon=\"2.36954045295715\"><ele>44.8339</ele><time>2007-04-15T09:22:04Z</time></trkpt><trkpt lat=\"48.8521499633789\" lon=\"2.36943173408508\"><ele>44.4955</ele><time>2007-04-15T09:22:05Z</time></trkpt><trkpt lat=\"48.8522987365723\" lon=\"2.36934399604797\"><ele>44.4135</ele><time>2007-04-15T09:22:06Z</time></trkpt><trkpt lat=\"48.8524398803711\" lon=\"2.36925864219666\"><ele>44.3896</ele><time>2007-04-15T09:22:07Z</time></trkpt><trkpt lat=\"48.8525581359863\" lon=\"2.36918663978577\"><ele>44.0623</ele><time>2007-04-15T09:22:08Z</time></trkpt><trkpt lat=\"48.8526725769043\" lon=\"2.36913585662842\"><ele>43.6846</ele><time>2007-04-15T09:22:09Z</time></trkpt><trkpt lat=\"48.8527526855469\" lon=\"2.36901879310608\"><ele>43.3476</ele><time>2007-04-15T09:22:10Z</time></trkpt><trkpt lat=\"48.8528022766113\" lon=\"2.36885619163513\"><ele>43.1258</ele><time>2007-04-15T09:22:11Z</time></trkpt><trkpt lat=\"48.8528366088867\" lon=\"2.36866211891174\"><ele>43.0144</ele><time>2007-04-15T09:22:12Z</time></trkpt><trkpt lat=\"48.8528594970703\" lon=\"2.36848425865173\"><ele>43.0068</ele><time>2007-04-15T09:22:13Z</time></trkpt><trkpt lat=\"48.8528480529785\" lon=\"2.36827802658081\"><ele>42.8858</ele><time>2007-04-15T09:22:14Z</time></trkpt><trkpt lat=\"48.8527946472168\" lon=\"2.36803293228149\"><ele>42.9868</ele><time>2007-04-15T09:22:15Z</time></trkpt><trkpt lat=\"48.8527412414551\" lon=\"2.36780381202698\"><ele>43.2274</ele><time>2007-04-15T09:22:16Z</time></trkpt><trkpt lat=\"48.8526763916016\" lon=\"2.36762928962708\"><ele>43.3903</ele><time>2007-04-15T09:22:17Z</time></trkpt><trkpt lat=\"48.8526458740234\" lon=\"2.36758232116699\"><ele>43.3915</ele><time>2007-04-15T09:22:18Z</time></trkpt><trkpt lat=\"48.8525276184082\" lon=\"2.36746644973755\"><ele>43.2038</ele><time>2007-04-15T09:22:19Z</time></trkpt><trkpt lat=\"48.8524894714356\" lon=\"2.36736726760864\"><ele>43.2761</ele><time>2007-04-15T09:22:20Z</time></trkpt><trkpt lat=\"48.8524551391602\" lon=\"2.36715388298035\"><ele>43.7048</ele><time>2007-04-15T09:22:21Z</time></trkpt><trkpt lat=\"48.8523826599121\" lon=\"2.36695957183838\"><ele>44.0991</ele><time>2007-04-15T09:22:22Z</time></trkpt><trkpt lat=\"48.8523025512695\" lon=\"2.36679768562317\"><ele>44.5365</ele><time>2007-04-15T09:22:23Z</time></trkpt><trkpt lat=\"48.8522491455078\" lon=\"2.36663126945496\"><ele>44.9744</ele><time>2007-04-15T09:22:24Z</time></trkpt><trkpt lat=\"48.8522567749023\" lon=\"2.36650133132935\"><ele>44.8842</ele><time>2007-04-15T09:22:25Z</time></trkpt><trkpt lat=\"48.8522605895996\" lon=\"2.36648607254028\"><ele>44.8755</ele><time>2007-04-15T09:22:26Z</time></trkpt><trkpt lat=\"48.8522720336914\" lon=\"2.36640882492065\"><ele>44.8307</ele><time>2007-04-15T09:22:27Z</time></trkpt><trkpt lat=\"48.8522758483887\" lon=\"2.36632061004639\"><ele>44.7766</ele><time>2007-04-15T09:22:28Z</time></trkpt><trkpt lat=\"48.8522682189941\" lon=\"2.36626029014587\"><ele>44.7287</ele><time>2007-04-15T09:22:29Z</time></trkpt><trkpt lat=\"48.8522148132324\" lon=\"2.36624884605408\"><ele>44.6568</ele><time>2007-04-15T09:22:30Z</time></trkpt><trkpt lat=\"48.8521614074707\" lon=\"2.3662383556366\"><ele>44.5823</ele><time>2007-04-15T09:22:31Z</time></trkpt><trkpt lat=\"48.852108001709\" lon=\"2.36618947982788\"><ele>44.4613</ele><time>2007-04-15T09:22:32Z</time></trkpt><trkpt lat=\"48.85205078125\" lon=\"2.36613202095032\"><ele>44.3083</ele><time>2007-04-15T09:22:33Z</time></trkpt><trkpt lat=\"48.8520469665527\" lon=\"2.36611914634705\"><ele>44.2856</ele><time>2007-04-15T09:22:34Z</time></trkpt><trkpt lat=\"48.8520469665527\" lon=\"2.36610460281372\"><ele>44.2667</ele><time>2007-04-15T09:22:35Z</time></trkpt><trkpt lat=\"48.8520469665527\" lon=\"2.36585855484009\"><ele>43.9456</ele><time>2007-04-15T09:22:36Z</time></trkpt><trkpt lat=\"48.8520393371582\" lon=\"2.36571478843689\"><ele>43.6735</ele><time>2007-04-15T09:22:37Z</time></trkpt><trkpt lat=\"48.8519859313965\" lon=\"2.36556696891785\"><ele>43.2494</ele><time>2007-04-15T09:22:38Z</time></trkpt><trkpt lat=\"48.8518905639648\" lon=\"2.36544942855835\"><ele>42.7398</ele><time>2007-04-15T09:22:39Z</time></trkpt><trkpt lat=\"48.8517951965332\" lon=\"2.36531019210815\"><ele>42.1498</ele><time>2007-04-15T09:22:40Z</time></trkpt><trkpt lat=\"48.8517265319824\" lon=\"2.36520481109619\"><ele>41.6894</ele><time>2007-04-15T09:22:41Z</time></trkpt><trkpt lat=\"48.8517417907715\" lon=\"2.36503648757935\"><ele>41.3541</ele><time>2007-04-15T09:22:42Z</time></trkpt><trkpt lat=\"48.8517646789551\" lon=\"2.36489510536194\"><ele>41.6861</ele><time>2007-04-15T09:22:43Z</time></trkpt><trkpt lat=\"48.8517761230469\" lon=\"2.36478590965271\"><ele>42.0635</ele><time>2007-04-15T09:22:44Z</time></trkpt><trkpt lat=\"48.851749420166\" lon=\"2.3646297454834\"><ele>42.4985</ele><time>2007-04-15T09:22:45Z</time></trkpt><trkpt lat=\"48.8517379760742\" lon=\"2.36440968513489\"><ele>43.2</ele><time>2007-04-15T09:22:46Z</time></trkpt><trkpt lat=\"48.8517074584961\" lon=\"2.36428117752075\"><ele>43.6079</ele><time>2007-04-15T09:22:47Z</time></trkpt><trkpt lat=\"48.8516693115234\" lon=\"2.36409735679626\"><ele>43.9989</ele><time>2007-04-15T09:22:48Z</time></trkpt><trkpt lat=\"48.8516159057617\" lon=\"2.36392855644226\"><ele>43.6954</ele><time>2007-04-15T09:22:49Z</time></trkpt><trkpt lat=\"48.8515663146973\" lon=\"2.3637900352478\"><ele>43.3979</ele><time>2007-04-15T09:22:50Z</time></trkpt><trkpt lat=\"48.8515243530273\" lon=\"2.36362504959106\"><ele>43.1461</ele><time>2007-04-15T09:22:51Z</time></trkpt><trkpt lat=\"48.8514633178711\" lon=\"2.36344838142395\"><ele>42.7799</ele><time>2007-04-15T09:22:52Z</time></trkpt><trkpt lat=\"48.8513984680176\" lon=\"2.36319923400879\"><ele>42.0116</ele><time>2007-04-15T09:22:53Z</time></trkpt><trkpt lat=\"48.8513603210449\" lon=\"2.36303758621216\"><ele>41.3582</ele><time>2007-04-15T09:22:54Z</time></trkpt><trkpt lat=\"48.8512954711914\" lon=\"2.36282539367676\"><ele>40.4873</ele><time>2007-04-15T09:22:55Z</time></trkpt><trkpt lat=\"48.8512496948242\" lon=\"2.36262559890747\"><ele>39.8002</ele><time>2007-04-15T09:22:56Z</time></trkpt><trkpt lat=\"48.8512191772461\" lon=\"2.36249589920044\"><ele>39.3857</ele><time>2007-04-15T09:22:57Z</time></trkpt><trkpt lat=\"48.8512725830078\" lon=\"2.3623628616333\"><ele>39.5213</ele><time>2007-04-15T09:22:58Z</time></trkpt><trkpt lat=\"48.8513145446777\" lon=\"2.36232280731201\"><ele>39.7084</ele><time>2007-04-15T09:22:59Z</time></trkpt><trkpt lat=\"48.8514404296875\" lon=\"2.36219239234924\"><ele>40.4227</ele><time>2007-04-15T09:23:00Z</time></trkpt><trkpt lat=\"48.8515663146973\" lon=\"2.36208319664001\"><ele>41.3379</ele><time>2007-04-15T09:23:01Z</time></trkpt><trkpt lat=\"48.8516693115234\" lon=\"2.36194467544556\"><ele>42.336</ele><time>2007-04-15T09:23:02Z</time></trkpt><trkpt lat=\"48.8516807556152\" lon=\"2.36191582679749\"><ele>42.4189</ele><time>2007-04-15T09:23:03Z</time></trkpt><trkpt lat=\"48.8517799377441\" lon=\"2.36172723770142\"><ele>42.9906</ele><time>2007-04-15T09:23:04Z</time></trkpt><trkpt lat=\"48.8518486022949\" lon=\"2.36158490180969\"><ele>42.924</ele><time>2007-04-15T09:23:05Z</time></trkpt><trkpt lat=\"48.8519477844238\" lon=\"2.36141681671143\"><ele>42.4379</ele><time>2007-04-15T09:23:06Z</time></trkpt><trkpt lat=\"48.8520355224609\" lon=\"2.36120629310608\"><ele>41.7853</ele><time>2007-04-15T09:23:07Z</time></trkpt><trkpt lat=\"48.8521118164062\" lon=\"2.36105704307556\"><ele>41.3395</ele><time>2007-04-15T09:23:08Z</time></trkpt><trkpt lat=\"48.8521995544434\" lon=\"2.3608717918396\"><ele>40.7779</ele><time>2007-04-15T09:23:09Z</time></trkpt><trkpt lat=\"48.8522872924805\" lon=\"2.3606903553009\"><ele>40.314</ele><time>2007-04-15T09:23:10Z</time></trkpt><trkpt lat=\"48.8523178100586\" lon=\"2.36059165000916\"><ele>40.0745</ele><time>2007-04-15T09:23:11Z</time></trkpt><trkpt lat=\"48.8523864746094\" lon=\"2.3603949546814\"><ele>39.6683</ele><time>2007-04-15T09:23:12Z</time></trkpt><trkpt lat=\"48.8524398803711\" lon=\"2.36022114753723\"><ele>39.3526</ele><time>2007-04-15T09:23:13Z</time></trkpt><trkpt lat=\"48.8525199890137\" lon=\"2.36000776290894\"><ele>39.0184</ele><time>2007-04-15T09:23:14Z</time></trkpt><trkpt lat=\"48.8525924682617\" lon=\"2.3598165512085\"><ele>38.5597</ele><time>2007-04-15T09:23:15Z</time></trkpt><trkpt lat=\"48.8526420593262\" lon=\"2.3596465587616\"><ele>38.1517</ele><time>2007-04-15T09:23:16Z</time></trkpt><trkpt lat=\"48.8526992797852\" lon=\"2.35946202278137\"><ele>37.7089</ele><time>2007-04-15T09:23:17Z</time></trkpt><trkpt lat=\"48.8527526855469\" lon=\"2.3593327999115\"><ele>37.3987</ele><time>2007-04-15T09:23:18Z</time></trkpt><trkpt lat=\"48.8528175354004\" lon=\"2.35915064811707\"><ele>36.9881</ele><time>2007-04-15T09:23:19Z</time></trkpt><trkpt lat=\"48.8528480529785\" lon=\"2.35902333259583\"><ele>36.8998</ele><time>2007-04-15T09:23:20Z</time></trkpt><trkpt lat=\"48.8528289794922\" lon=\"2.35888004302978\"><ele>36.7918</ele><time>2007-04-15T09:23:21Z</time></trkpt><trkpt lat=\"48.8528671264648\" lon=\"2.35871505737305\"><ele>36.6968</ele><time>2007-04-15T09:23:22Z</time></trkpt><trkpt lat=\"48.8529357910156\" lon=\"2.35852932929993\"><ele>36.6352</ele><time>2007-04-15T09:23:23Z</time></trkpt><trkpt lat=\"48.8530044555664\" lon=\"2.35832715034485\"><ele>36.6157</ele><time>2007-04-15T09:23:24Z</time></trkpt><trkpt lat=\"48.8530616760254\" lon=\"2.35811996459961\"><ele>37.0135</ele><time>2007-04-15T09:23:25Z</time></trkpt><trkpt lat=\"48.8530693054199\" lon=\"2.35791063308716\"><ele>37.3511</ele><time>2007-04-15T09:23:26Z</time></trkpt><trkpt lat=\"48.853099822998\" lon=\"2.35777235031128\"><ele>37.5816</ele><time>2007-04-15T09:23:27Z</time></trkpt><trkpt lat=\"48.8531074523926\" lon=\"2.35775351524353\"><ele>37.6133</ele><time>2007-04-15T09:23:28Z</time></trkpt><trkpt lat=\"48.8531227111816\" lon=\"2.35774183273315\"><ele>37.6365</ele><time>2007-04-15T09:23:29Z</time></trkpt><trkpt lat=\"48.8531532287598\" lon=\"2.3577184677124\"><ele>37.6812</ele><time>2007-04-15T09:23:30Z</time></trkpt><trkpt lat=\"48.8532257080078\" lon=\"2.35760116577148\"><ele>37.8629</ele><time>2007-04-15T09:23:31Z</time></trkpt><trkpt lat=\"48.8532829284668\" lon=\"2.35738968849182\"><ele>38.1804</ele><time>2007-04-15T09:23:32Z</time></trkpt><trkpt lat=\"48.8533248901367\" lon=\"2.35722422599792\"><ele>38.351</ele><time>2007-04-15T09:23:33Z</time></trkpt><trkpt lat=\"48.8533668518066\" lon=\"2.35709977149963\"><ele>38.5414</ele><time>2007-04-15T09:23:34Z</time></trkpt><trkpt lat=\"48.8534240722656\" lon=\"2.35695362091064\"><ele>38.802</ele><time>2007-04-15T09:23:35Z</time></trkpt><trkpt lat=\"48.8534927368164\" lon=\"2.35678005218506\"><ele>39.0812</ele><time>2007-04-15T09:23:36Z</time></trkpt><trkpt lat=\"48.8535804748535\" lon=\"2.35652112960815\"><ele>38.9473</ele><time>2007-04-15T09:23:37Z</time></trkpt><trkpt lat=\"48.8536071777344\" lon=\"2.35638689994812\"><ele>38.6572</ele><time>2007-04-15T09:23:38Z</time></trkpt><trkpt lat=\"48.853645324707\" lon=\"2.35622215270996\"><ele>38.3076</ele><time>2007-04-15T09:23:39Z</time></trkpt><trkpt lat=\"48.8537063598633\" lon=\"2.35601162910461\"><ele>37.8755</ele><time>2007-04-15T09:23:40Z</time></trkpt><trkpt lat=\"48.8537902832031\" lon=\"2.35574793815613\"><ele>37.6575</ele><time>2007-04-15T09:23:41Z</time></trkpt><trkpt lat=\"48.8538513183594\" lon=\"2.35555624961853\"><ele>37.7565</ele><time>2007-04-15T09:23:42Z</time></trkpt><trkpt lat=\"48.8539085388184\" lon=\"2.355393409729\"><ele>37.5782</ele><time>2007-04-15T09:23:43Z</time></trkpt><trkpt lat=\"48.8539619445801\" lon=\"2.35523056983948\"><ele>37.1836</ele><time>2007-04-15T09:23:44Z</time></trkpt><trkpt lat=\"48.8540344238281\" lon=\"2.35503172874451\"><ele>36.3294</ele><time>2007-04-15T09:23:45Z</time></trkpt><trkpt lat=\"48.8540992736816\" lon=\"2.35483694076538\"><ele>34.8801</ele><time>2007-04-15T09:23:46Z</time></trkpt><trkpt lat=\"48.854190826416\" lon=\"2.35463809967041\"><ele>33.467</ele><time>2007-04-15T09:23:47Z</time></trkpt><trkpt lat=\"48.8542556762695\" lon=\"2.35448813438416\"><ele>33.4295</ele><time>2007-04-15T09:23:48Z</time></trkpt><trkpt lat=\"48.8543319702148\" lon=\"2.35431170463562\"><ele>33.6365</ele><time>2007-04-15T09:23:49Z</time></trkpt><trkpt lat=\"48.8544158935547\" lon=\"2.35413217544556\"><ele>34.0538</ele><time>2007-04-15T09:23:50Z</time></trkpt><trkpt lat=\"48.8544731140137\" lon=\"2.35396838188171\"><ele>33.705</ele><time>2007-04-15T09:23:51Z</time></trkpt><trkpt lat=\"48.8545341491699\" lon=\"2.353835105896\"><ele>33.639</ele><time>2007-04-15T09:23:52Z</time></trkpt><trkpt lat=\"48.8545989990234\" lon=\"2.35370087623596\"><ele>33.6431</ele><time>2007-04-15T09:23:53Z</time></trkpt><trkpt lat=\"48.8546600341797\" lon=\"2.35356187820435\"><ele>33.5876</ele><time>2007-04-15T09:23:54Z</time></trkpt><trkpt lat=\"48.8547782897949\" lon=\"2.35329174995422\"><ele>33.4645</ele><time>2007-04-15T09:23:55Z</time></trkpt><trkpt lat=\"48.854850769043\" lon=\"2.35313439369202\"><ele>33.0445</ele><time>2007-04-15T09:23:56Z</time></trkpt><trkpt lat=\"48.8549499511719\" lon=\"2.35296869277954\"><ele>32.5514</ele><time>2007-04-15T09:23:57Z</time></trkpt><trkpt lat=\"48.8550071716309\" lon=\"2.35282278060913\"><ele>31.5812</ele><time>2007-04-15T09:23:58Z</time></trkpt><trkpt lat=\"48.8550720214844\" lon=\"2.35267019271851\"><ele>30.8734</ele><time>2007-04-15T09:23:59Z</time></trkpt><trkpt lat=\"48.8551406860352\" lon=\"2.35249423980713\"><ele>30.1957</ele><time>2007-04-15T09:24:00Z</time></trkpt><trkpt lat=\"48.8552017211914\" lon=\"2.35233116149902\"><ele>31.0126</ele><time>2007-04-15T09:24:01Z</time></trkpt><trkpt lat=\"48.8552055358887\" lon=\"2.35229992866516\"><ele>31.0352</ele><time>2007-04-15T09:24:02Z</time></trkpt><trkpt lat=\"48.8552513122559\" lon=\"2.35217046737671\"><ele>31.3996</ele><time>2007-04-15T09:24:03Z</time></trkpt><trkpt lat=\"48.8553199768066\" lon=\"2.35193800926208\"><ele>31.492</ele><time>2007-04-15T09:24:04Z</time></trkpt><trkpt lat=\"48.8553924560547\" lon=\"2.35175108909607\"><ele>31.2641</ele><time>2007-04-15T09:24:05Z</time></trkpt><trkpt lat=\"48.8554573059082\" lon=\"2.35158395767212\"><ele>31.1677</ele><time>2007-04-15T09:24:06Z</time></trkpt><trkpt lat=\"48.8555679321289\" lon=\"2.35136842727661\"><ele>31.3311</ele><time>2007-04-15T09:24:07Z</time></trkpt><trkpt lat=\"48.8556823730469\" lon=\"2.35121011734009\"><ele>31.1375</ele><time>2007-04-15T09:24:08Z</time></trkpt><trkpt lat=\"48.8557929992676\" lon=\"2.3510570526123\"><ele>30.6526</ele><time>2007-04-15T09:24:09Z</time></trkpt><trkpt lat=\"48.8558616638184\" lon=\"2.35091710090637\"><ele>30.439</ele><time>2007-04-15T09:24:10Z</time></trkpt><trkpt lat=\"48.8558807373047\" lon=\"2.35089159011841\"><ele>30.538</ele><time>2007-04-15T09:24:11Z</time></trkpt><trkpt lat=\"48.8558883666992\" lon=\"2.35085272789001\"><ele>30.5088</ele><time>2007-04-15T09:24:12Z</time></trkpt><trkpt lat=\"48.8559341430664\" lon=\"2.35061883926392\"><ele>32.1026</ele><time>2007-04-15T09:24:13Z</time></trkpt><trkpt lat=\"48.8559608459473\" lon=\"2.35043430328369\"><ele>33.392</ele><time>2007-04-15T09:24:14Z</time></trkpt><trkpt lat=\"48.8560028076172\" lon=\"2.35027360916138\"><ele>34.6453</ele><time>2007-04-15T09:24:15Z</time></trkpt><trkpt lat=\"48.8560523986816\" lon=\"2.35010361671448\"><ele>35.9883</ele><time>2007-04-15T09:24:16Z</time></trkpt><trkpt lat=\"48.8561096191406\" lon=\"2.34993529319763\"><ele>37.637</ele><time>2007-04-15T09:24:17Z</time></trkpt><trkpt lat=\"48.8561210632324\" lon=\"2.34990525245666\"><ele>38.0123</ele><time>2007-04-15T09:24:18Z</time></trkpt><trkpt lat=\"48.8561973571777\" lon=\"2.3497166633606\"><ele>40.2784</ele><time>2007-04-15T09:24:19Z</time></trkpt><trkpt lat=\"48.8562698364258\" lon=\"2.34952354431152\"><ele>42.3629</ele><time>2007-04-15T09:24:20Z</time></trkpt><trkpt lat=\"48.8563499450684\" lon=\"2.34933423995972\"><ele>44.2324</ele><time>2007-04-15T09:24:21Z</time></trkpt><trkpt lat=\"48.8564147949219\" lon=\"2.3491792678833\"><ele>45.5993</ele><time>2007-04-15T09:24:22Z</time></trkpt><trkpt lat=\"48.8564872741699\" lon=\"2.34897017478943\"><ele>45.6472</ele><time>2007-04-15T09:24:23Z</time></trkpt><trkpt lat=\"48.8564987182617\" lon=\"2.34875345230103\"><ele>45.591</ele><time>2007-04-15T09:24:24Z</time></trkpt><trkpt lat=\"48.856502532959\" lon=\"2.34873533248901\"><ele>45.6149</ele><time>2007-04-15T09:24:25Z</time></trkpt><trkpt lat=\"48.856502532959\" lon=\"2.34869885444641\"><ele>45.599</ele><time>2007-04-15T09:24:26Z</time></trkpt><trkpt lat=\"48.856502532959\" lon=\"2.34863567352295\"><ele>45.5714</ele><time>2007-04-15T09:24:27Z</time></trkpt><trkpt lat=\"48.8565788269043\" lon=\"2.34843897819519\"><ele>46.5365</ele><time>2007-04-15T09:24:28Z</time></trkpt><trkpt lat=\"48.8566360473633\" lon=\"2.34832811355591\"><ele>47.4801</ele><time>2007-04-15T09:24:29Z</time></trkpt><trkpt lat=\"48.8567047119141\" lon=\"2.34814929962158\"><ele>46.0883</ele><time>2007-04-15T09:24:30Z</time></trkpt><trkpt lat=\"48.8567581176758\" lon=\"2.34794998168945\"><ele>44.1368</ele><time>2007-04-15T09:24:31Z</time></trkpt><trkpt lat=\"48.8568115234375\" lon=\"2.34778618812561\"><ele>42.6929</ele><time>2007-04-15T09:24:32Z</time></trkpt><trkpt lat=\"48.8568572998047\" lon=\"2.3476619720459\"><ele>41.7316</ele><time>2007-04-15T09:24:33Z</time></trkpt><trkpt lat=\"48.8569068908691\" lon=\"2.347501039505\"><ele>40.7172</ele><time>2007-04-15T09:24:34Z</time></trkpt><trkpt lat=\"48.8569641113281\" lon=\"2.34729957580566\"><ele>40.3855</ele><time>2007-04-15T09:24:35Z</time></trkpt><trkpt lat=\"48.8569984436035\" lon=\"2.34712815284729\"><ele>40.0689</ele><time>2007-04-15T09:24:36Z</time></trkpt><trkpt lat=\"48.8570175170898\" lon=\"2.34689927101135\"><ele>39.6685</ele><time>2007-04-15T09:24:37Z</time></trkpt><trkpt lat=\"48.8570594787598\" lon=\"2.34670400619507\"><ele>39.1779</ele><time>2007-04-15T09:24:38Z</time></trkpt><trkpt lat=\"48.8571319580078\" lon=\"2.34654235839844\"><ele>40.0258</ele><time>2007-04-15T09:24:39Z</time></trkpt><trkpt lat=\"48.8571929931641\" lon=\"2.34635806083679\"><ele>41.5727</ele><time>2007-04-15T09:24:40Z</time></trkpt><trkpt lat=\"48.8572540283203\" lon=\"2.34620094299316\"><ele>42.8166</ele><time>2007-04-15T09:24:41Z</time></trkpt><trkpt lat=\"48.8573188781738\" lon=\"2.34601187705994\"><ele>44.3261</ele><time>2007-04-15T09:24:42Z</time></trkpt><trkpt lat=\"48.8573684692383\" lon=\"2.34581208229065\"><ele>45.6738</ele><time>2007-04-15T09:24:43Z</time></trkpt><trkpt lat=\"48.8574333190918\" lon=\"2.34561395645142\"><ele>44.147</ele><time>2007-04-15T09:24:44Z</time></trkpt><trkpt lat=\"48.8574752807617\" lon=\"2.34544515609741\"><ele>42.8607</ele><time>2007-04-15T09:24:45Z</time></trkpt><trkpt lat=\"48.8575248718262\" lon=\"2.34524202346802\"><ele>41.6736</ele><time>2007-04-15T09:24:46Z</time></trkpt><trkpt lat=\"48.8575897216797\" lon=\"2.3450038433075\"><ele>40.8834</ele><time>2007-04-15T09:24:47Z</time></trkpt><trkpt lat=\"48.8576507568359\" lon=\"2.34480690956116\"><ele>41.5951</ele><time>2007-04-15T09:24:48Z</time></trkpt><trkpt lat=\"48.8577079772949\" lon=\"2.3446090221405\"><ele>42.2316</ele><time>2007-04-15T09:24:49Z</time></trkpt><trkpt lat=\"48.8577537536621\" lon=\"2.34443712234497\"><ele>42.7001</ele><time>2007-04-15T09:24:50Z</time></trkpt><trkpt lat=\"48.8578186035156\" lon=\"2.34420275688171\"><ele>43.2838</ele><time>2007-04-15T09:24:51Z</time></trkpt><trkpt lat=\"48.8578758239746\" lon=\"2.34400987625122\"><ele>44.5065</ele><time>2007-04-15T09:24:52Z</time></trkpt><trkpt lat=\"48.8579406738281\" lon=\"2.34382128715515\"><ele>46.0976</ele><time>2007-04-15T09:24:53Z</time></trkpt><trkpt lat=\"48.8579940795898\" lon=\"2.34365725517273\"><ele>47.5921</ele><time>2007-04-15T09:24:54Z</time></trkpt><trkpt lat=\"48.8580474853516\" lon=\"2.34345865249634\"><ele>49.432</ele><time>2007-04-15T09:24:55Z</time></trkpt><trkpt lat=\"48.8580932617188\" lon=\"2.34327006340027\"><ele>51.3291</ele><time>2007-04-15T09:24:56Z</time></trkpt><trkpt lat=\"48.8581390380859\" lon=\"2.34307837486267\"><ele>53.5262</ele><time>2007-04-15T09:24:57Z</time></trkpt><trkpt lat=\"48.8581924438477\" lon=\"2.34287786483765\"><ele>56.0507</ele><time>2007-04-15T09:24:58Z</time></trkpt><trkpt lat=\"48.8582382202148\" lon=\"2.3427095413208\"><ele>58.3057</ele><time>2007-04-15T09:24:59Z</time></trkpt><trkpt lat=\"48.858283996582\" lon=\"2.34254503250122\"><ele>60.6364</ele><time>2007-04-15T09:25:00Z</time></trkpt><trkpt lat=\"48.8583297729492\" lon=\"2.34234714508057\"><ele>61.0169</ele><time>2007-04-15T09:25:01Z</time></trkpt><trkpt lat=\"48.8583984375\" lon=\"2.34222793579102\"><ele>59.7681</ele><time>2007-04-15T09:25:02Z</time></trkpt><trkpt lat=\"48.8584213256836\" lon=\"2.34201574325562\"><ele>58.3111</ele><time>2007-04-15T09:25:03Z</time></trkpt><trkpt lat=\"48.8584594726562\" lon=\"2.34181094169617\"><ele>56.7799</ele><time>2007-04-15T09:25:04Z</time></trkpt><trkpt lat=\"48.8585014343262\" lon=\"2.34158229827881\"><ele>54.3552</ele><time>2007-04-15T09:25:05Z</time></trkpt><trkpt lat=\"48.858528137207\" lon=\"2.34141993522644\"><ele>51.8915</ele><time>2007-04-15T09:25:06Z</time></trkpt><trkpt lat=\"48.8585586547852\" lon=\"2.34121155738831\"><ele>48.9827</ele><time>2007-04-15T09:25:07Z</time></trkpt><trkpt lat=\"48.8585929870606\" lon=\"2.34100341796875\"><ele>46.3523</ele><time>2007-04-15T09:25:08Z</time></trkpt><trkpt lat=\"48.8586273193359\" lon=\"2.34082937240601\"><ele>44.4384</ele><time>2007-04-15T09:25:09Z</time></trkpt><trkpt lat=\"48.8586540222168\" lon=\"2.340651512146\"><ele>43.3179</ele><time>2007-04-15T09:25:10Z</time></trkpt><trkpt lat=\"48.8587112426758\" lon=\"2.34042286872864\"><ele>42.305</ele><time>2007-04-15T09:25:11Z</time></trkpt><trkpt lat=\"48.858757019043\" lon=\"2.34026145935059\"><ele>41.8251</ele><time>2007-04-15T09:25:12Z</time></trkpt><trkpt lat=\"48.858814239502\" lon=\"2.34010553359985\"><ele>41.7074</ele><time>2007-04-15T09:25:13Z</time></trkpt><trkpt lat=\"48.8588371276856\" lon=\"2.3398904800415\"><ele>40.7272</ele><time>2007-04-15T09:25:14Z</time></trkpt><trkpt lat=\"48.8588256835938\" lon=\"2.33982920646667\"><ele>40.1256</ele><time>2007-04-15T09:25:15Z</time></trkpt><trkpt lat=\"48.8588333129883\" lon=\"2.33979630470276\"><ele>40.0308</ele><time>2007-04-15T09:25:16Z</time></trkpt><trkpt lat=\"48.8612937927246\" lon=\"2.3289110660553\"><ele>34.08</ele><time>2007-04-15T09:25:17Z</time></trkpt><trkpt lat=\"48.861255645752\" lon=\"2.32875299453735\"><ele>33.0617</ele><time>2007-04-15T09:25:18Z</time></trkpt><trkpt lat=\"48.861270904541\" lon=\"2.32874250411987\"><ele>33.141</ele><time>2007-04-15T09:25:19Z</time></trkpt><trkpt lat=\"48.8613777160644\" lon=\"2.32864713668823\"><ele>33.6926</ele><time>2007-04-15T09:25:20Z</time></trkpt><trkpt lat=\"48.8614349365234\" lon=\"2.32855176925659\"><ele>33.9187</ele><time>2007-04-15T09:25:21Z</time></trkpt><trkpt lat=\"48.861499786377\" lon=\"2.32840895652771\"><ele>34.1972</ele><time>2007-04-15T09:25:22Z</time></trkpt><trkpt lat=\"48.8615608215332\" lon=\"2.32828974723816\"><ele>34.5539</ele><time>2007-04-15T09:25:23Z</time></trkpt><trkpt lat=\"48.861572265625\" lon=\"2.32827162742615\"><ele>34.6129</ele><time>2007-04-15T09:25:24Z</time></trkpt><trkpt lat=\"48.861629486084\" lon=\"2.3281307220459\"><ele>34.6355</ele><time>2007-04-15T09:25:25Z</time></trkpt><trkpt lat=\"48.8616676330566\" lon=\"2.32804822921753\"><ele>34.6242</ele><time>2007-04-15T09:25:26Z</time></trkpt><trkpt lat=\"48.8616943359375\" lon=\"2.32794284820557\"><ele>33.9513</ele><time>2007-04-15T09:25:27Z</time></trkpt><trkpt lat=\"48.8617630004883\" lon=\"2.32772397994995\"><ele>32.7109</ele><time>2007-04-15T09:25:28Z</time></trkpt><trkpt lat=\"48.8618240356445\" lon=\"2.32753777503967\"><ele>31.924</ele><time>2007-04-15T09:25:29Z</time></trkpt><trkpt lat=\"48.861873626709\" lon=\"2.32738327980042\"><ele>31.5054</ele><time>2007-04-15T09:25:30Z</time></trkpt><trkpt lat=\"48.861930847168\" lon=\"2.32722187042236\"><ele>31.2107</ele><time>2007-04-15T09:25:31Z</time></trkpt><trkpt lat=\"48.8619842529297\" lon=\"2.32702684402466\"><ele>30.9975</ele><time>2007-04-15T09:25:32Z</time></trkpt><trkpt lat=\"48.8620452880859\" lon=\"2.32683515548706\"><ele>30.9646</ele><time>2007-04-15T09:25:33Z</time></trkpt><trkpt lat=\"48.8621101379394\" lon=\"2.32664942741394\"><ele>31.1163</ele><time>2007-04-15T09:25:34Z</time></trkpt><trkpt lat=\"48.862133026123\" lon=\"2.32655715942383\"><ele>31.1493</ele><time>2007-04-15T09:25:35Z</time></trkpt><trkpt lat=\"48.8621482849121\" lon=\"2.32649850845337\"><ele>31.1637</ele><time>2007-04-15T09:25:36Z</time></trkpt><trkpt lat=\"48.8622055053711\" lon=\"2.32630896568298\"><ele>31.183</ele><time>2007-04-15T09:25:37Z</time></trkpt><trkpt lat=\"48.8622550964356\" lon=\"2.32614064216614\"><ele>31.1185</ele><time>2007-04-15T09:25:38Z</time></trkpt><trkpt lat=\"48.8623123168945\" lon=\"2.32598447799683\"><ele>31.015</ele><time>2007-04-15T09:25:39Z</time></trkpt><trkpt lat=\"48.8624076843262\" lon=\"2.32574343681335\"><ele>30.6854</ele><time>2007-04-15T09:25:40Z</time></trkpt><trkpt lat=\"48.8624801635742\" lon=\"2.3255672454834\"><ele>30.3452</ele><time>2007-04-15T09:25:41Z</time></trkpt><trkpt lat=\"48.8625373840332\" lon=\"2.32542061805725\"><ele>30.1214</ele><time>2007-04-15T09:25:42Z</time></trkpt><trkpt lat=\"48.8625869750977\" lon=\"2.32525539398193\"><ele>29.8941</ele><time>2007-04-15T09:25:43Z</time></trkpt><trkpt lat=\"48.8626403808594\" lon=\"2.32505321502686\"><ele>29.6223</ele><time>2007-04-15T09:25:44Z</time></trkpt><trkpt lat=\"48.8627052307129\" lon=\"2.32485127449036\"><ele>29.4698</ele><time>2007-04-15T09:25:45Z</time></trkpt><trkpt lat=\"48.8627586364746\" lon=\"2.32469296455383\"><ele>29.4229</ele><time>2007-04-15T09:25:46Z</time></trkpt><trkpt lat=\"48.8628082275391\" lon=\"2.32453536987305\"><ele>29.407</ele><time>2007-04-15T09:25:47Z</time></trkpt><trkpt lat=\"48.8628845214844\" lon=\"2.32431244850159\"><ele>29.4956</ele><time>2007-04-15T09:25:48Z</time></trkpt><trkpt lat=\"48.8629379272461\" lon=\"2.32411217689514\"><ele>29.6896</ele><time>2007-04-15T09:25:49Z</time></trkpt><trkpt lat=\"48.8629913330078\" lon=\"2.32390952110291\"><ele>30.2013</ele><time>2007-04-15T09:25:50Z</time></trkpt><trkpt lat=\"48.8630599975586\" lon=\"2.32371735572815\"><ele>30.7137</ele><time>2007-04-15T09:25:51Z</time></trkpt><trkpt lat=\"48.8631134033203\" lon=\"2.32354736328125\"><ele>31.0727</ele><time>2007-04-15T09:25:52Z</time></trkpt><trkpt lat=\"48.8631744384766\" lon=\"2.32335042953491\"><ele>31.4202</ele><time>2007-04-15T09:25:53Z</time></trkpt><trkpt lat=\"48.8632316589356\" lon=\"2.3231520652771\"><ele>31.825</ele><time>2007-04-15T09:25:54Z</time></trkpt><trkpt lat=\"48.8632926940918\" lon=\"2.32293105125427\"><ele>32.3129</ele><time>2007-04-15T09:25:55Z</time></trkpt><trkpt lat=\"48.8633499145508\" lon=\"2.32273697853088\"><ele>32.8237</ele><time>2007-04-15T09:25:56Z</time></trkpt><trkpt lat=\"48.8634071350098\" lon=\"2.3225691318512\"><ele>33.4337</ele><time>2007-04-15T09:25:57Z</time></trkpt><trkpt lat=\"48.8634605407715\" lon=\"2.32247376441956\"><ele>33.7948</ele><time>2007-04-15T09:25:58Z</time></trkpt><trkpt lat=\"48.8634719848633\" lon=\"2.32245588302612\"><ele>33.7953</ele><time>2007-04-15T09:25:59Z</time></trkpt><trkpt lat=\"48.8634757995606\" lon=\"2.32244372367859\"><ele>33.7672</ele><time>2007-04-15T09:26:00Z</time></trkpt><trkpt lat=\"48.8635025024414\" lon=\"2.32230830192566\"><ele>33.3446</ele><time>2007-04-15T09:26:01Z</time></trkpt><trkpt lat=\"48.863525390625\" lon=\"2.32225894927978\"><ele>33.2924</ele><time>2007-04-15T09:26:02Z</time></trkpt><trkpt lat=\"48.8635368347168\" lon=\"2.32221150398254\"><ele>33.165</ele><time>2007-04-15T09:26:03Z</time></trkpt><trkpt lat=\"48.8635940551758\" lon=\"2.32198643684387\"><ele>32.6049</ele><time>2007-04-15T09:26:04Z</time></trkpt><trkpt lat=\"48.863655090332\" lon=\"2.32184290885925\"><ele>32.4671</ele><time>2007-04-15T09:26:05Z</time></trkpt><trkpt lat=\"48.8636894226074\" lon=\"2.32168889045715\"><ele>32.0864</ele><time>2007-04-15T09:26:06Z</time></trkpt><trkpt lat=\"48.8637580871582\" lon=\"2.32145762443542\"><ele>32.0614</ele><time>2007-04-15T09:26:07Z</time></trkpt><trkpt lat=\"48.8638191223144\" lon=\"2.3212993144989\"><ele>32.1259</ele><time>2007-04-15T09:26:08Z</time></trkpt><trkpt lat=\"48.8638954162598\" lon=\"2.32108497619629\"><ele>32.0818</ele><time>2007-04-15T09:26:09Z</time></trkpt><trkpt lat=\"48.8639640808106\" lon=\"2.32086420059204\"><ele>31.8776</ele><time>2007-04-15T09:26:10Z</time></trkpt><trkpt lat=\"48.864013671875\" lon=\"2.32068061828613\"><ele>31.6332</ele><time>2007-04-15T09:26:11Z</time></trkpt><trkpt lat=\"48.8640747070312\" lon=\"2.32050275802612\"><ele>31.3895</ele><time>2007-04-15T09:26:12Z</time></trkpt><trkpt lat=\"48.8641548156738\" lon=\"2.3203010559082\"><ele>31.0399</ele><time>2007-04-15T09:26:13Z</time></trkpt><trkpt lat=\"48.864200592041\" lon=\"2.3200786113739\"><ele>30.3606</ele><time>2007-04-15T09:26:14Z</time></trkpt><trkpt lat=\"48.8642120361328\" lon=\"2.32005524635315\"><ele>30.3042</ele><time>2007-04-15T09:26:15Z</time></trkpt><trkpt lat=\"48.8643569946289\" lon=\"2.31975173950195\"><ele>29.6991</ele><time>2007-04-15T09:26:16Z</time></trkpt><trkpt lat=\"48.8643684387207\" lon=\"2.31974530220032\"><ele>29.7153</ele><time>2007-04-15T09:26:17Z</time></trkpt><trkpt lat=\"48.8643836975098\" lon=\"2.31963443756104\"><ele>29.4333</ele><time>2007-04-15T09:26:18Z</time></trkpt><trkpt lat=\"48.864444732666\" lon=\"2.3194591999054\"><ele>29.1536</ele><time>2007-04-15T09:26:19Z</time></trkpt><trkpt lat=\"48.8644828796387\" lon=\"2.31935286521912\"><ele>29.0186</ele><time>2007-04-15T09:26:20Z</time></trkpt><trkpt lat=\"48.8645286560059\" lon=\"2.31922435760498\"><ele>28.8851</ele><time>2007-04-15T09:26:21Z</time></trkpt><trkpt lat=\"48.8645706176758\" lon=\"2.31903314590454\"><ele>29.6673</ele><time>2007-04-15T09:26:22Z</time></trkpt><trkpt lat=\"48.8646392822266\" lon=\"2.31882810592651\"><ele>31.015</ele><time>2007-04-15T09:26:23Z</time></trkpt><trkpt lat=\"48.8646850585938\" lon=\"2.31872987747192\"><ele>31.655</ele><time>2007-04-15T09:26:24Z</time></trkpt><trkpt lat=\"48.8647422790527\" lon=\"2.31856274604797\"><ele>32.6094</ele><time>2007-04-15T09:26:25Z</time></trkpt><trkpt lat=\"48.8648071289062\" lon=\"2.3183753490448\"><ele>33.5823</ele><time>2007-04-15T09:26:26Z</time></trkpt><trkpt lat=\"48.8648529052734\" lon=\"2.31816124916077\"><ele>34.1151</ele><time>2007-04-15T09:26:27Z</time></trkpt><trkpt lat=\"48.8648681640625\" lon=\"2.31798005104065\"><ele>34.3783</ele><time>2007-04-15T09:26:28Z</time></trkpt><trkpt lat=\"48.8648681640625\" lon=\"2.31793165206909\"><ele>34.4519</ele><time>2007-04-15T09:26:29Z</time></trkpt><trkpt lat=\"48.8648681640625\" lon=\"2.31768822669983\"><ele>34.8216</ele><time>2007-04-15T09:26:30Z</time></trkpt><trkpt lat=\"48.8648719787598\" lon=\"2.31741666793823\"><ele>34.4218</ele><time>2007-04-15T09:26:31Z</time></trkpt><trkpt lat=\"48.8648719787598\" lon=\"2.31717729568481\"><ele>32.5442</ele><time>2007-04-15T09:26:32Z</time></trkpt><trkpt lat=\"48.8648681640625\" lon=\"2.316890001297\"><ele>30.2894</ele><time>2007-04-15T09:26:33Z</time></trkpt><trkpt lat=\"48.8648529052734\" lon=\"2.31671833992004\"><ele>28.89</ele><time>2007-04-15T09:26:34Z</time></trkpt><trkpt lat=\"48.8648529052734\" lon=\"2.31651663780212\"><ele>29.36</ele><time>2007-04-15T09:26:35Z</time></trkpt><trkpt lat=\"48.8648529052734\" lon=\"2.31632328033447\"><ele>30.5064</ele><time>2007-04-15T09:26:36Z</time></trkpt><trkpt lat=\"48.8648338317871\" lon=\"2.31613302230835\"><ele>31.4779</ele><time>2007-04-15T09:26:37Z</time></trkpt><trkpt lat=\"48.8648262023926\" lon=\"2.3159544467926\"><ele>32.4328</ele><time>2007-04-15T09:26:38Z</time></trkpt><trkpt lat=\"48.864803314209\" lon=\"2.31572699546814\"><ele>33.8435</ele><time>2007-04-15T09:26:39Z</time></trkpt><trkpt lat=\"48.8648109436035\" lon=\"2.31555318832397\"><ele>35.5262</ele><time>2007-04-15T09:26:40Z</time></trkpt><trkpt lat=\"48.8648071289062\" lon=\"2.31536030769348\"><ele>37.2374</ele><time>2007-04-15T09:26:41Z</time></trkpt><trkpt lat=\"48.864803314209\" lon=\"2.31513476371765\"><ele>39.2332</ele><time>2007-04-15T09:26:42Z</time></trkpt><trkpt lat=\"48.8648223876953\" lon=\"2.31495428085327\"><ele>40.5125</ele><time>2007-04-15T09:26:43Z</time></trkpt><trkpt lat=\"48.8648300170898\" lon=\"2.31476330757141\"><ele>39.4156</ele><time>2007-04-15T09:26:44Z</time></trkpt><trkpt lat=\"48.864818572998\" lon=\"2.31451606750488\"><ele>37.6807</ele><time>2007-04-15T09:26:45Z</time></trkpt><trkpt lat=\"48.8648109436035\" lon=\"2.31421995162964\"><ele>35.7435</ele><time>2007-04-15T09:26:46Z</time></trkpt><trkpt lat=\"48.8648071289062\" lon=\"2.314124584198\"><ele>35.6361</ele><time>2007-04-15T09:26:47Z</time></trkpt><trkpt lat=\"48.8647956848144\" lon=\"2.31413316726685\"><ele>35.4855</ele><time>2007-04-15T09:26:48Z</time></trkpt><trkpt lat=\"48.8647956848144\" lon=\"2.31409382820129\"><ele>35.7225</ele><time>2007-04-15T09:26:49Z</time></trkpt><trkpt lat=\"48.8648338317871\" lon=\"2.30936908721924\"><ele>38.8066</ele><time>2007-04-15T09:26:50Z</time></trkpt><trkpt lat=\"48.8648414611816\" lon=\"2.30929398536682\"><ele>38.9073</ele><time>2007-04-15T09:26:51Z</time></trkpt><trkpt lat=\"48.8648681640625\" lon=\"2.30930638313293\"><ele>39.2598</ele><time>2007-04-15T09:26:52Z</time></trkpt><trkpt lat=\"48.8649215698242\" lon=\"2.30933594703674\"><ele>39.9647</ele><time>2007-04-15T09:26:53Z</time></trkpt><trkpt lat=\"48.8648910522461\" lon=\"2.30925869941711\"><ele>39.5619</ele><time>2007-04-15T09:26:54Z</time></trkpt><trkpt lat=\"48.8648338317871\" lon=\"2.30915331840515\"><ele>38.813</ele><time>2007-04-15T09:26:55Z</time></trkpt><trkpt lat=\"48.8648109436035\" lon=\"2.30904006958008\"><ele>38.5734</ele><time>2007-04-15T09:26:56Z</time></trkpt><trkpt lat=\"48.8647804260254\" lon=\"2.30892825126648\"><ele>38.2524</ele><time>2007-04-15T09:26:57Z</time></trkpt><trkpt lat=\"48.8647384643555\" lon=\"2.30880331993103\"><ele>37.8214</ele><time>2007-04-15T09:26:58Z</time></trkpt><trkpt lat=\"48.8647346496582\" lon=\"2.30878186225891\"><ele>37.7914</ele><time>2007-04-15T09:26:59Z</time></trkpt><trkpt lat=\"48.8647308349609\" lon=\"2.30861830711365\"><ele>37.8721</ele><time>2007-04-15T09:27:00Z</time></trkpt><trkpt lat=\"48.8646965026856\" lon=\"2.30840802192688\"><ele>37.6569</ele><time>2007-04-15T09:27:01Z</time></trkpt><trkpt lat=\"48.8646812438965\" lon=\"2.308269739151\"><ele>37.6517</ele><time>2007-04-15T09:27:02Z</time></trkpt><trkpt lat=\"48.8646774291992\" lon=\"2.3080952167511\"><ele>37.8665</ele><time>2007-04-15T09:27:03Z</time></trkpt><trkpt lat=\"48.8646697998047\" lon=\"2.30796265602112\"><ele>37.971</ele><time>2007-04-15T09:27:04Z</time></trkpt><trkpt lat=\"48.8646621704102\" lon=\"2.30779957771301\"><ele>38.1131</ele><time>2007-04-15T09:27:05Z</time></trkpt><trkpt lat=\"48.8646621704102\" lon=\"2.30776381492615\"><ele>38.1642</ele><time>2007-04-15T09:27:06Z</time></trkpt><trkpt lat=\"48.864688873291\" lon=\"2.30750322341919\"><ele>38.8883</ele><time>2007-04-15T09:27:07Z</time></trkpt><trkpt lat=\"48.8646850585938\" lon=\"2.30739116668701\"><ele>39.3477</ele><time>2007-04-15T09:27:08Z</time></trkpt><trkpt lat=\"48.8646659851074\" lon=\"2.30722904205322\"><ele>39.8258</ele><time>2007-04-15T09:27:09Z</time></trkpt><trkpt lat=\"48.8646621704102\" lon=\"2.30704522132874\"><ele>40.6056</ele><time>2007-04-15T09:27:10Z</time></trkpt><trkpt lat=\"48.8646621704102\" lon=\"2.30684900283813\"><ele>41.4966</ele><time>2007-04-15T09:27:11Z</time></trkpt><trkpt lat=\"48.8646812438965\" lon=\"2.30666923522949\"><ele>42.633</ele><time>2007-04-15T09:27:12Z</time></trkpt><trkpt lat=\"48.8646774291992\" lon=\"2.30650091171265\"><ele>41.8173</ele><time>2007-04-15T09:27:13Z</time></trkpt><trkpt lat=\"48.8647079467773\" lon=\"2.30633187294006\"><ele>41.5071</ele><time>2007-04-15T09:27:14Z</time></trkpt><trkpt lat=\"48.8647079467773\" lon=\"2.30616784095764\"><ele>40.7299</ele><time>2007-04-15T09:27:15Z</time></trkpt><trkpt lat=\"48.8647155761719\" lon=\"2.30596518516541\"><ele>39.8747</ele><time>2007-04-15T09:27:16Z</time></trkpt><trkpt lat=\"48.8647079467773\" lon=\"2.30579304695129\"><ele>39.1594</ele><time>2007-04-15T09:27:17Z</time></trkpt><trkpt lat=\"48.8646812438965\" lon=\"2.30551385879517\"><ele>38.8825</ele><time>2007-04-15T09:27:18Z</time></trkpt><trkpt lat=\"48.8646583557129\" lon=\"2.30531096458435\"><ele>38.6032</ele><time>2007-04-15T09:27:19Z</time></trkpt><trkpt lat=\"48.8646469116211\" lon=\"2.3050901889801\"><ele>38.4753</ele><time>2007-04-15T09:27:20Z</time></trkpt><trkpt lat=\"48.8646240234375\" lon=\"2.30491375923157\"><ele>38.2281</ele><time>2007-04-15T09:27:21Z</time></trkpt><trkpt lat=\"48.8646049499512\" lon=\"2.30470848083496\"><ele>38.1689</ele><time>2007-04-15T09:27:22Z</time></trkpt><trkpt lat=\"48.8646049499512\" lon=\"2.30446124076843\"><ele>38.4502</ele><time>2007-04-15T09:27:23Z</time></trkpt><trkpt lat=\"48.864616394043\" lon=\"2.30424237251282\"><ele>38.8528</ele><time>2007-04-15T09:27:24Z</time></trkpt><trkpt lat=\"48.8646202087402\" lon=\"2.30407929420471\"><ele>38.6537</ele><time>2007-04-15T09:27:25Z</time></trkpt><trkpt lat=\"48.864616394043\" lon=\"2.30386471748352\"><ele>37.7919</ele><time>2007-04-15T09:27:26Z</time></trkpt><trkpt lat=\"48.864616394043\" lon=\"2.30362415313721\"><ele>36.88</ele><time>2007-04-15T09:27:27Z</time></trkpt><trkpt lat=\"48.8646087646484\" lon=\"2.30345773696899\"><ele>36.1797</ele><time>2007-04-15T09:27:28Z</time></trkpt><trkpt lat=\"48.8645820617676\" lon=\"2.30321741104126\"><ele>35.488</ele><time>2007-04-15T09:27:29Z</time></trkpt><trkpt lat=\"48.8645401000977\" lon=\"2.30304360389709\"><ele>35.0286</ele><time>2007-04-15T09:27:30Z</time></trkpt><trkpt lat=\"48.864501953125\" lon=\"2.30286288261414\"><ele>34.4856</ele><time>2007-04-15T09:27:31Z</time></trkpt><trkpt lat=\"48.8644599914551\" lon=\"2.30267477035522\"><ele>33.7621</ele><time>2007-04-15T09:27:32Z</time></trkpt><trkpt lat=\"48.8644561767578\" lon=\"2.3026614189148\"><ele>33.6937</ele><time>2007-04-15T09:27:33Z</time></trkpt><trkpt lat=\"48.8644523620606\" lon=\"2.30262923240662\"><ele>33.6031</ele><time>2007-04-15T09:27:34Z</time></trkpt><trkpt lat=\"48.8643798828125\" lon=\"2.30078840255737\"><ele>40.1713</ele><time>2007-04-15T09:27:35Z</time></trkpt><trkpt lat=\"48.864315032959\" lon=\"2.30073523521423\"><ele>39.8891</ele><time>2007-04-15T09:27:36Z</time></trkpt><trkpt lat=\"48.8641586303711\" lon=\"2.3005256652832\"><ele>41.08</ele><time>2007-04-15T09:27:37Z</time></trkpt><trkpt lat=\"48.8641395568848\" lon=\"2.30041265487671\"><ele>42.7411</ele><time>2007-04-15T09:27:38Z</time></trkpt><trkpt lat=\"48.8641204833984\" lon=\"2.30026173591614\"><ele>44.9868</ele><time>2007-04-15T09:27:39Z</time></trkpt><trkpt lat=\"48.8640937805176\" lon=\"2.30014777183533\"><ele>46.4735</ele><time>2007-04-15T09:27:40Z</time></trkpt><trkpt lat=\"48.8640747070312\" lon=\"2.30000972747803\"><ele>48.4097</ele><time>2007-04-15T09:27:41Z</time></trkpt><trkpt lat=\"48.8640747070312\" lon=\"2.29999279975891\"><ele>48.5136</ele><time>2007-04-15T09:27:42Z</time></trkpt><trkpt lat=\"48.8640632629394\" lon=\"2.29985070228577\"><ele>47.312</ele><time>2007-04-15T09:27:43Z</time></trkpt><trkpt lat=\"48.8640365600586\" lon=\"2.29971575737\"><ele>45.9238</ele><time>2007-04-15T09:27:44Z</time></trkpt><trkpt lat=\"48.864013671875\" lon=\"2.29959487915039\"><ele>44.6964</ele><time>2007-04-15T09:27:45Z</time></trkpt><trkpt lat=\"48.8639984130859\" lon=\"2.29952549934387\"><ele>43.9588</ele><time>2007-04-15T09:27:46Z</time></trkpt><trkpt lat=\"48.8639640808106\" lon=\"2.29940867424011\"><ele>42.5821</ele><time>2007-04-15T09:27:47Z</time></trkpt><trkpt lat=\"48.863941192627\" lon=\"2.29922080039978\"><ele>40.8724</ele><time>2007-04-15T09:27:48Z</time></trkpt><trkpt lat=\"48.8639221191406\" lon=\"2.2990608215332\"><ele>39.8109</ele><time>2007-04-15T09:27:49Z</time></trkpt><trkpt lat=\"48.8638954162598\" lon=\"2.29889130592346\"><ele>38.8692</ele><time>2007-04-15T09:27:50Z</time></trkpt><trkpt lat=\"48.8638458251953\" lon=\"2.29875135421753\"><ele>37.8462</ele><time>2007-04-15T09:27:51Z</time></trkpt><trkpt lat=\"48.8638000488281\" lon=\"2.29856729507446\"><ele>36.8995</ele><time>2007-04-15T09:27:52Z</time></trkpt><trkpt lat=\"48.8637657165527\" lon=\"2.29845404624939\"><ele>36.3496</ele><time>2007-04-15T09:27:53Z</time></trkpt><trkpt lat=\"48.8637504577637\" lon=\"2.29829382896423\"><ele>36.0032</ele><time>2007-04-15T09:27:54Z</time></trkpt><trkpt lat=\"48.863697052002\" lon=\"2.2980751991272\"><ele>35.6581</ele><time>2007-04-15T09:27:55Z</time></trkpt><trkpt lat=\"48.8636703491211\" lon=\"2.29792237281799\"><ele>35.5208</ele><time>2007-04-15T09:27:56Z</time></trkpt><trkpt lat=\"48.8636436462402\" lon=\"2.29776835441589\"><ele>35.4073</ele><time>2007-04-15T09:27:57Z</time></trkpt><trkpt lat=\"48.8636131286621\" lon=\"2.29759836196899\"><ele>35.3042</ele><time>2007-04-15T09:27:58Z</time></trkpt><trkpt lat=\"48.8635749816894\" lon=\"2.29743313789368\"><ele>35.2297</ele><time>2007-04-15T09:27:59Z</time></trkpt><trkpt lat=\"48.8635444641113\" lon=\"2.29731011390686\"><ele>35.1866</ele><time>2007-04-15T09:28:00Z</time></trkpt><trkpt lat=\"48.8635025024414\" lon=\"2.29707169532776\"><ele>35.125</ele><time>2007-04-15T09:28:01Z</time></trkpt><trkpt lat=\"48.8634567260742\" lon=\"2.29693961143494\"><ele>34.891</ele><time>2007-04-15T09:28:02Z</time></trkpt><trkpt lat=\"48.8634376525879\" lon=\"2.29684114456177\"><ele>34.7977</ele><time>2007-04-15T09:28:03Z</time></trkpt><trkpt lat=\"48.8633995056152\" lon=\"2.29665803909302\"><ele>34.5678</ele><time>2007-04-15T09:28:04Z</time></trkpt><trkpt lat=\"48.8633232116699\" lon=\"2.29643082618713\"><ele>34.2083</ele><time>2007-04-15T09:28:05Z</time></trkpt><trkpt lat=\"48.8632698059082\" lon=\"2.2962703704834\"><ele>34.0507</ele><time>2007-04-15T09:28:06Z</time></trkpt><trkpt lat=\"48.8632621765137\" lon=\"2.29624009132385\"><ele>34.0453</ele><time>2007-04-15T09:28:07Z</time></trkpt><trkpt lat=\"48.8632202148438\" lon=\"2.29606699943542\"><ele>34.0624</ele><time>2007-04-15T09:28:08Z</time></trkpt><trkpt lat=\"48.8631324768066\" lon=\"2.29582810401916\"><ele>34.0484</ele><time>2007-04-15T09:28:09Z</time></trkpt><trkpt lat=\"48.8630714416504\" lon=\"2.29566860198975\"><ele>34.1383</ele><time>2007-04-15T09:28:10Z</time></trkpt><trkpt lat=\"48.8630218505859\" lon=\"2.29549670219421\"><ele>34.3128</ele><time>2007-04-15T09:28:11Z</time></trkpt><trkpt lat=\"48.8629684448242\" lon=\"2.295334815979\"><ele>34.445</ele><time>2007-04-15T09:28:12Z</time></trkpt><trkpt lat=\"48.8629341125488\" lon=\"2.29518604278564\"><ele>34.6372</ele><time>2007-04-15T09:28:13Z</time></trkpt><trkpt lat=\"48.8628845214844\" lon=\"2.29502844810486\"><ele>34.7774</ele><time>2007-04-15T09:28:14Z</time></trkpt><trkpt lat=\"48.8628578186035\" lon=\"2.2948739528656\"><ele>35.5823</ele><time>2007-04-15T09:28:15Z</time></trkpt><trkpt lat=\"48.8628158569336\" lon=\"2.29468870162964\"><ele>36.5767</ele><time>2007-04-15T09:28:16Z</time></trkpt><trkpt lat=\"48.8627243041992\" lon=\"2.29453468322754\"><ele>36.9114</ele><time>2007-04-15T09:28:17Z</time></trkpt><trkpt lat=\"48.8626327514648\" lon=\"2.29441928863525\"><ele>36.8687</ele><time>2007-04-15T09:28:18Z</time></trkpt><trkpt lat=\"48.8625755310059\" lon=\"2.29427671432495\"><ele>37.149</ele><time>2007-04-15T09:28:19Z</time></trkpt><trkpt lat=\"48.8625221252441\" lon=\"2.29413771629334\"><ele>37.4574</ele><time>2007-04-15T09:28:20Z</time></trkpt><trkpt lat=\"48.8624801635742\" lon=\"2.29401040077209\"><ele>38.1148</ele><time>2007-04-15T09:28:21Z</time></trkpt><trkpt lat=\"48.8624267578125\" lon=\"2.29388785362244\"><ele>38.521</ele><time>2007-04-15T09:28:22Z</time></trkpt><trkpt lat=\"48.8624038696289\" lon=\"2.29374003410339\"><ele>39.3628</ele><time>2007-04-15T09:28:23Z</time></trkpt><trkpt lat=\"48.8623466491699\" lon=\"2.29363203048706\"><ele>39.3764</ele><time>2007-04-15T09:28:24Z</time></trkpt><trkpt lat=\"48.8622665405273\" lon=\"2.29347062110901\"><ele>39.2477</ele><time>2007-04-15T09:28:25Z</time></trkpt><trkpt lat=\"48.8622169494629\" lon=\"2.29332828521728\"><ele>39.2611</ele><time>2007-04-15T09:28:26Z</time></trkpt><trkpt lat=\"48.8621253967285\" lon=\"2.29318356513977\"><ele>38.2903</ele><time>2007-04-15T09:28:27Z</time></trkpt><trkpt lat=\"48.8620185852051\" lon=\"2.29300832748413\"><ele>37.4288</ele><time>2007-04-15T09:28:28Z</time></trkpt><trkpt lat=\"48.861930847168\" lon=\"2.29286599159241\"><ele>36.9142</ele><time>2007-04-15T09:28:29Z</time></trkpt><trkpt lat=\"48.8618583679199\" lon=\"2.29275393486023\"><ele>36.5925</ele><time>2007-04-15T09:28:30Z</time></trkpt><trkpt lat=\"48.8617820739746\" lon=\"2.29265546798706\"><ele>36.2562</ele><time>2007-04-15T09:28:31Z</time></trkpt><trkpt lat=\"48.8616638183594\" lon=\"2.29251933097839\"><ele>35.8438</ele><time>2007-04-15T09:28:32Z</time></trkpt><trkpt lat=\"48.8615875244141\" lon=\"2.292396068573\"><ele>36.1014</ele><time>2007-04-15T09:28:33Z</time></trkpt><trkpt lat=\"48.8614730834961\" lon=\"2.29226756095886\"><ele>35.974</ele><time>2007-04-15T09:28:34Z</time></trkpt><trkpt lat=\"48.861385345459\" lon=\"2.29217171669006\"><ele>35.7498</ele><time>2007-04-15T09:28:35Z</time></trkpt><trkpt lat=\"48.8612861633301\" lon=\"2.29204964637756\"><ele>35.4321</ele><time>2007-04-15T09:28:36Z</time></trkpt><trkpt lat=\"48.8611869812012\" lon=\"2.2919225692749\"><ele>34.991</ele><time>2007-04-15T09:28:37Z</time></trkpt><trkpt lat=\"48.8611030578613\" lon=\"2.29181694984436\"><ele>34.4992</ele><time>2007-04-15T09:28:38Z</time></trkpt><trkpt lat=\"48.8609962463379\" lon=\"2.29168081283569\"><ele>33.7292</ele><time>2007-04-15T09:28:39Z</time></trkpt><trkpt lat=\"48.8609046936035\" lon=\"2.29156875610352\"><ele>32.6934</ele><time>2007-04-15T09:28:40Z</time></trkpt><trkpt lat=\"48.8608551025391\" lon=\"2.29146385192871\"><ele>32.0172</ele><time>2007-04-15T09:28:41Z</time></trkpt><trkpt lat=\"48.8608474731445\" lon=\"2.2914309501648\"><ele>31.889</ele><time>2007-04-15T09:28:42Z</time></trkpt><trkpt lat=\"48.8607711791992\" lon=\"2.29124999046326\"><ele>31.4254</ele><time>2007-04-15T09:28:43Z</time></trkpt><trkpt lat=\"48.8607215881348\" lon=\"2.29107904434204\"><ele>31.3258</ele><time>2007-04-15T09:28:44Z</time></trkpt><trkpt lat=\"48.8606719970703\" lon=\"2.29094195365906\"><ele>31.3661</ele><time>2007-04-15T09:28:45Z</time></trkpt><trkpt lat=\"48.8606643676758\" lon=\"2.29091000556946\"><ele>31.3856</ele><time>2007-04-15T09:28:46Z</time></trkpt><trkpt lat=\"48.8606567382812\" lon=\"2.29090452194214\"><ele>31.4006</ele><time>2007-04-15T09:28:47Z</time></trkpt><trkpt lat=\"48.8598709106445\" lon=\"2.29023432731628\"><ele>35.9066</ele><time>2007-04-15T09:28:48Z</time></trkpt><trkpt lat=\"48.8597946166992\" lon=\"2.29014587402344\"><ele>35.9787</ele><time>2007-04-15T09:28:49Z</time></trkpt><trkpt lat=\"48.8597106933594\" lon=\"2.29004645347595\"><ele>36.0241</ele><time>2007-04-15T09:28:50Z</time></trkpt><trkpt lat=\"48.8596229553223\" lon=\"2.2899432182312\"><ele>36.2828</ele><time>2007-04-15T09:28:51Z</time></trkpt><trkpt lat=\"48.8595504760742\" lon=\"2.28986740112305\"><ele>36.5758</ele><time>2007-04-15T09:28:52Z</time></trkpt><trkpt lat=\"48.8594665527344\" lon=\"2.28977179527283\"><ele>36.9901</ele><time>2007-04-15T09:28:53Z</time></trkpt><trkpt lat=\"48.8594245910644\" lon=\"2.28971171379089\"><ele>37.3151</ele><time>2007-04-15T09:28:54Z</time></trkpt><trkpt lat=\"48.859375\" lon=\"2.28963899612427\"><ele>37.7156</ele><time>2007-04-15T09:28:55Z</time></trkpt><trkpt lat=\"48.8592758178711\" lon=\"2.28954482078552\"><ele>38.0246</ele><time>2007-04-15T09:28:56Z</time></trkpt><trkpt lat=\"48.8591690063477\" lon=\"2.28942441940308\"><ele>38.5396</ele><time>2007-04-15T09:28:57Z</time></trkpt><trkpt lat=\"48.8590545654297\" lon=\"2.28928804397583\"><ele>38.7978</ele><time>2007-04-15T09:28:58Z</time></trkpt><trkpt lat=\"48.8589706420898\" lon=\"2.28918671607971\"><ele>38.937</ele><time>2007-04-15T09:28:59Z</time></trkpt><trkpt lat=\"48.8588562011719\" lon=\"2.28907608985901\"><ele>39.0383</ele><time>2007-04-15T09:29:00Z</time></trkpt><trkpt lat=\"48.8587608337402\" lon=\"2.28897905349731\"><ele>39.2399</ele><time>2007-04-15T09:29:01Z</time></trkpt><trkpt lat=\"48.858642578125\" lon=\"2.28884792327881\"><ele>39.6517</ele><time>2007-04-15T09:29:02Z</time></trkpt><trkpt lat=\"48.8585205078125\" lon=\"2.28873372077942\"><ele>39.8755</ele><time>2007-04-15T09:29:03Z</time></trkpt><trkpt lat=\"48.8583984375\" lon=\"2.28861284255981\"><ele>40.219</ele><time>2007-04-15T09:29:04Z</time></trkpt><trkpt lat=\"48.8582916259766\" lon=\"2.28845953941345\"><ele>40.9683</ele><time>2007-04-15T09:29:05Z</time></trkpt><trkpt lat=\"48.8581962585449\" lon=\"2.2883026599884\"><ele>41.3322</ele><time>2007-04-15T09:29:06Z</time></trkpt><trkpt lat=\"48.8581657409668\" lon=\"2.28825497627258\"><ele>41.3961</ele><time>2007-04-15T09:29:07Z</time></trkpt><trkpt lat=\"48.8580741882324\" lon=\"2.28815245628357\"><ele>41.3277</ele><time>2007-04-15T09:29:08Z</time></trkpt><trkpt lat=\"48.8579368591309\" lon=\"2.28799653053284\"><ele>41.6582</ele><time>2007-04-15T09:29:09Z</time></trkpt><trkpt lat=\"48.857795715332\" lon=\"2.2878315448761\"><ele>42.5811</ele><time>2007-04-15T09:29:10Z</time></trkpt><trkpt lat=\"48.8576583862305\" lon=\"2.2876672744751\"><ele>44.0545</ele><time>2007-04-15T09:29:11Z</time></trkpt><trkpt lat=\"48.8575553894043\" lon=\"2.28752303123474\"><ele>45.866</ele><time>2007-04-15T09:29:12Z</time></trkpt><trkpt lat=\"48.8574562072754\" lon=\"2.28738927841187\"><ele>46.4215</ele><time>2007-04-15T09:29:13Z</time></trkpt><trkpt lat=\"48.8573760986328\" lon=\"2.28724718093872\"><ele>46.5904</ele><time>2007-04-15T09:29:14Z</time></trkpt><trkpt lat=\"48.8572540283203\" lon=\"2.28709506988525\"><ele>46.2326</ele><time>2007-04-15T09:29:15Z</time></trkpt><trkpt lat=\"48.8571281433106\" lon=\"2.28694725036621\"><ele>45.8682</ele><time>2007-04-15T09:29:16Z</time></trkpt><trkpt lat=\"48.8570365905762\" lon=\"2.28683686256409\"><ele>45.7056</ele><time>2007-04-15T09:29:17Z</time></trkpt><trkpt lat=\"48.856876373291\" lon=\"2.28669142723084\"><ele>44.9595</ele><time>2007-04-15T09:29:18Z</time></trkpt><trkpt lat=\"48.856803894043\" lon=\"2.28658962249756\"><ele>44.5737</ele><time>2007-04-15T09:29:19Z</time></trkpt><trkpt lat=\"48.8567504882812\" lon=\"2.28652620315552\"><ele>44.1833</ele><time>2007-04-15T09:29:20Z</time></trkpt><trkpt lat=\"48.8566207885742\" lon=\"2.28637552261353\"><ele>43.5649</ele><time>2007-04-15T09:29:21Z</time></trkpt><trkpt lat=\"48.856517791748\" lon=\"2.28620600700378\"><ele>43.629</ele><time>2007-04-15T09:29:22Z</time></trkpt><trkpt lat=\"48.8564300537109\" lon=\"2.2860631942749\"><ele>43.7113</ele><time>2007-04-15T09:29:23Z</time></trkpt><trkpt lat=\"48.8563346862793\" lon=\"2.28593969345093\"><ele>43.598</ele><time>2007-04-15T09:29:24Z</time></trkpt><trkpt lat=\"48.8562469482422\" lon=\"2.28581953048706\"><ele>43.4673</ele><time>2007-04-15T09:29:25Z</time></trkpt><trkpt lat=\"48.8561553955078\" lon=\"2.28568601608276\"><ele>42.5585</ele><time>2007-04-15T09:29:26Z</time></trkpt><trkpt lat=\"48.8560676574707\" lon=\"2.2855715751648\"><ele>41.8056</ele><time>2007-04-15T09:29:27Z</time></trkpt><trkpt lat=\"48.8559494018555\" lon=\"2.2854106426239\"><ele>40.9854</ele><time>2007-04-15T09:29:28Z</time></trkpt><trkpt lat=\"48.8558578491211\" lon=\"2.28529405593872\"><ele>40.4829</ele><time>2007-04-15T09:29:29Z</time></trkpt><trkpt lat=\"48.8557434082031\" lon=\"2.28515315055847\"><ele>40.4055</ele><time>2007-04-15T09:29:30Z</time></trkpt><trkpt lat=\"48.8556823730469\" lon=\"2.2850513458252\"><ele>40.6286</ele><time>2007-04-15T09:29:31Z</time></trkpt><trkpt lat=\"48.8555641174316\" lon=\"2.28489470481873\"><ele>40.7508</ele><time>2007-04-15T09:29:32Z</time></trkpt><trkpt lat=\"48.8554267883301\" lon=\"2.28474020957947\"><ele>41.1054</ele><time>2007-04-15T09:29:33Z</time></trkpt><trkpt lat=\"48.855339050293\" lon=\"2.28462982177734\"><ele>41.6263</ele><time>2007-04-15T09:29:34Z</time></trkpt><trkpt lat=\"48.8552322387695\" lon=\"2.28449559211731\"><ele>42.5609</ele><time>2007-04-15T09:29:35Z</time></trkpt><trkpt lat=\"48.8551177978516\" lon=\"2.28435802459717\"><ele>43.8924</ele><time>2007-04-15T09:29:36Z</time></trkpt><trkpt lat=\"48.8550262451172\" lon=\"2.28424382209778\"><ele>45.2473</ele><time>2007-04-15T09:29:37Z</time></trkpt><trkpt lat=\"48.8549766540527\" lon=\"2.28417468070984\"><ele>45.6366</ele><time>2007-04-15T09:29:38Z</time></trkpt><trkpt lat=\"48.8548812866211\" lon=\"2.28404211997986\"><ele>44.2405</ele><time>2007-04-15T09:29:39Z</time></trkpt><trkpt lat=\"48.8548622131348\" lon=\"2.28402209281921\"><ele>43.9777</ele><time>2007-04-15T09:29:40Z</time></trkpt><trkpt lat=\"48.854736328125\" lon=\"2.28385806083679\"><ele>42.3647</ele><time>2007-04-15T09:29:41Z</time></trkpt><trkpt lat=\"48.8546295166016\" lon=\"2.28371715545654\"><ele>41.2299</ele><time>2007-04-15T09:29:42Z</time></trkpt><trkpt lat=\"48.8544845581055\" lon=\"2.28352403640747\"><ele>40.0388</ele><time>2007-04-15T09:29:43Z</time></trkpt><trkpt lat=\"48.8543739318848\" lon=\"2.28339552879334\"><ele>39.3612</ele><time>2007-04-15T09:29:44Z</time></trkpt><trkpt lat=\"48.8542594909668\" lon=\"2.28326559066772\"><ele>38.578</ele><time>2007-04-15T09:29:45Z</time></trkpt><trkpt lat=\"48.854175567627\" lon=\"2.28314781188965\"><ele>37.8391</ele><time>2007-04-15T09:29:46Z</time></trkpt><trkpt lat=\"48.8540687561035\" lon=\"2.2830057144165\"><ele>36.4028</ele><time>2007-04-15T09:29:47Z</time></trkpt><trkpt lat=\"48.8539581298828\" lon=\"2.2828733921051\"><ele>35.1617</ele><time>2007-04-15T09:29:48Z</time></trkpt><trkpt lat=\"48.8538513183594\" lon=\"2.28272604942322\"><ele>34.2822</ele><time>2007-04-15T09:29:49Z</time></trkpt><trkpt lat=\"48.8537445068359\" lon=\"2.28257727622986\"><ele>33.7243</ele><time>2007-04-15T09:29:50Z</time></trkpt><trkpt lat=\"48.8536529541016\" lon=\"2.2824273109436\"><ele>33.919</ele><time>2007-04-15T09:29:51Z</time></trkpt><trkpt lat=\"48.8535537719727\" lon=\"2.2822585105896\"><ele>34.812</ele><time>2007-04-15T09:29:52Z</time></trkpt><trkpt lat=\"48.8534851074219\" lon=\"2.28214406967163\"><ele>35.5479</ele><time>2007-04-15T09:29:53Z</time></trkpt><trkpt lat=\"48.8534164428711\" lon=\"2.28206872940063\"><ele>35.998</ele><time>2007-04-15T09:29:54Z</time></trkpt><trkpt lat=\"48.8533248901367\" lon=\"2.28191590309143\"><ele>37.2352</ele><time>2007-04-15T09:29:55Z</time></trkpt><trkpt lat=\"48.8532066345215\" lon=\"2.28174209594727\"><ele>37.8996</ele><time>2007-04-15T09:29:56Z</time></trkpt><trkpt lat=\"48.8531112670898\" lon=\"2.28157234191895\"><ele>38.4621</ele><time>2007-04-15T09:29:57Z</time></trkpt><trkpt lat=\"48.8530158996582\" lon=\"2.28141570091248\"><ele>38.5508</ele><time>2007-04-15T09:29:58Z</time></trkpt><trkpt lat=\"48.8529434204102\" lon=\"2.28127694129944\"><ele>38.4963</ele><time>2007-04-15T09:29:59Z</time></trkpt><trkpt lat=\"48.852840423584\" lon=\"2.2810788154602\"><ele>37.9755</ele><time>2007-04-15T09:30:00Z</time></trkpt><trkpt lat=\"48.8527793884277\" lon=\"2.28103494644165\"><ele>37.0628</ele><time>2007-04-15T09:30:01Z</time></trkpt><trkpt lat=\"48.8526725769043\" lon=\"2.28086304664612\"><ele>35.6255</ele><time>2007-04-15T09:30:02Z</time></trkpt><trkpt lat=\"48.8526077270508\" lon=\"2.28069567680359\"><ele>34.9179</ele><time>2007-04-15T09:30:03Z</time></trkpt><trkpt lat=\"48.8525199890137\" lon=\"2.2805278301239\"><ele>34.1681</ele><time>2007-04-15T09:30:04Z</time></trkpt><trkpt lat=\"48.8524360656738\" lon=\"2.28039050102234\"><ele>34.4891</ele><time>2007-04-15T09:30:05Z</time></trkpt><trkpt lat=\"48.8523712158203\" lon=\"2.28029346466064\"><ele>34.793</ele><time>2007-04-15T09:30:06Z</time></trkpt><trkpt lat=\"48.8523178100586\" lon=\"2.28017210960388\"><ele>35.1451</ele><time>2007-04-15T09:30:07Z</time></trkpt><trkpt lat=\"48.8522300720215\" lon=\"2.28005957603455\"><ele>35.1619</ele><time>2007-04-15T09:30:08Z</time></trkpt><trkpt lat=\"48.852165222168\" lon=\"2.27996349334717\"><ele>35.1666</ele><time>2007-04-15T09:30:09Z</time></trkpt><trkpt lat=\"48.8521156311035\" lon=\"2.27987408638\"><ele>35.2982</ele><time>2007-04-15T09:30:10Z</time></trkpt><trkpt lat=\"48.8520584106445\" lon=\"2.279780626297\"><ele>35.4035</ele><time>2007-04-15T09:30:11Z</time></trkpt><trkpt lat=\"48.851993560791\" lon=\"2.27968120574951\"><ele>35.4916</ele><time>2007-04-15T09:30:12Z</time></trkpt><trkpt lat=\"48.8519020080566\" lon=\"2.279536485672\"><ele>35.6369</ele><time>2007-04-15T09:30:13Z</time></trkpt><trkpt lat=\"48.8518180847168\" lon=\"2.27937388420105\"><ele>35.9139</ele><time>2007-04-15T09:30:14Z</time></trkpt><trkpt lat=\"48.8517646789551\" lon=\"2.27926015853882\"><ele>36.1393</ele><time>2007-04-15T09:30:15Z</time></trkpt><trkpt lat=\"48.8517189025879\" lon=\"2.27912354469299\"><ele>36.3684</ele><time>2007-04-15T09:30:16Z</time></trkpt><trkpt lat=\"48.8516540527344\" lon=\"2.27899765968323\"><ele>36.1545</ele><time>2007-04-15T09:30:17Z</time></trkpt><trkpt lat=\"48.8516311645508\" lon=\"2.27895402908325\"><ele>36.1282</ele><time>2007-04-15T09:30:18Z</time></trkpt><trkpt lat=\"48.8515930175781\" lon=\"2.27889251708984\"><ele>36.0918</ele><time>2007-04-15T09:30:19Z</time></trkpt><trkpt lat=\"48.8515281677246\" lon=\"2.27876925468445\"><ele>36.1291</ele><time>2007-04-15T09:30:20Z</time></trkpt><trkpt lat=\"48.8514442443848\" lon=\"2.27863478660584\"><ele>36.252</ele><time>2007-04-15T09:30:21Z</time></trkpt><trkpt lat=\"48.8513679504394\" lon=\"2.27849221229553\"><ele>36.536</ele><time>2007-04-15T09:30:22Z</time></trkpt><trkpt lat=\"48.8512802124023\" lon=\"2.27832365036011\"><ele>37.0187</ele><time>2007-04-15T09:30:23Z</time></trkpt><trkpt lat=\"48.8511848449707\" lon=\"2.27817988395691\"><ele>37.233</ele><time>2007-04-15T09:30:24Z</time></trkpt><trkpt lat=\"48.8510780334473\" lon=\"2.27806520462036\"><ele>37.2834</ele><time>2007-04-15T09:30:25Z</time></trkpt><trkpt lat=\"48.8509979248047\" lon=\"2.27793574333191\"><ele>37.2827</ele><time>2007-04-15T09:30:26Z</time></trkpt><trkpt lat=\"48.8509063720703\" lon=\"2.27778506278992\"><ele>37.173</ele><time>2007-04-15T09:30:27Z</time></trkpt><trkpt lat=\"48.8508453369141\" lon=\"2.27766609191895\"><ele>37.0346</ele><time>2007-04-15T09:30:28Z</time></trkpt><trkpt lat=\"48.8507919311523\" lon=\"2.27754497528076\"><ele>36.992</ele><time>2007-04-15T09:30:29Z</time></trkpt><trkpt lat=\"48.8506927490234\" lon=\"2.27740073204041\"><ele>37.3387</ele><time>2007-04-15T09:30:30Z</time></trkpt><trkpt lat=\"48.850643157959\" lon=\"2.27724599838257\"><ele>37.9574</ele><time>2007-04-15T09:30:31Z</time></trkpt><trkpt lat=\"48.8505935668945\" lon=\"2.27704381942749\"><ele>38.8823</ele><time>2007-04-15T09:30:32Z</time></trkpt><trkpt lat=\"48.8505859375\" lon=\"2.2770094871521\"><ele>39.051</ele><time>2007-04-15T09:30:33Z</time></trkpt><trkpt lat=\"48.8504600524902\" lon=\"2.27685856819153\"><ele>40.2634</ele><time>2007-04-15T09:30:34Z</time></trkpt><trkpt lat=\"48.8503837585449\" lon=\"2.27675032615662\"><ele>41.2259</ele><time>2007-04-15T09:30:35Z</time></trkpt><trkpt lat=\"48.8502655029297\" lon=\"2.27659869194031\"><ele>42.2994</ele><time>2007-04-15T09:30:36Z</time></trkpt><trkpt lat=\"48.8502082824707\" lon=\"2.27644562721252\"><ele>42.4188</ele><time>2007-04-15T09:30:37Z</time></trkpt><trkpt lat=\"48.8501167297363\" lon=\"2.2763307094574\"><ele>42.84</ele><time>2007-04-15T09:30:38Z</time></trkpt><trkpt lat=\"48.8500175476074\" lon=\"2.27621793746948\"><ele>43.3449</ele><time>2007-04-15T09:30:39Z</time></trkpt><trkpt lat=\"48.8499298095703\" lon=\"2.2761492729187\"><ele>43.6725</ele><time>2007-04-15T09:30:40Z</time></trkpt><trkpt lat=\"48.8498382568359\" lon=\"2.27603912353516\"><ele>44.0257</ele><time>2007-04-15T09:30:41Z</time></trkpt><trkpt lat=\"48.8497581481934\" lon=\"2.2759850025177\"><ele>44.4218</ele><time>2007-04-15T09:30:42Z</time></trkpt><trkpt lat=\"48.8496856689453\" lon=\"2.27593398094177\"><ele>44.8245</ele><time>2007-04-15T09:30:43Z</time></trkpt><trkpt lat=\"48.8495903015137\" lon=\"2.27581763267517\"><ele>45.4301</ele><time>2007-04-15T09:30:44Z</time></trkpt><trkpt lat=\"48.8495254516602\" lon=\"2.27572131156921\"><ele>45.6363</ele><time>2007-04-15T09:30:45Z</time></trkpt><trkpt lat=\"48.8494300842285\" lon=\"2.27558040618896\"><ele>45.9084</ele><time>2007-04-15T09:30:46Z</time></trkpt><trkpt lat=\"48.8493728637695\" lon=\"2.27557754516602\"><ele>46.2249</ele><time>2007-04-15T09:30:47Z</time></trkpt><trkpt lat=\"48.8493156433106\" lon=\"2.27552223205566\"><ele>46.4262</ele><time>2007-04-15T09:30:48Z</time></trkpt><trkpt lat=\"48.8491859436035\" lon=\"2.27538967132568\"><ele>46.8319</ele><time>2007-04-15T09:30:49Z</time></trkpt><trkpt lat=\"48.8491744995117\" lon=\"2.27537536621094\"><ele>46.859</ele><time>2007-04-15T09:30:50Z</time></trkpt><trkpt lat=\"48.8490562438965\" lon=\"2.27529716491699\"><ele>46.6187</ele><time>2007-04-15T09:30:51Z</time></trkpt><trkpt lat=\"48.8490219116211\" lon=\"2.27525925636292\"><ele>46.5141</ele><time>2007-04-15T09:30:52Z</time></trkpt><trkpt lat=\"48.8489875793457\" lon=\"2.2751739025116\"><ele>46.3277</ele><time>2007-04-15T09:30:53Z</time></trkpt><trkpt lat=\"48.8488960266113\" lon=\"2.27512693405151\"><ele>46.2057</ele><time>2007-04-15T09:30:54Z</time></trkpt><trkpt lat=\"48.8488006591797\" lon=\"2.27504563331604\"><ele>46.0614</ele><time>2007-04-15T09:30:55Z</time></trkpt><trkpt lat=\"48.8487129211426\" lon=\"2.27494835853577\"><ele>45.8141</ele><time>2007-04-15T09:30:56Z</time></trkpt><trkpt lat=\"48.8486061096191\" lon=\"2.27484536170959\"><ele>45.4433</ele><time>2007-04-15T09:30:57Z</time></trkpt><trkpt lat=\"48.8485221862793\" lon=\"2.27474308013916\"><ele>45.0751</ele><time>2007-04-15T09:30:58Z</time></trkpt><trkpt lat=\"48.8484191894531\" lon=\"2.27458953857422\"><ele>44.5223</ele><time>2007-04-15T09:30:59Z</time></trkpt><trkpt lat=\"48.8483047485352\" lon=\"2.27452254295349\"><ele>44.2322</ele><time>2007-04-15T09:31:00Z</time></trkpt><trkpt lat=\"48.8481750488281\" lon=\"2.27437114715576\"><ele>43.4996</ele><time>2007-04-15T09:31:01Z</time></trkpt><trkpt lat=\"48.84814453125\" lon=\"2.27432584762573\"><ele>43.3032</ele><time>2007-04-15T09:31:02Z</time></trkpt><trkpt lat=\"48.848030090332\" lon=\"2.2741847038269\"><ele>42.6932</ele><time>2007-04-15T09:31:03Z</time></trkpt><trkpt lat=\"48.8479232788086\" lon=\"2.27406311035156\"><ele>42.7545</ele><time>2007-04-15T09:31:04Z</time></trkpt><trkpt lat=\"48.8478660583496\" lon=\"2.27401185035706\"><ele>42.8334</ele><time>2007-04-15T09:31:05Z</time></trkpt><trkpt lat=\"48.8477478027344\" lon=\"2.27389717102051\"><ele>43.0752</ele><time>2007-04-15T09:31:06Z</time></trkpt><trkpt lat=\"48.8476753234863\" lon=\"2.27383756637573\"><ele>43.229</ele><time>2007-04-15T09:31:07Z</time></trkpt><trkpt lat=\"48.8476371765137\" lon=\"2.27378034591675\"><ele>43.4027</ele><time>2007-04-15T09:31:08Z</time></trkpt><trkpt lat=\"48.8476448059082\" lon=\"2.2737500667572\"><ele>43.4998</ele><time>2007-04-15T09:31:09Z</time></trkpt><trkpt lat=\"48.8475952148438\" lon=\"2.27366232872009\"><ele>43.7916</ele><time>2007-04-15T09:31:10Z</time></trkpt><trkpt lat=\"48.8475341796875\" lon=\"2.27357816696167\"><ele>44.1017</ele><time>2007-04-15T09:31:11Z</time></trkpt><trkpt lat=\"48.8474655151367\" lon=\"2.27346086502075\"><ele>44.3466</ele><time>2007-04-15T09:31:12Z</time></trkpt><trkpt lat=\"48.8473281860352\" lon=\"2.27327299118042\"><ele>44.1012</ele><time>2007-04-15T09:31:13Z</time></trkpt><trkpt lat=\"48.8472747802734\" lon=\"2.2731921672821\"><ele>44.0012</ele><time>2007-04-15T09:31:14Z</time></trkpt><trkpt lat=\"48.8471565246582\" lon=\"2.27297639846802\"><ele>44.0736</ele><time>2007-04-15T09:31:15Z</time></trkpt><trkpt lat=\"48.847095489502\" lon=\"2.27280735969543\"><ele>44.4296</ele><time>2007-04-15T09:31:16Z</time></trkpt><trkpt lat=\"48.8470573425293\" lon=\"2.27266311645508\"><ele>44.8572</ele><time>2007-04-15T09:31:17Z</time></trkpt><trkpt lat=\"48.8470001220703\" lon=\"2.27248883247376\"><ele>45.4216</ele><time>2007-04-15T09:31:18Z</time></trkpt><trkpt lat=\"48.8469657897949\" lon=\"2.27232909202576\"><ele>45.6955</ele><time>2007-04-15T09:31:19Z</time></trkpt><trkpt lat=\"48.8468971252441\" lon=\"2.27209091186523\"><ele>46.1226</ele><time>2007-04-15T09:31:20Z</time></trkpt><trkpt lat=\"48.8468551635742\" lon=\"2.27192378044128\"><ele>46.4527</ele><time>2007-04-15T09:31:21Z</time></trkpt><trkpt lat=\"48.8467712402344\" lon=\"2.27174615859985\"><ele>46.8212</ele><time>2007-04-15T09:31:22Z</time></trkpt><trkpt lat=\"48.8466949462891\" lon=\"2.27161502838135\"><ele>47.0599</ele><time>2007-04-15T09:31:23Z</time></trkpt><trkpt lat=\"48.8466148376465\" lon=\"2.27145552635193\"><ele>47.0502</ele><time>2007-04-15T09:31:24Z</time></trkpt><trkpt lat=\"48.8465766906738\" lon=\"2.27136254310608\"><ele>46.952</ele><time>2007-04-15T09:31:25Z</time></trkpt><trkpt lat=\"48.8465576171875\" lon=\"2.27127552032471\"><ele>46.9005</ele><time>2007-04-15T09:31:26Z</time></trkpt><trkpt lat=\"48.8465309143066\" lon=\"2.27119398117065\"><ele>46.7794</ele><time>2007-04-15T09:31:27Z</time></trkpt><trkpt lat=\"48.8464241027832\" lon=\"2.27103447914124\"><ele>46.0724</ele><time>2007-04-15T09:31:28Z</time></trkpt><trkpt lat=\"48.8464126586914\" lon=\"2.27086687088013\"><ele>45.8874</ele><time>2007-04-15T09:31:29Z</time></trkpt><trkpt lat=\"48.8464050292969\" lon=\"2.2706515789032\"><ele>45.2291</ele><time>2007-04-15T09:31:30Z</time></trkpt><trkpt lat=\"48.8463706970215\" lon=\"2.27046585083008\"><ele>44.3187</ele><time>2007-04-15T09:31:31Z</time></trkpt><trkpt lat=\"48.8463439941406\" lon=\"2.27030444145203\"><ele>43.5287</ele><time>2007-04-15T09:31:32Z</time></trkpt><trkpt lat=\"48.846305847168\" lon=\"2.27017879486084\"><ele>42.7181</ele><time>2007-04-15T09:31:33Z</time></trkpt><trkpt lat=\"48.846263885498\" lon=\"2.27002310752869\"><ele>41.7322</ele><time>2007-04-15T09:31:34Z</time></trkpt><trkpt lat=\"48.8462181091309\" lon=\"2.2698814868927\"><ele>40.9586</ele><time>2007-04-15T09:31:35Z</time></trkpt><trkpt lat=\"48.8461494445801\" lon=\"2.26971197128296\"><ele>40.0207</ele><time>2007-04-15T09:31:36Z</time></trkpt><trkpt lat=\"48.846076965332\" lon=\"2.26955938339233\"><ele>39.1675</ele><time>2007-04-15T09:31:37Z</time></trkpt><trkpt lat=\"48.846019744873\" lon=\"2.26942372322083\"><ele>38.5492</ele><time>2007-04-15T09:31:38Z</time></trkpt><trkpt lat=\"48.8459777832031\" lon=\"2.26925706863403\"><ele>38.0965</ele><time>2007-04-15T09:31:39Z</time></trkpt><trkpt lat=\"48.8459663391113\" lon=\"2.26919627189636\"><ele>37.9747</ele><time>2007-04-15T09:31:40Z</time></trkpt><trkpt lat=\"48.8459510803223\" lon=\"2.26909422874451\"><ele>38.1586</ele><time>2007-04-15T09:31:41Z</time></trkpt><trkpt lat=\"48.8458862304688\" lon=\"2.26893997192383\"><ele>38.4172</ele><time>2007-04-15T09:31:42Z</time></trkpt><trkpt lat=\"48.8458671569824\" lon=\"2.26888394355774\"><ele>38.5593</ele><time>2007-04-15T09:31:43Z</time></trkpt><trkpt lat=\"48.8458404541016\" lon=\"2.26879358291626\"><ele>38.8306</ele><time>2007-04-15T09:31:44Z</time></trkpt><trkpt lat=\"48.8457984924316\" lon=\"2.26863121986389\"><ele>39.391</ele><time>2007-04-15T09:31:45Z</time></trkpt><trkpt lat=\"48.8457908630371\" lon=\"2.26856517791748\"><ele>39.6607</ele><time>2007-04-15T09:31:46Z</time></trkpt><trkpt lat=\"48.8457260131836\" lon=\"2.26839351654053\"><ele>40.0858</ele><time>2007-04-15T09:31:47Z</time></trkpt><trkpt lat=\"48.8456649780273\" lon=\"2.26823711395264\"><ele>40.1065</ele><time>2007-04-15T09:31:48Z</time></trkpt><trkpt lat=\"48.8455848693848\" lon=\"2.26804852485657\"><ele>40.0187</ele><time>2007-04-15T09:31:49Z</time></trkpt><trkpt lat=\"48.8455238342285\" lon=\"2.26789498329163\"><ele>40.1198</ele><time>2007-04-15T09:31:50Z</time></trkpt><trkpt lat=\"48.8454780578613\" lon=\"2.26773381233215\"><ele>40.4019</ele><time>2007-04-15T09:31:51Z</time></trkpt><trkpt lat=\"48.8454437255859\" lon=\"2.26763033866882\"><ele>40.6344</ele><time>2007-04-15T09:31:52Z</time></trkpt><trkpt lat=\"48.8453941345215\" lon=\"2.26745843887329\"><ele>41.1233</ele><time>2007-04-15T09:31:53Z</time></trkpt><trkpt lat=\"48.8453559875488\" lon=\"2.26729583740234\"><ele>41.5947</ele><time>2007-04-15T09:31:54Z</time></trkpt><trkpt lat=\"48.8453178405762\" lon=\"2.26717925071716\"><ele>41.9166</ele><time>2007-04-15T09:31:55Z</time></trkpt><trkpt lat=\"48.8452796936035\" lon=\"2.26702499389648\"><ele>42.3313</ele><time>2007-04-15T09:31:56Z</time></trkpt><trkpt lat=\"48.845272064209\" lon=\"2.26699733734131\"><ele>42.4033</ele><time>2007-04-15T09:31:57Z</time></trkpt><trkpt lat=\"48.8452415466309\" lon=\"2.26684617996216\"><ele>42.7966</ele><time>2007-04-15T09:31:58Z</time></trkpt><trkpt lat=\"48.8452301025391\" lon=\"2.26668953895569\"><ele>43.2136</ele><time>2007-04-15T09:31:59Z</time></trkpt><trkpt lat=\"48.8452033996582\" lon=\"2.2665638923645\"><ele>43.4636</ele><time>2007-04-15T09:32:00Z</time></trkpt><trkpt lat=\"48.845157623291\" lon=\"2.26643872261047\"><ele>43.7511</ele><time>2007-04-15T09:32:01Z</time></trkpt><trkpt lat=\"48.8451156616211\" lon=\"2.26622867584228\"><ele>44.3508</ele><time>2007-04-15T09:32:02Z</time></trkpt><trkpt lat=\"48.8451309204102\" lon=\"2.26601028442383\"><ele>44.9014</ele><time>2007-04-15T09:32:03Z</time></trkpt><trkpt lat=\"48.8451042175293\" lon=\"2.26581645011902\"><ele>45.52</ele><time>2007-04-15T09:32:04Z</time></trkpt><trkpt lat=\"48.845100402832\" lon=\"2.265625\"><ele>45.7681</ele><time>2007-04-15T09:32:05Z</time></trkpt><trkpt lat=\"48.8451080322266\" lon=\"2.265469789505\"><ele>45.9177</ele><time>2007-04-15T09:32:06Z</time></trkpt><trkpt lat=\"48.8451194763184\" lon=\"2.26528739929199\"><ele>46.0816</ele><time>2007-04-15T09:32:07Z</time></trkpt><trkpt lat=\"48.845157623291\" lon=\"2.26510691642761\"><ele>46.1151</ele><time>2007-04-15T09:32:08Z</time></trkpt><trkpt lat=\"48.845157623291\" lon=\"2.26494550704956\"><ele>46.3706</ele><time>2007-04-15T09:32:09Z</time></trkpt><trkpt lat=\"48.8451156616211\" lon=\"2.26474571228027\"><ele>46.9617</ele><time>2007-04-15T09:32:10Z</time></trkpt><trkpt lat=\"48.845100402832\" lon=\"2.26460313796997\"><ele>47.2812</ele><time>2007-04-15T09:32:11Z</time></trkpt><trkpt lat=\"48.8451118469238\" lon=\"2.26444268226624\"><ele>47.5807</ele><time>2007-04-15T09:32:12Z</time></trkpt><trkpt lat=\"48.8450736999512\" lon=\"2.2642514705658\"><ele>47.9417</ele><time>2007-04-15T09:32:13Z</time></trkpt><trkpt lat=\"48.8450508117676\" lon=\"2.26415181159973\"><ele>48.0097</ele><time>2007-04-15T09:32:14Z</time></trkpt><trkpt lat=\"48.8450775146484\" lon=\"2.26391005516052\"><ele>47.2265</ele><time>2007-04-15T09:32:15Z</time></trkpt><trkpt lat=\"48.845085144043\" lon=\"2.26372814178467\"><ele>46.631</ele><time>2007-04-15T09:32:16Z</time></trkpt><trkpt lat=\"48.8450622558594\" lon=\"2.26349520683289\"><ele>45.7778</ele><time>2007-04-15T09:32:17Z</time></trkpt><trkpt lat=\"48.8450813293457\" lon=\"2.263338804245\"><ele>45.3112</ele><time>2007-04-15T09:32:18Z</time></trkpt><trkpt lat=\"48.8451118469238\" lon=\"2.26310110092163\"><ele>45.4401</ele><time>2007-04-15T09:32:19Z</time></trkpt><trkpt lat=\"48.8451461791992\" lon=\"2.26289176940918\"><ele>45.6192</ele><time>2007-04-15T09:32:20Z</time></trkpt><trkpt lat=\"48.8451499938965\" lon=\"2.26273250579834\"><ele>45.6698</ele><time>2007-04-15T09:32:21Z</time></trkpt><trkpt lat=\"48.8451232910156\" lon=\"2.26252388954163\"><ele>45.5876</ele><time>2007-04-15T09:32:22Z</time></trkpt><trkpt lat=\"48.845142364502\" lon=\"2.26233553886414\"><ele>46.5353</ele><time>2007-04-15T09:32:23Z</time></trkpt><trkpt lat=\"48.8450889587402\" lon=\"2.26219463348389\"><ele>47.1027</ele><time>2007-04-15T09:32:24Z</time></trkpt><trkpt lat=\"48.845027923584\" lon=\"2.26202988624573\"><ele>47.8791</ele><time>2007-04-15T09:32:25Z</time></trkpt><trkpt lat=\"48.8450012207031\" lon=\"2.26183342933655\"><ele>49.0006</ele><time>2007-04-15T09:32:26Z</time></trkpt><trkpt lat=\"48.8450164794922\" lon=\"2.26171517372131\"><ele>49.7136</ele><time>2007-04-15T09:32:27Z</time></trkpt><trkpt lat=\"48.8450660705566\" lon=\"2.26149654388428\"><ele>49.8444</ele><time>2007-04-15T09:32:28Z</time></trkpt><trkpt lat=\"48.8451156616211\" lon=\"2.26127767562866\"><ele>49.7276</ele><time>2007-04-15T09:32:29Z</time></trkpt><trkpt lat=\"48.8451461791992\" lon=\"2.26113700866699\"><ele>49.6989</ele><time>2007-04-15T09:32:30Z</time></trkpt><trkpt lat=\"48.8451881408691\" lon=\"2.26095843315124\"><ele>49.7257</ele><time>2007-04-15T09:32:31Z</time></trkpt><trkpt lat=\"48.8452033996582\" lon=\"2.26079392433166\"><ele>49.6849</ele><time>2007-04-15T09:32:32Z</time></trkpt><trkpt lat=\"48.8451957702637\" lon=\"2.26072263717651\"><ele>49.5719</ele><time>2007-04-15T09:32:33Z</time></trkpt><trkpt lat=\"48.8451957702637\" lon=\"2.26042604446411\"><ele>49.216</ele><time>2007-04-15T09:32:34Z</time></trkpt><trkpt lat=\"48.8452033996582\" lon=\"2.26027917861938\"><ele>49.0673</ele><time>2007-04-15T09:32:35Z</time></trkpt><trkpt lat=\"48.8451995849609\" lon=\"2.26006126403809\"><ele>48.792</ele><time>2007-04-15T09:32:36Z</time></trkpt><trkpt lat=\"48.8451919555664\" lon=\"2.25988411903381\"><ele>48.552</ele><time>2007-04-15T09:32:37Z</time></trkpt><trkpt lat=\"48.8451728820801\" lon=\"2.25968456268311\"><ele>48.2439</ele><time>2007-04-15T09:32:38Z</time></trkpt><trkpt lat=\"48.8451309204102\" lon=\"2.25949096679688\"><ele>47.8605</ele><time>2007-04-15T09:32:39Z</time></trkpt><trkpt lat=\"48.8451309204102\" lon=\"2.25924706459045\"><ele>47.5678</ele><time>2007-04-15T09:32:40Z</time></trkpt><trkpt lat=\"48.8451766967773\" lon=\"2.2590594291687\"><ele>47.6284</ele><time>2007-04-15T09:32:41Z</time></trkpt><trkpt lat=\"48.8452339172363\" lon=\"2.2588107585907\"><ele>47.6698</ele><time>2007-04-15T09:32:42Z</time></trkpt><trkpt lat=\"48.8452796936035\" lon=\"2.25866460800171\"><ele>47.5983</ele><time>2007-04-15T09:32:43Z</time></trkpt><trkpt lat=\"48.8452682495117\" lon=\"2.25846576690674\"><ele>47.4531</ele><time>2007-04-15T09:32:44Z</time></trkpt><trkpt lat=\"48.8452529907227\" lon=\"2.2582950592041\"><ele>47.1492</ele><time>2007-04-15T09:32:45Z</time></trkpt><trkpt lat=\"48.8452529907227\" lon=\"2.25814580917358\"><ele>46.1994</ele><time>2007-04-15T09:32:46Z</time></trkpt><trkpt lat=\"48.8452568054199\" lon=\"2.25792765617371\"><ele>44.7996</ele><time>2007-04-15T09:32:47Z</time></trkpt><trkpt lat=\"48.8452911376953\" lon=\"2.25776290893555\"><ele>43.6396</ele><time>2007-04-15T09:32:48Z</time></trkpt><trkpt lat=\"48.8453216552734\" lon=\"2.25758171081543\"><ele>42.3702</ele><time>2007-04-15T09:32:49Z</time></trkpt><trkpt lat=\"48.8453407287598\" lon=\"2.25738143920898\"><ele>41.4629</ele><time>2007-04-15T09:32:50Z</time></trkpt><trkpt lat=\"48.845344543457\" lon=\"2.25716662406921\"><ele>40.8903</ele><time>2007-04-15T09:32:51Z</time></trkpt><trkpt lat=\"48.8453559875488\" lon=\"2.25692963600159\"><ele>40.2499</ele><time>2007-04-15T09:32:52Z</time></trkpt><trkpt lat=\"48.8453598022461\" lon=\"2.25674915313721\"><ele>39.7797</ele><time>2007-04-15T09:32:53Z</time></trkpt><trkpt lat=\"48.8453521728516\" lon=\"2.25660467147827\"><ele>39.4171</ele><time>2007-04-15T09:32:54Z</time></trkpt><trkpt lat=\"48.8453636169434\" lon=\"2.25639843940735\"><ele>38.8789</ele><time>2007-04-15T09:32:55Z</time></trkpt><trkpt lat=\"48.8453674316406\" lon=\"2.25615334510803\"><ele>38.2543</ele><time>2007-04-15T09:32:56Z</time></trkpt><trkpt lat=\"48.8453750610352\" lon=\"2.25595450401306\"><ele>37.7554</ele><time>2007-04-15T09:32:57Z</time></trkpt><trkpt lat=\"48.8453826904297\" lon=\"2.25579714775085\"><ele>37.3325</ele><time>2007-04-15T09:32:58Z</time></trkpt><trkpt lat=\"48.8453903198242\" lon=\"2.25564026832581\"><ele>36.788</ele><time>2007-04-15T09:32:59Z</time></trkpt><trkpt lat=\"48.845386505127\" lon=\"2.25557374954224\"><ele>36.5519</ele><time>2007-04-15T09:33:00Z</time></trkpt><trkpt lat=\"48.8453826904297\" lon=\"2.25536775588989\"><ele>35.8287</ele><time>2007-04-15T09:33:01Z</time></trkpt><trkpt lat=\"48.8453979492188\" lon=\"2.25517821311951\"><ele>35.1544</ele><time>2007-04-15T09:33:02Z</time></trkpt><trkpt lat=\"48.8454055786133\" lon=\"2.25500798225403\"><ele>34.5418</ele><time>2007-04-15T09:33:03Z</time></trkpt><trkpt lat=\"48.8454132080078\" lon=\"2.25472235679626\"><ele>34.3389</ele><time>2007-04-15T09:33:04Z</time></trkpt><trkpt lat=\"48.8454170227051\" lon=\"2.25455164909363\"><ele>34.2303</ele><time>2007-04-15T09:33:05Z</time></trkpt><trkpt lat=\"48.8454284667969\" lon=\"2.25441074371338\"><ele>34.1223</ele><time>2007-04-15T09:33:06Z</time></trkpt><trkpt lat=\"48.8454360961914\" lon=\"2.25419688224792\"><ele>33.9723</ele><time>2007-04-15T09:33:07Z</time></trkpt><trkpt lat=\"48.8454093933106\" lon=\"2.25393986701965\"><ele>34.2849</ele><time>2007-04-15T09:33:08Z</time></trkpt><trkpt lat=\"48.8454170227051\" lon=\"2.25377225875854\"><ele>34.4728</ele><time>2007-04-15T09:33:09Z</time></trkpt><trkpt lat=\"48.8454322814941\" lon=\"2.25365114212036\"><ele>34.6043</ele><time>2007-04-15T09:33:10Z</time></trkpt><trkpt lat=\"48.8454284667969\" lon=\"2.25355076789856\"><ele>34.7317</ele><time>2007-04-15T09:33:11Z</time></trkpt><trkpt lat=\"48.8454246520996\" lon=\"2.25340914726257\"><ele>34.9073</ele><time>2007-04-15T09:33:12Z</time></trkpt><trkpt lat=\"48.8454055786133\" lon=\"2.2532172203064\"><ele>35.4895</ele><time>2007-04-15T09:33:13Z</time></trkpt><trkpt lat=\"48.845386505127\" lon=\"2.25302529335022\"><ele>36.3071</ele><time>2007-04-15T09:33:14Z</time></trkpt><trkpt lat=\"48.8453826904297\" lon=\"2.2529182434082\"><ele>36.7637</ele><time>2007-04-15T09:33:15Z</time></trkpt><trkpt lat=\"48.8454513549805\" lon=\"2.2527003288269\"><ele>37.627</ele><time>2007-04-15T09:33:16Z</time></trkpt><trkpt lat=\"48.8454399108887\" lon=\"2.25256252288818\"><ele>38.2116</ele><time>2007-04-15T09:33:17Z</time></trkpt><trkpt lat=\"48.8454551696777\" lon=\"2.25235676765442\"><ele>38.4538</ele><time>2007-04-15T09:33:18Z</time></trkpt><trkpt lat=\"48.8454704284668\" lon=\"2.25217127799988\"><ele>38.4355</ele><time>2007-04-15T09:33:19Z</time></trkpt><trkpt lat=\"48.845458984375\" lon=\"2.25199127197266\"><ele>38.4492</ele><time>2007-04-15T09:33:20Z</time></trkpt><trkpt lat=\"48.8454513549805\" lon=\"2.25182127952576\"><ele>38.4584</ele><time>2007-04-15T09:33:21Z</time></trkpt><trkpt lat=\"48.845458984375\" lon=\"2.25162768363953\"><ele>38.4024</ele><time>2007-04-15T09:33:22Z</time></trkpt><trkpt lat=\"48.8454895019531\" lon=\"2.25147175788879\"><ele>38.1787</ele><time>2007-04-15T09:33:23Z</time></trkpt><trkpt lat=\"48.8455085754394\" lon=\"2.25130915641785\"><ele>37.9607</ele><time>2007-04-15T09:33:24Z</time></trkpt><trkpt lat=\"48.845516204834\" lon=\"2.25113534927368\"><ele>37.743</ele><time>2007-04-15T09:33:25Z</time></trkpt><trkpt lat=\"48.8455047607422\" lon=\"2.25093746185303\"><ele>37.5192</ele><time>2007-04-15T09:33:26Z</time></trkpt><trkpt lat=\"48.8455123901367\" lon=\"2.250812292099\"><ele>37.4104</ele><time>2007-04-15T09:33:27Z</time></trkpt><trkpt lat=\"48.845531463623\" lon=\"2.25066590309143\"><ele>37.5632</ele><time>2007-04-15T09:33:28Z</time></trkpt><trkpt lat=\"48.8455772399902\" lon=\"2.25047636032104\"><ele>37.7357</ele><time>2007-04-15T09:33:29Z</time></trkpt><trkpt lat=\"48.8456077575684\" lon=\"2.25033187866211\"><ele>37.8724</ele><time>2007-04-15T09:33:30Z</time></trkpt><trkpt lat=\"48.8456153869629\" lon=\"2.2502715587616\"><ele>37.9357</ele><time>2007-04-15T09:33:31Z</time></trkpt><trkpt lat=\"48.8456420898438\" lon=\"2.25005340576172\"><ele>38.1654</ele><time>2007-04-15T09:33:32Z</time></trkpt><trkpt lat=\"48.845703125\" lon=\"2.24980878829956\"><ele>38.3857</ele><time>2007-04-15T09:33:33Z</time></trkpt><trkpt lat=\"48.8457679748535\" lon=\"2.24960875511169\"><ele>38.5479</ele><time>2007-04-15T09:33:34Z</time></trkpt><trkpt lat=\"48.845817565918\" lon=\"2.24952578544617\"><ele>38.588</ele><time>2007-04-15T09:33:35Z</time></trkpt><trkpt lat=\"48.8458786010742\" lon=\"2.24935007095337\"><ele>38.6409</ele><time>2007-04-15T09:33:36Z</time></trkpt><trkpt lat=\"48.8459091186523\" lon=\"2.24917674064636\"><ele>38.7173</ele><time>2007-04-15T09:33:37Z</time></trkpt><trkpt lat=\"48.8459358215332\" lon=\"2.24905228614807\"><ele>39.0091</ele><time>2007-04-15T09:33:38Z</time></trkpt><trkpt lat=\"48.8459396362305\" lon=\"2.24891209602356\"><ele>39.4558</ele><time>2007-04-15T09:33:39Z</time></trkpt><trkpt lat=\"48.8459548950195\" lon=\"2.24883270263672\"><ele>39.6477</ele><time>2007-04-15T09:33:40Z</time></trkpt><trkpt lat=\"48.8459587097168\" lon=\"2.24865818023682\"><ele>40.1956</ele><time>2007-04-15T09:33:41Z</time></trkpt><trkpt lat=\"48.8460083007812\" lon=\"2.24852705001831\"><ele>40.3504</ele><time>2007-04-15T09:33:42Z</time></trkpt><trkpt lat=\"48.8460235595703\" lon=\"2.24850940704346\"><ele>40.3212</ele><time>2007-04-15T09:33:43Z</time></trkpt><trkpt lat=\"48.8460578918457\" lon=\"2.24843668937683\"><ele>40.3474</ele><time>2007-04-15T09:33:44Z</time></trkpt><trkpt lat=\"48.8460807800293\" lon=\"2.24835419654846\"><ele>40.4551</ele><time>2007-04-15T09:33:45Z</time></trkpt><trkpt lat=\"48.8461227416992\" lon=\"2.24820590019226\"><ele>40.3103</ele><time>2007-04-15T09:33:46Z</time></trkpt><trkpt lat=\"48.8461532592773\" lon=\"2.24806427955627\"><ele>40.1554</ele><time>2007-04-15T09:33:47Z</time></trkpt><trkpt lat=\"48.8461952209473\" lon=\"2.24795317649841\"><ele>39.8886</ele><time>2007-04-15T09:33:48Z</time></trkpt><trkpt lat=\"48.8462142944336\" lon=\"2.24788284301758\"><ele>39.7606</ele><time>2007-04-15T09:33:49Z</time></trkpt><trkpt lat=\"48.8462791442871\" lon=\"2.24764347076416\"><ele>39.2672</ele><time>2007-04-15T09:33:50Z</time></trkpt><trkpt lat=\"48.8463172912598\" lon=\"2.24749970436096\"><ele>38.935</ele><time>2007-04-15T09:33:51Z</time></trkpt><trkpt lat=\"48.8463439941406\" lon=\"2.2473304271698\"><ele>38.8351</ele><time>2007-04-15T09:33:52Z</time></trkpt><trkpt lat=\"48.8463668823242\" lon=\"2.24719047546387\"><ele>38.756</ele><time>2007-04-15T09:33:53Z</time></trkpt><trkpt lat=\"48.8463745117188\" lon=\"2.2470600605011\"><ele>38.7969</ele><time>2007-04-15T09:33:54Z</time></trkpt><trkpt lat=\"48.8463935852051\" lon=\"2.24696040153503\"><ele>38.7292</ele><time>2007-04-15T09:33:55Z</time></trkpt><trkpt lat=\"48.846435546875\" lon=\"2.24678993225098\"><ele>38.5572</ele><time>2007-04-15T09:33:56Z</time></trkpt><trkpt lat=\"48.8464698791504\" lon=\"2.24668860435486\"><ele>38.3968</ele><time>2007-04-15T09:33:57Z</time></trkpt><trkpt lat=\"48.8465270996094\" lon=\"2.24652862548828\"><ele>38.115</ele><time>2007-04-15T09:33:58Z</time></trkpt><trkpt lat=\"48.8465766906738\" lon=\"2.24634718894958\"><ele>37.9484</ele><time>2007-04-15T09:33:59Z</time></trkpt><trkpt lat=\"48.846622467041\" lon=\"2.24619603157043\"><ele>37.8231</ele><time>2007-04-15T09:34:00Z</time></trkpt><trkpt lat=\"48.8466682434082\" lon=\"2.24602961540222\"><ele>37.7626</ele><time>2007-04-15T09:34:01Z</time></trkpt><trkpt lat=\"48.8467407226562\" lon=\"2.24579691886902\"><ele>37.9509</ele><time>2007-04-15T09:34:02Z</time></trkpt><trkpt lat=\"48.8468017578125\" lon=\"2.245600938797\"><ele>38.0716</ele><time>2007-04-15T09:34:03Z</time></trkpt><trkpt lat=\"48.8468551635742\" lon=\"2.24540281295776\"><ele>38.1736</ele><time>2007-04-15T09:34:04Z</time></trkpt><trkpt lat=\"48.8469009399414\" lon=\"2.24522972106934\"><ele>38.2396</ele><time>2007-04-15T09:34:05Z</time></trkpt><trkpt lat=\"48.8469581604004\" lon=\"2.24502921104431\"><ele>38.2776</ele><time>2007-04-15T09:34:06Z</time></trkpt><trkpt lat=\"48.8469924926758\" lon=\"2.2448787689209\"><ele>38.0725</ele><time>2007-04-15T09:34:07Z</time></trkpt><trkpt lat=\"48.8470458984375\" lon=\"2.24464988708496\"><ele>37.6697</ele><time>2007-04-15T09:34:08Z</time></trkpt><trkpt lat=\"48.8470726013184\" lon=\"2.24443769454956\"><ele>37.351</ele><time>2007-04-15T09:34:09Z</time></trkpt><trkpt lat=\"48.847110748291\" lon=\"2.24426603317261\"><ele>37.0534</ele><time>2007-04-15T09:34:10Z</time></trkpt><trkpt lat=\"48.84716796875\" lon=\"2.24410915374756\"><ele>36.9349</ele><time>2007-04-15T09:34:11Z</time></trkpt><trkpt lat=\"48.8471908569336\" lon=\"2.24398136138916\"><ele>37.1867</ele><time>2007-04-15T09:34:12Z</time></trkpt><trkpt lat=\"48.8472290039062\" lon=\"2.24385976791382\"><ele>37.3869</ele><time>2007-04-15T09:34:13Z</time></trkpt><trkpt lat=\"48.8472633361816\" lon=\"2.2437424659729\"><ele>37.5861</ele><time>2007-04-15T09:34:14Z</time></trkpt><trkpt lat=\"48.8473320007324\" lon=\"2.24357342720032\"><ele>37.827</ele><time>2007-04-15T09:34:15Z</time></trkpt><trkpt lat=\"48.8473625183106\" lon=\"2.24344110488892\"><ele>38.0713</ele><time>2007-04-15T09:34:16Z</time></trkpt><trkpt lat=\"48.8474044799805\" lon=\"2.24326777458191\"><ele>38.3079</ele><time>2007-04-15T09:34:17Z</time></trkpt><trkpt lat=\"48.8474388122559\" lon=\"2.24313712120056\"><ele>38.3823</ele><time>2007-04-15T09:34:18Z</time></trkpt><trkpt lat=\"48.8474769592285\" lon=\"2.2429940700531\"><ele>38.4624</ele><time>2007-04-15T09:34:19Z</time></trkpt><trkpt lat=\"48.8475303649902\" lon=\"2.24276232719421\"><ele>38.6717</ele><time>2007-04-15T09:34:20Z</time></trkpt><trkpt lat=\"48.8475532531738\" lon=\"2.24270248413086\"><ele>38.7242</ele><time>2007-04-15T09:34:21Z</time></trkpt><trkpt lat=\"48.8475952148438\" lon=\"2.24261689186096\"><ele>38.7775</ele><time>2007-04-15T09:34:22Z</time></trkpt><trkpt lat=\"48.8476676940918\" lon=\"2.2424795627594\"><ele>38.7693</ele><time>2007-04-15T09:34:23Z</time></trkpt><trkpt lat=\"48.8477592468262\" lon=\"2.24237775802612\"><ele>38.4966</ele><time>2007-04-15T09:34:24Z</time></trkpt><trkpt lat=\"48.8478202819824\" lon=\"2.24236965179443\"><ele>38.3991</ele><time>2007-04-15T09:34:25Z</time></trkpt><trkpt lat=\"48.8479537963867\" lon=\"2.24257326126099\"><ele>38.4633</ele><time>2007-04-15T09:34:26Z</time></trkpt><trkpt lat=\"48.8480072021484\" lon=\"2.24273443222046\"><ele>38.4525</ele><time>2007-04-15T09:34:27Z</time></trkpt><trkpt lat=\"48.8480415344238\" lon=\"2.24293732643127\"><ele>38.5074</ele><time>2007-04-15T09:34:28Z</time></trkpt><trkpt lat=\"48.8480453491211\" lon=\"2.24310779571533\"><ele>38.5708</ele><time>2007-04-15T09:34:29Z</time></trkpt><trkpt lat=\"48.8480491638184\" lon=\"2.24329829216003\"><ele>38.6456</ele><time>2007-04-15T09:34:30Z</time></trkpt><trkpt lat=\"48.8480377197266\" lon=\"2.2435257434845\"><ele>38.1835</ele><time>2007-04-15T09:34:31Z</time></trkpt><trkpt lat=\"48.848030090332\" lon=\"2.24367141723633\"><ele>37.8247</ele><time>2007-04-15T09:34:32Z</time></trkpt><trkpt lat=\"48.848030090332\" lon=\"2.24381899833679\"><ele>37.4705</ele><time>2007-04-15T09:34:33Z</time></trkpt><trkpt lat=\"48.8480339050293\" lon=\"2.24391794204712\"><ele>37.2376</ele><time>2007-04-15T09:34:34Z</time></trkpt><trkpt lat=\"48.8480491638184\" lon=\"2.24403429031372\"><ele>36.9767</ele><time>2007-04-15T09:34:35Z</time></trkpt><trkpt lat=\"48.8480529785156\" lon=\"2.2441713809967\"><ele>36.6617</ele><time>2007-04-15T09:34:36Z</time></trkpt><trkpt lat=\"48.8480453491211\" lon=\"2.24436473846436\"><ele>36.581</ele><time>2007-04-15T09:34:37Z</time></trkpt><trkpt lat=\"48.8480453491211\" lon=\"2.24447751045227\"><ele>36.5392</ele><time>2007-04-15T09:34:38Z</time></trkpt><trkpt lat=\"48.8480339050293\" lon=\"2.24466967582703\"><ele>36.4708</ele><time>2007-04-15T09:34:39Z</time></trkpt><trkpt lat=\"48.8480339050293\" lon=\"2.24483489990234\"><ele>36.4151</ele><time>2007-04-15T09:34:40Z</time></trkpt><trkpt lat=\"48.8480262756348\" lon=\"2.24497675895691\"><ele>36.3758</ele><time>2007-04-15T09:34:41Z</time></trkpt><trkpt lat=\"48.8480262756348\" lon=\"2.24510598182678\"><ele>36.3685</ele><time>2007-04-15T09:34:42Z</time></trkpt><trkpt lat=\"48.8480262756348\" lon=\"2.24521398544312\"><ele>36.3685</ele><time>2007-04-15T09:34:43Z</time></trkpt><trkpt lat=\"48.8480262756348\" lon=\"2.24540567398071\"><ele>36.3685</ele><time>2007-04-15T09:34:44Z</time></trkpt><trkpt lat=\"48.848030090332\" lon=\"2.24550724029541\"><ele>36.3639</ele><time>2007-04-15T09:34:45Z</time></trkpt><trkpt lat=\"48.8480262756348\" lon=\"2.24557137489319\"><ele>36.3685</ele><time>2007-04-15T09:34:46Z</time></trkpt><trkpt lat=\"48.848030090332\" lon=\"2.24568128585815\"><ele>36.3639</ele><time>2007-04-15T09:34:47Z</time></trkpt><trkpt lat=\"48.8480072021484\" lon=\"2.24570465087891\"><ele>36.3914</ele><time>2007-04-15T09:34:48Z</time></trkpt><trkpt lat=\"48.8480033874512\" lon=\"2.24570941925049\"><ele>36.3959</ele><time>2007-04-15T09:34:49Z</time></trkpt><trkpt lat=\"48.8480033874512\" lon=\"2.24571776390076\"><ele>36.3959</ele><time>2007-04-15T09:34:50Z</time></trkpt><trkpt lat=\"48.848030090332\" lon=\"2.24633193016052\"><ele>36.9074</ele><time>2007-04-15T09:34:51Z</time></trkpt><trkpt lat=\"48.8480606079102\" lon=\"2.24649810791016\"><ele>37.1395</ele><time>2007-04-15T09:34:52Z</time></trkpt><trkpt lat=\"48.8480796813965\" lon=\"2.24664378166199\"><ele>37.3614</ele><time>2007-04-15T09:34:53Z</time></trkpt><trkpt lat=\"48.848087310791\" lon=\"2.24677038192749\"><ele>37.585</ele><time>2007-04-15T09:34:54Z</time></trkpt><trkpt lat=\"48.848087310791\" lon=\"2.24692702293396\"><ele>37.8499</ele><time>2007-04-15T09:34:55Z</time></trkpt><trkpt lat=\"48.8481063842773\" lon=\"2.24702286720276\"><ele>38.0774</ele><time>2007-04-15T09:34:56Z</time></trkpt><trkpt lat=\"48.8481063842773\" lon=\"2.24713754653931\"><ele>38.2777</ele><time>2007-04-15T09:34:57Z</time></trkpt><trkpt lat=\"48.8481025695801\" lon=\"2.24733114242554\"><ele>38.5993</ele><time>2007-04-15T09:34:58Z</time></trkpt><trkpt lat=\"48.848087310791\" lon=\"2.24752926826477\"><ele>38.875</ele><time>2007-04-15T09:34:59Z</time></trkpt><trkpt lat=\"48.848087310791\" lon=\"2.24756360054016\"><ele>38.9405</ele><time>2007-04-15T09:35:00Z</time></trkpt><trkpt lat=\"48.848087310791\" lon=\"2.24771618843079\"><ele>39.2317</ele><time>2007-04-15T09:35:01Z</time></trkpt><trkpt lat=\"48.8480911254883\" lon=\"2.24786472320557\"><ele>39.5295</ele><time>2007-04-15T09:35:02Z</time></trkpt><trkpt lat=\"48.8480911254883\" lon=\"2.24788331985474\"><ele>39.5648</ele><time>2007-04-15T09:35:03Z</time></trkpt><trkpt lat=\"48.8480758666992\" lon=\"2.24809145927429\"><ele>39.9125</ele><time>2007-04-15T09:35:04Z</time></trkpt><trkpt lat=\"48.8480758666992\" lon=\"2.24821877479553\"><ele>40.1597</ele><time>2007-04-15T09:35:05Z</time></trkpt><trkpt lat=\"48.8480796813965\" lon=\"2.24841737747192\"><ele>40.3605</ele><time>2007-04-15T09:35:06Z</time></trkpt><trkpt lat=\"48.8480834960938\" lon=\"2.24863696098328\"><ele>40.2912</ele><time>2007-04-15T09:35:07Z</time></trkpt><trkpt lat=\"48.848087310791\" lon=\"2.24887228012085\"><ele>40.2186</ele><time>2007-04-15T09:35:08Z</time></trkpt><trkpt lat=\"48.848072052002\" lon=\"2.24909400939941\"><ele>40.0867</ele><time>2007-04-15T09:35:09Z</time></trkpt><trkpt lat=\"48.8480644226074\" lon=\"2.24927306175232\"><ele>40.1184</ele><time>2007-04-15T09:35:10Z</time></trkpt><trkpt lat=\"48.8480682373047\" lon=\"2.24944138526916\"><ele>40.2704</ele><time>2007-04-15T09:35:11Z</time></trkpt><trkpt lat=\"48.8480644226074\" lon=\"2.24964833259583\"><ele>40.4234</ele><time>2007-04-15T09:35:12Z</time></trkpt><trkpt lat=\"48.8480682373047\" lon=\"2.24984812736511\"><ele>40.6033</ele><time>2007-04-15T09:35:13Z</time></trkpt><trkpt lat=\"48.848072052002\" lon=\"2.25001978874207\"><ele>40.7444</ele><time>2007-04-15T09:35:14Z</time></trkpt><trkpt lat=\"48.8480606079102\" lon=\"2.25025200843811\"><ele>40.6854</ele><time>2007-04-15T09:35:15Z</time></trkpt><trkpt lat=\"48.8480453491211\" lon=\"2.25046372413635\"><ele>40.6381</ele><time>2007-04-15T09:35:16Z</time></trkpt><trkpt lat=\"48.8480415344238\" lon=\"2.25063610076904\"><ele>40.6379</ele><time>2007-04-15T09:35:17Z</time></trkpt><trkpt lat=\"48.8480491638184\" lon=\"2.25084924697876\"><ele>40.7033</ele><time>2007-04-15T09:35:18Z</time></trkpt><trkpt lat=\"48.8480491638184\" lon=\"2.25102925300598\"><ele>41.204</ele><time>2007-04-15T09:35:19Z</time></trkpt><trkpt lat=\"48.848030090332\" lon=\"2.25123357772827\"><ele>41.7274</ele><time>2007-04-15T09:35:20Z</time></trkpt><trkpt lat=\"48.8480377197266\" lon=\"2.25144863128662\"><ele>42.3365</ele><time>2007-04-15T09:35:21Z</time></trkpt><trkpt lat=\"48.848030090332\" lon=\"2.25170564651489\"><ele>42.9083</ele><time>2007-04-15T09:35:22Z</time></trkpt><trkpt lat=\"48.8480224609375\" lon=\"2.25187683105469\"><ele>42.8809</ele><time>2007-04-15T09:35:23Z</time></trkpt><trkpt lat=\"48.8480072021484\" lon=\"2.25205636024475\"><ele>42.8259</ele><time>2007-04-15T09:35:24Z</time></trkpt><trkpt lat=\"48.8479995727539\" lon=\"2.25230026245117\"><ele>42.7985</ele><time>2007-04-15T09:35:25Z</time></trkpt><trkpt lat=\"48.8479919433594\" lon=\"2.25257039070129\"><ele>42.6407</ele><time>2007-04-15T09:35:26Z</time></trkpt><trkpt lat=\"48.8479881286621\" lon=\"2.25276660919189\"><ele>42.2727</ele><time>2007-04-15T09:35:27Z</time></trkpt><trkpt lat=\"48.8479995727539\" lon=\"2.25297141075134\"><ele>41.8951</ele><time>2007-04-15T09:35:28Z</time></trkpt><trkpt lat=\"48.8480033874512\" lon=\"2.25313425064087\"><ele>41.5759</ele><time>2007-04-15T09:35:29Z</time></trkpt><trkpt lat=\"48.8479919433594\" lon=\"2.25336217880249\"><ele>41.317</ele><time>2007-04-15T09:35:30Z</time></trkpt><trkpt lat=\"48.8479919433594\" lon=\"2.25355386734009\"><ele>41.9017</ele><time>2007-04-15T09:35:31Z</time></trkpt><trkpt lat=\"48.8479843139648\" lon=\"2.25378608703613\"><ele>42.6077</ele><time>2007-04-15T09:35:32Z</time></trkpt><trkpt lat=\"48.8479843139648\" lon=\"2.25395107269287\"><ele>43.1001</ele><time>2007-04-15T09:35:33Z</time></trkpt><trkpt lat=\"48.8479804992676\" lon=\"2.25414872169495\"><ele>43.6768</ele><time>2007-04-15T09:35:34Z</time></trkpt><trkpt lat=\"48.8479881286621\" lon=\"2.25434827804565\"><ele>44.1402</ele><time>2007-04-15T09:35:35Z</time></trkpt><trkpt lat=\"48.8480072021484\" lon=\"2.2545759677887\"><ele>44.7228</ele><time>2007-04-15T09:35:36Z</time></trkpt><trkpt lat=\"48.8480110168457\" lon=\"2.25481271743774\"><ele>45.2659</ele><time>2007-04-15T09:35:37Z</time></trkpt><trkpt lat=\"48.8480110168457\" lon=\"2.25498008728027\"><ele>45.6354</ele><time>2007-04-15T09:35:38Z</time></trkpt><trkpt lat=\"48.8480110168457\" lon=\"2.25521802902222\"><ele>45.5608</ele><time>2007-04-15T09:35:39Z</time></trkpt><trkpt lat=\"48.8480033874512\" lon=\"2.25543212890625\"><ele>45.4085</ele><time>2007-04-15T09:35:40Z</time></trkpt><trkpt lat=\"48.8480033874512\" lon=\"2.25562715530396\"><ele>45.3111</ele><time>2007-04-15T09:35:41Z</time></trkpt><trkpt lat=\"48.8480072021484\" lon=\"2.2558581829071\"><ele>45.3028</ele><time>2007-04-15T09:35:42Z</time></trkpt><trkpt lat=\"48.8480033874512\" lon=\"2.25589323043823\"><ele>45.4117</ele><time>2007-04-15T09:35:43Z</time></trkpt><trkpt lat=\"48.8480072021484\" lon=\"2.25608801841736\"><ele>46.0942</ele><time>2007-04-15T09:35:44Z</time></trkpt><trkpt lat=\"48.848014831543\" lon=\"2.25628709793091\"><ele>46.8378</ele><time>2007-04-15T09:35:45Z</time></trkpt><trkpt lat=\"48.8480186462402\" lon=\"2.25652933120728\"><ele>47.7328</ele><time>2007-04-15T09:35:46Z</time></trkpt><trkpt lat=\"48.8479995727539\" lon=\"2.25677275657654\"><ele>47.5113</ele><time>2007-04-15T09:35:47Z</time></trkpt><trkpt lat=\"48.8480110168457\" lon=\"2.25697064399719\"><ele>46.7316</ele><time>2007-04-15T09:35:48Z</time></trkpt><trkpt lat=\"48.8480262756348\" lon=\"2.25718951225281\"><ele>45.8718</ele><time>2007-04-15T09:35:49Z</time></trkpt><trkpt lat=\"48.848072052002\" lon=\"2.25736045837402\"><ele>45.485</ele><time>2007-04-15T09:35:50Z</time></trkpt><trkpt lat=\"48.8481178283691\" lon=\"2.25757527351379\"><ele>45.3034</ele><time>2007-04-15T09:35:51Z</time></trkpt><trkpt lat=\"48.8481788635254\" lon=\"2.25777173042297\"><ele>46.089</ele><time>2007-04-15T09:35:52Z</time></trkpt><trkpt lat=\"48.8482284545898\" lon=\"2.25792956352234\"><ele>46.6994</ele><time>2007-04-15T09:35:53Z</time></trkpt><trkpt lat=\"48.8482933044434\" lon=\"2.2579939365387\"><ele>47.285</ele><time>2007-04-15T09:35:54Z</time></trkpt><trkpt lat=\"48.8484001159668\" lon=\"2.25799918174744\"><ele>47.7589</ele><time>2007-04-15T09:35:55Z</time></trkpt><trkpt lat=\"48.8485412597656\" lon=\"2.25788855552673\"><ele>47.7985</ele><time>2007-04-15T09:35:56Z</time></trkpt><trkpt lat=\"48.8486328125\" lon=\"2.25779414176941\"><ele>47.6278</ele><time>2007-04-15T09:35:57Z</time></trkpt><trkpt lat=\"48.8487243652344\" lon=\"2.25772905349731\"><ele>47.4505</ele><time>2007-04-15T09:35:58Z</time></trkpt><trkpt lat=\"48.8487396240234\" lon=\"2.25772547721863\"><ele>47.4426</ele><time>2007-04-15T09:35:59Z</time></trkpt><trkpt lat=\"48.8488311767578\" lon=\"2.25773763656616\"><ele>47.5396</ele><time>2007-04-15T09:36:00Z</time></trkpt><trkpt lat=\"48.8489379882812\" lon=\"2.25773477554321\"><ele>47.5782</ele><time>2007-04-15T09:36:01Z</time></trkpt><trkpt lat=\"48.8490333557129\" lon=\"2.25772714614868\"><ele>47.5774</ele><time>2007-04-15T09:36:02Z</time></trkpt><trkpt lat=\"48.8491554260254\" lon=\"2.25773882865906\"><ele>47.7137</ele><time>2007-04-15T09:36:03Z</time></trkpt><trkpt lat=\"48.8492622375488\" lon=\"2.25776720046997\"><ele>48.5016</ele><time>2007-04-15T09:36:04Z</time></trkpt><trkpt lat=\"48.8493576049805\" lon=\"2.25783491134644\"><ele>49.5099</ele><time>2007-04-15T09:36:05Z</time></trkpt><trkpt lat=\"48.8494491577148\" lon=\"2.25787711143494\"><ele>50.2889</ele><time>2007-04-15T09:36:06Z</time></trkpt><trkpt lat=\"48.8495254516602\" lon=\"2.25790333747864\"><ele>50.8621</ele><time>2007-04-15T09:36:07Z</time></trkpt><trkpt lat=\"48.8496475219727\" lon=\"2.25797891616821\"><ele>51.9155</ele><time>2007-04-15T09:36:08Z</time></trkpt><trkpt lat=\"48.8497314453125\" lon=\"2.25802683830261\"><ele>52.5742</ele><time>2007-04-15T09:36:09Z</time></trkpt><trkpt lat=\"48.8498191833496\" lon=\"2.25808262825012\"><ele>53.2507</ele><time>2007-04-15T09:36:10Z</time></trkpt><trkpt lat=\"48.8499069213867\" lon=\"2.25811648368835\"><ele>53.7971</ele><time>2007-04-15T09:36:11Z</time></trkpt><trkpt lat=\"48.8500022888184\" lon=\"2.25817131996155\"><ele>54.4206</ele><time>2007-04-15T09:36:12Z</time></trkpt><trkpt lat=\"48.8500595092773\" lon=\"2.25821018218994\"><ele>54.6492</ele><time>2007-04-15T09:36:13Z</time></trkpt><trkpt lat=\"48.850154876709\" lon=\"2.25826287269592\"><ele>54.9636</ele><time>2007-04-15T09:36:14Z</time></trkpt><trkpt lat=\"48.8502502441406\" lon=\"2.25831365585327\"><ele>55.2436</ele><time>2007-04-15T09:36:15Z</time></trkpt><trkpt lat=\"48.850341796875\" lon=\"2.25838279724121\"><ele>55.4695</ele><time>2007-04-15T09:36:16Z</time></trkpt><trkpt lat=\"48.8504333496094\" lon=\"2.25845646858215\"><ele>55.6678</ele><time>2007-04-15T09:36:17Z</time></trkpt><trkpt lat=\"48.8505516052246\" lon=\"2.25852966308594\"><ele>55.8975</ele><time>2007-04-15T09:36:18Z</time></trkpt><trkpt lat=\"48.8506927490234\" lon=\"2.25863409042358\"><ele>56.1922</ele><time>2007-04-15T09:36:19Z</time></trkpt><trkpt lat=\"48.850772857666\" lon=\"2.25869846343994\"><ele>56.3656</ele><time>2007-04-15T09:36:20Z</time></trkpt><trkpt lat=\"48.8508529663086\" lon=\"2.25875997543335\"><ele>56.4539</ele><time>2007-04-15T09:36:21Z</time></trkpt><trkpt lat=\"48.850959777832\" lon=\"2.25881814956665\"><ele>56.2397</ele><time>2007-04-15T09:36:22Z</time></trkpt><trkpt lat=\"48.8510551452637\" lon=\"2.25885915756226\"><ele>56.0702</ele><time>2007-04-15T09:36:23Z</time></trkpt><trkpt lat=\"48.8511390686035\" lon=\"2.25890493392944\"><ele>55.9733</ele><time>2007-04-15T09:36:24Z</time></trkpt><trkpt lat=\"48.8512229919434\" lon=\"2.25895071029663\"><ele>55.9097</ele><time>2007-04-15T09:36:25Z</time></trkpt><trkpt lat=\"48.8512992858887\" lon=\"2.2590160369873\"><ele>55.9569</ele><time>2007-04-15T09:36:26Z</time></trkpt><trkpt lat=\"48.8513145446777\" lon=\"2.25902342796326\"><ele>55.9529</ele><time>2007-04-15T09:36:27Z</time></trkpt><trkpt lat=\"48.8513870239258\" lon=\"2.25907373428345\"><ele>56.0018</ele><time>2007-04-15T09:36:28Z</time></trkpt><trkpt lat=\"48.8514022827148\" lon=\"2.25908350944519\"><ele>56.0131</ele><time>2007-04-15T09:36:29Z</time></trkpt><trkpt lat=\"48.8515548706055\" lon=\"2.25919032096863\"><ele>56.2477</ele><time>2007-04-15T09:36:30Z</time></trkpt><trkpt lat=\"48.8517036437988\" lon=\"2.25929188728333\"><ele>56.3482</ele><time>2007-04-15T09:36:31Z</time></trkpt><trkpt lat=\"48.851863861084\" lon=\"2.25939893722534\"><ele>55.827</ele><time>2007-04-15T09:36:32Z</time></trkpt><trkpt lat=\"48.8519897460938\" lon=\"2.25944399833679\"><ele>55.2631</ele><time>2007-04-15T09:36:33Z</time></trkpt><trkpt lat=\"48.8520889282227\" lon=\"2.25950980186462\"><ele>55.0241</ele><time>2007-04-15T09:36:34Z</time></trkpt><trkpt lat=\"48.8521766662598\" lon=\"2.25959491729736\"><ele>55.0126</ele><time>2007-04-15T09:36:35Z</time></trkpt><trkpt lat=\"48.8522796630859\" lon=\"2.25967717170715\"><ele>54.9381</ele><time>2007-04-15T09:36:36Z</time></trkpt><trkpt lat=\"48.8524322509766\" lon=\"2.25974655151367\"><ele>54.5498</ele><time>2007-04-15T09:36:37Z</time></trkpt><trkpt lat=\"48.8525238037109\" lon=\"2.25980234146118\"><ele>54.619</ele><time>2007-04-15T09:36:38Z</time></trkpt><trkpt lat=\"48.8526191711426\" lon=\"2.25984477996826\"><ele>55.0787</ele><time>2007-04-15T09:36:39Z</time></trkpt><trkpt lat=\"48.8527336120606\" lon=\"2.25992918014526\"><ele>55.8181</ele><time>2007-04-15T09:36:40Z</time></trkpt><trkpt lat=\"48.852840423584\" lon=\"2.26001286506653\"><ele>56.4296</ele><time>2007-04-15T09:36:41Z</time></trkpt><trkpt lat=\"48.8529167175293\" lon=\"2.26005411148071\"><ele>56.565</ele><time>2007-04-15T09:36:42Z</time></trkpt><trkpt lat=\"48.8530311584473\" lon=\"2.26013398170471\"><ele>56.7098</ele><time>2007-04-15T09:36:43Z</time></trkpt><trkpt lat=\"48.8531723022461\" lon=\"2.26020526885986\"><ele>56.7508</ele><time>2007-04-15T09:36:44Z</time></trkpt><trkpt lat=\"48.8532791137695\" lon=\"2.26027154922485\"><ele>56.6939</ele><time>2007-04-15T09:36:45Z</time></trkpt><trkpt lat=\"48.8533706665039\" lon=\"2.26031875610352\"><ele>56.4001</ele><time>2007-04-15T09:36:46Z</time></trkpt><trkpt lat=\"48.8535118103027\" lon=\"2.26042008399963\"><ele>55.5348</ele><time>2007-04-15T09:36:47Z</time></trkpt><trkpt lat=\"48.8535461425781\" lon=\"2.26044273376465\"><ele>55.3435</ele><time>2007-04-15T09:36:48Z</time></trkpt><trkpt lat=\"48.8536376953125\" lon=\"2.26051092147827\"><ele>54.8673</ele><time>2007-04-15T09:36:49Z</time></trkpt><trkpt lat=\"48.8537445068359\" lon=\"2.26058912277222\"><ele>54.379</ele><time>2007-04-15T09:36:50Z</time></trkpt><trkpt lat=\"48.853874206543\" lon=\"2.26068615913391\"><ele>53.8856</ele><time>2007-04-15T09:36:51Z</time></trkpt><trkpt lat=\"48.8539886474609\" lon=\"2.26076102256775\"><ele>53.5229</ele><time>2007-04-15T09:36:52Z</time></trkpt><trkpt lat=\"48.8541221618652\" lon=\"2.26082563400269\"><ele>53.1432</ele><time>2007-04-15T09:36:53Z</time></trkpt><trkpt lat=\"48.8542213439941\" lon=\"2.26089358329773\"><ele>53.2083</ele><time>2007-04-15T09:36:54Z</time></trkpt><trkpt lat=\"48.8543395996094\" lon=\"2.26097273826599\"><ele>53.617</ele><time>2007-04-15T09:36:55Z</time></trkpt><trkpt lat=\"48.8544273376465\" lon=\"2.26103258132935\"><ele>53.9395</ele><time>2007-04-15T09:36:56Z</time></trkpt><trkpt lat=\"48.8545379638672\" lon=\"2.26109933853149\"><ele>54.3525</ele><time>2007-04-15T09:36:57Z</time></trkpt><trkpt lat=\"48.8545761108398\" lon=\"2.26112723350525\"><ele>54.5086</ele><time>2007-04-15T09:36:58Z</time></trkpt><trkpt lat=\"48.854606628418\" lon=\"2.26118421554565\"><ele>54.6993</ele><time>2007-04-15T09:36:59Z</time></trkpt><trkpt lat=\"48.8547477722168\" lon=\"2.26128220558166\"><ele>55.3089</ele><time>2007-04-15T09:37:00Z</time></trkpt><trkpt lat=\"48.854850769043\" lon=\"2.26132798194885\"><ele>55.7227</ele><time>2007-04-15T09:37:01Z</time></trkpt><trkpt lat=\"48.8549728393555\" lon=\"2.2613959312439\"><ele>56.263</ele><time>2007-04-15T09:37:02Z</time></trkpt><trkpt lat=\"48.855110168457\" lon=\"2.26147294044495\"><ele>56.3014</ele><time>2007-04-15T09:37:03Z</time></trkpt><trkpt lat=\"48.855224609375\" lon=\"2.26156377792358\"><ele>56.2473</ele><time>2007-04-15T09:37:04Z</time></trkpt><trkpt lat=\"48.8552360534668\" lon=\"2.26156663894653\"><ele>56.2274</ele><time>2007-04-15T09:37:05Z</time></trkpt><trkpt lat=\"48.8553047180176\" lon=\"2.2616069316864\"><ele>56.1515</ele><time>2007-04-15T09:37:06Z</time></trkpt><trkpt lat=\"48.8553314208984\" lon=\"2.26162147521973\"><ele>56.1177</ele><time>2007-04-15T09:37:07Z</time></trkpt><trkpt lat=\"48.85546875\" lon=\"2.26169872283936\"><ele>55.8678</ele><time>2007-04-15T09:37:08Z</time></trkpt><trkpt lat=\"48.8555717468262\" lon=\"2.2617654800415\"><ele>55.6789</ele><time>2007-04-15T09:37:09Z</time></trkpt><trkpt lat=\"48.8556900024414\" lon=\"2.26180243492126\"><ele>55.5297</ele><time>2007-04-15T09:37:10Z</time></trkpt><trkpt lat=\"48.8557777404785\" lon=\"2.26184892654419\"><ele>55.4979</ele><time>2007-04-15T09:37:11Z</time></trkpt><trkpt lat=\"48.8558959960938\" lon=\"2.26191401481628\"><ele>55.2623</ele><time>2007-04-15T09:37:12Z</time></trkpt><trkpt lat=\"48.8559188842773\" lon=\"2.26192474365234\"><ele>55.1697</ele><time>2007-04-15T09:37:13Z</time></trkpt><trkpt lat=\"48.8560028076172\" lon=\"2.26197552680969\"><ele>54.8752</ele><time>2007-04-15T09:37:14Z</time></trkpt><trkpt lat=\"48.8561401367188\" lon=\"2.26207637786865\"><ele>54.5045</ele><time>2007-04-15T09:37:15Z</time></trkpt><trkpt lat=\"48.8562126159668\" lon=\"2.26212096214294\"><ele>54.3109</ele><time>2007-04-15T09:37:16Z</time></trkpt><trkpt lat=\"48.8562850952148\" lon=\"2.26219320297241\"><ele>54.2382</ele><time>2007-04-15T09:37:17Z</time></trkpt><trkpt lat=\"48.856388092041\" lon=\"2.2622492313385\"><ele>54.0004</ele><time>2007-04-15T09:37:18Z</time></trkpt><trkpt lat=\"48.8564758300781\" lon=\"2.26230478286743\"><ele>53.8573</ele><time>2007-04-15T09:37:19Z</time></trkpt><trkpt lat=\"48.8565673828125\" lon=\"2.26236438751221\"><ele>53.7453</ele><time>2007-04-15T09:37:20Z</time></trkpt><trkpt lat=\"48.8566589355469\" lon=\"2.26240682601929\"><ele>53.5827</ele><time>2007-04-15T09:37:21Z</time></trkpt><trkpt lat=\"48.8567504882812\" lon=\"2.26245069503784\"><ele>53.8937</ele><time>2007-04-15T09:37:22Z</time></trkpt><trkpt lat=\"48.8568725585938\" lon=\"2.26252341270447\"><ele>54.2613</ele><time>2007-04-15T09:37:23Z</time></trkpt><trkpt lat=\"48.8569030761719\" lon=\"2.2625253200531\"><ele>54.2968</ele><time>2007-04-15T09:37:24Z</time></trkpt><trkpt lat=\"48.8570098876953\" lon=\"2.26255655288696\"><ele>54.4238</ele><time>2007-04-15T09:37:25Z</time></trkpt><trkpt lat=\"48.8571891784668\" lon=\"2.26260161399841\"><ele>54.596</ele><time>2007-04-15T09:37:26Z</time></trkpt><trkpt lat=\"48.8573150634766\" lon=\"2.26264715194702\"><ele>54.6799</ele><time>2007-04-15T09:37:27Z</time></trkpt><trkpt lat=\"48.8574180603027\" lon=\"2.26269102096558\"><ele>54.7175</ele><time>2007-04-15T09:37:28Z</time></trkpt><trkpt lat=\"48.8575019836426\" lon=\"2.26270866394043\"><ele>54.7383</ele><time>2007-04-15T09:37:29Z</time></trkpt><trkpt lat=\"48.857593536377\" lon=\"2.26275873184204\"><ele>54.1903</ele><time>2007-04-15T09:37:30Z</time></trkpt><trkpt lat=\"48.8576927185059\" lon=\"2.26279926300049\"><ele>53.6686</ele><time>2007-04-15T09:37:31Z</time></trkpt><trkpt lat=\"48.8577880859375\" lon=\"2.26282548904419\"><ele>53.2103</ele><time>2007-04-15T09:37:32Z</time></trkpt><trkpt lat=\"48.8578872680664\" lon=\"2.26275777816772\"><ele>52.6211</ele><time>2007-04-15T09:37:33Z</time></trkpt><trkpt lat=\"48.8579254150391\" lon=\"2.26262998580933\"><ele>52.1792</ele><time>2007-04-15T09:37:34Z</time></trkpt><trkpt lat=\"48.8579292297363\" lon=\"2.26259803771973\"><ele>52.0949</ele><time>2007-04-15T09:37:35Z</time></trkpt><trkpt lat=\"48.8579292297363\" lon=\"2.26257848739624\"><ele>52.0579</ele><time>2007-04-15T09:37:36Z</time></trkpt><trkpt lat=\"48.8579330444336\" lon=\"2.26256942749023\"><ele>52.0152</ele><time>2007-04-15T09:37:37Z</time></trkpt><trkpt lat=\"48.857967376709\" lon=\"2.26250600814819\"><ele>51.6479</ele><time>2007-04-15T09:37:38Z</time></trkpt><trkpt lat=\"48.8580131530762\" lon=\"2.2623610496521\"><ele>51.3694</ele><time>2007-04-15T09:37:39Z</time></trkpt><trkpt lat=\"48.8580627441406\" lon=\"2.26219534873962\"><ele>51.0669</ele><time>2007-04-15T09:37:40Z</time></trkpt><trkpt lat=\"48.8581085205078\" lon=\"2.2620165348053\"><ele>50.7752</ele><time>2007-04-15T09:37:41Z</time></trkpt><trkpt lat=\"48.858154296875\" lon=\"2.26184225082397\"><ele>50.4586</ele><time>2007-04-15T09:37:42Z</time></trkpt><trkpt lat=\"48.8582077026367\" lon=\"2.26167154312134\"><ele>50.0544</ele><time>2007-04-15T09:37:43Z</time></trkpt><trkpt lat=\"48.8582496643066\" lon=\"2.26143288612366\"><ele>50.0949</ele><time>2007-04-15T09:37:44Z</time></trkpt><trkpt lat=\"48.8582801818848\" lon=\"2.26129293441772\"><ele>50.1718</ele><time>2007-04-15T09:37:45Z</time></trkpt><trkpt lat=\"48.8583068847656\" lon=\"2.26119160652161\"><ele>50.2538</ele><time>2007-04-15T09:37:46Z</time></trkpt><trkpt lat=\"48.8583221435547\" lon=\"2.26099824905396\"><ele>50.6336</ele><time>2007-04-15T09:37:47Z</time></trkpt><trkpt lat=\"48.858341217041\" lon=\"2.26078581809998\"><ele>51.0927</ele><time>2007-04-15T09:37:48Z</time></trkpt><trkpt lat=\"48.8583602905273\" lon=\"2.26055312156677\"><ele>51.4221</ele><time>2007-04-15T09:37:49Z</time></trkpt><trkpt lat=\"48.8583831787109\" lon=\"2.26037406921387\"><ele>51.6585</ele><time>2007-04-15T09:37:50Z</time></trkpt><trkpt lat=\"48.8583908081055\" lon=\"2.26017212867737\"><ele>51.8504</ele><time>2007-04-15T09:37:51Z</time></trkpt><trkpt lat=\"48.8583908081055\" lon=\"2.26014447212219\"><ele>51.8745</ele><time>2007-04-15T09:37:52Z</time></trkpt><trkpt lat=\"48.8583526611328\" lon=\"2.26002407073975\"><ele>51.9738</ele><time>2007-04-15T09:37:53Z</time></trkpt><trkpt lat=\"48.8583526611328\" lon=\"2.25997853279114\"><ele>51.9994</ele><time>2007-04-15T09:37:54Z</time></trkpt><trkpt lat=\"48.8583221435547\" lon=\"2.25990462303162\"><ele>51.9731</ele><time>2007-04-15T09:37:55Z</time></trkpt><trkpt lat=\"48.8583106994629\" lon=\"2.259850025177\"><ele>51.9457</ele><time>2007-04-15T09:37:56Z</time></trkpt><trkpt lat=\"48.8582954406738\" lon=\"2.25985383987427\"><ele>51.9091</ele><time>2007-04-15T09:37:57Z</time></trkpt><trkpt lat=\"48.8582916259766\" lon=\"2.25984025001526\"><ele>51.8999</ele><time>2007-04-15T09:37:58Z</time></trkpt><trkpt lat=\"48.8582801818848\" lon=\"2.2598135471344\"><ele>51.8724</ele><time>2007-04-15T09:37:59Z</time></trkpt><trkpt lat=\"48.8583068847656\" lon=\"2.25980567932129\"><ele>51.9365</ele><time>2007-04-15T09:38:00Z</time></trkpt><trkpt lat=\"48.8583106994629\" lon=\"2.25981259346008\"><ele>51.9457</ele><time>2007-04-15T09:38:01Z</time></trkpt><trkpt lat=\"48.8583221435547\" lon=\"2.2598888874054\"><ele>51.9731</ele><time>2007-04-15T09:38:02Z</time></trkpt><trkpt lat=\"48.8583145141602\" lon=\"2.25984740257263\"><ele>51.9548</ele><time>2007-04-15T09:38:03Z</time></trkpt><trkpt lat=\"48.8583221435547\" lon=\"2.25984477996826\"><ele>51.9731</ele><time>2007-04-15T09:38:04Z</time></trkpt><trkpt lat=\"48.8583793640137\" lon=\"2.25982594490051\"><ele>51.9885</ele><time>2007-04-15T09:38:05Z</time></trkpt><trkpt lat=\"48.8584022521973\" lon=\"2.2597496509552\"><ele>51.9752</ele><time>2007-04-15T09:38:06Z</time></trkpt><trkpt lat=\"48.8583946228027\" lon=\"2.25954103469849\"><ele>51.9595</ele><time>2007-04-15T09:38:07Z</time></trkpt><trkpt lat=\"48.8583793640137\" lon=\"2.25934958457947\"><ele>51.9569</ele><time>2007-04-15T09:38:08Z</time></trkpt><trkpt lat=\"48.8583297729492\" lon=\"2.25921368598938\"><ele>51.9915</ele><time>2007-04-15T09:38:09Z</time></trkpt><trkpt lat=\"48.8582305908203\" lon=\"2.25901079177856\"><ele>51.7047</ele><time>2007-04-15T09:38:10Z</time></trkpt><trkpt lat=\"48.8581428527832\" lon=\"2.25887966156006\"><ele>51.6708</ele><time>2007-04-15T09:38:11Z</time></trkpt><trkpt lat=\"48.8580551147461\" lon=\"2.25877404212952\"><ele>51.8049</ele><time>2007-04-15T09:38:12Z</time></trkpt><trkpt lat=\"48.8579292297363\" lon=\"2.25867557525635\"><ele>52.1555</ele><time>2007-04-15T09:38:13Z</time></trkpt><trkpt lat=\"48.8577995300293\" lon=\"2.25856566429138\"><ele>52.7695</ele><time>2007-04-15T09:38:14Z</time></trkpt><trkpt lat=\"48.8576812744141\" lon=\"2.25846338272095\"><ele>53.5533</ele><time>2007-04-15T09:38:15Z</time></trkpt><trkpt lat=\"48.857551574707\" lon=\"2.25831007957458\"><ele>54.7593</ele><time>2007-04-15T09:38:16Z</time></trkpt><trkpt lat=\"48.8574447631836\" lon=\"2.25817823410034\"><ele>54.9337</ele><time>2007-04-15T09:38:17Z</time></trkpt><trkpt lat=\"48.8573226928711\" lon=\"2.2580680847168\"><ele>54.7872</ele><time>2007-04-15T09:38:18Z</time></trkpt><trkpt lat=\"48.8572044372559\" lon=\"2.25796818733215\"><ele>54.6453</ele><time>2007-04-15T09:38:19Z</time></trkpt><trkpt lat=\"48.8571090698242\" lon=\"2.25787448883057\"><ele>54.5309</ele><time>2007-04-15T09:38:20Z</time></trkpt><trkpt lat=\"48.8569869995117\" lon=\"2.2577965259552\"><ele>54.3844</ele><time>2007-04-15T09:38:21Z</time></trkpt><trkpt lat=\"48.856876373291\" lon=\"2.25776886940002\"><ele>54.2516</ele><time>2007-04-15T09:38:22Z</time></trkpt><trkpt lat=\"48.8567657470703\" lon=\"2.25775527954102\"><ele>54.1189</ele><time>2007-04-15T09:38:23Z</time></trkpt><trkpt lat=\"48.8566398620606\" lon=\"2.25773906707764\"><ele>53.8758</ele><time>2007-04-15T09:38:24Z</time></trkpt><trkpt lat=\"48.856517791748\" lon=\"2.25771641731262\"><ele>53.3249</ele><time>2007-04-15T09:38:25Z</time></trkpt><trkpt lat=\"48.8564147949219\" lon=\"2.25769925117493\"><ele>52.8765</ele><time>2007-04-15T09:38:26Z</time></trkpt><trkpt lat=\"48.856315612793\" lon=\"2.25767755508423\"><ele>52.4669</ele><time>2007-04-15T09:38:27Z</time></trkpt><trkpt lat=\"48.8562164306641\" lon=\"2.25766777992249\"><ele>52.0528</ele><time>2007-04-15T09:38:28Z</time></trkpt><trkpt lat=\"48.8560829162598\" lon=\"2.25765180587769\"><ele>51.5157</ele><time>2007-04-15T09:38:29Z</time></trkpt><trkpt lat=\"48.8560409545898\" lon=\"2.25764393806458\"><ele>51.3584</ele><time>2007-04-15T09:38:30Z</time></trkpt><trkpt lat=\"48.8559532165527\" lon=\"2.25757360458374\"><ele>51.2047</ele><time>2007-04-15T09:38:31Z</time></trkpt><trkpt lat=\"48.8559112548828\" lon=\"2.25755882263184\"><ele>51.0886</ele><time>2007-04-15T09:38:32Z</time></trkpt><trkpt lat=\"48.8557929992676\" lon=\"2.25749468803406\"><ele>50.9768</ele><time>2007-04-15T09:38:33Z</time></trkpt><trkpt lat=\"48.8556900024414\" lon=\"2.25743818283081\"><ele>51.112</ele><time>2007-04-15T09:38:34Z</time></trkpt><trkpt lat=\"48.8555679321289\" lon=\"2.2573516368866\"><ele>51.337</ele><time>2007-04-15T09:38:35Z</time></trkpt><trkpt lat=\"48.855411529541\" lon=\"2.25724244117737\"><ele>51.5737</ele><time>2007-04-15T09:38:36Z</time></trkpt><trkpt lat=\"48.8553047180176\" lon=\"2.25716638565063\"><ele>51.7131</ele><time>2007-04-15T09:38:37Z</time></trkpt><trkpt lat=\"48.8552169799805\" lon=\"2.25710034370422\"><ele>51.824</ele><time>2007-04-15T09:38:38Z</time></trkpt><trkpt lat=\"48.8550872802734\" lon=\"2.25701475143433\"><ele>51.9126</ele><time>2007-04-15T09:38:39Z</time></trkpt><trkpt lat=\"48.8550567626953\" lon=\"2.25698065757751\"><ele>51.9802</ele><time>2007-04-15T09:38:40Z</time></trkpt><trkpt lat=\"48.8550415039062\" lon=\"2.25696969032288\"><ele>51.9906</ele><time>2007-04-15T09:38:41Z</time></trkpt><trkpt lat=\"48.8550109863281\" lon=\"2.25695276260376\"><ele>51.9919</ele><time>2007-04-15T09:38:42Z</time></trkpt><trkpt lat=\"48.8549919128418\" lon=\"2.25693774223328\"><ele>52.0727</ele><time>2007-04-15T09:38:43Z</time></trkpt><trkpt lat=\"48.8549842834473\" lon=\"2.25691485404968\"><ele>52.2008</ele><time>2007-04-15T09:38:44Z</time></trkpt><trkpt lat=\"48.8549728393555\" lon=\"2.25691628456116\"><ele>52.2643</ele><time>2007-04-15T09:38:45Z</time></trkpt><trkpt lat=\"48.8549156188965\" lon=\"2.25692653656006\"><ele>52.5708</ele><time>2007-04-15T09:38:46Z</time></trkpt><trkpt lat=\"48.8548126220703\" lon=\"2.25692176818848\"><ele>53.2059</ele><time>2007-04-15T09:38:47Z</time></trkpt><trkpt lat=\"48.8546714782715\" lon=\"2.25690007209778\"><ele>54.1309</ele><time>2007-04-15T09:38:48Z</time></trkpt><trkpt lat=\"48.8545379638672\" lon=\"2.25688219070435\"><ele>54.9963</ele><time>2007-04-15T09:38:49Z</time></trkpt><trkpt lat=\"48.8544120788574\" lon=\"2.25682210922241\"><ele>55.9679</ele><time>2007-04-15T09:38:50Z</time></trkpt><trkpt lat=\"48.8543281555176\" lon=\"2.25666046142578\"><ele>57.0433</ele><time>2007-04-15T09:38:51Z</time></trkpt><trkpt lat=\"48.8542785644531\" lon=\"2.25646471977234\"><ele>57.8278</ele><time>2007-04-15T09:38:52Z</time></trkpt><trkpt lat=\"48.8542747497559\" lon=\"2.25625205039978\"><ele>58.3924</ele><time>2007-04-15T09:38:53Z</time></trkpt><trkpt lat=\"48.8543395996094\" lon=\"2.25602698326111\"><ele>58.1502</ele><time>2007-04-15T09:38:54Z</time></trkpt><trkpt lat=\"48.8544387817383\" lon=\"2.25588345527649\"><ele>57.0386</ele><time>2007-04-15T09:38:55Z</time></trkpt><trkpt lat=\"48.8545608520508\" lon=\"2.25577425956726\"><ele>55.1446</ele><time>2007-04-15T09:38:56Z</time></trkpt><trkpt lat=\"48.8547019958496\" lon=\"2.25570702552795\"><ele>52.9339</ele><time>2007-04-15T09:38:57Z</time></trkpt><trkpt lat=\"48.8548431396484\" lon=\"2.25569581985474\"><ele>50.8977</ele><time>2007-04-15T09:38:58Z</time></trkpt><trkpt lat=\"48.8549728393555\" lon=\"2.25569343566895\"><ele>49.0499</ele><time>2007-04-15T09:38:59Z</time></trkpt><trkpt lat=\"48.8551063537598\" lon=\"2.25566339492798\"><ele>49.2303</ele><time>2007-04-15T09:39:00Z</time></trkpt><trkpt lat=\"48.8552169799805\" lon=\"2.25561261177063\"><ele>49.7721</ele><time>2007-04-15T09:39:01Z</time></trkpt><trkpt lat=\"48.8553161621094\" lon=\"2.25548243522644\"><ele>50.0548</ele><time>2007-04-15T09:39:02Z</time></trkpt><trkpt lat=\"48.8553237915039\" lon=\"2.2554566860199\"><ele>50.0388</ele><time>2007-04-15T09:39:03Z</time></trkpt><trkpt lat=\"48.8552589416504\" lon=\"2.25529980659485\"><ele>49.2732</ele><time>2007-04-15T09:39:04Z</time></trkpt><trkpt lat=\"48.8551483154297\" lon=\"2.2551372051239\"><ele>48.2192</ele><time>2007-04-15T09:39:05Z</time></trkpt><trkpt lat=\"48.8550682067871\" lon=\"2.25501418113708\"><ele>47.4433</ele><time>2007-04-15T09:39:06Z</time></trkpt><trkpt lat=\"48.8549919128418\" lon=\"2.25490617752075\"><ele>47.1002</ele><time>2007-04-15T09:39:07Z</time></trkpt><trkpt lat=\"48.8549499511719\" lon=\"2.25482416152954\"><ele>47.5846</ele><time>2007-04-15T09:39:08Z</time></trkpt><trkpt lat=\"48.8548393249512\" lon=\"2.25466394424438\"><ele>48.6544</ele><time>2007-04-15T09:39:09Z</time></trkpt><trkpt lat=\"48.8547325134277\" lon=\"2.2545108795166\"><ele>49.4004</ele><time>2007-04-15T09:39:10Z</time></trkpt><trkpt lat=\"48.8546829223633\" lon=\"2.25442719459534\"><ele>49.6162</ele><time>2007-04-15T09:39:11Z</time></trkpt><trkpt lat=\"48.854606628418\" lon=\"2.25432586669922\"><ele>49.9013</ele><time>2007-04-15T09:39:12Z</time></trkpt><trkpt lat=\"48.8545188903809\" lon=\"2.25420188903809\"><ele>50.0331</ele><time>2007-04-15T09:39:13Z</time></trkpt><trkpt lat=\"48.854434967041\" lon=\"2.25408840179443\"><ele>50.3838</ele><time>2007-04-15T09:39:14Z</time></trkpt><trkpt lat=\"48.854362487793\" lon=\"2.25399804115295\"><ele>50.7057</ele><time>2007-04-15T09:39:15Z</time></trkpt><trkpt lat=\"48.8542900085449\" lon=\"2.25389385223389\"><ele>50.8959</ele><time>2007-04-15T09:39:16Z</time></trkpt><trkpt lat=\"48.8542022705078\" lon=\"2.25381112098694\"><ele>51.0424</ele><time>2007-04-15T09:39:17Z</time></trkpt><trkpt lat=\"48.854076385498\" lon=\"2.25369310379028\"><ele>51.8533</ele><time>2007-04-15T09:39:18Z</time></trkpt><trkpt lat=\"48.8539848327637\" lon=\"2.25363302230835\"><ele>52.7443</ele><time>2007-04-15T09:39:19Z</time></trkpt><trkpt lat=\"48.8538589477539\" lon=\"2.25358772277832\"><ele>54.0777</ele><time>2007-04-15T09:39:20Z</time></trkpt><trkpt lat=\"48.8537292480469\" lon=\"2.2536187171936\"><ele>55.5744</ele><time>2007-04-15T09:39:21Z</time></trkpt><trkpt lat=\"48.8535995483398\" lon=\"2.25363063812256\"><ele>57.0334</ele><time>2007-04-15T09:39:22Z</time></trkpt><trkpt lat=\"48.8535118103027\" lon=\"2.25365400314331\"><ele>58.0231</ele><time>2007-04-15T09:39:23Z</time></trkpt><trkpt lat=\"48.8534393310547\" lon=\"2.25367021560669\"><ele>58.8309</ele><time>2007-04-15T09:39:24Z</time></trkpt><trkpt lat=\"48.8533210754394\" lon=\"2.25371599197388\"><ele>59.9932</ele><time>2007-04-15T09:39:25Z</time></trkpt><trkpt lat=\"48.8532180786133\" lon=\"2.25377440452576\"><ele>59.9268</ele><time>2007-04-15T09:39:26Z</time></trkpt><trkpt lat=\"48.8531265258789\" lon=\"2.2538104057312\"><ele>59.8579</ele><time>2007-04-15T09:39:27Z</time></trkpt><trkpt lat=\"48.8529586791992\" lon=\"2.25385332107544\"><ele>59.7195</ele><time>2007-04-15T09:39:28Z</time></trkpt><trkpt lat=\"48.8529396057129\" lon=\"2.25384926795959\"><ele>59.7075</ele><time>2007-04-15T09:39:29Z</time></trkpt><trkpt lat=\"48.8528633117676\" lon=\"2.25368595123291\"><ele>59.7613</ele><time>2007-04-15T09:39:30Z</time></trkpt><trkpt lat=\"48.8528747558594\" lon=\"2.25361084938049\"><ele>59.8167</ele><time>2007-04-15T09:39:31Z</time></trkpt><trkpt lat=\"48.8528861999512\" lon=\"2.25353813171387\"><ele>59.8681</ele><time>2007-04-15T09:39:32Z</time></trkpt><trkpt lat=\"48.8529243469238\" lon=\"2.2534167766571\"><ele>59.9509</ele><time>2007-04-15T09:39:33Z</time></trkpt><trkpt lat=\"48.852954864502\" lon=\"2.25316381454468\"><ele>59.205</ele><time>2007-04-15T09:39:34Z</time></trkpt><trkpt lat=\"48.8529891967773\" lon=\"2.25295400619507\"><ele>58.2585</ele><time>2007-04-15T09:39:35Z</time></trkpt><trkpt lat=\"48.8530158996582\" lon=\"2.25276303291321\"><ele>57.4255</ele><time>2007-04-15T09:39:36Z</time></trkpt><trkpt lat=\"48.8530654907227\" lon=\"2.25259447097778\"><ele>56.7701</ele><time>2007-04-15T09:39:37Z</time></trkpt><trkpt lat=\"48.8531227111816\" lon=\"2.25240302085876\"><ele>56.5815</ele><time>2007-04-15T09:39:38Z</time></trkpt><trkpt lat=\"48.8531532287598\" lon=\"2.25223135948181\"><ele>56.8204</ele><time>2007-04-15T09:39:39Z</time></trkpt><trkpt lat=\"48.8531761169434\" lon=\"2.25205636024475\"><ele>57.0546</ele><time>2007-04-15T09:39:40Z</time></trkpt><trkpt lat=\"48.8532295227051\" lon=\"2.25189518928528\"><ele>57.3862</ele><time>2007-04-15T09:39:41Z</time></trkpt><trkpt lat=\"48.8532524108887\" lon=\"2.25172877311707\"><ele>57.6414</ele><time>2007-04-15T09:39:42Z</time></trkpt><trkpt lat=\"48.8532943725586\" lon=\"2.25151515007019\"><ele>57.5046</ele><time>2007-04-15T09:39:43Z</time></trkpt><trkpt lat=\"48.853328704834\" lon=\"2.25136351585388\"><ele>57.2578</ele><time>2007-04-15T09:39:44Z</time></trkpt><trkpt lat=\"48.8533325195312\" lon=\"2.25121665000916\"><ele>56.9176</ele><time>2007-04-15T09:39:45Z</time></trkpt><trkpt lat=\"48.853343963623\" lon=\"2.25103712081909\"><ele>56.4605</ele><time>2007-04-15T09:39:46Z</time></trkpt><trkpt lat=\"48.8533363342285\" lon=\"2.25083589553833\"><ele>55.9989</ele><time>2007-04-15T09:39:47Z</time></trkpt><trkpt lat=\"48.8533096313477\" lon=\"2.25064015388489\"><ele>55.4795</ele><time>2007-04-15T09:39:48Z</time></trkpt><trkpt lat=\"48.8533020019531\" lon=\"2.2504358291626\"><ele>54.9708</ele><time>2007-04-15T09:39:49Z</time></trkpt><trkpt lat=\"48.8532943725586\" lon=\"2.2502613067627\"><ele>54.5336</ele><time>2007-04-15T09:39:50Z</time></trkpt><trkpt lat=\"48.8532791137695\" lon=\"2.25008845329285\"><ele>54.0822</ele><time>2007-04-15T09:39:51Z</time></trkpt><trkpt lat=\"48.8532485961914\" lon=\"2.24992489814758\"><ele>53.7966</ele><time>2007-04-15T09:39:52Z</time></trkpt><trkpt lat=\"48.8532180786133\" lon=\"2.24976682662964\"><ele>53.7234</ele><time>2007-04-15T09:39:53Z</time></trkpt><trkpt lat=\"48.8531951904297\" lon=\"2.24962401390076\"><ele>53.6685</ele><time>2007-04-15T09:39:54Z</time></trkpt><trkpt lat=\"48.8531723022461\" lon=\"2.24943828582764\"><ele>53.6135</ele><time>2007-04-15T09:39:55Z</time></trkpt><trkpt lat=\"48.853141784668\" lon=\"2.24923777580261\"><ele>53.5403</ele><time>2007-04-15T09:39:56Z</time></trkpt><trkpt lat=\"48.8531265258789\" lon=\"2.24918031692505\"><ele>53.5037</ele><time>2007-04-15T09:39:57Z</time></trkpt><trkpt lat=\"48.8530731201172\" lon=\"2.24897885322571\"><ele>53.6009</ele><time>2007-04-15T09:39:58Z</time></trkpt><trkpt lat=\"48.8530387878418\" lon=\"2.24880075454712\"><ele>53.7322</ele><time>2007-04-15T09:39:59Z</time></trkpt><trkpt lat=\"48.8530120849609\" lon=\"2.24864220619202\"><ele>53.8584</ele><time>2007-04-15T09:40:00Z</time></trkpt><trkpt lat=\"48.8529663085938\" lon=\"2.24841642379761\"><ele>54.0194</ele><time>2007-04-15T09:40:01Z</time></trkpt><trkpt lat=\"48.852912902832\" lon=\"2.24825620651245\"><ele>53.991</ele><time>2007-04-15T09:40:02Z</time></trkpt><trkpt lat=\"48.852897644043\" lon=\"2.24815726280212\"><ele>53.9543</ele><time>2007-04-15T09:40:03Z</time></trkpt><trkpt lat=\"48.8528900146484\" lon=\"2.24811840057373\"><ele>53.936</ele><time>2007-04-15T09:40:04Z</time></trkpt><trkpt lat=\"48.8528900146484\" lon=\"2.24808430671692\"><ele>53.936</ele><time>2007-04-15T09:40:05Z</time></trkpt><trkpt lat=\"48.8529777526856\" lon=\"2.248046875\"><ele>54.1466</ele><time>2007-04-15T09:40:06Z</time></trkpt><trkpt lat=\"48.8530693054199\" lon=\"2.24815821647644\"><ele>54.3663</ele><time>2007-04-15T09:40:07Z</time></trkpt><trkpt lat=\"48.8531188964844\" lon=\"2.24823665618896\"><ele>54.4854</ele><time>2007-04-15T09:40:08Z</time></trkpt><trkpt lat=\"48.8532028198242\" lon=\"2.24840259552002\"><ele>54.6037</ele><time>2007-04-15T09:40:09Z</time></trkpt><trkpt lat=\"48.8532905578613\" lon=\"2.24855947494507\"><ele>54.626</ele><time>2007-04-15T09:40:10Z</time></trkpt><trkpt lat=\"48.8533821105957\" lon=\"2.24865245819092\"><ele>54.6171</ele><time>2007-04-15T09:40:11Z</time></trkpt><trkpt lat=\"48.8534774780273\" lon=\"2.24876284599304\"><ele>54.4846</ele><time>2007-04-15T09:40:12Z</time></trkpt><trkpt lat=\"48.853588104248\" lon=\"2.24892354011536\"><ele>54.2918</ele><time>2007-04-15T09:40:13Z</time></trkpt><trkpt lat=\"48.8536148071289\" lon=\"2.24904608726501\"><ele>54.1447</ele><time>2007-04-15T09:40:14Z</time></trkpt><trkpt lat=\"48.853645324707\" lon=\"2.24914693832397\"><ele>54.0237</ele><time>2007-04-15T09:40:15Z</time></trkpt><trkpt lat=\"48.8536949157715\" lon=\"2.24921894073486\"><ele>53.9728</ele><time>2007-04-15T09:40:16Z</time></trkpt><trkpt lat=\"48.8538055419922\" lon=\"2.24937295913696\"><ele>53.8597</ele><time>2007-04-15T09:40:17Z</time></trkpt><trkpt lat=\"48.8538780212402\" lon=\"2.249516248703\"><ele>53.7258</ele><time>2007-04-15T09:40:18Z</time></trkpt><trkpt lat=\"48.8539352416992\" lon=\"2.24965929985046\"><ele>53.573</ele><time>2007-04-15T09:40:19Z</time></trkpt><trkpt lat=\"48.8540000915527\" lon=\"2.24977707862854\"><ele>53.4139</ele><time>2007-04-15T09:40:20Z</time></trkpt><trkpt lat=\"48.8540191650391\" lon=\"2.24981093406677\"><ele>53.3637</ele><time>2007-04-15T09:40:21Z</time></trkpt><trkpt lat=\"48.8541145324707\" lon=\"2.24994850158691\"><ele>53.1205</ele><time>2007-04-15T09:40:22Z</time></trkpt><trkpt lat=\"48.8541831970215\" lon=\"2.25004243850708\"><ele>53.0479</ele><time>2007-04-15T09:40:23Z</time></trkpt><trkpt lat=\"48.8542022705078\" lon=\"2.25007057189941\"><ele>53.0738</ele><time>2007-04-15T09:40:24Z</time></trkpt><trkpt lat=\"48.8542861938477\" lon=\"2.25019645690918\"><ele>53.1343</ele><time>2007-04-15T09:40:25Z</time></trkpt><trkpt lat=\"48.8543434143066\" lon=\"2.25026726722717\"><ele>53.1166</ele><time>2007-04-15T09:40:26Z</time></trkpt><trkpt lat=\"48.8544158935547\" lon=\"2.25037908554077\"><ele>53.0468</ele><time>2007-04-15T09:40:27Z</time></trkpt><trkpt lat=\"48.8544998168945\" lon=\"2.25052356719971\"><ele>52.8748</ele><time>2007-04-15T09:40:28Z</time></trkpt><trkpt lat=\"48.8545951843262\" lon=\"2.2506251335144\"><ele>52.5929</ele><time>2007-04-15T09:40:29Z</time></trkpt><trkpt lat=\"48.8546943664551\" lon=\"2.2507381439209\"><ele>52.2031</ele><time>2007-04-15T09:40:30Z</time></trkpt><trkpt lat=\"48.8547821044922\" lon=\"2.25084972381592\"><ele>51.8186</ele><time>2007-04-15T09:40:31Z</time></trkpt><trkpt lat=\"48.8548736572266\" lon=\"2.25096368789673\"><ele>51.744</ele><time>2007-04-15T09:40:32Z</time></trkpt><trkpt lat=\"48.8550224304199\" lon=\"2.25112748146057\"><ele>51.66</ele><time>2007-04-15T09:40:33Z</time></trkpt><trkpt lat=\"48.8551483154297\" lon=\"2.25124359130859\"><ele>51.6314</ele><time>2007-04-15T09:40:34Z</time></trkpt><trkpt lat=\"48.8552589416504\" lon=\"2.25136923789978\"><ele>51.5758</ele><time>2007-04-15T09:40:35Z</time></trkpt><trkpt lat=\"48.8553771972656\" lon=\"2.25147175788879\"><ele>51.386</ele><time>2007-04-15T09:40:36Z</time></trkpt><trkpt lat=\"48.8554916381836\" lon=\"2.25157356262207\"><ele>51.1385</ele><time>2007-04-15T09:40:37Z</time></trkpt><trkpt lat=\"48.8555564880371\" lon=\"2.25167036056519\"><ele>51.007</ele><time>2007-04-15T09:40:38Z</time></trkpt><trkpt lat=\"48.8556900024414\" lon=\"2.25177597999573\"><ele>50.8644</ele><time>2007-04-15T09:40:39Z</time></trkpt><trkpt lat=\"48.8558006286621\" lon=\"2.25191116333008\"><ele>50.9749</ele><time>2007-04-15T09:40:40Z</time></trkpt><trkpt lat=\"48.8559265136719\" lon=\"2.25200629234314\"><ele>51.2889</ele><time>2007-04-15T09:40:41Z</time></trkpt><trkpt lat=\"48.8559989929199\" lon=\"2.25209951400757\"><ele>51.6538</ele><time>2007-04-15T09:40:42Z</time></trkpt><trkpt lat=\"48.8560829162598\" lon=\"2.25219655036926\"><ele>52.0166</ele><time>2007-04-15T09:40:43Z</time></trkpt><trkpt lat=\"48.8561630249023\" lon=\"2.25224828720093\"><ele>52.2133</ele><time>2007-04-15T09:40:44Z</time></trkpt><trkpt lat=\"48.8563003540039\" lon=\"2.25233101844788\"><ele>52.5053</ele><time>2007-04-15T09:40:45Z</time></trkpt><trkpt lat=\"48.8564147949219\" lon=\"2.25244545936584\"><ele>52.8493</ele><time>2007-04-15T09:40:46Z</time></trkpt><trkpt lat=\"48.8565521240234\" lon=\"2.25259208679199\"><ele>52.5732</ele><time>2007-04-15T09:40:47Z</time></trkpt><trkpt lat=\"48.8566703796387\" lon=\"2.2527174949646\"><ele>51.9607</ele><time>2007-04-15T09:40:48Z</time></trkpt><trkpt lat=\"48.8567390441894\" lon=\"2.25282168388367\"><ele>51.59</ele><time>2007-04-15T09:40:49Z</time></trkpt><trkpt lat=\"48.8568115234375\" lon=\"2.25292491912842\"><ele>51.3149</ele><time>2007-04-15T09:40:50Z</time></trkpt><trkpt lat=\"48.8569412231445\" lon=\"2.25307559967041\"><ele>51.1474</ele><time>2007-04-15T09:40:51Z</time></trkpt><trkpt lat=\"48.8570365905762\" lon=\"2.2532172203064\"><ele>51.0856</ele><time>2007-04-15T09:40:52Z</time></trkpt><trkpt lat=\"48.8571166992188\" lon=\"2.25332093238831\"><ele>51.1875</ele><time>2007-04-15T09:40:53Z</time></trkpt><trkpt lat=\"48.8572158813477\" lon=\"2.25348424911499\"><ele>51.521</ele><time>2007-04-15T09:40:54Z</time></trkpt><trkpt lat=\"48.8572883605957\" lon=\"2.25359892845154\"><ele>51.6705</ele><time>2007-04-15T09:40:55Z</time></trkpt><trkpt lat=\"48.8573608398438\" lon=\"2.25375890731812\"><ele>51.6518</ele><time>2007-04-15T09:40:56Z</time></trkpt><trkpt lat=\"48.8574485778809\" lon=\"2.2539222240448\"><ele>51.5143</ele><time>2007-04-15T09:40:57Z</time></trkpt><trkpt lat=\"48.8574714660644\" lon=\"2.25397610664368\"><ele>51.426</ele><time>2007-04-15T09:40:58Z</time></trkpt><trkpt lat=\"48.8575439453125\" lon=\"2.25414848327637\"><ele>51.0941</ele><time>2007-04-15T09:40:59Z</time></trkpt><trkpt lat=\"48.8575973510742\" lon=\"2.25433468818665\"><ele>50.7371</ele><time>2007-04-15T09:41:00Z</time></trkpt><trkpt lat=\"48.8576469421387\" lon=\"2.25448203086853\"><ele>50.4862</ele><time>2007-04-15T09:41:01Z</time></trkpt><trkpt lat=\"48.8577270507812\" lon=\"2.25461673736572\"><ele>50.3394</ele><time>2007-04-15T09:41:02Z</time></trkpt><trkpt lat=\"48.8578071594238\" lon=\"2.25477433204651\"><ele>50.179</ele><time>2007-04-15T09:41:03Z</time></trkpt><trkpt lat=\"48.8578681945801\" lon=\"2.25494146347046\"><ele>49.9931</ele><time>2007-04-15T09:41:04Z</time></trkpt><trkpt lat=\"48.8579139709473\" lon=\"2.25508189201355\"><ele>49.9434</ele><time>2007-04-15T09:41:05Z</time></trkpt><trkpt lat=\"48.857982635498\" lon=\"2.25528812408447\"><ele>50.0676</ele><time>2007-04-15T09:41:06Z</time></trkpt><trkpt lat=\"48.8580474853516\" lon=\"2.25550031661987\"><ele>50.2965</ele><time>2007-04-15T09:41:07Z</time></trkpt><trkpt lat=\"48.8581008911133\" lon=\"2.25564694404602\"><ele>50.5688</ele><time>2007-04-15T09:41:08Z</time></trkpt><trkpt lat=\"48.8581619262695\" lon=\"2.25578665733337\"><ele>50.9501</ele><time>2007-04-15T09:41:09Z</time></trkpt><trkpt lat=\"48.8582534790039\" lon=\"2.25592136383057\"><ele>51.5006</ele><time>2007-04-15T09:41:10Z</time></trkpt><trkpt lat=\"48.8583106994629\" lon=\"2.25605750083923\"><ele>51.8496</ele><time>2007-04-15T09:41:11Z</time></trkpt><trkpt lat=\"48.8583602905273\" lon=\"2.25628304481506\"><ele>51.9528</ele><time>2007-04-15T09:41:12Z</time></trkpt><trkpt lat=\"48.8583984375\" lon=\"2.25650072097778\"><ele>51.9063</ele><time>2007-04-15T09:41:13Z</time></trkpt><trkpt lat=\"48.8584136962891\" lon=\"2.25669598579407\"><ele>52.0023</ele><time>2007-04-15T09:41:14Z</time></trkpt><trkpt lat=\"48.8584327697754\" lon=\"2.25692868232727\"><ele>52.7489</ele><time>2007-04-15T09:41:15Z</time></trkpt><trkpt lat=\"48.8584594726562\" lon=\"2.2571291923523\"><ele>53.3457</ele><time>2007-04-15T09:41:16Z</time></trkpt><trkpt lat=\"48.8584785461426\" lon=\"2.25733828544617\"><ele>53.9627</ele><time>2007-04-15T09:41:17Z</time></trkpt><trkpt lat=\"48.8585052490234\" lon=\"2.25754356384277\"><ele>54.2151</ele><time>2007-04-15T09:41:18Z</time></trkpt><trkpt lat=\"48.858528137207\" lon=\"2.25770282745361\"><ele>53.5527</ele><time>2007-04-15T09:41:19Z</time></trkpt><trkpt lat=\"48.8585472106934\" lon=\"2.25782895088196\"><ele>53.0563</ele><time>2007-04-15T09:41:20Z</time></trkpt><trkpt lat=\"48.8585548400879\" lon=\"2.25789165496826\"><ele>52.8223</ele><time>2007-04-15T09:41:21Z</time></trkpt><trkpt lat=\"48.8585739135742\" lon=\"2.25807929039001\"><ele>52.1561</ele><time>2007-04-15T09:41:22Z</time></trkpt><trkpt lat=\"48.8585968017578\" lon=\"2.25824475288391\"><ele>51.6069</ele><time>2007-04-15T09:41:23Z</time></trkpt><trkpt lat=\"48.8586196899414\" lon=\"2.25840544700623\"><ele>51.3707</ele><time>2007-04-15T09:41:24Z</time></trkpt><trkpt lat=\"48.8586502075195\" lon=\"2.25858068466187\"><ele>51.4513</ele><time>2007-04-15T09:41:25Z</time></trkpt><trkpt lat=\"48.8587188720703\" lon=\"2.25877904891968\"><ele>51.5026</ele><time>2007-04-15T09:41:26Z</time></trkpt><trkpt lat=\"48.8587913513184\" lon=\"2.25893807411194\"><ele>51.4776</ele><time>2007-04-15T09:41:27Z</time></trkpt><trkpt lat=\"48.8588600158691\" lon=\"2.25905442237854\"><ele>51.4035</ele><time>2007-04-15T09:41:28Z</time></trkpt><trkpt lat=\"48.8589515686035\" lon=\"2.25917911529541\"><ele>51.2692</ele><time>2007-04-15T09:41:29Z</time></trkpt><trkpt lat=\"48.859058380127\" lon=\"2.2592887878418\"><ele>51.2574</ele><time>2007-04-15T09:41:30Z</time></trkpt><trkpt lat=\"48.8591804504394\" lon=\"2.25939083099365\"><ele>51.2601</ele><time>2007-04-15T09:41:31Z</time></trkpt><trkpt lat=\"48.8593063354492\" lon=\"2.25947141647339\"><ele>51.2431</ele><time>2007-04-15T09:41:32Z</time></trkpt><trkpt lat=\"48.8594398498535\" lon=\"2.25955414772034\"><ele>51.1601</ele><time>2007-04-15T09:41:33Z</time></trkpt><trkpt lat=\"48.8595657348633\" lon=\"2.25961565971374\"><ele>51.0228</ele><time>2007-04-15T09:41:34Z</time></trkpt><trkpt lat=\"48.8596611022949\" lon=\"2.25967121124268\"><ele>50.887</ele><time>2007-04-15T09:41:35Z</time></trkpt><trkpt lat=\"48.859790802002\" lon=\"2.25971150398254\"><ele>50.6745</ele><time>2007-04-15T09:41:36Z</time></trkpt><trkpt lat=\"48.8599090576172\" lon=\"2.25973653793335\"><ele>50.4654</ele><time>2007-04-15T09:41:37Z</time></trkpt><trkpt lat=\"48.8600006103516\" lon=\"2.25975227355957\"><ele>50.2974</ele><time>2007-04-15T09:41:38Z</time></trkpt><trkpt lat=\"48.860034942627\" lon=\"2.25973629951477\"><ele>50.3186</ele><time>2007-04-15T09:41:39Z</time></trkpt><trkpt lat=\"48.8600425720215\" lon=\"2.25974106788635\"><ele>50.3142</ele><time>2007-04-15T09:41:40Z</time></trkpt><trkpt lat=\"48.8600578308106\" lon=\"2.25975060462952\"><ele>50.3064</ele><time>2007-04-15T09:41:41Z</time></trkpt><trkpt lat=\"48.8600997924805\" lon=\"2.25977492332458\"><ele>50.2928</ele><time>2007-04-15T09:41:42Z</time></trkpt><trkpt lat=\"48.8601150512695\" lon=\"2.25977659225464\"><ele>50.2951</ele><time>2007-04-15T09:41:43Z</time></trkpt><trkpt lat=\"48.8601226806641\" lon=\"2.25978064537048\"><ele>50.2942</ele><time>2007-04-15T09:41:44Z</time></trkpt><trkpt lat=\"48.8602333068848\" lon=\"2.25986909866333\"><ele>50.3051</ele><time>2007-04-15T09:41:45Z</time></trkpt><trkpt lat=\"48.8603210449219\" lon=\"2.25991010665894\"><ele>50.3685</ele><time>2007-04-15T09:41:46Z</time></trkpt><trkpt lat=\"48.8604125976562\" lon=\"2.25995659828186\"><ele>50.4698</ele><time>2007-04-15T09:41:47Z</time></trkpt><trkpt lat=\"48.8605194091797\" lon=\"2.26000475883484\"><ele>50.6233</ele><time>2007-04-15T09:41:48Z</time></trkpt><trkpt lat=\"48.8606376647949\" lon=\"2.26007413864136\"><ele>50.7652</ele><time>2007-04-15T09:41:49Z</time></trkpt><trkpt lat=\"48.8607635498047\" lon=\"2.26014733314514\"><ele>50.9163</ele><time>2007-04-15T09:41:50Z</time></trkpt><trkpt lat=\"48.8608512878418\" lon=\"2.26019859313965\"><ele>50.919</ele><time>2007-04-15T09:41:51Z</time></trkpt><trkpt lat=\"48.8609237670898\" lon=\"2.26028871536255\"><ele>50.6035</ele><time>2007-04-15T09:41:52Z</time></trkpt><trkpt lat=\"48.8610343933106\" lon=\"2.26040887832642\"><ele>50.1533</ele><time>2007-04-15T09:41:53Z</time></trkpt><trkpt lat=\"48.8611145019531\" lon=\"2.26052212715149\"><ele>49.8618</ele><time>2007-04-15T09:41:54Z</time></trkpt><trkpt lat=\"48.8612098693848\" lon=\"2.26065587997437\"><ele>49.5483</ele><time>2007-04-15T09:41:55Z</time></trkpt><trkpt lat=\"48.8613014221191\" lon=\"2.26078343391418\"><ele>49.2812</ele><time>2007-04-15T09:41:56Z</time></trkpt><trkpt lat=\"48.8614082336426\" lon=\"2.26095199584961\"><ele>48.8862</ele><time>2007-04-15T09:41:57Z</time></trkpt><trkpt lat=\"48.8614959716797\" lon=\"2.26110482215881\"><ele>48.5478</ele><time>2007-04-15T09:41:58Z</time></trkpt><trkpt lat=\"48.8615951538086\" lon=\"2.26124668121338\"><ele>48.2149</ele><time>2007-04-15T09:41:59Z</time></trkpt><trkpt lat=\"48.861701965332\" lon=\"2.26137590408325\"><ele>48.066</ele><time>2007-04-15T09:42:00Z</time></trkpt><trkpt lat=\"48.8618011474609\" lon=\"2.26151466369629\"><ele>48.4395</ele><time>2007-04-15T09:42:01Z</time></trkpt><trkpt lat=\"48.8619003295898\" lon=\"2.26166915893555\"><ele>49.1233</ele><time>2007-04-15T09:42:02Z</time></trkpt><trkpt lat=\"48.8619956970215\" lon=\"2.26181411743164\"><ele>49.7191</ele><time>2007-04-15T09:42:03Z</time></trkpt><trkpt lat=\"48.8621292114258\" lon=\"2.2618682384491\"><ele>50.4887</ele><time>2007-04-15T09:42:04Z</time></trkpt><trkpt lat=\"48.8622436523438\" lon=\"2.26190853118896\"><ele>51.1714</ele><time>2007-04-15T09:42:05Z</time></trkpt><trkpt lat=\"48.8623733520508\" lon=\"2.26195859909058\"><ele>51.9862</ele><time>2007-04-15T09:42:06Z</time></trkpt><trkpt lat=\"48.8625259399414\" lon=\"2.26199293136597\"><ele>52.6463</ele><time>2007-04-15T09:42:07Z</time></trkpt><trkpt lat=\"48.8626518249512\" lon=\"2.26200318336487\"><ele>52.0053</ele><time>2007-04-15T09:42:08Z</time></trkpt><trkpt lat=\"48.8628005981445\" lon=\"2.26199579238892\"><ele>51.2046</ele><time>2007-04-15T09:42:09Z</time></trkpt><trkpt lat=\"48.862907409668\" lon=\"2.26198196411133\"><ele>50.6162</ele><time>2007-04-15T09:42:10Z</time></trkpt><trkpt lat=\"48.8630599975586\" lon=\"2.26196503639221\"><ele>49.7875</ele><time>2007-04-15T09:42:11Z</time></trkpt><trkpt lat=\"48.8631896972656\" lon=\"2.26193714141846\"><ele>49.07</ele><time>2007-04-15T09:42:12Z</time></trkpt><trkpt lat=\"48.8633270263672\" lon=\"2.26191830635071\"><ele>48.3345</ele><time>2007-04-15T09:42:13Z</time></trkpt><trkpt lat=\"48.863468170166\" lon=\"2.26191854476929\"><ele>48.1894</ele><time>2007-04-15T09:42:14Z</time></trkpt><trkpt lat=\"48.8636436462402\" lon=\"2.26192593574524\"><ele>48.0546</ele><time>2007-04-15T09:42:15Z</time></trkpt><trkpt lat=\"48.8637809753418\" lon=\"2.26197361946106\"><ele>48.029</ele><time>2007-04-15T09:42:16Z</time></trkpt><trkpt lat=\"48.863899230957\" lon=\"2.26204705238342\"><ele>48.0874</ele><time>2007-04-15T09:42:17Z</time></trkpt><trkpt lat=\"48.8640174865723\" lon=\"2.26213884353638\"><ele>48.2108</ele><time>2007-04-15T09:42:18Z</time></trkpt><trkpt lat=\"48.8641471862793\" lon=\"2.26225638389587\"><ele>48.4222</ele><time>2007-04-15T09:42:19Z</time></trkpt><trkpt lat=\"48.8642616271973\" lon=\"2.26238489151001\"><ele>48.8182</ele><time>2007-04-15T09:42:20Z</time></trkpt><trkpt lat=\"48.8643913269043\" lon=\"2.26250290870666\"><ele>48.9921</ele><time>2007-04-15T09:42:21Z</time></trkpt><trkpt lat=\"48.8644943237305\" lon=\"2.26262903213501\"><ele>48.6294</ele><time>2007-04-15T09:42:22Z</time></trkpt><trkpt lat=\"48.8646125793457\" lon=\"2.2627477645874\"><ele>48.2463</ele><time>2007-04-15T09:42:23Z</time></trkpt><trkpt lat=\"48.8647193908691\" lon=\"2.26281595230103\"><ele>47.9902</ele><time>2007-04-15T09:42:24Z</time></trkpt><trkpt lat=\"48.864860534668\" lon=\"2.26292395591736\"><ele>47.5589</ele><time>2007-04-15T09:42:25Z</time></trkpt><trkpt lat=\"48.8649864196777\" lon=\"2.26299667358398\"><ele>47.2217</ele><time>2007-04-15T09:42:26Z</time></trkpt><trkpt lat=\"48.8651237487793\" lon=\"2.26305961608887\"><ele>46.5865</ele><time>2007-04-15T09:42:27Z</time></trkpt><trkpt lat=\"48.8652610778809\" lon=\"2.26311445236206\"><ele>45.864</ele><time>2007-04-15T09:42:28Z</time></trkpt><trkpt lat=\"48.8653984069824\" lon=\"2.26318430900574\"><ele>44.9661</ele><time>2007-04-15T09:42:29Z</time></trkpt><trkpt lat=\"48.8655586242676\" lon=\"2.26324534416199\"><ele>43.9185</ele><time>2007-04-15T09:42:30Z</time></trkpt><trkpt lat=\"48.8657035827637\" lon=\"2.26332211494446\"><ele>42.7087</ele><time>2007-04-15T09:42:31Z</time></trkpt><trkpt lat=\"48.8658218383789\" lon=\"2.26341247558594\"><ele>42.1475</ele><time>2007-04-15T09:42:32Z</time></trkpt><trkpt lat=\"48.8659248352051\" lon=\"2.26352548599243\"><ele>42.0363</ele><time>2007-04-15T09:42:33Z</time></trkpt><trkpt lat=\"48.8660430908203\" lon=\"2.26367211341858\"><ele>42.0054</ele><time>2007-04-15T09:42:34Z</time></trkpt><trkpt lat=\"48.8661346435547\" lon=\"2.26381945610046\"><ele>42.0711</ele><time>2007-04-15T09:42:35Z</time></trkpt><trkpt lat=\"48.866153717041\" lon=\"2.26384520530701\"><ele>42.0815</ele><time>2007-04-15T09:42:36Z</time></trkpt><trkpt lat=\"48.8662376403809\" lon=\"2.26399779319763\"><ele>42.2139</ele><time>2007-04-15T09:42:37Z</time></trkpt><trkpt lat=\"48.866325378418\" lon=\"2.26417207717896\"><ele>42.4405</ele><time>2007-04-15T09:42:38Z</time></trkpt><trkpt lat=\"48.8664131164551\" lon=\"2.26432919502258\"><ele>43.2964</ele><time>2007-04-15T09:42:39Z</time></trkpt><trkpt lat=\"48.8665084838867\" lon=\"2.26448488235474\"><ele>44.2635</ele><time>2007-04-15T09:42:40Z</time></trkpt><trkpt lat=\"48.8665924072266\" lon=\"2.26464462280273\"><ele>45.3771</ele><time>2007-04-15T09:42:41Z</time></trkpt><trkpt lat=\"48.86669921875\" lon=\"2.26477551460266\"><ele>46.4964</ele><time>2007-04-15T09:42:42Z</time></trkpt><trkpt lat=\"48.8668022155762\" lon=\"2.2648983001709\"><ele>47.5694</ele><time>2007-04-15T09:42:43Z</time></trkpt><trkpt lat=\"48.8669204711914\" lon=\"2.26501202583313\"><ele>48.2958</ele><time>2007-04-15T09:42:44Z</time></trkpt><trkpt lat=\"48.867015838623\" lon=\"2.26509928703308\"><ele>48.3192</ele><time>2007-04-15T09:42:45Z</time></trkpt><trkpt lat=\"48.867130279541\" lon=\"2.26519370079041\"><ele>48.2977</ele><time>2007-04-15T09:42:46Z</time></trkpt><trkpt lat=\"48.8672065734863\" lon=\"2.26526021957397\"><ele>48.2433</ele><time>2007-04-15T09:42:47Z</time></trkpt><trkpt lat=\"48.8672904968262\" lon=\"2.26532292366028\"><ele>48.1684</ele><time>2007-04-15T09:42:48Z</time></trkpt><trkpt lat=\"48.8673782348633\" lon=\"2.26539206504822\"><ele>48.0504</ele><time>2007-04-15T09:42:49Z</time></trkpt><trkpt lat=\"48.8674507141113\" lon=\"2.26544499397278\"><ele>47.936</ele><time>2007-04-15T09:42:50Z</time></trkpt><trkpt lat=\"48.8675537109375\" lon=\"2.26554012298584\"><ele>47.5294</ele><time>2007-04-15T09:42:51Z</time></trkpt><trkpt lat=\"48.8676681518555\" lon=\"2.26562166213989\"><ele>47.0019</ele><time>2007-04-15T09:42:52Z</time></trkpt><trkpt lat=\"48.8677864074707\" lon=\"2.26569390296936\"><ele>46.5322</ele><time>2007-04-15T09:42:53Z</time></trkpt><trkpt lat=\"48.8679428100586\" lon=\"2.26573538780212\"><ele>46.0474</ele><time>2007-04-15T09:42:54Z</time></trkpt><trkpt lat=\"48.8680992126465\" lon=\"2.26577663421631\"><ele>45.6001</ele><time>2007-04-15T09:42:55Z</time></trkpt><trkpt lat=\"48.8682403564453\" lon=\"2.26584196090698\"><ele>45.2622</ele><time>2007-04-15T09:42:56Z</time></trkpt><trkpt lat=\"48.8683776855469\" lon=\"2.26596808433533\"><ele>45.6226</ele><time>2007-04-15T09:42:57Z</time></trkpt><trkpt lat=\"48.8684577941894\" lon=\"2.2660927772522\"><ele>45.9762</ele><time>2007-04-15T09:42:58Z</time></trkpt><trkpt lat=\"48.8685455322266\" lon=\"2.26624846458435\"><ele>46.1056</ele><time>2007-04-15T09:42:59Z</time></trkpt><trkpt lat=\"48.8686332702637\" lon=\"2.26641726493835\"><ele>45.8929</ele><time>2007-04-15T09:43:00Z</time></trkpt><trkpt lat=\"48.8687210083008\" lon=\"2.266606092453\"><ele>45.2919</ele><time>2007-04-15T09:43:01Z</time></trkpt><trkpt lat=\"48.8687286376953\" lon=\"2.26663684844971\"><ele>45.2147</ele><time>2007-04-15T09:43:02Z</time></trkpt><trkpt lat=\"48.8687782287598\" lon=\"2.26681303977966\"><ele>44.9285</ele><time>2007-04-15T09:43:03Z</time></trkpt><trkpt lat=\"48.8688583374023\" lon=\"2.26697826385498\"><ele>44.5283</ele><time>2007-04-15T09:43:04Z</time></trkpt><trkpt lat=\"48.8689460754394\" lon=\"2.26711845397949\"><ele>44.1701</ele><time>2007-04-15T09:43:05Z</time></trkpt><trkpt lat=\"48.8690032958984\" lon=\"2.26723194122314\"><ele>44.0714</ele><time>2007-04-15T09:43:06Z</time></trkpt><trkpt lat=\"48.8690223693848\" lon=\"2.26729106903076\"><ele>44.1141</ele><time>2007-04-15T09:43:07Z</time></trkpt><trkpt lat=\"48.8691215515137\" lon=\"2.26751828193665\"><ele>44.2604</ele><time>2007-04-15T09:43:08Z</time></trkpt><trkpt lat=\"48.8692245483398\" lon=\"2.26771306991577\"><ele>44.4758</ele><time>2007-04-15T09:43:09Z</time></trkpt><trkpt lat=\"48.8692893981934\" lon=\"2.26786708831787\"><ele>44.7513</ele><time>2007-04-15T09:43:10Z</time></trkpt><trkpt lat=\"48.8693656921387\" lon=\"2.26802778244019\"><ele>44.9642</ele><time>2007-04-15T09:43:11Z</time></trkpt><trkpt lat=\"48.869457244873\" lon=\"2.26817154884338\"><ele>45.0497</ele><time>2007-04-15T09:43:12Z</time></trkpt><trkpt lat=\"48.8695335388184\" lon=\"2.26827955245972\"><ele>45.0473</ele><time>2007-04-15T09:43:13Z</time></trkpt><trkpt lat=\"48.8696212768555\" lon=\"2.26843166351318\"><ele>44.7802</ele><time>2007-04-15T09:43:14Z</time></trkpt><trkpt lat=\"48.8696556091309\" lon=\"2.26850938796997\"><ele>44.5786</ele><time>2007-04-15T09:43:15Z</time></trkpt><trkpt lat=\"48.8697662353516\" lon=\"2.26865029335022\"><ele>44.0137</ele><time>2007-04-15T09:43:16Z</time></trkpt><trkpt lat=\"48.8697853088379\" lon=\"2.268709897995\"><ele>43.8443</ele><time>2007-04-15T09:43:17Z</time></trkpt><trkpt lat=\"48.8698692321777\" lon=\"2.26888394355774\"><ele>43.1997</ele><time>2007-04-15T09:43:18Z</time></trkpt><trkpt lat=\"48.8699722290039\" lon=\"2.26900434494019\"><ele>42.5099</ele><time>2007-04-15T09:43:19Z</time></trkpt><trkpt lat=\"48.8700561523438\" lon=\"2.2691502571106\"><ele>42.441</ele><time>2007-04-15T09:43:20Z</time></trkpt><trkpt lat=\"48.8701362609863\" lon=\"2.26927781105042\"><ele>43.0926</ele><time>2007-04-15T09:43:21Z</time></trkpt><trkpt lat=\"48.8702201843262\" lon=\"2.26939487457275\"><ele>43.7868</ele><time>2007-04-15T09:43:22Z</time></trkpt><trkpt lat=\"48.8702926635742\" lon=\"2.26952266693115\"><ele>44.3843</ele><time>2007-04-15T09:43:23Z</time></trkpt><trkpt lat=\"48.8703384399414\" lon=\"2.26964998245239\"><ele>44.7812</ele><time>2007-04-15T09:43:24Z</time></trkpt><trkpt lat=\"48.8704032897949\" lon=\"2.269775390625\"><ele>45.2806</ele><time>2007-04-15T09:43:25Z</time></trkpt><trkpt lat=\"48.870418548584\" lon=\"2.26983284950256\"><ele>45.4115</ele><time>2007-04-15T09:43:26Z</time></trkpt><trkpt lat=\"48.8704719543457\" lon=\"2.26994013786316\"><ele>45.8006</ele><time>2007-04-15T09:43:27Z</time></trkpt><trkpt lat=\"48.8705215454102\" lon=\"2.27000880241394\"><ele>46.1319</ele><time>2007-04-15T09:43:28Z</time></trkpt><trkpt lat=\"48.8705787658691\" lon=\"2.27013564109802\"><ele>46.4454</ele><time>2007-04-15T09:43:29Z</time></trkpt><trkpt lat=\"48.8706474304199\" lon=\"2.27026104927063\"><ele>46.6774</ele><time>2007-04-15T09:43:30Z</time></trkpt><trkpt lat=\"48.8706588745117\" lon=\"2.2703001499176\"><ele>46.6853</ele><time>2007-04-15T09:43:31Z</time></trkpt><trkpt lat=\"48.8707084655762\" lon=\"2.27044796943665\"><ele>46.659</ele><time>2007-04-15T09:43:32Z</time></trkpt><trkpt lat=\"48.870777130127\" lon=\"2.27058148384094\"><ele>46.5496</ele><time>2007-04-15T09:43:33Z</time></trkpt><trkpt lat=\"48.8708305358887\" lon=\"2.27073550224304\"><ele>46.2358</ele><time>2007-04-15T09:43:34Z</time></trkpt><trkpt lat=\"48.8708801269531\" lon=\"2.27090668678284\"><ele>45.4435</ele><time>2007-04-15T09:43:35Z</time></trkpt><trkpt lat=\"48.870922088623\" lon=\"2.27104091644287\"><ele>44.8524</ele><time>2007-04-15T09:43:36Z</time></trkpt><trkpt lat=\"48.8709678649902\" lon=\"2.27114677429199\"><ele>44.4495</ele><time>2007-04-15T09:43:37Z</time></trkpt><trkpt lat=\"48.8710174560547\" lon=\"2.27129793167114\"><ele>44.1104</ele><time>2007-04-15T09:43:38Z</time></trkpt><trkpt lat=\"48.8710784912109\" lon=\"2.27145099639893\"><ele>43.9737</ele><time>2007-04-15T09:43:39Z</time></trkpt><trkpt lat=\"48.8711051940918\" lon=\"2.27158784866333\"><ele>43.9847</ele><time>2007-04-15T09:43:40Z</time></trkpt><trkpt lat=\"48.8711433410644\" lon=\"2.27177119255066\"><ele>44.3027</ele><time>2007-04-15T09:43:41Z</time></trkpt><trkpt lat=\"48.8711547851562\" lon=\"2.27189087867737\"><ele>44.5724</ele><time>2007-04-15T09:43:42Z</time></trkpt><trkpt lat=\"48.8711814880371\" lon=\"2.2719874382019\"><ele>44.8966</ele><time>2007-04-15T09:43:43Z</time></trkpt><trkpt lat=\"48.8711891174316\" lon=\"2.27216172218323\"><ele>45.2953</ele><time>2007-04-15T09:43:44Z</time></trkpt><trkpt lat=\"48.8711853027344\" lon=\"2.27236866950989\"><ele>45.6903</ele><time>2007-04-15T09:43:45Z</time></trkpt><trkpt lat=\"48.8712043762207\" lon=\"2.27250695228577\"><ele>46.1278</ele><time>2007-04-15T09:43:46Z</time></trkpt><trkpt lat=\"48.8712348937988\" lon=\"2.27275681495666\"><ele>46.7148</ele><time>2007-04-15T09:43:47Z</time></trkpt><trkpt lat=\"48.8712692260742\" lon=\"2.27293586730957\"><ele>47.1121</ele><time>2007-04-15T09:43:48Z</time></trkpt><trkpt lat=\"48.8713111877441\" lon=\"2.27313733100891\"><ele>47.4418</ele><time>2007-04-15T09:43:49Z</time></trkpt><trkpt lat=\"48.871337890625\" lon=\"2.27329969406128\"><ele>47.5906</ele><time>2007-04-15T09:43:50Z</time></trkpt><trkpt lat=\"48.8713760375977\" lon=\"2.27347302436829\"><ele>47.8266</ele><time>2007-04-15T09:43:51Z</time></trkpt><trkpt lat=\"48.8714065551758\" lon=\"2.27364706993103\"><ele>48.0404</ele><time>2007-04-15T09:43:52Z</time></trkpt><trkpt lat=\"48.8714408874512\" lon=\"2.27381634712219\"><ele>48.2002</ele><time>2007-04-15T09:43:53Z</time></trkpt><trkpt lat=\"48.871452331543\" lon=\"2.2739884853363\"><ele>48.3494</ele><time>2007-04-15T09:43:54Z</time></trkpt><trkpt lat=\"48.8714332580566\" lon=\"2.27406001091003\"><ele>48.4526</ele><time>2007-04-15T09:43:55Z</time></trkpt><trkpt lat=\"48.8714027404785\" lon=\"2.27417206764221\"><ele>48.6293</ele><time>2007-04-15T09:43:56Z</time></trkpt><trkpt lat=\"48.8713569641113\" lon=\"2.27434539794922\"><ele>48.5839</ele><time>2007-04-15T09:43:57Z</time></trkpt><trkpt lat=\"48.8713073730469\" lon=\"2.27453136444092\"><ele>48.4849</ele><time>2007-04-15T09:43:58Z</time></trkpt><trkpt lat=\"48.8712387084961\" lon=\"2.27471280097961\"><ele>48.354</ele><time>2007-04-15T09:43:59Z</time></trkpt><trkpt lat=\"48.8711967468262\" lon=\"2.27488327026367\"><ele>48.158</ele><time>2007-04-15T09:44:00Z</time></trkpt><trkpt lat=\"48.871166229248\" lon=\"2.27507400512695\"><ele>48.4269</ele><time>2007-04-15T09:44:01Z</time></trkpt><trkpt lat=\"48.8712043762207\" lon=\"2.27530479431152\"><ele>49.5405</ele><time>2007-04-15T09:44:02Z</time></trkpt><trkpt lat=\"48.8712272644043\" lon=\"2.27536368370056\"><ele>49.6823</ele><time>2007-04-15T09:44:03Z</time></trkpt><trkpt lat=\"48.8713073730469\" lon=\"2.27552676200867\"><ele>49.6466</ele><time>2007-04-15T09:44:04Z</time></trkpt><trkpt lat=\"48.871410369873\" lon=\"2.27567887306213\"><ele>48.8132</ele><time>2007-04-15T09:44:05Z</time></trkpt><trkpt lat=\"48.8715019226074\" lon=\"2.27581000328064\"><ele>47.582</ele><time>2007-04-15T09:44:06Z</time></trkpt><trkpt lat=\"48.8716011047363\" lon=\"2.27596020698547\"><ele>45.9184</ele><time>2007-04-15T09:44:07Z</time></trkpt><trkpt lat=\"48.8716812133789\" lon=\"2.2761082649231\"><ele>44.6874</ele><time>2007-04-15T09:44:08Z</time></trkpt><trkpt lat=\"48.8717155456543\" lon=\"2.27635836601257\"><ele>44.4808</ele><time>2007-04-15T09:44:09Z</time></trkpt><trkpt lat=\"48.8717460632324\" lon=\"2.27650499343872\"><ele>44.4244</ele><time>2007-04-15T09:44:10Z</time></trkpt><trkpt lat=\"48.8718032836914\" lon=\"2.27679800987244\"><ele>45.0138</ele><time>2007-04-15T09:44:11Z</time></trkpt><trkpt lat=\"48.8718414306641\" lon=\"2.27697205543518\"><ele>45.9769</ele><time>2007-04-15T09:44:12Z</time></trkpt><trkpt lat=\"48.8718681335449\" lon=\"2.27716088294983\"><ele>47.0584</ele><time>2007-04-15T09:44:13Z</time></trkpt><trkpt lat=\"48.8718948364258\" lon=\"2.27742433547974\"><ele>48.6314</ele><time>2007-04-15T09:44:14Z</time></trkpt><trkpt lat=\"48.8719177246094\" lon=\"2.27765011787415\"><ele>49.9606</ele><time>2007-04-15T09:44:15Z</time></trkpt><trkpt lat=\"48.8719444274902\" lon=\"2.27783799171448\"><ele>51.0185</ele><time>2007-04-15T09:44:16Z</time></trkpt><trkpt lat=\"48.8719711303711\" lon=\"2.27802729606628\"><ele>51.966</ele><time>2007-04-15T09:44:17Z</time></trkpt><trkpt lat=\"48.8719902038574\" lon=\"2.27824354171753\"><ele>52.8529</ele><time>2007-04-15T09:44:18Z</time></trkpt><trkpt lat=\"48.8720092773438\" lon=\"2.27839040756226\"><ele>53.0804</ele><time>2007-04-15T09:44:19Z</time></trkpt><trkpt lat=\"48.8720359802246\" lon=\"2.27864193916321\"><ele>52.4668</ele><time>2007-04-15T09:44:20Z</time></trkpt><trkpt lat=\"48.8720817565918\" lon=\"2.27882862091064\"><ele>52.0118</ele><time>2007-04-15T09:44:21Z</time></trkpt><trkpt lat=\"48.8720970153809\" lon=\"2.27903437614441\"><ele>51.4047</ele><time>2007-04-15T09:44:22Z</time></trkpt><trkpt lat=\"48.8721084594727\" lon=\"2.27917003631592\"><ele>51.0076</ele><time>2007-04-15T09:44:23Z</time></trkpt><trkpt lat=\"48.8721351623535\" lon=\"2.279376745224\"><ele>51.4415</ele><time>2007-04-15T09:44:24Z</time></trkpt><trkpt lat=\"48.8721733093262\" lon=\"2.27958917617798\"><ele>51.7951</ele><time>2007-04-15T09:44:25Z</time></trkpt><trkpt lat=\"48.8721923828125\" lon=\"2.27969932556152\"><ele>51.9438</ele><time>2007-04-15T09:44:26Z</time></trkpt><trkpt lat=\"48.8721923828125\" lon=\"2.27971005439758\"><ele>51.9628</ele><time>2007-04-15T09:44:27Z</time></trkpt><trkpt lat=\"48.8721961975098\" lon=\"2.27977204322815\"><ele>52.0593</ele><time>2007-04-15T09:44:28Z</time></trkpt><trkpt lat=\"48.872200012207\" lon=\"2.27978539466858\"><ele>52.0691</ele><time>2007-04-15T09:44:29Z</time></trkpt></trkseg></trk></gpx>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/test.gpx",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:xalan=\"http://xml.apache.org/xalan\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" creator=\"MotionX Live\" version=\"1.1\">\n  <trk>\n    <name>Track 002</name>\n    <desc>Mar 25, 2010 10:19 am</desc>\n    <trkseg>\n      <trkpt lat=\"39.757509\" lon=\"-104.902044\">\n        <ele>1602.000000</ele>\n        <time>2010-03-25T16:19:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757484\" lon=\"-104.902000\">\n        <ele>1605.000000</ele>\n        <time>2010-03-25T16:19:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757424\" lon=\"-104.901952\">\n        <ele>1606.000000</ele>\n        <time>2010-03-25T16:19:25Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757336\" lon=\"-104.901900\">\n        <ele>1608.000000</ele>\n        <time>2010-03-25T16:19:27Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757266\" lon=\"-104.901870\">\n        <ele>1608.000000</ele>\n        <time>2010-03-25T16:19:29Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757215\" lon=\"-104.901857\">\n        <ele>1607.000000</ele>\n        <time>2010-03-25T16:19:31Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757112\" lon=\"-104.901898\">\n        <ele>1607.000000</ele>\n        <time>2010-03-25T16:19:34Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757058\" lon=\"-104.902024\">\n        <ele>1607.000000</ele>\n        <time>2010-03-25T16:19:37Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757033\" lon=\"-104.902128\">\n        <ele>1608.000000</ele>\n        <time>2010-03-25T16:19:39Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757035\" lon=\"-104.902465\">\n        <ele>1609.000000</ele>\n        <time>2010-03-25T16:19:41Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757070\" lon=\"-104.902841\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:19:44Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757109\" lon=\"-104.903020\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:19:46Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757125\" lon=\"-104.903049\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:19:48Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757136\" lon=\"-104.903147\">\n        <ele>1609.000000</ele>\n        <time>2010-03-25T16:20:00Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757182\" lon=\"-104.903329\">\n        <ele>1609.000000</ele>\n        <time>2010-03-25T16:20:03Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757324\" lon=\"-104.903434\">\n        <ele>1609.000000</ele>\n        <time>2010-03-25T16:20:06Z</time>\n      </trkpt>\n      <trkpt lat=\"39.757858\" lon=\"-104.903452\">\n        <ele>1610.000000</ele>\n        <time>2010-03-25T16:20:09Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758390\" lon=\"-104.903485\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:20:12Z</time>\n      </trkpt>\n      <trkpt lat=\"39.758770\" lon=\"-104.903476\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:20:14Z</time>\n      </trkpt>\n      <trkpt lat=\"39.759124\" lon=\"-104.903450\">\n        <ele>1611.000000</ele>\n        <time>2010-03-25T16:20:16Z</time>\n      </trkpt>\n      <trkpt lat=\"39.759446\" lon=\"-104.903386\">\n        <ele>1612.000000</ele>\n        <time>2010-03-25T16:20:18Z</time>\n      </trkpt>\n      <trkpt lat=\"39.759743\" lon=\"-104.903212\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:20:20Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760028\" lon=\"-104.903071\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:20:22Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760313\" lon=\"-104.902947\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:20:24Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760608\" lon=\"-104.902876\">\n        <ele>1614.000000</ele>\n        <time>2010-03-25T16:20:26Z</time>\n      </trkpt>\n      <trkpt lat=\"39.760931\" lon=\"-104.902853\">\n        <ele>1613.000000</ele>\n        <time>2010-03-25T16:20:29Z</time>\n      </trkpt>\n    </trkseg>\n  </trk>\n</gpx>\n      "
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.usb/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator.usb\nBundle-SymbolicName: org.eclipse.kura.emulator.usb;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura.emulator.usb; version=\"1.0.0\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: javax.usb;version=\"1.0.2\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.usb;version=\"[1.3,1.4)\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.usb/OSGI-INF/usb.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" immediate=\"true\" name=\"org.eclipse.kura.usb.UsbService\">\n   <implementation class=\"org.eclipse.kura.emulator.usb.UsbServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.usb.UsbService\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.usb.UsbService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.usb/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.usb/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.usb/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#   Red Hat Inc\n#\n\noutput.. = target/classes/\nsource.. = src/main/java/,\\\n           src/main/resources/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nadditional.bundles = org.eclipse.osgi,\\\n                     slf4j.api,\\\n                     org.eclipse.kura.api\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.usb/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n      Red Hat Inc - fix issue #603\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>emulator</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.emulator.usb</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.usb/src/main/java/org/eclipse/kura/emulator/usb/UsbServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc \n *******************************************************************************/\npackage org.eclipse.kura.emulator.usb;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport javax.usb.UsbServices;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.usb.UsbBlockDevice;\nimport org.eclipse.kura.usb.UsbDevice;\nimport org.eclipse.kura.usb.UsbNetDevice;\nimport org.eclipse.kura.usb.UsbService;\nimport org.eclipse.kura.usb.UsbTtyDevice;\nimport org.osgi.service.component.ComponentContext;\n\npublic class UsbServiceImpl implements UsbService {\n\n    protected void activate(ComponentContext componentContext) {\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n    }\n\n    @Override\n    public UsbServices getUsbServices() throws KuraException {\n        return null;\n    }\n\n    @Override\n    public List<? extends UsbDevice> getUsbDevices() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<UsbBlockDevice> getUsbBlockDevices() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<UsbNetDevice> getUsbNetDevices() {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<UsbTtyDevice> getUsbTtyDevices() {\n        return Collections.emptyList();\n    }\n\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.watchdog/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator.watchdog\nBundle-SymbolicName: org.eclipse.kura.emulator.watchdog;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura.emulator.watchdog; version=\"1.0.0\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.watchdog;version=\"[1.0,1.1)\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.watchdog/OSGI-INF/metatype/org.eclipse.kura.watchdog.WatchdogService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.watchdog.WatchdogService\" \n         name=\"WatchdogService\" \n         description=\"Emulated implementation of the WatchdogService\">         \n\n        <Icon resource=\"WatchdogService\" size=\"32\"/>\n        \n        <AD id=\"enabled\"  \n            name=\"enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"false\" \n            description=\"The emulated WatchdogService is always disabled.\"/>\n                    \n    </OCD>\n    <Designate pid=\"org.eclipse.kura.watchdog.WatchdogService\">\n        <Object ocdref=\"org.eclipse.kura.watchdog.WatchdogService\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.watchdog/OSGI-INF/watchdog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.watchdog.WatchdogService\">\n   <implementation class=\"org.eclipse.kura.emulator.watchdog.WatchdogServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.watchdog.WatchdogService\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.watchdog.WatchdogService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.watchdog/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.watchdog/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.watchdog/build.properties",
    "content": "#\n# Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#   Red Hat Inc\n#\n\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.watchdog/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n      Red Hat Inc - fix issue #603\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>emulator</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.emulator.watchdog</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../../test/org.eclipse.kura.emulator.watchdog.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.watchdog/src/main/java/org/eclipse/kura/emulator/watchdog/CriticalServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator.watchdog;\n\npublic class CriticalServiceImpl {\n\n    private final String name;\n    private final long timeout;\n    private long updated;\n\n    /**\n     * \n     * @param name\n     * @param timeout\n     *            timeout for reporting interval in seconds\n     */\n    public CriticalServiceImpl(String name, long timeout) {\n        this.name = name;\n        this.timeout = timeout;\n        this.updated = System.currentTimeMillis();\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public long getTimeout() {\n        return this.timeout;\n    }\n\n    public boolean isTimedOut() {\n        long current = System.currentTimeMillis();\n        return this.timeout < current - this.updated;\n    }\n\n    public void update() {\n        this.updated = System.currentTimeMillis();\n    }\n\n    @Override\n    public String toString() {\n        return \"Service Name:  \" + this.name + \", Timeout(ms):  \" + this.timeout;\n    }\n}\n"
  },
  {
    "path": "kura/emulator/org.eclipse.kura.emulator.watchdog/src/main/java/org/eclipse/kura/emulator/watchdog/WatchdogServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator.watchdog;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.watchdog.CriticalComponent;\nimport org.eclipse.kura.watchdog.WatchdogService;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class WatchdogServiceImpl implements WatchdogService, ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(WatchdogServiceImpl.class);\n\n    private static List<CriticalServiceImpl> criticalServiceList;\n\n    private Map<String, Object> properties;\n    private ScheduledExecutorService executor;\n    private ScheduledFuture<?> future;\n    private int pingInterval = 10000; // milliseconds\n    private boolean configEnabled = false; // initialized in properties, if false -> no watchdog\n    private boolean enabled;\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        this.properties = properties;\n        if (properties == null) {\n            logger.debug(\"activating WatchdogService with null props\");\n        } else {\n            logger.debug(\"activating WatchdogService with {}\", properties.toString());\n        }\n        criticalServiceList = new ArrayList<>();\n        this.enabled = false;\n\n        // clean up if this is not our first run\n        if (this.executor != null) {\n            this.executor.shutdown();\n            while (!this.executor.isTerminated()) {\n                try {\n                    Thread.sleep(500);\n                } catch (InterruptedException e) {\n                    Thread.currentThread().interrupt();\n                    logger.debug(e.getMessage(), e);\n                }\n            }\n            this.executor = null;\n        }\n\n        this.executor = Executors.newSingleThreadScheduledExecutor();\n\n        this.future = this.executor.scheduleAtFixedRate(() -> {\n            Thread.currentThread().setName(getClass().getSimpleName());\n            if (WatchdogServiceImpl.this.configEnabled) {\n                doWatchdogLoop();\n            }\n        }, 0, this.pingInterval, TimeUnit.MILLISECONDS);\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        this.executor.shutdown();\n        while (!this.executor.isTerminated()) {\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                logger.debug(e.getMessage(), e);\n            }\n        }\n        this.executor = null;\n        criticalServiceList = null;\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.debug(\"updated...\");\n        this.properties = properties;\n        if (this.properties != null) {\n\n            Object enabledVal = this.properties.get(\"enabled\");\n            if (enabledVal != null) {\n                this.configEnabled = (Boolean) enabledVal;\n            }\n            if (!this.configEnabled) {\n                return;\n            }\n            if (this.properties.get(\"pingInterval\") != null) {\n                this.pingInterval = (Integer) this.properties.get(\"pingInterval\");\n                if (this.future != null) {\n                    this.future.cancel(false);\n                    while (!this.future.isDone()) {\n                        try {\n                            Thread.sleep(500);\n                        } catch (InterruptedException e) {\n                            Thread.currentThread().interrupt();\n                            logger.debug(e.getMessage(), e);\n                        }\n                    }\n                }\n                this.future = this.executor.scheduleAtFixedRate(() -> {\n                    Thread.currentThread().setName(getClass().getSimpleName());\n                    if (WatchdogServiceImpl.this.configEnabled) {\n                        doWatchdogLoop();\n                    }\n                }, 0, this.pingInterval, TimeUnit.MILLISECONDS);\n            }\n        }\n    }\n\n    @Override\n    public void startWatchdog() {\n        this.enabled = true;\n    }\n\n    @Override\n    public void stopWatchdog() {\n        this.enabled = false;\n    }\n\n    @Override\n    public int getHardwareTimeout() {\n        return 0;\n    }\n\n    @Override\n    public void registerCriticalComponent(CriticalComponent criticalComponent) {\n        final CriticalServiceImpl service = new CriticalServiceImpl(criticalComponent.getCriticalComponentName(),\n                criticalComponent.getCriticalComponentTimeout());\n        synchronized (criticalServiceList) {\n            // avoid to add same component twice (eg in case of a package updating)\n            boolean existing = false;\n            for (CriticalServiceImpl csi : criticalServiceList) {\n                if (criticalComponent.getCriticalComponentName().compareTo(csi.getName()) == 0) {\n                    existing = true;\n                }\n            }\n            if (!existing) {\n                criticalServiceList.add(service);\n            }\n        }\n\n        logger.debug(\"Added {} , with timeout = {}, list contains {} critical services\",\n                criticalComponent.getCriticalComponentName(), criticalComponent.getCriticalComponentTimeout(),\n                criticalServiceList.size());\n    }\n\n    /**\n     * @deprecated use {@link WatchdogServiceImpl#registerCriticalComponent(CriticalComponent)}\n     */\n    @Override\n    @Deprecated\n    public void registerCriticalService(CriticalComponent criticalComponent) {\n        registerCriticalComponent(criticalComponent);\n    }\n\n    @Override\n    public void unregisterCriticalComponent(CriticalComponent criticalComponent) {\n        synchronized (criticalServiceList) {\n            for (int i = 0; i < criticalServiceList.size(); i++) {\n                if (criticalComponent.getCriticalComponentName().compareTo(criticalServiceList.get(i).getName()) == 0) {\n                    criticalServiceList.remove(i);\n                    logger.debug(\"Critical service {} removed, {}\", criticalComponent.getCriticalComponentName(),\n                            System.currentTimeMillis());\n                }\n            }\n        }\n    }\n\n    /**\n     * @deprecated use {@link WatchdogServiceImpl#unregisterCriticalComponent(CriticalComponent)}\n     */\n    @Override\n    @Deprecated\n    public void unregisterCriticalService(CriticalComponent criticalComponent) {\n        unregisterCriticalComponent(criticalComponent);\n    }\n\n    @Override\n    public List<CriticalComponent> getCriticalComponents() {\n        return null;\n    }\n\n    @Override\n    public void checkin(CriticalComponent criticalService) {\n        synchronized (criticalServiceList) {\n            for (CriticalServiceImpl csi : criticalServiceList) {\n                if (criticalService.getCriticalComponentName().compareTo(csi.getName()) == 0) {\n                    csi.update();\n                }\n            }\n        }\n    }\n\n    private void doWatchdogLoop() {\n        if (!this.enabled) {\n            return;\n        }\n\n        boolean failure = false;\n        // Critical Services\n        synchronized (criticalServiceList) {\n            if (!criticalServiceList.isEmpty()) {\n                for (CriticalServiceImpl csi : criticalServiceList) {\n                    if (csi.isTimedOut()) {\n                        failure = true;\n                        logger.warn(\"Critical service {} failed -> SYSTEM REBOOT\", csi.getName());\n                    }\n                }\n            }\n        }\n        if (!failure) {\n            refreshWatchdog();\n        }\n    }\n\n    private void refreshWatchdog() {\n        File f = new File(\"/dev/watchdog\");\n        if (f.exists()) {\n            try (FileOutputStream fos = new FileOutputStream(f); PrintWriter pw = new PrintWriter(fos);) {\n                pw.write(\"w\");\n                pw.flush();\n                fos.getFD().sync();\n            } catch (IOException e) {\n                logger.info(e.getMessage(), e);\n            }\n        }\n    }\n\n    public boolean isConfigEnabled() {\n        return this.configEnabled;\n    }\n\n    public void setConfigEnabled(boolean configEnabled) {\n        this.configEnabled = configEnabled;\n    }\n}\n"
  },
  {
    "path": "kura/emulator/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>emulator</artifactId>\n\t<packaging>pom</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t</properties>\n\t\n\t<modules>\n\t\t<module>org.eclipse.kura.emulator</module>\n\t\t<module>org.eclipse.kura.emulator.gpio</module>\n\t\t<module>org.eclipse.kura.emulator.clock</module>\n\t\t<module>org.eclipse.kura.emulator.net</module>\n\t\t<module>org.eclipse.kura.emulator.position</module>\n\t\t<module>org.eclipse.kura.emulator.usb</module>\n\t\t<module>org.eclipse.kura.emulator.watchdog</module>\n\t</modules>\n</project>\n"
  },
  {
    "path": "kura/kura-pde-deps/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <groupId>org.eclipse.kura</groupId>\n    <artifactId>kura-pde-deps</artifactId>\n    <packaging>pom</packaging>\n    <name>Kura PDE Dependencies</name>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.camel</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.camel.cloud.factory</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.camel.xml</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.cloud.base.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.cloudconnection.kapua.mqtt.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.cloudconnection.raw.mqtt.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.configuration.change.manager</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.container.orchestration.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.container.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.certificates</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.cloud.factory</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.comm</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.configuration</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.crypto</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.identity</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.inventory</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.keystore</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.status</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.system</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.tamper.detection.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.db.h2db.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.db.sqlite.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.driver.block</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.driver.helper.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.driver.s7plc.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.emulator</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.emulator.clock</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.emulator.gpio</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.emulator.net</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.emulator.position</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.emulator.usb</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.emulator.watchdog</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.event.publisher</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.http.server.manager</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.json.marshaller.unmarshaller.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.linux.clock</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.linux.usb</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.linux.usb.aarch64</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.linux.usb.x86_64</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.linux.watchdog</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.log.filesystem.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.misc.cloudcat</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.protocol.modbus</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.request.handler.jaxrs</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.cloudconnection.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.configuration.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.identity.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.inventory.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.keystore.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.security.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.service.listing.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.rest.system.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.stress</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.useradmin.store</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.util</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.wire.camel</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.xml.marshaller.unmarshaller.provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.jul.to.slf4j.configuration</artifactId>\n        </dependency>\n        <!-- test-util -->\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core.testutil</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.test</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.util.test.driver</artifactId>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "kura/org.eclipse.kura.api/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.api\nBundle-SymbolicName: org.eclipse.kura.api;singleton:=true\nBundle-Version: 3.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura;version=\"1.7.0\",\n org.eclipse.kura.ai.inference;version=\"1.1.0\",\n org.eclipse.kura.annotation;version=\"1.0.0\",\n org.eclipse.kura.asset;version=\"1.0.0\",\n org.eclipse.kura.audit;version=\"1.0.0\",\n org.eclipse.kura.bluetooth.le;version=\"1.3.0\",\n org.eclipse.kura.bluetooth.le.beacon;version=\"1.1.0\",\n org.eclipse.kura.bluetooth.le.beacon.listener;version=\"1.0.0\",\n org.eclipse.kura.certificate;version=\"2.1.0\",\n org.eclipse.kura.certificate.enrollment;version=\"1.0.0\",\n org.eclipse.kura.channel;version=\"1.4.0\",\n org.eclipse.kura.channel.listener;version=\"1.0.0\",\n org.eclipse.kura.clock;version=\"1.0.1\",\n org.eclipse.kura.cloud;version=\"1.1.0\",\n org.eclipse.kura.cloud.factory;version=\"1.1.1\",\n org.eclipse.kura.cloudconnection;version=\"1.0.0\",\n org.eclipse.kura.cloudconnection.factory;version=\"1.0.0\",\n org.eclipse.kura.cloudconnection.listener;version=\"1.0.0\",\n org.eclipse.kura.cloudconnection.message;version=\"1.0.0\",\n org.eclipse.kura.cloudconnection.publisher;version=\"1.0.0\",\n org.eclipse.kura.cloudconnection.request;version=\"1.0.0\",\n org.eclipse.kura.cloudconnection.subscriber;version=\"1.0.0\",\n org.eclipse.kura.cloudconnection.subscriber.listener;version=\"1.0.0\",\n org.eclipse.kura.comm;version=\"1.1.0\",\n org.eclipse.kura.command;version=\"1.2.0\",\n org.eclipse.kura.configuration;version=\"1.2.0\",\n org.eclipse.kura.configuration.metatype;version=\"1.1.0\",\n org.eclipse.kura.connection.listener;version=\"1.0.0\",\n org.eclipse.kura.container.orchestration;version=\"1.3.0\",\n org.eclipse.kura.container.orchestration.listener;version=\"1.0.0\",\n org.eclipse.kura.container.signature;version=\"1.0.0\",\n org.eclipse.kura.crypto;version=\"1.4.0\",\n org.eclipse.kura.data;version=\"1.1.2\",\n org.eclipse.kura.data.listener;version=\"1.0.1\",\n org.eclipse.kura.data.transport.listener;version=\"1.0.1\",\n org.eclipse.kura.db;version=\"2.0.0\",\n org.eclipse.kura.db.keyvalue;version=\"1.0.0\",\n org.eclipse.kura.deployment.hook;version=\"1.0.0\",\n org.eclipse.kura.driver;version=\"1.0.0\",\n org.eclipse.kura.driver.descriptor;version=\"1.0.0\",\n org.eclipse.kura.executor;version=\"1.0.0\",\n org.eclipse.kura.gpio;version=\"1.2.0\",\n org.eclipse.kura.identity;version=\"1.2.0\",\n org.eclipse.kura.identity.configuration.extension;version=\"1.0.0\",\n org.eclipse.kura.linux.udev;version=\"1.0.1\",\n org.eclipse.kura.log;version=\"1.1.0\",\n org.eclipse.kura.log.listener;version=\"1.0.0\",\n org.eclipse.kura.marshalling;version=\"1.1.0\",\n org.eclipse.kura.message;version=\"1.5.0\",\n org.eclipse.kura.message.store;version=\"1.0.0\",\n org.eclipse.kura.message.store.provider;version=\"1.0.0\",\n org.eclipse.kura.net;version=\"2.7.0\",\n org.eclipse.kura.net.dhcp;version=\"1.2.0\",\n org.eclipse.kura.net.dns;version=\"1.2.0\",\n org.eclipse.kura.net.firewall;version=\"2.1.0\",\n org.eclipse.kura.net.modem;version=\"2.5.0\",\n org.eclipse.kura.net.route;version=\"1.1.0\",\n org.eclipse.kura.net.status;version=\"1.1.0\",\n org.eclipse.kura.net.status.ethernet;version=\"1.0.0\",\n org.eclipse.kura.net.status.loopback;version=\"1.0.0\",\n org.eclipse.kura.net.status.modem;version=\"1.1.0\",\n org.eclipse.kura.net.status.vlan;version=\"1.0.0\",\n org.eclipse.kura.net.status.wifi;version=\"1.1.0\",\n org.eclipse.kura.net.vlan;version=\"1.0.0\",\n org.eclipse.kura.net.wifi;version=\"2.5.0\",\n org.eclipse.kura.position;version=\"1.4.0\",\n org.eclipse.kura.security;version=\"1.3.0\",\n org.eclipse.kura.security.keystore;version=\"1.2.0\",\n org.eclipse.kura.security.tamper.detection;version=\"1.0.0\",\n org.eclipse.kura.ssl;version=\"2.1.0\",\n org.eclipse.kura.status;version=\"1.0.2\",\n org.eclipse.kura.system;version=\"1.9.0\",\n org.eclipse.kura.type;version=\"1.1.0\",\n org.eclipse.kura.usb;version=\"1.3.0\",\n org.eclipse.kura.watchdog;version=\"1.0.2\",\n org.eclipse.kura.wire;version=\"2.0.0\",\n org.eclipse.kura.wire.graph;version=\"1.0.0\",\n org.eclipse.kura.wire.multiport;version=\"1.0.0\",\n org.eclipse.kura.wire.store.provider;version=\"1.0.0\"\nImport-Package: com.google.common.net;version=\"32.1.0\",\n javax.comm;version=\"1.2.0\",\n javax.crypto,\n javax.microedition.io;resolution:=optional,\n javax.net.ssl,\n javax.usb;version=\"1.0.2\",\n org.apache.commons.io.output;version=\"2.4.0\",\n org.apache.logging.log4j;version=\"2.8.2\",\n org.bouncycastle.pkcs;version=\"1.78.1\",\n org.osgi.annotation.versioning;version=\"[1.0.0,2.0.0)\";resolution:=optional,\n org.osgi.framework;version=\"[1.5.0,2.0.0)\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.3.0\",\n org.osgi.service.wireadmin;version=\"1.0.1\",\n org.osgi.util.measurement;version=\"1.0.1\",\n org.osgi.util.position;version=\"1.0.1\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.api/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.api/build.properties",
    "content": "#\n# Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\nsource.. = src/main/java/,src/main/resources/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html,\\\n               about_files/\nadditional.bundles = org.eclipse.equinox.io,\\\n                     slf4j.api,\\\n                     org.eclipse.osgi,\\\n                     org.eclipse.osgi.util\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.api</artifactId>\n    <version>3.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>biz.aQute.bnd</groupId>\n                <artifactId>bnd-baseline-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothBeaconAdvertiserNotAvailable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraBluetoothBeaconAdvertiserNotAvailable is raised when the advertiser is not available.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic class KuraBluetoothBeaconAdvertiserNotAvailable extends KuraException {\n\n    private static final long serialVersionUID = -1243607248475874911L;\n\n    public KuraBluetoothBeaconAdvertiserNotAvailable(Object argument) {\n        super(KuraErrorCode.BLE_RESOURCE_NOT_FOUND, null, argument);\n    }\n\n    public KuraBluetoothBeaconAdvertiserNotAvailable(Throwable cause, Object argument) {\n        super(KuraErrorCode.BLE_RESOURCE_NOT_FOUND, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothCommandException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraBluetoothCommandException is raised when a command returns an error.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic class KuraBluetoothCommandException extends KuraException {\n\n    private static final long serialVersionUID = -5848254103027432830L;\n\n    public KuraBluetoothCommandException(Object argument) {\n        super(KuraErrorCode.BLE_COMMAND_ERROR, null, argument);\n    }\n\n    public KuraBluetoothCommandException(Throwable cause, Object argument) {\n        super(KuraErrorCode.BLE_COMMAND_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothConnectionException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraBluetoothConnectionException is raised when an error is detected during the device connection/disconnection.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic class KuraBluetoothConnectionException extends KuraException {\n\n    private static final long serialVersionUID = -376745878312274934L;\n\n    public KuraBluetoothConnectionException(Object argument) {\n        super(KuraErrorCode.BLE_CONNECTION_ERROR, null, argument);\n    }\n\n    public KuraBluetoothConnectionException(Throwable cause, Object argument) {\n        super(KuraErrorCode.BLE_CONNECTION_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothDiscoveryException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraBluetoothDiscoveryException is raised when an error is detected during the discovery procedure.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic class KuraBluetoothDiscoveryException extends KuraException {\n\n    private static final long serialVersionUID = -8567067163835638967L;\n\n    public KuraBluetoothDiscoveryException(Object argument) {\n        super(KuraErrorCode.BLE_DISCOVERY_ERROR, null, argument);\n    }\n\n    public KuraBluetoothDiscoveryException(Throwable cause, Object argument) {\n        super(KuraErrorCode.BLE_DISCOVERY_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothIOException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraBluetoothIOException is raised when an error is detected during IO operations.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic class KuraBluetoothIOException extends KuraException {\n\n    private static final long serialVersionUID = -2183860317209493405L;\n\n    public KuraBluetoothIOException(Object argument) {\n        super(KuraErrorCode.BLE_IO_ERROR, null, argument);\n    }\n\n    public KuraBluetoothIOException(Throwable cause, Object argument) {\n        super(KuraErrorCode.BLE_IO_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothNotificationException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraBluetoothNotificationException is raised when an error is detected during notification.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic class KuraBluetoothNotificationException extends KuraException {\n\n    private static final long serialVersionUID = -4188172396128459284L;\n\n    public KuraBluetoothNotificationException(Object argument) {\n        super(KuraErrorCode.BLE_NOTIFICATION_ERROR, null, argument);\n    }\n\n    public KuraBluetoothNotificationException(Throwable cause, Object argument) {\n        super(KuraErrorCode.BLE_NOTIFICATION_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothPairException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraBluetoothPairException is raised when an error is detected during the device pairing.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic class KuraBluetoothPairException extends KuraException {\n\n    private static final long serialVersionUID = 4156356604467216236L;\n\n    public KuraBluetoothPairException(Object argument) {\n        super(KuraErrorCode.BLE_PAIR_ERROR, null, argument);\n    }\n\n    public KuraBluetoothPairException(Throwable cause, Object argument) {\n        super(KuraErrorCode.BLE_PAIR_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothRemoveException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraBluetoothRemoveException is raised when an error is detected during removing a device from the system.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.0\n */\n@ProviderType\npublic class KuraBluetoothRemoveException extends KuraException {\n\n    private static final long serialVersionUID = 6080252526631911747L;\n\n    public KuraBluetoothRemoveException(Object argument) {\n        super(KuraErrorCode.BLE_REMOVE_ERROR, null, argument);\n    }\n\n    public KuraBluetoothRemoveException(Throwable cause, Object argument) {\n        super(KuraErrorCode.BLE_REMOVE_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothResourceNotFoundException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraBluetoothResourceNotFoundException is raised when a resource is not found.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic class KuraBluetoothResourceNotFoundException extends KuraException {\n\n    private static final long serialVersionUID = -1142491109524317287L;\n\n    public KuraBluetoothResourceNotFoundException(Object argument) {\n        super(KuraErrorCode.BLE_RESOURCE_NOT_FOUND, null, argument);\n    }\n\n    public KuraBluetoothResourceNotFoundException(Throwable cause, Object argument) {\n        super(KuraErrorCode.BLE_RESOURCE_NOT_FOUND, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraConnectException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraConnectException is raised during connect failures.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraConnectException extends KuraException {\n\n    private static final long serialVersionUID = 5894832757268538532L;\n\n    public KuraConnectException(Object argument) {\n        super(KuraErrorCode.CONNECTION_FAILED, null, argument);\n    }\n\n    public KuraConnectException(Throwable cause, Object argument) {\n        super(KuraErrorCode.CONNECTION_FAILED, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraConnectionStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\n@SuppressWarnings(\"checkstyle:hideUtilityClassConstructor\")\npublic class KuraConnectionStatus {\n\n    /**\n     * initial state for any connection\n     */\n    public static final int NEVERCONNECTED = -1;\n    /**\n     * attempts have been made to connect to the device, but currently\n     * no connection exists\n     */\n    public static final int DISCONNECTED = 0;\n    /**\n     * attempting to connect to field device, this is a transient state\n     */\n    public static final int CONNECTING = 1;\n    /**\n     * a connection to the field device currently exists. A status of\n     * CONNECTED does not assure that requests from or commands to this\n     * field device will succeed.\n     */\n    public static final int CONNECTED = 2;\n    /**\n     * attempting to disconnect from the field device. Disconnection from\n     * a field device may be delayed while outstanding commands are either\n     * completed or terminated.\n     */\n    public static final int DISCONNECTING = 3;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraDisconnectException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraConnectException is raised during disconnection failures.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.0\n */\n@ProviderType\npublic class KuraDisconnectException extends KuraException {\n\n    private static final long serialVersionUID = 52917095245324570L;\n\n    public KuraDisconnectException(Object argument) {\n        super(KuraErrorCode.DISCONNECTION_FAILED, null, argument);\n    }\n\n    public KuraDisconnectException(Throwable cause, Object argument) {\n        super(KuraErrorCode.DISCONNECTION_FAILED, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraErrorCode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura;\n\n/**\n * KuraErrorCode holds the enumeration of valid error codes for the exception message. For each defined enum value, a\n * corresponding message should be defined in the properties bundle named:\n * KuraExceptionMessagesBundle.properties.\n *\n * @since 1.3\n *\n */\npublic enum KuraErrorCode {\n    /**\n     * Configuration Error: {0}\n     */\n    CONFIGURATION_ERROR,\n    /**\n     * Error updating Configuration of ConfigurableComponent {0}\n     */\n    CONFIGURATION_UPDATE,\n    /**\n     * Error rolling back to snapshot.\n     */\n    CONFIGURATION_ROLLBACK,\n    /**\n     * The configuration attribute {0} is undefined.\n     */\n    CONFIGURATION_ATTRIBUTE_UNDEFINED,\n    /**\n     * The configuration attribute {0} cannot accept value {1}: {2}.\n     */\n    CONFIGURATION_ATTRIBUTE_INVALID,\n    /**\n     * The configuration attribute {0} is required and no value has been specified.\n     */\n    CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING,\n    /**\n     * Configuration snapshot {0} was not found.\n     */\n    CONFIGURATION_SNAPSHOT_NOT_FOUND,\n    /**\n     * Error Taking Snapshot.\n     */\n    CONFIGURATION_SNAPSHOT_TAKING,\n    /**\n     * Error Listing Snapshots.\n     */\n    CONFIGURATION_SNAPSHOT_LISTING,\n    /**\n     * Error Loading Snapshot\n     */\n    CONFIGURATION_SNAPSHOT_LOADING,\n    /**\n     * An internal error occurred. {0}\n     * \n     * @deprecated\n     */\n    INTERNAL_ERROR,\n    /**\n     * The serial port ha an invalid configuration. {0}\n     */\n    SERIAL_PORT_INVALID_CONFIGURATION,\n    /**\n     * The serial port does not exist. {0}\n     */\n    SERIAL_PORT_NOT_EXISTING,\n    /**\n     * The port is in use. {0}\n     */\n    PORT_IN_USE,\n    /**\n     * The operation succeeded only partially.\n     */\n    PARTIAL_SUCCESS,\n    /**\n     * The current subject is not authorized to perform this operation. {0}\n     */\n    SECURITY_EXCEPTION,\n    /**\n     * Not connected.\n     */\n    NOT_CONNECTED,\n    /**\n     * Timeout occurred while waiting for the operation to complete.\n     */\n    TIMED_OUT,\n    /**\n     * Connection failed. {0}\n     */\n    CONNECTION_FAILED,\n    /**\n     * Too many in-flight messages.\n     */\n    TOO_MANY_INFLIGHT_MESSAGES,\n    /**\n     * Error performing operation on store. {0}\n     */\n    STORE_ERROR,\n    /**\n     * Error encoding {0}.\n     */\n    ENCODE_ERROR,\n    /**\n     * Error decoding {0}.\n     */\n    DECODER_ERROR,\n    /**\n     * Metric {0} is invalid.\n     */\n    INVALID_METRIC_EXCEPTION,\n    /**\n     * Message or its encoding is invalid.\n     */\n    INVALID_MESSAGE_EXCEPTION,\n    /**\n     * Operation {0} not supported.\n     */\n    OPERATION_NOT_SUPPORTED,\n    /**\n     * Device {0} is unavailable.\n     */\n    UNAVAILABLE_DEVICE,\n    /**\n     * Device {0} is closed.\n     */\n    CLOSED_DEVICE,\n    /**\n     * Error accessing GPIO resource. {0}\n     */\n    GPIO_EXCEPTION,\n    /**\n     * Command {0} exited with code {1}.\n     *\n     * @since 1.0.8\n     */\n    OS_COMMAND_ERROR,\n    /**\n     * Invalid parameter. {0}\n     * \n     * @since 1.0.8\n     */\n    INVALID_PARAMETER,\n    /**\n     * Unable to execute system process {0}\n     *\n     * @since 1.2\n     */\n    PROCESS_EXECUTION_ERROR,\n    /**\n     * Error processing subscription for {0}\n     *\n     * @since 1.2\n     */\n    SUBSCRIPTION_ERROR,\n    /**\n     * Error during BLE notification.\n     *\n     * @since 1.3\n     */\n    BLE_NOTIFICATION_ERROR,\n    /**\n     * Error during BLE connection.\n     * \n     * @since 1.3\n     */\n    BLE_CONNECTION_ERROR,\n    /**\n     * Error during BLE pairing.\n     * \n     * @since 1.3\n     */\n    BLE_PAIR_ERROR,\n    /**\n     * BLE resource not found.\n     * \n     * @since 1.3\n     */\n    BLE_RESOURCE_NOT_FOUND,\n    /**\n     * Error during BLE IO activity.\n     * \n     * @since 1.3\n     */\n    BLE_IO_ERROR,\n    /**\n     * Error executing {0} command.\n     * \n     * @since 1.3\n     */\n    BLE_COMMAND_ERROR,\n    /**\n     * Error during discovery procedure.\n     * \n     * @since 1.3\n     */\n    BLE_DISCOVERY_ERROR,\n    /**\n     * Error during device remove.\n     * \n     * @since 2.0\n     */\n    BLE_REMOVE_ERROR,\n    /**\n     * Bad request.\n     * \n     * @since 2.0\n     */\n    BAD_REQUEST,\n    /**\n     * Not found.\n     * \n     * @since 2.0\n     */\n    NOT_FOUND,\n    /**\n     * Service unavailable. {0}.\n     * \n     * @since 2.0\n     */\n    SERVICE_UNAVAILABLE,\n    /**\n     * Disconnection failed.\n     * \n     * @since 2.0\n     */\n    DISCONNECTION_FAILED,\n    /**\n     * Error during IO operation.\n     * \n     * @since 2.2\n     */\n    IO_ERROR,\n    /**\n     * Modem unsupported.\n     * \n     * @since 2.3\n     */\n    UNSUPPORTED_MODEM,\n    /**\n     * Certificate invalid.\n     * \n     * @since 2.4\n     */\n    INVALID_CERTIFICATE_EXCEPTION\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport java.text.MessageFormat;\nimport java.util.Locale;\nimport java.util.MissingResourceException;\nimport java.util.ResourceBundle;\n\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.Logger;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The {@link KuraException} class is the superclass of all errors and exceptions in the Kura project. It extends the\n * JDK {@link Exception} class by requesting its invokers to provide an error code when building its instances. The code\n * is one value of {@link KuraErrorCode}; the code is used to document the possible error conditions generated by the\n * platform as well as to identify the localized exception messages to be reported. Exceptions messages are stored in\n * the {@code KuraExceptionMessagesBundle} Properties Bundle and they are keyed on the exception code.\n *\n * @see KuraErrorCode\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraException extends Exception {\n\n    /** The Constant denoting resource bundle. */\n    private static final String KURA_EXCEPTION_MESSAGES_BUNDLE = \"org.eclipse.kura.core.messages.KuraExceptionMessagesBundle\";\n\n    /** The Constant denoting message pattern. */\n    private static final String KURA_GENERIC_MESSAGES_PATTERN = \"Generic Error - {0}: {1}\";\n\n    /** The Logger. */\n    private static final Logger logger = LogManager.getLogger(KuraException.class);\n\n    /** The Constant denoting serial version identifier. */\n    private static final long serialVersionUID = 7468633737373095296L;\n\n    /** The associated arguments. */\n    private Object[] arguments;\n\n    /** The associated error code. */\n    private final KuraErrorCode code;\n\n    /**\n     * Builds a new {@link KuraException} instance based on the supplied {@link KuraErrorCode}.\n     *\n     * @param code\n     *            the error code\n     */\n    public KuraException(final KuraErrorCode code) {\n        this.code = code;\n    }\n\n    /**\n     * Builds a new {@link KuraException} instance based on the supplied {@link KuraErrorCode}.\n     *\n     * @param code\n     *            the error code\n     * @param arguments\n     *            the arguments\n     */\n    public KuraException(final KuraErrorCode code, final Object... arguments) {\n        this.code = code;\n        this.arguments = arguments;\n    }\n\n    /**\n     * Builds a new {@link KuraException} instance based on the supplied {@link KuraErrorCode}, an optional Throwable\n     * cause, and optional arguments for the associated exception message.\n     *\n     * @param code\n     *            the error code\n     * @param cause\n     *            the cause\n     * @param arguments\n     *            the arguments\n     */\n    public KuraException(final KuraErrorCode code, final Throwable cause, final Object... arguments) {\n        super(cause);\n        this.code = code;\n        this.arguments = arguments;\n    }\n\n    /**\n     * Factory method to build an {@link KuraException} with the {@link KuraErrorCode#INTERNAL_ERROR} code providing\n     * only a message. This method internally sets the error code to {@link KuraErrorCode#INTERNAL_ERROR} which is not\n     * meaningful at all for exception translations. That is why, the use of this method is <b>highly discouraged</b>.\n     * Hence, the advised way to construct a {@link KuraException} is to use its constructor with a proper\n     * {@link KuraErrorCode}.\n     *\n     * @param message\n     *            the message\n     * @return the kura exception\n     */\n    public static KuraException internalError(final String message) {\n        return new KuraException(KuraErrorCode.INTERNAL_ERROR, null, message);\n    }\n\n    /**\n     * Factory method to build an {@link KuraException} with the {@link KuraErrorCode#INTERNAL_ERROR} code providing a\n     * cause and a message. This method internally sets the error code to {@link KuraErrorCode#INTERNAL_ERROR} which is\n     * not meaningful at all for exception translations. That is why, the use of this method is <b>highly\n     * discouraged</b>. Hence, the advised way to construct a {@link KuraException} is to use its constructor with a\n     * proper {@link KuraErrorCode}.\n     *\n     * @param cause\n     *            the cause\n     * @return the kura exception\n     */\n    public static KuraException internalError(final Throwable cause) {\n        return new KuraException(KuraErrorCode.INTERNAL_ERROR, cause, \"\");\n    }\n\n    /**\n     * Factory method to build an {@link KuraException} with the {@link KuraErrorCode#INTERNAL_ERROR} code providing a\n     * cause and a message. This method internally sets the error code to {@link KuraErrorCode#INTERNAL_ERROR} which is\n     * not meaningful at all for exception translations. That is why, the use of this method is <b>highly\n     * discouraged</b>. Hence, the advised way to construct a {@link KuraException} is to use its constructor with a\n     * proper {@link KuraErrorCode}.\n     *\n     * @param cause\n     *            the cause\n     * @param message\n     *            the message\n     * @return the kura exception\n     */\n    public static KuraException internalError(final Throwable cause, final String message) {\n        return new KuraException(KuraErrorCode.INTERNAL_ERROR, cause, message);\n    }\n\n    /**\n     * Gets the error code.\n     *\n     * @return the error code\n     */\n    public KuraErrorCode getCode() {\n        return this.code;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String getLocalizedMessage() {\n        return getLocalizedMessage(Locale.getDefault());\n    }\n\n    /**\n     * Gets the localized message.\n     *\n     * @param locale\n     *            the locale\n     * @return the localized message\n     */\n    private String getLocalizedMessage(final Locale locale) {\n        final String pattern = getMessagePattern(locale, this.code);\n        if (this.code == null || KuraErrorCode.INTERNAL_ERROR.equals(this.code)) {\n            if (this.arguments != null && this.arguments.length > 1) {\n                // append all arguments into a single one\n                final StringBuilder sbAllArgs = new StringBuilder();\n                for (final Object arg : this.arguments) {\n                    sbAllArgs.append(\" - \");\n                    sbAllArgs.append(arg);\n                }\n                this.arguments = new Object[] { sbAllArgs.toString() };\n            }\n        }\n        return MessageFormat.format(pattern, this.arguments);\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String getMessage() {\n        return getLocalizedMessage(Locale.US);\n    }\n\n    /**\n     * Gets the message pattern.\n     *\n     * @param locale\n     *            the locale\n     * @param code\n     *            the code\n     * @return the message pattern\n     */\n    private String getMessagePattern(final Locale locale, final KuraErrorCode code) {\n        // Load the message pattern from the bundle\n        String messagePattern = null;\n        ResourceBundle resourceBundle = null;\n        try {\n            resourceBundle = ResourceBundle.getBundle(KURA_EXCEPTION_MESSAGES_BUNDLE, locale);\n            if (resourceBundle != null && code != null) {\n                messagePattern = resourceBundle.getString(code.name());\n                if (messagePattern == null) {\n                    logger.warn(\"Could not find Exception Messages for Locale {} and code {}\", locale, code);\n                }\n            }\n        } catch (final MissingResourceException mre) {\n            // log the failure to load a message bundle\n            logger.warn(\"Could not load Exception Messages Bundle for Locale {}\", locale);\n        }\n        // If no bundle or code in the bundle is found, use a generic message\n        if (messagePattern == null) {\n            if (code != null) {\n                // build a generic message format\n                messagePattern = MessageFormat.format(KURA_GENERIC_MESSAGES_PATTERN, code.name());\n            } else {\n                // build a generic message format\n                messagePattern = MessageFormat.format(KURA_GENERIC_MESSAGES_PATTERN, \"Unknown\");\n            }\n        }\n        return messagePattern;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraIOException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraIOException is raised when an IO failure is detected.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.2\n */\n@ProviderType\npublic class KuraIOException extends KuraException {\n\n    private static final long serialVersionUID = 4440807883112997377L;\n\n    public KuraIOException(Object argument) {\n        super(KuraErrorCode.IO_ERROR, null, argument);\n    }\n\n    public KuraIOException(Throwable cause, Object argument) {\n        super(KuraErrorCode.IO_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraInvalidMessageException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraInvalidMessageException extends KuraRuntimeException {\n\n    private static final long serialVersionUID = -3636897647706575102L;\n\n    public KuraInvalidMessageException(Object argument) {\n        super(KuraErrorCode.INVALID_MESSAGE_EXCEPTION, argument);\n    }\n\n    public KuraInvalidMessageException(Throwable cause) {\n        super(KuraErrorCode.INVALID_MESSAGE_EXCEPTION, cause);\n    }\n\n    public KuraInvalidMessageException(Throwable cause, Object argument) {\n        super(KuraErrorCode.INVALID_MESSAGE_EXCEPTION, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraInvalidMetricTypeException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraInvalidMetricTypeException extends KuraRuntimeException {\n\n    private static final long serialVersionUID = 3811194468467381264L;\n\n    public KuraInvalidMetricTypeException(Object argument) {\n        super(KuraErrorCode.INVALID_METRIC_EXCEPTION, argument);\n    }\n\n    public KuraInvalidMetricTypeException(Throwable cause, Object argument) {\n        super(KuraErrorCode.INVALID_METRIC_EXCEPTION, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraNotConnectedException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraNotConnectedException is raised when the attempted operation requires\n * an active connection to the remote server while the current state is\n * disconnected.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraNotConnectedException extends KuraException {\n\n    private static final long serialVersionUID = 5894832757268538532L;\n\n    public KuraNotConnectedException(Object argument) {\n        super(KuraErrorCode.NOT_CONNECTED, null, argument);\n    }\n\n    public KuraNotConnectedException(Throwable cause, Object argument) {\n        super(KuraErrorCode.NOT_CONNECTED, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraPartialSuccessException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraPartialSuccessException is used capture the response\n * of bulk operations which allow for the failures of some\n * of their steps.\n * KuraPartialSuccessException.getCauses() will return the\n * exceptions collected during operations for those steps\n * that failed.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraPartialSuccessException extends KuraException {\n\n    private static final long serialVersionUID = -350563041335590477L;\n\n    private final List<Throwable> causes;\n\n    public KuraPartialSuccessException(String message, List<Throwable> causes) {\n        super(KuraErrorCode.PARTIAL_SUCCESS, (Throwable) null, message);\n        this.causes = causes;\n    }\n\n    /**\n     * Returns the list of failures collected during the execution of the bulk operation.\n     *\n     * @return causes\n     */\n    public List<Throwable> getCauses() {\n        return this.causes;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraProcessExecutionErrorException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraProcessExecutionErrorException is raised when a command/process execution fails.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.2\n */\n@ProviderType\npublic class KuraProcessExecutionErrorException extends KuraException {\n\n    private static final long serialVersionUID = 5091705219678526443L;\n\n    public KuraProcessExecutionErrorException(Object argument) {\n        super(KuraErrorCode.PROCESS_EXECUTION_ERROR, null, argument);\n    }\n\n    public KuraProcessExecutionErrorException(Throwable cause, Object argument) {\n        super(KuraErrorCode.PROCESS_EXECUTION_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraRuntimeException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport java.text.MessageFormat;\nimport java.util.Locale;\nimport java.util.MissingResourceException;\nimport java.util.ResourceBundle;\n\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.Logger;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The {@link KuraRuntimeException} class is the superclass of all runtime exceptions in the Kura project. It extends\n * the JDK {@link RuntimeException} class by requesting its invokers to provide an error code when building its\n * instances. The code is one value of {@link KuraErrorCode}; the code is used to document the possible error conditions\n * generated by the platform as well as to identify the localized exception messages to be reported. Exceptions messages\n * are stored in the {@code KuraExceptionMessagesBundle} Properties Bundle and they are keyed on the exception code.\n *\n * @see KuraErrorCode\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraRuntimeException extends RuntimeException {\n\n    /** The Constant denoting resource bundle. */\n    private static final String KURA_EXCEPTION_MESSAGES_BUNDLE = \"org.eclipse.kura.core.messages.KuraExceptionMessagesBundle\";\n\n    /** The Constant denoting message pattern. */\n    private static final String KURA_GENERIC_MESSAGES_PATTERN = \"Generic Error - {0}: {1}\";\n\n    /** The Logger. */\n    private static final Logger logger = LogManager.getLogger(KuraRuntimeException.class);\n\n    /** The Constant denoting serial version identifier. */\n    private static final long serialVersionUID = -7202805328805688329L;\n\n    /** The associated arguments. */\n    private Object[] arguments;\n\n    /** The associated error code. */\n    private final KuraErrorCode code;\n\n    /**\n     * Builds a new {@link KuraRuntimeException} instance based on the supplied {@link KuraErrorCode}.\n     *\n     * @param code\n     *            the error code\n     */\n    public KuraRuntimeException(final KuraErrorCode code) {\n        this.code = code;\n    }\n\n    /**\n     * Builds a new {@link KuraRuntimeException} instance based on the supplied {@link KuraErrorCode}.\n     *\n     * @param code\n     *            the error code\n     * @param arguments\n     *            the arguments\n     */\n    public KuraRuntimeException(final KuraErrorCode code, final Object... arguments) {\n        this.code = code;\n        this.arguments = arguments;\n    }\n\n    /**\n     * Builds a new {@link KuraRuntimeException} instance based on the supplied {@link KuraErrorCode}, an optional\n     * Throwable cause, and optional arguments for the associated exception message.\n     *\n     * @param code\n     *            the error code\n     * @param cause\n     *            the cause\n     * @param arguments\n     *            the arguments\n     */\n    public KuraRuntimeException(final KuraErrorCode code, final Throwable cause, final Object... arguments) {\n        super(cause);\n        this.code = code;\n        this.arguments = arguments;\n    }\n\n    /**\n     * Gets the error code.\n     *\n     * @return the error code\n     */\n    public KuraErrorCode getCode() {\n        return this.code;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String getLocalizedMessage() {\n        return getLocalizedMessage(Locale.getDefault());\n    }\n\n    /**\n     * Gets the localized message.\n     *\n     * @param locale\n     *            the locale\n     * @return the localized message\n     */\n    private String getLocalizedMessage(final Locale locale) {\n        final String pattern = getMessagePattern(locale, this.code);\n        if (this.code == null || KuraErrorCode.INTERNAL_ERROR.equals(this.code)) {\n            if (this.arguments != null && this.arguments.length > 1) {\n                // append all arguments into a single one\n                final StringBuilder sbAllArgs = new StringBuilder();\n                for (final Object arg : this.arguments) {\n                    sbAllArgs.append(\" - \");\n                    sbAllArgs.append(arg);\n                }\n                this.arguments = new Object[] { sbAllArgs.toString() };\n            }\n        }\n        return MessageFormat.format(pattern, this.arguments);\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String getMessage() {\n        return getLocalizedMessage(Locale.US);\n    }\n\n    /**\n     * Gets the message pattern.\n     *\n     * @param locale\n     *            the locale\n     * @param code\n     *            the code\n     * @return the message pattern\n     */\n    private String getMessagePattern(final Locale locale, final KuraErrorCode code) {\n        // Load the message pattern from the bundle\n        String messagePattern = null;\n        ResourceBundle resourceBundle = null;\n        try {\n            resourceBundle = ResourceBundle.getBundle(KURA_EXCEPTION_MESSAGES_BUNDLE, locale);\n            if (resourceBundle != null && code != null) {\n                messagePattern = resourceBundle.getString(code.name());\n                if (messagePattern == null) {\n                    logger.warn(\"Could not find Exception Messages for Locale {} and code {}\", locale, code);\n                }\n            }\n        } catch (final MissingResourceException mre) {\n            // log the failure to load a message bundle\n            logger.warn(\"Could not load Exception Messages Bundle for Locale {}\", locale);\n        }\n        // If no bundle or code in the bundle is found, use a generic message\n        if (messagePattern == null) {\n            if (code != null) {\n                // build a generic message format\n                messagePattern = MessageFormat.format(KURA_GENERIC_MESSAGES_PATTERN, code.name());\n            } else {\n                // build a generic message format\n                messagePattern = MessageFormat.format(KURA_GENERIC_MESSAGES_PATTERN, \"Unknown\");\n            }\n        }\n        return messagePattern;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraStoreCapacityReachedException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraStoreCapacityReachedException is raised when a message can not be appended\n * to the publishing queue as the internal database buffer has reached its\n * capacity for messages that are not yet published or they are still in transit.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraStoreCapacityReachedException extends KuraStoreException {\n\n    private static final long serialVersionUID = 2622483579047285733L;\n\n    public KuraStoreCapacityReachedException(Object argument) {\n        super(argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraStoreException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraStoreException is raised when a failure occurred during a persistence operation.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraStoreException extends KuraException {\n\n    private static final long serialVersionUID = -3405089623687223551L;\n\n    public KuraStoreException(Object argument) {\n        super(KuraErrorCode.STORE_ERROR, null, argument);\n    }\n\n    public KuraStoreException(Throwable cause, Object argument) {\n        super(KuraErrorCode.STORE_ERROR, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraTimeoutException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraTimeoutException is raised when the attempted operation failed to respond before the timeout exprises.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraTimeoutException extends KuraException {\n\n    private static final long serialVersionUID = -3042470573773974746L;\n\n    public KuraTimeoutException(String message) {\n        super(KuraErrorCode.TIMED_OUT, null, message);\n    }\n\n    public KuraTimeoutException(String message, Throwable cause) {\n        super(KuraErrorCode.TIMED_OUT, cause, message);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraTooManyInflightMessagesException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraTooManyInflightMessagesException is raised if a publish is attempted when there are already too many messages\n * queued for publishing.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraTooManyInflightMessagesException extends KuraException {\n\n    private static final long serialVersionUID = 8759879149959567323L;\n\n    public KuraTooManyInflightMessagesException(Object argument) {\n        super(KuraErrorCode.TOO_MANY_INFLIGHT_MESSAGES, null, argument);\n    }\n\n    public KuraTooManyInflightMessagesException(Throwable cause, Object argument) {\n        super(KuraErrorCode.TOO_MANY_INFLIGHT_MESSAGES, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraUnsupportedModemException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraUnsupportedModemException is raised when a modem of unknown type is attached.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.3\n */\n@ProviderType\npublic class KuraUnsupportedModemException extends KuraException {\n\n    private static final long serialVersionUID = -8851093400895948523L;\n\n    public KuraUnsupportedModemException(Object argument) {\n        super(KuraErrorCode.UNSUPPORTED_MODEM, null, argument);\n    }\n\n    public KuraUnsupportedModemException(Throwable cause, Object argument) {\n        super(KuraErrorCode.UNSUPPORTED_MODEM, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/InferenceEngineMetricsService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.ai.inference;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * \n * The InferenceEngineMetricsService interface provides APIs to get performance\n * and status metrics from an Inference Engine.\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 3.0\n */\n@ProviderType\npublic interface InferenceEngineMetricsService extends InferenceEngineService {\n\n    /**\n     * Retrieve the performance and status metrics from the Inference Engine\n     * as a map of key-value pairs. Typically the keys are the names of the metrics.\n     * \n     * @return a Map containing the metrics. The key of the entries are the metric names.\n     * @throws KuraException\n     */\n    public Map<String, String> getMetrics() throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/InferenceEngineService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.ai.inference;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * An Inference Engine is a library or a server that accepts multiple files\n * describing an Artificial Intelligence and Machine Learning models\n * and allows to perform inference on data.\n * \n * The InferenceEngineService interface is a service API for managing an Inference Engine.\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.3\n */\n@ProviderType\npublic interface InferenceEngineService {\n\n    /**\n     * Run an inference for the given model and inputs.\n     * The input and output type and size must match the\n     * ones in the provided {@link ModelInfo}.\n     *\n     * This will fail if the model is not loaded or the engine is not ready.\n     * \n     * @param modelInfo\n     *            the {@link ModelInfo} of the model to be used\n     * @param inputData\n     *            a list of input {@link Tensor}\n     * @return a list of output {@link Tensor}\n     * @throws KuraIOException\n     */\n    public List<Tensor> infer(ModelInfo modelInfo, List<Tensor> inputData) throws KuraException;\n\n    /**\n     * Load the given model in the inference engine.\n     * If the path of the file containing the model is not provided,\n     * the engine will load it from a standard location in the filesystem.\n     *\n     * @param modelName\n     *            the name of the model\n     * @param model\n     *            an optional String representing the path on the filesystem where the model is stored\n     * @throws KuraIOException\n     */\n    public void loadModel(String modelName, Optional<String> modelPath) throws KuraException;\n\n    /**\n     * Remove a model from the inference engine\n     *\n     * @param modelName\n     *            the name of the model\n     * @throws KuraIOException\n     */\n    public void unloadModel(String modelName) throws KuraException;\n\n    /**\n     * Return true if the model is loaded and ready\n     *\n     * @param modelName\n     *            the name of the model\n     * @throws KuraIOException\n     */\n    public boolean isModelLoaded(String modelName) throws KuraException;\n\n    /*\n     * Return the names of the available models\n     *\n     * @return a List of model names\n     *\n     * @throws KuraIOException\n     */\n    public List<String> getModelNames() throws KuraException;\n\n    /**\n     * Return informations about a specified model\n     *\n     * @return a {@link ModelInfo} that describes a model\n     * @throws KuraIOException\n     */\n    public Optional<ModelInfo> getModelInfo(String modelName) throws KuraException;\n\n    /**\n     * Check if the inference engine is ready for inferencing\n     *\n     * @return true if the server is ready\n     * @throws KuraIOException\n     */\n    public boolean isEngineReady() throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/ModelInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.ai.inference;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The ModelInfo class represents the metadata of a model\n * for Artificial Intelligence and Machine Learning algorithms\n *\n * @since 2.3\n */\n@ProviderType\npublic class ModelInfo {\n\n    private final String name;\n    private final Optional<String> platform;\n    private final Optional<String> version;\n    private final Map<String, Object> parameters;\n    private final List<TensorDescriptor> inputDescriptors;\n    private final List<TensorDescriptor> outputDescriptors;\n\n    /**\n     * Instantiates a new ModelInfo\n     *\n     * @param modelName\n     *            the name of the model\n     * @param platform\n     *            an optional string representing the model platform\n     * @param version\n     *            an optional string representing the model version\n     * @param parameters\n     *            a map containing the model parameters. It can be empty.\n     * @param inputDescriptors\n     *            a list of {@link TensorDescriptor} of the input tensors\n     * @param outputDescriptors\n     *            a list of {@link TensorDescriptor} of the output tensors\n     */\n    protected ModelInfo(String modelName, Optional<String> platform, Optional<String> version,\n            Map<String, Object> parameters, List<TensorDescriptor> inputDescriptors,\n            List<TensorDescriptor> outputDescriptors) {\n        this.name = modelName;\n        this.platform = platform;\n        this.version = version;\n        this.parameters = Collections.unmodifiableMap(parameters);\n        this.inputDescriptors = Collections.unmodifiableList(inputDescriptors);\n        this.outputDescriptors = Collections.unmodifiableList(outputDescriptors);\n    }\n\n    /**\n     * Instantiates a builder for a {@link ModelInfo}\n     *\n     * @param name\n     *            the name of the model\n     * @return a {@link ModelInfoBuilder}\n     */\n    public static ModelInfoBuilder builder(String name) {\n        return new ModelInfoBuilder(name);\n    }\n\n    /**\n     * Creates a new {@link ModelInfoBuilder} and initializes it from this {@link ModelInfo} instance.\n     *\n     * @return a new {@link ModelInfoBuilder}\n     */\n    public ModelInfoBuilder toBuilder() {\n        return ModelInfoBuilder.fromModelInfo(this);\n    }\n\n    /**\n     * Return the name of the model\n     *\n     * @return a string representing the model name\n     */\n    public String getName() {\n        return this.name;\n    }\n\n    /**\n     * Return the platform used for running this model\n     *\n     * @return an optional string representing the model platform\n     */\n    public Optional<String> getPlatform() {\n        return this.platform;\n    }\n\n    /**\n     * Return the version of the model\n     *\n     * @return an optional string representing the version of the model\n     */\n    public Optional<String> getVersion() {\n        return this.version;\n    }\n\n    /**\n     * Return the optional parameters assigned to the model\n     *\n     * @return an unmodifiable map containing the model parameters\n     */\n    public Map<String, Object> getParameters() {\n        return this.parameters;\n    }\n\n    /**\n     * Return the descriptors of the input tensors\n     *\n     * @return an unmodifiable list of {@link TensorDescriptor} of the input tensors\n     */\n    public List<TensorDescriptor> getInputs() {\n        return this.inputDescriptors;\n    }\n\n    /**\n     * Return the descriptors of the output tensors\n     *\n     * @return an unmodifiable list of {@link TensorDescriptor} of the output tensors\n     */\n    public List<TensorDescriptor> getOutputs() {\n        return this.outputDescriptors;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/ModelInfoBuilder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.ai.inference;\n\nimport static java.util.Objects.isNull;\nimport static java.util.Objects.nonNull;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The ModelInfoBuilder class is a builder of {@link ModelInfo}\n *\n * @since 2.3\n */\n@ProviderType\npublic class ModelInfoBuilder {\n\n    private final String name;\n    private Optional<String> platform;\n    private Optional<String> version;\n    private final Map<String, Object> parameters;\n    private final List<TensorDescriptor> inputDescriptors;\n    private final List<TensorDescriptor> outputDescriptors;\n\n    ModelInfoBuilder(String name) {\n        this.name = name;\n        this.platform = Optional.empty();\n        this.version = Optional.empty();\n        this.parameters = new HashMap<>();\n        this.inputDescriptors = new ArrayList<>();\n        this.outputDescriptors = new ArrayList<>();\n    }\n\n    /**\n     * Instantiates a builder for a {@link ModelInfo} and initialises it from the supplied argument.\n     *\n     * @param modelInfo\n     * @return a {@link ModelInfoBuilder}\n     */\n    public static ModelInfoBuilder fromModelInfo(ModelInfo modelInfo) {\n        ModelInfoBuilder builder = new ModelInfoBuilder(modelInfo.getName());\n        builder.parameters.putAll(modelInfo.getParameters());\n        builder.inputDescriptors.addAll(modelInfo.getInputs());\n        builder.outputDescriptors.addAll(modelInfo.getOutputs());\n        builder.platform = modelInfo.getPlatform();\n        builder.version = modelInfo.getVersion();\n        return builder;\n    }\n\n    /**\n     * Set the model platform\n     *\n     * @param platform\n     *            a string representing the platform used for running the model\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder platform(String platform) {\n        if (nonNull(platform) && !platform.isEmpty()) {\n            this.platform = Optional.of(platform);\n        }\n        return this;\n    }\n\n    /**\n     * Set the version of the model\n     *\n     * @param version\n     *            a string representing the version of the model\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder version(String version) {\n        if (nonNull(version) && !version.isEmpty()) {\n            this.version = Optional.of(version);\n        }\n        return this;\n    }\n\n    /**\n     * Add a parameter to the model\n     *\n     * @param name\n     *            the name of the parameter\n     * @param parameter\n     *            an Object representing the value of the parameter\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder addParameter(String name, Object parameter) {\n        this.parameters.put(name, parameter);\n        return this;\n    }\n\n    /**\n     * Remove a parameter from the model\n     *\n     * @param name\n     *            the name of the parameter\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder removeParameter(String name) {\n        this.parameters.remove(name);\n        return this;\n    }\n\n    /**\n     * Add a descriptor of an input tensor\n     *\n     * @param inputDescriptor\n     *            a {@link TensorDescriptor} for the input tensor\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder addInputDescriptor(TensorDescriptor inputDescriptor) {\n        this.inputDescriptors.add(inputDescriptor);\n        return this;\n    }\n\n    /**\n     * Add a descriptor list of an input tensor\n     *\n     * @param inputDescriptors\n     *            a List of {@link TensorDescriptor} for the input tensor\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder addAllInputDescriptor(List<TensorDescriptor> inputDescriptors) {\n        this.inputDescriptors.addAll(inputDescriptors);\n        return this;\n    }\n\n    /**\n     * Remove a descriptor from the input tensor list\n     *\n     * @param inputDescriptor\n     *            a {@link TensorDescriptor} for the input tensor\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder removeInputDescriptor(TensorDescriptor inputDescriptor) {\n        this.inputDescriptors.remove(inputDescriptor);\n        return this;\n    }\n\n    /**\n     * Add a descriptor of an output tensor\n     *\n     * @param outputDescriptor\n     *            a {@link TensorDescriptor} for the output tensor\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder addOutputDescriptor(TensorDescriptor outputDescriptor) {\n        this.outputDescriptors.add(outputDescriptor);\n        return this;\n    }\n\n    /**\n     * Add a descriptor list of an output tensor\n     *\n     * @param outputDescriptors\n     *            a List of {@link TensorDescriptor} for the output tensor\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder addAllOutputDescriptor(List<TensorDescriptor> outputDescriptors) {\n        this.outputDescriptors.addAll(outputDescriptors);\n        return this;\n    }\n\n    /**\n     * Remove a descriptor from the output tensor list\n     *\n     * @param ioututDescriptor\n     *            a {@link TensorDescriptor} for the input tensor\n     * @return a ModelInfoBuilder\n     */\n    public ModelInfoBuilder removeOutputDescriptor(TensorDescriptor outputDescriptor) {\n        this.outputDescriptors.remove(outputDescriptor);\n        return this;\n    }\n\n    /**\n     * Create an instance of ModelInfo\n     *\n     * @return a {@ModelInfo}\n     */\n    public ModelInfo build() {\n        if (isNull(this.name) || this.name.isEmpty()) {\n            throw new IllegalArgumentException(\"The name of the model cannot be empty or null\");\n        }\n        if (this.inputDescriptors.isEmpty()) {\n            throw new IllegalArgumentException(\"The input descriptors list cannot be empty\");\n        }\n        if (this.outputDescriptors.isEmpty()) {\n            throw new IllegalArgumentException(\"The output descriptors list cannot be empty\");\n        }\n        return new ModelInfo(this.name, this.platform, this.version, this.parameters, this.inputDescriptors,\n                this.outputDescriptors);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/Tensor.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.ai.inference;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Tensor class represents the input or output of a model\n * for Artificial Intelligence and Machine Learning algorithms\n *\n * @since 2.3\n */\n@ProviderType\npublic class Tensor {\n\n    private final TensorDescriptor descriptor;\n    private final Class<?> type;\n    private final List<?> data;\n\n    /**\n     * Instantiates a Tensor\n     *\n     * @param type\n     *            the type of tensor data as Java class\n     * @param descriptor\n     *            the {@link TensorDescriptor} of this tensor\n     * @param data\n     *            the list of data of this tensor\n     */\n    public <T> Tensor(Class<T> type, TensorDescriptor descriptor, List<T> data) {\n        this.type = type;\n        this.descriptor = descriptor;\n        this.data = data;\n    }\n\n    /**\n     * Return the descriptor of the tensor\n     *\n     * @return the {@link TensorDescriptor} of the tensor\n     */\n    public TensorDescriptor getDescriptor() {\n        return this.descriptor;\n    }\n\n    /**\n     * Return the data contained in the tensor\n     *\n     * @param type\n     *            the type of the data as Java class. The type argument must match the type of the tensor.\n     * @return a list of data of the given type\n     */\n    @SuppressWarnings(\"unchecked\")\n    public <T> Optional<List<T>> getData(Class<T> type) {\n        if (this.type == type) {\n            return Optional.of((List<T>) this.data);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    /**\n     * Return the type of the tensor\n     *\n     * @return the {@link Class} of the data contained in the tensor\n     */\n    public Class<?> getType() {\n        return this.type;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/TensorDescriptor.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.ai.inference;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The TensorDescriptor class describes the {@link Tensor} used as input or output\n * of a model for Artificial Intelligence and Machine Learning algorithms\n *\n * @since 2.3\n */\n@ProviderType\npublic class TensorDescriptor {\n\n    private final String name;\n    private final String type;\n    private final Optional<String> format;\n    private final List<Long> shape;\n    private final Map<String, Object> parameters;\n\n    /**\n     * Instantiates a tensor descriptor\n     *\n     * @param name\n     *            the name of the tensor\n     * @param type\n     *            a string representing the type of data contained in the tensor.\n     *            Its value is implementation specific, so a user should refer to\n     *            the implementation documentation to figure out the allowed values.\n     * @param shape\n     *            the shape of the data\n     */\n    public TensorDescriptor(String name, String type, Optional<String> format, List<Long> shape,\n            Map<String, Object> parameters) {\n        this.name = name;\n        this.type = type;\n        this.format = format;\n        this.shape = Collections.unmodifiableList(shape);\n        this.parameters = Collections.unmodifiableMap(parameters);\n    }\n\n    /**\n     * Instantiates a builder for a {@link TensorDescriptor}\n     *\n     * @param name\n     *            the name of the tensor\n     * @param type\n     *            a string representing the type of data contained in the tensor.\n     *            Its value is implementation specific, so a user should refer to\n     *            the implementation documentation to figure out the allowed values.\n     * @param shape\n     *            the shape of the data as the size of a multi-dimensional matrix\n     */\n    public static TensorDescriptorBuilder builder(String name, String type, List<Long> shape) {\n        return new TensorDescriptorBuilder(name, type, shape);\n    }\n\n    /**\n     * Creates a new {@link TensorDescriptorBuilder} and initialises it from this {@link TensorDescriptor} instance.\n     *\n     * @return a new {@link TensorDescriptorBuilder}\n     */\n    public TensorDescriptorBuilder toBuilder() {\n        return TensorDescriptorBuilder.fromTensorDescriptor(this);\n    }\n\n    /**\n     * Return the name of the tensor\n     *\n     * @return a string representing the tensor name\n     */\n    public String getName() {\n        return this.name;\n    }\n\n    /**\n     * Return the type of data contained in the tensor.\n     * Its value is implementation specific, so a user should refer to\n     * the implementation documentation to figure out the allowed values.\n     *\n     * @return a string representing the type of data contained in the tensor\n     */\n    public String getType() {\n        return this.type;\n    }\n\n    /**\n     * Return the format of the data.\n     * It represents how the data are organised or grouped in the tensor.\n     * Its value is implementation specific, so a user should refer to\n     * the implementation documentation to figure out the allowed values.\n     *\n     * @return an optional string representing the format of the data in the tensor\n     */\n    public Optional<String> getFormat() {\n        return this.format;\n    }\n\n    /**\n     * Return the shape of the data as the size of a multi-dimensional matrix.\n     *\n     * @return an unmodifiable list of longs representing the shape of the data\n     */\n    public List<Long> getShape() {\n        return this.shape;\n    }\n\n    /**\n     * Return the optional parameters assign to the tensor\n     *\n     * @return an unmodifiable map containing the tensor parameters\n     */\n    public Map<String, Object> getParameters() {\n        return this.parameters;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/TensorDescriptorBuilder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.ai.inference;\n\nimport static java.util.Objects.isNull;\nimport static java.util.Objects.nonNull;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The TensorDescriptorBuilder class is a builder of {@link TensorDescriptor}\n *\n * @since 2.3\n */\n@ProviderType\npublic class TensorDescriptorBuilder {\n\n    private final String name;\n    private final String type;\n    private Optional<String> format;\n    private final List<Long> shape;\n    private final Map<String, Object> parameters;\n\n    TensorDescriptorBuilder(String name, String type, List<Long> shape) {\n        this.name = name;\n        this.type = type;\n        this.format = Optional.empty();\n        this.shape = shape;\n        this.parameters = new HashMap<>();\n    }\n\n    /**\n     * Instantiates a builder for a {@link TensorDescriptor} and initialises it from the supplied argument.\n     *\n     * @param descriptor\n     * @return a {@link TensorDescriptorBuilder}.\n     */\n    public static TensorDescriptorBuilder fromTensorDescriptor(TensorDescriptor descriptor) {\n        final TensorDescriptorBuilder result = new TensorDescriptorBuilder(descriptor.getName(), descriptor.getType(),\n                descriptor.getShape());\n        result.parameters.putAll(descriptor.getParameters());\n        result.format = descriptor.getFormat();\n        return result;\n    }\n\n    /**\n     * Set the format of the data contained in the tensor.\n     * It represents how the data are organised or grouped in the tensor\n     * (e.g. in row-major or column-major order).\n     * Its value is implementation specific, so a user should refer to\n     * the implementation documentation to figure out the allowed values.\n     *\n     * @param format\n     *            a string representing the format of the data in the tensor\n     * @return a TensorDescriptorBuilder\n     */\n    public TensorDescriptorBuilder format(String format) {\n        if (nonNull(format) && !format.isEmpty()) {\n            this.format = Optional.of(format);\n        }\n        return this;\n    }\n\n    /**\n     * Add a parameter to the tensor descriptor\n     *\n     * @param name\n     *            the name of the parameter\n     * @param parameter\n     *            an Object representing the value of the parameter\n     * @return a TensorDescriptorBuilder\n     */\n    public TensorDescriptorBuilder addParameter(String name, Object parameter) {\n        this.parameters.put(name, parameter);\n        return this;\n    }\n\n    /**\n     * Remove a parameter from the tensor descriptor\n     *\n     * @param name\n     *            the name of the parameter\n     * @return a TensorDescriptorBuilder\n     */\n    public TensorDescriptorBuilder removeParameter(String name) {\n        this.parameters.remove(name);\n        return this;\n    }\n\n    /**\n     * Create an instance of TensorDescriptor\n     *\n     * @return a {TensorDescriptor}\n     */\n    public TensorDescriptor build() {\n        if (isNull(this.name) || this.name.isEmpty()) {\n            throw new IllegalArgumentException(\"The name of the tensor cannot be empty or null\");\n        }\n        if (isNull(this.type) || this.type.isEmpty()) {\n            throw new IllegalArgumentException(\"The type of the tensor cannot be empty or null\");\n        }\n        if (isNull(this.shape) || this.shape.isEmpty()) {\n            throw new IllegalArgumentException(\"The shape of the tensor cannot be empty or null\");\n        }\n        return new TensorDescriptor(this.name, this.type, this.format, this.shape, this.parameters);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/Extensible.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.annotation;\n\nimport static java.lang.annotation.ElementType.TYPE;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation denotes that the annotated type can be extended by others for\n * special purpose functionalities\n *\n * @since 1.2\n */\n@Target(TYPE)\n@Retention(RUNTIME)\n@Documented\npublic @interface Extensible {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/Immutable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.annotation;\n\nimport static java.lang.annotation.ElementType.TYPE;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation denotes that the annotated type is immutable and eventually\n * it becomes thread-safe. By definition, a class is considered to be an\n * immutable class in which the state of its instance cannot be <i>observed</i>\n * to be changed. So, inherently this implies that,\n * <ul>\n * <li>All of its public fields must be declared as {@code final}</li>\n * <li>All of its public final reference fields are either {@code null} or refer\n * to other immutable objects</li>\n * <li>Constructors and methods do not contain references to any potentially\n * mutable internal state.</li>\n * </ul>\n * <p/>\n * In addition, the immutable objects are inherently thread-safe and that is the\n * reason, they can be passed between threads or published without explicit\n * synchronization or locks.\n *\n * @since 1.2\n */\n@Documented\n@Target(TYPE)\n@Retention(RUNTIME)\npublic @interface Immutable {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/NotThreadSafe.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.annotation;\n\nimport static java.lang.annotation.ElementType.TYPE;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation denotes that the annotated type is not thread-safe. On the\n * contrary, if any type is not annotated with this annotation, does not\n * necessarily indicate that the type in consideration is thread-safe. The\n * motive of this annotation is to inform consumers of the annotated type that\n * consumers must not make any abrupt assumption that the type is thread-safe.\n * If the author of the type believes that the consumer can make such\n * assumptions of thread-safety for types even though the types are not, it is\n * better to annotate the type with this annotation.\n *\n * @since 1.2\n */\n@Documented\n@Target(TYPE)\n@Retention(RUNTIME)\npublic @interface NotThreadSafe {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/Nullable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.annotation;\n\nimport static java.lang.annotation.ElementType.FIELD;\nimport static java.lang.annotation.ElementType.LOCAL_VARIABLE;\nimport static java.lang.annotation.ElementType.METHOD;\nimport static java.lang.annotation.ElementType.PARAMETER;\nimport static java.lang.annotation.RetentionPolicy.CLASS;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\n/**\n * The existence of this annotation indicates that the author believes that the\n * annotated field or method or parameter or local variable can accept null\n * values\n *\n * @since 1.2\n */\n@Documented\n@Target({ FIELD, METHOD, PARAMETER, LOCAL_VARIABLE })\n@Retention(CLASS)\npublic @interface Nullable {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/ThreadSafe.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.annotation;\n\nimport static java.lang.annotation.ElementType.TYPE;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\n/**\n * This annotation denotes that the annotated type is thread-safe. This\n * inherently means that there should not be any sequence of operations followed\n * which could potentially render the instance of the annotated type into an\n * invalid state.\n *\n * @since 1.2\n */\n@Documented\n@Target(TYPE)\n@Retention(RUNTIME)\npublic @interface ThreadSafe {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides all necessary annotations required for Kura\n *\n * @since 1.0.10\n */\npackage org.eclipse.kura.annotation;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/asset/Asset.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.asset;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.channel.listener.ChannelListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface Asset provides higher level abstraction to operate or\n * perform actions on the industrial device. This actually propagates the\n * necessary operations to the associated device driver. The asset exposes the\n * generic operations to perform read, write and monitor operations. The asset\n * only specifies the channel specific configuration (which is very channel\n * descriptor specific) and the associated driver is mainly responsible for\n * performing all the lower level tasks on the provided channel configuration.\n *\n * @see AssetRecord\n * @see AssetConfiguration\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n */\n@ProviderType\npublic interface Asset {\n\n    /**\n     * Gets the asset configuration.\n     *\n     * @return the asset configuration\n     */\n    public AssetConfiguration getAssetConfiguration();\n\n    /**\n     * Reads the communication channels identified by the set of channel names provided as argument.\n     * The read result is returned as a list of channel records.\n     * If for some reason the value of a channel cannot be read,\n     * a channel record containing a proper channel flag should be returned anyways.\n     * The channel flag shall best describe the reason of failure.\n     * If the connection to the asset is interrupted, then any necessary resources\n     * that correspond to this connection should be cleaned up and a {@code KuraException} shall be\n     * thrown.\n     *\n     * @param channelNames\n     *            the set of channel names which are to be read. The channel name\n     *            must be unique for every channel belonging to an asset.\n     *            Channel names are case sensitive.\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the method is not implemented by the asset then specific\n     *             error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED}\n     *             needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException}\n     * @throws KuraException\n     *             if the connection to the asset was interrupted, then error\n     *             code {@code KuraErrorCode#CONNECTION_FAILED} needs to be set\n     *             in the thrown {@link KuraException}.\n     * @throws NullPointerException\n     *             if argument is null\n     * @return the list of channel records which comprises the currently read\n     *         value in case of success or the reason of failure\n     */\n    public List<ChannelRecord> read(Set<String> channelNames) throws KuraException;\n\n    /**\n     * Performs a read on all READ or READ_WRITE channels that are defined on this asset and returns\n     * the result as a list of {@link ChannelRecord} instances.\n     *\n     * @see Asset#read(List)\n     *\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the method is not implemented by the asset then specific\n     *             error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED}\n     *             needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException}\n     * @throws KuraException\n     *             if the connection to the asset was interrupted, then error\n     *             code {@code KuraErrorCode#CONNECTION_FAILED} needs to be set\n     *             in the thrown {@link KuraException}.\n     * @return the list of channel records which comprises the currently read\n     *         value in case of success or the reason of failure\n     */\n    public List<ChannelRecord> readAllChannels() throws KuraException;\n\n    /**\n     * Registers a channel listener for the provided channel name for a monitor\n     * operation on it.\n     *\n     * @param channelName\n     *            the channel name. The channel name\n     *            must be unique for every channel belonging to an asset.\n     *            Channel names are case sensitive.\n     * @param channelListener\n     *            the channel listener\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the method is not implemented by the asset then specific\n     *             error code {@link org.eclipse.kura.KuraErrorCode#OPERATION_NOT_SUPPORTED}\n     *             needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException}\n     * @throws KuraException\n     *             if the connection to the asset was interrupted, then error\n     *             code {@link org.eclipse.kura.KuraErrorCode#CONNECTION_FAILED} needs to be set\n     *             in the thrown {@link KuraException} and if the channel is not\n     *             present, error code {@link org.eclipse.kura.KuraErrorCode#INTERNAL_ERROR}\n     *             needs to be set in the thrown {@link KuraException}. For any\n     *             other internal exception, then error code\n     *             {@link org.eclipse.kura.KuraErrorCode#INTERNAL_ERROR} will be set.\n     * @throws NullPointerException\n     *             if any of the arguments is null\n     * @throws IllegalArgumentException\n     *             If the provided channel name is not present in the configuration\n     *             of this asset\n     */\n    public void registerChannelListener(String channelName, ChannelListener channelListener) throws KuraException;\n\n    /**\n     * Unregisters a already registered channel listener which has been registered\n     * for a monitor operation\n     *\n     * @param channelListener\n     *            the channel listener to unregister\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the method is not implemented by the asset then specific\n     *             error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED}\n     *             needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException}\n     * @throws KuraException\n     *             For any other internal exception, then error code\n     *             {@code KuraErrorCode#INTERNAL_ERROR} will be set.\n     * @throws NullPointerException\n     *             if argument is null\n     */\n    public void unregisterChannelListener(ChannelListener channelListener) throws KuraException;\n\n    /**\n     * Writes the data to the provided communication channels that correspond to\n     * the given channel records. The write result is returned by setting the\n     * channel flag {@link org.eclipse.kura.channel.ChannelFlag#SUCCESS} in the provided channel\n     * records. If the connection to the asset is interrupted, then any\n     * necessary resources that correspond to this connection should be cleaned\n     * up and a {@link KuraException} with a suitable error code shall be\n     * thrown.\n     *\n     * @param channelRecords\n     *            the channel records hold the information of what channels are to\n     *            be written and the values that are to be written. They will be\n     *            filled by this function with a channel flag stating whether the\n     *            write process is successful or not.\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the method is not implemented by the asset then specific\n     *             error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED}\n     *             needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException}\n     * @throws KuraException\n     *             if the connection to the asset was interrupted, then error\n     *             code {@code KuraErrorCode#CONNECTION_FAILED} needs to be set\n     *             in the thrown {@link KuraException}\n     * @throws NullPointerException\n     *             if argument is null\n     */\n    public void write(List<ChannelRecord> channelRecords) throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/asset/AssetConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.asset;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.eclipse.kura.channel.Channel;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Class AssetConfiguration is responsible for storing the configuration for\n * an industrial device (also known as Asset in the context of Eclipse\n * Kura).<br>\n * <br>\n *\n * @see Channel\n * @see org.eclipse.kura.channel.ChannelType\n * @see org.eclipse.kura.type.DataType\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class AssetConfiguration {\n\n    /**\n     * The list of channels associated with this asset. The association denotes\n     * channel name and its actual object reference pair.\n     */\n    private final Map<String, Channel> assetChannels;\n\n    /** the asset description. */\n    private String assetDescription;\n\n    /** the driver PID as associated with this asset. */\n    private final String driverPid;\n\n    /**\n     * Instantiates a new asset configuration.\n     *\n     * @param description\n     *            the description of the asset\n     * @param driverPid\n     *            the driver PID\n     * @param channels\n     *            the map of all channel configurations\n     * @throws NullPointerException\n     *             if any of the arguments is null\n     */\n    public AssetConfiguration(final String description, final String driverPid, final Map<String, Channel> channels) {\n        requireNonNull(description, \"Asset description cannot be null\");\n        requireNonNull(driverPid, \"Asset driver PID cannot be null\");\n        requireNonNull(channels, \"Asset channel configurations cannot be null\");\n\n        this.assetDescription = description;\n        this.driverPid = driverPid;\n        this.assetChannels = Collections.unmodifiableMap(channels);\n    }\n\n    /**\n     * Gets the asset channels.\n     *\n     * @return the asset channels\n     */\n    public Map<String, Channel> getAssetChannels() {\n        return this.assetChannels;\n    }\n\n    /**\n     * Gets the asset description.\n     *\n     * @return the asset description\n     */\n    public String getAssetDescription() {\n        return this.assetDescription;\n    }\n\n    /**\n     * Gets the driver PID.\n     *\n     * @return the driver PID\n     */\n    public String getDriverPid() {\n        return this.driverPid;\n    }\n\n    /**\n     * Sets the asset description.\n     *\n     * @param description\n     *            the new asset description\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public void setAssetDescription(final String description) {\n        requireNonNull(description, \"Asset description cannot be null\");\n        this.assetDescription = description;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"AssetConfiguration [channels=\" + this.assetChannels + \", description=\" + this.assetDescription\n                + \", driverPid=\" + this.driverPid + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/asset/AssetService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.asset;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The interface AssetService is an utility service API to provide useful\n * methods for assets\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n */\n@ProviderType\npublic interface AssetService {\n\n    /**\n     * Gets the asset instance by the provided asset PID\n     * ({@code kura.service.pid}).\n     *\n     * @param assetPid\n     *            the asset PID to check\n     * @return the asset instance\n     * @throws NullPointerException\n     *             if the provided asset PID is null\n     */\n    public Asset getAsset(String assetPid);\n\n    /**\n     * Gets the asset PID. ({@code kura.service.pid}) by the provided asset\n     * instance\n     *\n     * @param asset\n     *            the asset instance to check\n     * @return the asset PID\n     * @throws NullPointerException\n     *             if the provided asset instance is null\n     */\n    public String getAssetPid(Asset asset);\n\n    /**\n     * Returns the list containing all the available asset instances\n     *\n     * @return the list of assets available in service registry or empty list\n     *         if no assets are available\n     */\n    public List<Asset> listAssets();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/asset/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides all necessary APIs for Kura Asset Component Model\n *\n * @since 1.2\n */\npackage org.eclipse.kura.asset;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/audit/AuditConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.audit;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Provides some well known audit context properties.\n * \n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.2\n */\n@ProviderType\npublic enum AuditConstants {\n\n    /**\n     * Contains an identifier for the entry point associated with an audit context. It must always be present.\n     */\n    KEY_ENTRY_POINT(\"entrypoint\"),\n    /**\n     * Reports the IP address of the device that performed a request. It can be missing.\n     */\n    KEY_IP(\"ip\"),\n    /**\n     * Reports the IP address of the Kura Identity associated with a request. It can be missing.\n     */\n    KEY_IDENTITY(\"identity\"),\n    /**\n     * A value for the <code>entrypoint</property> that indicates a context created by an internal framework\n     * component and not associated with an external entity.\n     */\n    ENTRY_POINT_INTERNAL(\"Internal\");\n\n    private final String value;\n\n    AuditConstants(final String value) {\n        this.value = value;\n    }\n\n    public String getValue() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/audit/AuditContext.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.audit;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a context that can be created by a framework entry point for audit purposes. Examples of entry points\n * are the Web UI, a cloud connection or the Rest service.\n * An AuditContext contains a set of properties. Some property are well known and described by the\n * {@link AuditConstants} enumeration, other custom properties can be added by the entry point implementation.\n * \n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.2\n */\n@ProviderType\npublic class AuditContext {\n\n    private static ThreadLocal<AuditContext> localContext = new ThreadLocal<>();\n\n    private final Map<String, String> properties;\n\n    /**\n     * Creates a new {@link AuditContext}.\n     * \n     * @param properties\n     *            The properties to be associated with this context. It must be a non null mutable map.\n     */\n    public AuditContext(final Map<String, String> properties) {\n        this.properties = requireNonNull(properties);\n    }\n\n    /**\n     * Returns the properties associated with this context\n     * \n     * @return the properties.\n     */\n    public Map<String, String> getProperties() {\n        return this.properties;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public String toString() {\n        return properties.toString().replaceAll(\"[\\n\\r\\t]\", \"_\");\n    }\n\n    /**\n     * Creates a copy of this AuditContext with a new and independent set of properties.\n     * \n     * @return a copy of this AuditContext.\n     */\n    public AuditContext copy() {\n        return new AuditContext(new HashMap<>(this.properties));\n    }\n\n    /**\n     * Returns the {@link AuditContext} associated with the current thread, if set, or a context with\n     * {@link AuditConstants#KEY_ENTRY_POINT} set to {@link AuditConstants#ENTRY_POINT_INTERNAL} otherwise.\n     * \n     * @return the {@link AuditContext}\n     */\n    public static AuditContext currentOrInternal() {\n        final AuditContext current = localContext.get();\n\n        if (current != null) {\n            return current;\n        } else {\n            final Map<String, String> properties = new HashMap<>(1);\n            properties.put(AuditConstants.KEY_ENTRY_POINT.getValue(), \"Internal\");\n\n            return new AuditContext(properties);\n        }\n    }\n\n    /**\n     * Returns the {@link AuditContext} associated with the current thread, if any.\n     * \n     * @return the {@link AuditContext} associated with this thread or empty if none is set\n     */\n    public static Optional<AuditContext> current() {\n        return Optional.ofNullable(localContext.get());\n    }\n\n    /**\n     * Sets the provided context as the thread local instance and returns a {@link Scope} that can be used for removing\n     * it.\n     * Subsequent calls to {@link AuditContext#currentOrInternal()} performed on the same thread will return the\n     * provided\n     * {@link AuditContext} instance until the returned {@link Scope} is closed.\n     * \n     * @param context\n     *            the context\n     * @return a {@link Scope} that removes the thread local context when closed.\n     */\n    public static Scope openScope(final AuditContext context) {\n        return new Scope(context);\n    }\n\n    /**\n     * Resents an {@link AutoCloseable} scope that removes the associated {@link AuditContext} when closed.\n     * See {@link AuditContext#openScope(AuditContext)} for more details.\n     * \n     * @noextend This class is not intended to be subclassed by clients.\n     * @since 2.2\n     */\n    @ProviderType\n    public static class Scope implements AutoCloseable {\n\n        private final AuditContext context;\n\n        private Scope(final AuditContext context) {\n            this.context = context;\n            localContext.set(context);\n        }\n\n        /**\n         * Removes the associated {@link AuditContext} from thread local storage.\n         * \n         * {@inheritDoc}\n         */\n        @Override\n        public void close() {\n            if (localContext.get() == context) {\n                localContext.remove();\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/audit/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides functionalities to track entry point information for audit purposes.\n *\n */\npackage org.eclipse.kura.audit;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeAdapter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le;\n\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.concurrent.Future;\nimport java.util.function.Consumer;\n\nimport org.eclipse.kura.KuraBluetoothDiscoveryException;\nimport org.eclipse.kura.KuraBluetoothRemoveException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothAdapter represents the physical Bluetooth adapter on the host machine (ex: hci0).\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeAdapter {\n\n    /**\n     * Search for a BLE device with the specified address. The method will perform a BLE discovery for at most timeout\n     * seconds or until the device is found. It will return a Future instance and the discovered device can be\n     * retrieved using the get() method. The get(long timeout, TimeUnit unit) is not supported and acts as the get()\n     * method.\n     *\n     * @param timeout\n     *            timeout in seconds for device discovery\n     * @param address\n     *            MAC address of the BLE device\n     * @return Future\n     */\n    public Future<BluetoothLeDevice> findDeviceByAddress(long timeout, String address);\n\n    /**\n     * Search for a BLE device with the specified name. The method will perform a BLE discovery for at most timeout\n     * seconds or until the device is found. It will return a Future instance and the discovered device can be\n     * retrieved using the get() method. The get(long timeout, TimeUnit unit) is not supported and acts as the get()\n     * method.\n     *\n     * @param timeout\n     *            timeout in seconds for device discovery\n     * @param name\n     *            system name of the BLE device\n     * @return Future\n     */\n    public Future<BluetoothLeDevice> findDeviceByName(long timeout, String name);\n\n    /**\n     * Search for a BLE device with the specified address. The method will perform a BLE discovery for at most timeout\n     * seconds or until the device is found. When the device is found or the timeout is reached the consumer is used to\n     * get the device.\n     *\n     * @param timeout\n     *            timeout in seconds for device discovery\n     * @param address\n     *            MAC address of the BLE device\n     * @param consumer\n     *            the consumer used to get the device\n     */\n    public void findDeviceByAddress(long timeout, String address, Consumer<BluetoothLeDevice> consumer);\n\n    /**\n     * Search for a BLE device with the specified name. The method will perform a BLE discovery for at most timeout\n     * seconds or until the device is found. When the device is found or the timeout is reached the consumer is used to\n     * get the device.\n     *\n     * @param timeout\n     *            timeout in seconds for device discovery\n     * @param name\n     *            system name of the BLE device\n     * @param consumer\n     *            the consumer used to get the device\n     */\n    public void findDeviceByName(long timeout, String name, Consumer<BluetoothLeDevice> consumer);\n\n    /**\n     * Search for BLE devices. The method will perform a BLE discovery for timeout seconds. It will return a Future\n     * instance and the discovered devices can be retrieved using the get() method. The get(long timeout, TimeUnit unit)\n     * is not supported and acts as the get() method.\n     *\n     * @param timeout\n     *            timeout in seconds for device discovery\n     * @return Future\n     */\n    public Future<List<BluetoothLeDevice>> findDevices(long timeout);\n\n    /**\n     * Search for BLE devices. The method will perform a BLE discovery for timeout seconds. When the timeout is reached\n     * the consumer is used to get the devices.\n     *\n     * @param timeout\n     *            timeout in seconds for device discovery\n     * @param consumer\n     *            the consumer used to get the device\n     */\n    public void findDevices(long timeout, Consumer<List<BluetoothLeDevice>> consumer);\n\n    /**\n     * Starts a BLE discovery.\n     *\n     * @throws KuraBluetoothDiscoveryException\n     * @since 2.2\n     */\n    public void startDiscovery() throws KuraBluetoothDiscoveryException;\n\n    /**\n     * Stops a BLE discovery.\n     *\n     * @throws KuraBluetoothDiscoveryException\n     */\n    public void stopDiscovery() throws KuraBluetoothDiscoveryException;\n\n    /**\n     * Returns the hardware address of this adapter.\n     *\n     * @return The hardware address of this adapter.\n     */\n    public String getAddress();\n\n    /**\n     * Returns the system name of this adapter.\n     *\n     * @return The system name of this adapter.\n     */\n    public String getName();\n\n    /**\n     * Returns the interface name of this adapter.\n     *\n     * @return The interface name of this adapter.\n     */\n    public String getInterfaceName();\n\n    /**\n     * Returns the local ID of the adapter.\n     *\n     * @return The local ID of the adapter.\n     */\n    public String getModalias();\n\n    /**\n     * Returns the friendly name of this adapter.\n     *\n     * @return The friendly name of this adapter, or NULL if not set.\n     */\n    public String getAlias();\n\n    /**\n     * Sets the friendly name of this adapter.\n     *\n     */\n    public void setAlias(String value);\n\n    /**\n     * Returns the Bluetooth class of the adapter.\n     *\n     * @return The Bluetooth class of the adapter.\n     */\n    public long getBluetoothClass();\n\n    /**\n     * Returns the power state the adapter.\n     *\n     * @return The power state of the adapter.\n     */\n    public boolean isPowered();\n\n    /**\n     * Sets the power state the adapter.\n     */\n    public void setPowered(boolean value);\n\n    /**\n     * Returns the discoverable state the adapter.\n     *\n     * @return The discoverable state of the adapter.\n     */\n    public boolean isDiscoverable();\n\n    /**\n     * Sets the discoverable state the adapter.\n     */\n    public void setDiscoverable(boolean value);\n\n    /**\n     * Returns the discoverable timeout the adapter.\n     *\n     * @return The discoverable timeout of the adapter.\n     */\n    public long getDiscoverableTimeout();\n\n    /**\n     * Sets the discoverable timeout the adapter. A value of 0 disables\n     * the timeout.\n     * \n     * @deprecated since 2.2 use instead {@link setDiscoverableTimeout}\n     */\n    @Deprecated\n    public void setDiscoverableTimout(long value);\n\n    /**\n     * Sets the discoverable timeout the adapter. A value of 0 disables\n     * the timeout.\n     * \n     * @since 2.2\n     */\n    public void setDiscoverableTimeout(long value);\n\n    /**\n     * Returns the pairable state the adapter.\n     *\n     * @return The pairable state of the adapter.\n     */\n    public boolean isPairable();\n\n    /**\n     * Sets the discoverable state the adapter.\n     */\n    public void setPairable(boolean value);\n\n    /**\n     * Returns the timeout in seconds after which pairable state turns off\n     * automatically, 0 means never.\n     *\n     * @return The pairable timeout of the adapter.\n     */\n    public long getPairableTimeout();\n\n    /**\n     * Sets the timeout after which pairable state turns off automatically, 0 means never.\n     */\n    public void setPairableTimeout(long value);\n\n    /**\n     * Returns the discovering state the adapter.\n     *\n     * @return The discovering state of the adapter.\n     */\n    public boolean isDiscovering();\n\n    /**\n     * Returns the UUIDs of the adapter.\n     *\n     * @return Array containing the UUIDs of the adapter.\n     */\n    public UUID[] getUUIDs();\n\n    /**\n     * Remove all the known devices from the system. Be aware that after the removing the objects representing the\n     * devices will not be valid anymore and any operation on them will have no effect.\n     *\n     * @return The number of devices removed from internal list\n     * @throws KuraBluetoothRemoveException\n     *\n     * @since 2.0\n     */\n    public int removeDevices() throws KuraBluetoothRemoveException;\n\n    /**\n     * Sets a scan filter for this adapter.\n     *\n     * <p>\n     * When a remote device is found that advertises any UUID from UUIDs, it will be reported if:\n     * <ul>\n     * <li>Pathloss and RSSI are both empty.</li>\n     * <li>only Pathloss param is set, device advertise TX power, and computed pathloss is less than Pathloss\n     * param.</li>\n     * <li>only RSSI param is set, and received RSSI is higher than RSSI param.</li>\n     * </ul>\n     * <p>\n     *\n     * <p>\n     * If \"auto\" transport is requested, scan will use LE, BREDR, or both, depending on what's\n     * currently enabled on the controller.\n     *\n     * To remove the filter, call this method with empty parameters.\n     *\n     * @param uuids\n     *            the uuids advertised by the devices\n     * @param rssi\n     *            the Receiver Signal Strength Indication value\n     * @param pathloss\n     *            the pathloss value\n     * @param trasportType\n     *            the trasportType (LE or BREDR)\n     *\n     * @deprecated use instead {@link setDiscoveryFilter(List<UUID>, int, int, BluetoothTransportType, boolean)}\n     * @since 2.0\n     */\n    @Deprecated\n    public void setDiscoveryFilter(List<UUID> uuids, int rssi, int pathloss, BluetoothTransportType transportType);\n\n    /**\n     * Sets a scan filter for this adapter.\n     *\n     * <p>\n     * When a remote device is found that advertises any UUID from UUIDs, it will be reported if:\n     * <ul>\n     * <li>Pathloss and RSSI are both empty.</li>\n     * <li>only Pathloss param is set, device advertise TX power, and computed pathloss is less than Pathloss\n     * param.</li>\n     * <li>only RSSI param is set, and received RSSI is higher than RSSI param.</li>\n     * </ul>\n     * <p>\n     *\n     * <p>\n     * If \"auto\" transport is requested, scan will use LE, BREDR, or both, depending on what's\n     * currently enabled on the controller.\n     *\n     * To remove the filter, call this method with empty parameters.\n     *\n     * @param uuids\n     *            the uuids advertised by the devices\n     * @param rssi\n     *            the Receiver Signal Strength Indication value\n     * @param pathloss\n     *            the pathloss value\n     * @param trasportType\n     *            the trasportType (LE or BREDR)\n     * @param duplicateData\n     *            whether to filter duplicate data\n     *\n     * @since 2.2\n     */\n    public void setDiscoveryFilter(List<UUID> uuids, int rssi, int pathloss, BluetoothTransportType transportType,\n            boolean duplicateData);\n\n    /**\n     * Set a device discovery filter based on RSSI value. Only devices with rssi greater than the provided value will be\n     * reported. Set it to 0 to remove the filter.\n     *\n     * @param rssi\n     *            the Receiver Signal Strength Indication value used by the filter\n     *\n     * @since 2.0\n     */\n    public void setRssiDiscoveryFilter(int rssi);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\nimport org.eclipse.kura.KuraBluetoothConnectionException;\nimport org.eclipse.kura.KuraBluetoothPairException;\nimport org.eclipse.kura.KuraBluetoothRemoveException;\nimport org.eclipse.kura.KuraBluetoothResourceNotFoundException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeDevice represents a Bluetooth LE device to which connections\n * may be made.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeDevice {\n\n    /**\n     * Find a BluetoothLeGattService specifying the UUID of the service.\n     *\n     * @param uuid\n     *            The UUID of the GATT service\n     * @return The BluetoothLeGattService\n     * @throws KuraBluetoothResourceNotFoundException\n     */\n    public BluetoothLeGattService findService(UUID uuid) throws KuraBluetoothResourceNotFoundException;\n\n    /**\n     * Find a BluetoothLeGattService specifying the UUID of the service and the timeout in seconds.\n     *\n     * @since 1.4\n     * @param uuid\n     *            The UUID of the GATT service\n     * @param timeout\n     *            The timeout for retrieving the service\n     * @return The BluetoothLeGattService\n     * @throws KuraBluetoothResourceNotFoundException\n     * \n     * @deprecated since 2.2 use instead {@link findService(UUID)}\n     */\n    @Deprecated\n    public BluetoothLeGattService findService(UUID uuid, long timeout) throws KuraBluetoothResourceNotFoundException;\n\n    /**\n     * Returns a list of BluetoothGattServices available on this device.\n     *\n     * @return A list of BluetoothLeGattService\n     * @throws KuraBluetoothResourceNotFoundException\n     */\n    public List<BluetoothLeGattService> findServices() throws KuraBluetoothResourceNotFoundException;\n\n    /**\n     * Disconnect from this device, removing all connected profiles.\n     *\n     * @throws KuraBluetoothConnectionException\n     */\n    public void disconnect() throws KuraBluetoothConnectionException;\n\n    /**\n     * A connection to this device is established, connecting each profile\n     * flagged as auto-connectable.\n     *\n     * @throws KuraBluetoothConnectionException\n     */\n    public void connect() throws KuraBluetoothConnectionException;\n\n    /**\n     * Connects a specific profile available on the device, given by UUID\n     *\n     * @param uuid\n     *            The UUID of the profile to be connected\n     * @throws KuraBluetoothConnectionException\n     */\n    public void connectProfile(UUID uuid) throws KuraBluetoothConnectionException;\n\n    /**\n     * Disconnects a specific profile available on the device, given by UUID\n     *\n     * @param uuid\n     *            The UUID of the profile to be disconnected\n     * @throws KuraBluetoothConnectionException\n     */\n    public void disconnectProfile(UUID uuid) throws KuraBluetoothConnectionException;\n\n    /**\n     * A connection to this device is established, and the device is then\n     * paired.\n     *\n     * @throws KuraBluetoothPairException\n     */\n    public void pair() throws KuraBluetoothPairException;\n\n    /**\n     * Cancel a pairing operation\n     *\n     * @throws KuraBluetoothPairException\n     */\n    public void cancelPairing() throws KuraBluetoothPairException;\n\n    /**\n     * Returns the hardware address of this device.\n     *\n     * @return The hardware address of this device.\n     */\n    public String getAddress();\n\n    /**\n     * Returns the remote friendly name of this device.\n     *\n     * @return The remote friendly name of this device, or NULL if not set.\n     */\n    public String getName();\n\n    /**\n     * Returns an alternative friendly name of this device.\n     *\n     * @return The alternative friendly name of this device, or NULL if not set.\n     */\n    public String getAlias();\n\n    /**\n     * Sets an alternative friendly name of this device.\n     */\n    public void setAlias(String value);\n\n    /**\n     * Returns the Bluetooth class of the device.\n     *\n     * @return The Bluetooth class of the device.\n     */\n    public int getBluetoothClass();\n\n    /**\n     * Returns the appearance of the device, as found by GAP service.\n     *\n     * @return The appearance of the device, as found by GAP service.\n     */\n    public short getAppearance();\n\n    /**\n     * Returns the proposed icon name of the device.\n     *\n     * @return The proposed icon name, or NULL if not set.\n     */\n    public String getIcon();\n\n    /**\n     * Returns the paired state the device.\n     *\n     * @return The paired state of the device.\n     */\n    public boolean isPaired();\n\n    /**\n     * Returns the trusted state the device.\n     *\n     * @return The trusted state of the device.\n     */\n    public boolean isTrusted();\n\n    /**\n     * Sets the trusted state the device.\n     */\n    public void setTrusted(boolean value);\n\n    /**\n     * Returns the blocked state the device.\n     *\n     * @return The blocked state of the device.\n     */\n    public boolean isBlocked();\n\n    /**\n     * Sets the blocked state the device.\n     */\n    public void setBlocked(boolean value);\n\n    /**\n     * Returns if device uses only pre-Bluetooth 2.1 pairing mechanism.\n     *\n     * @return True if device uses only pre-Bluetooth 2.1 pairing mechanism.\n     */\n    public boolean isLegacyPairing();\n\n    /**\n     * Returns the Received Signal Strength Indicator of the device.\n     *\n     * @return The Received Signal Strength Indicator of the device.\n     */\n    public short getRSSI();\n\n    /**\n     * Returns the connected state of the device.\n     *\n     * @return The connected state of the device.\n     */\n    public boolean isConnected();\n\n    /**\n     * Returns the UUIDs of the device.\n     *\n     * @return Array containing the UUIDs of the device, ends with NULL.\n     */\n    public UUID[] getUUIDs();\n\n    /**\n     * Returns the local ID of the adapter.\n     *\n     * @return The local ID of the adapter.\n     */\n    public String getModalias();\n\n    /**\n     * Returns the adapter on which this device was discovered or\n     * connected.\n     *\n     * @return The adapter.\n     */\n    public BluetoothLeAdapter getAdapter();\n\n    /**\n     * Returns a map containing manufacturer specific advertisement data.\n     * An entry has a short key and an array of bytes.\n     *\n     * @return manufacturer specific advertisement data.\n     */\n    public Map<Short, byte[]> getManufacturerData();\n\n    /**\n     * Returns a map containing service advertisement data.\n     * An entry has a UUID key and an array of bytes.\n     *\n     * @return service advertisement data.\n     */\n    public Map<UUID, byte[]> getServiceData();\n\n    /**\n     * Returns the transmission power level (0 means unknown).\n     *\n     * @return the transmission power level (0 means unknown).\n     */\n    public short getTxPower();\n\n    /**\n     * Returns if the service discovery is ended.\n     *\n     * @since 2.0\n     */\n    public boolean isServicesResolved();\n\n    /**\n     * Remove this device from the system. Be aware that after the removing the object representing the device\n     * will not be valid anymore and any operation on it will have no effect.\n     *\n     * @return TRUE if the device has been removed\n     * @throws BluetKuraBluetoothRemoveExceptionoothException\n     *\n     * @since 2.0\n     * @deprecated since 2.2 use instead {@link removeDevice}\n     */\n    @Deprecated\n    public boolean remove() throws KuraBluetoothRemoveException;\n\n    /**\n     * Remove this device from the system. Be aware that after the removing the object representing the device\n     * will not be valid anymore and any operation on it will have no effect.\n     *\n     * @throws BluetKuraBluetoothRemoveExceptionoothException\n     *\n     * @since 2.2\n     */\n    public void removeDevice() throws KuraBluetoothRemoveException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeGattCharacteristic.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le;\n\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.function.Consumer;\n\nimport org.eclipse.kura.KuraBluetoothIOException;\nimport org.eclipse.kura.KuraBluetoothNotificationException;\nimport org.eclipse.kura.KuraBluetoothResourceNotFoundException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeGattCharacteristic represents a GATT characteristic.\n * If an application uses value notifications, it has to keep a reference to the corresponding GATT characteristic to\n * avoid that the garbage collector deletes it and removes the associated consumer.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeGattCharacteristic {\n\n    /**\n     * Find a BluetoothLeGattDescriptor specifying the UUID of the descriptor.\n     *\n     * @param uuid\n     *            The UUID of the GATT descriptor\n     * @return The BluetoothLeGattDescriptor\n     * @throws KuraBluetoothResourceNotFoundException\n     */\n    public BluetoothLeGattDescriptor findDescriptor(UUID uuid) throws KuraBluetoothResourceNotFoundException;\n\n    /**\n     * Find a BluetoothLeGattDescriptor specifying the UUID of the descriptor and the timeout in seconds.\n     *\n     * @since 1.4\n     * @param uuid\n     *            The UUID of the GATT descriptor\n     * @param timeout\n     *            The timeout for retrieving the characteristic\n     * @return The BluetoothLeGattDescriptor\n     * @throws KuraBluetoothResourceNotFoundException\n     * \n     * @deprecated since 2.2 use instead {@link findDescriptor(UUID)}\n     */\n    @Deprecated\n    public BluetoothLeGattDescriptor findDescriptor(UUID uuid, long timeout)\n            throws KuraBluetoothResourceNotFoundException;\n\n    /**\n     * Returns a list of BluetoothLeGattDescriptors available on this characteristic.\n     *\n     * @return A list of BluetoothLeGattDescriptor\n     * @throws KuraBluetoothResourceNotFoundException\n     */\n    public List<BluetoothLeGattDescriptor> findDescriptors() throws KuraBluetoothResourceNotFoundException;\n\n    /**\n     * Reads the value of this characteristic.\n     *\n     * @return A byte[] containing the value of this characteristic.\n     * @throws KuraBluetoothIOException\n     */\n    public byte[] readValue() throws KuraBluetoothIOException;\n\n    /**\n     * Enables notifications for the value and calls accept function of the Consumer\n     * object. It enables notifications for this characteristic at BLE level.\n     * If an application uses value notifications, it has to keep a reference to the corresponding GATT characteristic\n     * to avoid that the garbage collector deletes it and removes the associated consumer.\n     *\n     * @param callback\n     *            A Consumer<byte[]> object. Its accept function will be called\n     *            when a notification is issued.\n     *\n     * @throws KuraBluetoothNotificationException\n     */\n    public void enableValueNotifications(Consumer<byte[]> callback) throws KuraBluetoothNotificationException;\n\n    /**\n     * Disables notifications of the value and unregisters the consumer object\n     * passed through the corresponding enable method. It disables notifications\n     * at BLE level for this characteristic.\n     *\n     * @throws KuraBluetoothNotificationException\n     */\n    public void disableValueNotifications() throws KuraBluetoothNotificationException;\n\n    /**\n     * Writes the value of this characteristic.\n     *\n     * @param value\n     *            The data as byte[] to be written\n     *\n     * @throws KuraBluetoothIOException\n     */\n    public void writeValue(byte[] value) throws KuraBluetoothIOException;\n\n    /**\n     * Get the UUID of this characteristic.\n     *\n     * @return The 128 byte UUID of this characteristic, NULL if an error occurred\n     */\n    public UUID getUUID();\n\n    /**\n     * Returns the service to which this characteristic belongs to.\n     *\n     * @return The BluetoothLeGattService.\n     */\n    public BluetoothLeGattService getService();\n\n    /**\n     * Returns the cached value of this characteristic, if any.\n     *\n     * @return The cached value of this characteristic.\n     */\n    public byte[] getValue();\n\n    /**\n     * Returns true if notification for changes of this characteristic are\n     * activated.\n     *\n     * @return True if notificatios are activated.\n     */\n    public boolean isNotifying();\n\n    /**\n     * Returns the list of BluetoothLeGattCharacteristicProperties this characteristic has.\n     *\n     * @return A list of BluetoothLeGattCharacteristicProperties for this characteristic.\n     */\n    public List<BluetoothLeGattCharacteristicProperties> getProperties();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeGattCharacteristicProperties.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeGattCharacteristicProperties contains the GATT characteristic property values\n *\n * @since 1.3\n */\n@ProviderType\npublic enum BluetoothLeGattCharacteristicProperties {\n\n    BROADCAST(0x01),\n    READ(0x02),\n    WRITE_WITHOUT_RESPONSE(0x04),\n    WRITE(0x08),\n    NOTIFY(0x10),\n    INDICATE(0x20),\n    AUTHENTICATE_SIGNED_WRITES(0x40),\n    EXTENDED_PROPERTIES(0x80),\n    UNKNOWN(0x00);\n\n    private final int code;\n\n    private BluetoothLeGattCharacteristicProperties(int code) {\n        this.code = code;\n    }\n\n    public int getCode() {\n        return this.code;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeGattDescriptor.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le;\n\nimport java.util.UUID;\n\nimport org.eclipse.kura.KuraBluetoothIOException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeGattDescriptor represents a GATT descriptor.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeGattDescriptor {\n\n    /**\n     * Reads the value of this descriptor\n     *\n     * @return A byte[] containing data from this descriptor\n     * @throws KuraBluetoothIOException\n     */\n    public byte[] readValue() throws KuraBluetoothIOException;\n\n    /**\n     * Writes the value of this descriptor.\n     *\n     * @param value\n     *            The data as byte[] to be written\n     * @throws KuraBluetoothIOException\n     */\n    public void writeValue(byte[] value) throws KuraBluetoothIOException;\n\n    /**\n     * Get the UUID of this descriptor.\n     *\n     * @return The 128 byte UUID of this descriptor, NULL if an error occurred\n     */\n    public UUID getUUID();\n\n    /**\n     * Returns the characteristic to which this descriptor belongs to.\n     *\n     * @return The characteristic.\n     */\n    public BluetoothLeGattCharacteristic getCharacteristic();\n\n    /**\n     * Returns the cached value of this descriptor, if any.\n     *\n     * @return The cached value of this descriptor.\n     */\n    public byte[] getValue();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeGattService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le;\n\nimport java.util.List;\nimport java.util.UUID;\n\nimport org.eclipse.kura.KuraBluetoothResourceNotFoundException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeGattService represents a GATT service.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeGattService {\n\n    /**\n     * Find a BluetoothLeGattCharacteristic specifying the UUID of the characteristic.\n     *\n     * @param uuid\n     *            The UUID of the GATT characteristic\n     * @return The BluetoothLeGattCharacteristic\n     * @throws KuraBluetoothResourceNotFoundException\n     */\n    public BluetoothLeGattCharacteristic findCharacteristic(UUID uuid) throws KuraBluetoothResourceNotFoundException;\n\n    /**\n     * Find a BluetoothLeGattCharacteristic specifying the UUID of the characteristic and the timeout in seconds.\n     *\n     * @since 1.4\n     * @param uuid\n     *            The UUID of the GATT characteristic\n     * @param timeout\n     *            The timeout for retrieving the service\n     * @return The BluetoothLeGattCharacteristic\n     * @throws KuraBluetoothResourceNotFoundException\n     * \n     * @deprecated since 2.2 use instead {@link findCharacteristic(UUID)}\n     */\n    @Deprecated\n    public BluetoothLeGattCharacteristic findCharacteristic(UUID uuid, long timeout)\n            throws KuraBluetoothResourceNotFoundException;\n\n    /**\n     * Returns a list of BluetoothLeGattCharacteristic available on this service.\n     *\n     * @return A list of BluetoothLeGattCharacteristic\n     * @throws KuraBluetoothResourceNotFoundException\n     */\n    public List<BluetoothLeGattCharacteristic> findCharacteristics() throws KuraBluetoothResourceNotFoundException;\n\n    /**\n     * Get the UUID of this service\n     *\n     * @return The 128 byte UUID of this service, NULL if an error occurred\n     */\n    public UUID getUUID();\n\n    /**\n     * Returns the device to which this service belongs to.\n     *\n     * @return The device.\n     */\n    public BluetoothLeDevice getDevice();\n\n    /**\n     * Returns true if this service is a primary service, false if secondary.\n     *\n     * @return true if this service is a primary service, false if secondary.\n     */\n    public boolean isPrimary();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeService provides a mechanism for interfacing with Bluetooth LE devices.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeService {\n\n    /**\n     * Return a list of available Bluetooth adapters.\n     */\n    public List<BluetoothLeAdapter> getAdapters();\n\n    /**\n     * Search for a Bluetooth adapter with the specified interface name (i.e. hci0).\n     * If the adapter is not available, it returns null.\n     *\n     * @param interfaceName\n     *            the name of the adapter (i.e. hci0)\n     */\n    public BluetoothLeAdapter getAdapter(String interfaceName);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothTransportType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.bluetooth.le;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Defines the type of transport for Bluetooth devices.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.0\n */\n@ProviderType\npublic enum BluetoothTransportType {\n\n    AUTO,\n    BREDR,\n    LE\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/AdvertisingReportAddressType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\n/**\n * AdvertisingReportAddressType represents the type of address in to the advertising packet.\n * Possible values are:\n * 0x00 : Public Device Address\n * 0x01 : Random Device Address\n * 0x02 : Public Identity Address\n * 0x03 : Random Identity Address\n * 0xFE : Unresolved\n *\n * @since 1.3\n */\npublic enum AdvertisingReportAddressType {\n\n    PUBLIC((byte) 0x00),\n    RANDOM((byte) 0x01),\n    /**\n     * @since 2.2\n     */\n    PUBLIC_IDENTITY((byte) 0x02),\n    /**\n     * @since 2.2\n     */\n    RANDOM_IDENTITY((byte) 0x03),\n    /**\n     * @since 2.2\n     */\n    UNRESOLVED((byte) 0xFE);\n\n    private final byte addressType;\n\n    private AdvertisingReportAddressType(byte addressType) {\n        this.addressType = addressType;\n    }\n\n    public byte getEventTypeCode() {\n        return this.addressType;\n    }\n\n    public static AdvertisingReportAddressType valueOf(byte address) {\n        AdvertisingReportAddressType type;\n        if (address == PUBLIC.getEventTypeCode()) {\n            type = PUBLIC;\n        } else if (address == RANDOM.getEventTypeCode()) {\n            type = RANDOM;\n        } else if (address == PUBLIC_IDENTITY.getEventTypeCode()) {\n            type = PUBLIC_IDENTITY;\n        } else if (address == RANDOM_IDENTITY.getEventTypeCode()) {\n            type = RANDOM_IDENTITY;\n        } else if (address == UNRESOLVED.getEventTypeCode()) {\n            type = UNRESOLVED;\n        } else {\n            throw new IllegalArgumentException(\"Address type not recognized\");\n        }\n        return type;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/AdvertisingReportEventType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Scott Ware\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * AdvertisingReportEventType represents the event type of an advertising packet.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic enum AdvertisingReportEventType {\n\n    ADV_IND((byte) 0x00),\n    ADV_DIRECT_IND((byte) 0x01),\n    ADV_SCAN_IND((byte) 0x02),\n    ADV_NONCONN_IND((byte) 0x03),\n    SCAN_RSP((byte) 0x04),\n\n    /**\n     * @since 2.2\n     */\n    ADV_IND_EXT((byte) 0x13),\n    /**\n     * @since 2.2\n     */\n    ADV_DIRECT_IND_EXT((byte) 0x15),\n    /**\n     * @since 2.2\n     */\n    ADV_SCAN_IND_EXT((byte) 0x12),\n    /**\n     * @since 2.2\n     */\n    ADV_NONCONN_IND_EXT((byte) 0x10),\n    /**\n     * @since 2.2\n     */\n    SCAN_RSP_ADV_IND_EXT((byte) 0x1B),\n    /**\n     * @since 2.2\n     */\n    SCAN_RSP_ADV_SCAN_IND_EXT((byte) 0x1A),\n    /**\n     * @since 2.2\n     */\n    DATA_STATUS_COMPLETED((byte) 0x00),\n    /**\n     * @since 2.2\n     */\n    DATA_STATUS_INCOMPLETE_ONGOING((byte) 0x20),\n    /**\n     * @since 2.2\n     */\n    DATA_STATUS_INCOMPLETE_FINISHED((byte) 0x40);\n\n    private DataStatus dataStatus = DataStatus.UNKNOWN;\n    private boolean connectable = false;\n    private boolean directed = false;\n    private boolean scannable = false;\n    private boolean scanResponse = false;\n    private final byte eventType;\n\n    private AdvertisingReportEventType(byte eventType) {\n        this.eventType = eventType;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public DataStatus getDataStatus() {\n        return this.dataStatus;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public boolean isConnectable() {\n        return connectable;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public boolean isDirected() {\n        return directed;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public boolean isScannable() {\n        return scannable;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public boolean isScanResponse() {\n        return scanResponse;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public byte getEventTypeCode() {\n        return this.eventType;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public static AdvertisingReportEventType valueOf(int event, boolean extendedReport) {\n        AdvertisingReportEventType type = null;\n\n        // Extended report has scope to use 2 octets but currently only uses 1\n        byte eventData = (byte) (event & 0xFF);\n\n        if (extendedReport) {\n            type = getLegacyType(event, eventData);\n        } else {\n            if (event == ADV_IND.eventType) {\n                type = ADV_IND;\n                type.connectable = true;\n            } else if (event == ADV_DIRECT_IND.eventType) {\n                type = ADV_DIRECT_IND;\n                type.connectable = true;\n                type.directed = true;\n            } else if (event == ADV_SCAN_IND.eventType) {\n                type = ADV_SCAN_IND;\n                type.scannable = true;\n            } else if (event == SCAN_RSP.eventType) {\n                type = SCAN_RSP;\n                type.scanResponse = true;\n            } else if (event == ADV_NONCONN_IND.eventType) {\n                type = ADV_NONCONN_IND;\n            } else {\n                throw new IllegalArgumentException(\"Report Event type not recognized\");\n            }\n        }\n\n        return type;\n    }\n\n    private static AdvertisingReportEventType getLegacyType(int event, byte eventData) {\n        AdvertisingReportEventType type = null;\n        // Check for legacy advertising PDU\n        if ((eventData & 0x10) == 0) {\n            // Data Status\n            byte status = (byte) (eventData & 0x60);\n\n            if (status == DATA_STATUS_COMPLETED.eventType) {\n                type = DATA_STATUS_COMPLETED;\n                type.dataStatus = DataStatus.COMPLETED;\n            } else if (status == DATA_STATUS_INCOMPLETE_ONGOING.eventType) {\n                type = DATA_STATUS_INCOMPLETE_ONGOING;\n                type.dataStatus = DataStatus.INCOMPLETE_ONGOING;\n            } else if (status == DATA_STATUS_INCOMPLETE_FINISHED.eventType) {\n                type = DATA_STATUS_INCOMPLETE_FINISHED;\n                type.dataStatus = DataStatus.INCOMPLETE_FINISHED;\n            } else {\n                throw new IllegalArgumentException(\"Data status type not recognized\");\n            }\n\n            // Connectable Flag\n            type.connectable = (eventData & 0x01) != 0;\n\n            // Scannable Flag\n            type.scannable = (eventData & 0x02) != 0;\n\n            // Directed Flag\n            type.directed = (eventData & 0x04) != 0;\n\n            // Scan Response Flag\n            type.scanResponse = (eventData & 0x08) != 0;\n        } else {\n            if (event == ADV_IND_EXT.eventType) {\n                type = ADV_IND_EXT;\n                type.connectable = true;\n            } else if (event == ADV_DIRECT_IND_EXT.eventType) {\n                type = ADV_DIRECT_IND_EXT;\n                type.connectable = true;\n                type.directed = true;\n            } else if (event == ADV_SCAN_IND_EXT.eventType) {\n                type = ADV_SCAN_IND_EXT;\n                type.scannable = true;\n            } else if (event == SCAN_RSP_ADV_IND_EXT.eventType) {\n                type = SCAN_RSP_ADV_IND_EXT;\n                type.connectable = true;\n                type.scanResponse = true;\n            } else if (event == SCAN_RSP_ADV_SCAN_IND_EXT.eventType) {\n                type = SCAN_RSP_ADV_SCAN_IND_EXT;\n                type.scannable = true;\n                type.scanResponse = true;\n            } else if (event == ADV_NONCONN_IND_EXT.eventType) {\n                type = ADV_NONCONN_IND_EXT;\n            } else {\n                throw new IllegalArgumentException(\"Report Event type not recognized\");\n            }\n        }\n\n        return type;\n    }\n\n    /**\n     * \n     * @deprecated since 2.2 use instead {@link valueOf(int event, boolean extendedReport)}\n     */\n    @Deprecated\n    public static AdvertisingReportEventType valueOf(byte event) {\n        return valueOf(event, false);\n    }\n\n    /**\n     * @since 2.2\n     */\n    public enum DataStatus {\n        UNKNOWN,\n        COMPLETED,\n        INCOMPLETE_ONGOING,\n        INCOMPLETE_FINISHED\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/AdvertisingReportPhy.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Scott Ware\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\n/**\n * AdvertisingReportPhy represents the Bluetooth physical layer (PHY) variant used for an advertising report.\n * Possible values are:\n * 0x00 : None\n * 0x01 : LE 1M\n * 0x02 : LE 2M\n * 0x03 : LE Coded\n *\n * @since 2.2\n */\npublic enum AdvertisingReportPhy {\n\n    NONE((byte) 0x00),\n    LE_1M((byte) 0x01),\n    LE_2M((byte) 0x02),\n    LE_CODED((byte) 0x03);\n\n    private final byte phy;\n\n    private AdvertisingReportPhy(byte phy) {\n        this.phy = phy;\n    }\n\n    public byte getPhyCode() {\n        return this.phy;\n    }\n\n    public static AdvertisingReportPhy valueOf(byte phy) {\n        AdvertisingReportPhy value;\n\n        if (phy == NONE.getPhyCode()) {\n            value = NONE;\n        } else if (phy == LE_1M.getPhyCode()) {\n            value = LE_1M;\n        } else if (phy == LE_2M.getPhyCode()) {\n            value = LE_2M;\n        } else if (phy == LE_CODED.getPhyCode()) {\n            value = LE_CODED;\n        } else {\n            throw new IllegalArgumentException(\"PHY variant not recognized\");\n        }\n        return value;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/AdvertisingReportRecord.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Scott Ware\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * AdvertisingReportRecord contains all the fields of a advertising record.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic class AdvertisingReportRecord {\n\n    private AdvertisingReportEventType eventType;\n    private AdvertisingReportAddressType addressType;\n    private String address;\n    private AdvertisingReportAddressType directAddressType;\n    private String directAddress;\n    private AdvertisingReportPhy primaryPhy;\n    private AdvertisingReportPhy secondaryPhy;\n    private byte[] reportData;\n    private int sid;\n    private int txPower;\n    private int periodicAdvertisingInterval;\n    private int length;\n    private int rssi;\n    private boolean extended;\n\n    public AdvertisingReportEventType getEventType() {\n        return this.eventType;\n    }\n\n    public void setEventType(int eventType) {\n        this.eventType = AdvertisingReportEventType.valueOf((byte) eventType, this.extended);\n    }\n\n    public AdvertisingReportAddressType getAddressType() {\n        return this.addressType;\n    }\n\n    public void setAddressType(int addressType) {\n        this.addressType = AdvertisingReportAddressType.valueOf((byte) addressType);\n    }\n\n    public String getAddress() {\n        return this.address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public AdvertisingReportAddressType getDirectAddressType() {\n        return this.directAddressType;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public void setDirectAddressType(int addressType) {\n        this.directAddressType = AdvertisingReportAddressType.valueOf((byte) addressType);\n    }\n\n    /**\n     * @since 2.2\n     */\n    public String getDirectAddress() {\n        return this.directAddress;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public void setDirectAddress(String address) {\n        this.directAddress = address;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public AdvertisingReportPhy getPrimaryPhy() {\n        return this.primaryPhy;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public void setPrimaryPhy(int phy) {\n        this.primaryPhy = AdvertisingReportPhy.valueOf((byte) phy);\n    }\n\n    /**\n     * @since 2.2\n     */\n    public AdvertisingReportPhy getSecondaryPhy() {\n        return this.secondaryPhy;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public void setSecondaryPhy(int phy) {\n        this.secondaryPhy = AdvertisingReportPhy.valueOf((byte) phy);\n    }\n\n    /**\n     * @since 2.2\n     */\n    public int getPeriodicAdvertisingInterval() {\n        return this.periodicAdvertisingInterval;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public void setPeriodicAdvertisingInterval(int periodicAdvertisingInterval) {\n        this.periodicAdvertisingInterval = periodicAdvertisingInterval;\n    }\n\n    public byte[] getReportData() {\n        return this.reportData;\n    }\n\n    public void setReportData(byte[] reportData) {\n        this.reportData = reportData;\n    }\n\n    public int getLength() {\n        return this.length;\n    }\n\n    public void setLength(int length) {\n        this.length = length;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public int getSid() {\n        return this.sid;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public void setSid(int sid) {\n        this.sid = sid;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public int getTxPower() {\n        return this.txPower;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public void setTxPower(int txPower) {\n        this.txPower = txPower;\n    }\n\n    public int getRssi() {\n        return this.rssi;\n    }\n\n    public void setRssi(int rssi) {\n        this.rssi = rssi;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public boolean isExtendedReport() {\n        return this.extended;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public void setExtendedReport(boolean extended) {\n        this.extended = extended;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeacon.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeBeacon is a representation of a generic Beacon advertise packet.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.3\n */\n@ProviderType\npublic abstract class BluetoothLeBeacon {\n\n    public static final byte AD_BYTES_NUMBER = 0x02;\n    public static final byte AD_FLAG = 0x01;\n\n    private boolean leBrHost;\n    private boolean leBrController;\n    private boolean brEdrSupported;\n    private boolean leGeneral;\n    private boolean leLimited;\n    private String address;\n    private int rssi;\n\n    public BluetoothLeBeacon() {\n        this.leBrHost = true;\n        this.leBrController = true;\n        this.brEdrSupported = false;\n        this.leGeneral = true;\n        this.leLimited = false;\n    }\n\n    public boolean isLeBrHost() {\n        return this.leBrHost;\n    }\n\n    public void setLeBrHost(boolean leBrHost) {\n        this.leBrHost = leBrHost;\n    }\n\n    public boolean isLeBrController() {\n        return this.leBrController;\n    }\n\n    public void setLeBrController(boolean leBrController) {\n        this.leBrController = leBrController;\n    }\n\n    public boolean isBrEdrSupported() {\n        return this.brEdrSupported;\n    }\n\n    public void setBrEdrSupported(boolean brEdrSupported) {\n        this.brEdrSupported = brEdrSupported;\n    }\n\n    public boolean isLeGeneral() {\n        return this.leGeneral;\n    }\n\n    public void setLeGeneral(boolean leGeneral) {\n        this.leGeneral = leGeneral;\n    }\n\n    public boolean isLeLimited() {\n        return this.leLimited;\n    }\n\n    public void setLeLimited(boolean leLimited) {\n        this.leLimited = leLimited;\n    }\n\n    public String getAddress() {\n        return this.address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public int getRssi() {\n        return this.rssi;\n    }\n\n    public void setRssi(int rssi) {\n        this.rssi = rssi;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconAdvertiser.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\nimport org.eclipse.kura.KuraBluetoothCommandException;\nimport org.eclipse.kura.bluetooth.le.BluetoothLeAdapter;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeBeaconAdvertising allows to manage the advertising mechanism for Bluetooth LE beacons.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeBeaconAdvertiser<T extends BluetoothLeBeacon> {\n\n    /**\n     * Start Beacon advertising.\n     * If the advertising has been already started or an error is detected, this method throws a\n     * KuraBluetoothCommandException.\n     *\n     * @throw KuraBluetoothCommandException\n     */\n    public void startBeaconAdvertising() throws KuraBluetoothCommandException;\n\n    /**\n     * Stop Beacon advertising.\n     * If the advertising has been already stopped or an error is detected, this method throws a\n     * KuraBluetoothCommandException.\n     *\n     * @throw KuraBluetoothCommandException\n     */\n    public void stopBeaconAdvertising() throws KuraBluetoothCommandException;\n\n    /**\n     * Set the minimum and maximum Beacon advertising interval.\n     * Both intervals are computed as Nx0.625 ms, where N can vary from 14 to 65534.\n     * So, the minimum and maximum intervals are in the range 8.75ms - 40.9s.\n     * Note that further limitations can be introduced by the hardware Bluetooth controller.\n     *\n     * @param min\n     *            Minimum time interval between advertises\n     * @param max\n     *            Maximum time interval between advertises\n     *\n     * @throw KuraBluetoothCommandException\n     */\n    public void updateBeaconAdvertisingInterval(Integer min, Integer max) throws KuraBluetoothCommandException;\n\n    /**\n     * Set the data in to the Beacon advertising packet.\n     *\n     * @param beacon\n     *            An instance of BluetoothLeBeacon class\n     *\n     * @throw KuraBluetoothCommandException\n     */\n    public void updateBeaconAdvertisingData(T beacon) throws KuraBluetoothCommandException;\n\n    /**\n     * Get the bluetooth adapter this advertiser is associated to.\n     *\n     * @return BluetoothLeAdapter\n     */\n    public BluetoothLeAdapter getAdapter();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconDecoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * BluetoothLeBeaconDecoder provides a way to decode beacons.\n *\n * @since 1.3\n */\n@ConsumerType\npublic interface BluetoothLeBeaconDecoder<T extends BluetoothLeBeacon> {\n\n    /**\n     * Decodes a byte array into a BluetoothLeBeacon object\n     *\n     * @param data\n     *            the byte array acquired by a scanner\n     * @return BluetoothLeBeacon\n     */\n    public T decode(byte[] data);\n\n    /**\n     * Get the type of beacon this decoder can manage\n     *\n     * @return Class<T> the type of beacon (i.e. BlueoothLeIBeacon)\n     *\n     */\n    public Class<T> getBeaconType();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconEncoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * BluetoothLeBeaconEncoder provides a way to encode beacons.\n *\n * @since 1.3\n */\n@ConsumerType\npublic interface BluetoothLeBeaconEncoder<T extends BluetoothLeBeacon> {\n\n    /**\n     * Encodes a BluetoothLeBeacon into a byte array\n     *\n     * @param beacon\n     *            the BluetoothLeBeacon to be broadcast by an advertiser\n     * @return byte[]\n     */\n    public byte[] encode(T beacon);\n\n    /**\n     * Get the type of beacon this encoder can manage\n     *\n     * @return Class<T> the type of beacon (i.e. BlueoothLeIBeacon)\n     *\n     */\n    public Class<T> getBeaconType();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\nimport org.eclipse.kura.KuraBluetoothBeaconAdvertiserNotAvailable;\nimport org.eclipse.kura.bluetooth.le.BluetoothLeAdapter;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeBeaconManager allows the management of specific Bluetooth LE Beacon devices.\n * It provides beacon scanner and advertiser classes using the given adapter and codecs.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeBeaconManager<T extends BluetoothLeBeacon> {\n\n    /**\n     * Instantiate a new scanner for beacons.\n     *\n     * @param adapter\n     *            the bluetooth adapter used by the scanner\n     * @param decoder\n     *            the decoder used to parse the data acquired by the scanner\n     * @return BluetoothLeBeaconScanner\n     */\n    public BluetoothLeBeaconScanner<T> newBeaconScanner(BluetoothLeAdapter adapter,\n            BluetoothLeBeaconDecoder<T> decoder);\n\n    /**\n     * Instantiate a new advertiser for beacons.\n     *\n     * @param adapter\n     *            the bluetooth adapter used by the advertiser\n     * @param encoder\n     *            the encoder used to encode the data to be broadcast\n     * @return BluetoothLeBeaconAdvertiser\n     * @throws KuraBluetoothBeaconAdvertiserNotAvailable\n     */\n    public BluetoothLeBeaconAdvertiser<T> newBeaconAdvertiser(BluetoothLeAdapter adapter,\n            BluetoothLeBeaconEncoder<T> encoder) throws KuraBluetoothBeaconAdvertiserNotAvailable;\n\n    /**\n     * Delete the given scanner.\n     *\n     * @param scanner\n     *            The scanner to be deleted\n     */\n    public void deleteBeaconScanner(BluetoothLeBeaconScanner<T> scanner);\n\n    /**\n     * Delete the given advertiser.\n     *\n     * @param advertiser\n     *            The advertiser to be deleted\n     */\n    public void deleteBeaconAdvertiser(BluetoothLeBeaconAdvertiser<T> advertiser);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconScanner.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\nimport org.eclipse.kura.KuraBluetoothCommandException;\nimport org.eclipse.kura.bluetooth.le.BluetoothLeAdapter;\nimport org.eclipse.kura.bluetooth.le.beacon.listener.BluetoothLeBeaconListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeBeaconScanner allows to manage the scanner mechanism for Bluetooth LE beacons.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeBeaconScanner<T extends BluetoothLeBeacon> {\n\n    /**\n     * Start a scan for beacons of given duration in seconds.\n     *\n     * @param duration\n     *            The scan duration in seconds\n     * @throws KuraBluetoothCommandException\n     */\n    public void startBeaconScan(long duration) throws KuraBluetoothCommandException;\n\n    /**\n     * Stop the scan for beacons.\n     */\n    public void stopBeaconScan();\n\n    /**\n     * Indicates if a scan is running.\n     *\n     * @return\n     */\n    public boolean isScanning();\n\n    /**\n     * Add a listener for detected beacons.\n     *\n     * @param listener\n     *            The beacon listener\n     */\n    public void addBeaconListener(BluetoothLeBeaconListener<T> listener);\n\n    /**\n     * Remove the given beacon listener\n     *\n     * @param listener\n     *            The beacon listener\n     */\n    public void removeBeaconListener(BluetoothLeBeaconListener<T> listener);\n\n    /**\n     * Get the bluetooth adapter this advertiser is associated to.\n     *\n     * @return BluetoothLeAdapter\n     */\n    public BluetoothLeAdapter getAdapter();\n\n    /**\n     * Get the decoder used by this scanner.\n     *\n     * @return BluetoothLeBeaconDecoder\n     */\n    public BluetoothLeBeaconDecoder<T> getDecoder();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon;\n\nimport org.eclipse.kura.KuraBluetoothBeaconAdvertiserNotAvailable;\nimport org.eclipse.kura.bluetooth.le.BluetoothLeAdapter;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * BluetoothLeBeaconService provides a mechanism for interfacing with specific Bluetooth LE Beacon devices.\n * It allows to advertise beacon packets and to scan for beacons of the given BluetoothLeBeacon type using the\n * configured adapter.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.3\n */\n@ProviderType\npublic interface BluetoothLeBeaconService<T extends BluetoothLeBeacon> {\n\n    /**\n     * Instantiate a new scanner for beacons.\n     *\n     * @param adapter\n     *            the bluetooth adapter used by the scanner\n     * @return BluetoothLeBeaconScanner\n     */\n    public BluetoothLeBeaconScanner<T> newBeaconScanner(BluetoothLeAdapter adapter);\n\n    /**\n     * Instantiate a new advertiser for beacons.\n     *\n     * @param adapter\n     *            the bluetooth adapter used by the advertiser\n     * @return BluetoothLeBeaconAdvertiser\n     * @throws KuraBluetoothBeaconAdvertiserNotAvailable\n     */\n    public BluetoothLeBeaconAdvertiser<T> newBeaconAdvertiser(BluetoothLeAdapter adapter)\n            throws KuraBluetoothBeaconAdvertiserNotAvailable;\n\n    /**\n     * Delete the given scanner.\n     *\n     * @param scanner\n     *            The scanenr to be deleted\n     */\n    public void deleteBeaconScanner(BluetoothLeBeaconScanner<T> scanner);\n\n    /**\n     * Delete the given advertiser.\n     *\n     * @param advertiser\n     *            The advertiser to be deleted\n     */\n    public void deleteBeaconAdvertiser(BluetoothLeBeaconAdvertiser<T> advertiser);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/listener/BluetoothLeBeaconListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.bluetooth.le.beacon.listener;\n\nimport org.eclipse.kura.bluetooth.le.beacon.BluetoothLeBeacon;\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * BluetoothLeBeaconListener must be implemented by any class wishing to receive BLE beacon data\n *\n * @since 1.3\n */\n@ConsumerType\n@FunctionalInterface\npublic interface BluetoothLeBeaconListener<T extends BluetoothLeBeacon> {\n\n    /**\n     * Fired when Bluetooth LE beacons data is received\n     *\n     * @param beacon\n     *            a received beacon\n     */\n    public void onBeaconsReceived(T beacon);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/listener/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Contains interface to track Bluetooth LE beacon devices.\n *\n */\npackage org.eclipse.kura.bluetooth.le.beacon.listener;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides APIs to manage Bluetooth LE beacon devices.\n *\n */\npackage org.eclipse.kura.bluetooth.le.beacon;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides APIs to manage connections to Bluetooth LE devices.\n *\n */\npackage org.eclipse.kura.bluetooth.le;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/CertificatesService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.certificate;\n\nimport java.security.cert.Certificate;\nimport java.util.Enumeration;\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.message.KuraApplicationTopic;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The CertificatesService is used to manage the storage, listing and retrieval of public certificates\n * from a key store.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface CertificatesService {\n\n    /**\n     * The storeCertificate interface method receives a certificate and an alias that should be stored in a key store\n     *\n     * @param cert\n     *            The certificate of type Certificate that has to be stored in a key store\n     * @param alias\n     *            A string that will be used to identify the certificate in a key store\n     * @throws KuraException\n     *             raised if the certificate storage operation failed\n     * @deprecated Since 2.2 use {@link #addCertificate(KuraCertificateEntry)}\n     */\n    @Deprecated\n    public void storeCertificate(Certificate cert, String alias) throws KuraException;\n\n    /**\n     * listCACertificatesAliases provides an enumeration of strings representing the different CA certificates\n     * stored in a key store\n     *\n     * @return An enumeration containing the strings that represent the CA aliases stored in a key store.\n     *\n     * @deprecated Since 2.2 use {@link #getCertificateEntry(String)}\n     */\n    @Deprecated\n    public Enumeration<String> listCACertificatesAliases();\n\n    /**\n     * listSSLCertificatesAliases provides an enumeration of strings representing the different ssl certificates\n     * stored in a key store\n     *\n     * @return An enumeration containing the strings that represent the aliases stored in a key store.\n     *\n     * @deprecated Since 2.2 use {@link #getCertificateEntry(String)}\n     */\n    @Deprecated\n    public Enumeration<String> listSSLCertificatesAliases();\n\n    /**\n     * listDMCertificatesAliases provides an enumeration of strings representing the different certificates used to\n     * authenticate\n     * the messages coming from the remote platform and stored in the device key store\n     *\n     * @return An enumeration containing the strings that represent the aliases stored in a key store.\n     *\n     * @deprecated Since 2.2 use {@link #getCertificateEntry(String)}\n     */\n    @Deprecated\n    public Enumeration<String> listDMCertificatesAliases();\n\n    /**\n     * listBundleCertificatesAliases provides an enumeration of strings representing the different certificates used to\n     * sign\n     * the bundles and that are stored in the device key store\n     *\n     * @return An enumeration containing the strings that represent the aliases stored in a key store.\n     *\n     * @deprecated Since 2.2 use {@link #getCertificateEntry(String)}\n     */\n    @Deprecated\n    public Enumeration<String> listBundleCertificatesAliases();\n\n    /**\n     * returnCertificate returns the certificate corresponding to the specified alias.\n     *\n     * @param alias\n     *            The string used to identify the certificate in a key store\n     * @return A Certificate object retrieved from a key store.\n     *\n     * @deprecated Since 2.2 use {@link #getCertificateEntry(String)}\n     */\n    @Deprecated\n    public Certificate returnCertificate(String alias) throws KuraException;\n\n    /**\n     * removeCertificate tries to remove the specified certificate from the key store. Returns true, if the removal\n     * operation succeeded. False, otherwise.\n     *\n     * @param alias\n     *            The string used to identify the certificate in a key store\n     * @throws KuraException\n     *             raised if the certificate removal operation failed\n     *\n     * @deprecated Since 2.2 use {@link #deleteCertificate(String)}\n     */\n    @Deprecated\n    public void removeCertificate(String alias) throws KuraException;\n\n    /**\n     * verifySignature is a method that takes the topic used\n     * to send the message and the signed message to verify the correctness of the signature.\n     *\n     * @param kuraAppTopic\n     *            The application topic part used to send the message\n     * @param kuraPayload\n     *            The kuraPayload message received and that needs to be verified\n     * @return A boolean value that is true if the signature received corresponds with the signature\n     *         calculated from the message content. False otherwise.\n     * @since 2.0\n     *\n     */\n    public boolean verifySignature(KuraApplicationTopic kuraAppTopic, KuraPayload kuraPayload);\n\n    /**\n     * Return the list of the installed {@KuraCertificate}\n     * \n     * @return a list of {@KuraCertificate}\n     * @throws KuraException\n     * \n     * @since 2.2\n     */\n    public List<KuraCertificateEntry> getCertificates() throws KuraException;\n\n    /**\n     * Return the {@KuraCertificate} identified by its id\n     * \n     * @param id\n     *            the id of the certificate\n     * @return the {@KuraCertificate}\n     * @throws KuraException\n     * \n     * @since 2.2\n     */\n    public KuraCertificateEntry getCertificateEntry(String id) throws KuraException;\n\n    /**\n     * Update the {@KuraCertificate} in a keystore\n     * \n     * @param id\n     *            the id of the certificate\n     * @param certificate\n     *            the new certificate\n     * @throws KuraException\n     * \n     * @since 2.2\n     */\n    public void updateCertificate(KuraCertificateEntry certificate) throws KuraException;\n\n    /**\n     * Add a {@KuraCertificate} in a keystore\n     * \n     * @param certificate\n     *            the new certificate\n     * @throws KuraException\n     * \n     * @since 2.2\n     */\n    public void addCertificate(KuraCertificateEntry certificate) throws KuraException;\n\n    /**\n     * Delete the certificate identified by its id\n     * \n     * @param id\n     *            the id of the certificate\n     * @throws KuraException\n     * \n     * @since 2.2\n     */\n    public void deleteCertificate(String id) throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/KuraCertificateEntry.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.certificate;\n\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.cert.Certificate;\n\n/**\n * \n * The KuraCertificateEntry represents a {@java.security.KeyStore.TrustedCertificateEntry} stored in a keystore.\n * The entry is identified by an id made with the id of the keystore and the alias.\n *\n * @since 2.2\n */\npublic class KuraCertificateEntry {\n\n    private String certificateId;\n    private String keystoreId;\n    private String alias;\n    private TrustedCertificateEntry certificateEntry;\n\n    public KuraCertificateEntry(String keystoreId, String alias, Certificate certificate) {\n        super();\n        this.keystoreId = keystoreId;\n        this.alias = alias;\n        this.certificateEntry = new TrustedCertificateEntry(certificate);\n        this.certificateId = keystoreId + \":\" + alias;\n    }\n\n    public KuraCertificateEntry(String keystoreId, String alias, TrustedCertificateEntry entry) {\n        super();\n        this.keystoreId = keystoreId;\n        this.alias = alias;\n        this.certificateEntry = entry;\n        this.certificateId = keystoreId + \":\" + alias;\n    }\n\n    public String getCertificateId() {\n        return this.certificateId;\n    }\n\n    public String getKeystoreId() {\n        return this.keystoreId;\n    }\n\n    public String getAlias() {\n        return this.alias;\n    }\n\n    public TrustedCertificateEntry getCertificateEntry() {\n        return this.certificateEntry;\n    }\n\n    public static String getKeystoreId(String id) {\n        if (id != null) {\n            return id.split(\":\")[0];\n        } else {\n            return \"\";\n        }\n    }\n\n    public static String getAlias(String id) {\n        if (id != null) {\n            String[] fields = id.split(\":\");\n            if (fields.length == 1) {\n                return \"\";\n            }\n            return fields[fields.length - 1];\n        } else {\n            return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/KuraPrivateKeyEntry.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.certificate;\n\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.PrivateKey;\nimport java.security.cert.Certificate;\n\n/**\n *\n * The KuraPrivateKeyEntry represents a {@java.security.KeyStore.PrivateKeyEntry} stored in a keystore\n * along with the its certificate chain.\n * The private key entry is identified by an id made with the id of the keystore and the alias.\n *\n * @since 2.2\n */\npublic class KuraPrivateKeyEntry {\n\n    private final String privateKeyId;\n    private final String keystoreId;\n    private final String alias;\n    private final PrivateKeyEntry privateKeyEntry;\n\n    public KuraPrivateKeyEntry(String keystoreId, String alias, PrivateKeyEntry privateKeyEntry) {\n        super();\n        this.keystoreId = keystoreId;\n        this.alias = alias;\n        this.privateKeyEntry = privateKeyEntry;\n        this.privateKeyId = keystoreId + \":\" + alias;\n    }\n\n    public KuraPrivateKeyEntry(String keystoreId, String alias, PrivateKey privateKey, Certificate[] certificateChain) {\n        super();\n        this.keystoreId = keystoreId;\n        this.alias = alias;\n        this.privateKeyEntry = new PrivateKeyEntry(privateKey, certificateChain);\n        this.privateKeyId = keystoreId + \":\" + alias;\n    }\n\n    public String getPrivateKeyId() {\n        return this.privateKeyId;\n    }\n\n    public String getKeystoreId() {\n        return this.keystoreId;\n    }\n\n    public String getAlias() {\n        return this.alias;\n    }\n\n    public PrivateKeyEntry getPrivateKey() {\n        return this.privateKeyEntry;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/enrollment/EnrollmentService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.certificate.enrollment;\n\nimport java.security.cert.CertStore;\nimport java.security.cert.Certificate;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Provides a list of APIs allowing the system to perform an enrollment in a Certificate Authority\n *\n * @since 2.4\n */\n\n@ProviderType\npublic interface EnrollmentService {\n\n    /**\n     * \n     * Perform the enrollment of the system with a configured Certificate Authority.\n     * \n     * @throws KuraException\n     *             if it is impossible to enroll the system.\n     */\n    public void enroll() throws KuraException;\n\n    /**\n     * Renew the client certificate submitting the certificate previously issued by the CA.\n     * \n     * @throws KuraException\n     *             if it is impossible to renew the system certificate\n     */\n    public void renew() throws KuraException;\n\n    /**\n     * Renew the client certificate creating a new keypair and a new CSR submitted to the CA.\n     * \n     * @throws KuraException\n     *             if it is impossible to renew the system certificate\n     */\n    public void rekey() throws KuraException;\n\n    /**\n     * \n     * Get the list of the Certificate Authority certificates stored in the relative\n     * {@link org.eclipse.kura.security.keystore.KeystoreService}\n     * \n     * @return returns the Certificate Authority <code>CertStore</code>\n     * @throws KuraException\n     *             if it is impossible to retrieve the certificate store.\n     */\n    public CertStore getCACertificates() throws KuraException;\n\n    /**\n     * Get the Client certificate stored in the relative\n     * {@link org.eclipse.kura.security.keystore.KeystoreService}\n     * \n     * @return returns the Client <code>Certificate</code> obtained by the Certificate\n     *         Authority\n     * @throws KuraException\n     *             if it is impossible to retrieve the certificate.\n     */\n    public Certificate getClientCertificate() throws KuraException;\n\n    /**\n     * Force the update of Certificate Authority certificate if a newest is available.\n     * \n     * @throws KuraException\n     *             if it is impossible to perform the request to the server.\n     */\n    public void forceCACertificateRollover() throws KuraException;\n\n    /**\n     * \n     * Check if the system in enrolled or not, that is the presence or not of the client certificate.\n     * \n     * @return true if the system in enrolled, false otherwise.\n     * @throws KuraException\n     *             if it is impossible to query the keystore for the certificate availability.\n     */\n    public boolean isEnrolled() throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Contains interfaces to manage certificates in a key store\n *\n */\npackage org.eclipse.kura.certificate;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/Channel.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.channel;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.eclipse.kura.annotation.NotThreadSafe;\nimport org.eclipse.kura.type.DataType;\nimport org.eclipse.kura.type.TypedValue;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Class Channel represents a communication channel. The\n * communication channel has all the required configuration to perform specific\n * operation (read/write).\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@NotThreadSafe\n@ProviderType\npublic class Channel {\n\n    private static final String MESSAGE_CHANNEL_CONFIGURATION_CANNOT_BE_NULL = \"Channel configuration cannot be null\";\n\n    private static final String MESSAGE_CHANNEL_VALUE_TYPE_CANNOT_BE_NULL = \"Channel value type cannot be null\";\n\n    private static final String MESSAGE_CHANNEL_TYPE_CANNOT_BE_NULL = \"Channel type cannot be null\";\n\n    private static final String MESSAGE_CHANNEL_NAME_CANNOT_BE_NULL = \"Channel name cannot be null\";\n\n    /** The communication channel configuration. */\n    private final transient Map<String, Object> configuration;\n\n    /** The name of the communication channel. */\n    private String name;\n\n    /** The type of the channel. (READ/WRITE/READ_WRITE) */\n    private ChannelType type;\n\n    /**\n     * The data type of the value as expected from the operation\n     */\n    private DataType valueType;\n\n    /**\n     * The data type of the scale/offset as expected from the operation\n     */\n    private ScaleOffsetType scaleOffsetType = ScaleOffsetType.DEFINED_BY_VALUE_TYPE;\n\n    /*\n     * The value used to scale the value\n     */\n    private Number valueScale = 1.0d;\n\n    /**\n     * The value used as offset of the value\n     */\n    private Number valueOffset = 0.0d;\n\n    private String unit = \"\";\n\n    /**\n     * Determines if this channel is enabled or not\n     */\n    private boolean isEnabled = true;\n\n    /**\n     * Instantiates a new channel.\n     *\n     * @param name\n     *            the name for this channel\n     * @param type\n     *            the type\n     * @param valueType\n     *            the value type\n     * @param config\n     *            the configuration\n     * @throws NullPointerException\n     *             if any of the arguments is null\n     * @deprecated Use {@link #Channel(String, ChannelType, DataType, ScaleOffsetType, Number, Number, Map)}\n     */\n\n    @Deprecated\n    public Channel(final String name, final ChannelType type, final DataType valueType,\n            final Map<String, Object> config) {\n\n        requireNonNull(name, MESSAGE_CHANNEL_NAME_CANNOT_BE_NULL);\n        requireNonNull(type, MESSAGE_CHANNEL_TYPE_CANNOT_BE_NULL);\n        requireNonNull(valueType, MESSAGE_CHANNEL_VALUE_TYPE_CANNOT_BE_NULL);\n        requireNonNull(config, MESSAGE_CHANNEL_CONFIGURATION_CANNOT_BE_NULL);\n\n        this.configuration = Collections.unmodifiableMap(config);\n        this.name = name;\n        this.type = type;\n        this.valueType = valueType;\n    }\n\n    /**\n     * Instantiates a new channel.\n     *\n     * @param name\n     *            the name for this channel\n     * @param type\n     *            the type\n     * @param valueType\n     *            the value type\n     * @param valueScale\n     *            the value used to scale the value, must have the same {@link DataType} as valueOffset\n     * @param valueOffset\n     *            the value used as offset of the value, must have the same {@link DataType} as valueScale\n     * @param config\n     *            the configuration\n     * @throws NullPointerException\n     *             if any of the arguments is null\n     * @throws IllegalArgumentException\n     *             if any of the valueScale and valueOffset have different types\n     *\n     * @since 2.8\n     */\n    public Channel(final String name, final ChannelType type, final DataType valueType,\n            final ScaleOffsetType scaleOffsetType, final Number valueScale, final Number valueOffset,\n            final Map<String, Object> config) {\n\n        requireNonNull(name, MESSAGE_CHANNEL_NAME_CANNOT_BE_NULL);\n        requireNonNull(type, MESSAGE_CHANNEL_TYPE_CANNOT_BE_NULL);\n        requireNonNull(valueType, MESSAGE_CHANNEL_VALUE_TYPE_CANNOT_BE_NULL);\n        requireNonNull(config, MESSAGE_CHANNEL_CONFIGURATION_CANNOT_BE_NULL);\n\n        requireNonNull(scaleOffsetType, \"Scale/Offset type cannot be null\");\n        requireNonNull(valueScale, \"Channel value scale cannot be null\");\n        requireNonNull(valueOffset, \"Channel value offset cannot be null\");\n\n        this.configuration = Collections.unmodifiableMap(config);\n        this.name = name;\n        this.type = type;\n        this.valueType = valueType;\n\n        this.scaleOffsetType = scaleOffsetType;\n        this.valueScale = valueScale;\n        this.valueOffset = valueOffset;\n\n    }\n\n    /**\n     * Gets the configuration of the communication channel.\n     *\n     * @return the configuration of the communication channel\n     */\n    public Map<String, Object> getConfiguration() {\n        return this.configuration;\n    }\n\n    /**\n     * Gets the name of the communication channel.\n     *\n     * @return the name of the communication channel\n     */\n    public String getName() {\n        return this.name;\n    }\n\n    /**\n     * Gets the type of the communication channel.\n     *\n     * @return the type of the communication channel\n     */\n    public ChannelType getType() {\n        return this.type;\n    }\n\n    /**\n     * Gets the value type as expected for operations.\n     *\n     * @return the value type\n     */\n    public DataType getValueType() {\n        return this.valueType;\n    }\n\n    /**\n     * Gets the Scale/Offset type as expected for operations.\n     *\n     * @return the value type\n     *\n     * @since 2.8\n     */\n    public ScaleOffsetType getScaleOffsetType() {\n        return this.scaleOffsetType;\n    }\n\n    /**\n     * Returns a boolean indicating if this channel is enabled or not\n     *\n     * @since 1.4\n     * @return a boolean indicating if this channel is enabled or not\n     */\n\n    public boolean isEnabled() {\n        return this.isEnabled;\n    }\n\n    /**\n     * Returns a double that represents the scale factor to be applied to the read value\n     *\n     * @return a double that represents the scale factor to be applied to the read value\n     *\n     * @since 2.3\n     *\n     * @deprecated Use {@link #getValueScaleAsNumber()}\n     */\n    @Deprecated\n    public double getValueScale() {\n        return this.valueScale.doubleValue();\n    }\n\n    /**\n     * Returns a {@link Number} that represents the scale factor to be applied to the read\n     * value\n     *\n     * @return a {@link Number} that represents the scale factor to be applied to the read value\n     *\n     * @since 2.8\n     */\n    public Number getValueScaleAsNumber() {\n        return this.valueScale;\n    }\n\n    /**\n     * Returns a double that represents the offset to be applied to the read value\n     *\n     * @return a double that represents the offset to be applied to the read value\n     *\n     * @since 2.3\n     *\n     * @deprecated Use {@link #getValueOffsetAsNumber()}\n     */\n    @Deprecated\n    public double getValueOffset() {\n        return this.valueOffset.doubleValue();\n    }\n\n    /**\n     * Returns a {@link TypedValue} that represents the offset factor to be applied to the read\n     * value\n     *\n     * @return a {@link TypedValue} that represents the offset factor to be applied to the read value\n     *\n     * @since 2.8\n     */\n    public Number getValueOffsetAsNumber() {\n        return this.valueOffset;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public String getUnit() {\n        return this.unit;\n    }\n\n    /**\n     * Sets the name.\n     *\n     * @param name\n     *            the new name\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public void setName(final String name) {\n        requireNonNull(name, MESSAGE_CHANNEL_NAME_CANNOT_BE_NULL);\n        this.name = name;\n    }\n\n    /**\n     * Sets the type.\n     *\n     * @param type\n     *            the new type\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public void setType(final ChannelType type) {\n        requireNonNull(type, MESSAGE_CHANNEL_TYPE_CANNOT_BE_NULL);\n        this.type = type;\n    }\n\n    /**\n     * Sets the value type.\n     *\n     * @param valueType\n     *            the new value type\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public void setValueType(final DataType valueType) {\n        requireNonNull(valueType, MESSAGE_CHANNEL_VALUE_TYPE_CANNOT_BE_NULL);\n        this.valueType = valueType;\n    }\n\n    /**\n     * Set the type of the scale/offset.\n     *\n     * @param scaleOffsetType\n     *            the scale/offset type\n     * @throws NullPointerException\n     *             if the argument is null\n     *\n     * @since 2.8\n     */\n    public void setScaleOffsetType(ScaleOffsetType scaleOffsetType) {\n        requireNonNull(this.valueType, \"Scale/Offset value type cannot be null\");\n        this.scaleOffsetType = scaleOffsetType;\n    }\n\n    /**\n     * Specifies if this channel is enabled or not\n     *\n     * @since 1.4\n     * @param isEnabled\n     *            a boolean indicating if this channel is enabled or not\n     */\n    public void setEnabled(boolean isEnabled) {\n        this.isEnabled = isEnabled;\n    }\n\n    /**\n     * Specifies the scale to be applied to the channel value\n     *\n     * @param scale\n     *            a double value that specifies the scale to be applied to the channel value\n     * @since 2.3\n     * @deprecated since version 3.0\n     */\n    @Deprecated\n    public void setScale(double scale) {\n        this.valueScale = scale;\n    }\n\n    /**\n     * Specifies the scale to be applied to the channel value\n     *\n     * @param scale\n     *            a {@link Number} value that specifies the scale to be applied to the channel value\n     * @since 2.8\n     */\n    public void setScale(Number scale) {\n        this.valueScale = scale;\n    }\n\n    /**\n     * Specifies the offset to be applied to the channel value\n     *\n     * @param offset\n     *            a double value that specifies the offset to be applied to the channel value\n     * @since 2.3\n     * @deprecated since version 3.0\n     */\n    @Deprecated\n    public void setOffset(double offset) {\n        this.valueOffset = offset;\n    }\n\n    /**\n     * Specifies the offset to be applied to the channel value\n     *\n     * @param offset\n     *            a {@link Number} value that specifies the offset to be applied to the channel value\n     * @since 2.8\n     */\n    public void setOffset(Number offset) {\n        this.valueOffset = offset;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public void setUnit(String unit) {\n        this.unit = unit;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"Channel [configuration=\" + this.configuration + \", name=\" + this.name + \", type=\" + this.type\n                + \", valueType=\" + this.valueType + \", valueScale=\" + this.valueScale + \", valueOffset=\"\n                + this.valueOffset + \", valueType=\" + this.valueType + \", unit=\" + this.unit + \"]\";\n    }\n\n    /**\n     * Creates a new {@link ChannelRecord} that represents a read request\n     * for the value of this {@code Channel}.\n     *\n     * @return\n     *         the {@link ChannelRecord}\n     */\n    public ChannelRecord createReadRecord() {\n        ChannelRecord result = ChannelRecord.createReadRecord(this.name, this.valueType, this.unit);\n        result.setChannelConfig(this.configuration);\n\n        return result;\n    }\n\n    /**\n     * Creates a new {@link ChannelRecord} that represents a write request for this\n     * {@code Channel}.\n     *\n     * @param vlaue\n     *            The value to be written.\n     * @throws IllegalArgumentException\n     *             If the {@link DataType} of the provided value differs from the data type\n     *             of this channel\n     * @throws NullPointerException\n     *             If the provided value is null\n     * @return\n     *         the {@link CheannelRecord}\n     */\n    public ChannelRecord createWriteRecord(TypedValue<?> value) {\n        requireNonNull(value, \"Value cannot be null\");\n        if (value.getType() != this.valueType) {\n            throw new IllegalArgumentException(\"The value type of the argument must match the channel value type\");\n        }\n        ChannelRecord result = ChannelRecord.createWriteRecord(this.name, value);\n        result.setChannelConfig(this.configuration);\n\n        return result;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.isEnabled, this.name, this.scaleOffsetType, this.type, this.unit, this.valueOffset,\n                this.valueScale, this.valueType);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if ((obj == null) || (getClass() != obj.getClass())) {\n            return false;\n        }\n        Channel other = (Channel) obj;\n        return this.isEnabled == other.isEnabled && Objects.equals(this.name, other.name)\n                && this.scaleOffsetType == other.scaleOffsetType && this.type == other.type\n                && Objects.equals(this.unit, other.unit) && Objects.equals(this.valueOffset, other.valueOffset)\n                && Objects.equals(this.valueScale, other.valueScale) && this.valueType == other.valueType;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ChannelFlag.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.channel;\n\n/**\n * This represents all the Channel specific flag codes\n *\n * @since 1.2\n */\npublic enum ChannelFlag {\n    /**\n     * In case of any failure on the channel\n     */\n    FAILURE,\n    /**\n     * In case of successful operation on channel\n     */\n    SUCCESS\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ChannelRecord.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.channel;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.annotation.NotThreadSafe;\nimport org.eclipse.kura.type.DataType;\nimport org.eclipse.kura.type.TypedValue;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Class ChannelRecord contains the information needed for performing a read or write\n * operation on a specific channel.<br/>\n * <br/>\n *\n * The possible cases for a channel record are the following:\n * <ul>\n *\n * <li>\n * Describing a read request: in this case the channel record must contain the channel\n * name and the data type to be read.\n * A channel record suitable for this use case can be created using the\n * {@link ChannelRecord#createReadRecord(String, DataType)} or {@link Channel#createReadRecord()} methods.\n * </li>\n *\n * <li>\n * Describing a write request: in this case the channel record must contain the channel\n * name, the value to be written and its data type\n * A channel record suitable for this use case can be created using the\n * {@link ChannelRecord#createWriteRecord(String, TypedValue)} or {@link Channel#createWriteRecord(TypedValue)} methods.\n * </li>\n *\n * <li>\n * Reporting a status: in this case the channel record must contain the channel\n * name and a {@link ChannelStatus} instance.\n * The status contains a flag, an exception message and an exception\n * instance.\n * A channel record suitable for this use case can be created using the\n * {@link ChannelRecord#createStatusRecord(String, ChannelStatus)} method.\n * </li>\n *\n * </ul>\n *\n * A channel record might also contain an user defined configuration, specified\n * as a {@code Map<String, Object>} instance.\n * This configuration can be used to provide additional information concerning the\n * operation to be performed.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@ProviderType\n@NotThreadSafe\npublic class ChannelRecord {\n\n    private static final String NULL_CHANNEL_NAME_ERROR_MESSAGE = \"Channel Name cannot be null\";\n\n    /**\n     * Provided channel configuration to perform read or write\n     * operation.\n     */\n    private transient Map<String, Object> channelConfiguration;\n\n    /**\n     * Represents a channel specific status which signifies the status\n     * of an operation performed on a channel.\n     */\n    private ChannelStatus channelStatus;\n\n    /**\n     * Represents the name of this channel\n     */\n    private String name;\n\n    /**\n     * Represents the type of the value involved in the read/write operation.\n     */\n    private DataType valueType;\n\n    /**\n     * Represents the value obtained/to be written from/to the channel\n     */\n    private TypedValue<?> value;\n\n    /** Represents the timestamp of the operation performed. */\n    private long timestamp;\n\n    private String unit;\n\n    private ChannelRecord() {\n    }\n\n    /**\n     * Creates a channel record that represents a read request.\n     *\n     * @param channelName\n     *            The name of the channel\n     * @param valueType\n     *            The type of the value to be read\n     * @throws NullPointerException\n     *             If any of the provided arguments is null\n     * @return the channel record\n     */\n    public static ChannelRecord createReadRecord(final String channelName, final DataType valueType) {\n        requireNonNull(channelName, NULL_CHANNEL_NAME_ERROR_MESSAGE);\n        requireNonNull(valueType, \"Value Type cannot be null\");\n\n        ChannelRecord result = new ChannelRecord();\n        result.name = channelName;\n        result.valueType = valueType;\n        result.unit = \"\";\n\n        return result;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public static ChannelRecord createReadRecord(final String channelName, final DataType valueType,\n            final String unit) {\n        requireNonNull(channelName, NULL_CHANNEL_NAME_ERROR_MESSAGE);\n        requireNonNull(valueType, \"Value Type cannot be null\");\n\n        ChannelRecord result = new ChannelRecord();\n        result.name = channelName;\n        result.valueType = valueType;\n        result.unit = unit;\n\n        return result;\n    }\n\n    /**\n     * Creates a channel record that represents a write request.\n     *\n     * @param channelName\n     *            The name of the channel\n     * @param value\n     *            The value to be written\n     * @throws NullPointerException\n     *             If any of the provided arguments is null\n     * @return the channel record\n     */\n    public static ChannelRecord createWriteRecord(final String channelName, final TypedValue<?> value) {\n        requireNonNull(channelName, NULL_CHANNEL_NAME_ERROR_MESSAGE);\n        requireNonNull(value, \"Value cannot be null\");\n\n        ChannelRecord result = new ChannelRecord();\n        result.name = channelName;\n        result.valueType = value.getType();\n        result.value = value;\n\n        return result;\n    }\n\n    /**\n     * Creates a channel record that describes the status of an operation.\n     *\n     * @param channelName\n     *            The name of the channel\n     * @param status\n     *            The status\n     * @throws NullPointerException\n     *             If any of the provided arguments is null\n     * @return the channel record\n     */\n    public static ChannelRecord createStatusRecord(final String channelName, final ChannelStatus status) {\n        requireNonNull(channelName, NULL_CHANNEL_NAME_ERROR_MESSAGE);\n        requireNonNull(status, \"Status cannot be null\");\n\n        ChannelRecord result = new ChannelRecord();\n        result.name = channelName;\n        result.channelStatus = status;\n\n        return result;\n    }\n\n    /**\n     * Returns the channel configuration as provided.\n     *\n     * @return the channel configuration\n     */\n    public Map<String, Object> getChannelConfig() {\n        return this.channelConfiguration;\n    }\n\n    /**\n     * Returns the channel operation status.\n     *\n     * @return the driver status\n     */\n    public ChannelStatus getChannelStatus() {\n        return this.channelStatus;\n    }\n\n    /**\n     * Returns the associated timestamp.\n     *\n     * @return the timestamp\n     */\n    public long getTimestamp() {\n        return this.timestamp;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public String getUnit() {\n        return this.unit;\n    }\n\n    /**\n     * Sets the channel configuration as provided.\n     *\n     * @param channelConfig\n     *            the channel configuration\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public void setChannelConfig(final Map<String, Object> channelConfig) {\n        requireNonNull(channelConfig, \"Channel configuration cannot be null\");\n        this.channelConfiguration = new HashMap<>(channelConfig);\n    }\n\n    /**\n     * Sets the status.\n     *\n     * @param status\n     *            the new driver status\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public void setChannelStatus(final ChannelStatus status) {\n        requireNonNull(status, \"Channel Status cannot be null\");\n        this.channelStatus = status;\n    }\n\n    /**\n     * Sets the timestamp as provided.\n     *\n     * @param timestamp\n     *            the new timestamp\n     */\n    public void setTimestamp(final long timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public void setUnit(final String unit) {\n        this.unit = unit;\n    }\n\n    /**\n     * Returns the name of the channel associated to the operation represented by this channel record\n     *\n     * @return the channel name\n     */\n    public String getChannelName() {\n        return this.name;\n    }\n\n    /**\n     * Returns the type of the value associated to the operation represented by this channel record\n     *\n     * @return the value type\n     */\n    public DataType getValueType() {\n        return this.valueType;\n    }\n\n    /**\n     * Returns the value associated to the operation represented by this channel record\n     *\n     * @return the value\n     */\n    public TypedValue<?> getValue() {\n        return this.value;\n    }\n\n    /**\n     * Sets the value associated to the operation represented by this channel record\n     *\n     * @param value\n     *            the value to be set\n     * @throws NullPointerException\n     *             if the provided value is null\n     */\n    public void setValue(TypedValue<?> value) {\n        requireNonNull(value, \"Value cannot be null\");\n        this.value = value;\n    }\n\n    @Override\n    public String toString() {\n        return \"ChannelRecord [channelConfiguration=\" + this.channelConfiguration + \", channelStatus=\"\n                + this.channelStatus + \", name=\" + this.name + \", valueType=\" + this.valueType + \", value=\" + this.value\n                + \", timestamp=\" + this.timestamp + \", unit=\" + this.unit + \"]\";\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.channelStatus == null ? 0 : this.channelStatus.hashCode());\n        result = prime * result + (this.name == null ? 0 : this.name.hashCode());\n        result = prime * result + (int) (this.timestamp ^ this.timestamp >>> 32);\n        result = prime * result + (this.unit == null ? 0 : this.unit.hashCode());\n        result = prime * result + (this.value == null ? 0 : this.value.hashCode());\n        result = prime * result + (this.valueType == null ? 0 : this.valueType.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        ChannelRecord other = (ChannelRecord) obj;\n        if (this.channelStatus == null) {\n            if (other.channelStatus != null) {\n                return false;\n            }\n        } else if (!this.channelStatus.equals(other.channelStatus)) {\n            return false;\n        }\n        if (this.name == null) {\n            if (other.name != null) {\n                return false;\n            }\n        } else if (!this.name.equals(other.name)) {\n            return false;\n        }\n        if (this.timestamp != other.timestamp) {\n            return false;\n        }\n        if (this.unit == null) {\n            if (other.unit != null) {\n                return false;\n            }\n        } else if (!this.unit.equals(other.unit)) {\n            return false;\n        }\n        if (this.value == null) {\n            if (other.value != null) {\n                return false;\n            }\n        } else if (!this.value.equals(other.value)) {\n            return false;\n        }\n        if (this.valueType != other.valueType) {\n            return false;\n        }\n        return true;\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ChannelStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.channel;\n\nimport static java.util.Objects.requireNonNull;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.Nullable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Class ChannelStatus is responsible for representing the status of any\n * channel specific operation\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class ChannelStatus {\n\n    /** The channel flag. */\n    private final ChannelFlag channelFlag;\n\n    /** The exception instance if needed. */\n    @Nullable\n    private final Exception exception;\n\n    /** The exception Message. */\n    @Nullable\n    private final String exceptionMessage;\n\n    /**\n     * Instantiates a new status.\n     *\n     * @param channelFlag\n     *            the channel flag\n     * @throws NullPointerException\n     *             if the channel flag is null\n     */\n    public ChannelStatus(final ChannelFlag channelFlag) {\n        requireNonNull(channelFlag, \"Channel Flag cannot be null\");\n        this.channelFlag = channelFlag;\n        this.exceptionMessage = null;\n        this.exception = null;\n    }\n\n    /**\n     * Instantiates a new status.\n     *\n     * @param channelFlag\n     *            the channel flag\n     * @param exceptionMessage\n     *            the exception message\n     * @param exception\n     *            the exception\n     * @throws NullPointerException\n     *             if the channel flag is null\n     */\n    public ChannelStatus(final ChannelFlag channelFlag, @Nullable final String exceptionMessage,\n            @Nullable final Exception exception) {\n        requireNonNull(channelFlag, \"Driver Flag cannot be null\");\n        this.channelFlag = channelFlag;\n        this.exceptionMessage = exceptionMessage;\n        this.exception = exception;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public boolean equals(final Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (this.getClass() != obj.getClass()) {\n            return false;\n        }\n        final ChannelStatus other = (ChannelStatus) obj;\n        if (this.channelFlag != other.channelFlag) {\n            return false;\n        }\n        if (this.exception == null) {\n            if (other.exception != null) {\n                return false;\n            }\n        } else if (!this.exception.equals(other.exception)) {\n            return false;\n        }\n        if (this.exceptionMessage == null) {\n            if (other.exceptionMessage != null) {\n                return false;\n            }\n        } else if (!this.exceptionMessage.equals(other.exceptionMessage)) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * Gets the channel flag.\n     *\n     * @return the channel flag\n     */\n    public ChannelFlag getChannelFlag() {\n        return this.channelFlag;\n    }\n\n    /**\n     * Gets the exception.\n     *\n     * @return the exception\n     */\n    public Exception getException() {\n        return this.exception;\n    }\n\n    /**\n     * Gets the exception message.\n     *\n     * @return the exception message\n     */\n    public String getExceptionMessage() {\n        return this.exceptionMessage;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.channelFlag == null ? 0 : this.channelFlag.hashCode());\n        result = prime * result + (this.exception == null ? 0 : this.exception.hashCode());\n        result = prime * result + (this.exceptionMessage == null ? 0 : this.exceptionMessage.hashCode());\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return \"ChannelStatus [channelFlag=\" + this.channelFlag + \", exception=\" + this.exception\n                + \", exceptionMessage=\" + this.exceptionMessage + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ChannelType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.channel;\n\n/**\n * This provides the necessary constants to denote the type of the channel\n * (whether the channel is for reading or writing or both)\n *\n * @since 1.2\n */\npublic enum ChannelType {\n\n    /**\n     * The channel will be used for performing reading operation\n     */\n    READ,\n\n    /**\n     * The channel will be used for performing both reading and writing\n     * operations\n     */\n    READ_WRITE,\n\n    /**\n     * The channel will be used for performing writing operation\n     */\n    WRITE;\n\n    /**\n     * Converts {@code channelTypeString}, if possible, to the related {@link ChannelType}.\n     *\n     * @param channelTypeString\n     *            String that we want to use to get the respective {@link ChannelType}.\n     * @return a ChannelType that corresponds to the String passed as argument.\n     * @throws IllegalArgumentException\n     *             if the passed string does not correspond to an existing {@link ChannelType}.\n     */\n    public static ChannelType getChannelType(String channelTypeString) {\n        if (READ.name().equalsIgnoreCase(channelTypeString)) {\n            return READ;\n        }\n        if (WRITE.name().equalsIgnoreCase(channelTypeString)) {\n            return WRITE;\n        }\n        if (READ_WRITE.name().equalsIgnoreCase(channelTypeString)) {\n            return READ_WRITE;\n        }\n\n        throw new IllegalArgumentException(\"Cannot convert to ChannelType\");\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ScaleOffsetType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.channel;\n\n/**\n * This contains all the required type constants for representing\n * Scale and Offset.\n *\n * @since 2.8\n */\npublic enum ScaleOffsetType {\n\n    DEFINED_BY_VALUE_TYPE,\n\n    /**\n     * @since 3.0\n     */\n    FLOAT,\n    DOUBLE,\n    /**\n     * @since 3.0\n     */\n    INTEGER,\n    LONG;\n\n    /**\n     * Converts {@code stringScaleOffsetType}, if possible, to the related {@link ScaleOffsetType}.\n     *\n     * @param stringDataType\n     *            String that we want to use to get the respective {@link ScaleOffsetType}.\n     * @return a ScaleOffsetType that corresponds to the String passed as argument.\n     * @throws IllegalArgumentException\n     *             if the passed string does not correspond to an existing {@link ScaleOffsetType}.\n     */\n    public static ScaleOffsetType getScaleOffsetType(String stringScaleOffsetType) {\n\n        if (DEFINED_BY_VALUE_TYPE.name().equalsIgnoreCase(stringScaleOffsetType)) {\n            return DEFINED_BY_VALUE_TYPE;\n        }\n\n        if (FLOAT.name().equalsIgnoreCase(stringScaleOffsetType)) {\n            return FLOAT;\n        }\n\n        if (DOUBLE.name().equalsIgnoreCase(stringScaleOffsetType)) {\n            return DOUBLE;\n        }\n\n        if (INTEGER.name().equalsIgnoreCase(stringScaleOffsetType)) {\n            return INTEGER;\n        }\n\n        if (LONG.name().equalsIgnoreCase(stringScaleOffsetType)) {\n            return LONG;\n        }\n\n        throw new IllegalArgumentException(\"Cannot convert to ScaleOffsetType\");\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/listener/ChannelEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.channel.listener;\n\nimport static java.util.Objects.requireNonNull;\n\nimport org.eclipse.kura.annotation.NotThreadSafe;\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents an event occurred while monitoring specific channel\n * configuration\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@NotThreadSafe\n@ProviderType\npublic class ChannelEvent {\n\n    /**\n     * Represents the channel record as triggered due to the asset specific\n     * monitor operation\n     */\n    private final ChannelRecord channelRecord;\n\n    /**\n     * Instantiates a new channel event.\n     *\n     * @param channelRecord\n     *            the channel record\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public ChannelEvent(final ChannelRecord channelRecord) {\n        requireNonNull(channelRecord, \"Channel record cannot be null\");\n        this.channelRecord = channelRecord;\n    }\n\n    /**\n     * Returns the associated channel record.\n     *\n     * @return the channel record\n     */\n    public ChannelRecord getChannelRecord() {\n        return this.channelRecord;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"ChannelEvent [channeRecord=\" + this.channelRecord + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/listener/ChannelListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.channel.listener;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * The listener interface ChannelListener is mainly for receiving channel events.\n * The class that is interested in processing a channel event implements this\n * interface.\n *\n * @see ChannelEvent\n * @since 1.2\n */\n@FunctionalInterface\n@ConsumerType\npublic interface ChannelListener {\n\n    /**\n     * Triggers on channel event\n     *\n     * @param event\n     *            the fired channel event\n     * @throws NullPointerException\n     *             if event is null\n     */\n    public void onChannelEvent(ChannelEvent event);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/listener/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\n/**\n * Provides the Kura Channel Listener API\n *\n * @since 1.2\n */\npackage org.eclipse.kura.channel.listener;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\n/**\n * Provides the Kura Channel API\n *\n * @since 1.2\n */\npackage org.eclipse.kura.channel;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/clock/ClockEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.clock;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * ClockEvent is raised when a clock synchronization has been performed.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class ClockEvent extends Event {\n\n    /** Topic of the ClockEvent */\n    public static final String CLOCK_EVENT_TOPIC = \"org/eclipse/kura/clock\";\n\n    public ClockEvent(Map<String, ?> properties) {\n        super(CLOCK_EVENT_TOPIC, properties);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/clock/ClockService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.clock;\n\nimport java.util.Date;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The ClockService is used to configure how to sych the hardware clock with a remote network service.\n * The service reports when the clock has been synchronized last and raises an event when it is synchronized.\n * The ClockService is configurable to determine how the clock synchronization should happen.\n * By default, the ClockService can be configured to set the time through a Java NTP Client.\n * It can also be extended to synchronize the clock through a native Linux NTPD service,\n * using the clock acquired from a GPS signal provided by the Position Service, or\n * through the a cellular carrier.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface ClockService {\n\n    /**\n     * Returns a Date denoting when the clock was synchronized last. If the clock has\n     * not yet synchronized since Kura started, null is returned.\n     *\n     * @return Date that the clock was last synchronized, null if not synchronized yet.\n     */\n    public Date getLastSync() throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/clock/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Contains interface and event model to synchronize hardware clock.\n *\n */\npackage org.eclipse.kura.clock;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudCallService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.KuraTimeoutException;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The CloudCallService provides helper methods to make a request/response conversation with the remote server.\n * The call methods deal with the logic required to build request messages and track the corresponding responses.\n * All call methods are synchronous; after a request is issued, the implementation will wait for the response\n * to arrive or a timeout occurs. The timeout interval used by the service is configurable as a property\n * of the {@link org.eclipse.kura.data.DataTransportService}.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated\n */\n@ProviderType\n@Deprecated\npublic interface CloudCallService {\n\n    /**\n     * Sends a local (to this device) request to a Cloudlet application\n     * with the given application ID waiting for the response.\n     *\n     * @param appId\n     * @param appTopic\n     * @param appPayload\n     *            the application specific payload of an KuraRequestPayload.\n     * @param timeout\n     * @return\n     * @throws KuraConnectException\n     * @throws KuraTimeoutException\n     * @throws KuraStoreException\n     * @throws KuraException\n     */\n    public KuraResponsePayload call(String appId, String appTopic, KuraPayload appPayload, int timeout)\n            throws KuraConnectException, KuraTimeoutException, KuraStoreException, KuraException;\n\n    /**\n     * Sends a request to a remote server or device identified by the specified deviceId\n     * and targeting the given application ID waiting for the response.\n     *\n     * @param deviceId\n     * @param appId\n     * @param appTopic\n     * @param appPayload\n     * @param timeout\n     * @return\n     * @throws KuraConnectException\n     * @throws KuraTimeoutException\n     * @throws KuraStoreException\n     * @throws KuraException\n     */\n    public KuraResponsePayload call(String deviceId, String appId, String appTopic, KuraPayload appPayload, int timeout)\n            throws KuraConnectException, KuraTimeoutException, KuraStoreException, KuraException;\n\n    /**\n     * Returns true if the underlying {@link org.eclipse.kura.data.DataService} is currently connected to the remote server.\n     *\n     * @return\n     */\n    public boolean isConnected();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudClient.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The CloudClient is designed to be used by single application bundles.\n * CloudClient instances are acquired from the CloudService and they\n * are released when the work is completed. Generally, a CloudClient\n * is acquired during the activation phase of a bundle and it is released\n * during the deactivation phase.\n * <br>\n * CloudClient leverages the {@link org.eclipse.kura.data.DataService}\n * for all interactions with the transport layer and the communication\n * with the remote server. CloudClient establishes a set of default\n * subscriptions that allow remote servers or other devices to direct messages\n * to the application instance.\n * <br>\n * If the bundle using the CloudClient relies on custom subscriptions\n * beyond the default ones, it is responsibility of the application to implement\n * the {@link CloudClientListener#onConnectionEstablished()} callback method in the\n * CloudCallbackHandler to restore the subscriptions it needs.\n * <br>\n * The <b>CloudClient.release method will unsubscribe</b> all subscriptions\n * incurred by this client and it will unregister this CloudClient\n * instance from the list of CloudCallbackHandlers registered.\n * <br>\n * There can be more than one instance of CloudClient in the system,\n * ideally one per ApplicationId but this is not enforced.\n * The class accepts more than one callback handler; all registered handlers are invoked\n * when a message is received. It is up to the received to analyze the topic\n * of the message received and handle it appropriately.\n * <br>\n * The CloudClient publishes and receives messages using a topic namespace\n * following a structure as: [CRTL_PREFIX/]accountName/deviceId/appId/appTopic.<br>\n * <ul>\n * <li>CRTL_PREFIX: is an optional prefix to denote topic used for control messages\n * as opposed to data messages. The framework makes use of control topics to\n * separate management messages like replies from those used for application data.\n * <li>accountName: an unique identifier that represents a group of devices and users\n * <li>deviceId: an unique identifier within an account that represents a single gateway device.\n * By default, the MAC address of its primary network interface is generally used as the deviceId of the gateway.\n * In the case of an MQTT transport, for example, deviceId maps to the Client Identifier (Client ID).\n * <li>appId: an identifier to denote an application running on the gateway device.\n * We suggest to version the application identifier in order to allow multiple versions of the application\n * to coexist, e.g. CONF-V1, CONF-V2, etc.\n * <li>appTopic topic defined and managed by the application.\n * </ul>\n * accountName, deviceId, and applicationId are derived based on the configuration parameters\n * of the system where this instance is deployed while the applicationTopic is controlled\n * by the application. The following is an example of topic used for publishing where the prefix\n * used for the control Topics is $EDC.\n * <ul>\n * <li>publish: accountName/deviceId/applicationId/appTopic\n * <li>controlPublish: $EDC/accountName/assetId/applicationId/appTopic\n * <li>subscribe: accountName/deviceId/applicationId/appTopic\n * <li>controlSubscribe: $EDC/accountName/deviceId/applicationId/appTopic\n * <li>default subscriptions: $EDC/accountName/deviceId/applicationId/#\n * </ul>\n * Note that the default subscription of a CloudClient allows remote servers\n * or applications running on other devices to publish messages addressed\n * to specific applications running on specific devices.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher} and \n * {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber}\n */\n@ProviderType\n@Deprecated\npublic interface CloudClient {\n\n    /**\n     * Returns the applicationId of this CloudClient\n     *\n     * @return applicationId\n     */\n    public String getApplicationId();\n\n    /**\n     * Releases this CloudClient handle. This instance should no longer be used.\n     * Note: CloudClient does not unsubscribes all subscriptions incurred by this client,\n     * this responsibility is left to the application developer\n     */\n    public void release();\n\n    /**\n     * Returns an indication of whether the connection to the remote server is established.\n     * If your application needs to manage the connection directly, it can use the\n     * {@link org.eclipse.kura.data.DataService#connect} and {@link org.eclipse.kura.data.DataService#disconnect} methods.\n     *\n     * @return boolean, whether connection to broker is established.\n     */\n    public boolean isConnected();\n\n    /**\n     * Publishes a message to the remote server using the default priority 5.\n     * Before passing the message the to {@link org.eclipse.kura.data.DataService},\n     * the CloudClient will manipulate the provided topic by appending the necessary parts\n     * to achieve topic partitioning and device identification. It is also responsible to\n     * encode the {@link KuraPayload} payload into binary format.\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit.\n     *\n     * @param appTopic\n     *            A String specifying the application portion of the topic the message is published on.\n     * @param payload\n     *            An KuraPayload representing the message to be published\n     * @param qos\n     *            An integer specifying the quality of service the message was published on.\n     * @param retain\n     *            Whether or not the broker should retain the message\n     * @return The published message's ID.\n     * @throws KuraException\n     *             if one of the message composition or message publishing operation fails.\n     */\n    public int publish(String appTopic, KuraPayload payload, int qos, boolean retain) throws KuraException;\n\n    /**\n     * Publishes a message to the remote server using the default priority 5.\n     * Before passing the message the to {@link org.eclipse.kura.data.DataService},\n     * the CloudClient will manipulate the provided topic by appending the necessary parts\n     * to achieve topic partitioning and device identification. It is also responsible to\n     * encode the {@link KuraPayload} payload into binary format.\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit.\n     *\n     * @param deviceId\n     *            A String specifying the device ID.\n     * @param appTopic\n     *            A String specifying the application portion of the topic the message is published on.\n     * @param payload\n     *            An KuraPayload representing the message to be published\n     * @param qos\n     *            An integer specifying the quality of service the message was published on.\n     * @param retain\n     *            Whether or not the broker should retain the message\n     * @return The published message's ID.\n     * @throws KuraException\n     *             if one of the message composition or message publishing operation fails.\n     * @since 1.2\n     */\n    public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain)\n            throws KuraException;\n\n    /**\n     * Publishes a message to the remote server.\n     * Before passing the message the to {@link org.eclipse.kura.data.DataService},\n     * the CloudClient will manipulate the provided topic by appending the necessary parts\n     * to achieve topic partitioning and device identification. It is also responsible to\n     * encode the {@link KuraPayload} payload into binary format.\n     * <br>\n     * The priority argument can be used to control the relative ordering of this\n     * message with other messages that may be currently queued for publishing.\n     * Priority level 0 (highest) should be used sparingly and reserved for\n     * messages that should be sent with the minimum latency. Life-cycle messages\n     * (e.g. device start and stop) are an example of messages that are\n     * published by the framework with priority 0.\n     * Priority 1 messages are used by the framework to publish response messages\n     * in request/response conversations to prevent a timeout at the requester.\n     * Application should consider using priority 5 or higher.\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit. The limit does not apply to internal messages with the priority less than 2.\n     * These priority levels are reserved to the framework which uses it for life-cycle messages\n     * - birth and death certificates - and replies to request/response flows.\n     *\n     * @param appTopic\n     *            A String specifying the application portion of the topic the message is published on.\n     * @param payload\n     *            An KuraPayload representing the message to be published\n     * @param qos\n     *            An integer specifying the quality of service the message was published on.\n     * @param retain\n     *            Whether or not the broker should retain the message\n     * @param priority\n     *            Relative ordering of this message with other messages that may be currently queued for publishing.\n     * @return The published message's ID.\n     * @throws KuraException\n     *             if one of the message composition or message publishing operation fails.\n     */\n    public int publish(String appTopic, KuraPayload payload, int qos, boolean retain, int priority)\n            throws KuraException;\n\n    /**\n     * Publishes a message to the remote server.\n     * Before passing the message the to {@link org.eclipse.kura.data.DataService},\n     * the CloudClient will manipulate the provided topic by appending the necessary parts\n     * to achieve topic partitioning and device identification. It is also responsible to\n     * encode the {@link KuraPayload} payload into binary format.\n     * <br>\n     * The priority argument can be used to control the relative ordering of this\n     * message with other messages that may be currently queued for publishing.\n     * Priority level 0 (highest) should be used sparingly and reserved for\n     * messages that should be sent with the minimum latency. Life-cycle messages\n     * (e.g. device start and stop) are an example of messages that are\n     * published by the framework with priority 0.\n     * Priority 1 messages are used by the framework to publish response messages\n     * in request/response conversations to prevent a timeout at the requester.\n     * Application should consider using priority 5 or higher.\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit. The limit does not apply to internal messages with the priority less than 2.\n     * These priority levels are reserved to the framework which uses it for life-cycle messages\n     * - birth and death certificates - and replies to request/response flows.\n     *\n     * @param deviceId\n     *            A String specifying the device ID.\n     * @param appTopic\n     *            A String specifying the application portion of the topic the message is published on.\n     * @param payload\n     *            An KuraPayload representing the message to be published\n     * @param qos\n     *            An integer specifying the quality of service the message was published on.\n     * @param retain\n     *            Whether or not the broker should retain the message\n     * @param priority\n     *            Relative ordering of this message with other messages that may be currently queued for publishing.\n     * @return The published message's ID.\n     * @throws KuraException\n     *             if one of the message composition or message publishing operation fails.\n     * @since 1.2\n     */\n    public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain, int priority)\n            throws KuraException;\n\n    /**\n     * Publishes a message to the remote server with a raw byte array payload.\n     * This is the lowest level publish API exposed by the CloudClient.\n     * Before passing the message the to {@link org.eclipse.kura.data.DataService},\n     * the CloudClient will manipulate the provided topic by appending the necessary parts\n     * to achieve topic partitioning and device identification.\n     * <br>\n     * The priority argument can be used to control the relative ordering of this\n     * message with other messages that may be currently queued for publishing.\n     * Priority level 0 (highest) should be used sparingly and reserved for\n     * messages that should be sent with the minimum latency. Life-cycle messages\n     * (e.g. device start and stop) are an example of messages that are\n     * published by the framework with priority 0.\n     * Priority 1 messages are used by the framework to publish response messages\n     * in request/response conversations to prevent a timeout at the requester.\n     * Application should consider using priority 5 or higher.\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit. The limit does not apply to internal messages with the priority less than 2.\n     * These priority levels are reserved to the framework which uses it for life-cycle messages\n     * - birth and death certificates - and replies to request/response flows.\n     *\n     * @param appTopic\n     *            A String specifying the application portion of the topic the message is published on.\n     * @param payload\n     *            Binary payload representing the message to be published\n     * @param qos\n     *            An integer specifying the quality of service the message was published on.\n     * @param retain\n     *            Whether or not the broker should retain the message\n     * @param priority\n     *            Relative ordering of this message with other messages that may be currently queued for publishing.\n     * @return The published message's ID.\n     * @throws KuraException\n     *             if one of the message composition or message publishing operation fails.\n     */\n    public int publish(String appTopic, byte[] payload, int qos, boolean retain, int priority) throws KuraException;\n\n    /**\n     * Publishes a message to the remote server with a raw byte array payload.\n     * This is the lowest level publish API exposed by the CloudClient.\n     * Before passing the message the to {@link org.eclipse.kura.data.DataService},\n     * the CloudClient will manipulate the provided topic by appending the necessary parts\n     * to achieve topic partitioning and device identification.\n     * <br>\n     * The priority argument can be used to control the relative ordering of this\n     * message with other messages that may be currently queued for publishing.\n     * Priority level 0 (highest) should be used sparingly and reserved for\n     * messages that should be sent with the minimum latency. Life-cycle messages\n     * (e.g. device start and stop) are an example of messages that are\n     * published by the framework with priority 0.\n     * Priority 1 messages are used by the framework to publish response messages\n     * in request/response conversations to prevent a timeout at the requester.\n     * Application should consider using priority 5 or higher.\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit. The limit does not apply to internal messages with the priority less than 2.\n     * These priority levels are reserved to the framework which uses it for life-cycle messages\n     * - birth and death certificates - and replies to request/response flows.\n     *\n     * @param deviceId\n     *            A String specifying the device ID.\n     * @param appTopic\n     *            A String specifying the application portion of the topic the message is published on.\n     * @param payload\n     *            Binary payload representing the message to be published\n     * @param qos\n     *            An integer specifying the quality of service the message was published on.\n     * @param retain\n     *            Whether or not the broker should retain the message\n     * @param priority\n     *            Relative ordering of this message with other messages that may be currently queued for publishing.\n     * @return The published message's ID.\n     * @throws KuraException\n     *             if one of the message composition or message publishing operation fails.\n     * @since 1.2\n     */\n    public int publish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraException;\n\n    /**\n     * Publishes a control message to the remote server. Control messages are qualified with an\n     * additional prefix appended at the beginning of the target topic. The\n     * prefix is configured as a property of the {@link org.eclipse.kura.data.DataService} and it appended\n     * automatically by this controlPublish method. Just as {@link #publish}, the\n     * controlPublish method will manipulate the provided topic by appending the necessary parts\n     * to achieve topic partitioning including device identification and encode\n     * the {@link KuraPayload} payload into binary format.\n     * <br>\n     * The priority argument can be used to control the relative ordering of this\n     * message with other messages that may be currently queued for publishing.\n     * Priority level 0 (highest) should be used sparingly and reserved for\n     * messages that should be sent with the minimum latency. Life-cycle messages\n     * (e.g. device start and stop) are an example of messages that are\n     * published by the framework with priority 0.\n     * Priority 1 messages are used by the framework to publish response messages\n     * in request/response conversations to prevent a timeout at the requester.\n     * Application should consider using priority 5 or higher.\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit. The limit does not apply to internal messages with the priority less than 2.\n     * These priority levels are reserved to the framework which uses it for life-cycle messages\n     * - birth and death certificates - and replies to request/response flows.\n     *\n     * @param appTopic\n     *            A String specifying the application topic the message is published on.\n     * @param payload\n     *            An KuraPayload representing the message to be published\n     * @param qos\n     *            An integer specifying the quality of service the message was published on.\n     * @param retain\n     *            Whether or not the broker should retain the message\n     * @param priority\n     *            Relative ordering of this message with other messages that may be currently queued for publishing.\n     * @return The published message's ID.\n     * @throws KuraException\n     *             if one of the message composition or message publishing operation fails.\n     */\n    public int controlPublish(String appTopic, KuraPayload payload, int qos, boolean retain, int priority)\n            throws KuraException;\n\n    /**\n     * Publishes a control message to the remote server addressing it to another device.\n     * Control messages are qualified with an additional prefix appended at the beginning of the target topic.\n     * The prefix is configured as a property of the {@link org.eclipse.kura.data.DataService} and it appended\n     * automatically by this controlPublish method. Just as {@link #publish}, the\n     * controlPublish method will manipulate the provided topic by appending the necessary parts\n     * to achieve topic partitioning including device identification and encode\n     * the {@link KuraPayload} payload into binary format.\n     * <br>\n     * The priority argument can be used to control the relative ordering of this\n     * message with other messages that may be currently queued for publishing.\n     * Priority level 0 (highest) should be used sparingly and reserved for\n     * messages that should be sent with the minimum latency. Life-cycle messages\n     * (e.g. device start and stop) are an example of messages that are\n     * published by the framework with priority 0.\n     * Priority 1 messages are used by the framework to publish response messages\n     * in request/response conversations to prevent a timeout at the requester.\n     * Application should consider using priority 5 or higher.\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit. The limit does not apply to internal messages with the priority less than 2.\n     * These priority levels are reserved to the framework which uses it for life-cycle messages\n     * - birth and death certificates - and replies to request/response flows.\n     *\n     * @param deviceId\n     *            A String specifying the device ID.\n     * @param appTopic\n     *            A String specifying the application topic the message is published on.\n     * @param payload\n     *            An KuraPayload representing the message to be published\n     * @param qos\n     *            An integer specifying the quality of service the message was published on.\n     * @param retain\n     *            Whether or not the broker should retain the message\n     * @param priority\n     *            Relative ordering of this message with other messages that may be currently queued for publishing.\n     * @return The published message's ID.\n     * @throws KuraException\n     *             if one of the message composition or message publishing operation fails.\n     */\n    public int controlPublish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain,\n            int priority) throws KuraException;\n\n    /**\n     * Publishes a control message to the remote server addressing it to another device\n     * with a raw byte array payload.\n     * Control messages are qualified with an additional prefix appended at the beginning of the target topic.\n     * The prefix is configured as a property of the {@link org.eclipse.kura.data.DataService} and it appended\n     * automatically by this controlPublish method. Just as {@link #publish}, the\n     * controlPublish method will manipulate the provided topic by appending the necessary parts\n     * to achieve topic partitioning including device identification.\n     * <br>\n     * The priority argument can be used to control the relative ordering of this\n     * message with other messages that may be currently queued for publishing.\n     * Priority level 0 (highest) should be used sparingly and reserved for\n     * messages that should be sent with the minimum latency. Life-cycle messages\n     * (e.g. device start and stop) are an example of messages that are\n     * published by the framework with priority 0.\n     * Priority 1 messages are used by the framework to publish response messages\n     * in request/response conversations to prevent a timeout at the requester.\n     * Application should consider using priority 5 or higher.\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit. The limit does not apply to internal messages with the priority less than 2.\n     * These priority levels are reserved to the framework which uses it for life-cycle messages\n     * - birth and death certificates - and replies to request/response flows.\n     *\n     * @param deviceId\n     *            A String specifying the device ID.\n     * @param appTopic\n     *            A String specifying the application topic the message is published on.\n     * @param payload\n     *            Binary payload representing the message to be published.\n     * @param qos\n     *            An integer specifying the quality of service the message was published on.\n     * @param retain\n     *            Whether or not the broker should retain the message.\n     * @param priority\n     *            Relative ordering of this message with other messages that may be currently queued for publishing.\n     * @return The published message's ID.\n     * @throws KuraException\n     *             if one of the message composition or message publishing operation fails.\n     */\n    public int controlPublish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraException;\n\n    /**\n     * Subscribes to a topic with the remote server. The topic is specified as a String\n     * object and the QoS is specified as an integer. The CloudClient will manipulate the\n     * provided topic by appending the necessary parts to achieve topic partitioning and\n     * device identification.<br>\n     * This is a synchronous call. If the subscribe fails, an exception will be thrown\n     * that will contain information about the cause of the failure.\n     *\n     * @param appTopic\n     *            A String object containing the application topic.\n     * @param qos\n     *            An int containing the Quality of Service.\n     * @throws KuraException\n     *             if the subscription fails.\n     */\n    public void subscribe(String appTopic, int qos) throws KuraException;\n\n    /**\n     * Subscribes to a topic with the remote server. The topic is specified by two StringS: one characterizing the\n     * deviceId and the other representing the appTopic. The QoS is specified as an integer. The CloudClient will\n     * manipulate the provided topic by appending the necessary parts to achieve topic partitioning and\n     * device identification.<br>\n     * This is a synchronous call. If the subscribe fails, an exception will be thrown\n     * that will contain information about the cause of the failure.\n     *\n     * @param deviceId\n     *            A String specifying the device ID.\n     * @param appTopic\n     *            A String object containing the application topic.\n     * @param qos\n     *            An int containing the Quality of Service.\n     * @throws KuraException\n     *             if the subscription fails.\n     * @since 1.2\n     */\n    public void subscribe(String deviceId, String appTopic, int qos) throws KuraException;\n\n    /**\n     * Subscribes to a control topic with the remote server. The topic is specified as a String\n     * object and the QoS is specified as an integer. The CloudClient will manipulate the\n     * provided topic by appending the necessary parts to achieve topic partitioning and\n     * including control prefix and device identification.<br>\n     * This is a synchronous call. If the subscribe fails, an exception will be thrown\n     * that will contain information about the cause of the failure.\n     *\n     * @param appTopic\n     *            A String object containing the application topic.\n     * @param qos\n     *            An int containing the Quality of Service.\n     * @throws KuraException\n     *             if the subscription fails.\n     */\n    public void controlSubscribe(String appTopic, int qos) throws KuraException;\n\n    /**\n     * Subscribes to a control topic with the remote server. The topic is specified by two StringS: one characterizing\n     * the deviceId and the other representing the appTopic. The QoS is specified as an integer. The CloudClient will\n     * manipulate the provided topic by appending the necessary parts to achieve topic partitioning and\n     * including control prefix and device identification.<br>\n     * This is a synchronous call. If the subscribe fails, an exception will be thrown\n     * that will contain information about the cause of the failure.\n     *\n     * @param deviceId\n     *            A String specifying the device ID.\n     * @param appTopic\n     *            A String object containing the application topic.\n     * @param qos\n     *            An int containing the Quality of Service.\n     * @throws KuraException\n     *             if the subscription fails.\n     * @since 1.2\n     */\n    public void controlSubscribe(String deviceId, String appTopic, int qos) throws KuraException;\n\n    /**\n     * Unubscribes to a topic with the remote server. The topic is specified as a String\n     * object and the QoS is specified as an integer. The CloudClient will manipulate the\n     * provided topic by appending the necessary parts to achieve topic partitioning and\n     * device identification.<br>\n     * This is a synchronous call. If the unsubscribe fails, an exception will be thrown\n     * that will contain information about the cause of the failure.\n     *\n     * @param appTopic\n     *            A String object containing the application topic.\n     * @throws KuraException\n     *             if the unsubscription fails.\n     */\n    public void unsubscribe(String appTopic) throws KuraException;\n\n    /**\n     * Unubscribes to a topic with the remote server. The topic is specified by two StringS: one characterizing\n     * the deviceId and the other representing the appTopic. The QoS is specified as an integer. The CloudClient will\n     * manipulate the provided topic by appending the necessary parts to achieve topic partitioning and\n     * device identification.<br>\n     * This is a synchronous call. If the unsubscribe fails, an exception will be thrown\n     * that will contain information about the cause of the failure.\n     *\n     * @param deviceId\n     *            A String specifying the device ID.\n     * @param appTopic\n     *            A String object containing the application topic.\n     * @throws KuraException\n     *             if the unsubscription fails.\n     * @since 1.2\n     */\n    public void unsubscribe(String deviceId, String appTopic) throws KuraException;\n\n    /**\n     * Unsubscribes to a control topic with the remote server. The topic is specified as a String\n     * object and the QoS is specified as an integer. The CloudClient will manipulate the\n     * provided topic by appending the necessary parts to achieve topic partitioning and\n     * including control prefix and device identification.<br>\n     * This is a synchronous call. If the unsubscribe fails, an exception will be thrown\n     * that will contain information about the cause of the failure.\n     *\n     * @param appTopic\n     *            A String object containing the application topic.\n     * @throws KuraException\n     *             if the unsubscription fails.\n     */\n    public void controlUnsubscribe(String appTopic) throws KuraException;\n\n    /**\n     * Unsubscribes to a control topic with the remote server. The topic is specified by two StringS: one characterizing\n     * the deviceId and the other representing the appTopic. The QoS is specified as an integer. The CloudClient will\n     * manipulate the provided topic by appending the necessary parts to achieve topic partitioning and\n     * including control prefix and device identification.<br>\n     * This is a synchronous call. If the unsubscribe fails, an exception will be thrown\n     * that will contain information about the cause of the failure.\n     *\n     * @param deviceId\n     *            A String specifying the device ID.\n     * @param appTopic\n     *            A String object containing the application topic.\n     * @throws KuraException\n     *             if the unsubscription fails.\n     * @since 1.2\n     */\n    public void controlUnsubscribe(String deviceId, String appTopic) throws KuraException;\n\n    /**\n     * Adds a CloudCallbackHandler with this CloudClient. This handler\n     * will receive events when a client publication has arrived, and\n     * when a publish has been fully acknowledged by the remote server.\n     *\n     * @param cloudClientListener\n     *            An implementation of the CloudCallbackHandler interface.\n     */\n    public void addCloudClientListener(CloudClientListener cloudClientListener);\n\n    /**\n     * Removes a CloudCallbackHandler from this CloudClient.\n     * The provided CloudCallbackHandler will no longer receive the events\n     * when a published message is received.\n     */\n    public void removeCloudClientListener(CloudClientListener cloudClientListener);\n\n    /**\n     * Gets the list of identifiers of messages that have not been published yet.\n     *\n     * @return a list of integers.\n     * @throws KuraException\n     *             if the operation fails.\n     */\n    List<Integer> getUnpublishedMessageIds() throws KuraException;\n\n    /**\n     * Finds the list of identifiers of messages that are still in-flight\n     * (messages published but not confirmed yet).\n     * This only applies to messages published with QoS &gt; 0.\n     *\n     * @return a list of integers.\n     * @throws KuraException\n     *             if the operation fails.\n     */\n    List<Integer> getInFlightMessageIds() throws KuraException;\n\n    /**\n     * Finds the list of identifiers of in-flight messages that have been dropped.\n     * This only applies to messages published with QoS &gt; 0.\n     * On the establishment of a new connection, the service can be configured\n     * either to republish or drop in-flight messages.\n     * The former option can be used if service users tolerate publishing message\n     * duplicates.\n     * The latter option can be used it service users tolerate losing messages.\n     *\n     * @return a list of integers.\n     * @throws KuraException\n     *             if the operation fails.\n     */\n    List<Integer> getDroppedInFlightMessageIds() throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudClientListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport org.eclipse.kura.message.KuraPayload;\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * CloudClientListener is the interface to be implemented by applications that needs to be notified of events in the\n * {@link CloudClient}.\n * Arrived methods are invoked whenever a message is sent to a appTopic associated to the CloudClient.\n * The Arrived method signatures are differentiated based on whether the incoming messages have been\n * published to a data topic (by default accountName/#) or a control topic (by default $EDC/accountName/#).\n *\n * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.listener.CloudConnectionListener} and \n * {@link org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener} instead\n */\n@ConsumerType\n@Deprecated\npublic interface CloudClientListener {\n\n    /**\n     * Called by the CloudClient when it receives a published control message from the broker.\n     * If the message received has a binary payload that it has NOT been encoded using the\n     * the KuraPayload class, the received bytes will be set as the body field of a new\n     * KuraPaylaod instance which is passed to the callback Listener interface.\n     *\n     * @param deviceId\n     *            The deviceId this message was addressed to.\n     * @param appTopic\n     *            The appTopic the message arrived on.\n     * @param msg\n     *            The KuraPayload that arrived.\n     * @param qos\n     *            The Quality of Service that the message was received on.\n     * @param retain\n     *            Whether the message was retained by the broker.\n     */\n    void onControlMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain);\n\n    /**\n     * Called by the client when it receives a published data message from the broker.\n     * If the message received has a binary payload that it has NOT been encoded using the\n     * the KuraPayload class, the received bytes will be set as the body field of a new\n     * KuraPaylaod instance which is passed to the callback Listener interface.\n     *\n     * @param deviceId\n     *            The asset ID of the semanticTopic prefix the message arrived on.\n     * @param appTopic\n     *            The appTopic the message arrived on.\n     * @param msg\n     *            The KuraPayload that arrived.\n     * @param qos\n     *            The Quality of Service that the message was received on.\n     * @param retain\n     *            Whether the message was retained by the broker.\n     */\n    void onMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain);\n\n    /**\n     * Called when the client has lost its connection with the broker. Depending on the {@link org.eclipse.kura.data.DataService}\n     * configuration, the client will attempt to reconnect and call the\n     * {@link CloudClientListener#onConnectionEstablished}\n     * method upon a successful reconnect. This is only a notification, the callback handler should\n     * not attempt to handle the reconnect.\n     * <br>\n     * If the bundle using the client relies on subscriptions beyond the default ones,\n     * it is responsibility of the application to implement the {@link CloudClientListener#onConnectionEstablished}\n     * callback method to restore the subscriptions it needs after a connection loss.\n     */\n    void onConnectionLost();\n\n    /**\n     * Called when the CloudClient has successfully connected with the broker.\n     * <br>\n     * If the bundle using the client relies on subscriptions beyond the default ones,\n     * it is responsibility of the application to implement the {@link CloudClientListener#onConnectionEstablished}\n     * callback method to restore the subscriptions it needs after a connection loss.\n     */\n    void onConnectionEstablished();\n\n    /**\n     * Called by the CloudClient when a published message has been fully acknowledged by the broker,\n     * as appropriate for the quality of service. The published method is not called for QoS 0 publications.\n     *\n     * @param messageId\n     *            The message id of the published message\n     */\n    void onMessageConfirmed(int messageId, String appTopic);\n\n    /**\n     * Called by the CloudClient when a message has been transfered from the publishing queue\n     * to the underlying {@link org.eclipse.kura.data.DataTransportService} for publishing on the wire.\n     */\n    void onMessagePublished(int messageId, String appTopic);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudConnectionEstablishedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * CloudConnectionEstablishedEvent is raised with the Cloud Connection is established.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class CloudConnectionEstablishedEvent extends Event {\n\n    /** Topic of the CloudConnectionEstablishedEvent */\n    public static final String CLOUD_CONNECTION_STATUS_ESTABLISHED = \"org/eclipse/kura/cloud/CloudConnectionStatus/ESTABLISHED\";\n\n    public CloudConnectionEstablishedEvent(Map<String, ?> properties) {\n        super(CLOUD_CONNECTION_STATUS_ESTABLISHED, properties);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudConnectionLostEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * CloudConnectionEstablishedEvent is raised with the Cloud Connection is lost.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class CloudConnectionLostEvent extends Event {\n\n    /** Topic of the CloudConnectionLostEvent */\n    public static final String CLOUD_CONNECTION_STATUS_LOST = \"org/eclipse/kura/cloud/CloudConnectionStatus/LOST\";\n\n    public CloudConnectionLostEvent(Map<String, ?> properties) {\n        super(CLOUD_CONNECTION_STATUS_LOST, properties);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudPayloadEncoding.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloud;\n\n/**\n * This enum specifies the supported payload encodings.\n *\n * @since 1.2\n */\npublic enum CloudPayloadEncoding {\n    KURA_PROTOBUF(\"kura-protobuf\"),\n    SIMPLE_JSON(\"simple-json\");\n\n    private final String encodingText;\n\n    private CloudPayloadEncoding(String encoding) {\n        this.encodingText = encoding;\n    }\n\n    /**\n     * Allows to map a provided string with the corresponding {@link CloudPayloadEncoding}\n     *\n     * @param proposedEncoding\n     *            the String that has to be mapped to the corresponding {@link CloudPayloadEncoding}\n     * @return {@link CloudPayloadEncoding} if the matching between passed string and enum values succeeds\n     * @throws IllegalArgumentException\n     *             if the argument cannot be matched to a corresponding {@link CloudPayloadEncoding} object.\n     */\n    public static CloudPayloadEncoding getEncoding(String proposedEncoding) {\n        for (CloudPayloadEncoding encoding : CloudPayloadEncoding.values()) {\n            if (encoding.encodingText.equalsIgnoreCase(proposedEncoding)) {\n                return encoding;\n            }\n        }\n        throw new IllegalArgumentException(\"Unsupported Encoding!\");\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudPayloadProtoBufDecoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface CloudPayloadProtoBufDecoder {\n\n    /**\n     * Decodes a Google Protocol Buffers encoded, optionally gzipped, binary payload to a\n     * {@link org.eclipse.kura.message.KuraPayload}.\n     *\n     * @param payload\n     * @return\n     * @throws KuraException\n     */\n    public KuraPayload buildFromByteArray(byte[] payload) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudPayloadProtoBufEncoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface CloudPayloadProtoBufEncoder {\n\n    /**\n     * Encodes a {@link org.eclipse.kura.message.KuraPayload} to a Google Protocol Buffers encoded, optionally gzipped,\n     * binary payload.\n     *\n     * @param kuraPayload\n     * @param gzipped\n     * @return\n     * @throws KuraException\n     */\n    byte[] getBytes(KuraPayload kuraPayload, boolean gzipped) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The CloudService provides an easy to use API layer for M2M application to communicate with a remote server.\n * It operates as a decorator for the {@link org.eclipse.kura.data.DataService} providing add-on\n * features over the management of the transport layer.\n * In addition to simple publish/subscribe, the Cloud Service API simplifies the implementation of more complex\n * interaction flows like request/response or remote resource management. Cloud Service abstracts the\n * developers from the complexity of the transport protocol and payload format used in the communication.<br>\n * CloudService allows for a single connection to a remote server to be shared across more than one application\n * in the gateway providing the necessary topic partitioning.<br>\n * Its responsibilities can be summarized as:\n * <ul>\n * <li>Adds application topic prefixes to allow for a single remote server connection to be shared across applications\n * <li>Define a payload data model and provide default encoding/decoding serializers\n * <li>Publish life-cycle messages when device and applications start and stop\n * </ul>\n * The CloudService can be used through the {@link CloudClient} API or by extending the {@link Cloudlet} class.\n * {@link Cloudlet} simplifies the interactions with remote servers providing a servlet-like API\n * to implement request and response flows and remote resource management.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n *\n * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.CloudConnectionManager}\n */\n@ProviderType\n@Deprecated\npublic interface CloudService {\n\n    /**\n     * Returns a new instance of the CloudClient for the given application Id.\n     * The CloudClient is designed to be used by single application bundles.\n     * CloudClient instances are acquired from the CloudService and they are released\n     * when the work is completed. Generally, a CloudClient is acquired during the\n     * activation phase of a bundle and it is released through the\n     * {@link CloudClient#release} method during the bundle deactivation phase.\n     * <br>\n     * CloudClient will clean-up the subscriptions and the callback registrations\n     * when the {@link CloudClient#release} method is called.\n     * <br>\n     * If the bundle using the CloudClient relies on subscriptions,\n     * it is responsibility of the application to implement the\n     * {@link CloudClientListener#onConnectionEstablished()} callback method\n     * in the CloudCallbackHandler to restore the subscriptions it needs.\n     *\n     * @param appId\n     *            A String object specifying a unique application ID.\n     * @return CloudClient instance\n     * @throws KuraException\n     */\n    public CloudClient newCloudClient(String appId) throws KuraException;\n\n    /**\n     * Returns the application identifiers for which a CloudClient instance was created.\n     *\n     * @return An array of application identifiers\n     */\n    public String[] getCloudApplicationIdentifiers();\n\n    /**\n     * Returns true if the underlying {@link org.eclipse.kura.data.DataService} is currently connected to the remote\n     * server.\n     *\n     * @return\n     */\n    public boolean isConnected();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/Cloudlet.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport java.util.Date;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.Logger;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraRequestPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.osgi.annotation.versioning.ConsumerType;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.component.ComponentException;\n\n/**\n * Cloudlet is an abstract class that can be extended by services that wants to implement remote resource management.\n * The Cloudlet abstracts the detailed of the communication with the remote clients providing easy to use template\n * methods to be implemented by subclasses to handle CRUD operations on local resources.\n * <ul>\n * <li>{@link Cloudlet#doGet} is used to implement a READ request for a resource identified by the supplied\n * {@link CloudletTopic#getResources()}\n * <li>{@link Cloudlet#doPut} is used to implement a CREATE or UPDATE request for a resource identified by the supplied\n * {@link CloudletTopic#getResources()}\n * <li>{@link Cloudlet#doDel} is used to implement a DELETE request for a resource identified by the supplied\n * {@link CloudletTopic#getResources()}\n * <li>{@link Cloudlet#doPost} is used to implement other operations on a resource identified by the supplied\n * {@link CloudletTopic#getResources()}\n * <li>{@link Cloudlet#doExec} is used to perform applicatioon operation not necessary tied to a given resource.\n * </ul>\n *\n * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.request.RequestHandler}\n */\n@ConsumerType\n@Deprecated\npublic abstract class Cloudlet implements CloudClientListener {\n\n    private static final Logger logger = LogManager.getLogger(Cloudlet.class);\n\n    protected static final int DFLT_PUB_QOS = 0;\n    protected static final boolean DFLT_RETAIN = false;\n    protected static final int DFLT_PRIORITY = 1;\n\n    private static final int NUM_CONCURRENT_CALLBACKS = 2;\n    private static ExecutorService callbackExecutor = Executors.newFixedThreadPool(NUM_CONCURRENT_CALLBACKS);\n\n    private CloudService cloudService;\n    private CloudClient cloudClient;\n\n    private ComponentContext ctx;\n\n    private final String applicationId;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setCloudService(CloudService cloudService) {\n        this.cloudService = cloudService;\n    }\n\n    public void unsetCloudService(CloudService cloudService) {\n        this.cloudService = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) {\n        // get the mqtt client for this application\n        try {\n\n            logger.info(\"Getting CloudApplicationClient for {}...\", this.applicationId);\n            this.cloudClient = this.cloudService.newCloudClient(this.applicationId);\n            this.cloudClient.addCloudClientListener(this);\n\n            // Don't subscribe because these are handled by the default subscriptions and we don't want to get messages\n            // twice\n            this.ctx = componentContext;\n        } catch (KuraException e) {\n            logger.error(\"Cannot activate\", e);\n            throw new ComponentException(e);\n        }\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        // close the application client.\n        // this will unsubscribe all open subscriptions\n        logger.info(\"Releasing CloudApplicationClient for {}...\", this.applicationId);\n        if (this.cloudClient != null) {\n            this.cloudClient.release();\n        }\n    }\n\n    protected Cloudlet(String appId) {\n        this.applicationId = appId;\n    }\n\n    public String getAppId() {\n        return this.applicationId;\n    }\n\n    protected CloudService getCloudService() {\n        return this.cloudService;\n    }\n\n    protected CloudClient getCloudApplicationClient() {\n        return this.cloudClient;\n    }\n\n    protected ComponentContext getComponentContext() {\n        return this.ctx;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Default handlers\n    //\n    // ----------------------------------------------------------------\n\n    protected void doGet(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload)\n            throws KuraException {\n        logger.info(\"Default GET handler\");\n        respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND);\n    }\n\n    protected void doPut(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload)\n            throws KuraException {\n        logger.info(\"Default PUT handler\");\n        respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND);\n    }\n\n    protected void doPost(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload)\n            throws KuraException {\n        logger.info(\"Default POST handler\");\n        respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND);\n    }\n\n    protected void doDel(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload)\n            throws KuraException {\n        logger.info(\"Default DEL handler\");\n        respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND);\n    }\n\n    protected void doExec(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload)\n            throws KuraException {\n        logger.info(\"Default EXEC handler\");\n        respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND);\n    }\n\n    @Override\n    public void onControlMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) {\n        try {\n\n            logger.debug(\"Control Arrived on topic: {}\", appTopic);\n\n            StringBuilder sb = new StringBuilder(this.applicationId).append(\"/\").append(\"REPLY\");\n\n            if (appTopic.startsWith(sb.toString())) {\n                // Ignore replies\n                return;\n            }\n\n            // Handle the message asynchronously to not block the master client\n            callbackExecutor.submit(new MessageHandlerCallable(this, deviceId, appTopic, msg, qos, retain));\n        } catch (Throwable t) {\n            logger.error(\"Unexpected throwable: {}\", t);\n        }\n    }\n\n    @Override\n    public void onMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) {\n        logger.error(\"Unexpected message arrived on topic: \" + appTopic);\n    }\n\n    @Override\n    public void onConnectionLost() {\n        logger.warn(\"Cloud Client Connection Lost!\");\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        logger.info(\"Cloud Client Connection Restored\");\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        logger.debug(\"Message Confirmed (\" + messageId + \")\");\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        logger.debug(\"Message Published (\" + messageId + \")\");\n    }\n}\n\nclass MessageHandlerCallable implements Callable<Void> {\n\n    private static final Logger logger = LogManager.getLogger(MessageHandlerCallable.class);\n\n    private final Cloudlet cloudApp;\n    @SuppressWarnings(\"unused\")\n    private final String deviceId;\n    private final String appTopic;\n    private final KuraPayload msg;\n    @SuppressWarnings(\"unused\")\n    private final int qos;\n    @SuppressWarnings(\"unused\")\n    private final boolean retain;\n\n    public MessageHandlerCallable(Cloudlet cloudApp, String deviceId, String appTopic, KuraPayload msg, int qos,\n            boolean retain) {\n        super();\n        this.cloudApp = cloudApp;\n        this.deviceId = deviceId;\n        this.appTopic = appTopic;\n        this.msg = msg;\n        this.qos = qos;\n        this.retain = retain;\n    }\n\n    @Override\n    public Void call() throws Exception {\n        logger.debug(\"Control Arrived on topic: {}\", this.appTopic);\n\n        // Prepare the default response\n        KuraRequestPayload reqPayload = KuraRequestPayload.buildFromKuraPayload(this.msg);\n        KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n\n        try {\n\n            CloudletTopic reqTopic = CloudletTopic.parseAppTopic(this.appTopic);\n            CloudletTopic.Method method = reqTopic.getMethod();\n            switch (method) {\n            case GET:\n                logger.debug(\"Handling GET request topic: {}\", this.appTopic);\n                this.cloudApp.doGet(reqTopic, reqPayload, respPayload);\n                break;\n\n            case PUT:\n                logger.debug(\"Handling PUT request topic: {}\", this.appTopic);\n                this.cloudApp.doPut(reqTopic, reqPayload, respPayload);\n                break;\n\n            case POST:\n                logger.debug(\"Handling POST request topic: {}\", this.appTopic);\n                this.cloudApp.doPost(reqTopic, reqPayload, respPayload);\n                break;\n\n            case DEL:\n                logger.debug(\"Handling DEL request topic: {}\", this.appTopic);\n                this.cloudApp.doDel(reqTopic, reqPayload, respPayload);\n                break;\n\n            case EXEC:\n                logger.debug(\"Handling EXEC request topic: {}\", this.appTopic);\n                this.cloudApp.doExec(reqTopic, reqPayload, respPayload);\n                break;\n\n            default:\n                logger.error(\"Bad request topic: {}\", this.appTopic);\n                respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_BAD_REQUEST);\n                break;\n            }\n        } catch (IllegalArgumentException e) {\n            logger.error(\"Bad request topic: {}\", this.appTopic);\n            respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_BAD_REQUEST);\n        } catch (KuraException e) {\n            logger.error(\"Error handling request topic: {}\\n{}\", this.appTopic, e);\n            respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR);\n            respPayload.setException(e);\n        }\n\n        try {\n\n            CloudClient cloudClient = this.cloudApp.getCloudApplicationClient();\n            respPayload.setTimestamp(new Date());\n\n            StringBuilder sb = new StringBuilder(\"REPLY\").append(\"/\").append(reqPayload.getRequestId());\n\n            String requesterClientId = reqPayload.getRequesterClientId();\n\n            logger.debug(\"Publishing response topic: {}\", sb.toString());\n            cloudClient.controlPublish(requesterClientId, sb.toString(), respPayload, Cloudlet.DFLT_PUB_QOS,\n                    Cloudlet.DFLT_RETAIN, Cloudlet.DFLT_PRIORITY);\n        } catch (KuraException e) {\n            logger.error(\"Error publishing response for topic: {}\\n{}\", this.appTopic, e);\n        }\n\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudletTopic.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.message.KuraMessage} properties\n */\n@ProviderType\n@Deprecated\npublic class CloudletTopic {\n\n    public enum Method {\n        GET,\n        PUT,\n        POST,\n        DEL,\n        EXEC;\n    }\n\n    private Method method;\n    private String[] resources;\n\n    public static CloudletTopic parseAppTopic(String appTopic) {\n        CloudletTopic edcApplicationTopic = new CloudletTopic();\n\n        String[] parts = appTopic.split(\"/\");\n        edcApplicationTopic.method = Method.valueOf(parts[0]);\n        if (parts.length > 1) {\n\n            edcApplicationTopic.resources = new String[parts.length - 1];\n            for (int i = 0; i < edcApplicationTopic.resources.length; i++) {\n                edcApplicationTopic.resources[i] = parts[i + 1];\n            }\n        }\n        return edcApplicationTopic;\n    }\n\n    private CloudletTopic() {\n        super();\n    }\n\n    public Method getMethod() {\n        return this.method;\n    }\n\n    public String[] getResources() {\n        return this.resources;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder(this.method.name());\n        if (this.resources != null) {\n            for (String resource : this.resources) {\n                sb.append(\"/\");\n                sb.append(resource);\n            }\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/factory/CloudServiceFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloud.factory;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A CloudServiceFactory represents an OSGi Declarative Service Component\n * which registers {@link org.eclipse.kura.cloud.CloudService}S in the framework.\n * The Component creates multiple component instances upon reception of a configuration\n * created through the Configuration Service.\n * <br>\n * It provides a CloudService implementation that can be used to connect to a specific Cloud platform.\n * <br>\n * Typically, each CloudService created by a CloudServiceFactory\n * establishes and manages its own connection, for example an Mqtt connection.\n * <br>\n * Multiple CloudServiceFactory services can be registered in the framework to support multiple simultaneous\n * connections to different Cloud platforms.\n * <br>\n * Kura provides a default CloudServiceFactory implementation and creates a default CloudService.\n * <br>\n * A CloudServiceFactory manages the construction of a CloudService and the services it depends on.\n * While the same can be achieved through the {@link org.eclipse.kura.configuration.ConfigurationService},\n * CloudServiceFactory simplifies this process and offers more control.\n * <br>\n * For example, in a stack architecture with CloudService at the top of the stack\n * and where lower layers are also components,\n * an implementation of CloudServiceFactory could create new configurations\n * for all the stack layers thus constructing a new whole stack instance.\n * <br>\n * The Kura {@link org.eclipse.kura.cloud.CloudService}/{@link org.eclipse.kura.data.DataService}/{@link org.eclipse.kura.data.DataTransportService}\n * cloud stack represents an example of the above architecture\n * and can serve as a reference implementation for alternative Cloud stacks.\n * <br>\n * In order to leverage the Kura configuration persistence in snapshot files,\n * an implementation will use the {@link org.eclipse.kura.configuration.ConfigurationService}\n * to create component configurations.\n *\n * @since 1.0.8\n *\n * @noimplement This interface is not intended to be implemented by clients.\n *\n * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory}\n */\n@ProviderType\n@Deprecated\npublic interface CloudServiceFactory {\n\n    /**\n     * The name of the property set in a @{link org.eclipse.kura.cloud.CloudService} configuration created\n     * through {@link #createConfiguration}.\n     * The property is set in the cloud service instance to relate it with the Factory that generated the whole cloud\n     * stack.\n     *\n     * @since 1.1.0\n     */\n    public static final String KURA_CLOUD_SERVICE_FACTORY_PID = \"kura.cloud.service.factory.pid\";\n\n    /**\n     * Returns the factory PID of the OSGi Factory Component represented by this CloudServiceFactory.\n     *\n     * @return a String representing the factory PID of the Factory Component.\n     */\n    String getFactoryPid();\n\n    /**\n     * Creates a {@link org.eclipse.kura.cloud.CloudService} instance and initializes its configuration with the defaults\n     * expressed in the Metatype of the target component factory providing the CloudService.\n     * <br>\n     * Implementation will normally rely on {@link org.eclipse.kura.configuration.ConfigurationService#createFactoryConfiguration}\n     * to perform the actual creation of the component instance and the persistence of the component configuration.\n     * <br>\n     * The created CloudService instance will have its <i>kura.service.pid</i> property\n     * set to the value provided in the <i>pid</i> parameter.\n     * <br>\n     * Kura apps can look up the created CloudService instance through {@link org.osgi.service.component.ComponentContext#locateServices}\n     * by filtering on the <i>kura.service.pid</i> property.\n     * <br>\n     * Likely, Kura apps will rely on OSGi Declarative Services to have their CloudService dependencies satisfied based\n     * on a <i>target</i> filter on the value of the property <i>kura.service.pid</i>\n     * in their component definition.\n     * <br>\n     * In the following example a Kura app declares two dependencies on CloudServiceS whose PIDs are\n     * <i>myCloudService</i> and <i>anotherCloudService</i>:\n     *\n     * <pre>\n     * &lt;reference name=\"myCloudServiceReference\"\n     *              policy=\"static\"\n     *              bind=\"setMyCloudService\"\n     *              unbind=\"unsetMyCloudService\"\n     *              cardinality=\"1..1\"\n     *              interface=\"org.eclipse.kura.cloud.CloudService\"/&gt;\n     * &lt;property  name=\"myCloudServiceReference.target\"\n     *              type=\"String\"\n     *              value=\"(kura.service.pid=myCloudService)\"/&gt;\n     *\n     * &lt;reference name=\"anotherCloudServiceReference\"\n     *              policy=\"static\"\n     *              bind=\"setAnotherCloudService\"\n     *              unbind=\"unsetAnotherCloudService\"\n     *              cardinality=\"1..1\"\n     *              interface=\"org.eclipse.kura.cloud.CloudService\"/&gt;\n     * &lt;property  name=\"anotherCloudServiceReference.target\"\n     *              type=\"String\"\n     *              value=\"(kura.service.pid=anotherCloudService)\"/&gt;\n     * </pre>\n     *\n     * @param pid\n     *            the Kura persistent identifier, <i>kura.service.pid</i>, of the factory component configuration.\n     * @throws KuraException\n     */\n    void createConfiguration(String pid) throws KuraException;\n\n    /**\n     * Returns the list of <i>kura.service.pid</i>s that compose the cloud stack associated with the provided\n     * <i>kura.service.pid</i> of the factory component configuration.\n     *\n     * @param pid\n     *            the Kura persistent identifier, <i>kura.service.pid</i>, of the factory component configuration.\n     * @return List&lt;String&gt;, the list of <i>kura.service.pid</i>s associated with the specified factory component\n     *         configuration.\n     * @throws KuraException\n     *             if the specified <i>kura.service.pid</i> is not correct or compliant with what the factory\n     *             implementation expects\n     * @since 1.1.0\n     */\n    List<String> getStackComponentsPids(String pid) throws KuraException;\n\n    /**\n     * Deletes a previously created configuration deactivating the associated {@link org.eclipse.kura.cloud.CloudService} instance.\n     *\n     * @param pid\n     *            the Kura persistent identifier, <i>kura.service.pid</i>, of the factory component configuration.\n     * @throws KuraException\n     */\n    void deleteConfiguration(String pid) throws KuraException;\n\n    /**\n     * Return a set of services managed by this factory\n     * <br>\n     * It is up to the factory how it does assembles this. The PIDs returned by this list must be the PIDs assigned\n     * to the OSGi service property <i>kura.service.pid</i> and it must be possible to pass all those results into\n     * the method {@link #getStackComponentsPids(String)} of the same factory instance.\n     * <br>\n     * The IDs returned by this method must not necessarily point to registered OSGi services. But if they do, they must\n     * point only to instances of the {@link org.eclipse.kura.cloud.CloudService}.\n     *\n     * @return the set of services, never returns {@code null}\n     * @throws KuraException\n     *\n     * @since 1.1.0\n     */\n    Set<String> getManagedCloudServicePids() throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/factory/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Contains interfaces to manage the construction of Cloud Services.\n */\n@Deprecated\npackage org.eclipse.kura.cloud.factory;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides services for managing communications between M2M applications and remote servers. Types of communications\n * include simple publish/subscribe models to more complex\n * request/response and remote resource management.\n *\n */\npackage org.eclipse.kura.cloud;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/CloudConnectionConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection;\n\n\n/**\n * Provides constants that are used by cloud connections to relate service instances to their respective\n * {@link CloudEndpoint} or {@link org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory}.\n *\n * @since 2.0\n */\npublic enum CloudConnectionConstants {\n\n    /**\n     * The key of the property that specifies the {@code kura.service.pid} of the associated\n     * {@link CloudEndpoint} in {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher} \n     * or {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber} component configuration.\n     */\n    CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME(\"cloud.endpoint.service.pid\"),\n\n    /**\n     * The key of the property that specifies the {@code kura.service.pid} of the associated\n     * {@link org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory} in {@link CloudEndpoint} component definition.\n     */\n    CLOUD_CONNECTION_FACTORY_PID_PROP_NAME(\"cloud.connection.factory.pid\");\n\n    private String value;\n\n    private CloudConnectionConstants(final String value) {\n        this.value = value;\n    }\n\n    public String value() {\n        return this.value;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/CloudConnectionManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraDisconnectException;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A {@link CloudEndpoint} can implement CloudConnectionManager to support the management of\n * long-lived/always on connections.\n *\n * This interface provides methods to connect, disconnect and get the connection state of the associated CloudEndpoint.\n * It also provides methods to register {@link CloudConnectionListener}s that will be notified of connection-related\n * events.\n *\n * The implementor must register itself as a CloudConnectionManager OSGi service provider.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.0\n */\n@ProviderType\npublic interface CloudConnectionManager {\n\n    /**\n     * Establishes a connection to the configured cloud platform.\n     *\n     * @throws org.eclipse.kura.KuraException\n     *             if the operation fails\n     */\n    public void connect() throws KuraConnectException;\n\n    /**\n     * Performs a clean disconnection from the cloud platform.\n     *\n     * @throws org.eclipse.kura.KuraException\n     *             if the operation fails\n     */\n    public void disconnect() throws KuraDisconnectException;\n\n    /**\n     * Tests if the connection is alive.\n     *\n     * @return {@code true} if the framework is connected to the remote server. {@code false} otherwise.\n     */\n    public boolean isConnected();\n\n    /**\n     * The implementation will register the {@link CloudConnectionListener} instance passed as argument. Once a cloud\n     * connection related event happens, all the registered {@link CloudConnectionListener}s will be notified.\n     *\n     * @param cloudConnectionListener\n     *            a {@link CloudConnectionListener} instance\n     */\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n    /**\n     * Unregisters the provided {@link CloudConnectionListener} instance from cloud connection related events\n     * notifications.\n     *\n     * @param cloudConnectionListener\n     */\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/CloudEndpoint.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * CloudEndpoint provide APIs to ease the communication with a cloud platform allowing to publish a message, manage\n * subscribers, subscribe to message delivery notification or get information about the specific cloud endpoint\n * configuration.\n *\n * Each CloudEndpoint is referenced by zero or more {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher}\n * and {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber} instances.\n *\n * Applications should not use directly this API but, instead, use the\n * {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher} and the\n * {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber} interfaces to give applications the capabilities\n * to publish and receive messages.\n *\n * The implementor must register itself as a CloudEndpoint OSGi service provider.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.0\n */\n@ProviderType\npublic interface CloudEndpoint {\n\n    /**\n     * Publishes the received {@link KuraMessage} to the associated cloud platform and returns, if supported, a String\n     * representing a message ID.\n     * {@code null} is returned if the cloud endpoint will not confirm the message delivery, either because this is not\n     * supported by the underlying protocol or because the cloud endpoint itself is not implemented or configured to\n     * request the confirmation.\n     *\n     * @param message\n     *            the {@link KuraMessage} to be published\n     * @return a String representing the message ID or {@code null} if not supported\n     * @throws KuraException\n     *             if the publishing operation fails.\n     */\n    public String publish(KuraMessage message) throws KuraException;\n\n    /**\n     * Registers the provided {@link CloudSubscriberListener} using the specified {@code subscriptionProperties} that\n     * will allow\n     * to disambiguate the specific subscriptions.\n     *\n     * @param subscriptionProperties\n     *            a map representing the subscription context\n     * @param cloudSubscriberListener\n     *            a {@link CloudSubscriberListener} object that will be notified when a message is received in a context\n     *            that matches the one identified by the subscription properties.\n     */\n    public void registerSubscriber(Map<String, Object> subscriptionProperties,\n            CloudSubscriberListener cloudSubscriberListener);\n\n    /**\n     * Unregisters the provided {@code cloudSubscriberListener}.\n     *\n     * @param cloudSubscriberListener\n     *            the {@link CloudSubscriberListener} to be unregistered.\n     */\n    public void unregisterSubscriber(CloudSubscriberListener cloudSubscriberListener);\n\n    /**\n     * Provides information related to the associated connection. The information provided depends on the specific\n     * implementation and type of connection to the remote resource. The default implementation returns an empty\n     * map.\n     *\n     * @return a map that represents all the information related to the specific connection.\n     */\n    public default Map<String, String> getInfo() {\n        return Collections.emptyMap();\n    }\n\n    /**\n     * The implementation will register the {@link CloudDeliveryListener} instance passed as argument. Once a cloud\n     * connection related event happens, all the registered {@link CloudDeliveryListener}s will be notified.\n     *\n     * @param cloudDeliveryListener\n     *            a {@link CloudDeliveryListener} instance\n     */\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener);\n\n    /**\n     * Unregisters the provided {@link CloudDeliveryListener} instance from cloud connection related events\n     * notifications.\n     *\n     * @param cloudConnectionListener\n     */\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/factory/CloudConnectionFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.factory;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A {@link CloudConnectionFactory} is responsible to register {@link org.eclipse.kura.cloudconnection.CloudEndpoint}\n * instances in the framework.\n * The Component creates multiple component instances upon reception of a configuration\n * created through the Configuration Service.\n *\n * It provides all the implementations that can be used to connect to a specific Cloud platform.\n *\n * A {@link CloudConnectionFactory} must create a {@link org.eclipse.kura.cloudconnection.CloudEndpoint} and,\n * eventually, a {@link org.eclipse.kura.cloudconnection.CloudConnectionManager} that are used to establish and manage\n * the connection to a cloud platform, for example an Mqtt connection.\n *\n * Multiple {@link CloudConnectionFactory} services can be registered in the framework to support multiple simultaneous\n * connections to different Cloud platforms.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.0\n */\n@ProviderType\npublic interface CloudConnectionFactory {\n\n    /**\n     * The name of the property set in the instance configuration created\n     * through {@link #createConfiguration}.\n     * The property is set in the instance to relate it with the Factory that generated\n     * the whole cloud stack.\n     */\n    public static final String KURA_CLOUD_CONNECTION_FACTORY_PID = \"kura.cloud.connection.factory.pid\";\n\n    /**\n     * Returns the factory PID of the OSGi Factory Component represented by this {@link CloudConnectionFactory}.\n     *\n     * @return a String representing the factory PID of the Factory Component.\n     */\n    public String getFactoryPid();\n\n    /**\n     * This method creates a CloudEndpoint instance and, eventually, more service instances that are necessary to\n     * identify and the manage the endpoint and the connection. It initializes the configuration of the created services\n     * with the defaults expressed in the Metatype of the target component factories.\n     *\n     * The created Cloud Endpoint instance will have its {@code kura.service.pid} property\n     * set to the value provided in the {@code pid} parameter.\n     *\n     * @param pid\n     *            the Kura persistent identifier ({@code kura.service.pid}) of the Cloud Endpoint service\n     *            instance created by this factory.\n     * @throws KuraException\n     *             an exception is thrown in case the creation operation fails\n     */\n    public void createConfiguration(String pid) throws KuraException;\n\n    /**\n     * Returns the list of {@code kura.service.pid}s that compose the cloud connection associated with the provided\n     * {@code kura.service.pid}.\n     *\n     * @param pid\n     *            the Kura persistent identifier, {@code kura.service.pid}\n     * @return the {@link List} of {@code kura.service.pid}s related to the provided {@code pid}.\n     * @throws KuraException\n     *             if the specified {@code kura.service.pid} is incorrect.\n     */\n    public List<String> getStackComponentsPids(String pid) throws KuraException;\n\n    /**\n     * Deletes a previously created configuration deactivating the associated instances.\n     *\n     * @param pid\n     *            the Kura persistent identifier, {@code kura.service.pid} of a Cloud Endpoint\n     * @throws KuraException\n     *             if the provided {@code kura.service.pid} is incorrect or the delete operation fails.\n     */\n    public void deleteConfiguration(String pid) throws KuraException;\n\n    /**\n     * Returns a set of {@code kura.service.pid} that corresponds to the Cloud Endpoint services managed by this\n     * factory.\n     *\n     * @return the set of services or an empty set.\n     * @throws KuraException\n     */\n    public Set<String> getManagedCloudConnectionPids() throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/factory/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Contains interfaces to manage the construction of Cloud Connection Services.\n */\npackage org.eclipse.kura.cloudconnection.factory;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/listener/CloudConnectionListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.listener;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * The CloudConnectionListener interface is implemented by applications that want to be notified on connection\n * status changes.\n * To be notified, the implementor needs to register itself to a specific {@link org.eclipse.kura.cloudconnection.CloudConnectionManager}.\n *\n * @since 2.0\n */\n@ConsumerType\npublic interface CloudConnectionListener {\n\n    /**\n     * Notifies a clean disconnection from the cloud platform.\n     */\n    public void onDisconnected();\n\n    /**\n     * Called when the client has lost its connection to the cloud platform. This is only a notification, the callback\n     * handler\n     * should not attempt to handle the reconnect.\n     *\n     * If the bundle using the client relies on subscriptions beyond the default ones,\n     * it is responsibility of the application to implement the {@link CloudConnectionListener#onConnectionEstablished}\n     * callback method to restore the subscriptions it needs after a connection loss.\n     */\n    public void onConnectionLost();\n\n    /**\n     * Called when the cloud stack has successfully connected to the cloud platform.\n     *\n     * If the bundle using the client relies on subscriptions beyond the default ones,\n     * it is responsibility of the application to implement the {@link CloudConnectionListener#onConnectionEstablished}\n     * callback method to restore the subscriptions it needs after a connection loss.\n     */\n    public void onConnectionEstablished();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/listener/CloudDeliveryListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.listener;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Implementors of this interface will be able to handle cloud stack related\n * events that deal with message delivery.\n *\n * All the registered listeners are called synchronously at the occurrence of the event.\n * It is expected that implementors of this interface do NOT perform long running tasks in the implementation of this\n * interface.\n *\n * @since 2.0\n */\n@ConsumerType\npublic interface CloudDeliveryListener {\n\n    /**\n     * Confirms message delivery to the cloud platform.\n     *\n     * @param messageId\n     */\n    public void onMessageConfirmed(String messageId);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/listener/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides APIs to listen to cloud connection notifications, such as connection status changes and message delivery\n * confirmations.\n *\n */\npackage org.eclipse.kura.cloudconnection.listener;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/message/KuraMessage.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.message;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.message.KuraPayload;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The class KuraMessage represents a message that is shared between an application running in the framework and, for\n * example, a {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher} or\n * {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber}.\n * It is composed by a {@link KuraPayload} and properties that enrich the context of the message.\n * The content of the {@code properties} field is not fixed or mandatory and represent message-related options.\n * Depending on the application, the value in the {@code properties} field can be used or not.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.0\n */\n@ProviderType\npublic class KuraMessage {\n\n    private final Map<String, Object> properties;\n    private final KuraPayload payload;\n\n    public KuraMessage(KuraPayload payload) {\n        this.properties = new HashMap<>();\n        this.payload = payload;\n    }\n\n    public KuraMessage(KuraPayload payload, Map<String, Object> properties) {\n        this.properties = new HashMap<>(properties);\n        this.payload = payload;\n    }\n\n    public Map<String, Object> getProperties() {\n        return this.properties;\n    }\n\n    public KuraPayload getPayload() {\n        return this.payload;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/message/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Defines the recommended structure for the messages produced by an application that need to be sent to a remote cloud\n * platform.\n */\npackage org.eclipse.kura.cloudconnection.message;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides services for managing connections between the IoT framework and the remote servers.\n * The term Cloud Connection identifies a set of interfaces that allow to specify and manage the cloud endpoint\n * specified.\n * Using the provided interfaces, the user application is able to publish messages to the cloud platform without knowing\n * the low level specificities of the underneath protocols used to communicate with the cloud platform. Interfaces are\n * available also to register subscribers that will receive and process messages from the cloud platform to the end\n * device.\n *\n */\npackage org.eclipse.kura.cloudconnection;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/publisher/CloudNotificationPublisher.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.publisher;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface used to identify a Cloud Publisher dedicated to send notifications until completion of a long-lived\n * operation initially handled by a {@link org.eclipse.kura.cloudconnection.request.RequestHandler}.\n *\n * @since 2.0\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface CloudNotificationPublisher extends CloudPublisher {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/publisher/CloudPublisher.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.publisher;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The CloudPublisher interface is an abstraction on top of the {@link org.eclipse.kura.cloudconnection.CloudEndpoint}\n * to simplify the publishing process for each application running in the framework.\n * A CloudPublisher is used to publish the specified {@link KuraMessage} to a cloud platform.\n * The CloudPublisher and the associated CloudEndpoint implementations abstract, to the user applications, all the low\n * level specificities like the message destination address, quality of service or properties because those are added by\n * the {@link CloudPublisher} implementation based, for example, on a configuration.\n *\n * When an application wants to publish, it has to take a CloudPublisher instance and use the\n * {@link CloudPublisher#publish(KuraMessage)} method, passing as argument a KuraMessage.\n *\n * Every KuraMessage accepted by the CloudPublisher is associated to a string identifier that can be\n * used to confirm that the KuraMessage has been published.\n * However, the semantics of the confirmation depends on both the implementation and the configuration of the\n * connection.\n * For example, if the protocol of the cloud connection supports message identifiers and acknowledgments, the\n * implementation will map the message identifier to the KuraMessage identifier and confirm it when\n * the message identifier is acknowledged. If the protocol does not support message identifiers, or the message does not\n * request an acknowledge, a confirmed KuraMessage identifier may at most indicate that the message has been\n * successfully transmitted. There is no guarantee that a KuraMessage identifier will ever be confirmed. It is\n * important that the implementation of the CloudPublisher and its configuration match the assumptions of the\n * API consumer about the delivery.\n *\n * For example, if the correct behavior of an application requires guaranteed message delivery, the\n * application should be configured to use a reliable publisher. Of course, applications that do not require this will\n * work with any publisher.\n *\n * @since 2.0\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface CloudPublisher {\n\n    /**\n     * Publishes the received {@link KuraMessage} using the associated cloud connection.\n     *\n     * @param message\n     *            The {@link KuraMessage} to be published\n     * @return a String representing the message ID. {@code null} is returned if the cloud endpoint will not confirm the\n     *         message delivery, either because this is not supported by the underlying protocol or because the cloud\n     *         endpoint itself is not implemented or configured to request the confirmation. The message ID can be\n     *         confirmed when the message is delivered. See {@link CloudDeliveryListener}.\n     * @throws KuraException\n     *             if the publishing operation fails.\n     */\n    public String publish(KuraMessage message) throws KuraException;\n\n    /**\n     * The implementation will register the {@link CloudConnectionListener} instance passed as argument. Once a cloud\n     * connection related event happens, all the registered {@link CloudConnectionListener}s will be notified.\n     *\n     * @param cloudConnectionListener\n     *            a {@link CloudConnectionListener} instance\n     */\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n    /**\n     * Unregisters the provided {@link CloudConnectionListener} instance from cloud connection related events\n     * notifications.\n     *\n     * @param cloudConnectionListener\n     */\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n    /**\n     * The implementation will register the {@link CloudDeliveryListener} instance passed as argument. Once a cloud\n     * connection related event happens, all the registered {@link CloudDeliveryListener}s will be notified.\n     *\n     * @param cloudDeliveryListener\n     *            a {@link CloudDeliveryListener} instance\n     */\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener);\n\n    /**\n     * Unregisters the provided {@link CloudDeliveryListener} instance from cloud connection related events\n     * notifications.\n     *\n     * @param cloudConnectionListener\n     */\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/publisher/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides services for managing communications between local applications and remote servers.\n *\n */\npackage org.eclipse.kura.cloudconnection.publisher;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.request;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Implemented by services that want to implement remote resource management.\n *\n * <ul>\n * <li>{@link RequestHandler#doGet} is used to implement a READ request for a resource identified in the supplied\n * {@link KuraMessage)}</li>\n * <li>{@link RequestHandler#doPut} is used to implement a CREATE or UPDATE request for a resource identified in the\n * supplied {@link KuraMessage}</li>\n * <li>{@link RequestHandler#doDel} is used to implement a DELETE request for a resource identified in the supplied\n * {@link KuraMessage}</li>\n * <li>{@link RequestHandler#doPost} is used to implement other operations on a resource identified in the supplied\n * {@link KuraMessage}</li>\n * <li>{@link RequestHandler#doExec} is used to perform application operation not necessary tied to a given\n * resource.</li>\n * </ul>\n *\n * Every request is also associated to a {@link RequestHandlerContext} that specifies the request context and can be\n * used to send notification messages, keeping the link with the original cloud stack that started the interaction.\n *\n * @since 2.0\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ConsumerType\npublic interface RequestHandler {\n\n    /**\n     * Used to implement a READ request for a resource identified by the supplied {@link CloudletResources)}\n     *\n     * @param context\n     *            a request context that can be used, for example, to publish notification messages to the remote cloud\n     *            platform\n     * @param reqMessage\n     *            represents, as a {@link KuraMessage}, the received message\n     * @return the response to be provided back as {@link KuraMessage}\n     * @throws KuraException\n     *             An exception is thrown in every condition where the request cannot be full fitted due to wrong\n     *             request parameters or exceptions during processing\n     */\n    public default KuraMessage doGet(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, \"get\");\n    }\n\n    /**\n     * Used to implement a CREATE or UPDATE request for a resource identified by the supplied {@link CloudletResources)}\n     *\n     * @param context\n     *            a request context that can be used, for example, to publish notification messages to the remote cloud\n     *            platform\n     * @param reqMessage\n     *            represents as a {@link KuraMessage} the received message\n     * @return the response to be provided back as {@link KuraMessage}\n     * @throws KuraException\n     *             An exception is thrown in every condition where the request cannot be full fitted due to wrong\n     *             request parameters or exceptions during processing\n     */\n    public default KuraMessage doPut(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, \"put\");\n    }\n\n    /**\n     * Used to implement other operations on a resource identified by the supplied {@link CloudletResources)}\n     *\n     * @param context\n     *            a request context that can be used, for example, to publish notification messages to the remote cloud\n     *            platform\n     * @param reqMessage\n     *            represents as a {@link KuraMessage} the received message\n     * @return the response to be provided back as {@link KuraMessage}\n     * @throws KuraException\n     *             An exception is thrown in every condition where the request cannot be full fitted due to wrong\n     *             request parameters or exceptions during processing\n     */\n    public default KuraMessage doPost(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, \"post\");\n    }\n\n    /**\n     * Used to implement a DELETE request for a resource identified by the supplied {@link CloudletResources)}\n     *\n     * @param context\n     *            a request context that can be used, for example, to publish notification messages to the remote cloud\n     *            platform\n     * @param reqMessage\n     *            represents as a {@link KuraMessage} the received message\n     * @return the response to be provided back as {@link KuraMessage}\n     * @throws KuraException\n     *             An exception is thrown in every condition where the request cannot be full fitted due to wrong\n     *             request parameters or exceptions during processing\n     */\n    public default KuraMessage doDel(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, \"delete\");\n    }\n\n    /**\n     * Used to perform application operation not necessary tied to a given resource\n     *\n     * @param context\n     *            a request context that can be used, for example, to publish notification messages to the remote cloud\n     *            platform\n     * @param reqMessage\n     *            represents as a {@link KuraMessage} the received message\n     * @return the response to be provided back as {@link KuraMessage}\n     * @throws KuraException\n     *             An exception is thrown in every condition where the request cannot be full fitted due to wrong\n     *             request parameters or exceptions during processing\n     */\n    public default KuraMessage doExec(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, \"exec\");\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandlerContext.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.request;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * PoJo class used to wrap the context associated to a request received from the cloud and passed to a\n * {@link RequestHandler}.\n * It should be used, for example, to provide the context that will be leveraged by a {@link RequestHandler} to publish\n * event notifications to a remote cloud platform.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.0\n */\n@ProviderType\npublic class RequestHandlerContext {\n\n    private final CloudNotificationPublisher notificationPublisher;\n    private final Map<String, String> contextProperties;\n\n    public RequestHandlerContext(CloudNotificationPublisher notificationPublisher,\n            Map<String, String> contextProperties) {\n        this.notificationPublisher = notificationPublisher;\n        this.contextProperties = new HashMap<>(contextProperties);\n    }\n\n    public CloudNotificationPublisher getNotificationPublisher() {\n        return this.notificationPublisher;\n    }\n\n    public Map<String, String> getContextProperties() {\n        return Collections.unmodifiableMap(this.contextProperties);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandlerContextConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.request;\n\n/**\n * This class is an enumeration that wraps property keys used to defined a Context for a RequestHandler.\n *\n * @since 2.0\n */\npublic enum RequestHandlerContextConstants {\n\n    TENANT_ID,\n    DEVICE_ID,\n    NOTIFICATION_PUBLISHER_PID;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandlerMessageConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.request;\n\n/**\n * This class is an enumeration that wraps some of the possible property keys set in the properties of a\n * {@link org.eclipse.kura.cloudconnection.message.KuraMessage} used for request/response.\n *\n * @since 2.0\n */\npublic enum RequestHandlerMessageConstants {\n\n    /**\n     * Request arguments. The corresponding value must be a {@code List<String>}.\n     */\n    ARGS_KEY(\"args\");\n\n    private String value;\n\n    RequestHandlerMessageConstants(final String value) {\n        this.value = value;\n    }\n\n    public String value() {\n        return this.value;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandlerRegistry.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.request;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Interface used to register or unregister {@link RequestHandler}s identified by a specific id.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.0\n */\n@ProviderType\npublic interface RequestHandlerRegistry {\n\n    /**\n     * Registers a {@link RequestHandler} identified by the specified {@code id}. Once registered, the\n     * {@link RequestHandler} instance can be notified for request messages targeting the registered {@code id}\n     *\n     * @param id\n     *            a String identifying a specific {@link RequestHandler}\n     * @param requestHandler\n     *            a {@link RequestHandler} instance identified by the specified {@code id}\n     * @throws KuraException\n     */\n    public void registerRequestHandler(String id, RequestHandler requestHandler) throws KuraException;\n\n    /**\n     * Unregisters the {@link RequestHandler} identified by the specified {@code id}. From that moment on, no\n     * notifications will be sent to the unregistered {@RequestHandler}\n     *\n     * @param id\n     *            a String identifying a specific {@link RequestHandler}\n     * @throws KuraException\n     */\n    public void unregister(String id) throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides services for managing requests and response between the gateway and the remote cloud platform.\n *\n */\npackage org.eclipse.kura.cloudconnection.request;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/subscriber/CloudSubscriber.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.subscriber;\n\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Interface intended to have a specific implementation associated to a\n * {@link org.eclipse.kura.cloudconnection.CloudEndpoint} that wraps the\n * specificities related to the targeted cloud provider.\n *\n * The {@link CloudSubscriber} interface is an abstraction on top of the\n * {@link org.eclipse.kura.cloudconnection.CloudEndpoint} to simplify the\n * subscription and notification process, for each application running in the framework.\n *\n * When an application wants to receive a message from the cloud, it has to take a {@link CloudSubscriber} instance and\n * register itself as a {@link CloudSubscriberListener}, in order to be notified when a message is received from the\n * associated cloud stack.\n *\n * In most cases, the consumers are not interested in the header of the received message and assume to always receive\n * the\n * same kind of message. In order to receive different kinds of messages, the consumer should register to multiple\n * subscribers.\n *\n * Some messaging protocols have a hierarchical addressing structure supporting multilevel wildcard subscriptions. For\n * example, an MQTT address (topic) hierarchy might look like\n * building/${building-number}/apartment/${apartment-number}/heating/temperature.\n * To receive the heating temperature measurements for all the buildings and apartments the subscriber can be configured\n * to subscribe to building/+/apartment/+/heating/temperature. When a message is received, the subscriber will notify\n * the application providing the payload received and some properties that are implementation specific, depending on the\n * subscriber, and that can allow the application to understand the corresponding resource.\n *\n * @since 2.0\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface CloudSubscriber {\n\n    /**\n     * Registers the {@link CloudSubscriberListener} instance passed as an argument. All the registered\n     * {@link CloudSubscriberListener}s will be notified by the implementation when a message is received.\n     *\n     * @param listener\n     *            a {@link CloudSubscriberListener} instance that will be notified when a message will be received from\n     *            the remote cloud platform.\n     */\n    public void registerCloudSubscriberListener(CloudSubscriberListener listener);\n\n    /**\n     * Unregisters the provided {@link CloudSubscriberListener} from the list of the notified listeners.\n     *\n     * @param listener\n     */\n    public void unregisterCloudSubscriberListener(CloudSubscriberListener listener);\n\n    /**\n     * The implementation will register the {@link CloudConnectionListener} instance passed as argument. Once a cloud\n     * connection related event happens, all the registered {@link CloudConnectionListener}s will be notified.\n     *\n     * @param cloudConnectionListener\n     *            a {@link CloudConnectionListener} instance\n     */\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n    /**\n     * Unregisters the provided {@link CloudConnectionListener} instance from cloud connection related events\n     * notifications.\n     *\n     * @param cloudConnectionListener\n     */\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/subscriber/listener/CloudSubscriberListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.subscriber.listener;\n\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * The {@link CloudSubscriberListener} interface has to be implemented by applications that needs to be notified of\n * events in the subscriber.\n * Notification methods are invoked whenever a message is received in the associated\n * {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber}.\n *\n * @since 2.0\n */\n@ConsumerType\n@FunctionalInterface\npublic interface CloudSubscriberListener {\n\n    /**\n     * Called by the {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber} when a message is received from\n     * the remote cloud platform.\n     * The received message will be parsed and passed as a {@link KuraMessage} to the listener.\n     *\n     * @param message\n     *            The {@link KuraMessage} that wraps the received message.\n     */\n    public void onMessageArrived(KuraMessage message);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/subscriber/listener/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides apis that allow to register subscriber applications.\n *\n */\npackage org.eclipse.kura.cloudconnection.subscriber.listener;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/subscriber/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides services for subscribing to remote servers and allows to invoke local applications.\n *\n */\npackage org.eclipse.kura.cloudconnection.subscriber;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/comm/CommConnection.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.comm;\n\nimport java.io.IOException;\n\nimport javax.microedition.io.StreamConnection;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This is the primary control class for a Serial port. An instance of\n * this class may be operated on by more than one thread. Settings will be\n * those of the last thread to successfully change each particular setting.\n * <p>\n * Code written to use a javax.comm.SerialPort object in a shared mode should\n * make use of synchronization blocks where exclusive transactions are wanted.\n * In most instances, both the OutputStream and the InputStream should be\n * synchronized on, normally with the OutputStream being synchronized first.\n *\n * <pre>\n * Example Code:\n *         try {\n *            String uri = new CommURI.Builder(\"/dev/tty.PL2303-00001004\")\n *                                        .withBaudRate(19200)\n *                                        .withDataBits(8)\n *                                        .withStopBits(1)\n *                                        .withParity(0)\n *                                        .withTimeout(2000)\n *                                        .build().toString();\n *            CommConnection connOne = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);\n *            assertNotNull(connOne);\n *            uri = new CommURI.Builder(\"/dev/tty.PL2303-00002006\")\n *                                        .withBaudRate(19200)\n *                                        .withDataBits(8)\n *                                        .withStopBits(1)\n *                                        .withParity(0)\n *                                        .withTimeout(2000)\n *                                        .build().toString();\n *            CommConnection connTwo = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);\n *            assertNotNull(connTwo);\n *\n *            InputStream isOne = connOne.openInputStream();\n *            OutputStream osOne = connOne.openOutputStream();\n *            InputStream isTwo = connTwo.openInputStream();\n *            OutputStream osTwo = connTwo.openOutputStream();\n *\n *            assertNotNull(isOne);\n *            assertNotNull(osOne);\n *            assertNotNull(isTwo);\n *            assertNotNull(osTwo);\n *\n *            //write from one to two\n *            byte[] array = \"this is a message from one to two\\n\".getBytes();\n *            osOne.write(array);\n *            StringBuffer sb = new StringBuffer();\n *            int c;\n *            while((c = isTwo.read()) != 0xa) {\n *                sb.append((char)c);\n *            }\n *            System.out.println(\"Port 2: Read from serial port two: \" + sb.toString());\n *\n *            array = \"this is a message from two to one\\n\".getBytes();\n *            osTwo.write(array);\n *            sb = new StringBuffer();\n *            while((c = isOne.read()) != 0xa) {\n *                sb.append((char)c);\n *            }\n *            System.out.println(\"Port 1: Read from serial port: \" + sb.toString());\n *\n *            isOne.close();\n *            osOne.close();\n *            isOne = null;\n *             osOne = null;\n *            isTwo.close();\n *            osTwo.close();\n *            isTwo = null;\n *            osTwo = null;\n *            connOne.close();\n *            connOne = null;\n *            connTwo.close();\n *            connTwo = null;\n *        } catch (Exception e) {\n *            e.printStackTrace();\n *        }\n * </pre>\n *\n * Note: avoid blocking read (InputStream.read()) if the InputStream can be closed on a different thread,\n * in this case, the read will never exit and the thread will be blocked forever.\n *\n * It is preferable to test InputStream.available before InputStream.read():\n *\n * <pre>\n *        if (isOne.available() != 0) {\n *            c = isOne.read();\n *        } else {\n *        try {\n *            Thread.sleep(100);\n *            continue;\n *        } catch (InterruptedException e) {\n *            return;\n *        }\n * </pre>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface CommConnection extends StreamConnection {\n\n    /**\n     * Returns the URI for this connection.\n     *\n     * @return this connection URI\n     */\n    public CommURI getURI();\n\n    /**\n     * Sends and array of bytes to a CommConnection\n     *\n     * @param message\n     *            the array of bytes to send to the CommConnection\n     * @throws KuraException\n     * @throws IOException\n     */\n    public void sendMessage(byte[] message) throws KuraException, IOException;\n\n    /**\n     * Sends and array of bytes to a CommConnection and returns an array of bytes\n     * that represents the 'response' to the command. If the timeout is exceeded\n     * before any bytes are read on the InputStream null is returned. This is\n     * meant to be used in common command/response type situations when communicating\n     * with serial devices\n     *\n     * @param command\n     *            the array of bytes to send to the CommConnection\n     * @param timeout\n     *            the maximum length of time to wait before returning a null\n     *            response in the event no response is ever returned.\n     * @return an array of bytes representing the response\n     * @throws KuraException\n     * @throws IOException\n     */\n    public byte[] sendCommand(byte[] command, int timeout) throws KuraException, IOException;\n\n    public byte[] sendCommand(byte[] command, int timeout, int demark) throws KuraException, IOException;\n\n    /**\n     * Reads all bytes that are waiting in the serial port buffer and returns them in\n     * an array. This can be used to read unsolicited messages from an attached\n     * serial device.\n     *\n     * @return the array of bytes buffered on the InputStream if any\n     * @throws KuraException\n     * @throws IOException\n     */\n    public byte[] flushSerialBuffer() throws KuraException, IOException;\n\n    @Override\n    public void close() throws IOException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/comm/CommURI.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.comm;\n\nimport java.net.URISyntaxException;\n\nimport javax.comm.SerialPort;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a Uniform Resource Identifier (URI) for a Comm/Serial Port.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class CommURI {\n\n    public static final int DATABITS_5 = SerialPort.DATABITS_5;\n    public static final int DATABITS_6 = SerialPort.DATABITS_6;\n    public static final int DATABITS_7 = SerialPort.DATABITS_7;\n    public static final int DATABITS_8 = SerialPort.DATABITS_8;\n\n    public static final int PARITY_EVEN = SerialPort.PARITY_EVEN;\n    public static final int PARITY_MARK = SerialPort.PARITY_MARK;\n    public static final int PARITY_NONE = SerialPort.PARITY_NONE;\n    public static final int PARITY_ODD = SerialPort.PARITY_ODD;\n    public static final int PARITY_SPACE = SerialPort.PARITY_SPACE;\n\n    public static final int STOPBITS_1 = SerialPort.STOPBITS_1;\n    public static final int STOPBITS_1_5 = SerialPort.STOPBITS_1_5;\n    public static final int STOPBITS_2 = SerialPort.STOPBITS_2;\n\n    public static final int FLOWCONTROL_NONE = SerialPort.FLOWCONTROL_NONE;\n    public static final int FLOWCONTROL_RTSCTS_IN = SerialPort.FLOWCONTROL_RTSCTS_IN;\n    public static final int FLOWCONTROL_RTSCTS_OUT = SerialPort.FLOWCONTROL_RTSCTS_OUT;\n    public static final int FLOWCONTROL_XONXOFF_IN = SerialPort.FLOWCONTROL_XONXOFF_IN;\n    public static final int FLOWCONTROL_XONXOFF_OUT = SerialPort.FLOWCONTROL_XONXOFF_OUT;\n\n    private final String port;\n    private final int baudRate;\n    private final int dataBits;\n    private final int stopBits;\n    private final int parity;\n    private final int flowControl;\n    private final int openTimeout;\n    private final int receiveTimeout;\n\n    /**\n     * Constructor to build the CommURI\n     *\n     * @param builder\n     *            the builder that contains the comm port parameters\n     */\n    private CommURI(Builder builder) {\n        this.port = builder.builderPort;\n        this.baudRate = builder.builderBaudRate;\n        this.dataBits = builder.builderDdataBits;\n        this.stopBits = builder.builderStopBits;\n        this.parity = builder.builderParity;\n        this.flowControl = builder.builderFlowControl;\n        this.openTimeout = builder.builderOpenTimeout;\n        this.receiveTimeout = builder.builderReceiveTimeout;\n    }\n\n    /**\n     * The COM port or device node associated with this port\n     *\n     * @return a {@link String } representing the port\n     */\n    public String getPort() {\n        return this.port;\n    }\n\n    /**\n     * The baud rate associated with the port\n     *\n     * @return an int representing the baud rate\n     */\n    public int getBaudRate() {\n        return this.baudRate;\n    }\n\n    /**\n     * The number of data bits associated with the port\n     *\n     * @return an int representing the number of data bits\n     */\n    public int getDataBits() {\n        return this.dataBits;\n    }\n\n    /**\n     * The number of stop bits associated with the port\n     *\n     * @return an int representing the number of stop bits\n     */\n    public int getStopBits() {\n        return this.stopBits;\n    }\n\n    /**\n     * The parity associated with the port\n     *\n     * @return an int representing the parity\n     */\n    public int getParity() {\n        return this.parity;\n    }\n\n    /**\n     * The flow control associated with the port\n     *\n     * @return an int representing the flow control\n     */\n    public int getFlowControl() {\n        return this.flowControl;\n    }\n\n    /**\n     * The open timeout associated with the port, this method is identical to {@link #getOpenTimeout()}\n     *\n     * @deprecated Use {@link #getOpenTimeout()} and {@link #getReceiveTimeout()} instead\n     * @since 1.1.0\n     * @return an int representing the open timeout in milliseconds\n     */\n    @Deprecated\n    public int getTimeout() {\n        return this.openTimeout;\n    }\n\n    /**\n     * The open timeout associated with the port\n     *\n     * @return an int representing the open timeout in milliseconds\n     * @since 1.2\n     */\n    public int getOpenTimeout() {\n        return this.openTimeout;\n    }\n\n    /**\n     * The receive timeout associated with the port\n     *\n     * @return an int representing the receive timeout in milliseconds\n     * @since 1.2\n     */\n    public int getReceiveTimeout() {\n        return this.receiveTimeout;\n    }\n\n    /**\n     * The {@link String } representing the CommURI\n     */\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"comm:\").append(this.port).append(\";baudrate=\").append(this.baudRate).append(\";databits=\")\n                .append(this.dataBits).append(\";stopbits=\").append(this.stopBits).append(\";parity=\")\n                .append(this.parity).append(\";flowcontrol=\").append(this.flowControl).append(\";timeout=\")\n                .append(this.openTimeout).append(\";receivetimeout=\").append(this.receiveTimeout);\n        return sb.toString();\n    }\n\n    /**\n     * Converts a String of the CommURI form to a CommURI Object\n     *\n     * @param uri\n     *            the {@link String } representing the CommURI\n     * @return a CommURI Object based on the uri String\n     * @throws URISyntaxException\n     */\n    public static CommURI parseString(String uri) throws URISyntaxException {\n        if (!uri.startsWith(\"comm:\")) {\n            throw new URISyntaxException(uri, \"Does not start with comm:\");\n        }\n\n        // get port\n        int idx = uri.indexOf(\";\") == -1 ? uri.length() : uri.indexOf(\";\");\n        String port = uri.substring(5, idx);\n        Builder builder = new Builder(port);\n\n        // get params\n        if (idx != uri.length()) {\n\n            String[] params = uri.substring(idx).split(\";\");\n            for (String param : params) {\n\n                int i = param.indexOf(\"=\");\n                if (i != -1) {\n                    String name = param.substring(0, i);\n                    String value = param.substring(i + 1);\n                    if (\"baudrate\".equals(name)) {\n                        builder = builder.withBaudRate(Integer.parseInt(value));\n                    } else if (\"databits\".equals(name)) {\n                        builder = builder.withDataBits(Integer.parseInt(value));\n                    } else if (\"stopbits\".equals(name)) {\n                        builder = builder.withStopBits(Integer.parseInt(value));\n                    } else if (\"parity\".equals(name)) {\n                        builder = builder.withParity(Integer.parseInt(value));\n                    } else if (\"flowcontrol\".equals(name)) {\n                        builder = builder.withFlowControl(Integer.parseInt(value));\n                    } else if (\"timeout\".equals(name)) {\n                        builder = builder.withOpenTimeout(Integer.parseInt(value));\n                    } else if (\"receivetimeout\".equals(name)) {\n                        builder = builder.withReceiveTimeout(Integer.parseInt(value));\n                    }\n                }\n            }\n        }\n        return builder.build();\n    }\n\n    /**\n     * Builder class used as a helper in building the components of a CommURI.\n     *\n     * @noextend This class is not intended to be subclassed by clients.\n     */\n    @ProviderType\n    public static class Builder {\n\n        private final String builderPort;\n        private int builderBaudRate = 19200;\n        private int builderDdataBits = 8;\n        private int builderStopBits = 1;\n        private int builderParity = 0;\n        private int builderFlowControl = 0;\n        private int builderOpenTimeout = 2000;\n        private int builderReceiveTimeout = 0;\n\n        public Builder(String port) {\n            this.builderPort = port;\n        }\n\n        public Builder withBaudRate(int baudRate) {\n            this.builderBaudRate = baudRate;\n            return this;\n        }\n\n        public Builder withDataBits(int dataBits) {\n            this.builderDdataBits = dataBits;\n            return this;\n        }\n\n        public Builder withStopBits(int stopBits) {\n            this.builderStopBits = stopBits;\n            return this;\n        }\n\n        public Builder withParity(int parity) {\n            this.builderParity = parity;\n            return this;\n        }\n\n        public Builder withFlowControl(int flowControl) {\n            this.builderFlowControl = flowControl;\n            return this;\n        }\n\n        /**\n         * Sets the open timeout associated with the port, this method is identical to {@link #withOpenTimeout(int)}\n         *\n         * @deprecated use {@link #withOpenTimeout(int)} and {@link #withReceiveTimeout(int)} instead\n         * @since 1.1.0\n         * @param timeout\n         *            The open timeout in milliseconds.\n         * @return\n         */\n        @Deprecated\n        public Builder withTimeout(int timeout) {\n            return withOpenTimeout(timeout);\n        }\n\n        /**\n         * Sets the open timeout associated with the port\n         *\n         * @param timeout\n         *            The open timeout in milliseconds.\n         * @return\n         * @since 1.2\n         */\n        public Builder withOpenTimeout(int timeout) {\n            this.builderOpenTimeout = timeout;\n            return this;\n        }\n\n        /**\n         * Sets the receive timeout associated with the port. Pass 0 to disable the receive timeout. The receive timeout\n         * is disabled by default.\n         *\n         * @param timeout\n         *            The receive timeout in milliseconds.\n         * @return\n         * @since 1.2\n         */\n        public Builder withReceiveTimeout(int timeout) {\n            this.builderReceiveTimeout = timeout;\n            return this;\n        }\n\n        public CommURI build() {\n            return new CommURI(this);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/comm/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides services for managing a connection with a serial port.\n *\n */\npackage org.eclipse.kura.comm;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/command/CommandService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.command;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface provides methods for running system commands from the web console.\n *\n * @deprecated use {@link org.eclipse.kura.executor.CommandExecutorService}\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\n@Deprecated\npublic interface CommandService {\n\n    @Deprecated\n    public String execute(String cmd) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/command/PasswordCommandService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.command;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraRequestPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface provides methods for running system commands from the web console.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface PasswordCommandService {\n\n    /**\n     * Password protected command execution service\n     *\n     * @param cmd\n     *            Command to be executed\n     * @param password\n     *            Password as specified in the CommandService\n     * @return String output as returned by the command\n     * @throws KuraException\n     *             raised if the command service is disabled, if the password is not correct\n     *             or if an internal error occurs\n     */\n    public String execute(String cmd, String password) throws KuraException;\n\n    /**\n     * Password protected command execution service\n     *\n     * @param commandReq\n     *            Payload containing command information\n     * @return KuraResponsePayload containing the result of the command execution and details on the result\n     * @deprecated\n     */\n    @Deprecated\n    public default KuraResponsePayload execute(KuraRequestPayload commandReq) {\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Password protected command execution service\n     *\n     * @param commandReq\n     *            Payload containing command information\n     * @return KuraResponsePayload containing the result of the command execution and details on the result\n     * @throws KuraException\n     *             raised if the command execution fails\n     * @since 2.0\n     */\n    public KuraPayload execute(KuraPayload commandReq) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/command/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Contains interface to execute shell commands.\n *\n */\npackage org.eclipse.kura.command;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/ComponentConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.configuration;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The ComponentConfiguration groups all the information related to the Configuration of a Component.\n * It provides access to parsed ObjectClassDefintion associated to this Component.\n * ComponentConfiguration does not reuse the OSGi ObjectClassDefinition as the latter\n * does not provide access to certain aspects such as the required attribute,\n * the min and max values. Instead it returns the raw ObjectClassDefintion as parsed\n * from the MetaType Information XML resource associated to this Component.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface ComponentConfiguration {\n\n    /**\n     * Returns the PID (service's persistent identity) of the component\n     * associated to this Configuration.\n     * For a component created via {@link ConfigurationService#createFactoryConfiguration(String, String, Map, boolean)}\n     * ,\n     * the service's persistent identity is the value of the second parameter of that method;\n     * at runtime, the same value is also available in the {@link ConfigurationService#KURA_SERVICE_PID}\n     * property of one of the configurations of the associated Factory Component.\n     * Otherwise, the service's persistent identity is defined as the name attribute of the\n     * Component Descriptor XML file; at runtime, the same value is also available\n     * in the component.name and in the service.pid properties of the Component Configuration.\n     * If not already specified by the component, the Configuration Service will automatically\n     * set the {@link ConfigurationService#KURA_SERVICE_PID} to the value of service.pid when\n     * the component is first updated.\n     *\n     * @return PID of the component associated to this Configuration.\n     */\n    public String getPid();\n\n    /**\n     * Returns the raw ObjectClassDefinition as parsed from the MetaType\n     * Information XML resource associated to this Component.\n     *\n     * @return\n     */\n    public OCD getDefinition();\n\n    /**\n     * Returns the Dictionary of properties currently used by this component.\n     *\n     * @return the Component's Configuration properties.\n     */\n    public Map<String, Object> getConfigurationProperties();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/ConfigurableComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.configuration;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Marker interface for all Service Component that wants to expose the Configuration through the ConfigurationService.\n * The Configuration Service tracks all OSGi Components which implement the {@link ConfigurableComponent} marker\n * interface.\n * <br>\n * <br>\n * <b>Important:</b> For a component implementing this interface to be properly tracked by the Configuration Service,\n * the component must be declared with {@code configurationPolicy = ConfigurationPolicy.REQUIRED} in its\n * OSGi Declarative Services annotation (or equivalent XML descriptor). Components with\n * {@code ConfigurationPolicy.OPTIONAL} will not be tracked because they may become active before receiving\n * a Configuration, and without a service.pid property, the Configuration Service cannot manage them.\n * <br>\n * <br>\n * When a ConfigurableComponent is registered, the Configuration Service will call its \"update\"\n * method with the latest saved configuration as returned the ConfigurationAdmin or, if none\n * is available, with the Configuration properties fabricated from the default attribute values as\n * specified in the ObjectClassDefinition of this service.\n * In OSGi terms, this process in similar to the Auto Configuration Service.\n * <b>The ConfigurationService assumes that Meta Type Information XML resource\n * for a given ConfigurableComponent with name abc\" to be stored under OSGI-INF/metatype/abc.xml.</b>\n * This is an extra restriction over the OSGi specification: the Meta Type Information XML resource\n * must be named as the name of the Declarative Service Component.\n * <br>\n */\n@ConsumerType\npublic interface ConfigurableComponent {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/ConfigurationService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.configuration;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.framework.Filter;\n\n/**\n * The Configuration Service is used to manage the configuration of OSGi Declarative Services\n * implementing the {@link ConfigurableComponent} or the {@link SelfConfiguringComponent}\n * interface.\n * It works in concert with the OSGi Configuration Admin and the OSGi Meta Type services.\n * What it provides over the native OSGi services is the ability to easily access the current\n * configuration of a Configurable Component or a SelfConfiguring Component together with\n * their full Meta Type Object Class Definition,\n * the ability to take snapshots of the current configuration of all managed\n * services or rollback to older snapshots and, finally, the ability to access\n * and manage configurations remotely through the Cloud Service.\n * <br>\n * <br>\n * The Configuration Service operates on a subset of all the services registered\n * under the OSGi container.\n * It tracks only OSGi services which implement the ConfigurableComponent\n * or the SelfConfiguringComponent interface.\n * <br>\n * <b>Important:</b> For a component implementing {@link ConfigurableComponent} to be properly tracked by the\n * Configuration Service, the component must be declared with\n * {@code configurationPolicy = ConfigurationPolicy.REQUIRED} in its OSGi Declarative Services annotation\n * (or equivalent XML descriptor). Components with {@code ConfigurationPolicy.OPTIONAL} will not be tracked\n * because they may become active before receiving a Configuration, and without a service.pid property,\n * the Configuration Service cannot manage them.\n * Instead, components implementing {@link SelfConfiguringComponent} need to have\n * {@code configurationPolicy = ConfigurationPolicy.OPTIONAL} unless a configuration for them is seeded\n * in snapshot_0.\n * <br>\n * More explicitly it does not manage the following services of the OSGi specification:\n * <ul>\n * <li>Managed Service\n * <li>Managed Service Factory\n * <li>Component Factory of the Declarative Service specification\n * </ul>\n * When a ConfigurableComponent or a SelfConfiguringComponent is tracked,\n * the Configuration Service will update its Configuration,\n * as returned by the Configuration Admin, with properties fabricated\n * from the default attribute values specified in its Meta Type Object Class Definition.\n * <br>\n * The configuration properties will be passed in the <i>activate</i> or <i>update</i> methods\n * of the Component definition.\n * <br>\n * In OSGi terms, this process in similar to the Auto Configuration Service.\n * <br>\n * <br>\n * The Configuration Service assumes the Meta Type Information XML resource\n * for a given Declarative Service with name \"abc\" to be stored under OSGI-INF/metatype/abc.xml.\n * <br>\n * This is an extra restriction over the OSGi specification:\n * the Meta Type Information XML resource\n * must be named as the name of the Declarative Service Component.\n * <br>\n * <br>\n * The Configuration Service has the ability to create a snapshot for the current configuration\n * of all the tracked components. The snapshot is saved in the form of an\n * XML file stored under $kura.snapshots/snapshot_epoch.xml where epoch is replaced\n * with the epoch timestamp at the time of the snapshot creation.\n * The Configuration Service also has the ability to rollback the configuration of\n * tracked components taking them back to a previous stored snapshot.\n * <br>\n * <br>\n * The Configuration Service also allows creation of new ConfigurableComponents instances\n * through OSGi Declarative Services by creating a new component Configuration via the OSGi Configuration Admin.\n * The approach is <a href=\n * \"http://www.jeremias-maerki.ch/wordpress/de/2010/04/22/osgi-ds-configuring-multiple-instances-of-a-component/\">using\n * OSGi Declative Services to configure multiple instances of a component</a>.\n * <br>\n * <br>\n * In order to manage the configuration of multiple component instances from the same configuration factory,\n * Kura relies on the following configuration properties:\n * <ul>\n * <li><b>service.factoryPid</b> is set by the Configuration Admin when the component configuration is first created.\n * Its value has to match the name of the targeted Declarative Service Component\n * <li><b>kura.service.pid</b> is the persistent identity assigned by Kura when the component configuration\n * is first created calling {@link #createFactoryConfiguration(String, String, Map, boolean)}.\n * </ul>\n * Both properties are stored in snapshots to recreate the component instances and restore their configuration\n * at every framework restart.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface ConfigurationService {\n\n    /**\n     * The name of the the Kura persistent identity property.\n     *\n     * @since 1.0.8\n     */\n    public static final String KURA_SERVICE_PID = \"kura.service.pid\";\n\n    /**\n     * Returns the list of Meta Type factory PIDs tracked by the Configuration Service.\n     *\n     * @return the list of Meta Type factory PIDs.\n     *\n     * @since 1.0.8\n     */\n    public Set<String> getFactoryComponentPids();\n\n    /**\n     * Creates a new ConfigurableComponent instance by creating a new configuration from a\n     * Configuration Admin factory.\n     * The Configuration Service will use the Configuration Admin\n     * to create the component configuration and will update the component configuration with the provided optional\n     * properties.\n     *\n     * @param factoryPid\n     *            the ID of the factory.\n     * @param pid\n     *            the value of the {@link ConfigurationService#KURA_SERVICE_PID}\n     *            that will be set in the component configuration properties.\n     * @param properties\n     *            an optional map of properties describing the component configuration.\n     *            The Configuration Service will first create an initial map of properties\n     *            with the property {@link ConfigurationService#KURA_SERVICE_PID}\n     *            set to the provided <i>pid</i> parameter and\n     *            with the default component configuration from its OSGi Meta Type.\n     *            If <i>properties</i> is not null, the Configuration Service will first remove\n     *            {@link ConfigurationService#KURA_SERVICE_PID}\n     *            from the provided properties and then it will merge them with the initial map.\n     * @param takeSnapshot\n     *            if set to true a snapshot will be taken.\n     * @throws KuraException\n     *             if pid is null, it already exists or creation fails.\n     *\n     * @since 1.0.8\n     */\n    public void createFactoryConfiguration(String factoryPid, String pid, Map<String, Object> properties,\n            boolean takeSnapshot) throws KuraException;\n\n    /**\n     * Deletes the ConfigurableComponent instance having the specified PID.\n     * Removes the component configuration and takes a new snapshot.\n     *\n     * @param pid\n     *            the PID of the component instance to delete.\n     * @param takeSnapshot\n     *            if set to true a snapshot will be taken.\n     * @throws KuraException\n     *             if the PID is not found or if the component instance was not created\n     *             via {@link #createFactoryConfiguration(String, String, Map, boolean)}.\n     *\n     * @since 1.0.8\n     */\n    public void deleteFactoryConfiguration(String pid, boolean takeSnapshot) throws KuraException;\n\n    /**\n     * Return the PIDs for all the services that\n     * implements the ConfigurableComponent Maker interface and registered themselves\n     * with the container.\n     *\n     * @return list of PIDs for registered ConfigurableComponents\n     */\n    public Set<String> getConfigurableComponentPids();\n\n    /**\n     * Returns the list of ConfigurableComponents currently registered with the ConfigurationService.\n     *\n     * @return list of registered ConfigurableComponents\n     */\n    public List<ComponentConfiguration> getComponentConfigurations() throws KuraException;\n\n    /**\n     * Returns the list of ConfigurableComponents currently registered with the ConfigurationService that match the\n     * provided OSGi filter.\n     *\n     * @param filter\n     *            the filter to be applied\n     * @return list of registered ConfigurableComponents\n     *\n     * @since 2.1\n     */\n    public List<ComponentConfiguration> getComponentConfigurations(Filter filter) throws KuraException;\n\n    /**\n     * Returns the ComponentConfiguration for the component identified with specified PID.\n     *\n     * @param pid\n     *            The ID of the component whose configuration is requested.\n     * @return ComponentConfiguration of the requested Component.\n     */\n    public ComponentConfiguration getComponentConfiguration(String pid) throws KuraException;\n\n    /**\n     * Returns the default ComponentConfiguration\n     * for the component having the specified PID.\n     *\n     * @param pid\n     *            The ID of the component whose configuration is requested.\n     * @return the ComponentConfiguration of the requested Component.\n     * @throws KuraException\n     *\n     * @since 1.0.8\n     */\n    public ComponentConfiguration getDefaultComponentConfiguration(String pid) throws KuraException;\n\n    /**\n     * Updates the Configuration of the registered component with the specified PID.\n     * Using the OSGi ConfigurationAdmin, it retrieves the Configuration of the\n     * component with the specified PID and then sends an update using the\n     * specified properties.\n     * <br>\n     * If the component to be updated is not yet registered with the ConfigurationService,\n     * it is first registered and then it is updated with the specified properties.\n     * Before updating the component, the specified properties are validated against\n     * the ObjectClassDefinition associated to the Component. The Configuration Service\n     * is fully compliant with the OSGi MetaType Information and the validation happens\n     * through the OSGi MetaType Service.\n     * <br>\n     * The Configuration Service is compliant with the OSGi MetaType Service so\n     * it accepts all attribute types defined in the OSGi Compendium Specifications.\n     * <br>\n     *\n     * @param pid\n     *            The PID of the component whose configuration is requested.\n     * @param properties\n     *            Properties to be used as the new Configuration for the specified Component.\n     * @throws KuraException\n     *             if the properties specified do not pass the validation of the ObjectClassDefinition\n     */\n    public void updateConfiguration(String pid, Map<String, Object> properties) throws KuraException;\n\n    /**\n     * Updates the Configuration of the registered component with the specified pid.\n     * Using the OSGi ConfigurationAdmin, it retrieves the Configuration of the\n     * component with the specified PID and then send an update using the\n     * specified properties.\n     * <br>\n     * If the component to be updated is not yet registered with the ConfigurationService,\n     * it is first registered and then it is updated with the specified properties.\n     * Before updating the component, the specified properties are validated against\n     * the ObjectClassDefinition associated to the Component. The Configuration Service\n     * is fully compliant with the OSGi MetaType Information and the validation happens\n     * through the OSGi MetaType Service.\n     * <br>\n     * The Configuration Service is compliant with the OSGi MetaType Service so\n     * it accepts all attribute types defined in the OSGi Compendium Specifications.\n     * <br>\n     *\n     * @param pid\n     *            The PID of the component whose configuration is requested.\n     * @param properties\n     *            Properties to be used as the new Configuration for the specified Component.\n     * @param takeSnapshot\n     *            defines whether or not this configuration update should trigger a snapshot.\n     * @throws KuraException\n     *             if the properties specified do not pass the validation of the ObjectClassDefinition.\n     *\n     * @since 1.0.8\n     */\n    public void updateConfiguration(String pid, Map<String, Object> properties, boolean takeSnapshot)\n            throws KuraException;\n\n    /**\n     * Updates the Configuration of the registered components.\n     * Using the OSGi ConfigurationAdmin, it retrieves the Configuration of the\n     * component with the specified PID and then send an update using the\n     * specified properties.\n     * <br>\n     * If the component to be updated is not yet registered with the ConfigurationService,\n     * it is first registered and then it is updated with the specified properties.\n     * Before updating the component, the specified properties are validated against\n     * the ObjectClassDefinition associated to the Component. The Configuration Service\n     * is fully compliant with the OSGi MetaType Information and the validation happens\n     * through the OSGi MetaType Service.\n     * <br>\n     * The Configuration Service is compliant with the OSGi MetaType Service so\n     * it accepts all attribute types defined in the OSGi Compendium Specifications.\n     * <br>\n     *\n     * @param configs\n     *            The list of ComponentConfiguration whose update is requested.\n     * @throws KuraException\n     *             if the properties specified do not pass the validation of the ObjectClassDefinition\n     */\n    public void updateConfigurations(List<ComponentConfiguration> configs) throws KuraException;\n\n    /**\n     * Updates the Configuration of the registered components.\n     * Using the OSGi ConfigurationAdmin, it retrieves the Configuration of the\n     * component with the specified PID and then send an update using the\n     * specified properties.\n     * <br>\n     * If the component to be updated is not yet registered with the ConfigurationService,\n     * it is first registered and then it is updated with the specified properties.\n     * Before updating the component, the specified properties are validated against\n     * the ObjectClassDefinition associated to the Component. The Configuration Service\n     * is fully compliant with the OSGi MetaType Information and the validation happens\n     * through the OSGi MetaType Service.\n     * <br>\n     * The Configuration Service is compliant with the OSGi MetaType Service so\n     * it accepts all attribute types defined in the OSGi Compendium Specifications.\n     * <br>\n     *\n     * @param configs\n     *            The list of ComponentConfiguration whose update is requested.\n     * @param takeSnapshot\n     *            defines whether or not this configuration update should trigger a snapshot.\n     * @throws KuraException\n     *             if the properties specified do not pass the validation of the ObjectClassDefinition\n     *\n     * @since 1.0.8\n     */\n    public void updateConfigurations(List<ComponentConfiguration> configs, boolean takeSnapshot) throws KuraException;\n\n    /**\n     * Returns the ID of all the snapshots taken by the ConfigurationService.\n     * The snapshot ID is the epoch time at which the snapshot was taken.\n     * The snapshots are stored in the KuraHome/snapshots/ directory.\n     * This API will return all the snpashot files available in that location.\n     *\n     * @return IDs of the snapshots available.\n     * @throws KuraException\n     */\n    public Set<Long> getSnapshots() throws KuraException;\n\n    /**\n     * Loads a snapshot given its ID and return the component configurations stored in that snapshot.\n     *\n     * @param sid\n     *            - ID of the snapshot to be loaded\n     * @return List of ComponentConfigurations contained in the snapshot\n     * @throws KuraException\n     */\n    public List<ComponentConfiguration> getSnapshot(long sid) throws KuraException;\n\n    /**\n     * Takes a new snapshot of the current configuration of all the registered ConfigurableCompoenents.\n     * It returns the ID of a snapshot as the epoch time at which the snapshot was taken.\n     *\n     * @return the ID of the snapshot.\n     * @throws KuraException\n     */\n    public long snapshot() throws KuraException;\n\n    /**\n     * Rolls back to the last saved snapshot if available.\n     *\n     * @return the ID of the snapshot it rolled back to\n     * @throws KuraException\n     *             if no snapshots are available or\n     */\n    public long rollback() throws KuraException;\n\n    /**\n     * Rolls back to the specified snapshot id.\n     *\n     * @param id\n     *            ID of the snapshot we need to rollback to\n     * @throws KuraException\n     *             if the snapshot is not found\n     */\n    public void rollback(long id) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/KuraConfigReadyEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.configuration;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraConfigReadyEvent extends Event {\n\n    /** Topic of the KuraConfigurationReadyEvent */\n    public static final String KURA_CONFIG_EVENT_READY_TOPIC = \"org/eclipse/kura/configuration/ConfigEvent/READY\";\n\n    public KuraConfigReadyEvent(Map<String, ?> properties) {\n        super(KURA_CONFIG_EVENT_READY_TOPIC, properties);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/KuraNetConfigReadyEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.configuration;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraNetConfigReadyEvent extends Event {\n\n    /** Topic of the KuraConfigurationReadyEvent */\n    public static final String KURA_NET_CONFIG_EVENT_READY_TOPIC = \"org/eclipse/kura/configuration/NetConfigEvent/READY\";\n\n    public KuraNetConfigReadyEvent(Map<String, ?> properties) {\n        super(KURA_NET_CONFIG_EVENT_READY_TOPIC, properties);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/Password.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.configuration;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class Password {\n\n    private char[] passwordVal;\n\n    public Password(String password) {\n        super();\n        if (password != null) {\n            this.passwordVal = password.toCharArray();\n        }\n    }\n\n    public Password(char[] password) {\n        super();\n        this.passwordVal = password;\n    }\n\n    public char[] getPassword() {\n        return this.passwordVal;\n    }\n\n    @Override\n    public String toString() {\n        return new String(this.passwordVal);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/SelfConfiguringComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.configuration;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * A SelfConfiguringComponent is a configurable component which maintains its state.\n * A SelfConfiguringComponent exposes its configuration information to the ConfigurationService\n * and therefore can be have its configuration updated locally or remotely through the\n * ConfigurationService APIs.\n * However, a SelfConfiguringComponent does not rely on the ConfigurationService\n * to keep the storage of its configuration. The configuration state is kept\n * internally in the SelfConfiguringComponent or derived at runtime from\n * other resources such system resources.<br>\n * An example of a SelfConfiguringComponent is the NetworkService whose state\n * is kept in the operating system instead of in the ConfigurationService.\n */\n@ConsumerType\npublic interface SelfConfiguringComponent {\n\n    /**\n     * This method is called by the ConfigurationService when it requires\n     * the current snapshot of the configuration for this components.\n     * As SelfConfiguringComponents do not rely on the ConfigurationService\n     * to capture and store the current configuration, this call is needed\n     * to expose the current configuration externally and, for example,\n     * being able to store it in snapshot files.\n     *\n     * @return the current configuration for this component\n     * @throws KuraException\n     */\n    public ComponentConfiguration getConfiguration() throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/AD.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.10.26 at 02:11:54 PM CEST\n//\n\npackage org.eclipse.kura.configuration.metatype;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * <p>\n * Java class for Tad complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tad\"&gt;\n *   &lt;complexContent&gt;\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\"&gt;\n *       &lt;sequence&gt;\n *         &lt;element name=\"Option\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Toption\" maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *       &lt;/sequence&gt;\n *       &lt;attribute name=\"name\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"description\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"id\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"type\" use=\"required\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tscalar\" /&gt;\n *       &lt;attribute name=\"cardinality\" type=\"{http://www.w3.org/2001/XMLSchema}int\" default=\"0\" /&gt;\n *       &lt;attribute name=\"min\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"max\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"default\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}boolean\" default=\"true\" /&gt;\n *       &lt;anyAttribute/&gt;\n *     &lt;/restriction&gt;\n *   &lt;/complexContent&gt;\n * &lt;/complexType&gt;\n * </pre>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface AD {\n\n    /**\n     * Gets the value of the option property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the option property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getOption().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Option }\n     *\n     *\n     */\n    public List<Option> getOption();\n\n    /**\n     * Gets the value of the name property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getName();\n\n    /**\n     * Gets the value of the description property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getDescription();\n\n    /**\n     * Gets the value of the id property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getId();\n\n    /**\n     * Gets the value of the type property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Scalar }\n     *\n     */\n    public Scalar getType();\n\n    /**\n     * Gets the value of the cardinality property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Integer }\n     *\n     */\n    public int getCardinality();\n\n    /**\n     * Gets the value of the min property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getMin();\n\n    /**\n     * Gets the value of the max property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getMax();\n\n    /**\n     * Gets the value of the default property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getDefault();\n\n    /**\n     * Gets the value of the required property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Boolean }\n     *\n     */\n    public boolean isRequired();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/Attribute.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.10.26 at 02:11:54 PM CEST\n//\n\npackage org.eclipse.kura.configuration.metatype;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * <p>\n * Java class for Tattribute complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tattribute\"&gt;\n *   &lt;complexContent&gt;\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\"&gt;\n *       &lt;sequence&gt;\n *         &lt;element name=\"Value\" type=\"{http://www.w3.org/2001/XMLSchema}string\" maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *       &lt;/sequence&gt;\n *       &lt;attribute name=\"adref\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"content\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;anyAttribute/&gt;\n *     &lt;/restriction&gt;\n *   &lt;/complexContent&gt;\n * &lt;/complexType&gt;\n * </pre>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface Attribute {\n\n    /**\n     * Gets the value of the value property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the value property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getValue().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link String }\n     *\n     *\n     */\n    public List<String> getValue();\n\n    /**\n     * Gets the value of the adref property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getAdref();\n\n    /**\n     * Gets the value of the content property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getContent();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/Designate.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.10.26 at 02:11:54 PM CEST\n//\n\npackage org.eclipse.kura.configuration.metatype;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * <p>\n * Java class for Tdesignate complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tdesignate\"&gt;\n *   &lt;complexContent&gt;\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\"&gt;\n *       &lt;sequence&gt;\n *         &lt;element name=\"Object\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tobject\"/&gt;\n *         &lt;any processContents='lax' maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *       &lt;/sequence&gt;\n *       &lt;attribute name=\"pid\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"factoryPid\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"bundle\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"optional\" type=\"{http://www.w3.org/2001/XMLSchema}boolean\" default=\"false\" /&gt;\n *       &lt;attribute name=\"merge\" type=\"{http://www.w3.org/2001/XMLSchema}boolean\" default=\"false\" /&gt;\n *       &lt;anyAttribute/&gt;\n *     &lt;/restriction&gt;\n *   &lt;/complexContent&gt;\n * &lt;/complexType&gt;\n * </pre>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface Designate {\n\n    /**\n     * Gets the value of the object property.\n     *\n     * @return\n     *         possible object is\n     *         {@link TObject }\n     *\n     */\n    public TObject getObject();\n\n    /**\n     * Gets the value of the pid property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getPid();\n\n    /**\n     * Gets the value of the factoryPid property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getFactoryPid();\n\n    /**\n     * Gets the value of the bundle property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getBundle();\n\n    /**\n     * Gets the value of the optional property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Boolean }\n     *\n     */\n    public boolean isOptional();\n\n    /**\n     * Gets the value of the merge property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Boolean }\n     *\n     */\n    public boolean isMerge();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/Icon.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.10.26 at 02:11:54 PM CEST\n//\n\npackage org.eclipse.kura.configuration.metatype;\n\nimport java.math.BigInteger;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * <p>\n * Java class for Ticon complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Ticon\"&gt;\n *   &lt;complexContent&gt;\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\"&gt;\n *       &lt;sequence&gt;\n *         &lt;any processContents='lax' maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *       &lt;/sequence&gt;\n *       &lt;attribute name=\"resource\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"size\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}positiveInteger\" /&gt;\n *       &lt;anyAttribute/&gt;\n *     &lt;/restriction&gt;\n *   &lt;/complexContent&gt;\n * &lt;/complexType&gt;\n * </pre>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface Icon {\n\n    /**\n     * Gets the value of the resource property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getResource();\n\n    /**\n     * Gets the value of the size property.\n     *\n     * @return\n     *         possible object is\n     *         {@link BigInteger }\n     *\n     */\n    public BigInteger getSize();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/MetaData.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.10.26 at 02:11:54 PM CEST\n//\n\npackage org.eclipse.kura.configuration.metatype;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * <p>\n * Java class for Tmetadata complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tmetadata\"&gt;\n *   &lt;complexContent&gt;\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\"&gt;\n *       &lt;sequence&gt;\n *         &lt;element name=\"OCD\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tocd\" maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *         &lt;element name=\"Designate\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tdesignate\" maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *       &lt;/sequence&gt;\n *       &lt;attribute name=\"localization\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;anyAttribute/&gt;\n *     &lt;/restriction&gt;\n *   &lt;/complexContent&gt;\n * &lt;/complexType&gt;\n * </pre>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface MetaData {\n\n    /**\n     * Gets the value of the ocd property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the ocd property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getOCD().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link OCD }\n     *\n     *\n     */\n    public List<OCD> getOCD();\n\n    /**\n     * Gets the value of the designate property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the designate property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getDesignate().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Designate }\n     *\n     *\n     */\n    public List<Designate> getDesignate();\n\n    /**\n     * Gets the value of the localization property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getLocalization();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/OCD.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.10.26 at 02:11:54 PM CEST\n//\n\npackage org.eclipse.kura.configuration.metatype;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * <p>\n * Java class for Tocd complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tocd\"&gt;\n *   &lt;complexContent&gt;\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\"&gt;\n *       &lt;sequence&gt;\n *         &lt;element name=\"AD\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tad\" maxOccurs=\"unbounded\"/&gt;\n *         &lt;element name=\"Icon\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Ticon\" maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *       &lt;/sequence&gt;\n *       &lt;attribute name=\"name\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"description\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"id\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;anyAttribute/&gt;\n *     &lt;/restriction&gt;\n *   &lt;/complexContent&gt;\n * &lt;/complexType&gt;\n * </pre>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface OCD {\n\n    /**\n     * Gets the value of the ad property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the ad property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAD().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link AD }\n     *\n     *\n     */\n    public List<AD> getAD();\n\n    /**\n     * Gets the value of the icon property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the icon property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getIcon().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Icon }\n     *\n     *\n     */\n    public List<Icon> getIcon();\n\n    /**\n     * Gets the value of the name property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getName();\n\n    /**\n     * Gets the value of the description property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getDescription();\n\n    /**\n     * Gets the value of the id property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getId();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/OCDService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.configuration.metatype;\n\nimport java.util.List;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This Interface provides the capability to get the OCDs for the specified Factories or Service Providers.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.4\n */\n@ProviderType\npublic interface OCDService {\n\n    /**\n     * Returns the {@link OCD}s of all registered component factories for which an OSGi MetaType is\n     * is registered in the {@link ConfigurationService}.\n     * <br>\n     * The {@link OCD}s are returned in the form of a {@link ComponentConfiguration} instance. The component factory pid\n     * can be obtained by calling {@link ComponentConfiguration#getPid()} method and the actual {@link OCD} can be\n     * obtained by calling the {@link ComponentConfiguration#getDefinition()} method.\n     *\n     *\n     * @return The list of the component factory {@link OCD}s.\n     * @since 1.4\n     */\n    public List<ComponentConfiguration> getFactoryComponentOCDs();\n\n    /**\n     * Returns the {@link OCD} of the registered component factory identified by the provided {@code factoryPid} and for\n     * which an OSGi MetaType is registered in the {@link ConfigurationService}.\n     * <br>\n     * The {@link OCD} is returned in the form of a {@link ComponentConfiguration} instance. The component factory pid\n     * can be obtained by calling {@link ComponentConfiguration#getPid()} method and the actual {@link OCD} can be\n     * obtained by calling the {@link ComponentConfiguration#getDefinition()} method.\n     *\n     * @return The {@link OCD} for the requested component factory if available, or null otherwise\n     * @since 1.4\n     */\n    public ComponentConfiguration getFactoryComponentOCD(String factoryPid);\n\n    /**\n     * Searches the Declarative Services layer for Components implementing any of the specified services and returns a\n     * {@link ComponentConfiguration} instance describing it.\n     * If the {@link ConfigurationService} contains a registered OSGi MetaType for a found Component, it will be\n     * returned inside the {@link ComponentConfiguration} instance.\n     * <br>\n     * The {@link ComponentConfiguration} instances in the returned list contain the following information:\n     * <ul>\n     * <li>\n     * The {@link ComponentConfiguration#getPid()} method returns the Component name.\n     * </li>\n     * <li>\n     * The {@link ComponentConfiguration#getDefinition()} method returns the {@link OCD} for the found Component if\n     * it is known to the {@link ConfigurationService}, or {@code null} otherwise.\n     * </li>\n     * </ul>\n     *\n     * @param clazzes\n     *            The list of service classes to be used as search filter.\n     * @return A list of {@link ComponentConfiguration} instances representing the found Components.\n     * @since 1.4\n     */\n    public List<ComponentConfiguration> getServiceProviderOCDs(Class<?>... classes);\n\n    /**\n     * @see {@link ConfigurationService#getServiceProviderOCDs(Class...)\n     *\n     * @param classNames\n     *            The list of service class or interface names to be used as search filter.\n     * @return A list of {@link ComponentConfiguration} instances representing the found Components.\n     * @since 1.4\n     */\n    public List<ComponentConfiguration> getServiceProviderOCDs(String... classNames);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/Option.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.10.26 at 02:11:54 PM CEST\n//\n\npackage org.eclipse.kura.configuration.metatype;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * <p>\n * Java class for Toption complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Toption\"&gt;\n *   &lt;complexContent&gt;\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\"&gt;\n *       &lt;sequence&gt;\n *         &lt;any processContents='lax' maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *       &lt;/sequence&gt;\n *       &lt;attribute name=\"label\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;attribute name=\"value\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;anyAttribute/&gt;\n *     &lt;/restriction&gt;\n *   &lt;/complexContent&gt;\n * &lt;/complexType&gt;\n * </pre>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface Option {\n\n    /**\n     * Gets the value of the label property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getLabel();\n\n    /**\n     * Gets the value of the value property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getValue();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/Scalar.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.configuration.metatype;\n\n/**\n * <p>\n * Java class for Tscalar.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n * <p>\n *\n * <pre>\n * &lt;simpleType name=\"Tscalar\"&gt;\n *   &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}string\"&gt;\n *     &lt;enumeration value=\"String\"/&gt;\n *     &lt;enumeration value=\"Long\"/&gt;\n *     &lt;enumeration value=\"Double\"/&gt;\n *     &lt;enumeration value=\"Float\"/&gt;\n *     &lt;enumeration value=\"Integer\"/&gt;\n *     &lt;enumeration value=\"Byte\"/&gt;\n *     &lt;enumeration value=\"Char\"/&gt;\n *     &lt;enumeration value=\"Boolean\"/&gt;\n *     &lt;enumeration value=\"Short\"/&gt;\n *     &lt;enumeration value=\"Password\"/&gt;\n *   &lt;/restriction&gt;\n * &lt;/simpleType&gt;\n * </pre>\n */\npublic enum Scalar {\n\n    STRING(\"String\"),  //\n    LONG(\"Long\"),  //\n    DOUBLE(\"Double\"),  //\n    FLOAT(\"Float\"),  //\n    INTEGER(\"Integer\"),  //\n    BYTE(\"Byte\"),  //\n    CHAR(\"Char\"),  //\n    BOOLEAN(\"Boolean\"),  //\n    SHORT(\"Short\"),  //\n    PASSWORD(\"Password\"); //\n\n    private final String value;\n\n    Scalar(String v) {\n        this.value = v;\n    }\n\n    public String value() {\n        return this.value;\n    }\n\n    public static Scalar fromValue(String v) {\n        if (\"character\".equalsIgnoreCase(v)) {\n            return CHAR;\n        }\n        for (Scalar c : Scalar.values()) {\n            if (c.value.equals(v)) {\n                return c;\n            }\n        }\n        throw new IllegalArgumentException(v);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/TObject.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.10.26 at 02:11:54 PM CEST\n//\n\npackage org.eclipse.kura.configuration.metatype;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * <p>\n * Java class for Tobject complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tobject\"&gt;\n *   &lt;complexContent&gt;\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\"&gt;\n *       &lt;sequence&gt;\n *         &lt;element name=\"Attribute\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tattribute\" maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/&gt;\n *       &lt;/sequence&gt;\n *       &lt;attribute name=\"ocdref\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" /&gt;\n *       &lt;anyAttribute/&gt;\n *     &lt;/restriction&gt;\n *   &lt;/complexContent&gt;\n * &lt;/complexType&gt;\n * </pre>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface TObject {\n\n    /**\n     * Gets the value of the attribute property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the attribute property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAttribute().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Attribute }\n     *\n     *\n     */\n    public List<Attribute> getAttribute();\n\n    /**\n     * Gets the value of the ocdref property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    public String getOcdref();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides expected schemas for JAXB bindings.\n *\n */\npackage org.eclipse.kura.configuration.metatype;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Contains services to manage all configurable components of the system. This provides an extension to the existing\n * OSGi MetaTypeService services.\n *\n */\npackage org.eclipse.kura.configuration;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/connection/listener/ConnectionListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.connection.listener;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Listener interface to be implemented by applications that needs to be notified about connection events.\n * All registered listeners are called sequentially by the implementations at the occurrence of the\n * event.\n *\n * @since 2.5.0\n */\n@ConsumerType\npublic interface ConnectionListener {\n\n    /**\n     * Notifies the listener that the connection has been established.\n     */\n    public void connected();\n\n    /**\n     * Notifies the listener that the connection has been closed.\n     */\n    public void disconnected();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/connection/listener/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides APIs to implement a ConnectionListener.\n *\n * @since 2.5\n *\n */\npackage org.eclipse.kura.connection.listener;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.container.orchestration.ContainerNetworkConfiguration.ContainerNetworkConfigurationBuilder;\nimport org.eclipse.kura.container.orchestration.ImageConfiguration.ImageConfigurationBuilder;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Object which represents a container configuration used to request the\n * generation of a new container instance.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.3\n *\n */\n@ProviderType\npublic class ContainerConfiguration {\n\n    private String containerName;\n    private List<ContainerPort> containerPorts;\n    private List<String> containerEnvVars;\n    private List<String> containerDevices;\n    private Map<String, String> containerVolumes;\n    private Boolean containerPrivileged;\n    private Boolean isFrameworkManaged = true;\n    private Map<String, String> containerLoggerParameters;\n    private String containerLoggingType;\n    private ImageConfiguration imageConfig;\n    private ContainerNetworkConfiguration networkConfiguration;\n    private List<String> entryPoint;\n    private Boolean containerRestartOnFailure = false;\n    private Optional<Long> memory;\n    private Optional<Float> cpus;\n    private Optional<String> gpus;\n    private Optional<String> runtime;\n    private Optional<String> enforcementDigest;\n\n    private ContainerConfiguration() {\n    }\n\n    /**\n     * The method will provide information if the container is or not managed by the\n     * framework\n     *\n     * @return <code>true</code> if the framework manages the container.\n     *         <code>false</code> otherwise\n     */\n    public boolean isFrameworkManaged() {\n        return this.isFrameworkManaged;\n    }\n\n    /**\n     * Returns the container name\n     *\n     * @return\n     */\n    public String getContainerName() {\n        return this.containerName;\n    }\n\n    /**\n     * Returns a list of {@link ContainerPort} mapped to the container.\n     *\n     * @return\n     * @since 2.5\n     */\n    public List<ContainerPort> getContainerPorts() {\n        return this.containerPorts;\n    }\n\n    /**\n     * Returns the list of external ports that will be mapped to the\n     * given container.\n     *\n     * @return\n     *\n     * @deprecated since 2.5. Please use {@link getContainerPorts} as it includes\n     *             the network\n     *             protocol with the port mapping.\n     */\n    @Deprecated\n    public List<Integer> getContainerPortsExternal() {\n        return this.containerPorts.stream().map(ContainerPort::getExternalPort).collect(Collectors.toList());\n    }\n\n    /**\n     * Returns the list of internal ports that will be mapped to the\n     * given container\n     *\n     * @return\n     *\n     * @deprecated since 2.5. Please use {@link getContainerPorts} as it includes\n     *             the network\n     *             protocol with the port mapping.\n     */\n    @Deprecated\n    public List<Integer> getContainerPortsInternal() {\n        return this.containerPorts.stream().map(ContainerPort::getInternalPort).collect(Collectors.toList());\n    }\n\n    /**\n     * Returns the list of environment properties that will be passed to the\n     * container\n     *\n     * @return\n     */\n    public List<String> getContainerEnvVars() {\n        return this.containerEnvVars;\n    }\n\n    /**\n     * Returns the list of devices that will be mapped to the container\n     *\n     * @return\n     */\n    public List<String> getContainerDevices() {\n        return this.containerDevices;\n    }\n\n    /**\n     * Returns a map that identifies the volumes and the internal container mapping\n     *\n     * @return\n     */\n    public Map<String, String> getContainerVolumes() {\n        return this.containerVolumes;\n    }\n\n    /**\n     * Returns a boolean representing if the container runs or will run in\n     * privileged mode.\n     *\n     * @return\n     */\n    public boolean isContainerPrivileged() {\n        return this.containerPrivileged;\n    }\n\n    /**\n     * Returns a Map that identifies configured logger parameters.\n     *\n     * @return\n     */\n    public Map<String, String> getLoggerParameters() {\n        return this.containerLoggerParameters;\n    }\n\n    /**\n     * Returns a string identifying which logger driver to use.\n     *\n     * @return\n     */\n    public String getContainerLoggingType() {\n        return this.containerLoggingType;\n    }\n\n    /**\n     * Returns the {@link ImageConfiguration} object\n     *\n     * @return\n     * @since 2.4\n     */\n    public ImageConfiguration getImageConfiguration() {\n        return this.imageConfig;\n    }\n\n    /**\n     * Returns the base image for the associated container. Detailed image\n     * information can be found in the {@link ImageConfig} class, provided by the\n     * {@link #getImageConfiguration()} method.\n     *\n     * @return\n     */\n    public String getContainerImage() {\n        return this.imageConfig.getImageName();\n    }\n\n    /**\n     * Returns the image tag for the associated container. Detailed image\n     * information can be found in the {@link ImageConfig} class, provided by the\n     * {@link #getImageConfiguration()} method.\n     *\n     * @return\n     */\n    public String getContainerImageTag() {\n        return this.imageConfig.getImageTag();\n    }\n\n    /**\n     * Returns the Registry credentials. Detailed image information can be found in\n     * the {@link ImageConfig} class, provided by the\n     * {@link #getImageConfiguration()} method.\n     *\n     * @return\n     */\n    public Optional<RegistryCredentials> getRegistryCredentials() {\n        return this.imageConfig.getRegistryCredentials();\n    }\n\n    /**\n     * Returns the image download timeout (in seconds). Detailed image information\n     * can be found in the {@link ImageConfig} class, provided by the\n     * {@link #getImageConfiguration()} method.\n     *\n     * @return\n     */\n    public int getImageDownloadTimeoutSeconds() {\n        return this.imageConfig.getimageDownloadTimeoutSeconds();\n    }\n\n    /**\n     * return the container's network configuration as a\n     * {@link ContainerNetworkConfiguration}.\n     *\n     * @return\n     * @since 2.4\n     */\n    public ContainerNetworkConfiguration getContainerNetworkConfiguration() {\n        return this.networkConfiguration;\n    }\n\n    /**\n     * Returns a List<String> of container entry points. An empty list can be\n     * returned if no entrypoints are specified.\n     *\n     * @return\n     * @since 2.4\n     */\n    public List<String> getEntryPoint() {\n        return this.entryPoint;\n    }\n\n    /**\n     * Returns boolean which determines if container will restart on failure\n     *\n     * @return\n     * @since 2.4\n     */\n    public boolean getRestartOnFailure() {\n        return this.containerRestartOnFailure;\n    }\n\n    /**\n     * Return the memory to be assigned to the container.\n     *\n     * @return\n     * @since 2.4\n     */\n    public Optional<Long> getMemory() {\n        return this.memory;\n    }\n\n    /**\n     * Return the cpus resources to be assigned to the container.\n     *\n     * @return\n     * @since 2.4\n     */\n    public Optional<Float> getCpus() {\n        return this.cpus;\n    }\n\n    /**\n     * Return the gpus to be assigned to the container.\n     *\n     * @return\n     * @since 2.4\n     */\n    public Optional<String> getGpus() {\n        return this.gpus;\n    }\n\n    /**\n     * Return the runtime option to be assigned to the container.\n     *\n     * @return the optional runtime string used by the container\n     * @since 2.7\n     */\n    public Optional<String> getRuntime() {\n        return this.runtime;\n    }\n\n    /**\n     * Return the enforcement digest assigned to the container.\n     *\n     * @return the optional runtime string used by the container\n     * @since 2.7\n     */\n    public Optional<String> getEnforcementDigest() {\n        return this.enforcementDigest;\n    }\n\n    /**\n     * Creates a builder for creating a new {@link ContainerConfiguration} instance.\n     *\n     * @return the builder.\n     */\n    public static ContainerConfigurationBuilder builder() {\n        return new ContainerConfigurationBuilder();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.containerDevices, this.containerEnvVars, this.containerLoggerParameters,\n                this.containerLoggingType, this.containerName, this.containerPorts, this.containerPrivileged,\n                this.containerVolumes, this.cpus, this.enforcementDigest, this.entryPoint, this.gpus, this.imageConfig,\n                this.isFrameworkManaged, this.memory, this.networkConfiguration, this.containerRestartOnFailure,\n                this.runtime);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        ContainerConfiguration other = (ContainerConfiguration) obj;\n        return Objects.equals(this.containerDevices, other.containerDevices)\n                && Objects.equals(this.containerEnvVars, other.containerEnvVars)\n                && Objects.equals(this.containerLoggerParameters, other.containerLoggerParameters)\n                && Objects.equals(this.containerLoggingType, other.containerLoggingType)\n                && Objects.equals(this.containerName, other.containerName)\n                && Objects.equals(this.containerPorts, other.containerPorts)\n                && Objects.equals(this.containerPrivileged, other.containerPrivileged)\n                && Objects.equals(this.containerVolumes, other.containerVolumes)\n                && Objects.equals(this.cpus, other.cpus) && Objects.equals(enforcementDigest, other.enforcementDigest)\n                && Objects.equals(this.entryPoint, other.entryPoint) && Objects.equals(this.gpus, other.gpus)\n                && Objects.equals(this.imageConfig, other.imageConfig)\n                && Objects.equals(this.isFrameworkManaged, other.isFrameworkManaged)\n                && Objects.equals(this.memory, other.memory)\n                && Objects.equals(this.networkConfiguration, other.networkConfiguration)\n                && Objects.equals(this.containerRestartOnFailure, other.containerRestartOnFailure)\n                && Objects.equals(this.runtime, other.runtime);\n    }\n\n    public static final class ContainerConfigurationBuilder {\n\n        private String containerName;\n        private List<Integer> containerPortsExternal = new ArrayList<>();\n        private List<Integer> containerPortsInternal = new ArrayList<>();\n        private List<ContainerPort> containerPorts = new ArrayList<>();\n        private List<String> containerEnvVars = new LinkedList<>();\n        private List<String> containerDevices = new LinkedList<>();\n        private Map<String, String> containerVolumes = new HashMap<>();\n        private Boolean containerPrivileged = false;\n        private Boolean isFrameworkManaged = false;\n        private Map<String, String> containerLoggerParameters;\n        private String containerLoggingType;\n        private final ImageConfigurationBuilder imageConfigBuilder = new ImageConfiguration.ImageConfigurationBuilder();\n        private final ContainerNetworkConfigurationBuilder networkConfigurationBuilder = new ContainerNetworkConfigurationBuilder();\n        private List<String> entryPoint = new LinkedList<>();\n        private Boolean containerRestartOnFailure = false;\n        private Optional<Long> memory = Optional.empty();\n        private Optional<Float> cpus = Optional.empty();\n        private Optional<String> gpus = Optional.empty();\n        private Optional<String> runtime = Optional.empty();\n        private Optional<String> enforcementDigest = Optional.empty();\n\n        public ContainerConfigurationBuilder setContainerName(String serviceName) {\n            this.containerName = serviceName;\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setFrameworkManaged(Boolean isFrameworkManaged) {\n            this.isFrameworkManaged = isFrameworkManaged;\n            return this;\n        }\n\n        /**\n         * Set a list of {@link ContainerPort}, to express which ports to expose and\n         * what protocol to use.\n         *\n         * @since 2.5\n         */\n        public ContainerConfigurationBuilder setContainerPorts(List<ContainerPort> containerPorts) {\n            this.containerPorts = containerPorts;\n            return this;\n        }\n\n        /**\n         * Accepts a list<Integer> of ports to be exposed. Assumes all ports\n         * are TCP. To use other Internet protocols\n         * please see the {@link setContainerPorts} method. Ensure that the\n         * number of elements in this list is the same\n         * as the number of elements set with {@link setInternalPorts}.\n         *\n         * @deprecated since 2.5. Please use {@link setContainerPorts} as it allows for\n         *             network protocol to be specified in a port mapping.\n         */\n        @Deprecated\n        public ContainerConfigurationBuilder setExternalPorts(List<Integer> containerPortsExternal) {\n            this.containerPortsExternal = new ArrayList<>(containerPortsExternal);\n            return this;\n        }\n\n        /**\n         * Accepts a list<Integer> of ports to be open internally within the\n         * container. Assumes all ports are TCP. To\n         * use other Internet protocols please see the\n         * {@link setContainerPorts} method.\n         * Ensure that the number of elements in this list is the same as\n         * the number of elements set with {@link setExternalPorts}.\n         *\n         * @deprecated since 2.5. Please use {@link setContainerPorts} as it allows for\n         *             network protocol to be specified in a port mapping.\n         *\n         */\n        @Deprecated\n        public ContainerConfigurationBuilder setInternalPorts(List<Integer> containerPortsInternal) {\n            this.containerPortsInternal = new ArrayList<>(containerPortsInternal);\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setEnvVars(List<String> vars) {\n            this.containerEnvVars = new LinkedList<>(vars);\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setDeviceList(List<String> devices) {\n            this.containerDevices = new LinkedList<>(devices);\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setVolumes(Map<String, String> volumeMap) {\n            this.containerVolumes = new HashMap<>(volumeMap);\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setLoggerParameters(Map<String, String> paramMap) {\n            this.containerLoggerParameters = new HashMap<>(paramMap);\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setLoggingType(String containerLoggingType) {\n            this.containerLoggingType = containerLoggingType;\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setPrivilegedMode(Boolean containerPrivileged) {\n            this.containerPrivileged = containerPrivileged;\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setContainerImage(String serviceImage) {\n            this.imageConfigBuilder.setImageName(serviceImage);\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setContainerImageTag(String serviceImageTag) {\n            this.imageConfigBuilder.setImageTag(serviceImageTag);\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setRegistryCredentials(Optional<RegistryCredentials> registryCredentials) {\n            this.imageConfigBuilder.setRegistryCredentials(registryCredentials);\n            return this;\n        }\n\n        public ContainerConfigurationBuilder setImageDownloadTimeoutSeconds(int imageDownloadTimeoutSeconds) {\n            this.imageConfigBuilder.setImageDownloadTimeoutSeconds(imageDownloadTimeoutSeconds);\n            return this;\n        }\n\n        /**\n         * @since 2.4\n         */\n        public ContainerConfigurationBuilder setEntryPoint(List<String> entryPoint) {\n            this.entryPoint = entryPoint;\n            return this;\n        }\n\n        /**\n         * Set the {@link NetworkConfiguration}\n         *\n         * @since 2.4\n         */\n        public ContainerConfigurationBuilder setContainerNetowrkConfiguration(\n                ContainerNetworkConfiguration networkConfiguration) {\n            this.networkConfigurationBuilder.setNetworkMode(networkConfiguration.getNetworkMode());\n            return this;\n        }\n\n        /**\n         * Set the {@link ImageConfiguration}\n         *\n         * @since 2.4\n         */\n        public ContainerConfigurationBuilder setImageConfiguration(ImageConfiguration imageConfig) {\n            this.imageConfigBuilder.setImageName(imageConfig.getImageName());\n            this.imageConfigBuilder.setImageTag(imageConfig.getImageTag());\n            this.imageConfigBuilder.setRegistryCredentials(imageConfig.getRegistryCredentials());\n            this.imageConfigBuilder.setImageDownloadTimeoutSeconds(imageConfig.getimageDownloadTimeoutSeconds());\n            return this;\n        }\n\n        /**\n         * Set if container will restart on failure\n         *\n         * @since 2.4\n         */\n        public ContainerConfigurationBuilder setRestartOnFailure(boolean containerRestartOnFailure) {\n            this.containerRestartOnFailure = containerRestartOnFailure;\n            return this;\n        }\n\n        /**\n         * @since 2.4\n         */\n        public ContainerConfigurationBuilder setMemory(Optional<Long> memory) {\n            this.memory = memory;\n            return this;\n        }\n\n        /**\n         * @since 2.4\n         */\n        public ContainerConfigurationBuilder setCpus(Optional<Float> cpus) {\n            this.cpus = cpus;\n            return this;\n        }\n\n        /**\n         * @since 2.4\n         */\n        public ContainerConfigurationBuilder setGpus(Optional<String> gpus) {\n            this.gpus = gpus;\n            return this;\n        }\n\n        /**\n         * @since 2.7\n         */\n        public ContainerConfigurationBuilder setRuntime(Optional<String> runtime) {\n            this.runtime = runtime;\n            return this;\n        }\n\n        /**\n         * @since 2.7\n         */\n        public ContainerConfigurationBuilder setEnforcementDigest(Optional<String> digest) {\n            this.enforcementDigest = digest;\n            return this;\n        }\n\n        public ContainerConfiguration build() {\n\n            if (this.containerPorts.isEmpty()) {\n                Iterator<Integer> extPort = this.containerPortsExternal.iterator();\n                Iterator<Integer> intPort = this.containerPortsInternal.iterator();\n\n                while (extPort.hasNext() && intPort.hasNext()) {\n                    this.containerPorts.add(new ContainerPort(intPort.next(), extPort.next()));\n                }\n            }\n\n            ContainerConfiguration result = new ContainerConfiguration();\n\n            result.containerName = requireNonNull(this.containerName, \"Request Container Name cannot be null\");\n            result.containerPorts = this.containerPorts;\n            result.containerEnvVars = this.containerEnvVars;\n            result.containerDevices = this.containerDevices;\n            result.containerVolumes = this.containerVolumes;\n            result.containerPrivileged = this.containerPrivileged;\n            result.isFrameworkManaged = this.isFrameworkManaged;\n            result.containerLoggerParameters = this.containerLoggerParameters;\n            result.containerLoggingType = this.containerLoggingType;\n            result.imageConfig = this.imageConfigBuilder.build();\n            result.networkConfiguration = this.networkConfigurationBuilder.build();\n            result.entryPoint = requireNonNull(this.entryPoint, \"Container EntryPoint list must not be null\");\n            result.containerRestartOnFailure = this.containerRestartOnFailure;\n            result.memory = this.memory;\n            result.cpus = this.cpus;\n            result.gpus = this.gpus;\n            result.runtime = this.runtime;\n            result.enforcementDigest = this.enforcementDigest;\n\n            return result;\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerInstanceDescriptor.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Object which represents a instantiated container. Used to track created\n * containers.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.3\n *\n */\n@ProviderType\npublic class ContainerInstanceDescriptor {\n\n    private String containerName;\n    private String containerImage;\n    private String containerImageTag;\n    private String containerID;\n    private List<ContainerPort> containerPorts = new ArrayList<>();\n    private ContainerState containerState = ContainerState.STOPPING;\n    private boolean isFrameworkManaged;\n\n    private ContainerInstanceDescriptor() {\n    }\n\n    /**\n     * Returns the container status as {@link ContainerState}\n     *\n     * @return\n     */\n    public ContainerState getContainerState() {\n        return this.containerState;\n    }\n\n    /**\n     * The method will provide information if the container is or not managed by the\n     * framework\n     *\n     * @return <code>true</code> if the framework manages the container.\n     *         <code>false</code> otherwise\n     */\n    public boolean isFrameworkManaged() {\n        return this.isFrameworkManaged;\n    }\n\n    /**\n     * Returns the container name\n     *\n     * @return\n     */\n    public String getContainerName() {\n        return this.containerName;\n    }\n\n    /**\n     * Returns the base image for the associated container\n     *\n     * @return\n     */\n    public String getContainerImage() {\n        return this.containerImage;\n    }\n\n    /**\n     * Returns the image tag for the associated container\n     *\n     * @return\n     */\n    public String getContainerImageTag() {\n        return this.containerImageTag;\n    }\n\n    /**\n     * Returns the containerID\n     *\n     * @return\n     */\n    public String getContainerId() {\n        return this.containerID;\n    }\n\n    /**\n     * Returns a list of {@link ContainerPort} mapped to the container.\n     *\n     * @return\n     * @since 2.5\n     */\n    public List<ContainerPort> getContainerPorts() {\n        return this.containerPorts;\n    }\n\n    /**\n     * Returns the list of external ports that will be mapped to the\n     * given container\n     *\n     * @return\n     *\n     * @deprecated please use {@link getContainerPorts} as it includes the network\n     *             protocol with the port mapping.\n     */\n    @Deprecated\n    public List<Integer> getContainerPortsExternal() {\n        return this.containerPorts.stream().map(ContainerPort::getExternalPort).collect(Collectors.toList());\n    }\n\n    /**\n     * Returns the list of internal ports that will be mapped to the\n     * given container\n     *\n     * @return\n     *\n     * @deprecated please use {@link getContainerPorts} as it includes the network\n     *             protocol with the port mapping.\n     *\n     */\n    @Deprecated\n    public List<Integer> getContainerPortsInternal() {\n        return this.containerPorts.stream().map(ContainerPort::getInternalPort).collect(Collectors.toList());\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.containerID, this.containerImage, this.containerImageTag, this.containerName,\n                this.containerPorts, this.containerState, this.isFrameworkManaged);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        ContainerInstanceDescriptor other = (ContainerInstanceDescriptor) obj;\n        return Objects.equals(this.containerID, other.containerID)\n                && Objects.equals(this.containerImage, other.containerImage)\n                && Objects.equals(this.containerImageTag, other.containerImageTag)\n                && Objects.equals(this.containerName, other.containerName)\n                && Objects.equals(this.containerPorts, other.containerPorts)\n                && this.containerState == other.containerState && this.isFrameworkManaged == other.isFrameworkManaged;\n    }\n\n    /**\n     * Creates a builder for creating a new {@link ContainerInstanceDescriptor}\n     * instance.\n     *\n     * @return the builder.\n     */\n    public static ContainerInstanceDescriptorBuilder builder() {\n        return new ContainerInstanceDescriptorBuilder();\n    }\n\n    public static final class ContainerInstanceDescriptorBuilder {\n\n        private String containerName;\n        private String containerImage;\n        private String containerImageTag = \"latest\";\n        private String containerId = \"\";\n        private List<Integer> containerPortsExternal = new ArrayList<>();\n        private List<Integer> containerPortsInternal = new ArrayList<>();\n        private List<ContainerPort> containerPorts = new ArrayList<>();\n        private ContainerState containerState = ContainerState.STOPPING;\n        private boolean isFrameworkManaged;\n\n        public ContainerInstanceDescriptorBuilder setContainerName(String serviceName) {\n            this.containerName = serviceName;\n            return this;\n        }\n\n        public ContainerInstanceDescriptorBuilder setFrameworkManaged(Boolean isFrameworkManaged) {\n            this.isFrameworkManaged = isFrameworkManaged;\n            return this;\n        }\n\n        public ContainerInstanceDescriptorBuilder setContainerImage(String serviceImage) {\n            this.containerImage = serviceImage;\n            return this;\n        }\n\n        public ContainerInstanceDescriptorBuilder setContainerImageTag(String serviceImageTag) {\n            this.containerImageTag = serviceImageTag;\n            return this;\n        }\n\n        public ContainerInstanceDescriptorBuilder setContainerID(String containerID) {\n            this.containerId = containerID;\n            return this;\n        }\n\n        /**\n         *\n         * Set a list of container ports, to express which ports to expose and what\n         * protocol to use.\n         *\n         * @since 2.5\n         */\n        public ContainerInstanceDescriptorBuilder setContainerPorts(List<ContainerPort> containerPorts) {\n            this.containerPorts = containerPorts;\n            return this;\n        }\n\n        /**\n         * Accepts a list<Integer> of ports to be exposed. Assumes all ports\n         * are TCP. To use other Internet protocols\n         * please see the {@link setContainerPorts} method. Ensure that the\n         * number of elements in this list is the same\n         * as the number of elements set with {@link setInternalPorts}.\n         *\n         * @deprecated please use {@link setContainerPorts} as it allows for network\n         *             protocol to be specified in a port mapping.\n         *\n         */\n        @Deprecated\n        public ContainerInstanceDescriptorBuilder setExternalPorts(List<Integer> containerPortsExternal) {\n            this.containerPortsExternal = new ArrayList<>(containerPortsExternal);\n            return this;\n        }\n\n        /**\n         * Accepts a list<Integer> of ports to be open internally within the\n         * container.\n         * Assumes all ports are TCP. To\n         * use other Internet protocols please see the\n         * {@link setContainerPorts} method.\n         * Ensure that the number of elements in this list is the same as\n         * the number of elements set with {@link setExternalPorts}.\n         *\n         * @deprecated please use {@link setContainerPorts} as it allows for network\n         *             protocol to be specified in a port mapping.\n         *\n         */\n        @Deprecated\n        public ContainerInstanceDescriptorBuilder setInternalPorts(List<Integer> containerPortsInternal) {\n            this.containerPortsInternal = new ArrayList<>(containerPortsInternal);\n            return this;\n        }\n\n        public ContainerInstanceDescriptorBuilder setContainerState(ContainerState containerState) {\n            this.containerState = containerState;\n            return this;\n        }\n\n        public ContainerInstanceDescriptor build() {\n            ContainerInstanceDescriptor containerDescriptor = new ContainerInstanceDescriptor();\n\n            if (this.containerPorts.isEmpty()) {\n                Iterator<Integer> extPort = this.containerPortsExternal.iterator();\n                Iterator<Integer> intPort = this.containerPortsInternal.iterator();\n\n                while (extPort.hasNext() && intPort.hasNext()) {\n                    this.containerPorts.add(new ContainerPort(intPort.next(), extPort.next()));\n                }\n            }\n\n            containerDescriptor.containerName = this.containerName;\n            containerDescriptor.containerImage = this.containerImage;\n            containerDescriptor.containerImageTag = this.containerImageTag;\n            containerDescriptor.containerID = this.containerId;\n            containerDescriptor.containerPorts = this.containerPorts;\n            containerDescriptor.containerState = this.containerState;\n            containerDescriptor.isFrameworkManaged = this.isFrameworkManaged;\n\n            return containerDescriptor;\n        }\n\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerNetworkConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Object which represents a container network configuration used to when\n * requesting the generation of a new container instance.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.4\n *\n */\n@ProviderType\npublic class ContainerNetworkConfiguration {\n\n    private Optional<String> networkMode;\n\n    private ContainerNetworkConfiguration() {\n    }\n\n    /**\n     * \n     * Returns the network mode a container will be created with (e.g. 'bridge',\n     * 'none', 'container:', 'host').\n     * \n     * @return\n     */\n    public Optional<String> getNetworkMode() {\n        return this.networkMode;\n    }\n\n    /**\n     * Creates a builder for creating a new {@link ContainerNetworkConfiguration}\n     * instance.\n     *\n     * @return the builder.\n     */\n    public static ContainerNetworkConfigurationBuilder builder() {\n        return new ContainerNetworkConfigurationBuilder();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.networkMode);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof ContainerNetworkConfiguration)) {\n            return false;\n        }\n        ContainerNetworkConfiguration other = (ContainerNetworkConfiguration) obj;\n        return Objects.equals(this.networkMode, other.networkMode);\n    }\n\n    public static final class ContainerNetworkConfigurationBuilder {\n\n        private Optional<String> networkMode = Optional.empty();\n\n        public ContainerNetworkConfigurationBuilder setNetworkMode(Optional<String> networkMode) {\n            this.networkMode = networkMode;\n            return this;\n        }\n\n        public ContainerNetworkConfiguration build() {\n            ContainerNetworkConfiguration result = new ContainerNetworkConfiguration();\n\n            result.networkMode = requireNonNull(this.networkMode,\n                    \"Requested Container Network Mode Name cannot be null\");\n\n            return result;\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerOrchestrationService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.container.orchestration;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.container.orchestration.listener.ContainerOrchestrationServiceListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Interface for managing the container lifecycle and interacting with the\n * container manager daemon.\n *\n * @since 2.3\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface ContainerOrchestrationService {\n\n    /**\n     * Lists all available containers by id only, like running the cli command 'docker ps -a'\n     *\n     * @return a list of string objects representing the container IDs\n     */\n    public List<String> listContainersIds();\n\n    /**\n     * Lists all available containers returning the corresponding\n     * {@link ContainerInstanceDescriptor}s\n     *\n     * @return a list of {@link ContainerInstanceDescriptor}s representing the\n     *         available containers\n     */\n    public List<ContainerInstanceDescriptor> listContainerDescriptors();\n\n    /**\n     * Lists all available images, returning the corresponding\n     * {@link ImageInstanceDescriptor}s\n     *\n     * @return a list of {@link ContainerInstanceDescriptor}s representing the\n     *         available containers\n     * @since 2.4\n     */\n    public List<ImageInstanceDescriptor> listImageInstanceDescriptors();\n\n    /**\n     * Deletes Image from container engine. Takes ImageID String as parameter. Will\n     * throw an error if image is being used by a container.\n     *\n     * @param imageId string parameter that identifies the image to be deleted\n     * @throws KuraException if the image is used by a container or if the image\n     *                       deletion process fails\n     * @since 2.4\n     */\n    public void deleteImage(String imageId) throws KuraException;\n\n    /**\n     * Allows to pull the required image, using the specified tag and credentials.\n     * The image will be downloaded respecting the configured timeout in seconds.\n     *\n     * @param imageConfig an ImageConfiguration object which contains info such as\n     *                    image name, tag, pull timeout in seconds and registry\n     *                    credentials.\n     * \n     * @throws KuraException        if the pull operation fails\n     * @throws InterruptedException\n     * @since 2.4\n     */\n    public void pullImage(ImageConfiguration imageConfig) throws KuraException, InterruptedException;\n\n    /**\n     * Allows to pull the required image, using the specified tag and credentials.\n     * The image will be downloaded respecting the configured timeout in seconds.\n     *\n     * @param imageName           the image name to be used. Must not be null.\n     * @param imageTag            a string representing the image tag. Must not be\n     *                            null.\n     * @param timeOutSeconds      a non negative integer representing the image\n     *                            download timeout in seconds\n     * @param registryCredentials an optional that can contain the registry URL and\n     *                            credentials for authentication\n     * @throws KuraException        if the pull operation fails\n     * @throws InterruptedException\n     */\n    public void pullImage(String imageName, String imageTag, int timeOutSeconds,\n            Optional<RegistryCredentials> registryCredentials) throws KuraException, InterruptedException;\n\n    /**\n     * Returns the id of the container corresponding to the specified name. If no\n     * container can be found an {@link Optional#empty(} result is returned.\n     *\n     * @param name the string representing the container name. Must not be null\n     * @return an {@link Optional} value that will contain the container ID, if the\n     *         container exists. Otherwise and {@link Optional#empty()}\n     */\n    public Optional<String> getContainerIdByName(String name);\n\n    /**\n     * Starts a container identified by the values provided in a not null\n     * {@link ContainerConfiguration} object. If the requested image does not\n     * exists, it will be downloaded. A String representing the container ID will be\n     * returned if the operation of container creation and start succeed.\n     *\n     * @param containerConfiguration\n     * @return a String representing the container ID created\n     * @throws KuraException is thrown if the image pull or container creation and\n     *                       start fail\n     */\n    public String startContainer(ContainerConfiguration containerConfiguration)\n            throws KuraException, InterruptedException;\n\n    /**\n     * Starts a container identified by the specified ID\n     *\n     * @param id the ID of an already existing container. Must not be null\n     * @throws KuraException if the container starting fails\n     */\n    public void startContainer(String id) throws KuraException;\n\n    /**\n     * Stops a container identified by the specified ID\n     *\n     * @param id the ID of an already existing container. Must not be null\n     * @throws KuraException if the container stopping fails\n     */\n    public void stopContainer(String id) throws KuraException;\n\n    /**\n     * Deletes a container identified by the specified ID\n     *\n     * @param id the ID of an already existing container. Must not be null\n     * @throws KuraException if the container removal fails\n     */\n    public void deleteContainer(String id) throws KuraException;\n\n    /**\n     * Adds a new {@link ContainerOrchestrationServiceListener}\n     *\n     * @param dockerListener\n     * @param containerName\n     */\n    public void registerListener(ContainerOrchestrationServiceListener dockerListener);\n\n    /**\n     * Removes the {@link ContainerOrchestrationServiceListener} specified as\n     * parameter\n     *\n     * @param dockerListener\n     */\n    public void unregisterListener(ContainerOrchestrationServiceListener dockerListener);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerPort.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.container.orchestration;\n\nimport java.util.Objects;\n\n/**\n * \n * This class is used to represent a port mapping within a container.\n * \n *\n * @since 2.5\n */\npublic class ContainerPort {\n\n    private int internalPort;\n    private int externalPort;\n    private PortInternetProtocol internetProtocol;\n\n    public ContainerPort(int internalPort, int externalPort, PortInternetProtocol internetProtocol) {\n        this.internalPort = internalPort;\n        this.externalPort = externalPort;\n        this.internetProtocol = internetProtocol;\n    }\n\n    public ContainerPort(int internalPort, int externalPort) {\n        this.internalPort = internalPort;\n        this.externalPort = externalPort;\n        this.internetProtocol = PortInternetProtocol.TCP;\n    }\n\n    public int getInternalPort() {\n        return internalPort;\n    }\n\n    public int getExternalPort() {\n        return externalPort;\n    }\n\n    public PortInternetProtocol getInternetProtocol() {\n        return internetProtocol;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(externalPort, internalPort, internetProtocol);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        ContainerPort other = (ContainerPort) obj;\n        return externalPort == other.externalPort && internalPort == other.internalPort\n                && internetProtocol == other.internetProtocol;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerState.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.container.orchestration;\n\n/**\n * Enum representing the possible container states as tracked by the orchestrator\n *\n * @since 2.3\n */\npublic enum ContainerState {\n    STARTING,\n    INSTALLED,\n    ACTIVE,\n    FAILED,\n    STOPPING;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ImageConfiguration.java",
    "content": "/***************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Object which represents an Image configuration used to request the generation\n * of a new image instance\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.4\n *\n */\n@ProviderType\npublic class ImageConfiguration {\n\n    private String imageName;\n    private String imageTag;\n    private Optional<RegistryCredentials> registryCredentials;\n    private int imageDownloadTimeoutSeconds = 500;\n\n    private ImageConfiguration() {\n    }\n\n    /**\n     * Returns an Image's name as a String.\n     * \n     * @return\n     */\n    public String getImageName() {\n        return this.imageName;\n    }\n\n    /**\n     * Returns an Image's tag as a String.\n     * \n     * @return\n     */\n    public String getImageTag() {\n        return this.imageTag;\n    }\n\n    /**\n     * Returns an Image's download timeout time as a int.\n     * \n     * @return\n     */\n    public int getimageDownloadTimeoutSeconds() {\n        return this.imageDownloadTimeoutSeconds;\n    }\n\n    /**\n     * Returns the Registry credentials\n     *\n     * @return\n     */\n    public Optional<RegistryCredentials> getRegistryCredentials() {\n        return this.registryCredentials;\n    }\n\n    /**\n     * Creates a builder for creating a new {@link ImageConfiguration} instance.\n     *\n     * @return the builder.\n     */\n    public static ImageConfigurationBuilder builder() {\n        return new ImageConfigurationBuilder();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.imageName, this.imageTag, this.registryCredentials);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof ImageConfiguration)) {\n            return false;\n        }\n        ImageConfiguration other = (ImageConfiguration) obj;\n        return Objects.equals(this.imageName, other.imageName) && Objects.equals(this.imageTag, other.imageTag)\n                && Objects.equals(this.registryCredentials, other.registryCredentials);\n    }\n\n    public static final class ImageConfigurationBuilder {\n\n        private String imageName;\n        private String imageTag = \"latest\";\n        private Optional<RegistryCredentials> registryCredentials;\n        private int imageDownloadTimeoutSeconds = 500;\n\n        public ImageConfigurationBuilder setImageName(String imageName) {\n            this.imageName = imageName;\n            return this;\n        }\n\n        public ImageConfigurationBuilder setImageTag(String imageTag) {\n            this.imageTag = imageTag;\n            return this;\n        }\n\n        public ImageConfigurationBuilder setRegistryCredentials(Optional<RegistryCredentials> registryCredentials) {\n            this.registryCredentials = registryCredentials;\n            return this;\n        }\n\n        public ImageConfigurationBuilder setImageDownloadTimeoutSeconds(int imageDownloadTimeoutSeconds) {\n            this.imageDownloadTimeoutSeconds = imageDownloadTimeoutSeconds;\n            return this;\n        }\n\n        public ImageConfiguration build() {\n            ImageConfiguration result = new ImageConfiguration();\n\n            result.imageName = requireNonNull(this.imageName, \"Request Image Name cannot be null\");\n            result.imageTag = this.imageTag;\n            result.registryCredentials = requireNonNull(this.registryCredentials,\n                    \"Request Registry Credentials object cannot be null.\");\n            result.imageDownloadTimeoutSeconds = this.imageDownloadTimeoutSeconds;\n\n            return result;\n        }\n\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ImageInstanceDescriptor.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Object which represents an image. Used to track created images, and images\n * that exist in the container engine.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.4\n *\n */\n@ProviderType\npublic class ImageInstanceDescriptor {\n\n    private String imageName = \"\";\n    private String imageTag = \"\";\n    private String imageId = \"\";\n    private String imageAuthor = \"\";\n    private String imageArch = \"\";\n    private long imageSize = 0;\n    private Map<String, String> imageLabels = new HashMap<>();\n\n    private ImageInstanceDescriptor() {\n    }\n\n    /**\n     * Returns an Image's name as a String.\n     * \n     * @return\n     */\n    public String getImageName() {\n        return this.imageName;\n    }\n\n    /**\n     * Returns an Image's tag as a String.\n     * \n     * @return\n     */\n    public String getImageTag() {\n        return this.imageTag;\n    }\n\n    /**\n     * Returns an Image's id as a String.\n     * \n     * @return\n     */\n    public String getImageId() {\n        return imageId;\n    }\n\n    /**\n     * Returns an Image's author as a String.\n     * \n     * @return\n     */\n    public String getImageAuthor() {\n        return imageAuthor;\n    }\n\n    /**\n     * Returns an Image's architecture as a String.\n     * \n     * @return\n     */\n    public String getImageArch() {\n        return imageArch;\n    }\n\n    /**\n     * Returns an Image's size as a long.\n     * \n     * @return\n     */\n    public long getImageSize() {\n        return imageSize;\n    }\n\n    /**\n     * Returns all of an Image's tags as a Map<String,String>.\n     * \n     * @return\n     */\n    public Map<String, String> getImageLabels() {\n        return imageLabels;\n    }\n\n    /**\n     * Creates a builder for creating a new {@link ImageInstanceDescriptor}\n     * instance.\n     *\n     * @return the builder.\n     */\n    public static ImageInstanceDescriptorBuilder builder() {\n        return new ImageInstanceDescriptorBuilder();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.imageName, this.imageTag, this.imageId, this.imageAuthor, this.imageArch,\n                this.imageSize, this.imageLabels);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof ImageInstanceDescriptor)) {\n            return false;\n        }\n        ImageInstanceDescriptor other = (ImageInstanceDescriptor) obj;\n        return Objects.equals(this.imageName, other.imageName) && Objects.equals(this.imageTag, other.imageTag)\n                && Objects.equals(this.imageId, other.imageId) && Objects.equals(this.imageAuthor, other.imageAuthor)\n                && Objects.equals(this.imageArch, other.imageArch) && Objects.equals(this.imageSize, other.imageSize)\n                && Objects.equals(this.imageLabels, other.imageLabels);\n    }\n\n    public static final class ImageInstanceDescriptorBuilder {\n\n        private String imageName;\n        private String imageTag;\n        private String imageId;\n        private String imageAuthor;\n        private String imageArch;\n        private long imageSize;\n        private Map<String, String> imageLabels = new HashMap<>();\n\n        public ImageInstanceDescriptorBuilder setImageName(String imageName) {\n            this.imageName = nullToEmpty(imageName);\n            return this;\n        }\n\n        public ImageInstanceDescriptorBuilder setImageTag(String imageTag) {\n            this.imageTag = nullToEmpty(imageTag);\n            return this;\n        }\n\n        public ImageInstanceDescriptorBuilder setImageId(String imageId) {\n            this.imageId = nullToEmpty(imageId);\n            return this;\n        }\n\n        public ImageInstanceDescriptorBuilder setImageAuthor(String imageAuthor) {\n            this.imageAuthor = nullToEmpty(imageAuthor);\n            return this;\n        }\n\n        public ImageInstanceDescriptorBuilder setImageArch(String imageArch) {\n            this.imageArch = nullToEmpty(imageArch);\n            return this;\n        }\n\n        public ImageInstanceDescriptorBuilder setimageSize(long imageSize) {\n            this.imageSize = imageSize;\n            return this;\n        }\n\n        public ImageInstanceDescriptorBuilder setImageLabels(Map<String, String> imageLabels) {\n            this.imageLabels = imageLabels;\n            return this;\n        }\n\n        public ImageInstanceDescriptor build() {\n            ImageInstanceDescriptor result = new ImageInstanceDescriptor();\n\n            result.imageName = this.imageName;\n            result.imageTag = this.imageTag;\n            result.imageId = requireNonNull(this.imageId, \"Image ID cannot be null\");\n            result.imageAuthor = this.imageAuthor;\n            result.imageArch = this.imageArch;\n            result.imageSize = this.imageSize;\n            result.imageLabels = requireNonNull(this.imageLabels, \"ImageLabels must not be null\");\n\n            return result;\n        }\n\n        private String nullToEmpty(String input) {\n            if (input == null) {\n                return \"\";\n            } else {\n                return input;\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/PasswordRegistryCredentials.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration;\n\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.eclipse.kura.configuration.Password;\n\n/**\n * Stores the credentials for password authentication to Container Orchestration registry\n * The password provided is managed as {@link org.eclipse.kura.configuration.Password} and is encrypted by the\n * {@link org.eclipse.kura.crypto.CryptoService#encryptAes(char[])}\n *\n * @since 2.3\n */\npublic class PasswordRegistryCredentials implements RegistryCredentials {\n\n    private final Optional<String> url;\n    private final String username;\n    private final Password password;\n\n    public PasswordRegistryCredentials(Optional<String> url, String username, Password password) {\n        super();\n        this.url = url;\n        this.username = username;\n        this.password = password;\n    }\n\n    public Optional<String> getUrl() {\n        return this.url;\n    }\n\n    public String getUsername() {\n        return this.username;\n    }\n\n    public Password getPassword() {\n        return this.password;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(Arrays.hashCode(this.password.getPassword()), this.url, this.username);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof PasswordRegistryCredentials)) {\n            return false;\n        }\n        PasswordRegistryCredentials other = (PasswordRegistryCredentials) obj;\n        return Arrays.equals(this.password.getPassword(), other.password.getPassword())\n                && Objects.equals(this.url, other.url) && Objects.equals(this.username, other.username);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/PortInternetProtocol.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.container.orchestration;\n\n/**\n * \n * This is an enum containing all supported internet protocols that can be run at a port in a container.\n * \n * @since 2.5\n *\n */\npublic enum PortInternetProtocol {\n    TCP,\n    UDP,\n    SCTP\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/RegistryCredentials.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration;\n\n/**\n * Marker interface for Remote Repository Credentials\n *\n * @since 2.3\n *\n */\npublic interface RegistryCredentials {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/listener/ContainerOrchestrationServiceListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.container.orchestration.listener;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Listener interface to be implemented by applications that needs to be notified of events in the\n * {@link org.eclipse.kura.container.orchestration.ContainerOrchestrationService}.\n * All registered listeners are called synchronously by the\n * {@link org.eclipse.kura.container.orchestration.ContainerOrchestrationService} at the\n * occurrence of the event.\n * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this\n * interface.\n *\n * @since 2.3\n */\n@ConsumerType\npublic interface ContainerOrchestrationServiceListener {\n\n    /**\n     * Notifies the listener that the connection to the orchestrator service is established.\n     */\n    public void onConnect();\n\n    /**\n     * Notifies the listener that the connection to the orchestrator service has been lost.\n     */\n    public void onDisconnect();\n\n    /**\n     * Notifies the listener that the connection to the orchestrator service has been disabled\n     */\n    public void onDisabled();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/listener/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides interfaces to listen to notifications from for container orchestrator.\n */\npackage org.eclipse.kura.container.orchestration.listener;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides interfaces for container orchestration.\n */\npackage org.eclipse.kura.container.orchestration;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/signature/ContainerSignatureValidationService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.container.signature;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.container.orchestration.ImageInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.RegistryCredentials;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Interface representing a service for validating the signature of a container image\n *\n * @since 2.7\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface ContainerSignatureValidationService {\n\n    /**\n     * Verifies the signature of a container image using the provided trust anchor. The trust anchor format depends on\n     * the signature format. For example, if the signature was generated with Cosign, the trust anchor is a ECDSA public\n     * key in PEM format. Other signature formats may require different trust anchors.\n     *\n     * If the signature is not included in a transparency log, the verification will fail unless the\n     * verifyInTransparencyLog is set to false.\n     *\n     * If the image is signed with a different protocol the verification will fail.\n     *\n     * If the device running the verification has no internet access and the signature verification process has no\n     * offline support, the verification will fail. Implementers can choose to throw an exception in this case.\n     *\n     * @param imageName\n     *            The image name of the container image to verify. The value will need to be expressed in the form of\n     *            registryURL/imagename in case of a custom registry.\n     * @param imageReference\n     *            The image tag (e.g. \"latest\") or the image digest (e.g. \"sha256:xxxx\") of the container image to\n     *            verify. @warning For improved security, it is recommended to use the image digest as input.\n     * @param trustAnchor\n     *            The trust anchor to use for verification (e.g. a public key or a x509 certificate) typically in PEM\n     *            format. The trust anchor is used to verify the signature of the container image.\n     * @param verifyInTransparencyLog\n     *            Sets the transparency log verification, to be used when an artifact signature has been uploaded to the\n     *            transparency log. Artifacts cannot be publicly verified when not included in a log.\n     * @return {@link:ValidationResult}\n     */\n    public ValidationResult verify(String imageName, String imageReference, String trustAnchor,\n            boolean verifyInTransparencyLog) throws KuraException;\n\n    /**\n     * Verifies the signature of a container image using the provided trust anchor and the provided registry\n     * credentials.\n     * The trust anchor format depends on the signature format. For example, if the signature was generated with Cosign,\n     * the trust anchor is a ECDSA public key in PEM format. Other signature formats may require different trust\n     * anchors.\n     *\n     * If the signature is not included in a transparency log, the verification will fail unless the\n     * verifyInTransparencyLog is set to false.\n     *\n     * If the image is signed with a different protocol the verification will fail.\n     *\n     * If the device running the verification has no internet access and the signature verification process has no\n     * offline support, the verification will fail. Likewise if the registry credentials are wrong, the verification\n     * will fail. Implementers can choose to throw an exception in both these cases.\n     *\n     * @param imageName\n     *            The image name of the container image to verify. The value will need to be expressed in the form of\n     *            registryURL/imagename in case of a custom registry.\n     * @param imageReference\n     *            The image tag (e.g. \"latest\") or the image digest (e.g. \"sha256:xxxx\") of the container image to\n     *            verify. @warning For improved security, it is recommended to use the image digest as input.\n     * @param trustAnchor\n     *            The trust anchor to use for verification (e.g. a public key or a x509 certificate) typically in PEM\n     *            format. The trust anchor is used to verify the signature of the container image.\n     * @param verifyInTransparencyLog\n     *            Sets the transparency log verification, to be used when an artifact signature has been uploaded to the\n     *            transparency log. Artifacts cannot be publicly verified when not included in a log.\n     * @param credentials\n     *            Credentials for registry authentication. If the registry requires authentication,\n     *            this needs to be provided to verify the signature. See {@link RegistryCredentials}.\n     * @return {@link:ValidationResult}\n     */\n    public ValidationResult verify(String imageName, String imageReference, String trustAnchor,\n            boolean verifyInTransparencyLog, RegistryCredentials credentials) throws KuraException;\n\n    /**\n     * Verifies the signature of a container image using the provided trust anchor. The trust anchor format depends on\n     * the signature format. For example, if the signature was generated with Cosing, the trust anchor is a ECDSA public\n     * key in PEM format. Other signature formats may require different trust anchors.\n     *\n     * If the signature is not included in a transparency log, the verification will fail unless the\n     * verifyInTransparencyLog is set to false.\n     *\n     * If the image is signed with a different protocol the verification will fail.\n     *\n     * If the device running the verification has no internet access and the signature verification process has no\n     * offline support, the verification will fail. Implementers can choose to throw an exception in this case.\n     *\n     * @param imageDescriptor\n     *            The image descriptor of the container image to verify (see {@link ImageInstanceDescriptor})\n     * @param trustAnchor\n     *            The trust anchor to use for verification (e.g. a public key or a x509 certificate) typically in PEM\n     *            format. The trust anchor is used to verify the signature of the container image.\n     * @param verifyInTransparencyLog\n     *            Sets the transparency log verification, to be used when an artifact signature has been uploaded to the\n     *            transparency log. Artifacts cannot be publicly verified when not included in a log.\n     * @return {@link:ValidationResult}\n     */\n    public ValidationResult verify(ImageInstanceDescriptor imageDescriptor, String trustAnchor,\n            boolean verifyInTransparencyLog) throws KuraException;\n\n    /**\n     * Verifies the signature of a container image using the provided trust anchor and the provided registry\n     * credentials.\n     * The trust anchor format depends on the signature format. For example, if the signature was generated with Cosing,\n     * the trust anchor is a ECDSA public key in PEM format. Other signature formats may require different trust\n     * anchors.\n     *\n     * If the signature is not included in a transparency log, the verification will fail unless the\n     * verifyInTransparencyLog is set to false.\n     *\n     * If the image is signed with a different protocol the verification will fail.\n     *\n     * If the device running the verification has no internet access and the signature verification process has no\n     * offline support, the verification will fail. Likewise if the registry credentials are wrong, the verification\n     * will fail. Implementers can choose to throw an exception in both these cases.\n     *\n     * @param imageDescriptor\n     *            The image descriptor of the container image to verify (see {@link ImageInstanceDescriptor})\n     * @param trustAnchor\n     *            The trust anchor to use for verification (e.g. a public key or a x509 certificate) typically in PEM\n     *            format. The trust anchor is used to verify the signature of the container image.\n     * @param verifyInTransparencyLog\n     *            Sets the transparency log verification, to be used when an artifact signature has been uploaded to the\n     *            transparency log. Artifacts cannot be publicly verified when not included in a log.\n     * @param credentials\n     *            Credentials for registry authentication. If the registry requires authentication,\n     *            this needs to be provided to verify the signature. See {@link RegistryCredentials}.\n     * @return {@link:ValidationResult}\n     */\n    public ValidationResult verify(ImageInstanceDescriptor imageDescriptor, String trustAnchor,\n            boolean verifyInTransparencyLog, RegistryCredentials credentials) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/signature/ValidationResult.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.container.signature;\n\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Class representing the result of the signature validation performed by {@link:ContainerSignatureValidationService}\n * \n * The validation result is composed of two main parts: whether or not the container image signature was\n * validated and the container image digest (in the \"algorithm:encoded\" format, @see\n * <a href=\"https://github.com/opencontainers/image-spec/blob/main/descriptor.md#digests\">Opencontainers specs</a>)\n *\n * If the signature is valid, the image digest MUST be provided.\n *\n * @since 2.7\n */\n@ProviderType\npublic final class ValidationResult {\n\n    private boolean isSignatureValid = false;\n    private Optional<String> imageDigest = Optional.empty();\n\n    public ValidationResult() {\n        // Nothing to do\n    }\n\n    public ValidationResult(boolean signatureValid, String digest) {\n        if (Objects.isNull(signatureValid) || Objects.isNull(digest)) {\n            throw new NullPointerException(\"Signature results and digest cannot be null.\");\n        }\n\n        if (signatureValid && digest.isEmpty()) {\n            throw new IllegalArgumentException(\"Image digest must be provided when signature is valid.\");\n        }\n\n        this.imageDigest = Optional.of(digest);\n        this.isSignatureValid = signatureValid;\n    }\n\n    public boolean isSignatureValid() {\n        return this.isSignatureValid;\n    }\n\n    public Optional<String> imageDigest() {\n        return this.imageDigest;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        ValidationResult other = (ValidationResult) obj;\n        return this.isSignatureValid == other.isSignatureValid && this.imageDigest.equals(other.imageDigest);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.isSignatureValid, this.imageDigest);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/signature/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides interfaces for container signature verification.\n */\npackage org.eclipse.kura.container.signature;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/crypto/CryptoService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.crypto;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\n\nimport javax.crypto.BadPaddingException;\nimport javax.crypto.IllegalBlockSizeException;\nimport javax.crypto.NoSuchPaddingException;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The CryptoService is used to provide AES encrypt and decrypt functionality, Base64 encoding and\n * decoding, and hash generation.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface CryptoService {\n\n    /**\n     * Returns an AES encrypted char array based on the provided value.\n     *\n     * @param value\n     *            A char array that will be encrypted.\n     * @return The char array representing the encrypted value.\n     * @throws KuraException\n     */\n    public char[] encryptAes(char[] value) throws KuraException;\n\n    /**\n     * Returns an OutputStream that encrypts provided data using AES in the same way as the encryptAes(char[]) method,\n     * and then writes it to the supplied OutputStream lazily. *\n     * \n     * @param streamToEncrypt\n     *            The OutputStream on which the encrypted data will be written.\n     * @return The OutputStream able to encrypt data.\n     * @throws KuraException\n     * @since 3.0\n     */\n    public OutputStream aesEncryptingStream(OutputStream destination) throws KuraException;\n\n    /**\n     * Returns an InputStream that decrypts data obtained from the supplied stream using AES in the same way as the\n     * decryptAes(char[]) method.\n     *\n     * @param streamToDecrypt\n     *            The InputStream to read the encrypted data from.\n     * @return InputStream able to decrypt data.\n     * @throws KuraException\n     * @since 3.0\n     */\n    public InputStream aesDecryptingStream(InputStream source) throws KuraException;\n\n    /**\n     * Returns a char array based on the provided encrypted value.\n     *\n     * @param encryptedValue\n     *            A char array representing the value to be decrypted.\n     * @return char[] that has been decrypted.\n     * @throws KuraException\n     */\n    public char[] decryptAes(char[] encryptedValue) throws KuraException;\n\n    /**\n     * Returns an AES encrypted string based on the provided value.\n     *\n     * @param value\n     *            A string that will be encrypted.\n     * @return String that has been encrypted.\n     * @throws NoSuchAlgorithmException\n     * @throws NoSuchPaddingException\n     * @throws InvalidKeyException\n     * @throws IllegalBlockSizeException\n     * @throws BadPaddingException\n     * @deprecated Use {@link #encryptAes(char[]) instead\n     */\n    @Deprecated\n    public String encryptAes(String value) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,\n            IllegalBlockSizeException, BadPaddingException;\n\n    /**\n     * Returns a plain text string based on the provided encrypted value.\n     *\n     * @param encryptedValue\n     *            A string representing the value to be decrypted.\n     * @return String that has been decrypted.\n     * @throws NoSuchAlgorithmException\n     * @throws NoSuchPaddingException\n     * @throws InvalidKeyException\n     * @throws IOException\n     * @throws IllegalBlockSizeException\n     * @throws BadPaddingException\n     * @deprecated Use {@link #decryptAes(char[])} instead\n     */\n    @Deprecated\n    public String decryptAes(String encryptedValue) throws NoSuchAlgorithmException, NoSuchPaddingException,\n            InvalidKeyException, IOException, IllegalBlockSizeException, BadPaddingException;\n\n    /**\n     * Returns a SHA1 hashed value of the provided string s.\n     *\n     * @param s\n     *            A string on which to run the SHA1 hashing algorithm.\n     * @return String that has been hashed.\n     * @throws NoSuchAlgorithmException\n     * @throws UnsupportedEncodingException\n     */\n    default String sha1Hash(String s) throws NoSuchAlgorithmException, UnsupportedEncodingException {\n        return hash(s, \"SHA-1\");\n    }\n\n    /**\n     * Returns a SHA-256 hashed value of the provided string s.\n     *\n     * @param s\n     *            A string on which to run the SHA-256 hashing algorithm.\n     * @return String that has been hashed.\n     * @throws NoSuchAlgorithmException\n     * @throws UnsupportedEncodingException\n     * @since 2.2\n     */\n    default String sha256Hash(String s) throws NoSuchAlgorithmException, UnsupportedEncodingException {\n        return hash(s, \"SHA-256\");\n    }\n\n    /**\n     * Returns an hashed value of the provided string s.\n     *\n     * @param s\n     *            A string on which to run the hashing algorithm.\n     * @param algorithm\n     *            A String representing the hashing algorithm to be applied\n     * @return String that has been hashed.\n     * @throws NoSuchAlgorithmException\n     * @throws UnsupportedEncodingException\n     * @since 2.2\n     */\n    public String hash(String s, String algorithm) throws NoSuchAlgorithmException, UnsupportedEncodingException;\n\n    /**\n     * Returns an encoded string based on the provided stringValue.\n     *\n     * @param stringValue\n     *            A string to be encoded.\n     * @return String that has been encoded.\n     * @throws NoSuchAlgorithmException\n     * @throws UnsupportedEncodingException\n     */\n    public String encodeBase64(String stringValue) throws NoSuchAlgorithmException, UnsupportedEncodingException;\n\n    /**\n     * Returns a decoded string based on the provided encodedValue.\n     *\n     * @param encodedValue\n     *            A string to be decoded.\n     * @return String that has been decoded.\n     * @throws NoSuchAlgorithmException\n     * @throws UnsupportedEncodingException\n     */\n    public String decodeBase64(String encodedValue) throws NoSuchAlgorithmException, UnsupportedEncodingException;\n\n    /**\n     * Takes a keystore path and returns the corresponding password that can be\n     * used to access to the data saved in the specified keystore.\n     *\n     * @param keyStorePath\n     *            A String that represents a unique identifier of the specified keystore.\n     * @return A char array that represents the password of the specified keystore.\n     */\n    public char[] getKeyStorePassword(String keyStorePath);\n\n    /**\n     * Takes a keystore path as a String and a char array representing a password\n     * that has to be stored for the specified keystore.\n     *\n     * @param keyStorePath\n     *            A String that represents a unique identifier of the specified keystore.\n     * @param password\n     *            A char array that represents the password of the specified keystore.\n     * @throws KuraException\n     */\n    public void setKeyStorePassword(String keyStorePath, char[] password) throws KuraException;\n\n    /**\n     * Takes a keystore path as a String and a char array representing a password\n     * that has to be stored for the specified keystore.\n     *\n     * @param keyStorePath\n     *            A String that represents a unique identifier of the specified keystore.\n     * @param password\n     *            A String that represents the password of the specified keystore.\n     * @throws IOException\n     * @deprecated Use {@link #setKeyStorePassword(String, char[])} instead\n     */\n    @Deprecated\n    public void setKeyStorePassword(String keyStorePath, String password) throws IOException;\n\n    /**\n     * Answers if the Kura framework is running in security mode.\n     *\n     * @return true if the framework is running in security mode.\n     */\n    public boolean isFrameworkSecure();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/crypto/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Contains interfaces to cryptographic functions and used to abstract the effective implementation.\n *\n */\npackage org.eclipse.kura.crypto;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.data;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraNotConnectedException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.KuraTimeoutException;\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The DataService provides the ability of connecting to a remote\n * broker, publish messages, subscribe to topics, receive messages on the\n * subscribed topics, and disconnect from the remote message broker.\n * The DataService delegates to the {@link DataTransportService} the implementation\n * of the transport protocol used to interact with the remote server.\n * <br>\n * The DataService offers methods and configuration options to manage the\n * connection to the remote server. For example, it can be configured\n * to auto-connect to the remote server on start-up or it offers\n * methods for applications to directly manage the connection.\n * It also adds the capability of storing published messages in a persistent store\n * and send them over the wire at a later time.\n * The purpose is to relieve service users from implementing their own persistent store.\n * Service users may publish messages independently on the DataService connection status.\n * <br>\n * In order to overcome the potential latencies introduced by buffering messages,\n * the DataService allows to assign a priority level to each published message.\n * Dependently on the store configuration there are certain guarantees that stored\n * messages are not lost due to sudden crashes or power outages.\n * <br>\n * The <a href=\"http://www.osgi.org/wiki/uploads/Links/whiteboard.pdf\">whiteboard pattern</a>\n * is used to notify the service users about events such as message arrived, connection lost etc.\n * through the {@link DataServiceListener}.\n * {@see DataServiceListener}\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface DataService {\n\n    /**\n     * Connects to the broker if not already connected.\n     */\n    public void connect() throws KuraConnectException;\n\n    /**\n     * Answers if the DataService is connected to the broker.\n     *\n     * @return\n     */\n    public boolean isConnected();\n\n    public boolean isAutoConnectEnabled();\n\n    public int getRetryInterval();\n\n    /**\n     * Disconnects from the broker. This method will block, up to the specified\n     * duration, allowing the protocol implementation to complete delivery of\n     * in-flight messages before actually disconnecting from the broker.\n     * If the Data Service is configured to auto-connect on startup and it's\n     * explicitly disconnected it will not automatically reconnect.\n     *\n     * @param quiesceTimeout\n     */\n    public void disconnect(long quiesceTimeout);\n\n    /**\n     * Subscribes to the specified topic with the remote server.\n     * The method requires an active connection with the remote server and it is operates synchronously.\n     * The implementation is a pass-through to the {@link DataTransportService#subscribe} method.\n     *\n     * @param topic\n     * @param qos\n     * @throws KuraTimeoutException\n     * @throws KuraException\n     * @throws KuraNotConnectedException\n     *             TODO\n     */\n    public void subscribe(String topic, int qos) throws KuraTimeoutException, KuraException, KuraNotConnectedException;\n\n    /**\n     * Unubscribes to the specified topic with the remote server.\n     * The method requires an active connection with the remote server and it is operates synchronously.\n     * The implementation is a pass-through to the {@link DataTransportService#unsubscribe} method.\n     *\n     * @param topic\n     * @throws KuraTimeoutException\n     * @throws KuraException\n     * @throws KuraNotConnectedException\n     *             TODO\n     */\n    public void unsubscribe(String topic) throws KuraTimeoutException, KuraException, KuraNotConnectedException;\n\n    /**\n     * Publishes a message to the broker. This method quickly returns deferring\n     * the actual message publication accordingly to the current service policy\n     * and to the specified priority, 0 being the highest.\n     *\n     * Messages are confirmed asynchronously to the caller by the\n     * {@link DataServiceListener#onMessageConfirmed} callback.\n     *\n     * A unique identifier is always returned, independently on the specified\n     * QoS or priority level, which can be used to match the asynchronous\n     * message confirm.\n     *\n     * The actual semantics associated to a message confirm is as follows:\n     * <ul>\n     * <li>For messages published at QoS = 0, receiving the confirm just means that\n     * the message is about to be transmitted on the wire without any guarantee\n     * that it eventually will.\n     * <li>For messages published at QoS &gt; 0, receiving the confirm means that the\n     * broker acknowledged the message.\n     * </ul>\n     *\n     * Priority level 0 (highest) should be used sparingly and reserved for\n     * messages that should be sent with the minimum latency.\n     * For example Cloud life-cycle messages are published with priority 0\n     * as soon the connection is established and just before disconnecting.\n     * Priority must be non-negative.\n     * <br>\n     * Data messages, tolerating an higher latency, may be published with a\n     * lower priority. Within each priority level and each QoS level, messages\n     * are guaranteed do be delivered in order (oldest first).\n     * <br>\n     * The KuraStoreCapacityReachedException is thrown if the database buffer\n     * has reached its capacity for messages that are not yet published or\n     * they are still in transit. The limit does not apply to internal messages\n     * with the priority less than 2.\n     * These priority levels are reserved to the framework which uses it for life-cycle messages\n     * - birth and death certificates - and replies to request/response flows.\n     *\n     * @param topic\n     * @param payload\n     * @param qos\n     * @param retain\n     * @param priority\n     * @return\n     * @throws KuraStoreException If the message cannot be stored.\n     * @throws IllegalArgumentException If the priority argument is negative.\n     */\n    public int publish(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException;\n\n    /**\n     * Finds the list of identifiers of messages that have not been published yet.\n     * Given the service has no means of knowing who\n     * published the message, a regex topic must be specified in order to find\n     * only the relevant identifiers.\n     *\n     *\n     * @param topicRegex\n     * @return\n     * @throws KuraStoreException\n     */\n    List<Integer> getUnpublishedMessageIds(String topicRegex) throws KuraStoreException;\n\n    /**\n     * Finds the list of identifiers of messages that are still in-flight\n     * (messages published but not confirmed yet).\n     * This only applies to messages published with QoS &gt; 0.\n     * Given the service has no means of knowing who\n     * published the message, a regex topic must be specified in order to find\n     * only the relevant identifiers.\n     *\n     * @param topicRegex\n     * @return\n     * @throws KuraStoreException\n     */\n    List<Integer> getInFlightMessageIds(String topicRegex) throws KuraStoreException;\n\n    /**\n     * Finds the list of identifiers of in-flight messages that have been dropped.\n     * This only applies to messages published with QoS &gt; 0.\n     * On the establishment of a new connection, the service can be configured\n     * either to republish or drop in-flight messages.\n     * The former option can be used if service users tolerate publishing message\n     * duplicates.\n     * The latter option can be used it service users tolerate losing messages.\n     * Given the service has no means of knowing who\n     * published the message, a regex topic must be specified in order to find\n     * only the relevant identifiers.\n     */\n    List<Integer> getDroppedInFlightMessageIds(String topicRegex) throws KuraStoreException;\n\n    /**\n     * Adds a listener.\n     *\n     * @param listener\n     *\n     * @since 1.0.8\n     */\n    public void addDataServiceListener(DataServiceListener listener);\n\n    /**\n     * Removes a listener.\n     *\n     * @param listener\n     *\n     * @since 1.0.8\n     */\n    public void removeDataServiceListener(DataServiceListener listener);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataServiceListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.data;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Implementors of this interface will be able to handle {@link DataService}\n * events such as notifications of connection establishing, message arrival, etc.\n * In order to detect implementors, the {@link DataService} uses the the\n * <a href=\"http://www.osgi.org/wiki/uploads/Links/whiteboard.pdf\">whiteboard pattern</a>.\n * <br>\n * All registered listeners are called synchronously by the {@link DataService} at the occurrence of the event.\n * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this\n * interface.\n *\n * @deprecated As of {@link org.eclipse.kura.data} 1.1.0, use\n *             {@link DataService#addDataServiceListener(org.eclipse.kura.data.listener.DataServiceListener)}\n *             to register a listener to a DataService.\n */\n@Deprecated\n@ConsumerType\npublic interface DataServiceListener {\n\n    /**\n     * Notifies that the DataService has established a connection.\n     */\n    public void onConnectionEstablished();\n\n    /**\n     * Notifies that the DataService is about to cleanly disconnect. If\n     * something needs to be done in reaction to this event, e.g. publishing a\n     * special last message, it SHOULD be done before the method returns.\n     * As soon as the method returns the DataService will start disconnecting.\n     */\n    public void onDisconnecting();\n\n    /**\n     * Notifies that the DataService has cleanly disconnected.\n     */\n    public void onDisconnected();\n\n    /**\n     * Notifies that the DataService has unexpectedly disconnected.\n     */\n    public void onConnectionLost(Throwable cause);\n\n    /**\n     * Notifies a message arrival.\n     *\n     * @param topic\n     * @param payload\n     * @param qos\n     * @param retained\n     */\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained);\n\n    /**\n     * Notifies the a message has been published. There is no guarantee the\n     * message has been actually transmitted over the wire or that it eventually\n     * will. The only guarantee is that message byte have been passed to the\n     * underlying OS.\n     *\n     * @param messageId\n     */\n    public void onMessagePublished(int messageId, String topic);\n\n    /**\n     * Confirms message delivery to the broker.\n     *\n     * @param messageId\n     */\n    public void onMessageConfirmed(int messageId, String topic);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataTransportListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.data;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Listener interface to be implemented by applications that needs to be notified of events in the\n * {@link DataTransportService}.\n * All registered listeners are called synchronously by the {@link DataTransportService} at the occurrence of the event.\n * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this\n * interface.\n *\n * @deprecated As of {@link org.eclipse.kura.data} 1.1.0, use\n *             {@link DataTransportService#addDataTransportListener(org.eclipse.kura.data.transport.listener.DataTransportListener)}\n *             to register a listener to a DataTransportService.\n */\n@Deprecated\n@ConsumerType\npublic interface DataTransportListener {\n\n    /**\n     * Notifies the listener of the establishment of the new connection with the remote server.\n     *\n     * @param newSession\n     *            true if the connection is to the same broker with the same client ID.\n     */\n    public void onConnectionEstablished(boolean newSession);\n\n    /**\n     * Notifies the listener that the connection to the remote server is about to be terminated.\n     */\n    public void onDisconnecting();\n\n    /**\n     * Notifies the listener that the connection to the remote server has been terminated.\n     */\n    public void onDisconnected();\n\n    /**\n     * Notifies the {@link DataTransportService} has received a configuration update.\n     */\n    public void onConfigurationUpdating(boolean wasConnected);\n\n    /**\n     * Notifies the {@link DataTransportService} has received a configuration update and it has applied the new\n     * configuration\n     */\n    public void onConfigurationUpdated(boolean wasConnected);\n\n    /**\n     * Notifies the listener that the connection to the remote server has been lost.\n     */\n    public void onConnectionLost(Throwable cause);\n\n    /**\n     * Notifies the listener that a new message has been received from the remote server.\n     */\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained);\n\n    /**\n     * Notifies the listener that a message has been confirmed by the remote server.\n     */\n    public void onMessageConfirmed(DataTransportToken token);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataTransportService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.data;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraNotConnectedException;\nimport org.eclipse.kura.KuraTimeoutException;\nimport org.eclipse.kura.KuraTooManyInflightMessagesException;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * DataTransportService implementations provide the ability of connecting to a\n * remote broker, publish messages, subscribe to topics, receive messages on the\n * subscribed topics, and disconnect from the remote message broker.\n *\n * The <a href=\"http://www.osgi.org/wiki/uploads/Links/whiteboard.pdf\">whiteboard pattern</a>\n * is used to notify the service users about events such as message arrived, connection lost etc.\n * through the {@link DataTransportListener}\n *\n * {@see DataTransportListener}\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface DataTransportService {\n\n    /**\n     * Connects to the remote broker. This method will block until the\n     * connection is established or a timeout occurs. The actual configuration\n     * needed to establish a connection is protocol specific (e.g. MQTT) and is\n     * exposed through the ConfigurationAdmin.\n     *\n     * @throws KuraConnectException\n     *             the caller MAY retry connecting a later time.\n     */\n    public void connect() throws KuraConnectException;\n\n    /**\n     * Returns true if the DataTransportService is currently connected to the remote server.\n     */\n    public boolean isConnected();\n\n    public String getBrokerUrl();\n\n    /**\n     * Returns the account name associated with the DataTransportService\n     */\n    public String getAccountName();\n\n    public String getUsername();\n\n    public String getClientId();\n\n    /**\n     * Disconnects from the broker. This method will block, up to the specified\n     * duration, allowing the protocol implementation to complete delivery of\n     * in-flight messages before actually disconnecting from the broker.\n     *\n     * @param quiesceTimeout\n     *            - timeout in milliseconds that will be used before forcing a disconnect\n     */\n    public void disconnect(long quiesceTimeout);\n\n    /**\n     * Subscribes to a topic on the broker. This method MAY block until the\n     * underlying protocol message (e.g. the MQTT SUBSCRIBE message) is\n     * acknowledged by the broker or a timeout occurs. This message is\n     * idempotent so the caller may safely retry subscribing. The timeout\n     * interval used by the service is configurable through the\n     * ConfigurationService.\n     *\n     * @param topic\n     * @param qos\n     * @throws KuraTimeoutException\n     *             TODO\n     * @throws KuraException\n     * @throws KuraNotConnectedException\n     *             TODO\n     */\n    public void subscribe(String topic, int qos) throws KuraTimeoutException, KuraException, KuraNotConnectedException;\n\n    /**\n     * Unsubscribes to a topic on the broker. This method MAY block until the\n     * underlying protocol message (e.g. the MQTT UNSUBSCRIBE message) is\n     * acknowledged by the broker or a timeout occurs. The timeout\n     * interval used by the service is configurable through the\n     * ConfigurationService.\n     *\n     * @param topic\n     * @throws KuraTimeoutException\n     * @throws KuraException\n     * @throws KuraNotConnectedException\n     *             TODO\n     */\n    public void unsubscribe(String topic) throws KuraTimeoutException, KuraException, KuraNotConnectedException;\n\n    /**\n     * Enqueues a message for publishing with the underlying transport implementation.\n     * An active connection to the remote server is required.\n     *\n     * @param topic\n     * @param payload\n     * @param qos\n     * @param retain\n     * @return\n     * @throws KuraTooManyInflightMessagesException\n     * @throws KuraException\n     * @throws KuraNotConnectedException\n     *             TODO\n     */\n    public DataTransportToken publish(String topic, byte[] payload, int qos, boolean retain)\n            throws KuraTooManyInflightMessagesException, KuraException, KuraNotConnectedException;\n\n    /**\n     * Adds a listener.\n     *\n     * @param listener\n     *\n     * @since 1.0.8\n     */\n    public void addDataTransportListener(DataTransportListener listener);\n\n    /**\n     * Removes a listener.\n     *\n     * @param listener\n     *\n     * @since 1.0.8\n     */\n    public void removeDataTransportListener(DataTransportListener listener);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataTransportToken.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.data;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * DataTransportToken is an receipt returned by the {@link DataTransportService} after the publishing of a message.\n * Such receipt can be used to track and compare subsequence message confirmation callbacks.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class DataTransportToken {\n\n    private final int messageId;\n    private final String sessionId;\n\n    public DataTransportToken(int messageId, String sessionId) {\n        super();\n        this.messageId = messageId;\n        this.sessionId = sessionId;\n    }\n\n    public int getMessageId() {\n        return this.messageId;\n    }\n\n    public String getSessionId() {\n        return this.sessionId;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + this.messageId;\n        result = prime * result + (this.sessionId == null ? 0 : this.sessionId.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        DataTransportToken other = (DataTransportToken) obj;\n        if (this.messageId != other.messageId) {\n            return false;\n        }\n        if (this.sessionId == null) {\n            if (other.sessionId != null) {\n                return false;\n            }\n        } else if (!this.sessionId.equals(other.sessionId)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/listener/DataServiceListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.data.listener;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Implementors of this interface will be able to handle {@link org.eclipse.kura.data.DataService}\n * events such as notifications of connection establishing, message arrival, etc.\n * <br>\n * All registered listeners are called synchronously by the {@link org.eclipse.kura.data.DataService} at the occurrence\n * of the event.\n * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this\n * interface.\n *\n * @since 1.0.8\n */\n@ConsumerType\npublic interface DataServiceListener {\n\n    /**\n     * Notifies that the DataService has established a connection.\n     */\n    public void onConnectionEstablished();\n\n    /**\n     * Notifies that the DataService is about to cleanly disconnect. If\n     * something needs to be done in reaction to this event, e.g. publishing a\n     * special last message, it SHOULD be done before the method returns.\n     * As soon as the method returns the DataService will start disconnecting.\n     */\n    public void onDisconnecting();\n\n    /**\n     * Notifies that the DataService has cleanly disconnected.\n     */\n    public void onDisconnected();\n\n    /**\n     * Notifies that the DataService has unexpectedly disconnected.\n     */\n    public void onConnectionLost(Throwable cause);\n\n    /**\n     * Notifies a message arrival.\n     *\n     * @param topic\n     * @param payload\n     * @param qos\n     * @param retained\n     */\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained);\n\n    /**\n     * Notifies the a message has been published. There is no guarantee the\n     * message has been actually transmitted over the wire or that it eventually\n     * will. The only guarantee is that message byte have been passed to the\n     * underlying OS.\n     *\n     * @param messageId\n     */\n    public void onMessagePublished(int messageId, String topic);\n\n    /**\n     * Confirms message delivery to the broker.\n     *\n     * @param messageId\n     */\n    public void onMessageConfirmed(int messageId, String topic);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/listener/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides interfaces to listen to notifications from the Data Service.\n */\npackage org.eclipse.kura.data.listener;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides services for connecting and communicating with a MQTT broker.\n *\n */\npackage org.eclipse.kura.data;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/transport/listener/DataTransportListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.data.transport.listener;\n\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Listener interface to be implemented by applications that needs to be notified of events in the\n * {@link org.eclipse.kura.data.DataTransportService}.\n * All registered listeners are called synchronously by the {@link org.eclipse.kura.data.DataTransportService} at the\n * occurrence of the event.\n * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this\n * interface.\n *\n * @since 1.0.8\n */\n@ConsumerType\npublic interface DataTransportListener {\n\n    /**\n     * Notifies the listener of the establishment of the new connection with the remote server.\n     *\n     * @param newSession\n     *            true if the connection is to the same broker with the same client ID.\n     */\n    public void onConnectionEstablished(boolean newSession);\n\n    /**\n     * Notifies the listener that the connection to the remote server is about to be terminated.\n     */\n    public void onDisconnecting();\n\n    /**\n     * Notifies the listener that the connection to the remote server has been terminated.\n     */\n    public void onDisconnected();\n\n    /**\n     * Notifies the {@link org.eclipse.kura.data.DataTransportService} has received a configuration update.\n     */\n    public void onConfigurationUpdating(boolean wasConnected);\n\n    /**\n     * Notifies the {@link org.eclipse.kura.data.DataTransportService} has received a configuration update and it has\n     * applied the new\n     * configuration\n     */\n    public void onConfigurationUpdated(boolean wasConnected);\n\n    /**\n     * Notifies the listener that the connection to the remote server has been lost.\n     */\n    public void onConnectionLost(Throwable cause);\n\n    /**\n     * Notifies the listener that a new message has been received from the remote server.\n     */\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained);\n\n    /**\n     * Notifies the listener that a message has been confirmed by the remote server.\n     */\n    public void onMessageConfirmed(DataTransportToken token);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/transport/listener/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides interfaces to listen to notifications from the Data Transport Service.\n */\npackage org.eclipse.kura.data.transport.listener;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/BaseDbService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.db;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * {@link BaseDbService} offers APIs to acquire and use a JDBC Connection to the embedded SQL database running in the\n * framework.\n * The configuration of the {@link BaseDbService} will determine the configuration of the embedded SQL database.\n * The usage of API is typical for JDBC Connections; the connection is first acquired with getConnection(),\n * and it must be released when the operation is completed with close(). The implementation of the\n * DbService and the returned JdbcConnection will manage the concurrent access into the database appropriately.\n *\n * @since 1.3\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface BaseDbService {\n\n    /**\n     * Returns the JDBC Connection to be used to communicate with the embedded SQL database.\n     * For each acquired connection, the DbService.close() method must be called.\n     *\n     * @return Connection to be used\n     * @throws SQLException\n     */\n    public Connection getConnection() throws SQLException;\n\n    /**\n     * Releases a previously acquired JDCB connection to the DbService.\n     *\n     * @param conn\n     *            to be released\n     */\n    public void close(Connection conn);\n\n    /**\n     * Utility method to silently rollback a JDBC Connection without throwing SQLExcepton.\n     * The method will catch any SQLExcepton thrown and log it.\n     */\n    public void rollback(Connection conn);\n\n    /**\n     * Utility method to silently close a JDBC ResultSet without throwing SQLExcepton.\n     * The method will catch any SQLExcepton thrown and log it.\n     */\n    public void close(ResultSet... rss);\n\n    /**\n     * Utility method to silently close a JDBC Statement without throwing SQLExcepton.\n     * The method will catch any SQLExcepton thrown and log it.\n     */\n    public void close(Statement... stmts);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/H2DbService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.db;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A {@link H2DbService} instance provides an implementation of {@link BaseDbService} using the H2 database engine.\n *\n * The Kura core implementation of {@link H2DbService} provides the capability to perform periodic database\n * defragmentation.\n * Since H2 currently does not support online defragmentation, the database needs to be shut down to perform the\n * operation.\n *\n * Running the defragmentation will cause the existing connections obtained using the\n * {@link H2DbService#getConnection()} method to be closed, so applications must be prepared to reopen connections if\n * necessary.\n *\n * As an alternative, it is possible to use the {@link H2DbService#withConnection(ConnectionCallable)} method.\n *\n *\n * @since 1.3\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface H2DbService extends BaseDbService {\n\n    public static final String DEFAULT_INSTANCE_PID = \"org.eclipse.kura.db.H2DbService\";\n\n    /**\n     * Executes the provided {@link ConnectionCallable} task on the current thread, and returns the result.\n     * It is not necessary to close the {@link Connection} received as argument. If an exception is thrown by the task,\n     * the connection will be rolled back automatically.\n     *\n     * This method guarantees that the execution of the provided task will not be affected by the defragmentation\n     * process.\n     * Performing long running operations in the provided tasks might delay the defragmentation\n     * process.\n     *\n     * @param task\n     *            the task to be executed.\n     * @return the result of the executed task.\n     * @throws SQLException\n     *             if the provided task throws a {@link SQLException}.\n     * @since 2.0\n     */\n    public <T> T withConnection(ConnectionCallable<T> task) throws SQLException;\n\n    /**\n     * Represents a task that can be executed using the {@link H2DbService#withConnection(ConnectionCallable)} method.\n     *\n     * @param <T>\n     *            The return type of the task.\n     * @since 2.0\n     */\n    @FunctionalInterface\n    public interface ConnectionCallable<T> {\n\n        public T call(Connection connection) throws SQLException;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/keyvalue/KeyValueDbService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.db.keyvalue;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.connection.listener.ConnectionListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * {@link KeyValueDbService} provides APIs to use the functionalities a of a database capable of storing data in form of key-value pairs.\n *\n * @since 2.5.0\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface KeyValueDbService {\n\n    /**\n     * Adds a {@link ConnectionListener}.\n     *\n     * @param listener\n     *            to add\n     *\n     */\n    public void addListener(ConnectionListener listener);\n\n    /**\n     * Removes a {@link ConnectionListener}\n     *\n     * @param listener\n     *            to remove\n     *\n     */\n    public void removeListener(ConnectionListener listener);\n\n    /**\n     * Returns whether the database is connected or not.\n     */\n    public boolean isConnected();\n\n    /**\n     * Set a key with the specified value in the database\n     * \n     * @param key\n     *            the key name\n     * @param value\n     *            the value of the key as array of byte\n     * @throws KuraException\n     *             if the operation is unsuccessful\n     */\n    void set(String key, byte[] value) throws KuraException;\n\n    /**\n     * Set a key with the specified value in the database\n     * \n     * @param key\n     *            the key name\n     * @param value\n     *            the value of the key as a String. The string encondig is platform dependent\n     * @throws KuraException\n     *             if the operation is unsuccessful\n     */\n    void set(String key, String value) throws KuraException;\n\n    /**\n     * Get a key with the specified value in the database\n     * \n     * @param key\n     *            the key name\n     * \n     * @return the key value as byte array\n     * @throws KuraException\n     *             if the operation is unsuccessful\n     */\n    byte[] get(String key) throws KuraException;\n\n    /**\n     * Get a key with the specified value in the database\n     * \n     * @param key\n     *            the key name\n     * \n     * @return the key value as String. The string encondig is platform dependent\n     * @throws KuraException\n     *             if the operation is unsuccessful\n     */\n    String getAsString(String key) throws KuraException;\n\n    /**\n     * Delete a key with the specified value in the database\n     * \n     * @param key\n     *            the key name\n     * \n     * @throws KuraException\n     *             if the operation is unsuccessful\n     */\n    void delete(String key) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/keyvalue/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides APIs to use functionalities offered by the key-value databases running in the framework.\n *\n */\n\npackage org.eclipse.kura.db.keyvalue;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides APIs to acquire and use a JDBC Connection to the embedded SQL database running in the framework.\n *\n */\npackage org.eclipse.kura.db;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/deployment/hook/DeploymentHook.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.deployment.hook;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * <p>\n * This interface can be implemented by a client to define a DEPLOY-V2 Cloudlet hook.\n * {@link DeploymentHook} instances can be used to customize the behavior of the DEPLOY-V2\n * Cloudlet by executing user-defined code at specific stages of deployment requests.\n * </p>\n *\n * <p>\n * A {@link DeploymentHook} implementation must be registered as an OSGi service and it is identified by the\n * value of the {@code kura.service.pid} service property.\n * </p>\n *\n * <p>\n * In order for a registered hook to be used for a particular request the following conditions must\n * be verified:\n * </p>\n *\n * <ul>\n * <li>The request must provide a metric named {@code request.type} of string type.</li>\n * <li>The configuration of the DEPLOY-V2 cloudlet must contain a mapping beetween the received {@code request.type}\n * and the {@code kura.service.pid} of a registered {@link DeploymentHook} implementation.</li>\n * </ul>\n *\n * <p>\n * The associations between {@code request.type} and hook {@code kura.service.pid} are maintained in the configuration\n * of the DEPLOY-V2 Cloudlet and are modifiable using the Kura WEB Ui.\n * </p>\n *\n * <p>\n * The {@link DeploymentHook} methods can be executed at different stages of the {@code /EXEC/download} and\n * {@code /EXEC/install} as specified below.\n * </p>\n *\n * <table border=1>\n * <tr>\n * <th>Method</th>\n * <th>/EXEC/download</th>\n * <th>/EXEC/install</th>\n * </tr>\n * <tr>\n * <td>{@link DeploymentHook#preDownload(RequestContext, Map) preDownload()}</td>\n * <td>Called immediately after a valid request is received by the Cloudlet.</td>\n * <td>Never called.</td>\n * </tr>\n * <tr>\n * <td>{@link DeploymentHook#postDownload(RequestContext, Map) postDownload()}</td>\n * <td>Called immediately after the download is completed successfully, or immediately after the\n * {@code preDownload} method is called if the requested file already exists.\n * When this method is called the requested file should be available on the device.</td>\n * <td>Called immediately after a valid request is received by the Cloudlet, and only if the requested\n * file is available on the device</td>\n * </tr>\n * <tr>\n * <td>{@link DeploymentHook#postInstall(RequestContext, Map) postInstall()}</td>\n * <td>Called immediately after the downloaded deployment package/script has been successfully\n * installed/executed.</td>\n * <td>Called immediately after the downloaded deployment package/script has been successfully\n * installed/executed.</td>\n * </tr>\n * </table>\n *\n * <p>\n * If any of the methods specified by this interface throws an exception, the current request will be aborted.\n * </p>\n *\n * @since 1.3\n */\n@ConsumerType\npublic interface DeploymentHook {\n\n    /**\n     * This method is called at the {@code preDownload} phase, see class description for more details.\n     *\n     * @param context\n     *            a {@link RequestContext} instance representing the current DEPLOY-V2 request\n     * @param properties\n     *            an hook-specific map of properties\n     * @throws KuraException\n     *             if an exception is thrown the current request will be aborted\n     */\n    public void preDownload(RequestContext context, Map<String, Object> properties) throws KuraException;\n\n    /**\n     * This method is called at the {@code preDownload} phase, see class description for more details.\n     *\n     * @param context\n     *            a {@link RequestContext} instance representing the current DEPLOY-V2 request\n     * @param properties\n     *            an hook-specific map of properties\n     * @throws KuraException\n     *             if an exception is thrown the current request will be aborted\n     */\n    public void postDownload(RequestContext context, Map<String, Object> properties) throws KuraException;\n\n    /**\n     * This method is called at the {@code preDownload} phase, see class description for more details.\n     *\n     * @param context\n     *            a {@link RequestContext} instance representing the current DEPLOY-V2 request\n     * @param properties\n     *            an hook-specific map of properties\n     * @throws KuraException\n     *             if an exception is thrown the current request will be aborted\n     */\n    public void postInstall(RequestContext context, Map<String, Object> properties) throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/deployment/hook/RequestContext.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.deployment.hook;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class provides some context information describing a DEPLOY-V2 request.\n *\n * @since 1.3\n */\n@ProviderType\npublic class RequestContext {\n\n    private final String downloadFilePath;\n    private final String requestType;\n\n    /**\n     * Creates a new {@link RequestContext} instance.\n     *\n     * @param downloadFilePath\n     *            the path of the downloaded file\n     * @param requestType\n     *            the value of the {@code request.type} metric contained in the request\n     */\n    public RequestContext(String downloadFilePath, String requestType) {\n        this.downloadFilePath = downloadFilePath;\n        this.requestType = requestType;\n    }\n\n    /**\n     * Returns the path of the downloaded file.\n     *\n     * @return the path of the downloaded file\n     */\n    public String getDownloadFilePath() {\n        return this.downloadFilePath;\n    }\n\n    /**\n     * Returns the value of the {@code request.type} metric of the request.\n     *\n     * @return the value of the {@code request.type} metric\n     */\n    public String getRequestType() {\n        return this.requestType;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/deployment/hook/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides APIs that allow to customize the behavior of the DEPLOY-V2 Cloudlet by registering\n * {@link org.eclipse.kura.deployment.hook.DeploymentHook DeploymentHook} instances.\n *\n */\npackage org.eclipse.kura.deployment.hook;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/ChannelDescriptor.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.driver;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Interface ChannelDescriptor is mainly used to provide the protocol\n * specific channel descriptions which will be used by the assets in the Kura\n * Wires Visualization model. It would enable asset to provide its protocol\n * specific configurable properties.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n */\n@ProviderType\npublic interface ChannelDescriptor {\n\n    /**\n     * Returns the protocol specific descriptor. For using drivers in\n     * cooperation with Kura Wires Visualization, the implementors can return\n     * list of {@code AD}s to provide configurable properties for a\n     * {@link org.eclipse.kura.configuration.ConfigurableComponent}.<br/>\n     * <br/>\n     *\n     * This method is essentially needed by Kura Wires Visualization model and\n     * in case the implementors need to use specific driver implementation in\n     * complete isolation, the implementors can return {@code null}.<br/>\n     * <br/>\n     *\n     * Furthermore, some implementors can also provide custom objects. In such\n     * case, implementors must also provide another implementation for providing\n     * configurable properties of a {@link org.eclipse.kura.configuration.ConfigurableComponent} using the\n     * provided custom object. As currently the {@code AD} uses OSGi\n     * Configuration Admin service to provide configurable properties, the\n     * custom object class needs to use OSGi Configuration Admin service for\n     * that same purpose.\n     *\n     * @return the protocol specific descriptor\n     */\n    public Object getDescriptor();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/Driver.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n *\n *******************************************************************************/\npackage org.eclipse.kura.driver;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.channel.listener.ChannelListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Interface Driver is the main interface that all Kura specific\n * communication drivers have to implement and register as an OSGi service\n * instance. A driver often implements a communication protocol to interact with\n * the field devices (assets). The configuration as provided to the driver for\n * communicating with the field device (asset) is provided by user using the\n * configurable component of the actual driver which is internally managed by\n * the OSGi Configuration Admin service\n *\n * @see ChannelRecord\n * @see ChannelDescriptor\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n */\n@ProviderType\npublic interface Driver {\n\n    /**\n     * Each driver is identified by the value of this property in the Component Configuration\n     */\n    public static final String DRIVER_PID_PROPERTY_NAME = \"driver.pid\";\n\n    /**\n     * The Class ConnectionException is a driver specific exception which is\n     * essentially used to raise exception related to driver connection\n     */\n    public final class ConnectionException extends Exception {\n\n        /** The Constant serial version UID. */\n        private static final long serialVersionUID = 3050873377900124238L;\n\n        /**\n         * Instantiates a new connection exception.\n         */\n        public ConnectionException() {\n            super();\n        }\n\n        /**\n         * Instantiates a new connection exception.\n         *\n         * @param messsage\n         *            the exception message\n         */\n        public ConnectionException(final String messsage) {\n            super(messsage);\n        }\n\n        /**\n         * Instantiates a new connection exception.\n         *\n         * @param message\n         *            the exception message\n         * @param cause\n         *            the exception cause\n         */\n        public ConnectionException(final String message, final Throwable cause) {\n            super(message, cause);\n        }\n\n        /**\n         * Instantiates a new connection exception.\n         *\n         * @param cause\n         *            the exception cause\n         */\n        public ConnectionException(final Throwable cause) {\n            super(cause);\n        }\n\n    }\n\n    /**\n     * Attempts to connect to the asset. Before performing any\n     * read/write/monitor operation on the connection, a communication channel\n     * has to be opened using this method. If the connection attempt fails it\n     * throws a {@code ConnectionException}\n     *\n     * Some communication protocols are not connection oriented. That means no\n     * connection has to be built up in order to read or write data. In this\n     * case the connect function may optionally test if the asset is reachable.\n     *\n     * @throws ConnectionException\n     *             if the connection to the field device is interrupted\n     */\n    public void connect() throws ConnectionException;\n\n    /**\n     * Attempts to disconnect the already established communication channel.\n     *\n     * @throws ConnectionException\n     *             if the connection to the field device is interrupted\n     */\n    public void disconnect() throws ConnectionException;\n\n    /**\n     * Returns the protocol specific channel descriptor.\n     *\n     * @return the channel descriptor\n     */\n    public ChannelDescriptor getChannelDescriptor();\n\n    /**\n     * Reads the communication channels that correspond to the given channel\n     * records. The read result is returned by setting the value in the channel\n     * record. If for some reason no value can be read the value should be set\n     * anyways. In this case the channel flag needs to be specified in the channel\n     * record. The flag shall best describe the reason of failure. If no value\n     * is set the default error code is\n     * {@code DriverFlag#DRIVER_ERROR_UNSPECIFIED}. If the connection to the\n     * asset is interrupted, then any necessary resources that correspond to\n     * this connection should be cleaned up and a {@code ConnectionException}\n     * shall be thrown.\n     *\n     * @param records\n     *            the records hold the information of what channels are to be\n     *            read. They will be filled by this function with the records\n     *            already read.\n     * @throws ConnectionException\n     *             if the connection to the field device is interrupted\n     * @throws NullPointerException\n     *             if argument is null\n     * @throws IllegalArgumentException\n     *             if argument is empty\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the method is not implemented by the driver then specific\n     *             error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED}\n     *             needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException}\n     */\n    public void read(List<ChannelRecord> records) throws ConnectionException;\n\n    /**\n     * Registers channel listener for the provided channel configuration for a\n     * monitor operation on it.\n     *\n     * @param channelConfig\n     *            the channel configuration\n     * @param listener\n     *            the listener\n     * @throws ConnectionException\n     *             if the connection to the field device is interrupted\n     * @throws NullPointerException\n     *             any of the arguments is null\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the method is not implemented by the driver then specific\n     *             error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED}\n     *             needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException}\n     */\n    public void registerChannelListener(Map<String, Object> channelConfig, ChannelListener listener)\n            throws ConnectionException;\n\n    /**\n     * Unregisters a already registered channel listener which has been\n     * registered for a monitor operation.\n     *\n     * @param listener\n     *            the listener to unregister\n     * @throws ConnectionException\n     *             if the connection to the field device is interrupted\n     * @throws NullPointerException\n     *             if the argument is null\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the method is not implemented by the driver then specific\n     *             error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED}\n     *             needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException}\n     */\n    public void unregisterChannelListener(ChannelListener listener) throws ConnectionException;\n\n    /**\n     * Writes the data channels that correspond to the given channel records. The\n     * write result is returned by setting the driver flag\n     * {@code ChannelFlag#SUCCESS} in the channel records. If the\n     * connection to the asset is interrupted, then any necessary resources that\n     * correspond to this connection should be cleaned up and a\n     * {@code ConnectionException} shall be thrown.\n     *\n     * @param records\n     *            the records hold the information of what channels are to be\n     *            written and the values that are to written. They will be\n     *            filled by this function with a driver flag stating whether the\n     *            write process was successful or not.\n     * @throws ConnectionException\n     *             if the connection to the field device is interrupted\n     * @throws NullPointerException\n     *             if the argument is null\n     * @throws IllegalArgumentException\n     *             if the provided list is empty\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the method is not implemented by the driver then specific\n     *             error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED}\n     *             needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException}\n     */\n    public void write(List<ChannelRecord> records) throws ConnectionException;\n\n    /**\n     * This method allows the driver to perform protocol specific optimizations in order to accelerate the execution of\n     * batches of read requests having the same channel configuration.\n     * The result of this optimization will be returned by the driver as a {@link PreparedRead} instance that can be\n     * used to perform the requests.\n     * In order to improve efficiency a driver should validate the channel configuration of the provided channels during\n     * this method call.\n     * It is also permitted to the implementation of the {@link PreparedRead#execute()} and\n     * {@link PreparedRead#getChannelRecords()} methods to return the same {@link ChannelRecord} instances provided as\n     * an\n     * argument to this method.\n     * If the validation of the channel configuration fails for some channels, the driver must not throw an exception\n     * but it is required to return channel records with proper error flags set as a result of the\n     * {@link PreparedRead#execute()} call.\n     *\n     * @see PreparedRead\n     * @param records\n     *            The list of channel records that represent the request to be optimized.\n     * @return The {@link PreparedRead} instance\n     * @throws NullPointerException\n     *             if the provided list is null\n     */\n    public PreparedRead prepareRead(List<ChannelRecord> records);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/DriverService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n *\n *******************************************************************************/\npackage org.eclipse.kura.driver;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The interface DriverService is an utility service API to provide useful\n * methods for drivers\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n * @deprecated The functionality provided by this service can be replaced by simple calls to OSGi/DS APIs.\n */\n@ProviderType\n@Deprecated\npublic interface DriverService {\n\n    /**\n     * Gets the driver instance by the provided driver PID\n     * ({@code kura.service.pid}).\n     *\n     * @param driverPid\n     *            the driver PID to check\n     * @return the driver instance\n     * @throws NullPointerException\n     *             if the provided driver PID is null\n     */\n    public Driver getDriver(String driverPid);\n\n    /**\n     * Gets the driver PID. ({@code kura.service.pid}) by the provided driver\n     * instance\n     *\n     * @param driver\n     *            the driver instance to check\n     * @return the driver PID\n     * @throws NullPointerException\n     *             if the provided driver instance is null\n     */\n    public String getDriverPid(Driver driver);\n\n    /**\n     * Returns the list containing all the available driver instances\n     *\n     * @return the list of drivers available in service registry or empty list if no\n     *         drivers are available\n     */\n    public List<Driver> listDrivers();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/PreparedRead.java",
    "content": "/**\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n */\npackage org.eclipse.kura.driver;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.driver.Driver.ConnectionException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface represents an optimized request that can be performed by a driver.\n * Implementations of this interface are returned by a driver as a result of\n * a call to the {@link Driver#prepareRead(java.util.List)} method.\n *\n * @see Driver#prepareRead(java.util.List)\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n */\n@ProviderType\npublic interface PreparedRead extends AutoCloseable {\n\n    /**\n     * Performs the optimized read request described by this {@link PreparedRead} instance.\n     * In order to improve efficiency this method can return the same {@link ChannelRecord} instances that were supplied\n     * as arguments to the {@link Driver#prepareRead(List)} call that created this {@link PreparedRead}.\n     * The returned records should not be modified while a valid (not closed) {@link PreparedRead} holds a\n     * reference to them, otherwise unpredictable behavior can occur.\n     *\n     * @return the result of the request as a list of {@link ChannelRecord} instances.\n     * @throws KuraException\n     *             if the provided {@link PreparedRead} is not valid (for example if it has been closed)\n     * @throws ConnectionException\n     *             if the connection to the field device is interrupted\n     */\n    public List<ChannelRecord> execute() throws ConnectionException, KuraException;\n\n    /**\n     * Returns the list of channel records associated with this prepared read.\n     * In order to improve efficiency this method can return the same {@link ChannelRecord} instances that were supplied\n     * as arguments to the {@link Driver#prepareRead(List)} call that created this {@link PreparedRead}.\n     * The returned records should not be modified while a valid (not closed) {@link PreparedRead} holds a\n     * reference to them, otherwise unpredictable behavior can occur.\n     *\n     * @return The list of channel records associated with this prepared read.\n     */\n    public List<ChannelRecord> getChannelRecords();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/descriptor/DriverDescriptor.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.descriptor;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Class DriverDescriptor is responsible for storing the driver instance\n * configuration. This class can then be passed for serialization and is used to\n * map all the information related to a driver instance.<br>\n * <br>\n *\n * @see org.eclipse.kura.driver.Driver\n * @see org.eclipse.kura.driver.ChannelDescriptor\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.4\n */\n@ProviderType\npublic class DriverDescriptor {\n\n    private final String pid;\n    private final String factoryPid;\n    private final Object channelDescriptor;\n\n    public DriverDescriptor(String pid, String factoryPid, Object channelDescriptor) {\n        this.pid = pid;\n        this.factoryPid = factoryPid;\n        this.channelDescriptor = channelDescriptor;\n    }\n\n    public String getPid() {\n        return this.pid;\n    }\n\n    public String getFactoryPid() {\n        return this.factoryPid;\n    }\n\n    public Object getChannelDescriptor() {\n        return this.channelDescriptor;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/descriptor/DriverDescriptorService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.descriptor;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The DriverDescriptorService interface is an utility service API to get descriptors for drivers\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.4\n */\n@ProviderType\npublic interface DriverDescriptorService {\n\n    /**\n     * Returns the {@link DriverDescriptor} corresponding to the Driver instance\n     * identified by the provided Driver {@code kura.service.pid}.\n     *\n     * @param driverPid\n     *            the Driver {@code kura.service.pid} that identifies a Driver\n     *            Instance\n     * @return the {@link DriverDescriptor} corresponding to the provided method\n     *         argument. Or an empty Optional is the provided argument is not a Driver {@code kura.service.pid}\n     * @throws NullPointerException\n     *             if the provided driver PID is null\n     * @since 1.4\n     */\n    Optional<DriverDescriptor> getDriverDescriptor(String driverPid);\n\n    /**\n     * Returns a list of {@link DriverDescriptor} objects that correspond to the\n     * entire list of Driver Instances in the Framework.\n     *\n     * @return a list of {@link DriverDescriptor}\n     * @since 1.4\n     */\n    List<DriverDescriptor> listDriverDescriptors();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/descriptor/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n/**\n * Provides all necessary APIs for Driver Descriptors of Kura Asset Component Model\n *\n * @since 1.4\n */\npackage org.eclipse.kura.driver.descriptor;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides all necessary APIs for Drivers of Kura Asset Component Model\n *\n * @since 1.2\n */\npackage org.eclipse.kura.driver;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/Command.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.executor;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Arrays;\nimport java.util.Map;\n\nimport org.apache.commons.io.output.NullOutputStream;\n\n/**\n *\n * The Command class includes the informations needed by the {@link CommandExecutorService} to run a system command.\n * The only mandatory parameter is the commandLine that represents the command to be run:\n * </br>\n * </br>\n * &nbsp&nbsp Command command = new Command(\"ls -all\");\n * </br>\n * </br>\n * Optional parameters are:\n * <ul>\n * <li>directory : the directory where the command is run</li>\n * <li>environment : a map containing the environment variables needed by the command</li>\n * <li>out : the output stream representing the output of the command</li>\n * <li>err : the error stream representing the errors of the command</li>\n * <li>in : the input stream representing the input of the command</li>\n * <li>timeout : the timeout in seconds after that the command is stopped. -1 means infinite timeout.</li>\n * <li>signal : the {@link Signal} sent to the command to stop it after timeout</li>\n * <li>executeInAShell : a flag that indicates if the command should be executed in a shell/terminal. Default is\n * false.</li>\n * </ul>\n * \n * @since 2.2\n *\n */\npublic class Command {\n\n    private final String[] commandLine;\n    private String directory;\n    private Map<String, String> environment;\n    private int timeout = -1;\n    private Signal signal;\n    private boolean executeInAShell;\n    private OutputStream out;\n    private OutputStream err;\n    private InputStream in;\n\n    public Command(String[] commandLine) {\n        this.commandLine = commandLine;\n        this.out = new NullOutputStream();\n        this.err = new NullOutputStream();\n    }\n\n    public String[] getCommandLine() {\n        return this.commandLine;\n    }\n\n    public String getDirectory() {\n        return this.directory;\n    }\n\n    public void setDirectory(String directory) {\n        this.directory = directory;\n    }\n\n    public Map<String, String> getEnvironment() {\n        return this.environment;\n    }\n\n    public void setEnvironment(Map<String, String> environment) {\n        this.environment = environment;\n    }\n\n    public int getTimeout() {\n        return this.timeout;\n    }\n\n    public void setTimeout(int timeout) {\n        this.timeout = timeout;\n    }\n\n    public Signal getSignal() {\n        return this.signal;\n    }\n\n    public void setSignal(Signal signal) {\n        this.signal = signal;\n    }\n\n    public boolean isExecutedInAShell() {\n        return this.executeInAShell;\n    }\n\n    public void setExecuteInAShell(boolean executeInAShell) {\n        this.executeInAShell = executeInAShell;\n    }\n\n    public OutputStream getOutputStream() {\n        return this.out;\n    }\n\n    public void setOutputStream(OutputStream out) {\n        this.out = out;\n    }\n\n    public OutputStream getErrorStream() {\n        return this.err;\n    }\n\n    public void setErrorStream(OutputStream err) {\n        this.err = err;\n    }\n\n    public InputStream getInputStream() {\n        return this.in;\n    }\n\n    public void setInputStream(InputStream in) {\n        this.in = in;\n    }\n\n    @Override\n    public String toString() {\n        return String.join(\" \", this.commandLine);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + Arrays.hashCode(this.commandLine);\n        result = prime * result + (this.directory == null ? 0 : this.directory.hashCode());\n        result = prime * result + (this.environment == null ? 0 : this.environment.hashCode());\n        result = prime * result + (this.executeInAShell ? 1231 : 1237);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        Command other = (Command) obj;\n        if (!Arrays.equals(this.commandLine, other.commandLine)) {\n            return false;\n        }\n        if (this.directory == null) {\n            if (other.directory != null) {\n                return false;\n            }\n        } else if (!this.directory.equals(other.directory)) {\n            return false;\n        }\n        if (this.environment == null) {\n            if (other.environment != null) {\n                return false;\n            }\n        } else if (!this.environment.equals(other.environment)) {\n            return false;\n        }\n        if (this.executeInAShell != other.executeInAShell) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/CommandExecutorService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.executor;\n\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface provides methods for running system processes or executing system commands.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.2\n */\n@ProviderType\npublic interface CommandExecutorService {\n\n    /**\n     * Synchronously executes a system command.\n     *\n     * @param command\n     *            the {@link Command} to be executed\n     * @return a {@link CommandStatus} object\n     */\n    public CommandStatus execute(Command command);\n\n    /**\n     * Asynchronously executes a system command.\n     *\n     * @param command\n     *            the {@link Command} to be executed\n     * @param callback\n     *            the consumer called when the command returns\n     */\n    public void execute(Command command, Consumer<CommandStatus> callback);\n\n    /**\n     * Stops the system process identified by the given {@link Pid}.\n     *\n     * @param pid\n     *            the {@link Pid} of the process to be stopped\n     * @param signal\n     *            the {@link Signal} sent to the process to stop it. If null, a default signal will be sent.\n     *            The type of the default signal is implementation specific\n     * @return a boolean value that is true if the stop operation succeeded\n     */\n    public boolean stop(Pid pid, Signal signal);\n\n    /**\n     * Kills the system commands containing all the tokens in the given command line.\n     * If more processes are found, all of them will be killed.\n     *\n     * @param commandLine\n     *            the command to be killed\n     * @param signal\n     *            the {@link Signal} sent to the command to kill it. If null, a default signal will be sent.\n     *            The type of the default signal is implementation specific\n     * @return a boolean value that is true if the kill operation succeeded\n     */\n    public boolean kill(String[] commandLine, Signal signal);\n\n    /**\n     * Returns true if the process identified by the given Pid is running.\n     *\n     * @param pid\n     *            the {@link Pid} object of the process\n     * @return a boolean value that is true if the process is running\n     */\n    public boolean isRunning(Pid pid);\n\n    /**\n     * Returns true if at least one process containing all the tokens in the given command line is found.\n     * It is equivalent to !getPids(commandLine).isEmpty().\n     *\n     * @param commandLine\n     *            the command to be checked\n     * @return a boolean value that is true if the command is running\n     */\n    public boolean isRunning(String[] commandLine);\n\n    /**\n     * This method searches for running processes containing all the tokens in the command line.\n     * It returns a map whose keys are the commands found and the values are the associated {@link Pid}s.\n     *\n     * @param commandLine\n     *            the command line\n     * @return a map of commands and associated {@link Pid}\n     */\n    public Map<String, Pid> getPids(String[] commandLine);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/CommandStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.executor;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.apache.commons.io.output.NullOutputStream;\n\n/**\n *\n * The CommandStatus object is returned by the {@link CommandExecutorService} after the execution of a command.\n * It contains all the relevant informations about the result of the command execution.\n * <p>\n * The parameters are the following:\n * <ul>\n * <li>command : the command run by the {@link CommandExecutorService}</li>\n * <li>exitStatus : the {@link ExitStatus} of the command. A value other than 0 means an error. When the command is\n * stopped by timeout the exit value is 124.</li>\n * <li>isTimedout : a flag that signals that the command was stopped by timeout</li>\n * <li>outputStream : the output of the command</li>\n * <li>errorStream : the error stream of the command</li>\n * <li>inputStream : the input stream used to send data to the process</li>\n * </ul>\n * \n * @since 2.2\n *\n */\npublic class CommandStatus {\n\n    private Command command;\n    private ExitStatus exitStatus;\n    private OutputStream outputStream;\n    private OutputStream errorStream;\n    private InputStream inputStream;\n    private boolean isTimedout;\n\n    public CommandStatus(Command command, ExitStatus exitStatus) {\n        this.command = command;\n        this.exitStatus = exitStatus;\n        this.outputStream = new NullOutputStream();\n        this.errorStream = new NullOutputStream();\n        this.isTimedout = false;\n    }\n\n    public Command getCommand() {\n        return command;\n    }\n\n    public void setCommand(Command command) {\n        this.command = command;\n    }\n\n    public ExitStatus getExitStatus() {\n        return this.exitStatus;\n    }\n\n    public void setExitStatus(ExitStatus exitStatus) {\n        this.exitStatus = exitStatus;\n    }\n\n    public OutputStream getErrorStream() {\n        return this.errorStream;\n    }\n\n    public void setErrorStream(OutputStream errorStream) {\n        this.errorStream = errorStream;\n    }\n\n    public OutputStream getOutputStream() {\n        return this.outputStream;\n    }\n\n    public void setOutputStream(OutputStream outputStream) {\n        this.outputStream = outputStream;\n    }\n\n    public InputStream getInputStream() {\n        return this.inputStream;\n    }\n\n    public void setInputStream(InputStream inputStream) {\n        this.inputStream = inputStream;\n    }\n\n    public boolean isTimedout() {\n        return this.isTimedout;\n    }\n\n    public void setTimedout(boolean isTimedout) {\n        this.isTimedout = isTimedout;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/ExitStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.executor;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface provides a method to retrieve the exit status of a system command.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.2\n */\n@ProviderType\npublic interface ExitStatus {\n\n    /**\n     * Returns a value representing the exit status of a command or process\n     *\n     * @return an integer that represents the exit code\n     */\n    public int getExitCode();\n\n    /**\n     * Returns if a command or process is successful\n     *\n     * @return a boolean that is true if the command is successful, false otherwise\n     */\n    public boolean isSuccessful();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/Pid.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.executor;\n\n/**\n * @since 2.2\n */\npublic interface Pid {\n\n    public int getPid();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/PrivilegedExecutorService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.executor;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This is a marker interface for the {@link CommandExecutorService}. It provides methods for starting system processes\n * or executing system commands using a privileged user. The privileged user is the same that started Kura, so this\n * interface provides the highest available level of permissions.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.2\n */\n@ProviderType\npublic interface PrivilegedExecutorService extends CommandExecutorService {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/Signal.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.executor;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface provides a method to retrieve the signal to send to system commands or processes (i.e. to kill them).\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.2\n */\n@ProviderType\npublic interface Signal {\n\n    public int getSignalNumber();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/UnprivilegedExecutorService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.executor;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This is a marker interface for the {@link CommandExecutorService}. It provides methods for starting system processes\n * or executing system commands using a specific user. The commands are run with the permissions that are granted to\n * that user.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.2\n */\n@ProviderType\npublic interface UnprivilegedExecutorService extends CommandExecutorService {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/GPIOService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The GPIOService is used to access available GPIO resources on the system.<br>\n * {@link KuraGPIOPin}s can be accessed by its name or by its controller and line offset.<br>\n * <br>\n * Operations on the pins can be done using the acquired {@link KuraGPIOPin} class.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface GPIOService {\n\n    /**\n     * Get a GPIO pin by its name.\n     * \n     * For example, to get the pin named \"GPIO22\", call:\n     * <pre>\n     * KuraGPIOPin pin = gpioService.getPinByName(\"GPIO22\");\n     * </pre>\n     * \n     * @param pinName the name of the pin\n     * \n     * @return the KuraGPIOPin instance\n     * @deprecated Use {@link #getPins(Map)} and select the desired pin from the returned list.\n     */\n    @Deprecated(since = \"3.0\", forRemoval = true)\n    public KuraGPIOPin getPinByName(String pinName);\n\n    /**\n     * Get a GPIO pin by its name, with the specified direction, mode and trigger.\n     * \n     * For example, to get an output open-drain pin with no trigger named \"GPIO22\", call:\n     * <pre>\n     * KuraGPIOPin pin = gpioService.getPinByName(\"GPIO22\", KuraGPIODirection.OUTPUT, KuraGPIOMode.OUTPUT_OPEN_DRAIN, KuraGPIOTrigger.NONE);\n     * </pre>\n     * \n     * @param pinName the name of the pin\n     * @param direction the direction of the pin\n     * @param mode the mode of the pin\n     * @param trigger the trigger of the pin\n     * \n     * @return the KuraGPIOPin instance\n     * @deprecated Use {@link #getPins(Map, KuraGPIODirection, KuraGPIOMode, KuraGPIOTrigger)} and \n     * select the desired pin from the returned list.\n     */\n    @Deprecated(since = \"3.0\", forRemoval = true)\n    public KuraGPIOPin getPinByName(String pinName, KuraGPIODirection direction, KuraGPIOMode mode,\n            KuraGPIOTrigger trigger);\n\n    /**\n     * Get a GPIO pin by its terminal index.\n     * \n     * @param terminal the terminal index of the pin\n     * \n     * @return the KuraGPIOPin instance\n     * @deprecated Use {@link #getPins(Map)} instead.\n     */\n    @Deprecated(since = \"3.0\", forRemoval = true)\n    public KuraGPIOPin getPinByTerminal(int terminal);\n\n    /** \n     * Get a GPIO pin by its terminal index, with the specified direction, mode and trigger.\n     * \n     * @param terminal the terminal index of the pin\n     * @param direction the direction of the pin\n     * @param mode the mode of the pin\n     * @param trigger the trigger of the pin\n     * \n     * @return the KuraGPIOPin instance\n     * @deprecated Use {@link #getPins(Map, KuraGPIODirection, KuraGPIOMode, KuraGPIOTrigger)} instead.\n     */\n    @Deprecated(since = \"3.0\", forRemoval = true)\n    public KuraGPIOPin getPinByTerminal(int terminal, KuraGPIODirection direction, KuraGPIOMode mode,\n            KuraGPIOTrigger trigger);\n\n    /** \n     * Get a map of available GPIO pins.\n     * \n     * @return a map of available GPIO pins, where the key is the terminal index and the value is the pin name\n     * @deprecated Use {@link #getAvailablePinDescriptions()} instead.\n     */\n    @Deprecated(since = \"3.0\", forRemoval = true)\n    public Map<Integer, String> getAvailablePins();\n    \n    /**\n     * Get the GPIO pins that match the given description properties.\n     * \n     * The description map is interpreted as a set of filter criteria:\n     * only the properties present in the map are considered when selecting\n     * pins. Pins that match all provided properties are returned; properties\n     * that are not specified are ignored.\n     * \n     * For example, to get all pins with a specific name, you can call:\n     * <pre>\n     * Map<String, String> description = new HashMap<>();\n     * description.put(\"name\", \"GPIO22\");\n     * List<KuraGPIOPin> pins = gpioService.getPins(description);\n     * </pre>\n     * \n     * To get all pins on a specific name and line, you can call:\n     * <pre>\n     * Map<String, String> description = new HashMap<>();\n     * description.put(\"name\", \"GPIO22\");\n     * description.put(\"line\", \"5\");\n     * List<KuraGPIOPin> pins = gpioService.getPins(description);\n     * </pre>\n     * \n     * @param description a map of property names to values used to filter pins; may contain\n     *        a subset of all supported properties\n     * \n     * @return a list of {@code KuraGPIOPin} instances matching the specified properties\n     * @since 3.0\n     */\n    public List<KuraGPIOPin> getPins(Map<String, String> description);\n    \n    /**\n     * Get the GPIO pins that match the given description properties, setting the direction, mode and trigger.\n     * \n     * The description map is interpreted as a set of filter criteria:\n     * only the properties present in the map are considered when selecting\n     * pins. Pins that match all provided properties are returned; properties\n     * that are not specified are ignored.\n     * \n     * For example, to get all pins with a specific name, you can call:\n     * <pre>\n     * Map<String, String> description = new HashMap<>();\n     * description.put(\"name\", \"GPIO22\");\n     * List<KuraGPIOPin> pins = gpioService.getPins(description, direction, mode, trigger);\n     * </pre>\n     * \n     * To get all pins on a specific name and line, you can call:\n     * <pre>\n     * Map<String, String> description = new HashMap<>();\n     * description.put(\"name\", \"GPIO22\");\n     * description.put(\"line\", \"5\");\n     * List<KuraGPIOPin> pins = gpioService.getPins(description, direction, mode, trigger);\n     * </pre>\n     * @param description a map of properties describing the pin\n     * @param direction the direction of the pin\n     * @param mode the mode of the pin\n     * @param trigger the trigger of the pin\n     * \n     * @return a list of KuraGPIOPin instances\n     * @since 3.0\n     */\n    public List<KuraGPIOPin> getPins(Map<String, String> description, KuraGPIODirection direction, KuraGPIOMode mode,\n            KuraGPIOTrigger trigger);\n    \n    /**\n     * Get the {@link KuraGPIODescription}s of all available GPIO pins.\n     * \n     * @return a list of available GPIO descriptions\n     * @since 3.0\n     */\n    public List<KuraGPIODescription> getAvailablePinDescriptions();\n    \n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraClosedDeviceException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraClosedDeviceException extends KuraException {\n\n    /**\n     *\n     */\n    private static final long serialVersionUID = -1750311704822256084L;\n\n    public KuraClosedDeviceException(Object argument) {\n        super(KuraErrorCode.CLOSED_DEVICE, null, argument);\n    }\n\n    public KuraClosedDeviceException(Throwable cause, Object argument) {\n        super(KuraErrorCode.CLOSED_DEVICE, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIODescription.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\n/**\n * GPIO description as a set of properties.\n *\n * The properties map contains the attributes needed to identify and configure a GPIO pin.\n * The mandatory DISPLAY_NAME_PROPERTY property is used to get a human readable name for the GPIO pin.\n *\n */\npublic class KuraGPIODescription {\n\n    public static final String DISPLAY_NAME_PROPERTY = \"display.name\";\n\n    private final Map<String, String> properties;\n\n    public KuraGPIODescription(Map<String, String> properties) {\n        if (properties == null) {\n            throw new IllegalArgumentException(\"Properties map cannot be null\");\n        }\n        if (!properties.containsKey(DISPLAY_NAME_PROPERTY) || properties.get(DISPLAY_NAME_PROPERTY).isEmpty()) {\n            throw new IllegalArgumentException(\"Missing mandatory property: \" + DISPLAY_NAME_PROPERTY);\n        }\n\n        this.properties = Collections.unmodifiableMap(new HashMap<>(properties));\n    }\n    \n    public Map<String, String> getProperties() {\n        return this.properties;\n    }\n\n    public String getDisplayName() {\n        return this.properties.get(DISPLAY_NAME_PROPERTY);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.properties);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof KuraGPIODescription)) {\n            return false;\n        }\n        KuraGPIODescription other = (KuraGPIODescription) obj;\n        return Objects.equals(this.properties, other.properties);\n    }\n\n    @Override\n    public String toString() {\n        return \"KuraGPIODescription [properties=\" + this.properties + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIODeviceException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraGPIODeviceException extends KuraException {\n\n    private static final long serialVersionUID = -1750311704822256084L;\n\n    public KuraGPIODeviceException(Object argument) {\n        super(KuraErrorCode.GPIO_EXCEPTION, null, argument);\n    }\n\n    public KuraGPIODeviceException(Throwable cause, Object argument) {\n        super(KuraErrorCode.GPIO_EXCEPTION, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIODirection.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\npublic enum KuraGPIODirection {\n    INPUT,\n    OUTPUT\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIOMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\npublic enum KuraGPIOMode {\n    OUTPUT_OPEN_DRAIN,\n    OUTPUT_PUSH_PULL,\n    INPUT_PULL_UP,\n    INPUT_PULL_DOWN\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIOPin.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\nimport java.io.IOException;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The <b>KuraGPIOPin</b> class is used to access the GPIO resource.<br>\n * The pin can be programmed either as an input or as an output. The way this is handled is implementation dependent.\n * <br>\n * <br>\n * Pins must be opened and closed before setting or getting values. Implementations, however, could automatically open a\n * pin if it is closed when accessing it, or automatically close it when it is not needed anymore.<br>\n * <br>\n * Status of input pins can be retrieved either with a call to {@link #getValue()} or by attaching a\n * {@link PinStatusListener}\n * to the pin.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface KuraGPIOPin {\n\n    /**\n     * Used to set the value of an output pin.\n     *\n     * @param active\n     *            New state of the pin.\n     * @throws KuraUnavailableDeviceException\n     *             when the GPIO resource is not available\n     * @throws KuraClosedDeviceException\n     *             when the GPIO resource has not yet been opened\n     * @throws IOException\n     *             if an I/O error occurs\n     */\n    public void setValue(boolean active) throws KuraUnavailableDeviceException, KuraClosedDeviceException, IOException;\n\n    /**\n     * Used to get the current value of a pin, either output or input\n     *\n     * @return true if the pin is in active state\n     * @throws KuraUnavailableDeviceException\n     *             when the GPIO resource is not available\n     * @throws KuraClosedDeviceException\n     *             when the GPIO resource has not yet been opened\n     * @throws IOException\n     *             if an I/O error occurs\n     */\n    public boolean getValue() throws KuraUnavailableDeviceException, KuraClosedDeviceException, IOException;\n\n    /**\n     * Adds a {@link PinStatusListener} to this input pin. The listener will be notified when the status of this input\n     * changes.<br>\n     * Attaching a listener to an output pin should not raise an exception, but will have no result.\n     *\n     * @param listener\n     *            Listener to be added to this pin\n     * @throws KuraClosedDeviceException\n     *             when the GPIO resource has not yet been opened\n     * @throws IOException\n     *             if an I/O error occurs\n     */\n    public void addPinStatusListener(PinStatusListener listener) throws KuraClosedDeviceException, IOException;\n\n    /**\n     * Removes a {@link PinStatusListener} from this input pin.<br>\n     * If the pin has no listeners attached, this method should fail silently.<br>\n     *\n     * @param listener\n     *            Listener to be removed from this pin\n     * @throws KuraClosedDeviceException\n     *             when the GPIO resource has not yet been opened\n     * @throws IOException\n     *             if an I/O error occurs\n     */\n    public void removePinStatusListener(PinStatusListener listener) throws KuraClosedDeviceException, IOException;\n\n    /**\n     * Opens the pin and allocates the needed resources to communicate with it.\n     *\n     * @throws KuraGPIODeviceException\n     *             when an exception occurs opening the pin\n     * @throws KuraUnavailableDeviceException\n     *             when the GPIO resource is not available\n     * @throws IOException\n     *             if a generic I/O error occurs\n     */\n    public void open() throws KuraGPIODeviceException, KuraUnavailableDeviceException, IOException;\n\n    /**\n     * Closes this pin and deallocates the resources needed to communicate with it.<br>\n     * <br>\n     * If there is a {@link PinStatusListener} attached to this pin, the implementation should remove it\n     * before closing the resource.\n     *\n     * @throws IOException\n     *             if a generic I/O error occurs\n     */\n    public void close() throws IOException;\n\n    /**\n     *\n     * @return {@link KuraGPIODirection} representing the direction (Input/Output) of the PIN\n     */\n    public KuraGPIODirection getDirection();\n\n    /**\n     *\n     * @return {@link KuraGPIOMode} representing the mode of the pun.<br>\n     *         Open Drain / Push Pull for outputs, Pull Up / Pull Down for inputs.\n     */\n    public KuraGPIOMode getMode();\n\n    /**\n     *\n     * @return {@link KuraGPIOTrigger} representing the trigger mode for this pin.\n     */\n    public KuraGPIOTrigger getTrigger();\n\n    /**\n     *\n     * @return the name associated with the the pin\n     * @deprecated Use {@link #getDescription()} to retrieve pin information.\n     */\n    @Deprecated(since = \"3.0\", forRemoval = true)\n    public String getName();\n\n    /**\n     *\n     * @return the numeric index of the pin's terminal\n     * @deprecated Use {@link #getDescription()} to retrieve pin information.\n     */\n    @Deprecated(since = \"3.0\", forRemoval = true)\n    public int getIndex();\n\n    /**\n     *\n     * @return true if the pin has been previously opened for use.\n     */\n    public boolean isOpen();\n    \n    /**\n     *\n     * @return the {@link KuraGPIODescription} associated with this pin.\n     * @since 3.0\n     */\n    public KuraGPIODescription getDescription();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIOTrigger.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\npublic enum KuraGPIOTrigger {\n    RAISING_EDGE,\n    FALLING_EDGE,\n    BOTH_EDGES,\n    HIGH_LEVEL,\n    LOW_LEVEL,\n    BOTH_LEVELS,\n    NONE\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraUnavailableDeviceException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraUnavailableDeviceException extends KuraException {\n\n    private static final long serialVersionUID = -5115093706356681148L;\n\n    public KuraUnavailableDeviceException(Object argument) {\n        super(KuraErrorCode.UNAVAILABLE_DEVICE, null, argument);\n    }\n\n    public KuraUnavailableDeviceException(Throwable cause, Object argument) {\n        super(KuraErrorCode.UNAVAILABLE_DEVICE, cause, argument);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/PinStatusListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.gpio;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * This interface is used to notify status change on the Input pins\n *\n */\n@ConsumerType\npublic interface PinStatusListener {\n\n    /**\n     * Invoked when the status of the attached input pin changes\n     *\n     * @param value\n     *            The new value of the pin.\n     */\n    public void pinStatusChange(boolean value);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides APIs to acquire and use GPIO resources available on the system.\n *\n */\npackage org.eclipse.kura.gpio;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/AdditionalConfigurations.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a set of additional configurations associated with an identity\n * managed by {@code IdentityConfigurationExtension} implementations.\n * <br>\n * This class contains a list of {@link ComponentConfiguration} instances, the\n * {@link ComponentConfiguration#getPid()} method of each configuration should\n * return the kura.service.pid of the associated\n * {@code IdentityConfigurationExtension}.\n * <br>\n * <br>\n * The {@link IdentityService#getIdentitiesConfiguration(List)} and\n * {@link IdentityService#getIdentityConfiguration(String, List)} method will\n * return the {@link ComponentConfiguration}s provided by all\n * {@code IdentityConfigurationExtension}s registered in the framework.\n * <br>\n * <br>\n * The\n * {@link IdentityService#updateIdentityConfiguration(IdentityConfiguration)}\n * method\n * will call\n * {@code IdentityConfigurationExtension.updateConfiguration(String, ComponentConfiguration)}\n * method of the {@code IdentityConfigurationExtension} instances whose\n * kura.service.pid is referenced by the provided configurations.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic class AdditionalConfigurations implements IdentityConfigurationComponent {\n\n    private final List<ComponentConfiguration> configurations;\n\n    /**\n     * Creates a new instance containing the provided configuration list.\n     *\n     * @param configurations the configuration list.\n     */\n    public AdditionalConfigurations(final List<ComponentConfiguration> configurations) {\n        this.configurations = requireNonNull(configurations, \"configuration list cannot be null\");\n    }\n\n    /**\n     * Returns the list of component configurations.\n     *\n     * @return the list of component configurations.\n     */\n    public List<ComponentConfiguration> getConfigurations() {\n        return this.configurations;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.configurations);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof AdditionalConfigurations)) {\n            return false;\n        }\n        AdditionalConfigurations other = (AdditionalConfigurations) obj;\n        return Objects.equals(this.configurations, other.configurations);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/AssignedPermissions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Describes the the set of permissions currently assigned to a given identity.\n * If the\n * {@link IdentityService#updateIdentityConfiguration(IdentityConfiguration)}\n * receives an {@link IdentityConfiguration} containing this component, it\n * should replace the currently assigned permission set with the specified one.\n * \n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic class AssignedPermissions implements IdentityConfigurationComponent {\n\n    private final Set<Permission> permissions;\n\n    /**\n     * Creates a new instance representing the provided permission set.\n     * \n     * @param permissions the permission set.\n     */\n    public AssignedPermissions(final Set<Permission> permissions) {\n        this.permissions = requireNonNull(permissions, \"permissions cannot be null\");\n    }\n\n    /**\n     * Returns the permission set.\n     * \n     * @return the permission set.\n     */\n    public Set<Permission> getPermissions() {\n        return permissions;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(permissions);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof AssignedPermissions)) {\n            return false;\n        }\n        AssignedPermissions other = (AssignedPermissions) obj;\n        return Objects.equals(permissions, other.permissions);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/IdentityConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Describes the configuration for an identity. It is composed by different\n * {@link IdentityConfigurationComponent}s that can be retrieved and updated\n * separately using the {@link IdentityService}.\n * \n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic class IdentityConfiguration {\n\n    private final String name;\n    private final List<IdentityConfigurationComponent> components;\n\n    /**\n     * Creates a new identity configuration with the given name and components.\n     * \n     * @param name       the identity name.\n     * @param components the {@link IdentityConfigurationComponent} list.\n     */\n    public IdentityConfiguration(String name, List<IdentityConfigurationComponent> components) {\n        this.name = requireNonNull(name, \"name cannot be null\");\n\n        if (this.name.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"name cannot be empty\");\n        }\n\n        this.components = requireNonNull(components, \"components cannot be null\");\n    }\n\n    /**\n     * Returns the identity name.\n     * \n     * @return the identity name.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Returns the list of {@link IdentityConfigurationComponent}s.\n     * \n     * @return the list of {@link IdentityConfigurationComponent}s.\n     */\n    public List<IdentityConfigurationComponent> getComponents() {\n        return components;\n    }\n\n    public <T extends IdentityConfigurationComponent> Optional<T> getComponent(final Class<T> clazz) {\n        for (final IdentityConfigurationComponent component : components) {\n            if (clazz.isInstance(component)) {\n                return Optional.of(clazz.cast(component));\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(components, name);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof IdentityConfiguration)) {\n            return false;\n        }\n        IdentityConfiguration other = (IdentityConfiguration) obj;\n        return Objects.equals(components, other.components) && Objects.equals(name, other.name);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/IdentityConfigurationComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a portion of the configuration of an identity that can be\n * retrieved and updated individually.\n * \n * The currently supported types are {@link PasswordConfiguration},\n * {@link AssignedPermissions} and {@link AdditionalConfigurations}.\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic interface IdentityConfigurationComponent {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/IdentityService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.identity;\n\nimport java.time.Duration;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A service interface that allows to manage Kura identities.\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic interface IdentityService {\n\n    /**\n     * Creates a new identity with the given name.\n     * \n     * @param identityName\n     *            the name of the identity to be created.\n     * @return {@code true} if the identity with the given name has been created as\n     *         part of the method call or {@code false} if the identity already\n     *         exists.\n     * @throws KuraException\n     *             if a failure occurs in creating the identity.\n     */\n    public boolean createIdentity(final String identityName) throws KuraException;\n\n    /**\n     * Creates a new identity using the provided configuration.\n     * \n     * @param identityConfiguration\n     *            the identity configuration including identity\n     *            name and optional configuration components.\n     * @return {@code true} if the identity with the given name has been created as\n     *         part of the method call or {@code false} if the identity already\n     *         exists.\n     * @throws KuraException\n     *             if a failure occurs in creating the identity.\n     * @since 2.8.0\n     */\n    public boolean createIdentity(final IdentityConfiguration identityConfiguration) throws KuraException;\n\n    /**\n     * Deletes the identity with the given name, including temporary identities.\n     * \n     * @param identityName\n     *            the name of the identity to be deleted.\n     * @return {@code true} if the identity with the given name has been deleted as\n     *         part of the method call or {@code false} if the identity does not\n     *         exist.\n     * @throws KuraException\n     *             if a failure occurs in deleting the identity.\n     */\n    public boolean deleteIdentity(final String identityName) throws KuraException;\n\n    /**\n     * Returns the configuration of all existing identities.\n     * \n     * @param componentsToReturn\n     *            the set of {@link IdentityConfigurationComponent}\n     *            types to be returned. If the set is empty a\n     *            {@link IdentityConfiguration} will be returned for\n     *            each defined identity with an empty component list.\n     *            This can be used to get the name for all defined\n     *            identities.\n     * \n     * @return the list of {@link IdentityConfiguration}s. An empty list will be\n     *         returned if no identities are defined.\n     * @throws KuraException\n     *             if a failure occurs in retrieving identity\n     *             configurations.\n     */\n    public List<IdentityConfiguration> getIdentitiesConfiguration(\n            Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) throws KuraException;\n\n    /**\n     * Returns the configuration of the identity with the given name.\n     * \n     * @param identityName\n     *            the identity name.\n     * @param componentsToReturn\n     *            the set of {@link IdentityConfigurationComponent}\n     *            types to be returned.\n     * @return the configuration of the requested identity or an empty optional if\n     *         the identity does not exist.\n     * @throws KuraException\n     *             if a failure occurs in retrieving identity\n     *             configuration.\n     */\n    public Optional<IdentityConfiguration> getIdentityConfiguration(final String identityName,\n            Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) throws KuraException;\n\n    /**\n     * Returns the default configuration for the identity with the given name, this\n     * method should succeed even if the identity does not exist. The result should\n     * be the same configuration returned by the\n     * {@link IdentityService#getIdentityConfiguration(String, Set)}\n     * method for an identity that has just been created with the\n     * {@link IdentityService#createIdentity(String)} method.\n     * \n     * This method can be useful for example to allow a user interface to show the\n     * initial identity configuration to the user before creating it.\n     *\n     * @param identityName\n     *            the identity name.\n     * @param componentsToReturn\n     *            the set of {@link IdentityConfigurationComponent}\n     *            types to be returned.\n     * @return the default configuration for the requested identity\n     * @throws KuraException\n     *             if a failure occurs in retrieving identity\n     *             configuration.\n     */\n    public IdentityConfiguration getIdentityDefaultConfiguration(final String identityName,\n            Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) throws KuraException;\n\n    /**\n     * Validates the provided identity configuration without performing any\n     * change to the system.\n     * \n     * @param identityConfiguration\n     *            the identity configuration that should be\n     *            validated.\n     * @throws KuraException\n     *             if the provided identity configuration is not\n     *             valid.\n     */\n    public void validateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException;\n\n    /**\n     * Updates the configuration of the given identity for the provided\n     * {@link IdentityConfigurationComponent} types.\n     * The configuration of the identities or identity\n     * components that have not been provided will not be modified.\n     * \n     * @param identityConfiguration\n     *            the identity configuration that should be\n     *            updated.\n     * @throws KuraException\n     *             if a failure occurs updating identity\n     *             configuration.\n     */\n    public void updateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException;\n\n    /**\n     * Defines a new permission.\n     * \n     * @param permission\n     *            the permission to be created.\n     * @return {@code true} if the permission has been created as\n     *         part of the method call or {@code false} if the permission already\n     *         exist.\n     * @throws KuraException\n     *             if a failure occurs creating the permission.\n     */\n    public boolean createPermission(final Permission permission) throws KuraException;\n\n    /**\n     * Removes an existing permission. The permission will also be removed from all\n     * identities assigned to it.\n     * \n     * @param permission\n     *            the permission to be deleted.\n     * @return {@code true} if the permission has been deleted as\n     *         part of the method call or {@code false} if the permission does not\n     *         exist.\n     * @throws KuraException\n     *             if a failure occurs deleting the permission.\n     */\n    public boolean deletePermission(final Permission permission) throws KuraException;\n\n    /**\n     * Returns the set of permissions that are currently defined within the\n     * framework.\n     * \n     * @return the set of permissions that are currently defined within the\n     *         framework.\n     * @throws KuraException\n     *             if a failure occurs retrieving the permission set.\n     */\n    public Set<Permission> getPermissions() throws KuraException;\n\n    /**\n     * Computes a {@link PasswordHash} for the given plaintext password. The\n     * password array will be overwritten at the end of the operation.\n     * \n     * @param password\n     *            the plaintext password.\n     * @return the computed password hash.\n     * @throws KuraException\n     *             if a failure occurs computing the password hash\n     */\n    public PasswordHash computePasswordHash(final char[] password) throws KuraException;\n\n    /**\n     * Checks if the provided password matches the one currently assigned to the\n     * given identity.\n     * \n     * @param identityName\n     * @param password\n     * @throws KuraException\n     *             if the passwords do not match of if a failure occurs\n     *             while\n     *             performing the check.\n     */\n    public void checkPassword(final String identityName, final char[] password) throws KuraException;\n\n    /**\n     * Checks if the specified permission is currently assigned to the given\n     * identity.\n     *\n     * @param identityName\n     * @param permission\n     * @throws KuraException\n     *             if the provided permission is not currently assigned to\n     *             the given identity or if occurs while performing the\n     *             check.\n     *\n     */\n    public void checkPermission(final String identityName, final Permission permission) throws KuraException;\n\n    /**\n     * Creates a temporary identity that is not persisted and has automatic\n     * expiration. Temporary identities behave like regular identities but are\n     * stored in-memory only and are automatically removed after the specified\n     * lifetime period.\n     *\n     * @param identityName\n     *            the name of the temporary identity to create.\n     * @param lifetime\n     *            the duration before automatic expiration. The identity\n     *            will be automatically removed after this period.\n     * @throws KuraException\n     *             if a failure occurs in creating the temporary identity\n     *             or if an identity with the given name already exists\n     *             (either regular or temporary).\n     * @since 2.8.0\n     */\n    public void createTemporaryIdentity(final String identityName, final Duration lifetime) throws KuraException;\n\n\n    /**\n     * Creates a temporary identity that is not persisted and has automatic\n     * expiration. Temporary identities behave like regular identities but are\n     * stored in-memory only and are automatically removed after the specified\n     * lifetime period.\n     *\n     * @param identityConfiguration\n     *            the identity configuration including identity\n     *            name and optional configuration components.\n     * @param lifetime\n     *            the duration before automatic expiration. The identity\n     *            will be automatically removed after this period.\n     * @throws KuraException\n     *             if a failure occurs in creating the temporary identity,\n     *             if an identity with the given name already exists\n     *             (either regular or temporary) or if the provided configuration\n     *             is not valid.\n     * @since 2.8.0\n     */\n    public void createTemporaryIdentity(final IdentityConfiguration identityConfiguration, final Duration lifetime) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/LoginBannerService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A service interface that provides messages that should be shown to the user\n * before and/or after login by user interface services (e.g. a web console).\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 3.0.0\n */\n@ProviderType\npublic interface LoginBannerService {\n\n    /**\n     * Returns the message that should be shown before user login.\n     * \n     * @return the pre login banner message, or an empty optional if no message should be shown\n     */\n    public Optional<String> getPreLoginBanner();\n\n    /**\n     * Returns the message that should be shown after a successful user login.\n     * \n     * @return the post login banner message, or an empty optional if no message should be shown\n     */\n    public Optional<String> getPostLoginBanner();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/PasswordConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Describes the password related configuration for an identity.\n * \n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic class PasswordConfiguration implements IdentityConfigurationComponent {\n\n    private final boolean passwordChangeNeeded;\n    private final boolean passwordAuthEnabled;\n    private final Optional<char[]> newPassword;\n    private final Optional<PasswordHash> passwordHash;\n\n    /**\n     * Creates a new password configuration.\n     * \n     * @param passwordChangeNeeded a {@code boolean} indicating whether a password\n     *                             change for the given\n     *                             identity is required at next login.\n     * @param passwordAuthEnabled  a {@code boolean} indicating whether a password\n     *                             authentication is\n     *                             enabled for the given identity.\n     * @param newPassword          a new password that should be set for the given\n     *                             identity, setting this parameter to empty will\n     *                             not change the current identity password during a\n     *                             configuration update.\n     * @param passwordHash         the password hash. This value is ignored by the\n     *                             {@link IdentityService} in case of identity\n     *                             configuration update.\n     */\n    public PasswordConfiguration(boolean passwordChangeNeeded, boolean passwordAuthEnabled,\n            Optional<char[]> newPassword, Optional<PasswordHash> passwordHash) {\n        this.passwordChangeNeeded = passwordChangeNeeded;\n        this.passwordAuthEnabled = passwordAuthEnabled;\n        this.newPassword = requireNonNull(newPassword, \"newPassword cannot be null\");\n        this.passwordHash = requireNonNull(passwordHash, \"password hash cannot be null\");\n    }\n\n    /**\n     * Defines whether a password change is required for the given identity at next\n     * login.\n     * \n     * @return a {@code boolean} indicating whether a password change for the given\n     *         identity is required at next login.\n     */\n    public boolean isPasswordChangeNeeded() {\n        return passwordChangeNeeded;\n    }\n\n    /**\n     * Defines whether a password authentication is enabled for the given identity.\n     * \n     * @return a {@code boolean} indicating whether a password authentication is\n     *         enabled for the given identity.\n     */\n    public boolean isPasswordAuthEnabled() {\n        return passwordAuthEnabled;\n    }\n\n    /**\n     * Returns the hash of the password currently associated with the given\n     * identity, if any.\n     * \n     * @return the password hash.\n     */\n    public Optional<PasswordHash> getPasswordHash() {\n        return passwordHash;\n    }\n\n    /**\n     * Returns the new password that should be set for the given identity as part of\n     * a configuration update. The {@link IdentityService} will always return an\n     * empty optional when the password data for an existing identity is retrieved.\n     * \n     * @return the new password.\n     */\n    public Optional<char[]> getNewPassword() {\n        return newPassword;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(newPassword, passwordAuthEnabled, passwordChangeNeeded, passwordHash);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof PasswordConfiguration)) {\n            return false;\n        }\n        PasswordConfiguration other = (PasswordConfiguration) obj;\n        return Objects.equals(newPassword, other.newPassword) && passwordAuthEnabled == other.passwordAuthEnabled\n                && passwordChangeNeeded == other.passwordChangeNeeded\n                && Objects.equals(passwordHash, other.passwordHash);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/PasswordHash.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a password hash computed using an implementation defined\n * algorithm. The implementation must override the\n * {@link Object#hashCode()} and {@link Object#equals()} methods.\n * <br>\n * <br>\n * Instances of this class can be constructed using the\n * {@link IdentityService#computePasswordHash(char[])}.\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic interface PasswordHash {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/PasswordStrengthRequirements.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport java.util.Objects;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a set of password strength requirements that should be enforced by\n * the framework for new passwords.\n * \n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic class PasswordStrengthRequirements {\n\n    private final int passwordMinimumLength;\n    private final boolean digitsRequired;\n    private final boolean specialCharactersRequired;\n    private final boolean bothCasesRequired;\n\n    /**\n     * Creates a new instance.\n     * \n     * @param passwordMinimumLength     the minimum allowed password length.\n     * @param digitsRequired            a {@code boolean} indicating whether new\n     *                                  passwords must contain\n     *                                  at least one digit.\n     * @param specialCharactersRequired a {@code boolean} indicating whether new\n     *                                  passwords must contain\n     *                                  at least one non alphanumeric character.\n     * @param bothCasesRequired         a {@code boolean} indicating whether new\n     *                                  passwords must contain\n     *                                  at least one upper case and lower case\n     *                                  character.\n     */\n    public PasswordStrengthRequirements(int passwordMinimumLength, boolean digitsRequired,\n            boolean specialCharactersRequired, boolean bothCasesRequired) {\n        this.passwordMinimumLength = passwordMinimumLength;\n        this.digitsRequired = digitsRequired;\n        this.specialCharactersRequired = specialCharactersRequired;\n        this.bothCasesRequired = bothCasesRequired;\n    }\n\n    /**\n     * Returns the minimum allowed password length.\n     *\n     * @return the minimum allowed password length.\n     */\n    public int getPasswordMinimumLength() {\n        return passwordMinimumLength;\n    }\n\n    /**\n     * Returns a {@code boolean} indicating whether new passwords must contain\n     * at least one digit.\n     * \n     * @return a {@code boolean} indicating whether new passwords must contain\n     *         at least one digit.\n     */\n    public boolean digitsRequired() {\n        return digitsRequired;\n    }\n\n    /**\n     * Returns a {@code boolean} indicating whether new passwords must contain\n     * at least one non alphanumeric character.\n     * \n     * @return a {@code boolean} indicating whether new passwords must contain\n     *         at least one non alphanumeric character.\n     */\n    public boolean specialCharactersRequired() {\n        return specialCharactersRequired;\n    }\n\n    /**\n     * Returns a {@code boolean} indicating whether new passwords must contain\n     * at least one upper case and lower case character.\n     * \n     * @return a {@code boolean} indicating whether new passwords must contain\n     *         at least one upper case and lower case character.\n     */\n    public boolean bothCasesRequired() {\n        return bothCasesRequired;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(passwordMinimumLength, bothCasesRequired, digitsRequired,\n                specialCharactersRequired);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof PasswordStrengthRequirements)) {\n            return false;\n        }\n        PasswordStrengthRequirements other = (PasswordStrengthRequirements) obj;\n        return passwordMinimumLength == other.passwordMinimumLength\n                && bothCasesRequired == other.bothCasesRequired\n                && digitsRequired == other.digitsRequired\n                && specialCharactersRequired == other.specialCharactersRequired;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/PasswordStrengthVerificationService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A service interface that allows to retrieve and verify the password strength\n * requirements that the framework should enforce for new password.\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic interface PasswordStrengthVerificationService {\n\n    /**\n     * Checks whether the provided password satisfies the password strength\n     * requirements currently configured on the system.\n     * \n     * @param password\n     *            the password to be verified.\n     * @throws KuraException\n     *             if the password does not satisfy the current password\n     *             strength requirements.\n     */\n    public void checkPasswordStrength(final char[] password) throws KuraException;\n\n    /**\n     * Similar to {@link #checkPasswordStrength(char[])} checks whether\n     * the provided password satisfies the password strength requirements currently configured\n     * on the system and in addition verifies that the password\n     * does not match the identityName ignoring the characters case.\n     * \n     * @param identityName\n     *            the name of the identity\n     * @param password\n     *            the password to be verified.\n     * @since 3.0\n     * @throws KuraException\n     *             if the password does not satisfy the current password\n     *             strength requirements.\n     */\n    public void checkPasswordStrength(String identityName, final char[] password) throws KuraException;\n\n    /**\n     * Returns the password strength requirements that the framework should enforce\n     * for new passwords.\n     * \n     * @return the password strength requirements.\n     * @throws KuraException\n     *             if a failure occurs while retrieving the password\n     *             strength requirements.\n     */\n    public PasswordStrengthRequirements getPasswordStrengthRequirements() throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/Permission.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Objects;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a permission that can be assigned to Kura identites.\n * \n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.7.0\n */\n@ProviderType\npublic class Permission {\n\n    private final String name;\n\n    /**\n     * Creates a new instance.\n     * \n     * @param name the permission name.\n     */\n    public Permission(String name) {\n        this.name = requireNonNull(name, \"name cannot be null\");\n    }\n\n    /**\n     * Returns the permission name.\n     * \n     * @return the permission name.\n     */\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof Permission)) {\n            return false;\n        }\n        Permission other = (Permission) obj;\n        return Objects.equals(name, other.name);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/configuration/extension/IdentityConfigurationExtension.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.identity.configuration.extension;\n\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A service interface that can be implemented to provide additional\n * configuration for Kura identities. The additional configuration can be\n * retrieved and updated by clients through the {@code IdentityService} using\n * the {@code AdditionalConfigurations} class.\n * <br>\n * <br>\n * Implementing service must be registered with the kura.service.pid property\n * set to an unique identifier.\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.7\n */\n@ProviderType\npublic interface IdentityConfigurationExtension {\n\n    /**\n     * Retrieves the default configuration managed by this extension for the\n     * given identity, if any. This method may be called for the given identity name\n     * even if it currently does not exists on the system.\n     * <br>\n     * The returned configuration should be the same as the one returned by\n     * {@link IdentityConfigurationExtension#getConfiguration(String)} for an\n     * identity that has just been created before that any configuration update is\n     * applied to it.\n     * <br>\n     * The {@link ComponentConfiguration#getPid()} method of the returned\n     * configuration must be set to the value of the kura.service.pid property of\n     * the extension service.\n     * \n     * \n     * @param identityName the name of the identity.\n     * @return the default additional configuration, or an empty optional.\n     * @throws KuraException if a failure occurs while retrieving the configuration.\n     */\n    public Optional<ComponentConfiguration> getDefaultConfiguration(String identityName) throws KuraException;\n\n    /**\n     * Performs a validation of the provided configuration without applying any\n     * change to the system. This method can be called also for identities that do\n     * not exist on the system yet,\n     * typically this will be done just before creating a new identity.\n     * \n     * @param identityName  the name of the identity.\n     * @param configuration the configuration to be validated.\n     * @throws KuraException if the provided configuration is not valid.\n     */\n    public void validateConfiguration(String identityName, ComponentConfiguration configuration) throws KuraException;\n\n    /**\n     * Retrieves the additional configuration managed by this extension for the\n     * given identity, if any.\n     * <br>\n     * <br>\n     * The {@link ComponentConfiguration#getPid()} method of the returned\n     * configuration must be set to the value of the kura.service.pid property of\n     * the extension service.\n     * \n     * \n     * @param identityName the name of the identity.\n     * @return the additional configuration, or an empty optional.\n     * @throws KuraException if a failure occurs while retrieving the configuration.\n     */\n    public Optional<ComponentConfiguration> getConfiguration(String identityName) throws KuraException;\n\n    /**\n     * Updates the additional configuration managed by this extension for the\n     * given identity.\n     * \n     * @param identityName  the name of the identity.\n     * @param configuration the configuration to be applied.\n     * @throws KuraException if a failure occurs while updating the configuration.\n     */\n    public void updateConfiguration(String identityName, ComponentConfiguration configuration) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/configuration/extension/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\n/**\n * Provides APIs that allow external components to provide additional\n * custom configuration for Kura identities.\n *\n * @since 2.7\n */\npackage org.eclipse.kura.identity.configuration.extension;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\n/**\n * Provides APIs to interact with Kura Identities\n *\n * @since 2.7\n */\npackage org.eclipse.kura.identity;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/linux/udev/LinuxUdevListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.linux.udev;\n\nimport org.eclipse.kura.usb.UsbDevice;\nimport org.osgi.annotation.versioning.ConsumerType;\n\n@ConsumerType\npublic interface LinuxUdevListener {\n\n    /**\n     * Callback for notifications of new UsbDevice ATTACH events\n     *\n     * @param device\n     *            The UsbDevice that was just attached\n     */\n    void attached(UsbDevice device);\n\n    /**\n     * Callback for notifications of new UsbDevice DETACH events\n     *\n     * @param device\n     *            The UsbDevice that was just detached\n     */\n    void detached(UsbDevice device);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/linux/udev/UdevEventType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.linux.udev;\n\npublic enum UdevEventType {\n\n    ATTACHED,\n    DETACHED;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/linux/udev/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides APIs to manage USB devices attached to the system.\n *\n */\npackage org.eclipse.kura.linux.udev;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/LogEntry.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.log;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Identifies a device Log message.\n *\n * A {@code LogEntry} object contains all the information associated to a device log message. The log message can be\n * produced by the operating system, the framework, a bundle in the framework or other generic resource.\n *\n * @since 2.3\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class LogEntry {\n\n    private final long timestamp;\n\n    private final Map<String, Object> properties;\n\n    /**\n     * Instantiates a new {@link LogEntry}\n     *\n     * @param readProperties\n     *            a Map representing the properties in a key-value format\n     */\n    public LogEntry(Map<String, Object> readProperties) {\n        this(readProperties, 0);\n\n    }\n\n    /**\n     * Instantiates a new {@link LogEntry}\n     *\n     * @param readProperties\n     *            a Map representing the properties in a key-value format\n     * @param timestamp\n     *            a long representing the source timestamp\n     *\n     * @since 2.4\n     */\n    public LogEntry(Map<String, Object> readProperties, long timestamp) {\n        requireNonNull(readProperties, \"Log properties cannot be null.\");\n\n        this.properties = Collections.unmodifiableMap(readProperties);\n        this.timestamp = timestamp;\n    }\n\n    /**\n     * Returns the log properties\n     *\n     * @return an unmodifiable Map with the properties associated to this LogEntry instance\n     */\n    public Map<String, Object> getProperties() {\n        return this.properties;\n    }\n\n    /**\n     * @since 2.4\n     */\n    public long getTimestamp() {\n        return this.timestamp;\n    }\n\n    @Override\n    public String toString() {\n        return this.properties.toString() + \" timestamp: \" + this.timestamp;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/LogProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.log;\n\nimport org.eclipse.kura.log.listener.LogListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The LogProvider interface is implemented by all the services responsible to notify {@link LogListener}.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 2.3\n */\n@ProviderType\npublic interface LogProvider {\n\n    /**\n     * Registers a {@link LogListener} that will be notified of new log events\n     * \n     * @param listener\n     *            a {@link LogListener}\n     */\n    public void registerLogListener(LogListener listener);\n\n    /**\n     * Unregisters a {@link LogListener} from the list of log events listeners\n     * \n     * @param listener\n     *            the {@link LogListener} to unregister\n     */\n    public void unregisterLogListener(LogListener listener);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/LogReader.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.log;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The LogReader interface is implemented by all the services responsible to read logs from the system, filesystem or\n * processes running on the system.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 2.3\n */\n@ProviderType\npublic interface LogReader extends LogProvider {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/listener/LogListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.log.listener;\n\nimport org.eclipse.kura.log.LogEntry;\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Listener interface to be implemented by applications that need to be notified of events in the {@link LogProvider}.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 2.3\n */\n@ConsumerType\npublic interface LogListener {\n\n    /**\n     * Notifies the listener that a new log entry has been received.\n     */\n    public void newLogEntry(LogEntry entry);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Defines APIs for reading device logs.\n *\n * @since 1.0\n */\npackage org.eclipse.kura.log;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/marshalling/Marshaller.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.marshalling;\n\nimport java.io.OutputStream;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface exposes methods for marshalling content\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.4\n */\n@ProviderType\npublic interface Marshaller {\n\n    /**\n     * Returns a {@link String} that represents the {@link Object} passed as input.\n     *\n     * @param object\n     *            the object that will be marshalled.\n     * @return a {@link String} representing the string representation of the object passed as input\n     * @throws KuraException\n     *             when the marshalling operation fails.\n     */\n    public String marshal(Object object) throws KuraException;\n\n    /**\n     * Serialises the provided {@link Object} and writes the result to the supplied {@link OutputStream}\n     * \n     * @param out\n     *            the {@link OutputStream} on which the data will be written\n     * @param object\n     *            the {@link Object} that will be marshalled.\n     * @throws KuraException\n     * @since 3.0\n     */\n    public void marshal(final OutputStream out, Object object) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/marshalling/Unmarshaller.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.marshalling;\n\nimport java.io.InputStream;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface exposes methods for unmarshalling content\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.4\n */\n@ProviderType\npublic interface Unmarshaller {\n\n    /**\n     * This method takes a String representation and a class that will be used as reference to construct the result.\n     *\n     * @param string\n     *            the input string\n     * @param clazz\n     *            the class representing the type of object expected for the result\n     * @return an object that is constructed from the passed string\n     * @throws KuraException\n     *             when the unmarshaling operation fails.\n     */\n    public <T> T unmarshal(String string, Class<T> clazz) throws KuraException;\n\n    /**\n     * Deserialises an object of the specified type from the provided {@link InputStream}\n     * \n     * @param in\n     *            the input stream\n     * @param clazz\n     *            the class representing the type of object expected for the result\n     * @return an object that is constructed from the passed string\n     * @throws KuraException\n     *             when the unmarshaling operation fails.\n     * @since 3.0\n     */\n    public <T> T unmarshal(InputStream in, Class<T> clazz) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/marshalling/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * APIs for all the marshaller/unmarshaller services\n */\npackage org.eclipse.kura.marshalling;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraAlertPayload.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @since 2.0\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraAlertPayload extends KuraPayload {\n\n    public static final String CODE_METRIC_NAME = \"alert_code\";\n    public static final String SEVERITY_METRIC_NAME = \"alert_severity\";\n    public static final String STATUS_METRIC_NAME = \"alert_status\";\n    public static final String MESSAGE_METRIC_NAME = \"alert_message\";\n    public static final String CREATION_TIMESTAMP_METRIC_NAME = \"alert_creation_date\";\n\n    private static final DateFormat DATE_FORMAT = new SimpleDateFormat(\"EEE MMM dd HH:mm:ss zzz yyyy\");\n\n    public KuraAlertPayload(final String code, final KuraAlertSeverity severity, final KuraAlertStatus status) {\n        setCode(code);\n        setSeverity(severity);\n        setStatus(status);\n    }\n\n    public void setCode(final String code) {\n        super.addMetric(CODE_METRIC_NAME, validateCode(code));\n    }\n\n    public void setSeverity(final KuraAlertSeverity severity) {\n        super.addMetric(SEVERITY_METRIC_NAME, severity.name());\n    }\n\n    public void setStatus(final KuraAlertStatus status) {\n        super.addMetric(STATUS_METRIC_NAME, status.name());\n    }\n\n    public void setCreationTimestamp(final Date date) {\n        super.addMetric(CREATION_TIMESTAMP_METRIC_NAME, date.toString());\n    }\n\n    public void setMessage(final String message) {\n        if (message == null) {\n            super.removeMetric(MESSAGE_METRIC_NAME);\n        } else {\n            super.addMetric(MESSAGE_METRIC_NAME, message);\n        }\n    }\n\n    public String getCode() {\n        return (String) getMetric(CODE_METRIC_NAME);\n    }\n\n    public KuraAlertSeverity getSeverity() {\n        return KuraAlertSeverity.valueOf((String) getMetric(SEVERITY_METRIC_NAME));\n    }\n\n    public KuraAlertStatus getStatus() {\n        return KuraAlertStatus.valueOf((String) getMetric(STATUS_METRIC_NAME));\n    }\n\n    public String getMessage() {\n        final Object rawMessage = getMetric(MESSAGE_METRIC_NAME);\n\n        if (rawMessage instanceof String) {\n            return (String) rawMessage;\n        }\n\n        return null;\n    }\n\n    public Date getCreationTimestamp() {\n        try {\n            return DATE_FORMAT.parse((String) getMetric(CREATION_TIMESTAMP_METRIC_NAME));\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    @Override\n    public void addMetric(String name, Object value) {\n        if (CODE_METRIC_NAME.equals(name)) {\n            setCode((String) value);\n            return;\n        } else if (MESSAGE_METRIC_NAME.equals(name)) {\n            setMessage((String) value);\n            return;\n        } else if (CREATION_TIMESTAMP_METRIC_NAME.equals(name)) {\n            setCreationTimestamp((Date) value);\n            return;\n        } else if (SEVERITY_METRIC_NAME.equals(name)) {\n            KuraAlertSeverity.valueOf((String) value);\n        } else if (STATUS_METRIC_NAME.equals(name)) {\n            KuraAlertStatus.valueOf((String) value);\n        }\n\n        super.addMetric(name, value);\n    }\n\n    private String validateCode(final String code) {\n        final String trimmed = code.trim();\n        if (trimmed.isEmpty()) {\n            throw new IllegalArgumentException(\"alert code cannot be empty\");\n        }\n        return trimmed;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraAlertSeverity.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\n/**\n * @since 2.0\n */\npublic enum KuraAlertSeverity {\n    WARNING,\n    CRITICAL;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraAlertStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\n/**\n * @since 2.0\n */\npublic enum KuraAlertStatus {\n    ACTIVE,\n    INACTIVE,\n    RESET;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraApplicationTopic.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Models the application specific part of the topic for messages posted to the Kura platform.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.0\n */\n@ProviderType\npublic abstract class KuraApplicationTopic {\n\n    protected String applicationId;\n    protected String applicationTopic;\n\n    public String getApplicationId() {\n        return this.applicationId;\n    }\n\n    public String getApplicationTopic() {\n        return this.applicationTopic;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraBirthPayload.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\nimport static org.eclipse.kura.message.KuraDeviceProfile.APPLICATION_FRAMEWORK_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.APPLICATION_FRAMEWORK_VERSION_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.AVAILABLE_PROCESSORS_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.BIOS_VERSION_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.CONNECTION_INTERFACE_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.CONNECTION_IP_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.CPU_VERSION_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.DEFAULT_APPLICATION_FRAMEWORK;\nimport static org.eclipse.kura.message.KuraDeviceProfile.DISPLAY_NAME_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.FIRMWARE_VERSION_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.JDK_VENDOR_VERSION_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.JVM_NAME_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.JVM_PROFILE_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.JVM_VENDOR_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.JVM_VERSION_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.KURA_VERSION_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.MODEL_ID_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.MODEL_NAME_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.OSGI_FRAMEWORK_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.OSGI_FRAMEWORK_VERSION_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.OS_ARCH_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.OS_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.OS_VERSION_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.PART_NUMBER_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.SERIAL_NUMBER_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.TOTAL_MEMORY_KEY;\nimport static org.eclipse.kura.message.KuraDeviceProfile.UPTIME_KEY;\n\nimport java.util.Optional;\n\n/**\n * The KuraBirthPayload is an extension of {@link KuraPayload} that contains the parameters that allow to define the\n * form of a device. The message is usually published when connecting to the broker.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.1\n */\npublic class KuraBirthPayload extends KuraPayload {\n\n    /**\n     * Provides information on the device tampering status.\n     * \n     * @since 2.2\n     */\n    public enum TamperStatus {\n\n        /**\n         * Tamper detection is not supported\n         */\n        UNSUPPORTED,\n        /**\n         * The device has been tampered\n         */\n        TAMPERED,\n        /**\n         * The device has not been tampered\n         */\n        NOT_TAMPERED;\n\n    }\n\n    private static final String ACCEPT_ENCODING_KEY = \"accept_encoding\";\n    private static final String APPLICATION_IDS_KEY = \"application_ids\";\n    private static final String MODEM_IMEI_KEY = \"modem_imei\";\n    private static final String MODEM_IMSI_KEY = \"modem_imsi\";\n    private static final String MODEM_ICCID_KEY = \"modem_iccid\";\n    private static final String MODEM_RSSI_KEY = \"modem_rssi\";\n    private static final String MODEM_FIRMWARE_VERSION = \"modem_firmware_version\";\n    private static final String PAYLOAD_ENCODING_KEY = \"payload_encoding\";\n    /**\n     * @since 2.2\n     */\n    private static final String TAMPER_STATUS = \"tamper_status\";\n\n    public String getUptime() {\n        return (String) getMetric(UPTIME_KEY);\n    }\n\n    public String getDisplayName() {\n        return (String) getMetric(DISPLAY_NAME_KEY);\n    }\n\n    public String getModelName() {\n        return (String) getMetric(MODEL_NAME_KEY);\n    }\n\n    public String getModelId() {\n        return (String) getMetric(MODEL_ID_KEY);\n    }\n\n    public String getPartNumber() {\n        return (String) getMetric(PART_NUMBER_KEY);\n    }\n\n    public String getSerialNumber() {\n        return (String) getMetric(SERIAL_NUMBER_KEY);\n    }\n\n    public String getFirmwareVersion() {\n        return (String) getMetric(FIRMWARE_VERSION_KEY);\n    }\n\n    public String getBiosVersion() {\n        return (String) getMetric(BIOS_VERSION_KEY);\n    }\n\n    /**\n     * @since 2.2\n     */\n    public String getCpuVersion() {\n        return (String) getMetric(CPU_VERSION_KEY);\n    }\n\n    public String getOs() {\n        return (String) getMetric(OS_KEY);\n    }\n\n    public String getOsVersion() {\n        return (String) getMetric(OS_VERSION_KEY);\n    }\n\n    public String getJvmName() {\n        return (String) getMetric(JVM_NAME_KEY);\n    }\n\n    public String getJvmVersion() {\n        return (String) getMetric(JVM_VERSION_KEY);\n    }\n\n    public String getJvmProfile() {\n        return (String) getMetric(JVM_PROFILE_KEY);\n    }\n\n    /**\n     * @since 2.2\n     */\n    public TamperStatus getTamperStatus() {\n        final String tamperStatus = (String) getMetric(TAMPER_STATUS);\n\n        if (tamperStatus == null) {\n            return TamperStatus.UNSUPPORTED;\n        }\n\n        return TamperStatus.valueOf(tamperStatus);\n    }\n\n    /**\n     * @deprecated Use {@link #getApplicationFrameworkVersion()}\n     */\n    @Deprecated\n    public String getKuraVersion() {\n        return (String) getMetric(KURA_VERSION_KEY);\n    }\n\n    public String getApplicationFramework() {\n        final String value = (String) getMetric(APPLICATION_FRAMEWORK_KEY);\n        if (value != null) {\n            return value;\n        }\n        return DEFAULT_APPLICATION_FRAMEWORK;\n    }\n\n    public String getApplicationFrameworkVersion() {\n        final String value = (String) getMetric(APPLICATION_FRAMEWORK_VERSION_KEY);\n        if (value != null) {\n            return value;\n        }\n        return (String) getMetric(KURA_VERSION_KEY);\n    }\n\n    public String getConnectionInterface() {\n        return (String) getMetric(CONNECTION_INTERFACE_KEY);\n    }\n\n    public String getConnectionIp() {\n        return (String) getMetric(CONNECTION_IP_KEY);\n    }\n\n    public String getAcceptEncoding() {\n        return (String) getMetric(ACCEPT_ENCODING_KEY);\n    }\n\n    public String getApplicationIdentifiers() {\n        return (String) getMetric(APPLICATION_IDS_KEY);\n    }\n\n    public String getAvailableProcessors() {\n        return (String) getMetric(AVAILABLE_PROCESSORS_KEY);\n    }\n\n    public String getTotalMemory() {\n        return (String) getMetric(TOTAL_MEMORY_KEY);\n    }\n\n    public String getOsArch() {\n        return (String) getMetric(OS_ARCH_KEY);\n    }\n\n    public String getOsgiFramework() {\n        return (String) getMetric(OSGI_FRAMEWORK_KEY);\n    }\n\n    public String getOsgiFrameworkVersion() {\n        return (String) getMetric(OSGI_FRAMEWORK_VERSION_KEY);\n    }\n\n    public String getModemImei() {\n        return (String) getMetric(MODEM_IMEI_KEY);\n    }\n\n    public String getModemImsi() {\n        return (String) getMetric(MODEM_IMSI_KEY);\n    }\n\n    public String getModemIccid() {\n        return (String) getMetric(MODEM_ICCID_KEY);\n    }\n\n    public String getModemRssi() {\n        return (String) getMetric(MODEM_RSSI_KEY);\n    }\n\n    /**\n     * @since 2.2\n     */\n    public String getModemFirmwareVersion() {\n        return (String) getMetric(MODEM_FIRMWARE_VERSION);\n    }\n\n    public String getPayloadEncoding() {\n        return (String) getMetric(PAYLOAD_ENCODING_KEY);\n    }\n\n    /**\n     * @since 2.6\n     */\n    public String getJvmVendor() {\n        return (String) getMetric(JVM_VENDOR_KEY);\n    }\n\n    /**\n     * @since 2.6\n     */\n    public String getJdkVendorVersion() {\n        return (String) getMetric(JDK_VENDOR_VERSION_KEY);\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"KuraBirthPayload [\");\n\n        sb.append(\"getUptime()=\").append(getUptime()).append(\", \");\n        sb.append(\"getDisplayName()=\").append(getDisplayName()).append(\", \");\n        sb.append(\"getModelName()=\").append(getModelName()).append(\", \");\n        sb.append(\"getModelId()=\").append(getModelId()).append(\", \");\n        sb.append(\"getPartNumber()=\").append(getPartNumber()).append(\", \");\n        sb.append(\"getSerialNumber()=\").append(getSerialNumber()).append(\", \");\n        sb.append(\"getFirmwareVersion()=\").append(getFirmwareVersion()).append(\", \");\n        sb.append(\"getAvailableProcessors()=\").append(getAvailableProcessors()).append(\", \");\n        sb.append(\"getTotalMemory()=\").append(getTotalMemory()).append(\", \");\n        sb.append(\"getBiosVersion()=\").append(getBiosVersion()).append(\", \");\n        sb.append(\"getCpuVersion()=\").append(getCpuVersion()).append(\", \");\n        sb.append(\"getOs()=\").append(getOs()).append(\", \");\n        sb.append(\"getOsVersion()=\").append(getOsVersion()).append(\", \");\n        sb.append(\"getOsArch()=\").append(getOsArch()).append(\", \");\n        sb.append(\"getJvmName()=\").append(getJvmName()).append(\", \");\n        sb.append(\"getJvmVersion()=\").append(getJvmVersion()).append(\", \");\n        sb.append(\"getJvmProfile()=\").append(getJvmProfile()).append(\", \");\n        sb.append(\"getKuraVersion()=\").append(getApplicationFrameworkVersion()).append(\", \");\n        sb.append(\"getApplicationFramework()=\").append(getApplicationFramework()).append(\", \");\n        sb.append(\"getApplicationFrameworkVersion()=\").append(getApplicationFrameworkVersion()).append(\", \");\n        sb.append(\"getOsgiFramework()=\").append(getOsgiFramework()).append(\", \");\n        sb.append(\"getOsgiFrameworkVersion()=\").append(getOsgiFrameworkVersion()).append(\", \");\n        sb.append(\"getConnectionInterface()=\").append(getConnectionInterface()).append(\", \");\n        sb.append(\"getConnectionIp()=\").append(getConnectionIp()).append(\", \");\n        sb.append(\"getAcceptEncoding()=\").append(getAcceptEncoding()).append(\", \");\n        sb.append(\"getApplicationIdentifiers()=\").append(getApplicationIdentifiers()).append(\", \");\n        sb.append(\"getPayloadEncoding()=\").append(getPayloadEncoding()).append(\", \");\n        sb.append(\"getTamperStatus()=\").append(getTamperStatus()).append(\", \");\n        sb.append(\"getJvmVendor()=\").append(getJvmVendor()).append(\", \");\n        sb.append(\"getJdkVendorVersion()=\").append(getJdkVendorVersion());\n\n        sb.append(\"]\");\n\n        return sb.toString();\n    }\n\n    @Override\n    public void addMetric(String name, Object value) {\n        if (value != null) {\n            super.addMetric(name, value);\n        }\n    }\n\n    public static class KuraBirthPayloadBuilder {\n\n        private String uptime;\n        private String displayName;\n        private String availableProcessors;\n        private String totalMemory;\n        private String osArch;\n        private String modelName;\n        private String modelId;\n        private String partNumber;\n        private String serialNumber;\n        private String firmwareVersion;\n        private String biosVersion;\n        private String cpuVersion;\n        private String os;\n        private String osVersion;\n        private String jvmName;\n        private String jvmVersion;\n        private String jvmProfile;\n        private String jvmVendor;\n        private Optional<String> jdkVendorVersion;\n        private String kuraVersion;\n        private String applicationFramework;\n        private String applicationFrameworkVersion;\n        private String connectionInterface;\n        private String connectionIp;\n        private String acceptEncoding;\n        private String applicationIdentifiers;\n        private String osgiFramework;\n        private String osgiFrameworkVersion;\n        private String modemImei;\n        private String modemIccid;\n        private String modemImsi;\n        private String modemRssi;\n        private String modemFirmwareVersion;\n        private String payloadEncoding;\n        private TamperStatus tamperStatus;\n\n        private KuraPosition position;\n\n        public KuraBirthPayloadBuilder withUptime(String uptime) {\n            this.uptime = uptime;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withDisplayName(String displayName) {\n            this.displayName = displayName;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withAvailableProcessors(String availableProcessors) {\n            this.availableProcessors = availableProcessors;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withTotalMemory(String totalMemory) {\n            this.totalMemory = totalMemory;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withOsArch(String osArch) {\n            this.osArch = osArch;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withOsgiFramework(String osgiFramework) {\n            this.osgiFramework = osgiFramework;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withOsgiFrameworkVersion(String osgiFrameworkVersion) {\n            this.osgiFrameworkVersion = osgiFrameworkVersion;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withModelName(String modelName) {\n            this.modelName = modelName;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withModelId(String modelId) {\n            this.modelId = modelId;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withPartNumber(String partNumber) {\n            this.partNumber = partNumber;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withSerialNumber(String serialNumber) {\n            this.serialNumber = serialNumber;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withFirmwareVersion(String firmwareVersion) {\n            this.firmwareVersion = firmwareVersion;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withBiosVersion(String biosVersion) {\n            this.biosVersion = biosVersion;\n            return this;\n        }\n\n        /**\n         * @since 2.2\n         */\n        public KuraBirthPayloadBuilder withCpuVersion(String cpuVersion) {\n            this.cpuVersion = cpuVersion;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withOs(String os) {\n            this.os = os;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withOsVersion(String osVersion) {\n            this.osVersion = osVersion;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withJvmName(String jvmName) {\n            this.jvmName = jvmName;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withJvmVersion(String jvmVersion) {\n            this.jvmVersion = jvmVersion;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withJvmProfile(String jvmProfile) {\n            this.jvmProfile = jvmProfile;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withKuraVersion(String kuraVersion) {\n            withApplicationFramework(DEFAULT_APPLICATION_FRAMEWORK);\n            withApplicationFrameworkVersion(kuraVersion);\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withApplicationFramework(String applicationFramework) {\n            this.applicationFramework = applicationFramework;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withApplicationFrameworkVersion(String applicationFrameworkVersion) {\n            this.applicationFrameworkVersion = applicationFrameworkVersion;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withConnectionInterface(String connectionInterface) {\n            this.connectionInterface = connectionInterface;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withConnectionIp(String connectionIp) {\n            this.connectionIp = connectionIp;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withAcceptEncoding(String acceptEncoding) {\n            this.acceptEncoding = acceptEncoding;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withApplicationIdentifiers(String applicationIdentifiers) {\n            this.applicationIdentifiers = applicationIdentifiers;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withModemImei(String modemImei) {\n            this.modemImei = modemImei;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withModemIccid(String modemIccid) {\n            this.modemIccid = modemIccid;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withModemImsi(String modemImsi) {\n            this.modemImsi = modemImsi;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withModemRssi(String modemRssi) {\n            this.modemRssi = modemRssi;\n            return this;\n        }\n\n        /**\n         * @since 2.2\n         */\n        public KuraBirthPayloadBuilder withModemFirmwareVersion(String modemFirmwareVersion) {\n            this.modemFirmwareVersion = modemFirmwareVersion;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withPosition(KuraPosition position) {\n            this.position = position;\n            return this;\n        }\n\n        public KuraBirthPayloadBuilder withPayloadEncoding(String payloadEncoding) {\n            this.payloadEncoding = payloadEncoding;\n            return this;\n        }\n\n        /**\n         * @since 2.2\n         */\n        public KuraBirthPayloadBuilder withTamperStatus(TamperStatus tamperStatus) {\n            this.tamperStatus = tamperStatus;\n            return this;\n        }\n\n        /**\n         * \n         * @since 2.6\n         * @param jvmVendor\n         * @return\n         */\n        public KuraBirthPayloadBuilder withJvmVendor(String jvmVendor) {\n            this.jvmVendor = jvmVendor;\n            return this;\n        }\n\n        /**\n         * \n         * @since 2.6\n         * @param jdkVendorVersion\n         * @return\n         */\n        public KuraBirthPayloadBuilder withJdkVendorVersion(String jdkVendorVersion) {\n            this.jdkVendorVersion = Optional.ofNullable(jdkVendorVersion);\n            return this;\n        }\n\n        public KuraBirthPayload build() {\n            KuraBirthPayload birthPayload = new KuraBirthPayload();\n\n            birthPayload.addMetric(UPTIME_KEY, this.uptime);\n\n            birthPayload.addMetric(DISPLAY_NAME_KEY, this.displayName);\n            birthPayload.addMetric(MODEL_NAME_KEY, this.modelName);\n            birthPayload.addMetric(MODEL_ID_KEY, this.modelId);\n            birthPayload.addMetric(PART_NUMBER_KEY, this.partNumber);\n            birthPayload.addMetric(SERIAL_NUMBER_KEY, this.serialNumber);\n            birthPayload.addMetric(FIRMWARE_VERSION_KEY, this.firmwareVersion);\n            birthPayload.addMetric(BIOS_VERSION_KEY, this.biosVersion);\n            birthPayload.addMetric(CPU_VERSION_KEY, this.cpuVersion);\n            birthPayload.addMetric(OS_KEY, this.os);\n            birthPayload.addMetric(OS_VERSION_KEY, this.osVersion);\n            birthPayload.addMetric(JVM_NAME_KEY, this.jvmName);\n            birthPayload.addMetric(JVM_VERSION_KEY, this.jvmVersion);\n            birthPayload.addMetric(JVM_PROFILE_KEY, this.jvmProfile);\n            birthPayload.addMetric(KURA_VERSION_KEY, this.kuraVersion);\n            if (this.applicationFramework != null) {\n                birthPayload.addMetric(APPLICATION_FRAMEWORK_KEY, this.applicationFramework);\n            } else {\n                birthPayload.addMetric(APPLICATION_FRAMEWORK_KEY, DEFAULT_APPLICATION_FRAMEWORK);\n            }\n            birthPayload.addMetric(KURA_VERSION_KEY, this.applicationFrameworkVersion);\n            birthPayload.addMetric(APPLICATION_FRAMEWORK_VERSION_KEY, this.applicationFrameworkVersion);\n            birthPayload.addMetric(CONNECTION_INTERFACE_KEY, this.connectionInterface);\n            birthPayload.addMetric(CONNECTION_IP_KEY, this.connectionIp);\n            birthPayload.addMetric(ACCEPT_ENCODING_KEY, this.acceptEncoding);\n            birthPayload.addMetric(APPLICATION_IDS_KEY, this.applicationIdentifiers);\n            birthPayload.addMetric(AVAILABLE_PROCESSORS_KEY, this.availableProcessors);\n            birthPayload.addMetric(TOTAL_MEMORY_KEY, this.totalMemory);\n            birthPayload.addMetric(OS_ARCH_KEY, this.osArch);\n            birthPayload.addMetric(OSGI_FRAMEWORK_KEY, this.osgiFramework);\n            birthPayload.addMetric(OSGI_FRAMEWORK_VERSION_KEY, this.osgiFrameworkVersion);\n            birthPayload.addMetric(MODEM_IMEI_KEY, this.modemImei);\n            birthPayload.addMetric(MODEM_ICCID_KEY, this.modemIccid);\n            birthPayload.addMetric(MODEM_IMSI_KEY, this.modemImsi);\n            birthPayload.addMetric(MODEM_RSSI_KEY, this.modemRssi);\n            birthPayload.addMetric(MODEM_FIRMWARE_VERSION, this.modemFirmwareVersion);\n            birthPayload.addMetric(PAYLOAD_ENCODING_KEY, this.payloadEncoding);\n            if (tamperStatus != null && tamperStatus != TamperStatus.UNSUPPORTED) {\n                birthPayload.addMetric(TAMPER_STATUS, tamperStatus.name());\n            }\n            birthPayload.setPosition(this.position);\n\n            birthPayload.addMetric(JVM_VENDOR_KEY, this.jvmVendor);\n            if (this.jdkVendorVersion.isPresent()) {\n                birthPayload.addMetric(JDK_VENDOR_VERSION_KEY, this.jdkVendorVersion.get());\n            }\n\n            return birthPayload;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraDeviceProfile.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\n/**\n * The KuraDeviceProfile is a container class that holds the parameters that make up the from of a device.\n * This information is used to build the birth and disconnect certificates that are published when\n * connecting to and disconnecting from the broker.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.1\n *\n */\npublic class KuraDeviceProfile {\n\n    public static final String UPTIME_KEY = \"uptime\";\n    public static final String DISPLAY_NAME_KEY = \"display_name\";\n    public static final String MODEL_NAME_KEY = \"model_name\";\n    public static final String MODEL_ID_KEY = \"model_id\";\n    public static final String PART_NUMBER_KEY = \"part_number\";\n    public static final String SERIAL_NUMBER_KEY = \"serial_number\";\n    public static final String AVAILABLE_PROCESSORS_KEY = \"available_processors\";\n    public static final String TOTAL_MEMORY_KEY = \"total_memory\";\n    public static final String FIRMWARE_VERSION_KEY = \"firmware_version\";\n    /**\n     * @since 2.2\n     */\n    public static final String CPU_VERSION_KEY = \"cpu_version\";\n    public static final String BIOS_VERSION_KEY = \"bios_version\";\n    public static final String OS_KEY = \"os\";\n    public static final String OS_VERSION_KEY = \"os_version\";\n    public static final String OS_ARCH_KEY = \"os_arch\";\n    public static final String JVM_NAME_KEY = \"jvm_name\";\n    public static final String JVM_VERSION_KEY = \"jvm_version\";\n    public static final String JVM_PROFILE_KEY = \"jvm_profile\";\n    public static final String KURA_VERSION_KEY = \"kura_version\";\n    public static final String APPLICATION_FRAMEWORK_KEY = \"application_framework\";\n    public static final String APPLICATION_FRAMEWORK_VERSION_KEY = \"application_framework_version\";\n    public static final String OSGI_FRAMEWORK_KEY = \"osgi_framework\";\n    public static final String OSGI_FRAMEWORK_VERSION_KEY = \"osgi_framework_version\";\n    public static final String CONNECTION_INTERFACE_KEY = \"connection_interface\";\n    public static final String CONNECTION_IP_KEY = \"connection_ip\";\n\n    public static final String DEFAULT_APPLICATION_FRAMEWORK = \"Kura\";\n\n    /**\n     * @since 2.6\n     */\n    public static final String JVM_VENDOR_KEY = \"jvm_vendor\";\n    /**\n     * @since 2.6\n     */\n    public static final String JDK_VENDOR_VERSION_KEY = \"jdk_vendor_version\";\n\n    private String uptime;\n    private String displayName;\n    private String modelName;\n    private String modelId;\n    private String partNumber;\n    private String serialNumber;\n    private String availableProcessors;\n    private String totalMemory;\n    private String firmwareVersion;\n    private String biosVersion;\n    private String cpuVersion;\n    private String os;\n    private String osVersion;\n    private String osArch;\n    private String jvmName;\n    private String jvmVersion;\n    private String jvmProfile;\n    private String applicationFramework;\n    private String applicationFrameworkVersion;\n    private String osgiFramework;\n    private String osgiFrameworkVersion;\n    private String connectionInterface;\n    private String connectionIp;\n    private Double latitude;\n    private Double longitude;\n    private Double altitude;\n    private String jvmVendor;\n    private String jdkVendorVersion;\n\n    /**\n     * Empty constructor for a KuraDeviceProfile.\n     */\n    public KuraDeviceProfile() {\n        // Values filled with setters\n    }\n\n    /**\n     * Returns The length of time the unit has been powered on.\n     *\n     * @return A String representing the length of time the device has been powered on.\n     */\n    public String getUptime() {\n        return this.uptime;\n    }\n\n    /**\n     * Returns the readable display name for the device.\n     *\n     * @return A String representing the readable display name for the device.\n     */\n    public String getDisplayName() {\n        return this.displayName;\n    }\n\n    /**\n     * Returns the device model name\n     *\n     * @return A String representing the device model name\n     */\n    public String getModelName() {\n        return this.modelName;\n    }\n\n    /**\n     * Returns the device model ID.\n     *\n     * @return A String representing the device model ID.\n     */\n    public String getModelId() {\n        return this.modelId;\n    }\n\n    /**\n     * Returns the part number of the device.\n     *\n     * @return A String representing the part number of the device.\n     */\n    public String getPartNumber() {\n        return this.partNumber;\n    }\n\n    /**\n     * Returns the serial number of the device.\n     *\n     * @return A String representing the serial number of the device.\n     */\n    public String getSerialNumber() {\n        return this.serialNumber;\n    }\n\n    /**\n     * Returns the version of firmware running on the device.\n     *\n     * @return A String representing the version of firmware running on the device.\n     */\n    public String getFirmwareVersion() {\n        return this.firmwareVersion;\n    }\n\n    /**\n     * Returns the version of the BIOS on the device.\n     *\n     * @return A String representing the version of the BIOS on the device.\n     */\n    public String getBiosVersion() {\n        return this.biosVersion;\n    }\n\n    /**\n     * Returns the CPU version information.\n     * \n     * @since 2.2\n     * @return A string representing the CPU version information.\n     */\n    public String getCpuVersion() {\n        return this.cpuVersion;\n    }\n\n    /**\n     * Returns the name of the operating system.\n     *\n     * @return A String representing the name of the operating system.\n     */\n    public String getOs() {\n        return this.os;\n    }\n\n    /**\n     * Returns the version of the operating system.\n     *\n     * @return A String representing the version of the operating system.\n     */\n    public String getOsVersion() {\n        return this.osVersion;\n    }\n\n    /**\n     * Returns the name of the JVM.\n     *\n     * @return A String representing the name of the JVM.\n     */\n    public String getJvmName() {\n        return this.jvmName;\n    }\n\n    /**\n     * Returns the version of the JVM.\n     *\n     * @return A String representing the version of the JVM.\n     */\n    public String getJvmVersion() {\n        return this.jvmVersion;\n    }\n\n    /**\n     * Returns the profile of the JVM.\n     *\n     * @return A String representing the profile of the JVM.\n     */\n    public String getJvmProfile() {\n        return this.jvmProfile;\n    }\n\n    /**\n     * Returns the Kura version.\n     *\n     * @return A String representing the Kura version\n     * @deprecated use {@link #getApplicationFrameworkVersion()} instead\n     */\n    @Deprecated\n    public String getKuraVersion() {\n        return this.applicationFrameworkVersion;\n    }\n\n    /**\n     * Returns the Application Framework.\n     *\n     * @return A String representing the Application Framework\n     */\n    public String getApplicationFramework() {\n        return this.applicationFramework;\n    }\n\n    /**\n     * Returns the Application Framework version.\n     *\n     * @return A String representing the Application Framework version\n     */\n    public String getApplicationFrameworkVersion() {\n        return this.applicationFrameworkVersion;\n    }\n\n    /**\n     * Returns the name of the interface used to connect to the cloud.\n     *\n     * @return A String representing the name of the interface used to connect to the cloud.\n     */\n    public String getConnectionInterface() {\n        return this.connectionInterface;\n    }\n\n    /**\n     * Returns the IP address of the interface used to connect to the cloud.\n     *\n     * @return A String representing the IP address of the interface used to connect to the cloud.\n     */\n    public String getConnectionIp() {\n        return this.connectionIp;\n    }\n\n    /**\n     * Returns the latitude of the device's location.\n     *\n     * @return A String representing the latitude of the device's location.\n     */\n    public Double getLatitude() {\n        return this.latitude;\n    }\n\n    /**\n     * Returns the longitude of the device's location.\n     *\n     * @return A String representing the longitude of the device's location.\n     */\n    public Double getLongitude() {\n        return this.longitude;\n    }\n\n    /**\n     * Returns the altitude of the device's location.\n     *\n     * @return A String representing thealtitude of the device's location.\n     */\n    public Double getAltitude() {\n        return this.altitude;\n    }\n\n    /**\n     * \n     * @since 2.6\n     * @return a String representing the JVM vendor name.\n     */\n    public String getJvmVendor() {\n        return this.jvmVendor;\n    }\n\n    /**\n     * \n     * @since 2.6\n     * @return a String representing the JDK vendor version.\n     */\n    public String getJdkVendorVersion() {\n        return this.jdkVendorVersion;\n    }\n\n    /**\n     * Sets the length of time the unit has been powered on.\n     *\n     * @param uptime\n     *            A String representing the length of time the unit has been powered on.\n     */\n    public void setUptime(String uptime) {\n        this.uptime = uptime;\n    }\n\n    /**\n     * Sets the readable display name for the device\n     *\n     * @param displayName\n     *            A String representing the readable display name for the device\n     */\n    public void setDisplayName(String displayName) {\n        this.displayName = displayName;\n    }\n\n    /**\n     * Sets the device model name.\n     *\n     * @param modelName\n     *            A String representing the device model name.\n     */\n    public void setModelName(String modelName) {\n        this.modelName = modelName;\n    }\n\n    /**\n     * Sets the device model ID.\n     *\n     * @param modelId\n     *            A String representing the device model ID.\n     */\n    public void setModelId(String modelId) {\n        this.modelId = modelId;\n    }\n\n    /**\n     * Sets the part number of the device.\n     *\n     * @param partNumber\n     *            A String representing the part number of the device.\n     */\n    public void setPartNumber(String partNumber) {\n        this.partNumber = partNumber;\n    }\n\n    /**\n     * Sets the serial number of the device.\n     *\n     * @param serialNumber\n     *            A String representing the serial number of the device.\n     */\n    public void setSerialNumber(String serialNumber) {\n        this.serialNumber = serialNumber;\n    }\n\n    /**\n     * Sets the version of firmware running on the device.\n     *\n     * @param firmwareVersion\n     *            A String representing the version of firmware running on the device.\n     */\n    public void setFirmwareVersion(String firmwareVersion) {\n        this.firmwareVersion = firmwareVersion;\n    }\n\n    /**\n     * Sets the version of the BIOS on the device.\n     *\n     * @param biosVersion\n     *            A String representing the version of the BIOS on the device.\n     */\n    public void setBiosVersion(String biosVersion) {\n        this.biosVersion = biosVersion;\n    }\n\n    /**\n     * Sets the CPU version information\n     * \n     * @since 2.2\n     * @param cpuVersion\n     *            the CPU version information\n     */\n    public void setCpuVersion(String cpuVersion) {\n        this.cpuVersion = cpuVersion;\n    }\n\n    /**\n     * Sets the name of the operating system.\n     *\n     * @param os\n     *            A String representing the name of the operating system.\n     */\n    public void setOs(String os) {\n        this.os = os;\n    }\n\n    /**\n     * Sets the version of the operating system.\n     *\n     * @param osVersion\n     *            A String representing the version of the operating system.\n     */\n    public void setOsVersion(String osVersion) {\n        this.osVersion = osVersion;\n    }\n\n    /**\n     * Sets the name of the JVM.\n     *\n     * @param jvmName\n     *            A String representing the name of the JVM.\n     */\n    public void setJvmName(String jvmName) {\n        this.jvmName = jvmName;\n    }\n\n    /**\n     * Sets the version of the JVM.\n     *\n     * @param jvmVersion\n     *            A String representing the version of the JVM.\n     */\n    public void setJvmVersion(String jvmVersion) {\n        this.jvmVersion = jvmVersion;\n    }\n\n    /**\n     * Sets the profile of the JVM.\n     *\n     * @param jvmProfile\n     *            A String representing the profile of the JVM.\n     */\n    public void setJvmProfile(String jvmProfile) {\n        this.jvmProfile = jvmProfile;\n    }\n\n    /**\n     * Sets the name of the interface used to connect to the cloud.\n     *\n     * @param connectionInterface\n     *            A String representing the name of the interface used to connect to the cloud.\n     */\n    public void setConnectionInterface(String connectionInterface) {\n        this.connectionInterface = connectionInterface;\n    }\n\n    /**\n     * Sets the IP address of the interface used to connect to the cloud.\n     *\n     * @param connectionIp\n     *            A String representing the IP address of the interface used to connect to the cloud.\n     */\n    public void setConnectionIp(String connectionIp) {\n        this.connectionIp = connectionIp;\n    }\n\n    /**\n     * Sets the latitude of the device's location.\n     *\n     * @param latitude\n     *            A String representing the latitude of the device's location.\n     */\n    public void setLatitude(Double latitude) {\n        this.latitude = latitude;\n    }\n\n    /**\n     * Sets the longitude of the device's location.\n     *\n     * @param longitude\n     *            A String representing the longitude of the device's location.\n     */\n    public void setLongitude(Double longitude) {\n        this.longitude = longitude;\n    }\n\n    /**\n     * Sets the altitude of the device's location.\n     *\n     * @param altitude\n     *            A String representing the altitude of the device's location.\n     */\n    public void setAltitude(Double altitude) {\n        this.altitude = altitude;\n    }\n\n    /**\n     * \n     * @since 2.6\n     * @param jvmVendor a String representing the JVM vendor name.\n     */\n    public void setJvmVendor(String jvmVendor) {\n        this.jvmVendor = jvmVendor;\n    }\n\n    /**\n     * \n     * @since 2.6\n     * @param jdkVendorVersion a String representing the JDK vendor version.\n     */\n    public void setJdkVendorVersion(String jdkVendorVersion) {\n        this.jdkVendorVersion = jdkVendorVersion;\n    }\n\n    public String getAvailableProcessors() {\n        return this.availableProcessors;\n    }\n\n    public void setAvailableProcessors(String availableProcessors) {\n        this.availableProcessors = availableProcessors;\n    }\n\n    public void setApplicationFramework(String applicationFramework) {\n        this.applicationFramework = applicationFramework;\n    }\n\n    public void setApplicationFrameworkVersion(String applicationFrameworkVersion) {\n        this.applicationFrameworkVersion = applicationFrameworkVersion;\n    }\n\n    public String getTotalMemory() {\n        return this.totalMemory;\n    }\n\n    public void setTotalMemory(String totalMemory) {\n        this.totalMemory = totalMemory;\n    }\n\n    public String getOsArch() {\n        return this.osArch;\n    }\n\n    public void setOsArch(String osArch) {\n        this.osArch = osArch;\n    }\n\n    public String getOsgiFramework() {\n        return this.osgiFramework;\n    }\n\n    public void setOsgiFramework(String osgiFramework) {\n        this.osgiFramework = osgiFramework;\n    }\n\n    public String getOsgiFrameworkVersion() {\n        return this.osgiFrameworkVersion;\n    }\n\n    public void setOsgiFrameworkVersion(String osgiFrameworkVersion) {\n        this.osgiFrameworkVersion = osgiFrameworkVersion;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraDisconnectPayload.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\nimport java.util.Iterator;\n\n/**\n * The KuraDisconnectPayload is an extension of {@link KuraPayload} that contains the parameters stored in a message\n * that is usually published when disconnecting from the broker.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.1\n */\npublic class KuraDisconnectPayload extends KuraPayload {\n\n    private static final String UPTIME = \"uptime\";\n    private static final String DISPLAY_NAME = \"display_name\";\n\n    public KuraDisconnectPayload(String uptime, String displayName) {\n        super();\n\n        addMetric(UPTIME, uptime);\n        addMetric(DISPLAY_NAME, displayName);\n    }\n\n    public KuraDisconnectPayload(KuraPayload kuraMessage) {\n        Iterator<String> hdrIterator = kuraMessage.metricsIterator();\n        while (hdrIterator.hasNext()) {\n            String hdrName = hdrIterator.next();\n            String hdrVal = (String) kuraMessage.getMetric(hdrName);\n            addMetric(hdrName, hdrVal);\n        }\n        setBody(kuraMessage.getBody());\n    }\n\n    public String getUptime() {\n        return (String) getMetric(UPTIME);\n    }\n\n    public String getDisplayName() {\n        return (String) getMetric(DISPLAY_NAME);\n    }\n\n    @Override\n    public String toString() {\n        return \"KuraBirthMessage [getUptime()=\" + getUptime() + \", getDisplayName()=\" + getDisplayName() + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraPayload.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraPayload defines the recommended payload structure for the messages sent to a remote cloud platform.\n * It was defined as an open format that is flexible from the aspect of data modeling\n * yet is efficient when it comes to bandwidth conservation. The same payload model could be used by the REST API\n * - in which case it is serialized into XML or JSON as requested by the client - or uses the efficient\n * Google ProtoBuf when sent over an MQTT connection when the bandwidth is very important.\n * The KuraPayload contains the following fields: sentOn timestamp, an optional set of metrics represented as\n * name-value pairs, an optional position field to capture a GPS position, and an optional binary body.\n * <ul>\n * <li>sentOn: it is the timestamp when the data was captured and sent to the remote cloud platform.\n * <li>metrics: a metric is a data structure composed of the name, a value, and the type of the value.\n * When used with the REST API valid metric types are: string, double, int, float, long, boolean, base64Binary.\n *\n * Each payload can have zero or more metrics.\n * <li>position: it is an optional field used to capture a geo position associated to this payload.\n * <li>body: it is an optional part of the payload that allows additional information to be transmitted in any format\n * determined by the user.\n * </ul>\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraPayload {\n\n    /**\n     * Timestamp when the data was captured and sent to the remote cloud platform.\n     */\n    private Date timestamp;\n\n    /**\n     * It is an optional field used to capture a geo position associated to this payload.\n     */\n    private KuraPosition position;\n\n    /**\n     * A metric is a data structure composed of the name, a value, and the type of the value.\n     * When used with the REST API valid metric types are: string, double, int, float, long, boolean, base64Binary.\n     * Each payload can have zero or more metrics.\n     */\n    private final Map<String, Object> metrics;\n\n    /**\n     * It is an optional part of the payload that allows additional information to be transmitted in any format\n     * determined by the user.\n     */\n    private byte[] body;\n\n    public KuraPayload() {\n        this.metrics = new HashMap<>();\n        this.body = null;\n    }\n\n    public Date getTimestamp() {\n        return this.timestamp;\n    }\n\n    public void setTimestamp(Date timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    public KuraPosition getPosition() {\n        return this.position;\n    }\n\n    public void setPosition(KuraPosition position) {\n        this.position = position;\n    }\n\n    public Object getMetric(String name) {\n        return this.metrics.get(name);\n    }\n\n    public void addMetric(String name, Object value) {\n        this.metrics.put(name, value);\n    }\n\n    public void removeMetric(String name) {\n        this.metrics.remove(name);\n    }\n\n    public void removeAllMetrics() {\n        this.metrics.clear();\n    }\n\n    public Set<String> metricNames() {\n        return Collections.unmodifiableSet(this.metrics.keySet());\n    }\n\n    public Iterator<String> metricsIterator() {\n        return this.metrics.keySet().iterator();\n    }\n\n    public Map<String, Object> metrics() {\n        return Collections.unmodifiableMap(this.metrics);\n    }\n\n    public byte[] getBody() {\n        return this.body;\n    }\n\n    public void setBody(byte[] body) {\n        this.body = body;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraPosition.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\nimport java.util.Date;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * KuraPosition is a data structure to capture a geo location. It can be\n * associated to a KuraPayload to geotag a KuraMessage before sending to a\n * remote cloud platform. Refer to the description of each of the fields for more\n * information on the model of KuraPosition.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraPosition {\n\n    /**\n     * Longitude of this position in degrees. This is a mandatory field.\n     */\n    private Double longitude;\n\n    /**\n     * Latitude of this position in degrees. This is a mandatory field.\n     */\n    private Double latitude;\n\n    /**\n     * Altitude of the position in meters.\n     */\n    private Double altitude;\n\n    /**\n     * Dilution of the precision (DOP) of the current GPS fix.\n     */\n    private Double precision;\n\n    /**\n     * Heading (direction) of the position in degrees\n     */\n    private Double heading;\n\n    /**\n     * Speed for this position in meter/sec.\n     */\n    private Double speed;\n\n    /**\n     * Timestamp extracted from the GPS system\n     */\n    private Date timestamp;\n\n    /**\n     * Number of satellites seen by the systems\n     */\n    private Integer satellites;\n\n    /**\n     * Status of GPS system: 1 = no GPS response, 2 = error in response, 4 =\n     * valid.\n     */\n    private Integer status;\n\n    public KuraPosition() {\n    }\n\n    public Double getLongitude() {\n        return this.longitude;\n    }\n\n    public void setLongitude(double longitude) {\n        this.longitude = longitude;\n    }\n\n    public Double getLatitude() {\n        return this.latitude;\n    }\n\n    public void setLatitude(double latitude) {\n        this.latitude = latitude;\n    }\n\n    public Double getAltitude() {\n        return this.altitude;\n    }\n\n    public void setAltitude(double altitude) {\n        this.altitude = altitude;\n    }\n\n    public Double getPrecision() {\n        return this.precision;\n    }\n\n    public void setPrecision(double precision) {\n        this.precision = precision;\n    }\n\n    public Double getHeading() {\n        return this.heading;\n    }\n\n    public void setHeading(double heading) {\n        this.heading = heading;\n    }\n\n    public Double getSpeed() {\n        return this.speed;\n    }\n\n    public void setSpeed(double speed) {\n        this.speed = speed;\n    }\n\n    public Date getTimestamp() {\n        return this.timestamp;\n    }\n\n    public void setTimestamp(Date timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    public Integer getSatellites() {\n        return this.satellites;\n    }\n\n    public void setSatellites(int satellites) {\n        this.satellites = satellites;\n    }\n\n    public Integer getStatus() {\n        return this.status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraRequestPayload.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\nimport java.text.ParseException;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraRequestPayload extends KuraPayload {\n\n    public static final String METRIC_REQUEST_ID = \"request.id\";\n    public static final String REQUESTER_CLIENT_ID = \"requester.client.id\";\n\n    public KuraRequestPayload() {\n        super();\n    }\n\n    public KuraRequestPayload(KuraPayload payload) {\n        super();\n\n        for (String name : payload.metricNames()) {\n            Object value = payload.getMetric(name);\n            addMetric(name, value);\n        }\n\n        setBody(payload.getBody());\n        setPosition(payload.getPosition());\n        setTimestamp(payload.getTimestamp());\n    }\n\n    public String getRequestId() {\n        return (String) getMetric(METRIC_REQUEST_ID);\n    }\n\n    public void setRequestId(String requestId) {\n        addMetric(METRIC_REQUEST_ID, requestId);\n    }\n\n    public String getRequesterClientId() {\n        return (String) getMetric(REQUESTER_CLIENT_ID);\n    }\n\n    public void setRequesterClientId(String requesterClientId) {\n        addMetric(REQUESTER_CLIENT_ID, requesterClientId);\n    }\n\n    public static KuraRequestPayload buildFromKuraPayload(KuraPayload payload) throws ParseException {\n        if (payload.getMetric(METRIC_REQUEST_ID) == null) {\n            throw new ParseException(\"Not a valid request payload\", 0);\n        }\n        KuraRequestPayload requestPayload = new KuraRequestPayload(payload);\n        return requestPayload;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraResponsePayload.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class KuraResponsePayload extends KuraPayload {\n\n    public static final int RESPONSE_CODE_OK = 200;\n    public static final int RESPONSE_CODE_BAD_REQUEST = 400;\n    public static final int RESPONSE_CODE_NOTFOUND = 404;\n    public static final int RESPONSE_CODE_ERROR = 500;\n\n    public static final String METRIC_RESPONSE_CODE = \"response.code\";\n    public static final String METRIC_EXCEPTION_MSG = \"response.exception.message\";\n    public static final String METRIC_EXCEPTION_STACK = \"response.exception.stack\";\n\n    public KuraResponsePayload(int responseCode) {\n        super();\n        addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode));\n    }\n\n    public KuraResponsePayload(Throwable t) {\n        this(RESPONSE_CODE_ERROR, t);\n    }\n\n    public KuraResponsePayload(int responseCode, Throwable t) {\n        super();\n        addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode));\n        setException(t);\n    }\n\n    public KuraResponsePayload(KuraPayload kuraPayload) {\n        for (String name : kuraPayload.metricNames()) {\n            Object value = kuraPayload.getMetric(name);\n            addMetric(name, value);\n        }\n        setBody(kuraPayload.getBody());\n    }\n\n    public int getResponseCode() {\n        return (Integer) getMetric(METRIC_RESPONSE_CODE);\n    }\n\n    public void setResponseCode(int responseCode) {\n        addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode));\n    }\n\n    public String getExceptionMessage() {\n        return (String) getMetric(METRIC_EXCEPTION_MSG);\n    }\n\n    public void setExceptionMessage(String message) {\n        if (message != null) {\n            addMetric(METRIC_EXCEPTION_MSG, message);\n        }\n    }\n\n    public String getExceptionStack() {\n        return (String) getMetric(METRIC_EXCEPTION_STACK);\n    }\n\n    public void setExceptionStack(String stack) {\n        if (stack != null) {\n            addMetric(METRIC_EXCEPTION_STACK, stack);\n        }\n    }\n\n    public void setException(Throwable t) {\n        if (t != null) {\n            addMetric(METRIC_EXCEPTION_MSG, t.getMessage());\n            addMetric(METRIC_EXCEPTION_STACK, stackTraceAsString(t));\n        }\n    }\n\n    private String stackTraceAsString(Throwable t) {\n        StringWriter sw = new StringWriter();\n        PrintWriter pw = new PrintWriter(sw);\n        t.printStackTrace(pw);\n        return sw.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraTopic.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Models a topic for messages posted to the Kura platform.\n * Topics are expected to be in the form of \"account/asset/&lt;application_specific&gt;\";\n * The system control topic prefix is defined in the {@link org.eclipse.kura.cloud.CloudService} and defaults\n * to $EDC.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @deprecated Please use the new Cloud Connection APIs and refer to {@link KuraApplicationTopic}\n */\n@Deprecated\n@ProviderType\npublic class KuraTopic {\n\n    private String fullTopic;\n    private String[] topicParts;\n    private String prefix;\n    private String accountName;\n    private String deviceId;\n    private String applicationId;\n    private String applicationTopic;\n\n    public KuraTopic(String fullTopic) {\n        this(fullTopic, \"$\");\n    }\n\n    public KuraTopic(String fullTopic, String controlPrefix) {\n        this.fullTopic = fullTopic;\n        if (fullTopic.compareTo(\"#\") == 0) {\n            return;\n        }\n\n        this.topicParts = fullTopic.split(\"/\");\n        if (this.topicParts.length == 0) {\n            return;\n        }\n\n        // prefix\n        int index = 0;\n        int offset = 0; // skip a slash\n        if (this.topicParts[0].startsWith(controlPrefix)) {\n            this.prefix = this.topicParts[index];\n            offset += this.prefix.length() + 1;\n            index++;\n        }\n\n        // account name\n        if (index < this.topicParts.length) {\n            this.accountName = this.topicParts[index];\n            offset += this.accountName.length() + 1;\n            index++;\n        }\n\n        // deviceId\n        if (index < this.topicParts.length) {\n            this.deviceId = this.topicParts[index];\n            offset += this.deviceId.length() + 1;\n            index++;\n        }\n\n        // applicationId\n        if (index < this.topicParts.length) {\n            this.applicationId = this.topicParts[index];\n            offset += this.applicationId.length() + 1;\n            index++;\n        }\n\n        // applicationTopic\n        if (offset < this.fullTopic.length()) {\n            this.applicationTopic = this.fullTopic.substring(offset);\n        }\n    }\n\n    public String getFullTopic() {\n        return this.fullTopic;\n    }\n\n    public String[] getTopicParts() {\n        return this.topicParts;\n    }\n\n    public String getPrefix() {\n        return this.prefix;\n    }\n\n    public String getAccountName() {\n        return this.accountName;\n    }\n\n    public String getDeviceId() {\n        return this.deviceId;\n    }\n\n    public String getApplicationId() {\n        return this.applicationId;\n    }\n\n    public String getApplicationTopic() {\n        return this.applicationTopic;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Defines the recommended payload structure for the messages sent a remote cloud platform.\n *\n */\npackage org.eclipse.kura.message;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/StoredMessage.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message.store;\n\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a message stored by a MessageStore implementation.\n * \n * @since 2.5\n * @noextend This class is not intended to be extended by clients.\n */\n@ProviderType\npublic class StoredMessage {\n\n    private final int id;\n    private final String topic;\n    private final int qos;\n    private final boolean retain;\n    private final int priority;\n    private final byte[] payload;\n    private final Optional<Date> createdOn;\n    private final Optional<Date> publishedOn;\n    private final Optional<Date> confirmedOn;\n    private final Optional<Date> droppedOn;\n    private final Optional<DataTransportToken> dataTransportToken;\n\n    private StoredMessage(final Builder b) {\n        this.id = b.id;\n        this.topic = b.topic;\n        this.qos = b.qos;\n        this.retain = b.retain;\n        this.priority = b.priority;\n        this.payload = b.payload;\n        this.createdOn = Optional.ofNullable(b.createdOn);\n        this.publishedOn = Optional.ofNullable(b.publishedOn);\n        this.confirmedOn = Optional.ofNullable(b.confirmedOn);\n        this.dataTransportToken = Optional.ofNullable(b.dataTransportToken);\n        this.droppedOn = Optional.ofNullable(b.droppedOn);\n    }\n\n    /**\n     * Returns the unique identifier of this message.\n     * \n     * @return the unique identifier of this message.\n     */\n    public int getId() {\n        return id;\n    }\n\n    /**\n     * Returns the topic of this message.\n     * \n     * @return the topic.\n     */\n    public String getTopic() {\n        return topic;\n    }\n\n    /**\n     * Returns the QoS of this message.\n     * A QoS value of zero indicates that the message reception does not need to be\n     * acknowledged by the recipient.\n     * A QoS value greater or equal than one indicates that the acknowledgement is\n     * required.\n     * \n     * @see StoredMessage#getConfirmedOn()\n     * @return the QoS value\n     */\n    public int getQos() {\n        return qos;\n    }\n\n    /**\n     * Returns the value of the MQTT <code>retain</code> field.\n     * \n     * @return the value of the MQTT <code>retain</field>.\n     */\n    public boolean isRetain() {\n        return retain;\n    }\n\n    /**\n     * Defines a message priority. The lower the value of this field, the higher the\n     * priority.\n     * <br>\n     * Messages with higher priority (lower value of this field) will be published\n     * first.\n     * \n     * @return the priority value\n     */\n    public int getPriority() {\n        return priority;\n    }\n\n    /**\n     * Returns the message payload.\n     * \n     * @return the message payload.\n     */\n    public byte[] getPayload() {\n        return payload;\n    }\n\n    /**\n     * Returns the timestamp of the instant when this message has been added to a\n     * store.\n     * \n     * @return the timestamp of creation instant\n     */\n    public Optional<Date> getCreatedOn() {\n        return createdOn;\n    }\n\n    /**\n     * Returns the timestamp of the instant when this message has been sent to the\n     * recipient.\n     * An empty value means that the message has not been sent yet.\n     * \n     * @return the publish timestamp, if any.\n     */\n    public Optional<Date> getPublishedOn() {\n        return publishedOn;\n    }\n\n    /**\n     * For messages with QoS greater or equal than one, this field reports the\n     * timestamp of the instant when the confirmation has been received from the\n     * recipient.\n     * <br>\n     * The returned value will be emtpy for messages with QoS zero, or for messages\n     * with QoS\n     * greater or equal than one that have not been confirmed yet.\n     * \n     * @see StoredMessage#getQos()\n     * @return the timestamp of the confirmation, if any\n     */\n    public Optional<Date> getConfirmedOn() {\n        return confirmedOn;\n    }\n\n    /**\n     * Returns the timestamp of the instant when this messages has been discarded.\n     * If returned value is empty, this message has not been dropped.\n     * \n     * @return the discard timestamp, if any\n     */\n    public Optional<Date> getDroppedOn() {\n        return droppedOn;\n    }\n\n    /**\n     * Returns the {@link DataTransportToken} associated with this message, if any.\n     * A {@link DataTransportToken} is an identifier of this message\n     * generated by the {@link org.eclipse.kura.data.DataTransportService} instance\n     * that published it.\n     * \n     * @return the {@link DataTransportToken}.\n     */\n    public Optional<DataTransportToken> getDataTransportToken() {\n        return dataTransportToken;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + Arrays.hashCode(payload);\n        result = prime * result + Objects.hash(confirmedOn, createdOn, dataTransportToken, droppedOn, id, priority,\n                publishedOn, qos, retain, topic);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof StoredMessage)) {\n            return false;\n        }\n        StoredMessage other = (StoredMessage) obj;\n        return Objects.equals(confirmedOn, other.confirmedOn) && Objects.equals(createdOn, other.createdOn)\n                && Objects.equals(dataTransportToken, other.dataTransportToken)\n                && Objects.equals(droppedOn, other.droppedOn) && id == other.id && Arrays.equals(payload, other.payload)\n                && priority == other.priority && Objects.equals(publishedOn, other.publishedOn) && qos == other.qos\n                && retain == other.retain && Objects.equals(topic, other.topic);\n    }\n\n    @Override\n    public String toString() {\n        return \"StoredMessage [id=\" + id + \", topic=\" + topic + \", qos=\" + qos + \", retain=\" + retain + \", priority=\"\n                + priority + \", payload=\" + Arrays.toString(payload) + \", createdOn=\" + createdOn + \", publishedOn=\"\n                + publishedOn + \", confirmedOn=\" + confirmedOn + \", droppedOn=\" + droppedOn + \", dataTransportToken=\"\n                + dataTransportToken + \"]\";\n    }\n\n    /**\n     * A builder that can be used to create {@link StoredMessage} instances.\n     * \n     * @since 2.5\n     * @noextend This class is not intended to be extended by clients.\n     */\n    @ProviderType\n    public static class Builder {\n\n        private final int id;\n        private String topic;\n        private int qos;\n        private boolean retain;\n        private byte[] payload;\n        private int priority;\n        private Date createdOn;\n        private Date publishedOn;\n        private Date confirmedOn;\n        private Date droppedOn;\n        private DataTransportToken dataTransportToken;\n\n        /**\n         * Creates a new builder for a message with the given id.\n         * \n         * @param id the message id.\n         */\n        public Builder(int id) {\n            this.id = id;\n        }\n\n        /**\n         * Sets the <code>topic</code> parameter.\n         * \n         * @param topic the <code>topic</code> parameter.\n         * @return this builder.\n         */\n        public Builder withTopic(String topic) {\n            this.topic = topic;\n            return this;\n        }\n\n        /**\n         * Sets the <code>QoS</code> parameter.\n         * \n         * @param qos the <code>QoS</code> parameter.\n         * @return this builder.\n         */\n        public Builder withQos(int qos) {\n            this.qos = qos;\n            return this;\n        }\n\n        /**\n         * Sets the <code>retain</code> parameter.\n         * \n         * @param retain the <code>retain</code> parameter.\n         * @return this builder.\n         */\n        public Builder withRetain(boolean retain) {\n            this.retain = retain;\n            return this;\n        }\n\n        /**\n         * Sets the <code>createdOn</code> parameter.\n         * \n         * @param createdOn the <code>createdOn</code> parameter.\n         * @return this builder.\n         */\n        public Builder withCreatedOn(Date createdOn) {\n            this.createdOn = createdOn;\n            return this;\n        }\n\n        /**\n         * Sets the <code>publishedOn</code> parameter.\n         * \n         * @param publishedOn the <code>publishedOn</code> parameter.\n         * @return this builder.\n         */\n        public Builder withPublishedOn(Date publishedOn) {\n            this.publishedOn = publishedOn;\n            return this;\n        }\n\n        /**\n         * Sets the <code>confirmedOn</code> parameter.\n         * \n         * @param confirmedOn the <code>confirmedOn</code> parameter.\n         * @return this builder.\n         */\n        public Builder withConfirmedOn(Date confirmedOn) {\n            this.confirmedOn = confirmedOn;\n            return this;\n        }\n\n        /**\n         * Sets the <code>payload</code> parameter.\n         * \n         * @param payload the <code>payload</code> parameter.\n         * @return this builder.\n         */\n        public Builder withPayload(byte[] payload) {\n            this.payload = payload;\n            return this;\n        }\n\n        /**\n         * Sets the <code>priority</code> parameter.\n         * \n         * @param priority the <code>priority</code> parameter.\n         * @return this builder.\n         */\n        public Builder withPriority(int priority) {\n            this.priority = priority;\n            return this;\n        }\n\n        /**\n         * Sets the <code>token</code> parameter.\n         * \n         * @param token the <code>token</code> parameter.\n         * @return this builder.\n         */\n        public Builder withDataTransportToken(DataTransportToken token) {\n            this.dataTransportToken = token;\n            return this;\n        }\n\n        /**\n         * Sets the <code>droppedOn</code> parameter.\n         * \n         * @param droppedOn the <code>droppedOn</code> parameter.\n         * @return this builder.\n         */\n        public Builder withDroppedOn(Date droppedOn) {\n            this.droppedOn = droppedOn;\n            return this;\n        }\n\n        /**\n         * Created a new {@link StoredMessage} basing on this builder.\n         * \n         * @return the new message.\n         */\n        public StoredMessage build() {\n            return new StoredMessage(this);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\n/**\n * Provides a representation of the messages stored by a\n * {@link org.eclipse.kura.message.store.provider.MessageStoreProvider}\n * instance.\n * \n * @since 2.5\n */\npackage org.eclipse.kura.message.store;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/provider/MessageStore.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message.store.provider;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.message.store.StoredMessage;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a message store suitable for supporting the Kura default\n * {@link org.eclipse.kura.data.DataService} implementation.\n * \n * See {@link StoredMessage} for a description of the stored message fields.\n * \n * @since 2.5\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface MessageStore {\n\n    /**\n     * Inserts a new message in the store. The implementation must set the value of\n     * the <code>createdOn</code> message parameter to the current time.\n     * <br>\n     * \n     * @param topic    the value of the <code>topic</code> parameter.\n     * @param payload  topic the value of the <code>payload</code> parameter.\n     * @param qos      topic the value of the <code>QoS</code> parameter.\n     * @param retain   topic the value of the <code>retain</code> parameter.\n     * @param priority topic the value of the <code>priority</code> parameter.\n     * @return An identifier for the stored message.\n     * @throws KuraStoreException\n     */\n    public int store(String topic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraStoreException;\n\n    /**\n     * Sets the value of the <code>publishedOn</code> parameter to the current time.\n     * <br>\n     * This method must be used for messages with QoS = 0.\n     *\n     * @param msgId the message identifier\n     * @throws KuraStoreException\n     */\n    public void markAsPublished(int msgId) throws KuraStoreException;\n\n    /**\n     * Sets the value of the <code>publishedOn</code> parameter to the current time\n     * and associates the given {@link DataTransportToken} with the current\n     * message.\n     * <br>\n     * This method must be used for messages with QoS >= 1.\n     *\n     * @param msgId              the message identifier.\n     * @param dataTransportToken the {@link DataTransportToken}.\n     * @throws KuraStoreException\n     */\n    public void markAsPublished(int msgId, DataTransportToken dataTransportToken) throws KuraStoreException;\n\n    /**\n     * Sets the value of the <code>confirmedOn</code> parameter to the current time.\n     * <br>\n     * This method must be used for messages with QoS >= 1.\n     *\n     * @param msgId the message identifier.\n     * @throws KuraStoreException\n     */\n    public void markAsConfirmed(int msgId) throws KuraStoreException;\n\n    /**\n     * Gets the next message that should be published, if any.\n     * \n     * The returned message must have the following properties:\n     * \n     * <ol>\n     * <li>The <code>publishedOn</code> parameter must not be set.</li>\n     * <li>It must have the lowest value of the <code>priority</code> numeric\n     * parameter (highest priority) between messages that satisfy 1.</li>\n     * <li>It must have the minimum <code>createdOn</code> parameter value between\n     * the messages that satisfy 2.</li>\n     * </ol>\n     * \n     * In other words it must be the oldest message between the ones with highest\n     * priority that have not been published yet.\n     *\n     * @return the next message that should be published, if any.\n     * @throws KuraStoreException\n     */\n    public Optional<StoredMessage> getNextMessage() throws KuraStoreException;\n\n    /**\n     * Retrieves the message with the given identifier from the store.\n     * \n     * @param msgId the message identifier.\n     * @return the retrieved message, or empty if there is no message in the store\n     *         with the given identifier.\n     * @throws KuraStoreException\n     */\n    public Optional<StoredMessage> get(int msgId) throws KuraStoreException;\n\n    /**\n     * Returns the number of messages currently in the store.\n     * This should include all messages, regardless of the value of their\n     * parameters.\n     * \n     * @return the message count.\n     * @throws KuraStoreException\n     */\n    public int getMessageCount() throws KuraStoreException;\n\n    /**\n     * Returns the list of messages whose <code>publishedOn</code> parameter is not\n     * set.\n     * <br>\n     * It is not necessary to return the message <code>payload</code>.\n     *\n     * @return the unpublished message list.\n     * @throws KuraStoreException\n     */\n    public List<StoredMessage> getUnpublishedMessages() throws KuraStoreException;\n\n    /**\n     * Returns the list of messages that satisfy all of the following conditions:\n     * \n     * <ol>\n     * <li>The value of the <code>QoS</code> parameter is greater than 0.</li>\n     * <li>The <code>publishedOn</code> parameter is set.</li>\n     * <li>The <code>confirmedOn</code> parameter is not set.</li>\n     * <li>The <code>droppedOn</code> parameter is not set.</li>\n     * </ol>\n     * \n     * It is not necessary to return the message <code>payload</code>.\n     *\n     * @return the in-flight message list.\n     * @throws KuraStoreException\n     */\n    public List<StoredMessage> getInFlightMessages() throws KuraStoreException;\n\n    /**\n     * Returns the list of messages with the following property:\n     * \n     * <ol>\n     * <li>The <code>droppedOn</code> parameter must be set.</li>\n     * </ol>\n     * \n     * It is not necessary to return the message <code>payload</code>.\n     *\n     * @return the dropped message list.\n     * @throws KuraStoreException\n     */\n    public List<StoredMessage> getDroppedMessages() throws KuraStoreException;\n\n    /**\n     * Removes the value of the <code>publishedOn</code> parameter from the messages\n     * that satisfy all of the following conditions:\n     * \n     * <ul>\n     * <li>The <code>publishedOn</code> parameter is set.</li>\n     * <li>The <code>confirmedOn</code> parameter is not set.</li>\n     * </ul>\n     *\n     * @throws KuraStoreException\n     */\n    public void unpublishAllInFlighMessages() throws KuraStoreException;\n\n    /**\n     * Sets the value of the <code>droppedOn</code> parameter to the current\n     * timestamp to all messages that satisfy all of the following conditions:\n     *\n     * <ul>\n     * <li>The value of the <code>QoS</code> parameter is greater than 0.</li>\n     * <li>The <code>publishedOn</code> parameter is set.</li>\n     * <li>The <code>confirmedOn</code> parameter is not set.</li>\n     * </ul>\n     * \n     * @throws KuraStoreException\n     */\n    public void dropAllInFlightMessages() throws KuraStoreException;\n\n    /**\n     * Deletes the messages that satisfy any of the following conditions:\n     * \n     * <ul>\n     * <li>The value of the <code>droppedOn</code> parameter is set and is more than\n     * <code>purgeAgeSeconds</code> in the past.</li>\n     * <li>The value of the <code>confirmedOn</code> parameter is set and is more\n     * than\n     * <code>purgeAgeSeconds</code> in the past.</li>\n     * <li>The value of the <code>QoS</code> parameter is 0 and\n     * <code>publishedOn</code> is set and is more than <code>purgeAgeSeconds</code>\n     * in the\n     * past.</li>\n     * </ul>\n     *\n     * @param purgeAgeSeconds the purge age in seconds.\n     * @throws KuraStoreException\n     */\n    public void deleteStaleMessages(int purgeAgeSeconds) throws KuraStoreException;\n\n    /**\n     * Closes the message store, releasing any runtime resources allocated for it.\n     */\n    public void close();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/provider/MessageStoreProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.message.store.provider;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.connection.listener.ConnectionListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a service that allows to create {@link MessageStore} instances.\n * \n * @since 2.5\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface MessageStoreProvider {\n\n    /**\n     * Opens or creates a {@link MessageStore} instance with the given name. Invoking\n     * this method could allocate the resources required to support the returned {@link MessageStore} instance (for\n     * example tables in a RDBMS).*\n     * \n     * @param name\n     *            the store name.\n     * @return the opened {@link MessageStore}\n     * @throws KuraStoreException\n     */\n    public MessageStore openMessageStore(String name) throws KuraStoreException;\n\n    /**\n     * Adds a {@link ConnectionListener}. A typical behavior of a client of this listener is to close the currently open\n     * {@link MessageStore} instances when a {@link ConnectionListener#disconnected()} event is received.\n     *\n     * @param listener\n     *            to add\n     *\n     * @since 2.5.0\n     */\n    public void addListener(ConnectionListener listener);\n\n    /**\n     * Removes a {@link ConnectionListener}\n     *\n     * @param listener\n     *            to remove\n     *\n     * @since 2.5.0\n     */\n    public void removeListener(ConnectionListener listener);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/provider/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\n/**\n * Provides APIs for creating message stores suitable to support the default\n * Kura {@link org.eclipse.kura.data.DataService} implementation.\n *\n * @since 2.5\n */\npackage org.eclipse.kura.message.store.provider;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/ConnectionInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Interface for network interface 'connection info'. At runtime an interface\n * may be associated with gateways or DNS but the interface itself may not be\n * active. If this is the case the ConnectionInfo class is used to keep all\n * relevant information in the event that this interface should become the\n * active one. This is necessary because many operating systems to not persist\n * this information.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic interface ConnectionInfo {\n\n    /**\n     * Gets the gateway address associated with this interface\n     *\n     * @return A IP4Address representing the gateway if it is not null\n     */\n    public IP4Address getGateway();\n\n    /**\n     * Gets the DNS addresses associated with this interface\n     *\n     * @return A List of IP4Address objects representing the DNS of this interface.\n     *         If there are none it returns an\n     *         empty list.\n     */\n    public List<IP4Address> getDnsServers();\n\n    /**\n     * Gets the interface name associated with this connection information\n     *\n     * @return The interface name associated with this connection information\n     */\n    public String getIfaceName();\n\n    /**\n     * Reports IP address\n     *\n     * @return IP address as {@link IP4Address}\n     */\n    public IP4Address getIpAddress();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/EthernetInterface.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Network interface for Ethernet cards.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface EthernetInterface<T extends NetInterfaceAddress> extends NetInterface<T> {\n\n    /**\n     * Indicates whether the physical carrier is found (e.g. whether a cable is plugged in or not).\n     *\n     * @return\n     */\n    public boolean isLinkUp();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/EthernetMonitorService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Placeholder for the EthernetLinkStateMonitorService\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic interface EthernetMonitorService {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/IP4Address.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.net.UnknownHostException;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents an Internet Protocol version 4 (IPv4) address.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class IP4Address extends IPAddress {\n\n    IP4Address(byte[] addr, java.net.InetAddress jnAddress) {\n        super(addr, jnAddress);\n    }\n\n    /**\n     * Returns the default IPv4 address (0.0.0.0/0).\n     * \n     * @return the 0.0.0.0/0 IPv4 address\n     * @throws UnknownHostException\n     * @since 2.6\n     */\n    public static IP4Address getDefaultAddress() throws UnknownHostException {\n        return (IP4Address) IPAddress.parseHostAddress(\"0.0.0.0\");\n    }\n\n    @Override\n    public String toString() {\n        return getHostAddress();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/IP6Address.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.net.UnknownHostException;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents an Internet Protocol version 6 (IPv6) address.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class IP6Address extends IPAddress {\n\n    IP6Address(byte[] addr, java.net.InetAddress jnAddress) {\n        super(addr, jnAddress);\n    }\n\n    /**\n     * Returns the default IPv6 address (::/0).\n     * \n     * @return the ::/0 IPv6 address\n     * @throws UnknownHostException\n     * @since 2.6\n     */\n    public static IP6Address getDefaultAddress() throws UnknownHostException {\n        return (IP6Address) IPAddress.parseHostAddress(\"::\");\n    }\n\n    /**\n     * Utility routine to check if the InetAddress is an IPv4 compatible IPv6\n     * address.\n     *\n     * @return a boolean indicating if the InetAddress is an IPv4 compatible IPv6\n     *         address; or false if address is IPv4\n     *         address.\n     */\n    public boolean isIPv4CompatibleAddress() {\n        return ((java.net.Inet6Address) this.javaNetAddress).isIPv4CompatibleAddress();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/IPAddress.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.Arrays;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\nimport com.google.common.net.InetAddresses;\n\n/**\n * This class represents an Internet Protocol (IP) address.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic abstract class IPAddress {\n\n    private final byte[] address;\n    protected java.net.InetAddress javaNetAddress;\n\n    IPAddress(byte[] address, java.net.InetAddress jnAddress) {\n        this.address = address;\n        this.javaNetAddress = jnAddress;\n    }\n\n    /**\n     * Returns an InetAddress object given the raw IP address.\n     * The argument is in network byte order: the highest order byte of the address\n     * is in getAddress()[0].\n     * This method doesn't block, i.e. no reverse name service lookup is performed.\n     * <br>\n     * IPv4 address byte array must be 4 bytes long and IPv6 byte array must be 16\n     * bytes long\n     *\n     * @param addr\n     *            - the raw IP address in network byte order\n     * @return an InetAddress object created from the raw IP address.\n     */\n    public static IPAddress getByAddress(byte[] addr) throws UnknownHostException {\n        IPAddress result = null;\n        java.net.InetAddress jnetAddr = java.net.InetAddress.getByAddress(addr);\n        if (jnetAddr instanceof java.net.Inet4Address) {\n            result = new IP4Address(addr, jnetAddr);\n        } else if (jnetAddr instanceof java.net.Inet6Address) {\n            result = new IP6Address(addr, jnetAddr);\n        }\n        return result;\n    }\n\n    // TODO - only works on IPv4 now\n    public static IPAddress getByAddress(int addr) throws UnknownHostException {\n\n        StringBuffer sb = new StringBuffer();\n        for (int shift = 24; shift > 0; shift -= 8) {\n            // process 3 bytes, from high order byte down\n            sb.append(Integer.toString(addr >>> shift & 0xff));\n            sb.append('.');\n        }\n        sb.append(Integer.toString(addr & 0xff));\n\n        InetAddress jnetAddr = InetAddress.getByName(sb.toString());\n        return getByAddress(jnetAddr.getAddress());\n    }\n\n    /**\n     * Parse a literal representation of an IP address and returns the\n     * corresponding IPAddress class.\n     *\n     * @param hostAddress\n     * @return\n     */\n    public static IPAddress parseHostAddress(String hostAddress) throws UnknownHostException {\n        if (hostAddress != null && !hostAddress.isEmpty() && !InetAddresses.isInetAddress(hostAddress)) {\n            throw new UnknownHostException(\"Invalid IP address: \" + hostAddress);\n        }\n\n        InetAddress jnetAddr = InetAddress.getByName(hostAddress);\n        return getByAddress(jnetAddr.getAddress());\n    }\n\n    /**\n     * Returns the raw IP address of this InetAddress object.\n     * The result is in network byte order: the highest order byte of the address is\n     * in getAddress()[0].\n     *\n     * @return the raw IP address of this object.\n     */\n    public byte[] getAddress() {\n        return this.address;\n    }\n\n    /**\n     * Returns the IP address string in textual presentation.\n     *\n     * @return the raw IP address in a string format.\n     */\n    public String getHostAddress() {\n        return this.javaNetAddress.getHostAddress();\n    }\n\n    /**\n     * Utility routine to check if the InetAddress in a wildcard address.\n     *\n     * @return a boolean indicating if the Inetaddress is a wildcard address.\n     */\n    public boolean isAnyLocalAddress() {\n        return this.javaNetAddress.isAnyLocalAddress();\n    }\n\n    /**\n     * Utility routine to check if the InetAddress is an link local address.\n     *\n     * @return a boolean indicating if the InetAddress is a link local address; or\n     *         false if address is not a link local\n     *         unicast address.\n     */\n    public boolean isLinkLocalAddress() {\n        return this.javaNetAddress.isLinkLocalAddress();\n    }\n\n    /**\n     * Utility routine to check if the InetAddress is a loopback address.\n     *\n     * @return a boolean indicating if the InetAddress is a loopback address; or\n     *         false otherwise.\n     */\n    public boolean isLoopbackAddress() {\n        return this.javaNetAddress.isLoopbackAddress();\n    }\n\n    /**\n     * Utility routine to check if the multicast address has global scope.\n     *\n     * @return a boolean indicating if the address has is a multicast address of\n     *         global scope, false if it is not of\n     *         global scope or it is not a multicast address\n     */\n    public boolean isMCGlobal() {\n        return this.javaNetAddress.isMCGlobal();\n    }\n\n    /**\n     * Utility routine to check if the multicast address has link scope.\n     *\n     * @return a boolean indicating if the address has is a multicast address of\n     *         link-local scope, false if it is not of\n     *         link-local scope or it is not a multicast address\n     */\n    public boolean isMCLinkLocal() {\n        return this.javaNetAddress.isMCLinkLocal();\n    }\n\n    /**\n     * Utility routine to check if the multicast address has node scope.\n     *\n     * @return a boolean indicating if the address has is a multicast address of\n     *         node-local scope, false if it is not of\n     *         node-local scope or it is not a multicast address\n     */\n    public boolean isMCNodeLocal() {\n        return this.javaNetAddress.isMCNodeLocal();\n    }\n\n    /**\n     * Utility routine to check if the multicast address has organization scope.\n     *\n     * @return a boolean indicating if the address has is a multicast address of\n     *         organization-local scope, false if it\n     *         is not of organization-local scope or it is not a multicast address\n     */\n    public boolean isMCOrgLocal() {\n        return this.javaNetAddress.isMCOrgLocal();\n    }\n\n    /**\n     * Utility routine to check if the multicast address has site scope.\n     *\n     * @return a boolean indicating if the address has is a multicast address of\n     *         site-local scope, false if it is not of\n     *         site-local scope or it is not a multicast address\n     */\n    public boolean isMCSiteLocal() {\n        return this.javaNetAddress.isMCSiteLocal();\n    }\n\n    /**\n     * Utility routine to check if the InetAddress is an IP multicast address.\n     *\n     * @return\n     */\n    public boolean isMulticastAddress() {\n        return this.javaNetAddress.isMulticastAddress();\n    }\n\n    /**\n     * Utility routine to check if the InetAddress is a site local address.}\n     *\n     * @return a boolean indicating if the InetAddress is a site local address; or\n     *         false if address is not a site local\n     *         unicast address.\n     */\n    public boolean isSiteLocalAddress() {\n        return this.javaNetAddress.isSiteLocalAddress();\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + Arrays.hashCode(this.address);\n        result = prime * result + (this.javaNetAddress == null ? 0 : this.javaNetAddress.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        IPAddress other = (IPAddress) obj;\n        if (!Arrays.equals(this.address, other.address)) {\n            return false;\n        }\n        if (this.javaNetAddress == null) {\n            if (other.javaNetAddress != null) {\n                return false;\n            }\n        } else if (!this.javaNetAddress.equals(other.javaNetAddress)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/LoopbackInterface.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Placeholder for a LoopbackInterface\n *\n * @param <T>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface LoopbackInterface<T extends NetInterfaceAddress> extends NetInterface<T> {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for all network configuration classes\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface NetConfig {\n\n    /**\n     * Checks whether or not this configuration is valid.\n     *\n     * @return true if the configuration is valid, otherwise false\n     */\n    public boolean isValid();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfig4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv4-based configurations of network interfaces\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface NetConfig4 extends NetConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfig6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv6-based configurations of network interfaces\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface NetConfig6 extends NetConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfigIP.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.net.UnknownHostException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.StringTokenizer;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Base class for configuration of network interfaces.\n * The two subclasses NetConfigIP4 and NetConfigIP6 represent\n * configurations of IPv4 and IPv6 addresses respectively.\n *\n * @param <T>\n *            IPv4 or IPv6 address\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic abstract class NetConfigIP<T extends IPAddress> implements NetConfig {\n\n    private NetInterfaceStatus status;\n    private boolean autoConnect;\n    private boolean dhcp;\n    private T address;\n    private short networkPrefixLength;\n    private T subnetMask;\n    private T gateway;\n    private List<T> dnsServers;\n    private List<String> domains;\n    private Map<String, Object> properties;\n\n    NetConfigIP(NetInterfaceStatus status, boolean autoConnect) {\n        this.status = status;\n        this.autoConnect = autoConnect;\n        this.dhcp = false;\n        this.address = null;\n        this.networkPrefixLength = -1;\n        this.subnetMask = null;\n        this.gateway = null;\n        this.dnsServers = new ArrayList<>();\n        this.domains = new ArrayList<>();\n        this.properties = new HashMap<>();\n    }\n\n    NetConfigIP(NetInterfaceStatus status, boolean autoConnect, boolean dhcp) {\n        this.status = status;\n        this.autoConnect = autoConnect;\n        this.dhcp = dhcp;\n        this.address = null;\n        this.networkPrefixLength = -1;\n        this.subnetMask = null;\n        this.gateway = null;\n        this.dnsServers = new ArrayList<>();\n        this.domains = new ArrayList<>();\n        this.properties = new HashMap<>();\n    }\n\n    NetConfigIP(NetInterfaceStatus status, boolean autoConnect, T address, short networkPrefixLength, T gateway)\n            throws KuraException {\n        this.status = status;\n        this.autoConnect = autoConnect;\n        this.dhcp = false;\n        this.address = address;\n        this.networkPrefixLength = networkPrefixLength;\n        this.subnetMask = calculateNetmaskFromNetworkPrefix(networkPrefixLength);\n        this.gateway = gateway;\n        this.dnsServers = new ArrayList<>();\n        this.domains = new ArrayList<>();\n        this.properties = new HashMap<>();\n    }\n\n    NetConfigIP(NetInterfaceStatus status, boolean autoConnect, T address, T subnetMask, T gateway)\n            throws KuraException {\n        this.status = status;\n        this.autoConnect = autoConnect;\n        this.dhcp = false;\n        this.address = address;\n        this.networkPrefixLength = calculateNetworkPrefixFromNetmask(subnetMask.getHostAddress());\n        this.subnetMask = subnetMask;\n        this.gateway = gateway;\n        this.dnsServers = new ArrayList<>();\n        this.domains = new ArrayList<>();\n        this.properties = new HashMap<>();\n    }\n\n    /**\n     * Return the NetInterfaceStatus of this configuration\n     *\n     * @return\n     */\n    public NetInterfaceStatus getStatus() {\n        return this.status;\n    }\n\n    /**\n     * Sets the NetInterfaceStatus to be used for the network interface\n     *\n     * @param status\n     */\n    public void setStatus(NetInterfaceStatus status) {\n        this.status = status;\n    }\n\n    public boolean isAutoConnect() {\n        return this.autoConnect;\n    }\n\n    public void setAutoConnect(boolean autoConnect) {\n        this.autoConnect = autoConnect;\n    }\n\n    public boolean isDhcp() {\n        return this.dhcp;\n    }\n\n    /**\n     * Sets whether of not this configuration should be a dhcp client. If dhcp\n     * is set to true it overrides and static configuration that is present in\n     * the configuration.\n     *\n     * @param dhcp\n     *             whether or not dhcp client mode should be used\n     */\n    public void setDhcp(boolean dhcp) {\n        this.dhcp = dhcp;\n    }\n\n    /**\n     * Returns the address that should be statically assigned to the interface.\n     * The returned address is IP4Address or IP6Address depending on\n     * the NetConfigIP instance used. This is only used if dhcp is set to false.\n     *\n     * @return the static address for the interface\n     */\n    public T getAddress() {\n        return this.address;\n    }\n\n    /**\n     * Sets the static address to be assigned to the interface.\n     * The address should IP4Address or IP6Address depending on\n     * the NetConfigIP instance used. This is only used if dhcp is set to false.\n     *\n     * @param address\n     *                - address to be statically assigned to the interface\n     */\n    public void setAddress(T address) {\n        this.address = address;\n    }\n\n    /**\n     * Return the prefix to be used for the network interface\n     *\n     * @return\n     */\n    public short getNetworkPrefixLength() {\n        return this.networkPrefixLength;\n    }\n\n    /**\n     * Sets the prefix length to be used for the network interface\n     *\n     * @param networkPrefixLength\n     * @throws KuraException\n     */\n    public void setNetworkPrefixLength(short networkPrefixLength) throws KuraException {\n        this.networkPrefixLength = networkPrefixLength;\n        this.subnetMask = calculateNetmaskFromNetworkPrefix(networkPrefixLength);\n    }\n\n    /**\n     * Return the prefix to be used for the network interface\n     *\n     * @return\n     */\n    public T getSubnetMask() {\n        return this.subnetMask;\n    }\n\n    /**\n     * Sets the subnet mask to be used for the network interface\n     *\n     * @param subnetMask\n     * @throws KuraException\n     */\n    public void setSubnetMask(T subnetMask) throws KuraException {\n        this.networkPrefixLength = calculateNetworkPrefixFromNetmask(subnetMask.getHostAddress());\n        this.subnetMask = subnetMask;\n    }\n\n    /**\n     * Returns the address of the gateway to be used for the interface\n     *\n     * @return\n     */\n    public T getGateway() {\n        return this.gateway;\n    }\n\n    /**\n     * Sets the gateway to be used for the interface\n     *\n     * @param gateway\n     */\n    public void setGateway(T gateway) {\n        this.gateway = gateway;\n    }\n\n    /**\n     * Returns the list of Name Servers to be associated to the interface.\n     * The returned addresses are IP4Address or IP6Address depending on\n     * the NetConfigIP instance used. This is only used if dhcp is set to false.\n     *\n     * @return list of address for the DNS Servers\n     */\n    public List<T> getDnsServers() {\n        if (this.dnsServers != null) {\n            return Collections.unmodifiableList(this.dnsServers);\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Sets the list of Name Servers to be associated to the interface.\n     * The addresses are IP4Address or IP6Address depending on\n     * the NetConfigIP instance used. This is only used if dhcp is set to false.\n     */\n    public void setDnsServers(List<T> dnsServers) {\n        this.dnsServers = dnsServers;\n    }\n\n    /**\n     * Returns the list of DNS domains to be associated to the interface.\n     * This is only used if dhcp is set to false.\n     *\n     * @return - list of DNS domains\n     */\n    public List<String> getDomains() {\n        if (this.domains != null) {\n            return Collections.unmodifiableList(this.domains);\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Sets the list of DNS domains to be associated to the interface.\n     * This is only used if dhcp is set to false.\n     *\n     * @param domains\n     */\n    public void setDomains(List<String> domains) {\n        this.domains = domains;\n    }\n\n    public Map<String, Object> getProperties() {\n        if (this.properties != null) {\n            return Collections.unmodifiableMap(this.properties);\n        } else {\n            return null;\n        }\n    }\n\n    public void setProperties(Map<String, Object> properties) {\n        this.properties = properties;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.address == null ? 0 : this.address.hashCode());\n        result = prime * result + (this.autoConnect ? 1231 : 1237);\n        result = prime * result + (this.dhcp ? 1231 : 1237);\n        result = prime * result + (this.dnsServers == null ? 0 : this.dnsServers.hashCode());\n        result = prime * result + (this.domains == null ? 0 : this.domains.hashCode());\n        result = prime * result + (this.gateway == null ? 0 : this.gateway.hashCode());\n        result = prime * result + this.networkPrefixLength;\n        result = prime * result + (this.properties == null ? 0 : this.properties.hashCode());\n        result = prime * result + (this.status == null ? 0 : this.status.hashCode());\n        result = prime * result + (this.subnetMask == null ? 0 : this.subnetMask.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        @SuppressWarnings(\"rawtypes\")\n        NetConfigIP other = (NetConfigIP) obj;\n        if (this.address == null) {\n            if (other.address != null) {\n                return false;\n            }\n        } else if (!this.address.equals(other.address)) {\n            return false;\n        }\n        if (this.autoConnect != other.autoConnect) {\n            return false;\n        }\n        if (this.dhcp != other.dhcp) {\n            return false;\n        }\n        if (this.dnsServers == null) {\n            if (other.dnsServers != null) {\n                return false;\n            }\n        } else if (!this.dnsServers.equals(other.dnsServers)) {\n            return false;\n        }\n        if (this.domains == null) {\n            if (other.domains != null) {\n                return false;\n            }\n        } else if (!this.domains.equals(other.domains)) {\n            return false;\n        }\n        if (this.gateway == null) {\n            if (other.gateway != null) {\n                return false;\n            }\n        } else if (!this.gateway.equals(other.gateway)) {\n            return false;\n        }\n        if (this.networkPrefixLength != other.networkPrefixLength) {\n            return false;\n        }\n        if (this.properties == null) {\n            if (other.properties != null) {\n                return false;\n            }\n        } else if (!this.properties.equals(other.properties)) {\n            return false;\n        }\n        if (this.status != other.status) {\n            return false;\n        }\n        if (this.subnetMask == null) {\n            if (other.subnetMask != null) {\n                return false;\n            }\n        } else if (!this.subnetMask.equals(other.subnetMask)) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public boolean isValid() {\n        // FIXME\n        if (this.dhcp) {\n            return true;\n        } else {\n            try {\n                this.address.getHostAddress();\n            } catch (Exception e) {\n                return false;\n            }\n\n            for (IPAddress dns : this.dnsServers) {\n                try {\n                    dns.getHostAddress();\n                } catch (Exception e) {\n                    return false;\n                }\n            }\n\n            // if we got here...\n            return true;\n        }\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"NetConfigIP [status=\");\n        builder.append(this.status);\n        builder.append(\", autoConnect=\");\n        builder.append(this.autoConnect);\n        builder.append(\", dhcp=\");\n        builder.append(this.dhcp);\n        builder.append(\", address=\");\n        builder.append(this.address);\n        builder.append(\", networkPrefixLength=\");\n        builder.append(this.networkPrefixLength);\n        builder.append(\", subnetMask=\");\n        builder.append(this.subnetMask);\n        builder.append(\", gateway=\");\n        builder.append(this.gateway);\n        builder.append(\", dnsServers=\");\n        builder.append(this.dnsServers);\n        builder.append(\", domains=\");\n        builder.append(this.domains);\n        builder.append(\", properties=\");\n        builder.append(this.properties);\n        builder.append(\"]\");\n        return builder.toString();\n    }\n\n    // TODO - only works on IPv4 now\n    private short calculateNetworkPrefixFromNetmask(String netmask) throws KuraException {\n        if (netmask == null) {\n            throw new KuraException(KuraErrorCode.INTERNAL_ERROR, \"netmask is null\");\n        }\n\n        int netmaskValue = 0;\n        StringTokenizer st = new StringTokenizer(netmask, \".\");\n        for (int i = 24; i >= 0; i -= 8) {\n            netmaskValue = netmaskValue | Integer.parseInt(st.nextToken()) << i;\n        }\n\n        boolean hitZero = false;\n        int displayMask = 1 << 31;\n        int count = 0;\n\n        for (int c = 1; c <= 32; c++) {\n            if ((netmaskValue & displayMask) == 0) {\n                hitZero = true;\n            } else {\n                if (hitZero) {\n                    throw new KuraException(KuraErrorCode.INTERNAL_ERROR, \"received invalid mask: \" + netmask);\n                }\n\n                count++;\n            }\n\n            netmaskValue <<= 1;\n        }\n\n        return (short) count;\n    }\n\n    // TODO - only works on IPv4 now\n    private T calculateNetmaskFromNetworkPrefix(int networkPrefixLength) throws KuraException {\n        if (networkPrefixLength < 0) {\n            return null;\n        }\n        int mask = ~((1 << 32 - networkPrefixLength) - 1);\n        StringBuilder sb = new StringBuilder(15);\n        for (int shift = 24; shift > 0; shift -= 8) {\n            // process 3 bytes, from high order byte down.\n            sb.append(Integer.toString(mask >>> shift & 0xff));\n            sb.append('.');\n        }\n\n        sb.append(Integer.toString(mask & 0xff));\n\n        try {\n            @SuppressWarnings(\"unchecked\")\n            T netmask = (T) IPAddress.parseHostAddress(sb.toString());\n            return netmask;\n        } catch (UnknownHostException e) {\n            throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfigIP4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Configuration for a network interface based on IPv4 addresses.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class NetConfigIP4 extends NetConfigIP<IP4Address> implements NetConfig4 {\n\n    private List<IP4Address> winsServers;\n\n    public NetConfigIP4(NetInterfaceStatus status, boolean autoConnect) {\n        super(status, autoConnect);\n        this.winsServers = new ArrayList<>();\n    }\n\n    public NetConfigIP4(NetInterfaceStatus status, boolean autoConnect, boolean dhcp) {\n        super(status, autoConnect, dhcp);\n        this.winsServers = new ArrayList<>();\n    }\n\n    public NetConfigIP4(NetInterfaceStatus status, boolean autoConnect, IP4Address address, short networkPrefixLength,\n            IP4Address gateway) throws KuraException {\n        super(status, autoConnect, address, networkPrefixLength, gateway);\n        this.winsServers = new ArrayList<>();\n    }\n\n    public NetConfigIP4(NetInterfaceStatus status, boolean autoConnect, IP4Address address, IP4Address subnetMask,\n            IP4Address gateway) throws KuraException {\n        super(status, autoConnect, address, subnetMask, gateway);\n        this.winsServers = new ArrayList<>();\n    }\n\n    /**\n     * Returns the list of Windows Servers to be associated with the interface\n     *\n     * @return\n     */\n    public List<IP4Address> getWinsServers() {\n        if (this.winsServers != null) {\n            return Collections.unmodifiableList(this.winsServers);\n        } else {\n            return null;\n        }\n    }\n\n    /**\n     * Sets the list of Windows Servers to be associated with the interface\n     *\n     * @param winsServers\n     */\n    public void setWinsServers(List<IP4Address> winsServers) {\n        this.winsServers = winsServers;\n    }\n\n    @Override\n    public boolean isValid() {\n        return super.isValid();\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"NetConfigIP4 [winsServers=\");\n        builder.append(this.winsServers);\n        builder.append(\", super.toString()=\");\n        builder.append(super.toString());\n        builder.append(\"]\");\n        return builder.toString();\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + (this.winsServers == null ? 0 : this.winsServers.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj)) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        NetConfigIP4 other = (NetConfigIP4) obj;\n        if (this.winsServers == null) {\n            if (other.winsServers != null) {\n                return false;\n            }\n        } else if (!this.winsServers.equals(other.winsServers)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfigIP6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Configuration for a network interface based on IPv6 addresses.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class NetConfigIP6 extends NetConfigIP<IP6Address> implements NetConfig6 {\n\n    /**\n     * Empty Constructor\n     */\n    public NetConfigIP6(NetInterfaceStatus status, boolean autoConnect) {\n        super(status, autoConnect);\n    }\n\n    /**\n     * Constructor for a DHCP Client Configuration for a\n     * network interface based on IPv6 addresses.\n     *\n     * @param dhcp\n     *            whether or not DHCP client mode should be used\n     */\n    public NetConfigIP6(NetInterfaceStatus status, boolean autoConnect, boolean dhcp) {\n        super(status, autoConnect, dhcp);\n    }\n\n    /**\n     * Constructor for a Static Configuration for a\n     * network interface based on IPv6 addresses.\n     *\n     * @param address\n     *            - address to be assigned to the interface\n     * @param networkPrefixLength\n     *            - network prefix length to be assigned to the interface\n     * @param gateway\n     *            - default gateway to be assigned to the interface\n     * @throws KuraException\n     */\n    public NetConfigIP6(NetInterfaceStatus status, boolean autoConnect, IP6Address address, short networkPrefixLength,\n            IP6Address gateway) throws KuraException {\n        super(status, autoConnect, address, networkPrefixLength, gateway);\n    }\n\n    /**\n     * Constructor for a Static Configuration for a\n     * network interface based on IPv6 addresses.\n     *\n     * @param address\n     *            - address to be assigned to the interface\n     * @param subnetMask\n     *            - subnet mask to be assigned to the interface\n     * @param gateway\n     *            - default gateway to be assigned to the interface\n     * @throws KuraException\n     */\n    public NetConfigIP6(NetInterfaceStatus status, boolean autoConnect, IP6Address address, IP6Address subnetMask,\n            IP6Address gateway) throws KuraException {\n        super(status, autoConnect, address, subnetMask, gateway);\n    }\n\n    @Override\n    public boolean isValid() {\n        return super.isValid();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterface.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.List;\n\nimport org.eclipse.kura.usb.UsbDevice;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * NetworkInterface represent a network interface of the system.\n * Its APIs are purposefully modeled after the java.net.NetworkInterface.\n * Compared to the standard Java API, this class provides additional information\n * such as the NetworkInterfaceType, whether the interface is provided to the system\n * through a USB Adapter, and additional low-level characteristics of the interface.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface NetInterface<T extends NetInterfaceAddress> {\n\n    /**\n     * Returns the name of this NetworkInterface.\n     *\n     * @return interface name\n     */\n    public String getName();\n\n    /**\n     * Returns the type of this NetworkInterface.\n     *\n     * @return interface type\n     */\n    public NetInterfaceType getType();\n\n    /**\n     * The driver handling the device.\n     *\n     * @return\n     */\n    public String getDriver();\n\n    /**\n     * The version of the driver handling the device.\n     *\n     * @return\n     */\n    public String getDriverVersion();\n\n    /**\n     * The firmware version for the device.\n     *\n     * @return\n     */\n    public String getFirmwareVersion();\n\n    /**\n     * The current state of the device.\n     *\n     * @return\n     */\n    public NetInterfaceState getState();\n\n    /**\n     * Returns the hardware address (usually MAC) of the interface if it has one.\n     *\n     * @return a byte array containing the address or null if the address doesn't exist\n     */\n    public byte[] getHardwareAddress();\n\n    /**\n     * Returns a List of all InterfaceAddresses of this network interface.\n     *\n     * @return a List object with all or a subset of the InterfaceAddresss of this network interface\n     */\n    public List<T> getNetInterfaceAddresses();\n\n    /**\n     * Returns whether a network interface is a loopback interface.\n     *\n     * @return true if the interface is a loopback interface.\n     */\n    public boolean isLoopback();\n\n    /**\n     * Returns whether a network interface is a point to point interface.\n     * A typical point to point interface would be a PPP connection through a modem.\n     *\n     * @return true if the interface is a point to point interface.\n     */\n    public boolean isPointToPoint();\n\n    /**\n     * Returns whether this interface is a virtual interface (also called subinterface).\n     * Virtual interfaces are, on some systems, interfaces created as a child of a physical\n     * interface and given different settings (like address or MTU).\n     * Usually the name of the interface will the name of the parent followed by a colon (:)\n     * and a number identifying the child since there can be several virtual interfaces\n     * attached to a single physical interface.\n     *\n     * @return true if this interface is a virtual interface.\n     */\n    public boolean isVirtual();\n\n    /**\n     * Returns whether a network interface supports multicasting or not.\n     *\n     * @return true if the interface supports Multicasting.\n     */\n    public boolean supportsMulticast();\n\n    /**\n     * Returns whether a network interface is up and running.\n     *\n     * @return true if the interface is up and running.\n     */\n    public boolean isUp();\n\n    /**\n     * Returns whether a network interface will auto connect.\n     *\n     * @return true if the interface will auto connect.\n     */\n    public boolean isAutoConnect();\n\n    /**\n     * Returns the Maximum Transmission Unit (MTU) of this interface\n     * - Design speed of the device, in megabits/second (Mb/s).\n     *\n     * @return the value of the MTU for that interface.\n     */\n    public int getMTU();\n\n    //\n    // Kura Extensions\n    //\n\n    /**\n     * Returns the UsbDevice which provided this NetworkInterface to the system if any.\n     *\n     * @return the UsbDevice providing this NetworkInterface to the system\n     *         or null if this NetworkInterface is not provided by a USB device\n     */\n    public UsbDevice getUsbDevice();\n\n    /*\n     * public String getScope();\n     *\n     * public String getBroadcast();\n     *\n     * public String getMask();\n     *\n     * public boolean isBroadcast();\n     *\n     * public boolean isRunning();\n     *\n     * public boolean isMulticast();\n     *\n     * public boolean isAllmulti();\n     *\n     * public boolean isPromisc();\n     *\n     * public long getRxPackets();\n     *\n     * public long getRxErrors();\n     *\n     * public long getRxDropped();\n     *\n     * public long getRxOverruns();\n     *\n     * public long getRxFrame();\n     *\n     * public long getTxPackets();\n     *\n     * public long getTxErrors();\n     *\n     * public long getTxDropped();\n     *\n     * public long getTxOverruns();\n     *\n     * public long getTxCarrier();\n     *\n     * public long getCollisions();\n     *\n     * public long getTxQueueLength();\n     *\n     * public long getTxBytes();\n     *\n     * public long getRxBytes();\n     */\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceAddedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * An event raised when a new network interface has been added to the system.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic class NetInterfaceAddedEvent extends Event {\n\n    /** Topic of the NetworkInterfaceAddedEvent */\n    public static final String NETWORK_EVENT_INTERFACE_ADDED_TOPIC = \"org/eclipse/kura/net/NetworkEvent/interface/ADDED\";\n\n    /** Name of the property to access the network interface name */\n    public static final String NETWORK_EVENT_INTERFACE_PROPERTY = \"network.interface\";\n\n    public NetInterfaceAddedEvent(Map<String, ?> properties) {\n        super(NETWORK_EVENT_INTERFACE_ADDED_TOPIC, properties);\n    }\n\n    /**\n     * Returns the name of the added interface.\n     *\n     * @return\n     */\n    public String getInterfaceName() {\n        return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceAddress.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents a Network Interface address as currently running on the system\n * In short it's an IP address, a subnet mask and a broadcast address when the address is an IPv4 one.\n * An IP address and a network prefix length in the case of IPv6 address.\n * Both IPv4 and IPv6 addresses will have a gateway and one or more DNS addresses.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface NetInterfaceAddress {\n\n    /**\n     * Returns an InetAddress for this address.\n     *\n     * @return the address\n     */\n    public IPAddress getAddress();\n\n    /**\n     * Returns the network prefix length for this address.\n     * This is also known as the subnet mask in the context of IPv4 addresses.\n     * Typical IPv4 values would be 8 (255.0.0.0), 16 (255.255.0.0) or 24 (255.255.255.0).\n     * Typical IPv6 values would be 128 (::1/128) or 10 (fe80::203:baff:fe27:1243/10)\n     *\n     * @return a short representing the prefix length for the subnet of that address.\n     */\n    public short getNetworkPrefixLength();\n\n    /**\n     * Returns the network mask for this address\n     * Typical IPv4 values would be 255.0.0.0, 255.255.0.0 or 255.255.255.0.\n     * Typical IPv6 values would be ::1/128 or fe80::203:baff:fe27:1243/10\n     *\n     * @return an IPaddress representing the subnet mask of that address\n     */\n    public IPAddress getNetmask();\n\n    /**\n     * Returns the InetAddress for the gateway.\n     *\n     * @return the gateway address\n     */\n    public IPAddress getGateway();\n\n    /**\n     * Returns an InetAddress for the broadcast address for this InterfaceAddress.\n     *\n     * @return the broadcast address\n     */\n    public IPAddress getBroadcast();\n\n    /**\n     * Gets the list of DNS servers associated with this interface\n     *\n     * @return the list of DNS servers\n     */\n    public List<? extends IPAddress> getDnsServers();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceAddressConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Extends a NetInterfaceAddress which is status as currently running on the system with the\n * interface's configuration in the form of a List of NetConfig objects. The configuration\n * and the status may differ based on environmental conditions and this is why configuration\n * is modeled separately. For example, an interface could be configured as a DHCP client.\n * In this case, the configuration would not include an IP address. However, the 'status' in\n * the NetInterfaceAddress would because the interface does have an IP - just not one that is\n * configured because it is dynamically assigned by the DHCP server.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface NetInterfaceAddressConfig extends NetInterfaceAddress {\n\n    /**\n     * Returns a List of NetConfig Objects associated with a given NetInterfaceAddressConfig\n     * for a given NetInterface\n     *\n     * @return the NetConfig Objects associated with the NetInterfaceAddressConfig\n     */\n    public List<NetConfig> getConfigs();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker class for NetInterfaceConfig objects.\n * Network interfaces implementing this maker will return addresses of type NetInterfaceAddressConfig in their\n * getNetInterfaceAddresses() method.\n * NetInterfaceAddressConfig complements NetInterfaceAddress, which provides the current addresses associated to the\n * interface, with the NetConfig objects.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface NetInterfaceConfig<T extends NetInterfaceAddressConfig> extends NetInterface<T> {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceRemovedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * An event raised when a network interface has been removed from the system.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic class NetInterfaceRemovedEvent extends Event {\n\n    /** Topic of the NetworkInterfaceRemovedEvent */\n    public static final String NETWORK_EVENT_INTERFACE_REMOVED_TOPIC = \"org/eclipse/kura/net/NetworkEvent/interface/REMOVED\";\n\n    /** Name of the property to access the network interface name */\n    public static final String NETWORK_EVENT_INTERFACE_PROPERTY = \"network.interface\";\n\n    public NetInterfaceRemovedEvent(Map<String, ?> properties) {\n        super(NETWORK_EVENT_INTERFACE_REMOVED_TOPIC, properties);\n    }\n\n    /**\n     * Returns the name of the removed interface.\n     *\n     * @return\n     */\n    public String getInterfaceName() {\n        return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceState.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\n/**\n * The current state of the a NetworkInterface.\n */\npublic enum NetInterfaceState {\n\n    /** The device is in an unknown state. */\n    UNKNOWN(0),\n    /** The device is recognized but not managed by NetworkManager. */\n    UNMANAGED(10),\n    /** The device cannot be used (carrier off, rfkill, etc). */\n    UNAVAILABLE(20),\n    /** The device is not connected. */\n    DISCONNECTED(30),\n    /** The device is preparing to connect. */\n    PREPARE(40),\n    /** The device is being configured. */\n    CONFIG(50),\n    /** The device is awaiting secrets necessary to continue connection. */\n    NEED_AUTH(60),\n    /** The IP settings of the device are being requested and configured. */\n    IP_CONFIG(70),\n    /** The device's IP connectivity ability is being determined. */\n    IP_CHECK(80),\n    /** The device is waiting for secondary connections to be activated. */\n    SECONDARIES(90),\n    /** The device is active. */\n    ACTIVATED(100),\n    /** The device's network connection is being torn down. */\n    DEACTIVATING(110),\n    /** The device is in a failure state following an attempt to activate it. */\n    FAILED(120);\n\n    private int code;\n\n    private NetInterfaceState(int code) {\n        this.code = code;\n    }\n\n    public static NetInterfaceState parseCode(int code) {\n        for (NetInterfaceState state : NetInterfaceState.values()) {\n            if (state.code == code) {\n                return state;\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceStateChangedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * Event raised when the state of a network interface has changed.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic class NetInterfaceStateChangedEvent extends Event {\n\n    /** Topic of the NetworkStateChangedEvent */\n    public static final String NETWORK_EVENT_INTERFACE_STATE_CHANGED_TOPIC = \"org/eclipse/kura/net/NetworkEvent/interface/STATE_CHANGED\";\n\n    /** Name of the property to access the network interface name */\n    public static final String NETWORK_EVENT_INTERFACE_PROPERTY = \"network.interface\";\n\n    /** Name of the property to access the new network state */\n    public static final String NETWORK_EVENT_NEW_STATE_PROPERTY = \"network.state.new\";\n\n    /** Name of the property to access the old network state */\n    public static final String NETWORK_EVENT_OLD_STATE_PROPERTY = \"network.state.old\";\n\n    /** Name of the property to access the reason of the change */\n    public static final String NETWORK_EVENT_STATE_CHANGE_REASON_PROPERTY = \"network.state.change.reason\";\n\n    public NetInterfaceStateChangedEvent(Map<String, ?> properties) {\n        super(NETWORK_EVENT_INTERFACE_STATE_CHANGED_TOPIC, properties);\n    }\n\n    /**\n     * Returns the network interface name.\n     *\n     * @return\n     */\n    public String getInterfaceName() {\n        return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY);\n    }\n\n    /**\n     * Returns the new network interface state.\n     *\n     * @return\n     */\n    public NetInterfaceState getNewState() {\n        return (NetInterfaceState) getProperty(NETWORK_EVENT_NEW_STATE_PROPERTY);\n    }\n\n    /**\n     * Returns the old network interface state.\n     *\n     * @return\n     */\n    public NetInterfaceState getOldState() {\n        return (NetInterfaceState) getProperty(NETWORK_EVENT_OLD_STATE_PROPERTY);\n    }\n\n    /**\n     * Returns the reason for the state transition.\n     *\n     * @return\n     */\n    public Reason getReason() {\n        return (Reason) getProperty(NETWORK_EVENT_STATE_CHANGE_REASON_PROPERTY);\n    }\n\n    public enum Reason {\n        /** The reason for the device state change is unknown. */\n        REASON_UNKNOWN,\n\n        /** The state change is normal. */\n        REASON_NONE,\n\n        /** The device is now managed. */\n        REASON_NOW_MANAGED,\n\n        /** The device is no longer managed. */\n        REASON_NOW_UNMANAGED,\n\n        /** The device could not be readied for configuration. */\n        REASON_CONFIG_FAILED,\n\n        /**\n         * IP configuration could not be reserved (no available address, timeout, etc).\n         */\n        REASON_CONFIG_UNAVAILABLE,\n\n        /** The IP configuration is no longer valid. */\n        REASON_CONFIG_EXPIRED,\n\n        /** Secrets were required, but not provided. */\n        REASON_NO_SECRETS,\n\n        /**\n         * The 802.1X supplicant disconnected from the access point or authentication\n         * server.\n         */\n        REASON_SUPPLICANT_DISCONNECT,\n\n        /** Configuration of the 802.1X supplicant failed. */\n        REASON_SUPPLICANT_CONFIG_FAILED,\n\n        /** The 802.1X supplicant quit or failed unexpectedly. */\n        REASON_SUPPLICANT_FAILED,\n\n        /** The 802.1X supplicant took too long to authenticate. */\n        REASON_SUPPLICANT_TIMEOUT,\n\n        /** The PPP service failed to start within the allowed time. */\n        REASON_PPP_START_FAILED,\n\n        /** The PPP service disconnected unexpectedly. */\n        REASON_PPP_DISCONNECT,\n\n        /** The PPP service quit or failed unexpectedly. */\n        REASON_PPP_FAILED,\n\n        /** The DHCP service failed to start within the allowed time. */\n        REASON_DHCP_START_FAILED,\n\n        /** The DHCP service reported an unexpected error. */\n        REASON_DHCP_ERROR,\n\n        /** The DHCP service quit or failed unexpectedly. */\n        REASON_DHCP_FAILED,\n\n        /** The shared connection service failed to start. */\n        REASON_SHARED_START_FAILED,\n\n        /** The shared connection service quit or failed unexpectedly. */\n        REASON_SHARED_FAILED,\n\n        /** The AutoIP service failed to start. */\n        REASON_AUTOIP_START_FAILED,\n\n        /** The AutoIP service reported an unexpected error. */\n        REASON_AUTOIP_ERROR,\n\n        /** The AutoIP service quit or failed unexpectedly. */\n        REASON_AUTOIP_FAILED,\n\n        /** Dialing failed because the line was busy. */\n        REASON_MODEM_BUSY,\n\n        /** Dialing failed because there was no dial tone. */\n        REASON_MODEM_NO_DIAL_TONE,\n\n        /** Dialing failed because there was carrier. */\n        REASON_MODEM_NO_CARRIER,\n\n        /** Dialing timed out. */\n        REASON_MODEM_DIAL_TIMEOUT,\n\n        /** Dialing failed. */\n        REASON_MODEM_DIAL_FAILED,\n\n        /** Modem initialization failed. */\n        REASON_MODEM_INIT_FAILED,\n\n        /** Failed to select the specified GSM APN. */\n        REASON_GSM_APN_FAILED,\n\n        /** Not searching for networks. */\n        REASON_GSM_REGISTRATION_NOT_SEARCHING,\n\n        /** Network registration was denied.* */\n        REASON_GSM_REGISTRATION_DENIED,\n\n        /** Network registration timed out. */\n        REASON_GSM_REGISTRATION_TIMEOUT,\n\n        /** Failed to register with the requested GSM network. */\n        REASON_GSM_REGISTRATION_FAILED,\n\n        /** PIN check failed. */\n        REASON_GSM_PIN_CHECK_FAILED,\n\n        /** Necessary firmware for the device may be missing. */\n        REASON_FIRMWARE_MISSING,\n\n        /** The device was removed. */\n        REASON_REMOVED,\n\n        /** NetworkManager went to sleep. */\n        REASON_SLEEPING,\n\n        /** The device's active connection was removed or disappeared. */\n        REASON_CONNECTION_REMOVED,\n\n        /** A user or client requested the disconnection. */\n        REASON_USER_REQUESTED,\n\n        /** The device's carrier/link changed. */\n        REASON_CARRIER,\n\n        /** The device's existing connection was assumed. */\n        REASON_CONNECTION_ASSUMED,\n\n        /** The 802.1x supplicant is now available. */\n        REASON_SUPPLICANT_AVAILABLE,\n\n        /** The modem could not be found. */\n        REASON_MODEM_NOT_FOUND,\n\n        /** The Bluetooth connection timed out or failed. */\n        REASON_BT_FAILED,\n\n        /** GSM Modem's SIM Card not inserted. */\n        REASON_GSM_SIM_NOT_INSERTED,\n\n        /** GSM Modem's SIM Pin required. */\n        REASON_GSM_SIM_PIN_REQUIRED,\n\n        /** GSM Modem's SIM Puk required. */\n        REASON_GSM_SIM_PUK_REQUIRED,\n\n        /** GSM Modem's SIM wrong */\n        REASON_GSM_SIM_WRONG,\n\n        /** InfiniBand device does not support connected mode. */\n        REASON_INFINIBAND_MODE,\n\n        /** A dependency of the connection failed. */\n        REASON_DEPENDENCY_FAILED,\n\n        /** Problem with the RFC 2684 Ethernet over ADSL bridge. */\n        REASON_BR2684_FAILED;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\n/**\n * Used to track interface configuration status\n */\npublic enum NetInterfaceStatus {\n    /** IPv4 configuration is disabled **/\n    netIPv4StatusDisabled,\n\n    /**\n     * IPv4 configuration is not managed by Kura\n     *\n     * @since 1.4\n     **/\n    netIPv4StatusUnmanaged,\n\n    /**\n     * IPv4 configuration only at Layer 2 of the OSI model\n     *\n     * @since 1.4\n     **/\n    netIPv4StatusL2Only,\n\n    /** IPv4 configuration is enabled as a LAN interface **/\n    netIPv4StatusEnabledLAN,\n\n    /** IPv4 configuration is enabled as a WAN interface **/\n    netIPv4StatusEnabledWAN,\n\n    /** IPv4 configuration is unknown **/\n    netIPv4StatusUnknown,\n\n    /** IPv6 configuration is disabled **/\n    netIPv6StatusDisabled,\n\n    /**\n     * IPv6 configuration is not managed by Kura\n     *\n     * @since 1.4\n     **/\n    netIPv6StatusUnmanaged,\n\n    /**\n     * IPv6 configuration only at Layer 2 of the OSI model\n     *\n     * @since 1.4\n     **/\n    netIPv6StatusL2Only,\n\n    /** IPv6 configuration is enabled as a LAN interface **/\n    netIPv6StatusEnabledLAN,\n\n    /** IPv6 configuration is enabled as a WAN interface **/\n    netIPv6StatusEnabledWAN,\n\n    /** IPv6 configuration is unknown **/\n    netIPv6StatusUnknown;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\n/**\n * Used to store network interface types\n */\npublic enum NetInterfaceType {\n\n    /** The device type is unknown. */\n    UNKNOWN,\n    /** The device is wired Ethernet device. */\n    ETHERNET,\n    /** The device is an 802.11 WiFi device. */\n    WIFI,\n    /** Unused */\n    UNUSED1,\n    /** Unused */\n    UNUSED2,\n    /** The device is Bluetooth device that provides PAN or DUN capabilities. */\n    BT,\n    /** The device is an OLPC mesh networking device. */\n    OLPC_MESH,\n    /** The device is an 802.16e Mobile WiMAX device. */\n    WIMAX,\n    /**\n     * The device is a modem supporting one or more of analog telephone, CDMA/EVDO, GSM/UMTS/HSPA, or LTE\n     * standards to access a cellular or wireline data network.\n     */\n    MODEM,\n    /** The device is an IP-capable InfiniBand interface. */\n    INFINIBAND,\n    /** The device is a bond master interface. */\n    BOND,\n    /** The device is a VLAN interface. */\n    VLAN,\n    /** The device is an ADSL device supporting PPPoE and PPPoATM protocols. */\n    ADSL,\n    /** The device is a loopback device. */\n    LOOPBACK;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetProtocol.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\n/**\n * Used to distinguish network protocol types\n */\npublic enum NetProtocol {\n\n    /** Transmission Control Protocol (TCP) **/\n    tcp,\n\n    /** User Datagram Protocol (UDP) **/\n    udp\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetRouterMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\n/**\n * Used to specify the route mode of each interface.\n * \n * @deprecated since version 3.0.\n */\n@Deprecated\npublic enum NetRouterMode {\n    /** DHCP and NAT **/\n    netRouterDchpNat,\n\n    /** DHCP only **/\n    netRouterDchp,\n\n    /** NAT only **/\n    netRouterNat,\n\n    /** OFF **/\n    netRouterOff;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkAdminService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Sterwen-Technology\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.net.dhcp.DhcpLease;\nimport org.eclipse.kura.net.firewall.FirewallNatConfig;\nimport org.eclipse.kura.net.firewall.FirewallOpenPortConfigIP;\nimport org.eclipse.kura.net.firewall.FirewallPortForwardConfigIP;\nimport org.eclipse.kura.net.wifi.WifiAccessPoint;\nimport org.eclipse.kura.net.wifi.WifiChannel;\nimport org.eclipse.kura.net.wifi.WifiConfig;\nimport org.eclipse.kura.net.wifi.WifiHotspotInfo;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Service API for getting and setting network interface configurations.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic interface NetworkAdminService {\n\n    /**\n     * Returns a list of all of the configurations associated with all of the\n     * interfaces on\n     * the system.\n     *\n     * @return list of NetInterfaceConfigs on the system\n     * @throws KuraException\n     * \n     * @deprecated since 2.4. Use {@link getNetworkInterfaceConfigs(boolean\n     *             recompute)} instead.\n     */\n    @Deprecated\n    public List<? extends NetInterfaceConfig<? extends NetInterfaceAddressConfig>> getNetworkInterfaceConfigs()\n            throws KuraException;\n\n    /**\n     * Returns the configuration information for the specified NetworkInterface\n     * name.\n     * The returned NetConfig captured how the interface was configured; the\n     * returned\n     * list will have a NetConfig4 instance for IPv4 and an NetConfig6 instance for\n     * IPv6.\n     * This should not be confused with the currently active NetInterfaceAddress\n     * associated\n     * with the NetInterface.\n     *\n     * @param interfaceName\n     * @return list of NetConfig for this interface.\n     * \n     * @deprecated since 2.4. Use {@link getNetworkInterfaceConfigs(String\n     *             interfaceName, boolean recompute)} instead.\n     */\n    @Deprecated\n    public List<NetConfig> getNetworkInterfaceConfigs(String interfaceName) throws KuraException;\n\n    /**\n     * Updates the configuration of the specified EthernetInterface.\n     *\n     * @param interfaceName\n     *                      - name of the Ethernet interface\n     * @param autoConnect\n     *                      - specifies the auto-connect value for the interface\n     * @param mtu\n     *                      - required MTU for the interface, -1 to keep the\n     *                      automatic default\n     * @throws KuraException\n     * \n     * @deprecated Since 2.4. Use the\n     *             {@link org.eclipse.kura.configuration.ConfigurationService} to\n     *             update the configuration of an Ethernet interface.\n     */\n    @Deprecated\n    public void updateEthernetInterfaceConfig(String interfaceName, boolean autoConnect, int mtu,\n            List<NetConfig> netConfigs) throws KuraException;\n\n    /**\n     * Updates the configuration of the specified WifiInterface.\n     *\n     * @param interfaceName\n     *                      - name of the wifi interface\n     * @param autoConnect\n     *                      - specifies the auto-connect value for the interface\n     * @throws KuraException\n     * \n     * @deprecated Since 2.4. Use the\n     *             {@link org.eclipse.kura.configuration.ConfigurationService} to\n     *             update the configuration of a Wifi interface.\n     */\n    @Deprecated\n    public void updateWifiInterfaceConfig(String interfaceName, boolean autoConnect, WifiAccessPoint accessPoint,\n            List<NetConfig> netConfigs) throws KuraException;\n\n    /**\n     * Updates the configuration of the specified ModemInterface.\n     *\n     * @param interfaceName\n     *                      - name of the Modem interface\n     * @param serialNum\n     *                      - the modem's serial number\n     * @param modemId\n     *                      - user string to identify the modem\n     * @param pppNumber\n     *                      - ppp number to use for this interface\n     * @param autoConnect\n     *                      - specifies the auto-connect value for the interface\n     * @param mtu\n     *                      - required MTU for the interface, -1 to keep the\n     *                      automatic default\n     * @param netConfigs\n     *                      - list of NetConfigs for this interface\n     * @throws KuraException\n     * \n     * @deprecated Since 2.4. Use the\n     *             {@link org.eclipse.kura.configuration.ConfigurationService} to\n     *             update the configuration of a Modem interface.\n     */\n    @Deprecated\n    public void updateModemInterfaceConfig(String interfaceName, String serialNum, String modemId, int pppNumber,\n            boolean autoConnect, int mtu, List<NetConfig> netConfigs) throws KuraException;\n\n    /**\n     * Enables the specified interface.\n     *\n     * @param interfaceName\n     *                      - name of the interface to be enabled.\n     */\n    public void enableInterface(String interfaceName, boolean dhcp) throws KuraException;\n\n    /**\n     * Disables the specified interface.\n     *\n     * @param interfaceName\n     *                      - name of the interface to be disabled.\n     */\n    public void disableInterface(String interfaceName) throws KuraException;\n\n    /**\n     * Used to control DHCP clients on specified interfaces.\n     *\n     * @param interfaceName\n     *                      The interface of the DHCP server to modify the state\n     * @param enable\n     *                      Whether to enable or disable the DHCP client\n     * @throws KuraException\n     */\n    public void manageDhcpClient(String interfaceName, boolean enable) throws KuraException;\n\n    /**\n     * Used to control DHCP servers on specified interfaces.\n     *\n     * @param interfaceName\n     *                      The interface of the DHCP server to modify the state\n     * @param enable\n     *                      Whether to enable or disable the DHCP server\n     * @throws KuraException\n     */\n    public void manageDhcpServer(String interfaceName, boolean enable) throws KuraException;\n\n    /**\n     * Releases current IP address and acquires a new lease for the provided\n     * interface.\n     *\n     * @param interfaceName\n     *                      The interface on which to renew the lease\n     * @throws KuraException\n     */\n    public void renewDhcpLease(String interfaceName) throws KuraException;\n\n    /**\n     * Gets the firewall configuration of the system as currently specified\n     *\n     * @return A list of NetConfigs representing the firewall configuration\n     * @throws KuraException\n     */\n    public List<NetConfig> getFirewallConfiguration() throws KuraException;\n\n    /**\n     * Sets the 'open port' portion of the firewall configuration\n     *\n     * @param firewallConfiguration\n     *                              A list of FirewallOpenPortConfigIP Objects\n     *                              representing the configuration to set\n     * @throws KuraException\n     * \n     * @deprecated Since 2.4\n     */\n    @Deprecated\n    public void setFirewallOpenPortConfiguration(\n            List<FirewallOpenPortConfigIP<? extends IPAddress>> firewallConfiguration) throws KuraException;\n\n    /**\n     * Sets the 'port forwarding' portion of the firewall configuration\n     *\n     * @param firewallConfiguration\n     *                              A list of FirewallPortForwardConfigIP Objects\n     *                              representing the configuration to set\n     * @throws KuraException\n     * \n     * @deprecated Since 2.4\n     */\n    @Deprecated\n    public void setFirewallPortForwardingConfiguration(\n            List<FirewallPortForwardConfigIP<? extends IPAddress>> firewallConfiguration) throws KuraException;\n\n    /**\n     * Sets the 'ip forwarding' portion of the firewall configuration\n     *\n     * @param natConfigs\n     *                   A list of FirewallNatConfig Objects representing the\n     *                   configuration to set\n     * @throws KuraException\n     * \n     * @deprecated Since 2.4\n     */\n    @Deprecated\n    public void setFirewallNatConfiguration(List<FirewallNatConfig> natConfigs) throws KuraException;\n\n    /**\n     * Updates the Firewall configuration based on current environmental conditions.\n     * This is\n     * used to update the firewall in events where NAT rules need to change based on\n     * a new WAN\n     * interface coming up or going down. This ensures all downstream clients\n     * utilizing NAT\n     * on the gateway can and will maintain active Internet connections through the\n     * gateway.\n     *\n     * @param gatewayIface\n     *                     The new gateway interface that is now active as the WAN\n     *                     interface\n     * @throws KuraException\n     */\n    public void manageFirewall(String gatewayIface) throws KuraException;\n\n    /**\n     * Obtains information for WiFi hotspots in range.\n     *\n     * @param ifaceName\n     *                  - name of WiFi interface\n     * @return list of hotspot information.\n     * @throws KuraException\n     * @since 1.2\n     */\n    public List<WifiHotspotInfo> getWifiHotspotList(String ifaceName) throws KuraException;\n\n    /**\n     * Verifies WiFi credentials by trying to establish connection with access\n     * point.\n     *\n     * @param ifaceName\n     *                   - name of WiFi interface\n     * @param wifiConfig\n     *                   WiFi configuration\n     * @param tout\n     *                   - timeout (in seconds)\n     * @return status - <i>true</i> if credentials are correct, <i>false</i>\n     *         otherwise\n     */\n    public boolean verifyWifiCredentials(String ifaceName, WifiConfig wifiConfig, int tout);\n\n    /**\n     * Obtains information for WiFi Frequencies.\n     *\n     * @param ifaceName\n     *                  - name of WiFi interface\n     * @return list of channels and frequencies.\n     * @throws KuraException\n     * @since 2.2\n     */\n    public List<WifiChannel> getWifiFrequencies(String ifaceName) throws KuraException;\n\n    /**\n     * Obtains information for WiFi Country code.\n     *\n     * @return Name of the Country Code or 00 if unknown.\n     * @throws KuraException\n     * @since 2.2\n     */\n    public String getWifiCountryCode() throws KuraException;\n\n    /**\n     * Information on Dynamic Frequencies Selection\n     * \n     * @param ifaceName\n     *                  - name of WiFi interface\n     * @return True if Dynamic Frequencies Selection is supported, false otherwise\n     * @since 2.3\n     */\n    public boolean isWifiDFS(String ifaceName) throws KuraException;\n\n    /**\n     * Information on WiFi 802.11ac\n     * \n     * @param ifaceName\n     *                  - name of WiFi interface\n     * @return True if WiFi 802.11ac is supported, false otherwise.\n     * @since 2.3\n     */\n    public boolean isWifiIEEE80211AC(String ifaceName) throws KuraException;\n\n    /**\n     * Obtains the DHCP Lease values\n     * \n     * @return list of ipAddresses, macAddresses, hostnames;\n     * @throws KuraException\n     * @since 2.3\n     * @deprecated since 2.6. Use {@link getDhcpLeases(String ifaceName)} instead.\n     */\n    @Deprecated\n    public List<DhcpLease> getDhcpLeases() throws KuraException;\n\n    /**\n     * Obtains the DHCP Lease values assigned by a DHCP server running on a given\n     * network interface\n     * \n     * @param ifaceName the name of the network interface\n     * @return list of ipAddresses, macAddresses, hostnames;\n     * @throws KuraException\n     * @since 2.6\n     */\n    public List<DhcpLease> getDhcpLeases(String ifaceName) throws KuraException;\n\n    /**\n     * Returns a list of all of the configurations associated with all of the\n     * interfaces on\n     * the system and their current values.\n     *\n     * @param recompute:\n     *                   if true the configuration and current values are\n     *                   recomputed. Otherwise, a cached value is returned\n     * @return list of NetInterfaceConfigs on the system\n     * @throws KuraException\n     * \n     * @since 2.4\n     */\n    public List<? extends NetInterfaceConfig<? extends NetInterfaceAddressConfig>> getNetworkInterfaceConfigs(\n            boolean recompute) throws KuraException;\n\n    /**\n     * Returns the configuration information for the specified NetworkInterface\n     * name.\n     * The returned NetConfig captured how the interface was configured; the\n     * returned\n     * list will have a NetConfig4 instance for IPv4 and an NetConfig6 instance for\n     * IPv6.\n     * This should not be confused with the currently active NetInterfaceAddress\n     * associated\n     * with the NetInterface.\n     *\n     * @param interfaceName:\n     *                       the name of the network interface\n     * @param recompute:\n     *                       if true the configuration are recomputed. Otherwise, a\n     *                       cached value is returned\n     * @return list of NetConfig for this interface.\n     * \n     * @since 2.4\n     */\n    public List<NetConfig> getNetworkInterfaceConfigs(String interfaceName, boolean recompute) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkPair.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Model class for a 'network' that is specified by an IP and a mask. For example in the network\n * represented by 192.168.1.0/24 the IpAddress would be 192.168.1.0 and the mask is 24 bits or\n * 255.255.255.0. NetworkPairs are used in various components such as DHCP server configurations\n * where a network must be specified to provide addresses on.\n *\n * @param <T>\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class NetworkPair<T extends IPAddress> {\n\n    /** The IP Address portion of the NetworkPair **/\n    @SuppressWarnings({ \"checkstyle:memberName\", \"checkstyle:visibilityModifier\" })\n    public T m_ipAddress;\n\n    /** The prefix portion of the NetworkPair **/\n    @SuppressWarnings({ \"checkstyle:memberName\", \"checkstyle:visibilityModifier\" })\n    public short m_prefix;\n\n    public NetworkPair(T ipAddress, short prefix) {\n        this.m_ipAddress = ipAddress;\n        this.m_prefix = prefix;\n    }\n\n    public T getIpAddress() {\n        return this.m_ipAddress;\n    }\n\n    public void setIpAddress(T ipAddress) {\n        this.m_ipAddress = ipAddress;\n    }\n\n    public short getPrefix() {\n        return this.m_prefix;\n    }\n\n    public void setPrefix(short prefix) {\n        this.m_prefix = prefix;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(this.m_ipAddress.getHostAddress()).append(\"/\").append(this.m_prefix);\n\n        return sb.toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (!(o instanceof NetworkPair<?>)) {\n            return false;\n        }\n\n        NetworkPair<?> other = (NetworkPair<?>) o;\n\n        return (this.m_ipAddress.equals(other.m_ipAddress) && this.m_prefix == other.m_prefix);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 67;\n        int result = 1;\n        result = prime * result + this.m_prefix;\n        result = prime * result + (this.m_ipAddress == null ? 0 : this.m_ipAddress.hashCode());\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.net.modem.ModemDevice;\nimport org.eclipse.kura.net.wifi.WifiAccessPoint;\nimport org.eclipse.kura.usb.UsbNetDevice;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The NetworkService allows to browse and configure the network interfaces of\n * the system.\n * <br>\n * NetworkService extends what is offered by the standard Java APIs by offering\n * information\n * like the NetworkInterface type - e.g. wired vs wireless vs modem - and\n * additional information\n * regarding the address of a NetworkInterface - e.g. its getway address, DNS,\n * and so on.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface NetworkService {\n\n    /**\n     * Returns the overall state of the networking subsystem\n     * \n     * @deprecated since 2.3\n     */\n    @Deprecated\n    public NetworkState getState() throws KuraException;\n\n    /**\n     * Returns the state of a specific network interface\n     * \n     * @deprecated since 2.3\n     */\n    @Deprecated\n    public NetInterfaceState getState(String interfaceName) throws KuraException;\n\n    /**\n     * Gets the names of all the network interface attached to the system.\n     *\n     * @return the names of all interfaces regardless of 'up' status\n     */\n    public List<String> getAllNetworkInterfaceNames() throws KuraException;\n\n    /**\n     * Gets the names of all the network interface attached to the system.\n     * For each returned NetworkInterface, its currently active\n     * InterfaceAddresses are returned.\n     *\n     * @return all NetworkInterfaces\n     */\n    public List<NetInterface<? extends NetInterfaceAddress>> getNetworkInterfaces() throws KuraException;\n\n    /**\n     * Returns the list of all available WifiAccessPoints as seen from the system.\n     *\n     * @return all access points accessible from the system.\n     */\n    public List<WifiAccessPoint> getAllWifiAccessPoints() throws KuraException;\n\n    /**\n     * Returns the list of the WifiAccessPoints visible from the specified wifi\n     * network interface.\n     * If this wifiInterfaceName is in Master mode it will return a List with one\n     * WifiAccessPoint\n     * which is itself.\n     *\n     * @param wifiInterfaceName\n     *                          name of the interface used to scan for the available\n     *                          access points\n     * @return the list of the WifiAccessPoints visible from the specified wifi\n     *         network interface.\n     */\n    public List<WifiAccessPoint> getWifiAccessPoints(String wifiInterfaceName) throws KuraException;\n\n    /**\n     * Return the active NetworkIntefaces which have active connections for the\n     * system.\n     *\n     * @return\n     */\n    public List<NetInterface<? extends NetInterfaceAddress>> getActiveNetworkInterfaces() throws KuraException;\n\n    /**\n     * Given an interface name (e.g. 'ppp0'), look up the associated usb port\n     * \n     * @param the\n     *            name of the ppp interface (i.e. ppp0)\n     * @return a string representing the usb port of the modem (i.e. 1-2.3)\n     */\n    public String getModemUsbPort(String pppInterfaceName);\n\n    /**\n     * Given a modem device, look up the associated ppp interface name\n     * \n     * @param modemDevice\n     * @return the name of the ppp interface\n     * @throws KuraException\n     */\n    public String getModemPppPort(ModemDevice modemDevice) throws KuraException;\n\n    /**\n     * Given a usb path, look up the associated ppp interface name\n     * \n     * @param usbPath\n     *                a string representing the usb port (i.e. 1-2.3)\n     * @return the name of the ppp interface\n     * @throws KuraException\n     * \n     * @since 2.3\n     */\n    public String getModemPppInterfaceName(String usbPath);\n\n    /**\n     * Given a usb path, look up the associated modem device\n     * \n     * @param usbPath\n     *                a string representing the usb port (i.e. 1-2.3)\n     * @return the {@link ModemDevice} attached to the specified usb port\n     * @throws KuraException\n     * \n     * @since 2.3\n     */\n    public Optional<ModemDevice> getModemDevice(String usbPath);\n\n    /**\n     * Return the {@link UsbNetDevice} associated to the given network interface\n     * name, if any.\n     * \n     * @param interfaceName the name of the network interface\n     * @return an optional {@link UsbNetDevice}\n     * \n     * @since 2.4\n     */\n    public Optional<UsbNetDevice> getUsbNetDevice(String interfaceName);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkState.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\n/**\n * The overall state of the networking subsystem.\n */\npublic enum NetworkState {\n    /** Networking state is unknown. */\n    UNKNOWN(0),\n    /** Networking is inactive and all devices are disabled. */\n    ASLEEP(10),\n    /** There is no active network connection. */\n    DISCONNECTED(20),\n    /** Network connections are being cleaned up. */\n    DISCONNECTING(30),\n    /** A network device is connecting to a network and there is no other available network connection. */\n    CONNECTING(40),\n    /** A network device is connected, but there is only link-local connectivity. */\n    CONNECTED_LOCAL(50),\n    /** A network device is connected, but there is only site-local connectivity. */\n    CONNECTED_SITE(60),\n    /** A network device is connected, with global network connectivity. */\n    CONNECTED_GLOBAL(70);\n\n    private int code;\n\n    private NetworkState(int code) {\n        this.code = code;\n    }\n\n    public static NetworkState parseCode(int code) {\n        for (NetworkState state : NetworkState.values()) {\n            if (state.code == code) {\n                return state;\n            }\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkStateChangedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * Event raised when the state of the network has changed.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class NetworkStateChangedEvent extends Event {\n\n    /** Topic of the NetworkStateChangedEvent */\n    public static final String NETWORK_EVENT_STATE_CHANGED_TOPIC = \"org/eclipse/kura/net/NetworkEvent/STATE_CHANGED\";\n\n    /** Name of the property to access the new network state */\n    public static final String NETWORK_EVENT_NEW_STATE_PROPERTY = \"network.state\";\n\n    public NetworkStateChangedEvent(Map<String, ?> properties) {\n        super(NETWORK_EVENT_STATE_CHANGED_TOPIC, properties);\n    }\n\n    /**\n     * Returns the new network state.\n     *\n     * @return\n     */\n    public NetworkState getState() {\n        return (NetworkState) getProperty(NETWORK_EVENT_NEW_STATE_PROPERTY);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpLease.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Sterwen Technology and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Sterwen-Technology\n *******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @since 2.3\n */\n@ProviderType\npublic class DhcpLease {\n    private String macAddress;\n    private String ipAddress;\n    private String hostname;\n\n    public DhcpLease(String macAddress, String ipAddress, String hostname) {\n        super();\n        this.macAddress = macAddress;\n        this.ipAddress = ipAddress;\n        this.hostname = hostname;\n    }\n\n    public String getMacAddress() {\n        return macAddress;\n    }\n\n    public void setMacAddress(String macAddress) {\n        this.macAddress = macAddress;\n    }\n\n    public String getIpAddress() {\n        return ipAddress;\n    }\n\n    public void setIpAddress(String ipAddress) {\n        this.ipAddress = ipAddress;\n    }\n\n    public String getHostname() {\n        return hostname;\n    }\n\n    public void setHostname(String hostname) {\n        this.hostname = hostname;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"[\");\n        sb.append(\"MacAddress:\").append(macAddress).append(\", IpAddress:\").append(ipAddress).append(\", Hostname:\").append(hostname);\n        sb.append(\"]\");\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a DHCP server.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@FunctionalInterface\n@ProviderType\npublic interface DhcpServer {\n\n    /**\n     * Returns whether or not the DhcpServer is actively running or not\n     *\n     * @return a boolean denoting whether or not the DhcpServer is running or not\n     * @throws KuraException\n     */\n    public boolean isRunning() throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerCfg.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The configuration representing generic portion of DHCP server configuration.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.2\n */\n@ProviderType\npublic class DhcpServerCfg {\n\n    private String interfaceName;\n    private boolean enabled;\n    private int defaultLeaseTime;\n    private int maximumLeaseTime;\n    private boolean passDns;\n\n    /**\n     * The basic Constructor for a DhcpServerCfg\n     *\n     * @param interfaceName\n     *            the interface name associated with the DhcpServerConfig\n     * @param enabled\n     *            the status of the DhcpServer as a boolean\n     * @param defaultLeaseTime\n     *            the default lease time to issue to DHCP clients\n     * @param maximumLeaseTime\n     *            the maximum lease time to issue to DHCP clients\n     * @param passDns\n     *            whether or not to pass DNS to DHCP clients\n     */\n    public DhcpServerCfg(String interfaceName, boolean enabled, int defaultLeaseTime, int maximumLeaseTime,\n            boolean passDns) {\n        super();\n        this.interfaceName = interfaceName;\n        this.enabled = enabled;\n        this.defaultLeaseTime = defaultLeaseTime;\n        this.maximumLeaseTime = maximumLeaseTime;\n        this.passDns = passDns;\n    }\n\n    public String getInterfaceName() {\n        return this.interfaceName;\n    }\n\n    public void setInterfaceName(String interfaceName) {\n        this.interfaceName = interfaceName;\n    }\n\n    public boolean isEnabled() {\n        return this.enabled;\n    }\n\n    public void setEnabled(boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public int getDefaultLeaseTime() {\n        return this.defaultLeaseTime;\n    }\n\n    public void setDefaultLeaseTime(int defaultLeaseTime) {\n        this.defaultLeaseTime = defaultLeaseTime;\n    }\n\n    public int getMaximumLeaseTime() {\n        return this.maximumLeaseTime;\n    }\n\n    public void setMaximumLeaseTime(int maximumLeaseTime) {\n        this.maximumLeaseTime = maximumLeaseTime;\n    }\n\n    public boolean isPassDns() {\n        return this.passDns;\n    }\n\n    public void setPassDns(boolean passDns) {\n        this.passDns = passDns;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder(this.getClass().getName());\n        sb.append(\": [\").append(\"ifaceName=\").append(this.interfaceName).append(\", enabled?=\").append(this.enabled)\n                .append(\", defaultLeaseTime=\").append(this.defaultLeaseTime).append(\", maximumLeaseTime=\")\n                .append(this.maximumLeaseTime).append(\", passDNS?=\").append(this.passDns).append(']');\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerCfgIP.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport java.util.List;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The abstract representation of a 'networking' portion of DhcpServerConfig object.\n *\n * @param <T>\n *            is the an appropriate subclass of IPAddress\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.2\n */\n@ProviderType\npublic abstract class DhcpServerCfgIP<T extends IPAddress> {\n\n    private T subnet;\n    private T subnetMask;\n    private short prefix;\n    private T routerAddress;\n    private T rangeStart;\n    private T rangeEnd;\n    private List<T> dnsServers;\n\n    /**\n     * The basic Constructor for a DhcpServerConfigIP\n     *\n     * @param subnet\n     *            the subnet of the DhcpServerConfig\n     * @param subnetMask\n     *            the subnet mask of the DhcpServerConfig\n     * @param prefix\n     *            the network prefix associated with the DhcpServerConfig\n     * @param routerAddress\n     *            the router IPAddress\n     * @param rangeStart\n     *            the network starting address to issue to DHCP clients\n     * @param rangeEnd\n     *            the network ending address to issue to DHCP clients\n     * @param dnsServers\n     *            the DNS servers that will get passed to DHCP clients if passDns is true\n     */\n    public DhcpServerCfgIP(T subnet, T subnetMask, short prefix, T routerAddress, T rangeStart, T rangeEnd,\n            List<T> dnsServers) {\n        super();\n        this.subnet = subnet;\n        this.subnetMask = subnetMask;\n        this.prefix = prefix;\n        this.routerAddress = routerAddress;\n        this.rangeStart = rangeStart;\n        this.rangeEnd = rangeEnd;\n        this.dnsServers = dnsServers;\n    }\n\n    public T getSubnet() {\n        return this.subnet;\n    }\n\n    public void setSubnet(T subnet) {\n        this.subnet = subnet;\n    }\n\n    public T getSubnetMask() {\n        return this.subnetMask;\n    }\n\n    public void setSubnetMask(T subnetMask) {\n        this.subnetMask = subnetMask;\n    }\n\n    public short getPrefix() {\n        return this.prefix;\n    }\n\n    public void setPrefix(short prefix) {\n        this.prefix = prefix;\n    }\n\n    public T getRouterAddress() {\n        return this.routerAddress;\n    }\n\n    public void setRouterAddress(T routerAddress) {\n        this.routerAddress = routerAddress;\n    }\n\n    public T getRangeStart() {\n        return this.rangeStart;\n    }\n\n    public void setRangeStart(T rangeStart) {\n        this.rangeStart = rangeStart;\n    }\n\n    public T getRangeEnd() {\n        return this.rangeEnd;\n    }\n\n    public void setRangeEnd(T rangeEnd) {\n        this.rangeEnd = rangeEnd;\n    }\n\n    public List<T> getDnsServers() {\n        return this.dnsServers;\n    }\n\n    public void setDnsServers(List<T> dnsServers) {\n        this.dnsServers = dnsServers;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerCfgIP4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport java.net.Inet4Address;\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\nimport java.util.List;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.net.IP4Address;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The configuration representing a 'networking' portion of DHCP server configuration for an IPv4 network.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.2\n */\n@ProviderType\npublic class DhcpServerCfgIP4 extends DhcpServerCfgIP<IP4Address> {\n\n    /**\n     * The basic Constructor for a DhcpServerCfgIP4\n     *\n     * @param subnet\n     *            the subnet of the DhcpServerConfig\n     * @param subnetMask\n     *            the subnet mask of the DhcpServerConfig\n     * @param prefix\n     *            the network prefix associated with the DhcpServerConfig\n     * @param routerAddress\n     *            the router IPAddress\n     * @param rangeStart\n     *            the network starting address to issue to DHCP clients\n     * @param rangeEnd\n     *            the network ending address to issue to DHCP clients\n     * @param dnsServers\n     *            the DNS servers that will get passed to DHCP clients if passDns is true\n     */\n    public DhcpServerCfgIP4(IP4Address subnet, IP4Address subnetMask, short prefix, IP4Address routerAddress,\n            IP4Address rangeStart, IP4Address rangeEnd, List<IP4Address> dnsServers) {\n        super(subnet, subnetMask, prefix, routerAddress, rangeStart, rangeEnd, dnsServers);\n    }\n\n    /**\n     * Validates DHCP pool\n     */\n    public boolean isValid() throws KuraException {\n        boolean ret = false;\n        if (isIpAddressInSubnet(getRangeStart().getHostAddress(), getSubnet().getHostAddress(),\n                getSubnetMask().getHostAddress())\n                && isIpAddressInSubnet(getRangeEnd().getHostAddress(), getSubnet().getHostAddress(),\n                        getSubnetMask().getHostAddress())) {\n            ret = true;\n        }\n        return ret;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder(this.getClass().getName());\n        sb.append(\": [subnet=\").append(getSubnet().getHostAddress()).append(\", subnetMask=\")\n                .append(getSubnetMask().getHostAddress()).append(\", prefix=\").append(getPrefix())\n                .append(\", routerAddress=\").append(getRouterAddress()).append(\", rangeStart=\").append(getRangeStart())\n                .append(\", rangeEnd=\").append(getRangeEnd());\n        for (IP4Address dnsServer : getDnsServers()) {\n            sb.append(\", dnsServer=\").append(dnsServer);\n        }\n        sb.append(']');\n        return sb.toString();\n    }\n\n    private static int inet4address2int(Inet4Address inet4addr) {\n\n        byte[] baInet4addr = inet4addr.getAddress();\n        return (baInet4addr[0] & 0xFF) << 24 | (baInet4addr[1] & 0xFF) << 16 | (baInet4addr[2] & 0xFF) << 8\n                | baInet4addr[3] & 0xFF;\n    }\n\n    private boolean isIpAddressInSubnet(String ip, String subnet, String netmask) throws KuraException {\n        boolean retVal = false;\n        try {\n            int iIp = inet4address2int((Inet4Address) InetAddress.getByName(ip));\n            int iSubnet = inet4address2int((Inet4Address) InetAddress.getByName(subnet));\n            int iNetmask = inet4address2int((Inet4Address) InetAddress.getByName(netmask));\n\n            if ((iSubnet & iNetmask) == (iIp & iNetmask)) {\n                retVal = true;\n            }\n        } catch (UnknownHostException e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e);\n        }\n\n        return retVal;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerCfgIP6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport java.util.List;\n\nimport org.eclipse.kura.net.IP6Address;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The configuration representing a 'networking' portion of DHCP server configuration for an IPv6 network.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 1.2\n */\n@ProviderType\npublic class DhcpServerCfgIP6 extends DhcpServerCfgIP<IP6Address> {\n\n    /**\n     * The basic Constructor for a DhcpServerCfgIP6\n     *\n     * @param subnet\n     *            the subnet of the DhcpServerConfig\n     * @param subnetMask\n     *            the subnet mask of the DhcpServerConfig\n     * @param prefix\n     *            the network prefix associated with the DhcpServerConfig\n     * @param routerAddress\n     *            the router IPAddress\n     * @param rangeStart\n     *            the network starting address to issue to DHCP clients\n     * @param rangeEnd\n     *            the network ending address to issue to DHCP clients\n     * @param dnsServers\n     *            the DNS servers that will get passed to DHCP clients if passDns is true\n     */\n    public DhcpServerCfgIP6(IP6Address subnet, IP6Address subnetMask, short prefix, IP6Address routerAddress,\n            IP6Address rangeStart, IP6Address rangeEnd, List<IP6Address> dnsServers) {\n        super(subnet, subnetMask, prefix, routerAddress, rangeStart, rangeEnd, dnsServers);\n    }\n\n    /**\n     * class validator\n     *\n     */\n    public boolean isValid() {\n        // TODO need to range implement validation\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport java.util.List;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for all DHCP server configuration classes\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface DhcpServerConfig extends NetConfig {\n\n    /**\n     * Returns the interface name associated with this DhcpServerConfig\n     *\n     * @return a {@link String} representing the interface name\n     */\n    public String getInterfaceName();\n\n    /**\n     * Returns the {@link boolean} status associated with this DhcpServerConfig\n     *\n     * @return a {@link boolean} representing the status\n     */\n    public boolean isEnabled();\n\n    /**\n     * Returns the subnet associated with this DhcpServerConfig\n     *\n     * @return a {@link IPAddress } representing the subnet\n     */\n    public IPAddress getSubnet();\n\n    /**\n     * Returns the router IP address associated with this DhcpServerConfig\n     *\n     * @return a {@link IPAddress } representing the router IP address\n     */\n    public IPAddress getRouterAddress();\n\n    /**\n     * Returns the subnet mask associated with this DhcpServerConfig\n     *\n     * @return a {@link IPAddress } representing the subnet mask\n     */\n    public IPAddress getSubnetMask();\n\n    /**\n     * Returns the default lease time offered by the DHCP server\n     *\n     * @return the default lease time (in seconds) offered by the DHCP server\n     */\n    public int getDefaultLeaseTime();\n\n    /**\n     * Returns the maximum lease time offered by the DHCP server\n     *\n     * @return the maximum lease time (in seconds) offered by the DHCP server\n     */\n    public int getMaximumLeaseTime();\n\n    /**\n     * Returns the network prefix length for this DHCP server's address range\n     * This is also known as the subnet mask in the context of IPv4 addresses.\n     * Typical IPv4 values would be 8 (255.0.0.0), 16 (255.255.0.0) or 24 (255.255.255.0).\n     * Typical IPv6 values would be 128 (::1/128) or 10 (fe80::203:baff:fe27:1243/10)\n     *\n     * @return a short representing the prefix length for the subnet of the DHCP server address range.\n     */\n    public short getPrefix();\n\n    /**\n     * Returns the starting DHCP server InetAddress to provide to DHCP clients.\n     *\n     * @return the starting address to provide to DHCP clients\n     */\n    public IPAddress getRangeStart();\n\n    /**\n     * Returns the ending DHCP server InetAddress to provide to DHCP clients.\n     *\n     * @return the ending address to provide to DHCP clients\n     */\n    public IPAddress getRangeEnd();\n\n    /**\n     * Returns whether or not DHCP clients should get DNS services.\n     *\n     * @return a boolean representing whether or not DHCP clients should receive DNS services.\n     */\n    public boolean isPassDns();\n\n    /**\n     * Returns the DNS servers associated with this DhcpServerConfig that will be passed to DHCP clients\n     *\n     * @return a {@link List } of IPAddresses that represent the DNS servers\n     */\n    public List<? extends IPAddress> getDnsServers();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfig4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv4-based configurations of DHCP Servers\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface DhcpServerConfig4 extends DhcpServerConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfig6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv6-based configurations of DHCP Servers\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface DhcpServerConfig6 extends DhcpServerConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfigIP.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport java.util.List;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The abstract representation of a DhcpServerConfig object.\n *\n * @param <T>\n *            is the an appropriate subclass of IPAddress\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic abstract class DhcpServerConfigIP<T extends IPAddress> implements DhcpServerConfig {\n\n    private String interfaceName;\n    private boolean enabled;\n    private T subnet;\n    private T routerAddress;\n    private T subnetMask;\n    private int defaultLeaseTime;\n    private int maximumLeaseTime;\n    private short prefix;\n    private T rangeStart;\n    private T rangeEnd;\n    private boolean passDns;\n    private List<T> dnsServers;\n\n    /**\n     * The basic Constructor for a DhcpServerConfigIP\n     *\n     * @param interfaceName\n     *                         the interface name associated with the\n     *                         DhcpServerConfig\n     * @param enabled\n     *                         the status of the DhcpServer as a boolean\n     * @param subnet\n     *                         the subnet of the DhcpServerConfig\n     * @param routerAddress\n     *                         the router IPAddress\n     * @param subnetMask\n     *                         the subnet mask of the DhcpServerConfig\n     * @param defaultLeaseTime\n     *                         the default lease time to issue to DHCP clients\n     * @param maximumLeaseTime\n     *                         the maximum lease time to issue to DHCP clients\n     * @param prefix\n     *                         the network prefix associated with the\n     *                         DhcpServerConfig\n     * @param rangeStart\n     *                         the network starting address to issue to DHCP clients\n     * @param rangeEnd\n     *                         the network ending address to issue to DHCP clients\n     * @param passDns\n     *                         whether or not to pass DNS to DHCP clients\n     * @param dnsServers\n     *                         the DNS servers that will get passed to DHCP clients\n     *                         if passDns is true\n     */\n    @Deprecated\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    public DhcpServerConfigIP(String interfaceName, boolean enabled, T subnet, T routerAddress, T subnetMask,\n            int defaultLeaseTime, int maximumLeaseTime, short prefix, T rangeStart, T rangeEnd, boolean passDns,\n            List<T> dnsServers) {\n        super();\n\n        this.interfaceName = interfaceName;\n        this.enabled = enabled;\n        this.subnet = subnet;\n        this.routerAddress = routerAddress;\n        this.subnetMask = subnetMask;\n        this.defaultLeaseTime = defaultLeaseTime;\n        this.maximumLeaseTime = maximumLeaseTime;\n        this.prefix = prefix;\n        this.rangeStart = rangeStart;\n        this.rangeEnd = rangeEnd;\n        this.passDns = passDns;\n        this.dnsServers = dnsServers;\n    }\n\n    /**\n     * The basic Constructor for a DhcpServerConfigIP\n     *\n     * @param dhcpServerCfg\n     *                        DHCP server configuration\n     * @param dhcpServerCfgIP\n     *                        'network' configuration\n     * @since 1.2\n     */\n    public DhcpServerConfigIP(DhcpServerCfg dhcpServerCfg, DhcpServerCfgIP<T> dhcpServerCfgIP) {\n        this.interfaceName = dhcpServerCfg.getInterfaceName();\n        this.enabled = dhcpServerCfg.isEnabled();\n        this.subnet = dhcpServerCfgIP.getSubnet();\n        this.routerAddress = dhcpServerCfgIP.getRouterAddress();\n        this.subnetMask = dhcpServerCfgIP.getSubnetMask();\n        this.defaultLeaseTime = dhcpServerCfg.getDefaultLeaseTime();\n        this.maximumLeaseTime = dhcpServerCfg.getMaximumLeaseTime();\n        this.prefix = dhcpServerCfgIP.getPrefix();\n        this.rangeStart = dhcpServerCfgIP.getRangeStart();\n        this.rangeEnd = dhcpServerCfgIP.getRangeEnd();\n        this.passDns = dhcpServerCfg.isPassDns();\n        this.dnsServers = dhcpServerCfgIP.getDnsServers();\n    }\n\n    @Override\n    public String getInterfaceName() {\n        return this.interfaceName;\n    }\n\n    /**\n     * sets the interface name for the DhcpServerConfig\n     *\n     * @param interfaceName\n     *                      the interface name in the form of a {@link String}\n     */\n    public void setInterfaceName(String interfaceName) {\n        this.interfaceName = interfaceName;\n    }\n\n    @Override\n    public boolean isEnabled() {\n        return this.enabled;\n    }\n\n    /**\n     * sets the status for the DhcpServerConfig\n     *\n     * @param enabled\n     *                the Dhcp Server status in the form of a {@link boolean}\n     */\n    public void setEnabledRouterMode(boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    @Override\n    public T getSubnet() {\n        return this.subnet;\n    }\n\n    /**\n     * sets the subnet for the DhcpServerConfig\n     *\n     * @param subnet\n     *               the subnet in the form of a {@link IPAddress}\n     */\n    public void setSubnet(T subnet) {\n        this.subnet = subnet;\n    }\n\n    @Override\n    public T getRouterAddress() {\n        return this.routerAddress;\n    }\n\n    /**\n     * sets the router IPAddress for the DhcpServerConfig\n     *\n     * @param routerAddress\n     *                      the router IPAddress in the form of a {@link IPAddress}\n     */\n    public void setRouterAddress(T routerAddress) {\n        this.routerAddress = routerAddress;\n    }\n\n    @Override\n    public T getSubnetMask() {\n        return this.subnetMask;\n    }\n\n    /**\n     * sets the subnet mask for the DhcpServerConfig\n     *\n     * @param subnetMask\n     *                   the subnet mask in the form of a {@link IPAddress}\n     */\n    public void setSubnetMask(T subnetMask) {\n        this.subnetMask = subnetMask;\n    }\n\n    @Override\n    public int getDefaultLeaseTime() {\n        return this.defaultLeaseTime;\n    }\n\n    /**\n     * sets the default lease time for DHCP clients\n     *\n     * @param defaultLeaseTime\n     *                         the default lease time\n     */\n    public void setDefaultLeaseTime(int defaultLeaseTime) {\n        this.defaultLeaseTime = defaultLeaseTime;\n    }\n\n    @Override\n    public int getMaximumLeaseTime() {\n        return this.maximumLeaseTime;\n    }\n\n    /**\n     * sets the maximum lease time for DHCP clients\n     *\n     * @param maximumLeaseTime\n     *                         the maximum lease time\n     */\n    public void setMaximumLeaseTime(int maximumLeaseTime) {\n        this.maximumLeaseTime = maximumLeaseTime;\n    }\n\n    @Override\n    public short getPrefix() {\n        return this.prefix;\n    }\n\n    /**\n     * sets the network prefix for the DhcpServerConfig\n     *\n     * @param prefix\n     *               the prefix\n     */\n    public void setPrefix(short prefix) {\n        this.prefix = prefix;\n    }\n\n    @Override\n    public T getRangeStart() {\n        return this.rangeStart;\n    }\n\n    /**\n     * sets the starting IPAddress in the pool for the DHCP clients\n     *\n     * @param m_rangeStart\n     *                     the starting IPAddress\n     */\n    public void setRangeStart(T rangeStart) {\n        this.rangeStart = rangeStart;\n    }\n\n    @Override\n    public T getRangeEnd() {\n        return this.rangeEnd;\n    }\n\n    /**\n     * sets the ending IPAddress in the pool for the DHCP clients\n     *\n     * @param rangeEnd\n     *                 the ending IPAddress\n     */\n    public void setRangeEnd(T rangeEnd) {\n        this.rangeEnd = rangeEnd;\n    }\n\n    @Override\n    public boolean isPassDns() {\n        return this.passDns;\n    }\n\n    /**\n     * whether or not to pass DNS to DHCP clients\n     *\n     * @param passDns\n     *                true to pass, false to not\n     */\n    public void setPassDns(boolean passDns) {\n        this.passDns = passDns;\n    }\n\n    @Override\n    public List<T> getDnsServers() {\n        return this.dnsServers;\n    }\n\n    /**\n     * the DNS servers to pass to DHCP clients if passDns is set to true\n     *\n     * @param m_dnsServers\n     *                     the DNS servers to pass\n     */\n    public void setDnsServers(List<T> dnsServers) {\n        this.dnsServers = dnsServers;\n    }\n\n    @Override\n    public boolean isValid() {\n        if (this.interfaceName == null || !isValidSubnet()) {\n            return false;\n        }\n        if (!isValidPoolRange() || !isValidLeaseTime() || this.prefix <= 0) {\n            return false;\n        }\n        return true;\n    }\n\n    private boolean isValidSubnet() {\n        return this.subnet != null && this.subnetMask != null ? true : false;\n    }\n\n    private boolean isValidPoolRange() {\n        return this.rangeStart != null && this.rangeEnd != null ? true : false;\n    }\n\n    private boolean isValidLeaseTime() {\n        return this.defaultLeaseTime > 0 && this.maximumLeaseTime > 0 ? true : false;\n    }\n\n    /**\n     * Returns a string representation of the Dhcp Server Configuration.\n     * DO NOT use it to write the service configuration file in the filesystem.\n     */\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n\n        sb.append(\"# enabled? \").append(this.enabled).append(\"\\n\");\n        sb.append(\"# prefix: \").append(this.prefix).append(\"\\n\");\n        sb.append(\"# pass DNS? \").append(this.passDns).append(\"\\n\\n\");\n\n        sb.append(\"subnet \" + this.subnet.getHostAddress() + \" netmask \" + this.subnetMask.getHostAddress() + \" {\\n\");\n\n        // DNS servers\n        if (this.passDns && this.dnsServers != null && !this.dnsServers.isEmpty()) {\n            sb.append(\"    option domain-name-servers \");\n            for (int i = 0; i < this.dnsServers.size(); i++) {\n                if (this.dnsServers.get(i) != null) {\n                    sb.append(this.dnsServers.get(i).getHostAddress());\n                }\n\n                if (i + 1 == this.dnsServers.size()) {\n                    sb.append(\";\\n\\n\");\n                } else {\n                    sb.append(\",\");\n                }\n            }\n        }\n        // interface\n        if (this.interfaceName != null) {\n            sb.append(\"    interface \" + this.interfaceName + \";\\n\");\n        }\n        // router address\n        if (this.routerAddress != null) {\n            sb.append(\"    option routers \" + this.routerAddress.getHostAddress() + \";\\n\");\n        }\n        // if DNS should not be forwarded, add the following lines\n        if (!this.passDns) {\n            sb.append(\"    ddns-update-style none;\\n\");\n            sb.append(\"    ddns-updates off;\\n\");\n        }\n        // Lease times\n        sb.append(\"    default-lease-time \" + this.defaultLeaseTime + \";\\n\");\n        if (this.maximumLeaseTime > -1) {\n            sb.append(\"    max-lease-time \" + this.maximumLeaseTime + \";\\n\");\n        }\n\n        // Add the pool and range\n        sb.append(\"    pool {\\n\");\n        sb.append(\"        range \" + this.rangeStart.getHostAddress() + \" \" + this.rangeEnd.getHostAddress() + \";\\n\");\n        sb.append(\"    }\\n\");\n        sb.append(\"}\\n\");\n\n        return sb.toString();\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 59;\n        int result = super.hashCode();\n        result = prime * result + (this.enabled ? 1 : 0);\n        result = prime * result + (this.interfaceName == null ? 0 : this.interfaceName.hashCode());\n        result = prime * result + (this.subnet == null ? 0 : this.subnet.hashCode());\n        result = prime * result + (this.subnetMask == null ? 0 : this.subnetMask.hashCode());\n        result = prime * result + (this.routerAddress == null ? 0 : this.routerAddress.hashCode());\n        result = prime * result + (this.rangeStart == null ? 0 : this.rangeStart.hashCode());\n        result = prime * result + (this.rangeEnd == null ? 0 : this.rangeEnd.hashCode());\n        result = prime * result + (this.dnsServers == null ? 0 : this.dnsServers.hashCode());\n        result = prime * result + this.defaultLeaseTime;\n        result = prime * result + this.maximumLeaseTime;\n        result = prime * result + this.prefix;\n        result = prime * result + (this.passDns ? 1 : 0);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n\n        @SuppressWarnings(\"rawtypes\")\n        DhcpServerConfigIP other = (DhcpServerConfigIP) obj;\n\n        if (this.enabled != other.enabled) {\n            return false;\n        }\n\n        if (this.interfaceName == null) {\n            if (other.interfaceName != null) {\n                return false;\n            }\n        } else if (!this.interfaceName.equals(other.interfaceName)) {\n            return false;\n        }\n\n        if (this.subnet == null) {\n            if (other.subnet != null) {\n                return false;\n            }\n        } else if (!this.subnet.equals(other.subnet)) {\n            return false;\n        }\n\n        if (this.routerAddress == null) {\n            if (other.routerAddress != null) {\n                return false;\n            }\n        } else if (!this.routerAddress.equals(other.routerAddress)) {\n            return false;\n        }\n\n        if (this.subnetMask == null) {\n            if (other.subnetMask != null) {\n                return false;\n            }\n        } else if (!this.subnetMask.equals(other.subnetMask)) {\n            return false;\n        }\n\n        if (this.defaultLeaseTime != other.defaultLeaseTime) {\n            return false;\n        }\n\n        if (this.maximumLeaseTime != other.maximumLeaseTime) {\n            return false;\n        }\n\n        if (this.prefix != other.prefix) {\n            return false;\n        }\n\n        if (this.rangeStart == null) {\n            if (other.rangeStart != null) {\n                return false;\n            }\n        } else if (!this.rangeStart.equals(other.rangeStart)) {\n            return false;\n        }\n\n        if (this.rangeEnd == null) {\n            if (other.rangeEnd != null) {\n                return false;\n            }\n        } else if (!this.rangeEnd.equals(other.rangeEnd)) {\n            return false;\n        }\n\n        if (this.passDns != other.passDns) {\n            return false;\n        }\n\n        if (this.dnsServers == null) {\n            if (other.dnsServers != null) {\n                return false;\n            }\n        } else if (!this.dnsServers.equals(other.dnsServers)) {\n            return false;\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfigIP4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.net.IP4Address;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The configuration representing a DHCP server configuration for an IPv4 network.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class DhcpServerConfigIP4 extends DhcpServerConfigIP<IP4Address> implements DhcpServerConfig4 {\n\n    /**\n     * The basic Constructor for a DhcpServerConfigIP4\n     *\n     * @param interfaceName\n     *            the interface name associated with the DhcpServerConfig\n     * @param enabled\n     *            the status of the DhcpServer as a boolean\n     * @param subnet\n     *            the subnet of the DhcpServerConfig\n     * @param routerAddress\n     *            the router IPAddress\n     * @param subnetMask\n     *            the subnet mask of the DhcpServerConfig\n     * @param defaultLeaseTime\n     *            the default lease time to issue to DHCP clients\n     * @param maximumLeaseTime\n     *            the maximum lease time to issue to DHCP clients\n     * @param prefix\n     *            the network prefix associated with the DhcpServerConfig\n     * @param rangeStart\n     *            the network starting address to issue to DHCP clients\n     * @param rangeEnd\n     *            the network ending address to issue to DHCP clients\n     * @param passDns\n     *            whether or not to pass DNS to DHCP clients\n     * @param dnsServers\n     *            the DNS servers that will get passed to DHCP clients if passDns is true\n     */\n    @Deprecated\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    public DhcpServerConfigIP4(String interfaceName, boolean enabled, IP4Address subnet, IP4Address routerAddress,\n            IP4Address subnetMask, int defaultLeaseTime, int maximumLeaseTime, short prefix, IP4Address rangeStart,\n            IP4Address rangeEnd, boolean passDns, List<IP4Address> dnsServers) {\n\n        super(interfaceName, enabled, subnet, routerAddress, subnetMask, defaultLeaseTime, maximumLeaseTime, prefix,\n                rangeStart, rangeEnd, passDns, dnsServers);\n    }\n\n    /**\n     * The basic Constructor for a DhcpServerConfigIP4\n     *\n     * @param dhcpServerCfg\n     *            DHCP server configuration\n     * @param dhcpServerCfgIP4\n     *            'network' configuration\n     * @throws KuraException\n     * @since 1.2\n     */\n    public DhcpServerConfigIP4(DhcpServerCfg dhcpServerCfg, DhcpServerCfgIP4 dhcpServerCfgIP4) throws KuraException {\n\n        super(dhcpServerCfg, dhcpServerCfgIP4);\n        if (!isValid() || !dhcpServerCfgIP4.isValid()) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfigIP6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dhcp;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.net.IP6Address;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The configuration representing a DHCP server configuration for an IPv6 network.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class DhcpServerConfigIP6 extends DhcpServerConfigIP<IP6Address> implements DhcpServerConfig6 {\n\n    /**\n     * The basic Constructor for a DhcpServerConfigIP6\n     *\n     * @param interfaceName\n     *            the interface name associated with the DhcpServerConfig\n     * @param enabled\n     *            the status of the DhcpServer as a {@link boolean }\n     * @param subnet\n     *            the subnet of the DhcpServerConfig\n     * @param routerAddress\n     *            the router IPAddress\n     * @param subnetMask\n     *            the subnet mask of the DhcpServerConfig\n     * @param defaultLeaseTime\n     *            the default lease time to issue to DHCP clients\n     * @param maximumLeaseTime\n     *            the maximum lease time to issue to DHCP clients\n     * @param prefix\n     *            the network prefix associated with the DhcpServerConfig\n     * @param rangeStart\n     *            the network starting address to issue to DHCP clients\n     * @param rangeEnd\n     *            the network ending address to issue to DHCP clients\n     * @param passDns\n     *            whether or not to pass DNS to DHCP clients\n     * @param dnsServers\n     *            the DNS servers that will get passed to DHCP clients if passDns is true\n     */\n    @Deprecated\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    public DhcpServerConfigIP6(String interfaceName, boolean enabled, IP6Address subnet, IP6Address routerAddress,\n            IP6Address subnetMask, int defaultLeaseTime, int maximumLeaseTime, short prefix, IP6Address rangeStart,\n            IP6Address rangeEnd, boolean passDns, List<IP6Address> dnsServers) {\n\n        super(interfaceName, enabled, subnet, routerAddress, subnetMask, defaultLeaseTime, maximumLeaseTime, prefix,\n                rangeStart, rangeEnd, passDns, dnsServers);\n\n    }\n\n    /**\n     * The basic Constructor for a DhcpServerConfigIP6\n     *\n     * @param dhcpServerCfg\n     *            DHCP server configuration\n     * @param dhcpServerCfgIP4\n     *            'network' configuration\n     * @throws KuraException\n     * @since 1.2\n     */\n    public DhcpServerConfigIP6(DhcpServerCfg dhcpServerCfg, DhcpServerCfgIP6 dhcpServerCfgIP6) throws KuraException {\n\n        super(dhcpServerCfg, dhcpServerCfgIP6);\n        if (!isValid() || !dhcpServerCfgIP6.isValid()) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Interfaces for all DHCP server instances.\n *\n */\npackage org.eclipse.kura.net.dhcp;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsMonitorService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dns;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for dns server monitoring service\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic interface DnsMonitorService {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dns;\n\nimport java.util.Set;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetConfig;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The placeholder for all DNS proxy servers\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface DnsServerConfig extends NetConfig {\n\n    /**\n     * returns the DNS forwarders associated with this DnsServerConfig\n     *\n     * @return a {@link java.util.List } of DNS forwarders\n     */\n    public Set<? extends IPAddress> getForwarders();\n\n    /**\n     * returns the allowed networks for resolving DNS queries\n     *\n     * @return a {@link java.util.List } of {@link NetworkPair } representing the networks that are allowed to\n     *         perform DNS queries\n     */\n    public Set<? extends NetworkPair<? extends IPAddress>> getAllowedNetworks();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfig4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dns;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Placeholder for IPv4 DNS server configurations\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface DnsServerConfig4 extends DnsServerConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfig6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dns;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Placeholder for IPv6 DNS server configurations\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface DnsServerConfig6 extends DnsServerConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfigIP.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dns;\n\nimport java.util.Set;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Base class for DNS proxy configurations\n *\n * @param <T>\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic abstract class DnsServerConfigIP<T extends IPAddress> implements DnsServerConfig {\n\n    private Set<T> forwarders;\n    private Set<NetworkPair<T>> allowedNetworks;\n\n    /**\n     * Creates a DNS configuration with a default set of forwarders and a set of allowed networks\n     *\n     * @param forwarders\n     *            The recursive DNS servers to use\n     * @param allowedNetworks\n     *            The LAN networks that are allowed to make queries\n     */\n    public DnsServerConfigIP(Set<T> forwarders, Set<NetworkPair<T>> allowedNetworks) {\n        super();\n\n        this.forwarders = forwarders;\n        this.allowedNetworks = allowedNetworks;\n    }\n\n    /**\n     * Gets the current recursive domain name servers to use to resolve queries\n     */\n    @Override\n    public Set<T> getForwarders() {\n        return this.forwarders;\n    }\n\n    /**\n     * Sets the current recursive domain name servers to use to resolve queries\n     *\n     * @param forwarders\n     *            The recursive DNS servers to use\n     */\n    public void setForwarders(Set<T> forwarders) {\n        this.forwarders = forwarders;\n    }\n\n    /**\n     * Gets a List of networks that are allowed to make DNS queries\n     */\n    @Override\n    public Set<NetworkPair<T>> getAllowedNetworks() {\n        return this.allowedNetworks;\n    }\n\n    /**\n     * Sets a List of networks that are allowed to make DNS queries\n     *\n     * @param allowedNetworks\n     *            The LAN networks that are allowed to make queries\n     */\n    public void setAllowedNetworks(Set<NetworkPair<T>> allowedNetworks) {\n        this.allowedNetworks = allowedNetworks;\n    }\n\n    @Override\n    public String toString() {\n        return \"DnsServerConfigIP [m_forwarders=\" + this.forwarders + \", m_allowedNetworks=\" + this.allowedNetworks\n                + \"]\";\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.allowedNetworks == null ? 0 : this.allowedNetworks.hashCode());\n        result = prime * result + (this.forwarders == null ? 0 : this.forwarders.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        DnsServerConfigIP<?> other = (DnsServerConfigIP<?>) obj;\n        if (this.allowedNetworks == null) {\n            if (other.allowedNetworks != null) {\n                return false;\n            }\n        } else if (!this.allowedNetworks.equals(other.allowedNetworks)) {\n            return false;\n        }\n        if (this.forwarders == null) {\n            if (other.forwarders != null) {\n                return false;\n            }\n        } else if (!this.forwarders.equals(other.forwarders)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfigIP4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dns;\n\nimport java.util.Set;\n\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * DNS server configurations for IPv4 networks\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class DnsServerConfigIP4 extends DnsServerConfigIP<IP4Address> implements DnsServerConfig4 {\n\n    public DnsServerConfigIP4(Set<IP4Address> forwarders, Set<NetworkPair<IP4Address>> allowedNetworks) {\n        super(forwarders, allowedNetworks);\n    }\n\n    @Override\n    public boolean isValid() {\n        // TODO Auto-generated method stub\n        return false;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfigIP6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.dns;\n\nimport java.util.Set;\n\nimport org.eclipse.kura.net.IP6Address;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * DNS server configurations for IPv6 networks\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class DnsServerConfigIP6 extends DnsServerConfigIP<IP6Address> implements DnsServerConfig6 {\n\n    public DnsServerConfigIP6(Set<IP6Address> forwarders, Set<NetworkPair<IP6Address>> allowedNetworks) {\n        super(forwarders, allowedNetworks);\n    }\n\n    @Override\n    public boolean isValid() {\n        // TODO Auto-generated method stub\n        return false;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Interfaces for all DNS server instances.\n *\n */\npackage org.eclipse.kura.net.dns;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallAutoNatConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport org.eclipse.kura.net.NetConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents an automatic NAT configuration\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class FirewallAutoNatConfig implements NetConfig {\n\n    /** The source interface (LAN interface) for the NAT configuration **/\n    private String sourceInterface;\n\n    /** The destination interface (WAN interface) for the NAT configuration **/\n    private String destinationInterface;\n\n    /** Whether or not MASQUERADE should be enabled **/\n    private boolean masquerade;\n\n    /**\n     * Creates a null NAT configuration\n     */\n    public FirewallAutoNatConfig() {\n        super();\n    }\n\n    /**\n     * Creates a complete auto NAT configuration\n     *\n     * @param sourceInterface\n     *            The source interface (LAN interface) for the NAT configuration\n     * @param destinationInterface\n     *            The destination interface (WAN interface) for the NAT configuration\n     * @param masquerade\n     *            Whether or not MASQUERADE should be enabled\n     */\n    public FirewallAutoNatConfig(String sourceInterface, String destinationInterface, boolean masquerade) {\n        super();\n        this.sourceInterface = sourceInterface;\n        this.destinationInterface = destinationInterface;\n        this.masquerade = masquerade;\n    }\n\n    public String getSourceInterface() {\n        return this.sourceInterface;\n    }\n\n    public void setSourceInterface(String sourceInterface) {\n        this.sourceInterface = sourceInterface;\n    }\n\n    public String getDestinationInterface() {\n        return this.destinationInterface;\n    }\n\n    public void setDestinationInterface(String destinationInterface) {\n        this.destinationInterface = destinationInterface;\n    }\n\n    public boolean isMasquerade() {\n        return this.masquerade;\n    }\n\n    public void setMasquerade(boolean masquerade) {\n        this.masquerade = masquerade;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.destinationInterface == null ? 0 : this.destinationInterface.hashCode());\n        result = prime * result + (this.masquerade ? 1231 : 1237);\n        result = prime * result + (this.sourceInterface == null ? 0 : this.sourceInterface.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        FirewallAutoNatConfig other = (FirewallAutoNatConfig) obj;\n\n        if (this.masquerade != other.masquerade) {\n            return false;\n        }\n        if (this.sourceInterface == null) {\n            if (other.sourceInterface != null) {\n                return false;\n            }\n        } else if (!this.sourceInterface.equals(other.sourceInterface)) {\n            return false;\n        }\n\n        return true;\n    }\n\n    @Override\n    public boolean isValid() {\n        boolean result = false;\n        if (this.destinationInterface != null && !this.destinationInterface.trim().isEmpty()\n                && this.sourceInterface != null && !this.sourceInterface.trim().isEmpty()) {\n            result = true;\n        }\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"FirewallNatConfig [m_sourceInterface=\");\n        builder.append(this.sourceInterface);\n        builder.append(\", m_destinationInterface=\");\n        builder.append(this.destinationInterface);\n        builder.append(\", m_masquerade=\");\n        builder.append(this.masquerade);\n        builder.append(\"]\");\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallNatConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport org.eclipse.kura.net.NetConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a NAT configuration\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class FirewallNatConfig implements NetConfig {\n\n    /** The source interface (WAN interface) **/\n    private final String sourceInterface;\n\n    /** The destination interface (LAN interface) **/\n    private final String destinationInterface;\n\n    /** protocol (i.e. all, tcp, udp) */\n    private final String protocol;\n\n    /** source network/host in CIDR notation */\n    private final String source;\n\n    /** destination network/host in CIDR notation */\n    private final String destination;\n\n    /** Whether or not MASQUERADE should be enabled **/\n    private final boolean masquerade;\n\n    /**\n     * Represent the type of the rule\n     * \n     * @since 2.2\n     */\n    private final RuleType type;\n\n    /**\n     * \n     * @deprecated since version 2.2. It will be removed in the next major release. Use instead\n     *             {@link #FirewallNatConfig(String, String, String, String, String, boolean, RuleType)}\n     */\n    @Deprecated\n    public FirewallNatConfig(String srcIface, String dstIface, String protocol, String src, String dst,\n            boolean masquerade) {\n        this.sourceInterface = srcIface;\n        this.destinationInterface = dstIface;\n        this.protocol = protocol;\n        this.source = src;\n        this.destination = dst;\n        this.masquerade = masquerade;\n        this.type = RuleType.GENERIC;\n    }\n\n    /**\n     * \n     * Create a configuration for a NAT rule\n     * \n     * @param srcIface\n     *            the source network interface (WAN interface)\n     * @param dstIface\n     *            the destination network interface (LAN interface)\n     * @param protocol\n     *            the network protocol (i.e. tcp, udp)\n     * @param src\n     *            the source network/host address in CIDR notation\n     * @param dst\n     *            the destination network/host address in CIDR notation\n     * @param masquerade\n     *            whether or not MASQUERADE should be enabled\n     * @param type\n     *            the type of the rule (IP forwarding, Port forwarding or generic)\n     * \n     * @since 2.2\n     */\n    public FirewallNatConfig(String srcIface, String dstIface, String protocol, String src, String dst,\n            boolean masquerade, RuleType type) {\n        this.sourceInterface = srcIface;\n        this.destinationInterface = dstIface;\n        this.protocol = protocol;\n        this.source = src;\n        this.destination = dst;\n        this.masquerade = masquerade;\n        this.type = type;\n    }\n\n    public String getSourceInterface() {\n        return this.sourceInterface;\n    }\n\n    public String getDestinationInterface() {\n        return this.destinationInterface;\n    }\n\n    public String getProtocol() {\n        return this.protocol;\n    }\n\n    public String getSource() {\n        return this.source;\n    }\n\n    public String getDestination() {\n        return this.destination;\n    }\n\n    public boolean isMasquerade() {\n        return this.masquerade;\n    }\n\n    /**\n     * \n     * @since 2.2\n     */\n    public RuleType getRuleType() {\n        return this.type;\n    }\n\n    @Override\n    public boolean isValid() {\n        boolean result = false;\n        if (this.destinationInterface != null && !this.destinationInterface.trim().isEmpty()\n                && this.sourceInterface != null && !this.sourceInterface.trim().isEmpty()) {\n            result = true;\n        }\n\n        return result;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.destinationInterface == null ? 0 : this.destinationInterface.hashCode());\n        result = prime * result + (this.sourceInterface == null ? 0 : this.sourceInterface.hashCode());\n        result = prime * result + (this.protocol == null ? 0 : this.protocol.hashCode());\n        result = prime * result + (this.source == null ? 0 : this.source.hashCode());\n        result = prime * result + (this.destination == null ? 0 : this.destination.hashCode());\n        result = prime * result + (this.masquerade ? 1231 : 1237);\n        result = prime * result + (this.type == null ? 0 : this.type.hashCode());\n\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        FirewallNatConfig other = (FirewallNatConfig) obj;\n\n        if (this.masquerade != other.masquerade) {\n            return false;\n        }\n\n        if (this.sourceInterface == null) {\n            if (other.sourceInterface != null) {\n                return false;\n            }\n        } else if (!this.sourceInterface.equals(other.sourceInterface)) {\n            return false;\n        } else if (!this.protocol.equals(other.protocol)) {\n            return false;\n        }\n\n        if (this.destinationInterface == null) {\n            if (other.destinationInterface != null) {\n                return false;\n            }\n        } else if (!this.destinationInterface.equals(other.destinationInterface)) {\n            return false;\n        }\n\n        if (this.source == null) {\n            if (other.source != null) {\n                return false;\n            }\n        } else if (!this.source.equals(other.source)) {\n            return false;\n        }\n\n        if (this.destination == null) {\n            if (other.destination != null) {\n                return false;\n            }\n        } else if (!this.destination.equals(other.destination)) {\n            return false;\n        }\n\n        if (this.type == null) {\n            if (other.type != null) {\n                return false;\n            }\n        } else if (!this.type.equals(other.type)) {\n            return false;\n        }\n\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"FirewallNatConfig [m_sourceInterface=\");\n        builder.append(this.sourceInterface);\n        builder.append(\", destinationInterface=\");\n        builder.append(this.destinationInterface);\n        builder.append(\", source=\");\n        builder.append(this.source);\n        builder.append(\", destination=\");\n        builder.append(this.destination);\n        builder.append(\", type=\");\n        builder.append(this.type);\n        builder.append(\"]\");\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetConfig;\nimport org.eclipse.kura.net.NetProtocol;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for firewall open port configurations\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface FirewallOpenPortConfig extends NetConfig {\n\n    /**\n     * Gets the port that is open for inbound connections\n     *\n     * @return The port number representing the inbound network port\n     */\n    public int getPort();\n\n    /**\n     * Gets range of ports that are open for inbound connections\n     *\n     * @return The port range representing the inbound network port\n     */\n    public String getPortRange();\n\n    /**\n     * Gets the type of network protocol (TCP or UDP) that is open for inbound connections\n     *\n     * @return The NetProtocol type associated with this interface\n     */\n    public NetProtocol getProtocol();\n\n    /**\n     * Gets the (optional) permitted remote network that can make inbound connections\n     *\n     * @return The NetworkPair representing the permitted network\n     */\n    public NetworkPair<? extends IPAddress> getPermittedNetwork();\n\n    /**\n     * Gets the (optional) permitted remote network that can make inbound connections in CIDR notation (i.e.\n     * 192.168.0.0/24 or 2001:db8::/32)\n     *\n     * @return The NetworkPair representing the permitted network\n     * @since 2.6\n     */\n    public String getPermittedNetworkString();\n\n    /**\n     * Gets the (optional) permitted MAC address that is allowed to make inbound connections\n     *\n     * @return The MAC address that is allowed to make inbound connections\n     */\n    public String getPermittedMac();\n\n    /**\n     * Gets the (optional) permitted source port range that is allowed to make inbound connections\n     *\n     * @return The source port range that is allowed to make inbound connections\n     */\n    public String getSourcePortRange();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfig4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv4 firewall open port configurations\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface FirewallOpenPortConfig4 extends FirewallOpenPortConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfig6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv6 firewall open port configurations\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.6\n */\n@ProviderType\npublic interface FirewallOpenPortConfig6 extends FirewallOpenPortConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfigIP.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport java.net.UnknownHostException;\nimport java.util.Objects;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetProtocol;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The base class for firewall open port configurations\n *\n * @param <T>\n *            the type of IPAddess\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic abstract class FirewallOpenPortConfigIP<T extends IPAddress> implements FirewallOpenPortConfig {\n\n    /** The port to open for inbound connections **/\n    private int port;\n\n    /** Range of ports to open for inbound connections **/\n    private String portRange;\n\n    /** The type of protocol to allow for inbound connections **/\n    private NetProtocol protocol;\n\n    /** The (optional) permitted network for inbound connections **/\n    private NetworkPair<T> permittedNetwork;\n\n    /** The (optional) permitted interface name for inbound connections **/\n    private String permittedInterfaceName;\n\n    /** The (optional) not permitted interface name for inbound connections **/\n    private String unpermittedInterfaceName;\n\n    /** The (optional) permitted MAC address for inbound connections **/\n    private String permittedMac;\n\n    /** The (options) permitted source port range for inbound connections **/\n    private String sourcePortRange;\n\n    /**\n     * Creates and empty open port configuration\n     * \n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public FirewallOpenPortConfigIP() {\n        super();\n    }\n\n    /**\n     * Creates a complete Open Port configuration\n     *\n     * @param portRange\n     *            The range of ports to open for inbound connections\n     * @param protocol\n     *            The type of protocol to allow for inbound connections\n     * @param permittedNetwork\n     *            The (optional) permitted network for inbound connections\n     * @param permittedInterfaceName\n     *            The (optional) permitted interface name for inbound connections\n     * @param unpermittedInterfaceName\n     *            The (optional) not permitted interface name for inbound connections\n     * @param permittedMac\n     *            The (optional) permitted MAC address for inbound connections\n     * @param sourcePortRange\n     *            The (optional) permitted source port range for inbound connections\n     * \n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public FirewallOpenPortConfigIP(int port, NetProtocol protocol, NetworkPair<T> permittedNetwork,\n            String permittedInterfaceName, String unpermittedInterfaceName, String permittedMac,\n            String sourcePortRange) {\n        super();\n        this.port = port;\n        this.portRange = null;\n        this.protocol = protocol;\n        this.permittedNetwork = permittedNetwork;\n        this.permittedInterfaceName = permittedInterfaceName;\n        this.unpermittedInterfaceName = unpermittedInterfaceName;\n        this.permittedMac = permittedMac;\n        this.sourcePortRange = sourcePortRange;\n    }\n\n    /**\n     * Creates a complete Open Port configuration\n     *\n     * @param port\n     *            The port to open for inbound connections\n     * @param protocol\n     *            The type of protocol to allow for inbound connections\n     * @param permittedNetwork\n     *            The (optional) permitted network for inbound connections\n     * @param permittedInterfaceName\n     *            The (optional) permitted interface name for inbound connections\n     * @param unpermittedInterfaceName\n     *            The (optional) not permitted interface name for inbound connections\n     * @param permittedMac\n     *            The (optional) permitted MAC address for inbound connections\n     * @param sourcePortRange\n     *            The (options) permitted source port range for inbound connections\n     * \n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public FirewallOpenPortConfigIP(String portRange, NetProtocol protocol, NetworkPair<T> permittedNetwork,\n            String permittedInterfaceName, String unpermittedInterfaceName, String permittedMac,\n            String sourcePortRange) {\n        super();\n        this.portRange = portRange;\n        this.port = -1;\n        this.protocol = protocol;\n        this.permittedNetwork = permittedNetwork;\n        this.permittedInterfaceName = permittedInterfaceName;\n        this.unpermittedInterfaceName = unpermittedInterfaceName;\n        this.permittedMac = permittedMac;\n        this.sourcePortRange = sourcePortRange;\n    }\n\n    protected FirewallOpenPortConfigIP(FirewallOpenPortConfigIPBuilder<T, ?> builder) {\n        this.portRange = builder.portRange;\n        this.port = builder.port;\n        this.protocol = builder.protocol;\n        this.permittedNetwork = builder.permittedNetwork;\n        this.permittedInterfaceName = builder.permittedInterfaceName;\n        this.unpermittedInterfaceName = builder.unpermittedInterfaceName;\n        this.permittedMac = builder.permittedMac;\n        this.sourcePortRange = builder.sourcePortRange;\n    }\n\n    @Override\n    public int getPort() {\n        return this.port;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public void setPort(int port) {\n        this.port = port;\n    }\n\n    @Override\n    public String getPortRange() {\n        return this.portRange;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public void setPortRange(String portRange) {\n        this.portRange = portRange;\n    }\n\n    @Override\n    public NetProtocol getProtocol() {\n        return this.protocol;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public void setProtocol(NetProtocol protocol) {\n        this.protocol = protocol;\n    }\n\n    @Override\n    public NetworkPair<T> getPermittedNetwork() {\n        return this.permittedNetwork;\n    }\n\n    /**\n     * @since 2.6\n     */\n    @Override\n    public String getPermittedNetworkString() {\n        return this.permittedNetwork.getIpAddress().getHostAddress() + \"/\" + this.permittedNetwork.getPrefix();\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public void setPermittedNetwork(NetworkPair<T> permittedNetwork) {\n        this.permittedNetwork = permittedNetwork;\n    }\n\n    public String getPermittedInterfaceName() {\n        return this.permittedInterfaceName;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public void setPermittedInterfaceName(String permittedInterfaceName) {\n        this.permittedInterfaceName = permittedInterfaceName;\n    }\n\n    public String getUnpermittedInterfaceName() {\n        return this.unpermittedInterfaceName;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public void setUnpermittedInterfaceName(String unpermittedInterfaceName) {\n        this.unpermittedInterfaceName = unpermittedInterfaceName;\n    }\n\n    @Override\n    public String getPermittedMac() {\n        return this.permittedMac;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public void setPermittedMac(String permittedMac) {\n        this.permittedMac = permittedMac;\n    }\n\n    @Override\n    public String getSourcePortRange() {\n        return this.sourcePortRange;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder\n     */\n    @Deprecated\n    public void setSourcePortRange(String sourcePortRange) {\n        this.sourcePortRange = sourcePortRange;\n    }\n\n    /**\n     * The base builder class for firewall open port configurations\n     * \n     * @since 2.6\n     */\n    @ProviderType\n    public abstract static class FirewallOpenPortConfigIPBuilder<U extends IPAddress, T extends FirewallOpenPortConfigIPBuilder<U, T>> {\n\n        protected int port = -1;\n        protected String portRange;\n        protected NetProtocol protocol;\n        protected NetworkPair<U> permittedNetwork;\n        protected String permittedInterfaceName;\n        protected String unpermittedInterfaceName;\n        protected String permittedMac;\n        protected String sourcePortRange;\n\n        public T withPort(int port) {\n            this.port = port;\n            return getThis();\n        }\n\n        public T withPortRange(String portRange) {\n            this.portRange = portRange;\n            return getThis();\n        }\n\n        public T withProtocol(NetProtocol protocol) {\n            this.protocol = protocol;\n            return getThis();\n        }\n\n        public T withPermittedNetwork(NetworkPair<U> permittedNetwork) {\n            this.permittedNetwork = permittedNetwork;\n            return getThis();\n        }\n\n        public T withPermittedInterfaceName(String permittedInterfaceName) {\n            this.permittedInterfaceName = permittedInterfaceName;\n            return getThis();\n        }\n\n        public T withUnpermittedInterfaceName(String unpermittedInterfaceName) {\n            this.unpermittedInterfaceName = unpermittedInterfaceName;\n            return getThis();\n        }\n\n        public T withPermittedMac(String permittedMac) {\n            this.permittedMac = permittedMac;\n            return getThis();\n        }\n\n        public T withSourcePortRange(String sourcePortRange) {\n            this.sourcePortRange = sourcePortRange;\n            return getThis();\n        }\n\n        public abstract T getThis();\n\n        public abstract FirewallOpenPortConfigIP<U> build() throws UnknownHostException;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(permittedInterfaceName, permittedMac, permittedNetwork, port, portRange, protocol,\n                sourcePortRange, unpermittedInterfaceName);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        FirewallOpenPortConfigIP<?> other = (FirewallOpenPortConfigIP<?>) obj;\n        return Objects.equals(permittedInterfaceName, other.permittedInterfaceName)\n                && Objects.equals(permittedMac, other.permittedMac)\n                && Objects.equals(permittedNetwork, other.permittedNetwork) && port == other.port\n                && Objects.equals(portRange, other.portRange) && protocol == other.protocol\n                && Objects.equals(sourcePortRange, other.sourcePortRange)\n                && Objects.equals(unpermittedInterfaceName, other.unpermittedInterfaceName);\n    }\n\n    @Override\n    public boolean isValid() {\n        if (this.port < 0 || this.port > 65535) {\n            return false;\n        }\n\n        if (this.protocol == null || !this.protocol.equals(NetProtocol.tcp) || !this.protocol.equals(NetProtocol.udp)) {\n            return false;\n        }\n\n        // TODO - add checks for optional parameters to make sure if they are not null they are valid\n\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"FirewallOpenPortConfigIP [port=\");\n        builder.append(this.port);\n        builder.append(\", portRange=\");\n        builder.append(this.portRange);\n        builder.append(\", protocol=\");\n        builder.append(this.protocol);\n        builder.append(\", permittedNetwork=\");\n        builder.append(this.permittedNetwork);\n        builder.append(\", permittedMac=\");\n        builder.append(this.permittedMac);\n        builder.append(\", sourcePortRange=\");\n        builder.append(this.sourcePortRange);\n        builder.append(\"]\");\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfigIP4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport java.net.UnknownHostException;\n\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.NetProtocol;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The implementation of IPv4 firewall open port configurations\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class FirewallOpenPortConfigIP4 extends FirewallOpenPortConfigIP<IP4Address> implements FirewallOpenPortConfig4 {\n\n    /**\n     * @deprecated since 2.6. Use {@link FirewallOpenPortConfigIP4.builder()}\n     */\n    @Deprecated\n    public FirewallOpenPortConfigIP4() {\n        super();\n    }\n\n    /**\n     * @deprecated since 2.6. Use {@link FirewallOpenPortConfigIP4.builder()}\n     */\n    @Deprecated\n    public FirewallOpenPortConfigIP4(int port, NetProtocol protocol, NetworkPair<IP4Address> permittedNetwork,\n            String permittedInterfaceName, String unpermittedInterfaceName, String permittedMac,\n            String sourcePortRange) {\n        super(port, protocol, permittedNetwork, permittedInterfaceName, unpermittedInterfaceName, permittedMac,\n                sourcePortRange);\n    }\n\n    /**\n     * @deprecated since 2.6. Use {@link FirewallOpenPortConfigIP4.builder()}\n     */\n    @Deprecated\n    public FirewallOpenPortConfigIP4(String portRange, NetProtocol protocol, NetworkPair<IP4Address> permittedNetwork,\n            String permittedInterfaceName, String unpermittedInterfaceName, String permittedMac,\n            String sourcePortRange) {\n        super(portRange, protocol, permittedNetwork, permittedInterfaceName, unpermittedInterfaceName, permittedMac,\n                sourcePortRange);\n    }\n\n    private FirewallOpenPortConfigIP4(FirewallOpenPortConfigIP4Builder builder) {\n        super(builder);\n    }\n\n    /**\n     * Return the builder for the IPv4 firewall open port configuration\n     * \n     * @since 2.6\n     */\n    public static FirewallOpenPortConfigIP4Builder builder() {\n        return new FirewallOpenPortConfigIP4Builder();\n    }\n\n    /**\n     * The builder class for the IPv4 firewall open port configuration\n     * \n     * @since 2.6\n     */\n    @ProviderType\n    public static class FirewallOpenPortConfigIP4Builder\n            extends FirewallOpenPortConfigIPBuilder<IP4Address, FirewallOpenPortConfigIP4Builder> {\n\n        /**\n         * Builds a new IPv4 firewall open port configuration\n         */\n        @Override\n        public FirewallOpenPortConfigIP4 build() throws UnknownHostException {\n            if (this.permittedNetwork == null) {\n                this.withPermittedNetwork(new NetworkPair<>(IP4Address.getDefaultAddress(), (short) 0));\n            }\n            return new FirewallOpenPortConfigIP4(this);\n        }\n\n        @Override\n        public FirewallOpenPortConfigIP4Builder getThis() {\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfigIP6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport java.net.UnknownHostException;\n\nimport org.eclipse.kura.net.IP6Address;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The implementation of IPv6 firewall open port configurations\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.6\n */\n@ProviderType\npublic class FirewallOpenPortConfigIP6 extends FirewallOpenPortConfigIP<IP6Address> implements FirewallOpenPortConfig6 {\n\n    private FirewallOpenPortConfigIP6(FirewallOpenPortConfigIP6Builder builder) {\n        super(builder);\n    }\n\n    public static FirewallOpenPortConfigIP6Builder builder() {\n        return new FirewallOpenPortConfigIP6Builder();\n    }\n\n    /**\n     * The builder class for the IPv6 firewall open port configuration\n     */\n    @ProviderType\n    public static class FirewallOpenPortConfigIP6Builder\n            extends FirewallOpenPortConfigIPBuilder<IP6Address, FirewallOpenPortConfigIP6Builder> {\n\n        /**\n         * Builds a new IPv6 firewall open port configuration\n         */\n        @Override\n        public FirewallOpenPortConfigIP6 build() throws UnknownHostException {\n            if (this.permittedNetwork == null) {\n                this.withPermittedNetwork(new NetworkPair<>(IP6Address.getDefaultAddress(), (short) 0));\n            }\n            return new FirewallOpenPortConfigIP6(this);\n        }\n\n        @Override\n        public FirewallOpenPortConfigIP6Builder getThis() {\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetConfig;\nimport org.eclipse.kura.net.NetProtocol;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for firewall port forward configurations\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface FirewallPortForwardConfig extends NetConfig {\n\n    /**\n     * The external (WAN) interface to listen for inbound connections on\n     *\n     * @return The interface name used for this port forward configuration\n     */\n    public String getInboundInterface();\n\n    /**\n     * The internal (LAN) interface packets will be forwarded to\n     *\n     * @return The interface name used for this port forward configuration\n     */\n    public String getOutboundInterface();\n\n    /**\n     * The LAN IP address to forward connections to\n     *\n     * @return The LAN IPAddress to forward connections to\n     * @deprecated since 2.6. Use {@link FirewallPortForwardConfig#getIPAddress}\n     */\n    @Deprecated\n    public IP4Address getAddress();\n\n    /**\n     * The LAN IP address to forward connections to\n     *\n     * @return The LAN IPAddress to forward connections to\n     * @since 2.6\n     */\n    public IPAddress getIPAddress();\n\n    /**\n     * The netmask of the LAN IP address to forward connections to\n     *\n     * @return The netmask of the LAN IPAddress to forward connections to\n     * @since 2.6\n     */\n    public short getIPAddressNetmask();\n\n    /**\n     * Gets the type of network protocol (TCP or UDP) that is used for this configuration\n     *\n     * @return The NetProtocol type associated with this interface\n     */\n    public NetProtocol getProtocol();\n\n    /**\n     * The inbound (WAN) port to use for this configuration\n     *\n     * @return The WAN port number\n     */\n    public int getInPort();\n\n    /**\n     * The outbound (LAN) port to use for this configuration\n     *\n     * @return The LAN port number\n     */\n    public int getOutPort();\n\n    /**\n     * Use masquerading\n     *\n     * @return boolean\n     */\n    public boolean isMasquerade();\n\n    /**\n     * Gets the (optional) permitted remote network that can make inbound connections\n     *\n     * @return The NetworkPair representing the permitted network\n     */\n    public NetworkPair<? extends IPAddress> getPermittedNetwork();\n\n    /**\n     * Gets the (optional) permitted MAC address that is allowed to make inbound connections\n     *\n     * @return The MAC address that is allowed to make inbound connections\n     */\n    public String getPermittedMac();\n\n    /**\n     * Gets the (optional) permitted source port range that is allowed to make inbound connections\n     *\n     * @return The source port range that is allowed to make inbound connections\n     */\n    public String getSourcePortRange();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfig4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv4 firewall port forward configurations\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface FirewallPortForwardConfig4 extends FirewallPortForwardConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfig6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv6 firewall port forward configurations\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.6\n */\n@ProviderType\npublic interface FirewallPortForwardConfig6 extends FirewallPortForwardConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfigIP.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport java.net.UnknownHostException;\n\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetProtocol;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The base class for firewall port forward configurations\n *\n * @param <T>\n *            the type of IPAddess\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic abstract class FirewallPortForwardConfigIP<T extends IPAddress> implements FirewallPortForwardConfig {\n\n    /** The interface name on which this configuration will listen for inbound connections **/\n    private String inboundIface;\n\n    /** The interface name on which packet will be forwarded */\n    private String outboundIface;\n\n    /** The LAN address to forward to **/\n    private T address;\n\n    /** The protocol (TCP or UDP) to listen for and forward **/\n    private NetProtocol protocol;\n\n    /** The inbound (WAN) port to listen on **/\n    private int inPort;\n\n    /** The outbound (LAN) port to listen on **/\n    private int outPort;\n\n    /** use masquerading */\n    private boolean masquerade;\n\n    /** The (optional) permitted network for inbound connections **/\n    private NetworkPair<T> permittedNetwork;\n\n    /** The (optional) permitted MAC address for inbound connections **/\n    private String permittedMac;\n\n    /** The (options) permitted source port range for inbound connections **/\n    private String sourcePortRange;\n\n    /**\n     * Creates and empty port forward configuration\n     * \n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public FirewallPortForwardConfigIP() {\n        super();\n    }\n\n    /**\n     * Creates a complete port forward configuration\n     *\n     * @param inboundIface\n     *            The interface name on which this configuration will listen for inbound connections\n     * @param outboundIface\n     *            The inetrface name on which packet will be forwarded\n     * @param address\n     *            The LAN address to forward to\n     * @param protocol\n     *            The protocol (TCP or UDP) to listen for and forward\n     * @param inPort\n     *            The inbound (WAN) port to listen on\n     * @param outPort\n     *            The outbound (LAN) port to listen on\n     * @param masquerade\n     *            Use masquerade\n     * @param permittedNetwork\n     *            The (optional) permitted network for inbound connections\n     * @param permittedMac\n     *            The (optional) permitted MAC address for inbound connections\n     * @param sourcePortRange\n     *            The (options) permitted source port range for inbound connections\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    @Deprecated\n    public FirewallPortForwardConfigIP(String inboundIface, String outboundIface, IP4Address address,\n            NetProtocol protocol, int inPort, int outPort, boolean masquerade, NetworkPair<T> permittedNetwork,\n            String permittedMac, String sourcePortRange) {\n        super();\n        this.inboundIface = inboundIface;\n        this.outboundIface = outboundIface;\n        this.address = (T) address;\n        this.protocol = protocol;\n        this.inPort = inPort;\n        this.outPort = outPort;\n        this.masquerade = masquerade;\n        this.permittedNetwork = permittedNetwork;\n        this.permittedMac = permittedMac;\n        this.sourcePortRange = sourcePortRange;\n    }\n\n    protected FirewallPortForwardConfigIP(FirewallPortForwardConfigIPBuilder<T, ?> builder) {\n        this.inboundIface = builder.inboundIface;\n        this.outboundIface = builder.outboundIface;\n        this.address = builder.address;\n        this.protocol = builder.protocol;\n        this.inPort = builder.inPort;\n        this.outPort = builder.outPort;\n        this.masquerade = builder.masquerade;\n        this.permittedNetwork = builder.permittedNetwork;\n        this.permittedMac = builder.permittedMac;\n        this.sourcePortRange = builder.sourcePortRange;\n    }\n\n    @Override\n    public String getInboundInterface() {\n        return this.inboundIface;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setInboundInterface(String interfaceName) {\n        this.inboundIface = interfaceName;\n    }\n\n    @Override\n    public String getOutboundInterface() {\n        return this.outboundIface;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setOutboundInterface(String interfaceName) {\n        this.outboundIface = interfaceName;\n    }\n\n    /**\n     * @deprecated since 2.6. Use {@link getIPAddress}\n     */\n    @Override\n    @Deprecated\n    public IP4Address getAddress() {\n        return (IP4Address) this.address;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setAddress(IP4Address address) {\n        this.address = (T) address;\n    }\n\n    /**\n     * @since 2.6\n     */\n    @Override\n    public T getIPAddress() {\n        return this.address;\n    }\n\n    @Override\n    public NetProtocol getProtocol() {\n        return this.protocol;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setProtocol(NetProtocol protocol) {\n        this.protocol = protocol;\n    }\n\n    @Override\n    public int getInPort() {\n        return this.inPort;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setInPort(int inPort) {\n        this.inPort = inPort;\n    }\n\n    @Override\n    public int getOutPort() {\n        return this.outPort;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setOutPort(int outPort) {\n        this.outPort = outPort;\n    }\n\n    @Override\n    public boolean isMasquerade() {\n        return this.masquerade;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setMasquerade(boolean masquerade) {\n        this.masquerade = masquerade;\n    }\n\n    @Override\n    public NetworkPair<T> getPermittedNetwork() {\n        return this.permittedNetwork;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setPermittedNetwork(NetworkPair<T> permittedNetwork) {\n        this.permittedNetwork = permittedNetwork;\n    }\n\n    @Override\n    public String getPermittedMac() {\n        return this.permittedMac;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setPermittedMac(String permittedMac) {\n        this.permittedMac = permittedMac;\n    }\n\n    @Override\n    public String getSourcePortRange() {\n        return this.sourcePortRange;\n    }\n\n    /**\n     * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder\n     */\n    @Deprecated\n    public void setSourcePortRange(String sourcePortRange) {\n        this.sourcePortRange = sourcePortRange;\n    }\n\n    /**\n     * The base builder class for firewall port forward configurations\n     * \n     * @since 2.6\n     */\n    @ProviderType\n    public abstract static class FirewallPortForwardConfigIPBuilder<U extends IPAddress, T extends FirewallPortForwardConfigIPBuilder<U, T>> {\n\n        protected String inboundIface;\n        protected String outboundIface;\n        protected U address;\n        protected NetProtocol protocol;\n        protected int inPort;\n        protected int outPort;\n        protected boolean masquerade = false;\n        protected NetworkPair<U> permittedNetwork;\n        protected String permittedMac;\n        protected String sourcePortRange;\n\n        public T withInboundIface(String inboundIface) {\n            this.inboundIface = inboundIface;\n            return getThis();\n        }\n\n        public T withOutboundIface(String outboundIface) {\n            this.outboundIface = outboundIface;\n            return getThis();\n        }\n\n        public T withAddress(U address) {\n            this.address = address;\n            return getThis();\n        }\n\n        public T withProtocol(NetProtocol protocol) {\n            this.protocol = protocol;\n            return getThis();\n        }\n\n        public T withInPort(int inPort) {\n            this.inPort = inPort;\n            return getThis();\n        }\n\n        public T withOutPort(int outPort) {\n            this.outPort = outPort;\n            return getThis();\n        }\n\n        public T withMasquerade(boolean masquerade) {\n            this.masquerade = masquerade;\n            return getThis();\n        }\n\n        public T withPermittedNetwork(NetworkPair<U> permittedNetwork) {\n            this.permittedNetwork = permittedNetwork;\n            return getThis();\n        }\n\n        public T withPermittedMac(String permittedMac) {\n            this.permittedMac = permittedMac;\n            return getThis();\n        }\n\n        public T withSourcePortRange(String sourcePortRange) {\n            this.sourcePortRange = sourcePortRange;\n            return getThis();\n        }\n\n        public abstract T getThis();\n\n        public abstract FirewallPortForwardConfigIP<U> build() throws UnknownHostException;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.address == null ? 0 : this.address.hashCode());\n        result = prime * result + this.inPort;\n        result = prime * result + (this.inboundIface == null ? 0 : this.inboundIface.hashCode());\n        result = prime * result + (this.outboundIface == null ? 0 : this.outboundIface.hashCode());\n        result = prime * result + (this.masquerade ? 1231 : 1237);\n        result = prime * result + this.outPort;\n        result = prime * result + (this.permittedMac == null ? 0 : this.permittedMac.hashCode());\n        result = prime * result + (this.permittedNetwork == null ? 0 : this.permittedNetwork.hashCode());\n        result = prime * result + (this.protocol == null ? 0 : this.protocol.hashCode());\n        result = prime * result + (this.sourcePortRange == null ? 0 : this.sourcePortRange.hashCode());\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"FirewallPortForwardConfigIP [inboundIface=\");\n        builder.append(this.inboundIface);\n        builder.append(\", outboundIface=\");\n        builder.append(this.outboundIface);\n        builder.append(\", address=\");\n        builder.append(this.address);\n        builder.append(\", protocol=\");\n        builder.append(this.protocol);\n        builder.append(\", inPort=\");\n        builder.append(this.inPort);\n        builder.append(\", outPort=\");\n        builder.append(this.outPort);\n        builder.append(\", permittedNetwork=\");\n        builder.append(this.permittedNetwork);\n        builder.append(\", permittedMac=\");\n        builder.append(this.permittedMac);\n        builder.append(\", sourcePortRange=\");\n        builder.append(this.sourcePortRange);\n        builder.append(\"]\");\n        return builder.toString();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        @SuppressWarnings(\"rawtypes\")\n        FirewallPortForwardConfigIP other = (FirewallPortForwardConfigIP) obj;\n        if (this.address == null) {\n            if (other.address != null) {\n                return false;\n            }\n        } else if (!this.address.equals(other.address)) {\n            return false;\n        }\n        if (this.inPort != other.inPort) {\n            return false;\n        }\n        if (this.inboundIface == null) {\n            if (other.inboundIface != null) {\n                return false;\n            }\n        } else if (!this.inboundIface.equals(other.inboundIface)) {\n            return false;\n        }\n        if (this.outboundIface == null) {\n            if (other.outboundIface != null) {\n                return false;\n            }\n        } else if (!this.outboundIface.equals(other.outboundIface)) {\n            return false;\n        }\n        if (this.outPort != other.outPort) {\n            return false;\n        }\n        if (this.masquerade != other.masquerade) {\n            return false;\n        }\n        if (this.permittedMac == null) {\n            if (other.permittedMac != null) {\n                return false;\n            }\n        } else if (!this.permittedMac.equals(other.permittedMac)) {\n            return false;\n        }\n        if (this.permittedNetwork == null) {\n            if (other.permittedNetwork != null) {\n                return false;\n            }\n        } else if (!this.permittedNetwork.equals(other.permittedNetwork)) {\n            return false;\n        }\n        if (this.protocol != other.protocol) {\n            return false;\n        }\n        if (this.sourcePortRange == null) {\n            if (other.sourcePortRange != null) {\n                return false;\n            }\n        } else if (!this.sourcePortRange.equals(other.sourcePortRange)) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public boolean isValid() {\n        if (this.inboundIface == null || this.inboundIface.trim().isEmpty()) {\n            return false;\n        }\n\n        if (this.outboundIface == null || this.outboundIface.trim().isEmpty()) {\n            return false;\n        }\n\n        if (this.address == null) {\n            return false;\n        }\n\n        if (this.inPort < 0 || this.inPort > 65535 || this.outPort < 0 || this.outPort > 65535) {\n            return false;\n        }\n\n        if (this.protocol == null || !this.protocol.equals(NetProtocol.tcp) || !this.protocol.equals(NetProtocol.udp)) {\n            return false;\n        }\n\n        // TODO - add checks for optional parameters to make sure if they are not null they are valid\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfigIP4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport java.net.UnknownHostException;\n\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.NetProtocol;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The class for IPv4 firewall port forward configurations\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class FirewallPortForwardConfigIP4 extends FirewallPortForwardConfigIP<IP4Address>\n        implements FirewallPortForwardConfig4 {\n\n    /**\n     * @deprecated since 2.6. Use {@link FirewallPortForwardConfigIP4.builder()}\n     */\n    @Deprecated\n    public FirewallPortForwardConfigIP4() {\n        super();\n    }\n\n    /**\n     * @deprecated since 2.6. Use {@link FirewallPortForwardConfigIP4.builder()}\n     */\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    @Deprecated\n    public FirewallPortForwardConfigIP4(String inboundIface, String outboundIface, IP4Address address,\n            NetProtocol protocol, int inPort, int outPort, boolean masquerade, NetworkPair<IP4Address> permittedNetwork,\n            String permittedMac, String sourcePortRange) {\n        super(inboundIface, outboundIface, address, protocol, inPort, outPort, masquerade, permittedNetwork,\n                permittedMac, sourcePortRange);\n    }\n\n    private FirewallPortForwardConfigIP4(FirewallPortForwardConfigIP4Builder builder) {\n        super(builder);\n    }\n\n    /**\n     * Return the builder for the IPv4 firewall port forward configuration\n     * \n     * @since 2.6\n     */\n    public static FirewallPortForwardConfigIP4Builder builder() {\n        return new FirewallPortForwardConfigIP4Builder();\n    }\n\n    /**\n     * @since 2.6\n     */\n    @Override\n    public short getIPAddressNetmask() {\n        return (short) 32;\n    }\n\n    /**\n     * The builder class for the IPv4 firewall port forward configuration\n     * \n     * @since 2.6\n     */\n    @ProviderType\n    public static class FirewallPortForwardConfigIP4Builder\n            extends FirewallPortForwardConfigIPBuilder<IP4Address, FirewallPortForwardConfigIP4Builder> {\n\n        /**\n         * Builds a new IPv4 firewall port forward configuration\n         */\n        @Override\n        public FirewallPortForwardConfigIP4 build() throws UnknownHostException {\n            if (this.permittedNetwork == null) {\n                this.withPermittedNetwork(new NetworkPair<>(IP4Address.getDefaultAddress(), (short) 0));\n            }\n            return new FirewallPortForwardConfigIP4(this);\n        }\n\n        @Override\n        public FirewallPortForwardConfigIP4Builder getThis() {\n            return this;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfigIP6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\nimport java.net.UnknownHostException;\n\nimport org.eclipse.kura.net.IP6Address;\nimport org.eclipse.kura.net.NetworkPair;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The implementation of IPv6 firewall port forward configurations\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.6\n */\n@ProviderType\npublic class FirewallPortForwardConfigIP6 extends FirewallPortForwardConfigIP<IP6Address>\n        implements FirewallPortForwardConfig6 {\n\n    private FirewallPortForwardConfigIP6(FirewallPortForwardConfigIP6Builder builder) {\n        super(builder);\n    }\n\n    public static FirewallPortForwardConfigIP6Builder builder() {\n        return new FirewallPortForwardConfigIP6Builder();\n    }\n\n    /**\n     * @since 2.6\n     */\n    @Override\n    public short getIPAddressNetmask() {\n        return (short) 128;\n    }\n\n    /**\n     * The builder class for the IPv6 firewall port forward configuration\n     */\n    @ProviderType\n    public static class FirewallPortForwardConfigIP6Builder\n            extends FirewallPortForwardConfigIPBuilder<IP6Address, FirewallPortForwardConfigIP6Builder> {\n\n        /**\n         * Builds a new IPv6 firewall port forward configuration\n         */\n        @Override\n        public FirewallPortForwardConfigIP6 build() throws UnknownHostException {\n            if (this.permittedNetwork == null) {\n                this.withPermittedNetwork(new NetworkPair<>(IP6Address.getDefaultAddress(), (short) 0));\n            }\n            return new FirewallPortForwardConfigIP6(this);\n        }\n\n        @Override\n        public FirewallPortForwardConfigIP6Builder getThis() {\n            return this;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/RuleType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.firewall;\n\n/**\n * Represents the type of NAT rule\n * \n * @since 2.2\n */\npublic enum RuleType {\n\n    PORT_FORWARDING,\n    IP_FORWARDING,\n    GENERIC;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Interfaces firewall configuration instances.\n *\n */\npackage org.eclipse.kura.net.firewall;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/CellularModem.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Sterwen-Technology\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.comm.CommURI;\nimport org.eclipse.kura.net.NetConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic interface CellularModem {\n\n    public enum SerialPortType {\n        DATAPORT,\n        ATPORT,\n        GPSPORT\n    }\n\n    /**\n     * Reports modem's model\n     *\n     * @return model, null if not known\n     */\n    public String getModel() throws KuraException;\n\n    /**\n     * Returns modem's manufacturer identification\n     *\n     * @return manufacturer, null if not known\n     */\n    public String getManufacturer() throws KuraException;\n\n    /**\n     * Answers modem's serial number (IMEI/MEID/ESN)\n     *\n     * @return serial number, null if not known\n     * @throws KuraException\n     */\n    public String getSerialNumber() throws KuraException;\n\n    /**\n     * Answers International Mobile Subscribe Identity (IMSI)\n     *\n     * @return IMSI number, null if not known\n     * @throws KuraException\n     * \n     * @deprecated since 2.4. Use {@link getMobileSubscriberIdentity(boolean\n     *             recompute)} instead.\n     */\n    @Deprecated\n    public String getMobileSubscriberIdentity() throws KuraException;\n\n    /**\n     * Answers Integrated Circuit Card Identification (ICCID)\n     *\n     * @return ICCID, \"N/A\" if not applicable\n     * @throws KuraException\n     * \n     * @deprecated since 2.4. Use {@link getIntegratedCirquitCardId(boolean\n     *             recompute)} instead.\n     */\n    @Deprecated\n    public String getIntegratedCirquitCardId() throws KuraException;\n\n    /**\n     * Reports modem's revision identification\n     *\n     * @return revision ID, null if not known\n     */\n    public String getRevisionID() throws KuraException;\n\n    /**\n     * Reports if Modem replies to the 'AT' command\n     *\n     * @return 'true' if AT reachable, 'false' otherwise\n     * @throws KuraException\n     */\n    public boolean isReachable() throws KuraException;\n\n    /**\n     * Reports if specified port can be opened\n     *\n     * @param port\n     *             - modem's serial port\n     * @return 'true' if port can be opened, 'false' otherwise\n     */\n    public boolean isPortReachable(String port);\n\n    /**\n     * resets the modem and tries to restore the state\n     * of the modem driver. (e.g. PPP connection, status thread)\n     *\n     * @throws KuraException\n     */\n    public void reset() throws KuraException;\n\n    /**\n     * Reports signal strength in dBm\n     *\n     * @throws KuraException\n     * @return signal strength\n     * \n     * @deprecated since 2.4. Use {@link getSignalStrength(boolean recompute)}\n     *             instead.\n     */\n    @Deprecated\n    public int getSignalStrength() throws KuraException;\n\n    /**\n     * Reports modem registration status\n     *\n     * @throws KuraException\n     * @return modem registration status as {@link ModemRegistrationStatus}\n     * \n     * @deprecated since 2.4. Use {@link getRegistrationStatus(boolean recompute)}\n     *             instead.\n     */\n    @Deprecated\n    public ModemRegistrationStatus getRegistrationStatus() throws KuraException;\n\n    /**\n     * Reports number of bytes transmitted during a call\n     *\n     * @return number of bytes transmitted\n     * @throws KuraException\n     */\n    public long getCallTxCounter() throws KuraException;\n\n    /**\n     * Reports number of bytes received during a call\n     *\n     * @return number of bytes received\n     * @throws KuraException\n     */\n    public long getCallRxCounter() throws KuraException;\n\n    /**\n     * Reports Service Type\n     *\n     * @throws KuraException\n     * @return service indication\n     */\n    public String getServiceType() throws KuraException;\n\n    /**\n     * Returns the associated UsbModemDevice\n     *\n     * @return <code>UsbModemDevice</code>\n     */\n    public ModemDevice getModemDevice();\n\n    /**\n     * @since 2.4\n     */\n    public String getLAC() throws KuraException;\n\n    /**\n     * @since 2.4\n     */\n    public String getCI() throws KuraException;\n\n    /**\n     * @since 2.4\n     */\n    public String getPLMNID() throws KuraException;\n\n    /**\n     * @since 2.4\n     */\n    public String getBand() throws KuraException;\n\n    /**\n     * @since 2.4\n     */\n    public String getNetworkName() throws KuraException;\n\n    /**\n     * @since 2.4\n     */\n    public String getRadio() throws KuraException;\n\n    public String getDataPort() throws KuraException;\n\n    public String getAtPort() throws KuraException;\n\n    public String getGpsPort() throws KuraException;\n\n    public CommURI getSerialConnectionProperties(SerialPortType portType) throws KuraException;\n\n    public boolean isGpsSupported() throws KuraException;\n\n    public boolean isGpsEnabled();\n\n    public void enableGps() throws KuraException;\n\n    public void disableGps() throws KuraException;\n\n    /**\n     * @since 2.2\n     */\n    public boolean hasDiversityAntenna();\n\n    /**\n     * @since 2.2\n     */\n    public boolean isDiversityEnabled();\n\n    /**\n     * @since 2.2\n     */\n    public void enableDiversity() throws KuraException;\n\n    /**\n     * @since 2.2\n     */\n    public void disableDiversity() throws KuraException;\n\n    public List<NetConfig> getConfiguration();\n\n    public void setConfiguration(List<NetConfig> netConfigs);\n\n    public List<ModemTechnologyType> getTechnologyTypes() throws KuraException;\n\n    /**\n     * @since 1.4\n     */\n    public List<ModemPdpContext> getPdpContextInfo() throws KuraException;\n\n    /**\n     * Return the firmware version of the modem module\n     * \n     * @return a string representing the firmware version\n     * \n     * @since 2.3\n     */\n    public String getFirmwareVersion() throws KuraException;\n\n    /**\n     * Reports signal strength in dBm\n     * \n     * @param recompute:\n     *                   if true the value is recomputed. Otherwise, a cached value\n     *                   is returned\n     * @return an integer representing the rssi\n     * @throws KuraException\n     * \n     * @since 2.4\n     */\n    public int getSignalStrength(boolean recompute) throws KuraException;\n\n    /**\n     * Reports modem registration status\n     *\n     * @param recompute:\n     *                   if true the value is recomputed. Otherwise, a cached value\n     *                   is returned\n     * @throws KuraException\n     * @return modem registration status as {@link ModemRegistrationStatus}\n     * \n     * @since 2.4\n     */\n    public ModemRegistrationStatus getRegistrationStatus(boolean recompute) throws KuraException;\n\n    /**\n     * Answers International Mobile Subscribe Identity (IMSI)\n     *\n     * @param recompute:\n     *                   if true the value is recomputed. Otherwise, a cached value\n     *                   is returned\n     * @return IMSI number, null if not known\n     * @throws KuraException\n     * \n     * @since 2.4\n     */\n    public String getMobileSubscriberIdentity(boolean recompute) throws KuraException;\n\n    /**\n     * Answers Integrated Circuit Card Identification (ICCID)\n     *\n     * @param recompute:\n     *                   if true the value is recomputed. Otherwise, a cached value\n     *                   is returned\n     * @return ICCID, \"N/A\" if not applicable\n     * @throws KuraException\n     * \n     * @since 2.4\n     */\n    public String getIntegratedCirquitCardId(boolean recompute) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemAddedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * Emitted when a modem is inserted into the gateway\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class ModemAddedEvent extends Event {\n\n    /** Topic of the ModemAddedEvent */\n    public static final String MODEM_EVENT_ADDED_TOPIC = \"org/eclipse/kura/net/modem/ADDED\";\n\n    ModemDevice modemDevice;\n\n    public ModemAddedEvent(ModemDevice modemDevice) {\n        super(MODEM_EVENT_ADDED_TOPIC, (Map<String, ?>) null);\n\n        this.modemDevice = modemDevice;\n    }\n\n    public ModemDevice getModemDevice() {\n        return this.modemDevice;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemCdmaServiceProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\n/**\n * @deprecated since 3.0\n */\n@Deprecated\npublic enum ModemCdmaServiceProvider {\n\n    UNKNOWN(0),\n    SPRINT(1),\n    AERIS(2),\n    VERIZON(3);\n\n    private int provider;\n\n    private ModemCdmaServiceProvider(int provider) {\n        this.provider = provider;\n    }\n\n    public int getProvider() {\n        return this.provider;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.Arrays;\nimport java.util.Objects;\n\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Modem configuration representation\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class ModemConfig implements NetConfig {\n\n    /**\n     * Configuration for a cellular modem.\n     */\n    public enum PdpType {\n        IP,\n        PPP,\n        IPv6,\n        UNKNOWN\n    }\n\n    public enum AuthType {\n        NONE,\n        AUTO,\n        PAP,\n        CHAP\n    }\n\n    private boolean enabled = false;\n    private String dialString = \"\";\n    private int pppNumber = 0;\n    private int profileID = 0;\n    private PdpType pdpType = PdpType.IP;\n    private AuthType authType = AuthType.NONE;\n    private String apn = \"\";\n    private String username = \"\";\n    private Password password = new Password(\"\");\n    private boolean persist = false;\n    private int holdoff = 1;\n    private int maxFail = 0;\n    private int idle = 0;\n    private String activeFilter = \"\";\n    private int lcpEchoInterval = 0;\n    private int lcpEchoFailure = 0;\n    private IPAddress ipAddress = null;\n    private int dataCompression = 0; // FIXME: change to enum?\n    private int headerCompression = 0; // FIXME: change to enum?\n    private boolean gpsEnabled = false;\n    private boolean diversityEnabled = false;\n    private int resetTimeout = 0;\n\n    /**\n     * Empty constructor\n     */\n    public ModemConfig() {\n    }\n\n    /**\n     * PDP config constructor\n     *\n     * @param apn\n     *            - access point name as {@link String}\n     * @param ipAddress\n     *            - IP address as {@link String}\n     * @param profileID\n     *            - PDP profile ID as {@link int}\n     * @param pdpType\n     *            - PDP type as {@link PdpType}\n     * @param dataCompression\n     *            - PDP data compression as {@link int}\n     * @param headerCompresion\n     *            - PDP header compression as {@link int}\n     */\n    public ModemConfig(int profileID, PdpType pdpType, String apn, IPAddress ipAddress, int dataCompression,\n            int headerCompresion) {\n\n        this.profileID = profileID;\n        this.pdpType = pdpType;\n        this.apn = apn;\n        this.ipAddress = ipAddress;\n        this.dataCompression = dataCompression;\n        this.headerCompression = headerCompresion;\n    }\n\n    /**\n     * Reports whether it is enabled.\n     *\n     * @return is enabled as {@link boolean}\n     */\n    public boolean isEnabled() {\n        return this.enabled;\n    }\n\n    /**\n     * Sets the enabled setting.\n     *\n     * @param enabled\n     *            - enabled status as {@link boolean}\n     */\n    public void setEnabled(boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    /**\n     * Gets the dial string.\n     *\n     * @return dial string as {@link String}\n     */\n    public String getDialString() {\n        return this.dialString;\n    }\n\n    /**\n     * Sets the dial string.\n     *\n     * @param dialString\n     *            - dial string as {@link String}\n     */\n    public void setDialString(String dialString) {\n        this.dialString = dialString;\n    }\n\n    /**\n     * Reports authentication type.\n     *\n     * @return authentication type as {@link AuthType}\n     */\n    public AuthType getAuthType() {\n        return this.authType;\n    }\n\n    /**\n     * Sets authentication type.\n     *\n     * @param authType\n     *            - authentication type as {@link AuthType}\n     */\n    public void setAuthType(AuthType authType) {\n        this.authType = authType;\n    }\n\n    /**\n     * Reports user name.\n     *\n     * @return user name as {@link String}\n     */\n    public String getUsername() {\n        return this.username;\n    }\n\n    /**\n     * Sets user name.\n     *\n     * @param username\n     *            - user name as {@link String}\n     */\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    /**\n     * Reports password.\n     *\n     * @return password as {@link String}\n     * @deprecated\n     */\n    @Deprecated\n    public String getPassword() {\n        return this.password.toString();\n    }\n\n    /**\n     * Reports password.\n     *\n     * @return password as {@link Password}\n     * @since 1.3\n     */\n    public Password getPasswordAsPassword() {\n        return this.password;\n    }\n\n    /**\n     * Sets password.\n     *\n     * @param password\n     *            - password as {@link String}\n     */\n    public void setPassword(String password) {\n        this.password = new Password(password);\n    }\n\n    /**\n     * Sets password.\n     *\n     * @param password\n     *            - password as {@link Password}\n     * @since 1.3\n     */\n    public void setPassword(Password password) {\n        this.password = password;\n    }\n\n    /**\n     * Reports if pppd is instructed to exit after a connection is terminated.\n     *\n     * @return 'persist' flag {@link boolean}\n     */\n    public boolean isPersist() {\n        return this.persist;\n    }\n\n    /**\n     * Sets 'persist' flag to instruct pppd if it needs to exit after a connection is terminated.\n     *\n     * @param persist\n     *            as {@link boolean}\n     */\n    public void setPersist(boolean persist) {\n        this.persist = persist;\n    }\n\n    /**\n     * Returns the 'holdoff' parameter that instruct pppd on how many seconds to wait before re-initiating the link\n     * after it terminates. This option only has any effect if the persist or demand option is used. The holdoff period\n     * is not\n     * applied if the link was terminated because it was idle.\n     *\n     * @return 'holdoff' parameter {@link integer}\n     * @since 2.5\n     */\n    public int getHoldoff() {\n        return this.holdoff;\n    }\n\n    /**\n     * Sets 'holdoff' parameter to instruct pppd on how many seconds to wait before re-initiating the link after it\n     * terminates. This option only has any effect if the persist or demand option is used. The holdoff period is not\n     * applied if the link was terminated because it was idle.\n     *\n     * @param holdoff\n     *            as {@link integer}\n     * @since 2.5\n     */\n    public void setHoldoff(int holdoff) {\n        this.holdoff = holdoff;\n    }\n\n    /**\n     * Reports maximum number of failed connection attempts.\n     *\n     * @return maximum number of failed connection attempts as {@link int}\n     */\n    public int getMaxFail() {\n        return this.maxFail;\n    }\n\n    /**\n     * Sets maximum number of failed connection attempts\n     *\n     * @param maxFail\n     *            - maximum number of failed connection attempts as {@link int}\n     */\n    public void setMaxFail(int maxFail) {\n        this.maxFail = maxFail;\n    }\n\n    /**\n     * Reports value of the 'idle' option.\n     * The 'idle' option specifies that pppd should disconnect if the link is idle for n seconds.\n     *\n     * @return value of the 'idle' option as {@link int}\n     * @deprecated since 3.0\n     */\n    @Deprecated\n    public int getIdle() {\n        return this.idle;\n    }\n\n    /**\n     * Sets value of the 'idle' option.\n     * The 'idle' option specifies that pppd should disconnect if the link is idle for n seconds.\n     *\n     * @param idle\n     * @deprecated since 3.0\n     */\n    @Deprecated\n    public void setIdle(int idle) {\n        this.idle = idle;\n    }\n\n    /**\n     * Reports the value of the 'active-filter' option that specifies a packet filter to be\n     * applied to data packets to determine which packets are to be regarded as link activity.\n     *\n     * @return value of the 'active-filter' option as {@link String}\n     * @deprecated since 3.0\n     */\n    @Deprecated\n    public String getActiveFilter() {\n        return this.activeFilter;\n    }\n\n    /**\n     * Sets the value of the 'active-filter' option that specifies a packet filter to be\n     * applied to data packets to determine which packets are to be regarded as link activity.\n     *\n     * @param activeFilter\n     *            - active filter as {@link String}\n     * @deprecated since 3.0\n     */\n    @Deprecated\n    public void setActiveFilter(String activeFilter) {\n        this.activeFilter = activeFilter;\n    }\n\n    /**\n     * Reports LCP echo interval\n     *\n     * @return LCP echo interval (in sec) as {@link int}\n     */\n    public int getLcpEchoInterval() {\n        return this.lcpEchoInterval;\n    }\n\n    /**\n     * Sets LCP echo interval\n     *\n     * @param lcpEchoInterval\n     *            - LCP Echo interval as {@link int}\n     */\n    public void setLcpEchoInterval(int lcpEchoInterval) {\n        this.lcpEchoInterval = lcpEchoInterval;\n    }\n\n    /**\n     * Reports number of failed LCP echo requests\n     *\n     * @return number of failed LCP echo requests as {@link int}\n     */\n    public int getLcpEchoFailure() {\n        return this.lcpEchoFailure;\n    }\n\n    /**\n     * Sets number of failed LCP echo requests\n     * (unacknowledged LCP echo requests to be sent for pppd to presume the peer to be dead)\n     *\n     * @param lcpEchoFailure\n     */\n    public void setLcpEchoFailure(int lcpEchoFailure) {\n        this.lcpEchoFailure = lcpEchoFailure;\n    }\n\n    /**\n     * Reports PPP number (i.e. '0' for ppp0).\n     *\n     * @return PPP number as {@link int}\n     */\n    public int getPppNumber() {\n        return this.pppNumber;\n    }\n\n    /**\n     * Sets PPP number (i.e. '0' for ppp0).\n     *\n     * @param pppNumber\n     *            - PPP number as {@link int}\n     */\n    public void setPppNumber(int pppNumber) {\n        this.pppNumber = pppNumber;\n    }\n\n    /**\n     * Reports PDP profile ID.\n     *\n     * @return PDP profile ID as {@link int}\n     */\n    public int getProfileID() {\n        return this.profileID;\n    }\n\n    /**\n     * Sets PDP profile ID.\n     *\n     * @param id\n     *            - PDP profile ID as {@link int}\n     */\n    public void setProfileID(int id) {\n        this.profileID = id;\n    }\n\n    /**\n     * Reports PDP type.\n     *\n     * @return PDP type as {@link PdpType}\n     */\n    public PdpType getPdpType() {\n        return this.pdpType;\n    }\n\n    /**\n     * Sets PDP type.\n     *\n     * @param pdpType\n     *            - PDP type as {@link PdpType}\n     */\n    public void setPdpType(PdpType pdpType) {\n        this.pdpType = pdpType;\n    }\n\n    /**\n     * Reports access point name.\n     *\n     * @return access point name as {@link String}\n     */\n    public String getApn() {\n        return this.apn;\n    }\n\n    /**\n     * Sets access point name.\n     *\n     * @param apn\n     *            - access point name as {@link String}\n     */\n    public void setApn(String apn) {\n        this.apn = apn;\n    }\n\n    /**\n     * Reports PDP IP address.\n     *\n     * @return IP address as {@link IPAddress}\n     */\n    public IPAddress getIpAddress() {\n        return this.ipAddress;\n    }\n\n    /**\n     * Sets PDP IP address.\n     *\n     * @param address\n     *            - IP address as {@link IPAddress}\n     */\n    public void setIpAddress(IPAddress address) {\n        this.ipAddress = address;\n    }\n\n    /**\n     * Reports a value of numeric parameter that supports PDP data compression.\n     *\n     * @return PDP data compression as {@link int}\n     */\n    public int getDataCompression() {\n        return this.dataCompression;\n    }\n\n    /**\n     * Sets a value of numeric parameter that supports PDP data compression.\n     *\n     * @param dataCompression\n     *            - PDP data compression as {@link int}\n     */\n    public void setDataCompression(int dataCompression) {\n        this.dataCompression = dataCompression;\n    }\n\n    /**\n     * Reports a value of numeric parameter that supports PDP header compression.\n     *\n     * @return PDP header compression as {@link int}\n     */\n    public int getHeaderCompression() {\n        return this.headerCompression;\n    }\n\n    /**\n     * Sets a value of numeric parameter that supports PDP header compression.\n     *\n     * @param headerCompression\n     *            headerCompression PDP header compression as {@link int}\n     */\n    public void setHeaderCompression(int headerCompression) {\n        this.headerCompression = headerCompression;\n    }\n\n    /**\n     * Reports if PDP data compression is enabled.\n     *\n     * @return {@link boolean}\n     */\n    public boolean isDataCompression() {\n        return this.dataCompression == 0 ? false : true;\n    }\n\n    /**\n     * Reports if PDP header compression is enabled.\n     *\n     * @return {@link boolean}\n     */\n    public boolean isHeaderCompression() {\n        return this.headerCompression == 0 ? false : true;\n    }\n\n    public boolean isGpsEnabled() {\n        return this.gpsEnabled;\n    }\n\n    public int getResetTimeout() {\n        return this.resetTimeout;\n    }\n\n    public void setResetTimeout(int tout) {\n        this.resetTimeout = tout;\n    }\n\n    public void setGpsEnabled(boolean gpsEnabled) {\n        this.gpsEnabled = gpsEnabled;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public boolean isDiversityEnabled() {\n        return this.diversityEnabled;\n    }\n\n    /**\n     * @since 2.2\n     */\n    public void setDiversityEnabled(boolean diversityEnabled) {\n        this.diversityEnabled = diversityEnabled;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.activeFilter, this.apn, this.authType, this.dataCompression, this.dialString,\n                this.diversityEnabled, this.enabled, this.gpsEnabled, this.headerCompression, this.holdoff, this.idle,\n                this.ipAddress, this.lcpEchoFailure, this.lcpEchoInterval, this.maxFail, this.password, this.pdpType,\n                this.persist, this.pppNumber, this.profileID, this.resetTimeout, this.username);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof ModemConfig)) {\n            return false;\n        }\n        ModemConfig other = (ModemConfig) obj;\n        return Objects.equals(this.activeFilter, other.activeFilter) && Objects.equals(this.apn, other.apn)\n                && this.authType == other.authType && this.dataCompression == other.dataCompression\n                && Objects.equals(this.dialString, other.dialString) && this.diversityEnabled == other.diversityEnabled\n                && this.enabled == other.enabled && this.gpsEnabled == other.gpsEnabled\n                && this.headerCompression == other.headerCompression && this.holdoff == other.holdoff\n                && this.idle == other.idle && Objects.equals(this.ipAddress, other.ipAddress)\n                && this.lcpEchoFailure == other.lcpEchoFailure && this.lcpEchoInterval == other.lcpEchoInterval\n                && this.maxFail == other.maxFail\n                && Arrays.equals(this.password.getPassword(), other.getPasswordAsPassword().getPassword())\n                && this.pdpType == other.pdpType && this.persist == other.persist && this.pppNumber == other.pppNumber\n                && this.profileID == other.profileID && this.resetTimeout == other.resetTimeout\n                && Objects.equals(this.username, other.username);\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(super.toString());\n\n        sb.append(\"ModemConfig - \");\n\n        sb.append(\"Enabled: \").append(this.enabled);\n        sb.append(\" - PPP Number: \").append(this.pppNumber);\n        sb.append(\" - Dial String: \").append(this.dialString);\n        sb.append(\" - Profile ID: \").append(this.profileID);\n        sb.append(\" - PDP Type: \").append(this.pdpType);\n        sb.append(\" - Auth Type: \").append(this.authType);\n        sb.append(\" - APN: \").append(this.apn);\n        sb.append(\" - Username: \").append(this.username);\n        sb.append(\" - Password: \").append(this.password);\n        sb.append(\" - IP Address: \").append(this.ipAddress == null ? \"null\" : this.ipAddress.getHostAddress());\n        sb.append(\" - Data Compression: \").append(this.dataCompression);\n        sb.append(\" - Header Compression: \").append(this.headerCompression);\n\n        return sb.toString();\n    }\n\n    @Override\n    public boolean isValid() {\n        boolean result = true;\n        if (this.pppNumber < 0) {\n            result = false;\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemConnectionStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\npublic enum ModemConnectionStatus {\n    /** UNKNOWN **/\n    UNKNOWN,\n\n    /** DISCONNECTED **/\n    DISCONNECTED,\n\n    /** CONNECTING **/\n    CONNECTING,\n\n    /** CONNECTED **/\n    CONNECTED\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemConnectionType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\npublic enum ModemConnectionType {\n    /** Point to Point Protocol **/\n    PPP,\n\n    /** Direct IP **/\n    DirectIP\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface ModemDevice {\n\n    /**\n     * The list of serial ports available on the device\n     *\n     * @return a list of serial ports names\n     */\n    public List<String> getSerialPorts();\n\n    /**\n     * The manufacturer name of the device\n     *\n     * @return The manufacturer name of the device\n     */\n    public String getManufacturerName();\n\n    /**\n     * The product name of the device\n     *\n     * @return The product name of the device\n     */\n    public String getProductName();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemGpsDisabledEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class ModemGpsDisabledEvent extends Event {\n\n    /** Topic of the ModemGpsDisabledEvent */\n    public static final String MODEM_EVENT_GPS_DISABLED_TOPIC = \"org/eclipse/kura/net/modem/gps/DISABLED\";\n\n    public ModemGpsDisabledEvent(Map<String, Object> properties) {\n        super(MODEM_EVENT_GPS_DISABLED_TOPIC, properties);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemGpsEnabledEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class ModemGpsEnabledEvent extends Event {\n\n    /** Topic of the ModemGpsEnabledEvent */\n    public static final String MODEM_EVENT_GPS_ENABLED_TOPIC = \"org/eclipse/kura/net/modem/gps/ENABLED\";\n\n    /**\n     * @since 2.2\n     */\n    public static final String PORT = \"port\";\n\n    /**\n     * @since 2.2\n     */\n    public static final String BAUD_RATE = \"baudRate\";\n\n    /**\n     * @since 2.2\n     */\n    public static final String DATA_BITS = \"bitsPerWord\";\n\n    /**\n     * @since 2.2\n     */\n    public static final String STOP_BITS = \"stopBits\";\n\n    /**\n     * @since 2.2\n     */\n    public static final String PARITY = \"parity\";\n\n    /**\n     * @deprecated Use PORT instead\n     */\n    @SuppressWarnings(\"checkstyle:constantName\")\n    @Deprecated\n    public static final String Port = PORT;\n\n    /**\n     * @deprecated Use BAUD_RATE instead\n     */\n    @SuppressWarnings(\"checkstyle:constantName\")\n    @Deprecated\n    public static final String BaudRate = BAUD_RATE;\n\n    /**\n     * @deprecated Use DATA_BITS instead\n     */\n    @SuppressWarnings(\"checkstyle:constantName\")\n    @Deprecated\n    public static final String DataBits = DATA_BITS;\n\n    /**\n     * @deprecated Use STOP_BITS instead\n     */\n    @SuppressWarnings(\"checkstyle:constantName\")\n    @Deprecated\n    public static final String StopBits = STOP_BITS;\n\n    /**\n     * @deprecated Use PARITY instead\n     */\n    @SuppressWarnings(\"checkstyle:constantName\")\n    @Deprecated\n    public static final String Parity = PARITY;\n\n    public ModemGpsEnabledEvent(Map<String, Object> properties) {\n        super(MODEM_EVENT_GPS_ENABLED_TOPIC, properties);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemInterface.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.List;\n\nimport org.eclipse.kura.net.NetInterface;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Network interface for modems.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface ModemInterface<T extends ModemInterfaceAddress> extends NetInterface<T> {\n\n    /**\n     * Reports ppp interface number for this modem\n     *\n     * @return ppp interface number as {@link int}\n     */\n    public int getPppNum();\n\n    /**\n     * Reports identifier string for this modem\n     *\n     * @return modem identifier as {@link String}\n     */\n    public String getModemIdentifier();\n\n    /**\n     * Reports modem's model\n     *\n     * @return model, null if not known\n     */\n    public String getModel();\n\n    /**\n     * Returns modem's manufacturer identification\n     *\n     * @return manufacturer, null if not known\n     */\n    public String getManufacturer();\n\n    /**\n     * Answers modem's serial number\n     *\n     * @return ESN, null if not known\n     */\n    public String getSerialNumber();\n\n    /**\n     * Reports modem's revision identification\n     *\n     * @return array of revision ID's, null if not known\n     */\n    public String[] getRevisionId();\n\n    /**\n     * Reports network technology (e.g. EVDO, HSDPA, etc)\n     *\n     * @return - network technology as <code>ModemTechnologyType</code>\n     */\n    public List<ModemTechnologyType> getTechnologyTypes();\n\n    /**\n     * Reports if modem is powered on\n     *\n     * @return\n     *         true - modem is on <br>\n     *         false - modem is off\n     */\n    public boolean isPoweredOn();\n\n    /**\n     * Reports modem's power mode. (e.g. ONLINE, OFFLINE, LOW_POWER)\n     *\n     * @return modem power mode\n     */\n    public ModemPowerMode getPowerMode();\n\n    /**\n     * Return's the associated ModemDevice for this modem\n     *\n     * @return <code>ModemDevice</code>\n     */\n    public ModemDevice getModemDevice();\n\n    /**\n     * Reports if GPS is supported\n     *\n     * @return * @return\n     *         true - GPS is supported <br>\n     *         false - GPS is not supported\n     */\n    public boolean isGpsSupported();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemInterfaceAddress.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Modem Interface Address represents the modem state\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface ModemInterfaceAddress extends NetInterfaceAddress {\n\n    /**\n     * Reports signal strength in dBm\n     *\n     * @return signal strength\n     */\n    public int getSignalStrength();\n\n    /**\n     * Reports roaming status\n     *\n     * @return\n     *         true - modem is roaming\n     *         false - modem is not roaming\n     */\n    public boolean isRoaming();\n\n    /**\n     * Reports connection status\n     *\n     * @return connection status\n     */\n    public ModemConnectionStatus getConnectionStatus();\n\n    /**\n     * Reports number of bytes transmitted during a call\n     *\n     * @return number of bytes transmitted\n     */\n    public long getBytesTransmitted();\n\n    /**\n     * Reports number of bytes received during a call\n     *\n     * @return number of bytes received\n     */\n    public long getBytesReceived();\n\n    /**\n     * Reports Connection Type\n     *\n     * @return connection type\n     */\n    public ModemConnectionType getConnectionType();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemInterfaceAddressConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.List;\n\nimport org.eclipse.kura.net.NetConfig;\nimport org.eclipse.kura.net.NetInterfaceAddressConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Modem Interface Address Config represents the modem status and the modem configuration\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface ModemInterfaceAddressConfig extends ModemInterfaceAddress, NetInterfaceAddressConfig {\n\n    /**\n     * Returns a List of NetConfig Objects associated with a given ModemInterfaceAddressConfig\n     * for a given ModemInterface\n     *\n     * @return the NetConfig Objects associated with the ModemInterfaceAddressConfig\n     */\n    @Override\n    public List<NetConfig> getConfigs();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemManagerService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.Collection;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ConsumerType;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic interface ModemManagerService {\n\n    /**\n     * Returns the modem tracked with the given id.\n     * \n     * @deprecated since 2.2 use\n     *             {@link ModemManagerService#withModemService(String, Function)}\n     *             instead\n     * @param id\n     *           The id of the modem, in case of an USB modem, the id is the USB\n     *           port as returned by\n     *           {@link org.eclipse.kura.usb.UsbModemDevice#getUsbPort()}, in case\n     *           of a serial modem the id is the\n     *           product name as returned by\n     *           {@link org.eclipse.kura.usb.UsbModemDevice#getProductName()}\n     * @return The cellular modem instance, or {@code null} if a modem with the\n     *         given id is not currently tracked\n     */\n    @Deprecated\n    public CellularModem getModemService(String id);\n\n    /**\n     * Returns the list of currently tracked modems\n     * \n     * @deprecated since 2.2 use\n     *             {@link ModemManagerService#withAllModemServices(Function)}\n     *             instead\n     * @return the list of currently tracked modems\n     */\n    @Deprecated\n    public Collection<CellularModem> getAllModemServices();\n\n    /**\n     * Applies the provided function to the modem named {@code id}.\n     * The function will have exclusive access to the modem until it returns.\n     * \n     * @since 2.2\n     * \n     * @param <T>\n     *             The return type of the function\n     * @param id\n     *             The id of the modem, in case of an USB modem, the id is the USB\n     *             port as returned by\n     *             {@link org.eclipse.kura.usb.UsbModemDevice#getUsbPort()}, in case\n     *             of a serial modem the id is the\n     *             product name as returned by\n     *             {@link org.eclipse.kura.usb.UsbModemDevice#getProductName()}\n     * @param func\n     * @return The result of the provided function applied to the modem\n     */\n    public <T> T withModemService(String id, ModemFunction<Optional<CellularModem>, T> func) throws KuraException;\n\n    /**\n     * Applies the provided function to all currently tracked modems.\n     * The function will have exclusive access to the modems until it returns.\n     * \n     * \n     * @since 2.2\n     * \n     * @param <T>\n     *             The return type of the function\n     * @param func\n     *             The function to be called\n     * @return The result of the provided function applied to the modem\n     */\n    public <T> T withAllModemServices(ModemFunction<Collection<CellularModem>, T> func) throws KuraException;\n\n    /**\n     * \n     * @since 2.2\n     * \n     * @param <T>\n     * @param <U>\n     */\n    @ConsumerType\n    public interface ModemFunction<T, U> {\n\n        public U apply(final T arg) throws KuraException;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemMonitorListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * @deprecated since 3.0\n */\n@ConsumerType\n@Deprecated\npublic interface ModemMonitorListener {\n\n    /**\n     * @since 2.0\n     */\n    public void setCellularSignalLevel(String interfaceName, int signalLevel);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemMonitorService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for the ModemMonitor\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic interface ModemMonitorService {\n\n    public void registerListener(ModemMonitorListener listener);\n\n    public void unregisterListener(ModemMonitorListener listener);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemPdpContext.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\n/**\n * @since 1.4\n * @deprecated since 3.0\n */\n@Deprecated\npublic class ModemPdpContext {\n\n    private final int number;\n    private final ModemPdpContextType type;\n    private final String apn;\n\n    public ModemPdpContext(int number, ModemPdpContextType type, String apn) {\n        this.number = number;\n        this.type = type;\n        this.apn = apn;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder(this.getClass().getName());\n        sb.append(super.toString());\n        sb.append(\"; \").append(\"Context Number: \").append(this.number);\n        sb.append(\"; \").append(\"PDP Type: \").append(this.type);\n        sb.append(\"; \").append(\"APN: \").append(this.apn);\n        return sb.toString();\n    }\n\n    public int getNumber() {\n        return this.number;\n    }\n\n    public ModemPdpContextType getType() {\n        return this.type;\n    }\n\n    public String getApn() {\n        return this.apn;\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemPdpContextType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\n/**\n * @since 1.4\n * @deprecated since 3.0\n */\n@Deprecated\npublic enum ModemPdpContextType {\n    IP(\"IP\"),\n    PPP(\"PPP\"),\n    IPV6(\"IPV6\"),\n    IPV4IPV6(\"IPV4IPV6\");\n\n    private String contextType;\n\n    private ModemPdpContextType(String contextType) {\n        this.contextType = contextType;\n    }\n\n    public String getValue() {\n        return this.contextType;\n    }\n\n    public static ModemPdpContextType getContextType(String str) {\n        if (\"IP\".equals(str)) {\n            return IP;\n        } else if (\"PPP\".equals(str)) {\n            return PPP;\n        } else if (\"IPV6\".equals(str)) {\n            return IPV6;\n        } else {\n            return IPV4IPV6;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemPowerMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\npublic enum ModemPowerMode {\n    /** UNKNOWN Mode **/\n    UNKNOWN,\n\n    /** OFFLINE Mode **/\n    OFFLINE,\n\n    /** ONLINE Mode **/\n    ONLINE,\n\n    /** LOW_POWER Mode **/\n    LOW_POWER\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemReadyEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n * \n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic class ModemReadyEvent extends Event {\n\n    /** Topic of the ModemRemovedEvent */\n    public static final String MODEM_EVENT_READY_TOPIC = \"org/eclipse/kura/net/modem/READY\";\n\n    public static final String IMEI = \"IMEI\";\n    public static final String IMSI = \"IMSI\";\n    public static final String ICCID = \"ICCID\";\n    public static final String RSSI = \"RSSI\";\n    /**\n     * @since 2.2\n     */\n    public static final String FW_VERSION = \"FW_VER\";\n    /**\n     * @since 2.2\n     */\n    public static final String MODEM_DEVICE = \"MODEM_DEVICE\";\n\n    public ModemReadyEvent(Map<String, Object> properties) {\n        super(MODEM_EVENT_READY_TOPIC, properties);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemRegistrationStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\npublic enum ModemRegistrationStatus {\n\n    UNKNOWN,\n    NOT_REGISTERED,\n    REGISTERED_HOME,\n    REGISTERED_ROAMING,\n    REGISTRATION_DENIED\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemRemovedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * Emitted when a modem is removed from the gateway\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class ModemRemovedEvent extends Event {\n\n    /** Topic of the ModemRemovedEvent */\n    public static final String MODEM_EVENT_REMOVED_TOPIC = \"org/eclipse/kura/net/modem/REMOVED\";\n\n    public ModemRemovedEvent(Map<String, ?> properties) {\n        super(MODEM_EVENT_REMOVED_TOPIC, properties);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemTechnologyType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\npublic enum ModemTechnologyType {\n    NONE,\n    CDMA,\n    EVDO,\n    LTE,\n    HSPA,\n    HSDPA,\n    UMTS,\n    GSM_GPRS,\n    GPS\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/SerialModemDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.modem;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n * \n * @deprecated This class is deprecated and should not be used.\n * @since 2.3\n */\n@ProviderType\n@Deprecated\npublic class SerialModemDevice implements ModemDevice {\n\n    private final String productName;\n    private final String manufacturerName;\n    private final List<String> serialPorts;\n\n    public SerialModemDevice(String product, String manufacturer, List<String> serialPorts) {\n        this.productName = product;\n        this.manufacturerName = manufacturer;\n        this.serialPorts = serialPorts;\n    }\n\n    @Override\n    public String getProductName() {\n        return this.productName;\n    }\n\n    @Override\n    public String getManufacturerName() {\n        return this.manufacturerName;\n    }\n\n    @Override\n    public List<String> getSerialPorts() {\n        return this.serialPorts;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.manufacturerName == null ? 0 : this.manufacturerName.hashCode());\n        result = prime * result + (this.productName == null ? 0 : this.productName.hashCode());\n        result = prime * result + (this.serialPorts == null ? 0 : this.serialPorts.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        SerialModemDevice other = (SerialModemDevice) obj;\n        if (this.manufacturerName == null) {\n            if (other.manufacturerName != null) {\n                return false;\n            }\n        } else if (!this.manufacturerName.equals(other.manufacturerName)) {\n            return false;\n        }\n        if (this.productName == null) {\n            if (other.productName != null) {\n                return false;\n            }\n        } else if (!this.productName.equals(other.productName)) {\n            return false;\n        }\n        if (this.serialPorts == null) {\n            if (other.serialPorts != null) {\n                return false;\n            }\n        } else if (!this.serialPorts.equals(other.serialPorts)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides interfaces for instances and configurations of modems.\n *\n */\npackage org.eclipse.kura.net.modem;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Contains interfaces and event model to manage and configure network interfaces on a given system.\n * <p>\n *\n *\n */\npackage org.eclipse.kura.net;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.route;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Route configuration interface\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface RouteConfig extends NetConfig {\n\n    /**\n     * Gets the description of the route\n     *\n     * @return The description of the route\n     */\n    public String getDescription();\n\n    /**\n     * Gets the destination of the route\n     *\n     * @return The destination of the route\n     */\n    public IPAddress getDestination();\n\n    /**\n     * Gets the gateway of the route\n     *\n     * @return The gateway of the route\n     */\n    public IPAddress getGateway();\n\n    /**\n     * Gets the network mask of the route\n     *\n     * @return The network mask of the route\n     */\n    public IPAddress getNetmask();\n\n    /**\n     * Gets the interface name associated with the route\n     *\n     * @return The interface name associated with the route\n     */\n    public String getInterfaceName();\n\n    /**\n     * Gets the metric of the route\n     *\n     * @return The metric of the route\n     */\n    public int getMetric();\n\n    /**\n     * Compares one route to another\n     *\n     * @return Whether or not the two routes are equal\n     */\n    public boolean equals(RouteConfig r);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfig4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.route;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv4 route configs\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface RouteConfig4 extends RouteConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfig6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.route;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for IPv6 route configs\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface RouteConfig6 extends RouteConfig {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfigIP.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.route;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Base class for Route configurations\n *\n * @param <T>\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic abstract class RouteConfigIP<T extends IPAddress> implements RouteConfig {\n\n    private T destination;\n    private T gateway;\n    private T netmask;\n    private String interfaceName;\n    private int metric;\n\n    public RouteConfigIP(T destination, T gateway, T netmask, String interfaceName, int metric) {\n        super();\n\n        this.destination = destination;\n        this.gateway = gateway;\n        this.netmask = netmask;\n        this.interfaceName = interfaceName;\n        this.metric = metric;\n    }\n\n    @Override\n    public String getDescription() {\n        StringBuffer desc = new StringBuffer();\n        String gw;\n        if (this.gateway == null) {\n            gw = \"default\";\n        } else {\n            gw = this.gateway.getHostAddress();\n        }\n        desc.append(\"Destination: \" + this.destination.getHostAddress() + \", \" + \"Gateway: \" + gw + \", \" + \"Netmask: \"\n                + this.netmask.getHostAddress() + \", \" + \"Interface: \" + this.interfaceName + \", \" + \"Metric: \"\n                + this.metric);\n        return desc.toString();\n    }\n\n    @Override\n    public T getDestination() {\n        return this.destination;\n    }\n\n    public void setDestination(T destination) {\n        this.destination = destination;\n    }\n\n    @Override\n    public T getGateway() {\n        return this.gateway;\n    }\n\n    public void setGateway(T gateway) {\n        this.gateway = gateway;\n    }\n\n    @Override\n    public T getNetmask() {\n        return this.netmask;\n    }\n\n    public void setNetmask(T netmask) {\n        this.netmask = netmask;\n    }\n\n    @Override\n    public String getInterfaceName() {\n        return this.interfaceName;\n    }\n\n    public void setInterfaceName(String interfaceName) {\n        this.interfaceName = interfaceName;\n    }\n\n    @Override\n    public int getMetric() {\n        return this.metric;\n    }\n\n    public void setMetric(int metric) {\n        this.metric = metric;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.destination == null ? 0 : this.destination.hashCode());\n        result = prime * result + (this.gateway == null ? 0 : this.gateway.hashCode());\n        result = prime * result + (this.interfaceName == null ? 0 : this.interfaceName.hashCode());\n        result = prime * result + this.metric;\n        result = prime * result + (this.netmask == null ? 0 : this.netmask.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        @SuppressWarnings(\"rawtypes\")\n        RouteConfigIP other = (RouteConfigIP) obj;\n        if (this.destination == null) {\n            if (other.destination != null) {\n                return false;\n            }\n        } else if (!this.destination.equals(other.destination)) {\n            return false;\n        }\n        if (this.gateway == null) {\n            if (other.gateway != null) {\n                return false;\n            }\n        } else if (!this.gateway.equals(other.gateway)) {\n            return false;\n        }\n        if (this.interfaceName == null) {\n            if (other.interfaceName != null) {\n                return false;\n            }\n        } else if (!this.interfaceName.equals(other.interfaceName)) {\n            return false;\n        }\n        if (this.metric != other.metric) {\n            return false;\n        }\n        if (this.netmask == null) {\n            if (other.netmask != null) {\n                return false;\n            }\n        } else if (!this.netmask.equals(other.netmask)) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public boolean isValid() {\n        if (this.destination == null || this.gateway == null || this.netmask == null\n                || this.interfaceName == null) {\n            return false;\n        }\n\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"RouteConfigIP [m_destination=\");\n        builder.append(this.destination);\n        builder.append(\", m_gateway=\");\n        builder.append(this.gateway);\n        builder.append(\", m_netmask=\");\n        builder.append(this.netmask);\n        builder.append(\", m_interfaceName=\");\n        builder.append(this.interfaceName);\n        builder.append(\", m_metric=\");\n        builder.append(this.metric);\n        builder.append(\"]\");\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfigIP4.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.route;\n\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.IPAddress;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Implementation of IPv4 route configurations\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class RouteConfigIP4 extends RouteConfigIP<IP4Address> implements RouteConfig4 {\n\n    public RouteConfigIP4(IP4Address destination, IP4Address gateway, IP4Address netmask, String interfaceName,\n            int metric) {\n        super(destination, gateway, netmask, interfaceName, metric);\n    }\n\n    @Override\n    public boolean equals(RouteConfig route) {\n\n        if (!compareHostAddress(getDestination(), route.getDestination())) {\n            return false;\n        } else if (!compareHostAddress(getGateway(), route.getGateway())) {\n            return false;\n        } else if (!compareHostAddress(getNetmask(), route.getNetmask())) {\n            return false;\n        } else if (!getInterfaceName().equals(route.getInterfaceName())) {\n            return false;\n        } else if (getMetric() != route.getMetric()) {\n            return false;\n        }\n\n        return true;\n    }\n\n    private boolean compareHostAddress(IPAddress adr1, IPAddress adr2) {\n        String host1 = adr1 == null || adr1.getHostAddress() == null ? \"\" : adr1.getHostAddress();\n        String host2 = adr2 == null || adr2.getHostAddress() == null ? \"\" : adr2.getHostAddress();\n\n        return host1.equals(host2);\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"destination: \").append(getDestination() != null ? getDestination().getHostAddress() : \"null\")\n                .append(\", gateway: \").append(getGateway() != null ? getGateway().getHostAddress() : \"null\")\n                .append(\", netmask: \").append(getNetmask() != null ? getNetmask().getHostAddress() : \"null\")\n                .append(\", interfaceName: \").append(getInterfaceName()).append(\", metric: \").append(getMetric());\n\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfigIP6.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.route;\n\nimport org.eclipse.kura.net.IP6Address;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Implementation of IPv6 route configurations\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class RouteConfigIP6 extends RouteConfigIP<IP6Address> implements RouteConfig6 {\n\n    public RouteConfigIP6(IP6Address destination, IP6Address gateway, IP6Address netmask, String interfaceName,\n            int metric) {\n        super(destination, gateway, netmask, interfaceName, metric);\n    }\n\n    @Override\n    public boolean equals(RouteConfig r) {\n        // TODO Auto-generated method stub\n        return false;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RoutingAgentService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.route;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.net.NetInterfaceConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Routing agent service is used to control the static routing table. The\n * service is used to specify\n * which interfaces should be used in considering routes and what their\n * priorities should be.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic interface RoutingAgentService {\n\n    /**\n     * Sets interface priorities\n     *\n     * @param priorities\n     *                   - list of interface priorities as {@link Map}\n     */\n    public void setPriorities(Map<String, Integer> priorities);\n\n    /**\n     * Adds interface to RoutingAgent\n     *\n     * @param netIfaceConfig\n     *                       - interface configuration as {@link NetInterfaceConfig}\n     * @throws KuraException\n     */\n    @SuppressWarnings(\"rawtypes\")\n    public void addInterface(NetInterfaceConfig netIfaceConfig) throws KuraException;\n\n    /**\n     * Removes interface from RoutingAgent\n     *\n     * @param interfaceName\n     *                      - interface name as {@link String}\n     * @throws KuraException\n     */\n    void removeInterface(String interfaceName) throws KuraException;\n\n    /**\n     * Get the default gateway\n     *\n     * @return interfaceName - interface name as {@link String}\n     * @throws KuraException\n     */\n    public String getDefaultGateway() throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides services to manage interfaces and their priorities in the static routing table.\n *\n */\npackage org.eclipse.kura.net.route;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceIpAddress.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status;\n\nimport java.util.Objects;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class describes an IP address with its prefix.\n * It can be used for IPv4 or IPv6 addresses.\n *\n */\n@ProviderType\npublic class NetworkInterfaceIpAddress<T extends IPAddress> {\n\n    private final T address;\n    private final short prefix;\n\n    public NetworkInterfaceIpAddress(T address, short prefix) {\n        this.address = address;\n        this.prefix = prefix;\n    }\n\n    public T getAddress() {\n        return this.address;\n    }\n\n    public short getPrefix() {\n        return this.prefix;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.address, this.prefix);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        NetworkInterfaceIpAddress<T> other = (NetworkInterfaceIpAddress<T>) obj;\n        return Objects.equals(this.address, other.address) && this.prefix == other.prefix;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceIpAddressStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.eclipse.kura.net.IPAddress;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class describes the IP address status of a network interface:\n * a list of IP addresses, an optional gateway and a list of DNS servers\n * address. It can be used for IPv4 or IPv6 addresses.\n *\n */\n@ProviderType\npublic class NetworkInterfaceIpAddressStatus<T extends IPAddress> {\n\n    private final List<NetworkInterfaceIpAddress<T>> addresses;\n    private final Optional<T> gateway;\n    private final List<T> dnsServerAddresses;\n\n    private NetworkInterfaceIpAddressStatus(Builder<T> builder) {\n        this.addresses = builder.addresses;\n        this.gateway = builder.gateway;\n        this.dnsServerAddresses = builder.dnsServerAddresses;\n    }\n\n    public List<NetworkInterfaceIpAddress<T>> getAddresses() {\n        return this.addresses;\n    }\n\n    public Optional<T> getGateway() {\n        return this.gateway;\n    }\n\n    public List<T> getDnsServerAddresses() {\n        return this.dnsServerAddresses;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.addresses, this.dnsServerAddresses, this.gateway);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        NetworkInterfaceIpAddressStatus<T> other = (NetworkInterfaceIpAddressStatus<T>) obj;\n        return Objects.equals(this.addresses, other.addresses)\n                && Objects.equals(this.dnsServerAddresses, other.dnsServerAddresses)\n                && Objects.equals(this.gateway, other.gateway);\n    }\n\n    public static <U extends IPAddress> Builder<U> builder() {\n        return new Builder<>();\n    }\n\n    public static final class Builder<U extends IPAddress> {\n\n        private List<NetworkInterfaceIpAddress<U>> addresses = Collections.emptyList();\n        private Optional<U> gateway = Optional.empty();\n        private List<U> dnsServerAddresses = Collections.emptyList();\n\n        private Builder() {\n        }\n\n        public Builder<U> withAddresses(List<NetworkInterfaceIpAddress<U>> addresses) {\n            this.addresses = addresses;\n            return this;\n        }\n\n        public Builder<U> withGateway(Optional<U> gateway) {\n            this.gateway = gateway;\n            return this;\n        }\n\n        public Builder<U> withDnsServerAddresses(List<U> dnsServerAddresses) {\n            this.dnsServerAddresses = dnsServerAddresses;\n            return this;\n        }\n\n        public NetworkInterfaceIpAddressStatus<U> build() {\n            return new NetworkInterfaceIpAddressStatus<>(this);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceState.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status;\n\n/**\n * The state of a network interface.\n */\npublic enum NetworkInterfaceState {\n\n    /** The device is in an unknown state. */\n    UNKNOWN,\n    /** The device is recognized but not managed. */\n    UNMANAGED,\n    /** The device cannot be used (carrier off, rfkill, etc). */\n    UNAVAILABLE,\n    /** The device is not connected. */\n    DISCONNECTED,\n    /** The device is preparing to connect. */\n    PREPARE,\n    /** The device is being configured. */\n    CONFIG,\n    /** The device is awaiting secrets necessary to continue connection. */\n    NEED_AUTH,\n    /** The IP settings of the device are being requested and configured. */\n    IP_CONFIG,\n    /** The device's IP connectivity ability is being determined. */\n    IP_CHECK,\n    /** The device is waiting for secondary connections to be activated. */\n    SECONDARIES,\n    /** The device is active. */\n    ACTIVATED,\n    /** The device's network connection is being turn down. */\n    DEACTIVATING,\n    /** The device is in a failure state following an attempt to activate it. */\n    FAILED;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status;\n\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.IP6Address;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Abstract class that contains common properties to describe the status of a\n * network interface. Specific interfaces, like ethernet or wifi, must extend\n * this class.\n *\n * A network interface is identified by Eclipse Kura using the interfaceId\n * field. It is used to internally manage the interface.\n * The interfaceName, instead, is the IP interface as it may appear on the\n * system. For Ethernet and WiFi interfaces the two values coincide\n * (i.e. eth0, wlp1s0, ...).\n * For modems, instead, the id is typically the usb or pci path, while the\n * interfaceName is the IP interface created when they are connected.\n * When the modem is disconnected the interfaceName can have a different value.\n *\n */\n@ProviderType\npublic abstract class NetworkInterfaceStatus {\n\n    private final String interfaceId;\n    private final String interfaceName;\n    private final byte[] hardwareAddress;\n    private final NetworkInterfaceType type;\n    private final String driver;\n    private final String driverVersion;\n    private final String firmwareVersion;\n    private final boolean virtual;\n    private final NetworkInterfaceState state;\n    private final boolean autoConnect;\n    private final int mtu;\n    private final Optional<NetworkInterfaceIpAddressStatus<IP4Address>> interfaceIp4Addresses;\n    private final Optional<NetworkInterfaceIpAddressStatus<IP6Address>> interfaceIp6Addresses;\n\n    protected NetworkInterfaceStatus(NetworkInterfaceStatusBuilder<?> builder) {\n        this.interfaceId = builder.interfaceId;\n        this.interfaceName = builder.interfaceName;\n        this.hardwareAddress = builder.hardwareAddress;\n        this.type = builder.type;\n        this.driver = builder.driver;\n        this.driverVersion = builder.driverVersion;\n        this.firmwareVersion = builder.firmwareVersion;\n        this.virtual = builder.virtual;\n        this.state = builder.state;\n        this.autoConnect = builder.autoConnect;\n        this.mtu = builder.mtu;\n        this.interfaceIp4Addresses = builder.interfaceIp4Addresses;\n        this.interfaceIp6Addresses = builder.interfaceIp6Addresses;\n    }\n\n    public String getInterfaceId() {\n        return this.interfaceId;\n    }\n\n    public String getInterfaceName() {\n        return this.interfaceName;\n    }\n\n    public byte[] getHardwareAddress() {\n        return this.hardwareAddress;\n    }\n\n    public NetworkInterfaceType getType() {\n        return this.type;\n    }\n\n    public String getDriver() {\n        return this.driver;\n    }\n\n    public String getDriverVersion() {\n        return this.driverVersion;\n    }\n\n    public String getFirmwareVersion() {\n        return this.firmwareVersion;\n    }\n\n    public boolean isVirtual() {\n        return this.virtual;\n    }\n\n    public NetworkInterfaceState getState() {\n        return this.state;\n    }\n\n    public boolean isAutoConnect() {\n        return this.autoConnect;\n    }\n\n    public int getMtu() {\n        return this.mtu;\n    }\n\n    public Optional<NetworkInterfaceIpAddressStatus<IP4Address>> getInterfaceIp4Addresses() {\n        return this.interfaceIp4Addresses;\n    }\n\n    public Optional<NetworkInterfaceIpAddressStatus<IP6Address>> getInterfaceIp6Addresses() {\n        return this.interfaceIp6Addresses;\n    }\n\n    /**\n     * Abstract builder for a {@link NetworkInterfaceStatus} object. The builders\n     * for specific interfaces, like ethernet or wifi, must extend this class.\n     *\n     */\n    public abstract static class NetworkInterfaceStatusBuilder<T extends NetworkInterfaceStatusBuilder<T>> {\n\n        private static final String NA = \"N/A\";\n        private String interfaceId = NA;\n        private String interfaceName = NA;\n        private byte[] hardwareAddress = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };\n        private NetworkInterfaceType type = NetworkInterfaceType.UNKNOWN;\n        private String driver = NA;\n        private String driverVersion = NA;\n        private String firmwareVersion = NA;\n        private boolean virtual = false;\n        private NetworkInterfaceState state = NetworkInterfaceState.UNKNOWN;\n        private boolean autoConnect = false;\n        private int mtu = 0;\n        private Optional<NetworkInterfaceIpAddressStatus<IP4Address>> interfaceIp4Addresses = Optional.empty();\n        private Optional<NetworkInterfaceIpAddressStatus<IP6Address>> interfaceIp6Addresses = Optional.empty();\n\n        public T withInterfaceId(String interfaceId) {\n            this.interfaceId = interfaceId;\n            return getThis();\n        }\n\n        public T withInterfaceName(String interfacenName) {\n            this.interfaceName = interfacenName;\n            return getThis();\n        }\n\n        public T withHardwareAddress(byte[] hardwareAddress) {\n            this.hardwareAddress = hardwareAddress;\n            return getThis();\n        }\n\n        protected T withType(NetworkInterfaceType type) {\n            this.type = type;\n            return getThis();\n        }\n\n        public T withDriver(String driver) {\n            this.driver = driver;\n            return getThis();\n        }\n\n        public T withDriverVersion(String driverVersion) {\n            this.driverVersion = driverVersion;\n            return getThis();\n        }\n\n        public T withFirmwareVersion(String firmwareVersion) {\n            this.firmwareVersion = firmwareVersion;\n            return getThis();\n        }\n\n        public T withVirtual(boolean virtual) {\n            this.virtual = virtual;\n            return getThis();\n        }\n\n        public T withState(NetworkInterfaceState state) {\n            this.state = state;\n            return getThis();\n        }\n\n        public T withAutoConnect(boolean autoConnect) {\n            this.autoConnect = autoConnect;\n            return getThis();\n        }\n\n        public T withMtu(int mtu) {\n            this.mtu = mtu;\n            return getThis();\n        }\n\n        public T withInterfaceIp4Addresses(\n                Optional<NetworkInterfaceIpAddressStatus<IP4Address>> interfaceIp4Addresses) {\n            this.interfaceIp4Addresses = interfaceIp4Addresses;\n            return getThis();\n        }\n\n        public T withInterfaceIp6Addresses(\n                Optional<NetworkInterfaceIpAddressStatus<IP6Address>> interfaceIp6Addresses) {\n            this.interfaceIp6Addresses = interfaceIp6Addresses;\n            return getThis();\n        }\n\n        public abstract T getThis();\n\n        public abstract NetworkInterfaceStatus build();\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + Arrays.hashCode(this.hardwareAddress);\n        result = prime * result + Objects.hash(this.autoConnect, this.driver, this.driverVersion, this.firmwareVersion,\n                this.interfaceName, this.interfaceIp4Addresses, this.interfaceIp6Addresses, this.mtu, this.interfaceId,\n                this.state, this.type, this.virtual);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        NetworkInterfaceStatus other = (NetworkInterfaceStatus) obj;\n        return this.autoConnect == other.autoConnect && Objects.equals(this.driver, other.driver)\n                && Objects.equals(this.driverVersion, other.driverVersion)\n                && Objects.equals(this.firmwareVersion, other.firmwareVersion)\n                && Arrays.equals(this.hardwareAddress, other.hardwareAddress)\n                && Objects.equals(this.interfaceName, other.interfaceName)\n                && Objects.equals(this.interfaceIp4Addresses, other.interfaceIp4Addresses)\n                && Objects.equals(this.interfaceIp6Addresses, other.interfaceIp6Addresses) && this.mtu == other.mtu\n                && Objects.equals(this.interfaceId, other.interfaceId) && this.state == other.state\n                && this.type == other.type\n                && this.virtual == other.virtual;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status;\n\n/**\n * The type of a network interface.\n *\n */\npublic enum NetworkInterfaceType {\n\n    /** The device type is unknown. */\n    UNKNOWN,\n    /** The device is a wired Ethernet device. */\n    ETHERNET,\n    /** The device is an 802.11 WiFi device. */\n    WIFI,\n    /** Unused */\n    UNUSED1,\n    /** Unused */\n    UNUSED2,\n    /** The device is a Bluetooth device. */\n    BT,\n    /** The device is an OLPC mesh networking device. */\n    OLPC_MESH,\n    /** The device is an 802.16e Mobile WiMAX device. */\n    WIMAX,\n    /**\n     * The device is a modem supporting one or more of analog telephone, CDMA/EVDO,\n     * GSM/UMTS/HSPA, or LTE standards to access a cellular or wireline data\n     * network.\n     */\n    MODEM,\n    /** The device is an IP-capable InfiniBand interface. */\n    INFINIBAND,\n    /** The device is a bond master interface. */\n    BOND,\n    /** The device is a VLAN interface. */\n    VLAN,\n    /** The device is an ADSL device. */\n    ADSL,\n    /** The device is a bridge master interface. */\n    BRIDGE,\n    /** This is a generic support for unrecognized device types. */\n    GENERIC,\n    /** The device is a team master interface. */\n    TEAM,\n    /** The device is a TUN or TAP interface. */\n    TUN,\n    /** The device is an IP tunnel interface. */\n    TUNNEL,\n    /** The device is a MACVLAN interface. */\n    MACVLAN,\n    /** The device is a VXLAN interface. */\n    VXLAN,\n    /** The device is a VETH interface. */\n    VETH,\n    /** The device is a MACsec interface. */\n    MACSEC,\n    /** The device is a dummy interface. */\n    DUMMY,\n    /** The device is a PPP interface. */\n    PPP,\n    /** The device is a Open vSwitch interface. */\n    OVS_INTERFACE,\n    /** The device is a Open vSwitch port. */\n    OVS_PORT,\n    /** The device is a Open vSwitch bridge. */\n    OVS_BRIDGE,\n    /** The device is a IEEE 802.15.4 (WPAN) MAC Layer Device. */\n    WPAN,\n    /** The device is a 6LoWPAN interface. */\n    SIXLOWPAN,\n    /** The device is a WireGuard interface. */\n    WIREGUARD,\n    /** The device is an 802.11 Wi-Fi P2P device. */\n    WIFI_P2P,\n    /** The device is a VRF (Virtual Routing and Forwarding) interface. */\n    VRF,\n    /** The device is a loopback device. */\n    LOOPBACK;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkStatusService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n ******************************************************************************/\npackage org.eclipse.kura.net.status;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Service API for getting the network interfaces status.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface NetworkStatusService {\n\n    /**\n     * Return an optional {@link NetworkInterfaceStatus} of the given network\n     * interface selected by its id. For Ethernet and WiFi interfaces, the\n     * identifier is typically the interface name. For the modems, instead,\n     * it is the usb or pci path.\n     * If the interface doesn't exist, an Empty value is returned.\n     *\n     * @param interfaceId\n     *            the identifier of the network interface\n     * @return the {@link NetworkInterfaceStatus}\n     * @throws KuraException\n     *             when an error occurs while retrieving the status of the\n     *             given interface\n     */\n    public Optional<NetworkInterfaceStatus> getNetworkStatus(String interfaceId) throws KuraException;\n\n    /**\n     * Return an optional {@link NetworkInterfaceStatus} of the given network\n     * interface selected by its id.For Ethernet and WiFi interfaces, the\n     * identifier is typically the interface name. For the modems, instead,\n     * it is the usb or pci path.\n     * If the interface doesn't exist, an Empty value is returned.\n     * \n     * @param interfaceId\n     *            the identifier of the network interface\n     * @param recompute\n     *            If set to true, the NetworkStatusService will perform some additional expensive operations (like AP\n     *            scanning) to ensure the status returned by the method is up to date. If set to false, it will return\n     *            the status as returned by the network configuration provider.\n     * @return the {@link NetworkInterfaceStatus}\n     * @throws KuraException\n     *             when an error occurs while retrieving the status of the\n     *             given interface\n     */\n\n    public Optional<NetworkInterfaceStatus> getNetworkStatus(String interfaceId, boolean recompute)\n            throws KuraException;\n\n    /**\n     * Return the identifiers of the network interfaces detected in the\n     * system. For Ethernet and WiFi interfaces, the identifier is typically\n     * the interface name. For the modems, instead, it is the usb or pci path.\n     *\n     * @return a list containing the network interface identifiers\n     */\n    public List<String> getInterfaceIds() throws KuraException;\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/ethernet/EthernetInterfaceStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.ethernet;\n\nimport java.util.Objects;\n\nimport org.eclipse.kura.net.status.NetworkInterfaceStatus;\nimport org.eclipse.kura.net.status.NetworkInterfaceType;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Class that contains specific properties to describe the status of an\n * Ethernet interface.\n *\n */\n@ProviderType\npublic class EthernetInterfaceStatus extends NetworkInterfaceStatus {\n\n    private final boolean linkUp;\n\n    private EthernetInterfaceStatus(EthernetInterfaceStatusBuilder builder) {\n        super(builder);\n        this.linkUp = builder.linkUp;\n    }\n\n    public boolean isLinkUp() {\n        return this.linkUp;\n    }\n\n    public static EthernetInterfaceStatusBuilder builder() {\n        return new EthernetInterfaceStatusBuilder();\n    }\n\n    public static class EthernetInterfaceStatusBuilder\n            extends NetworkInterfaceStatusBuilder<EthernetInterfaceStatusBuilder> {\n\n        private boolean linkUp = false;\n\n        public EthernetInterfaceStatusBuilder withIsLinkUp(boolean linkUp) {\n            this.linkUp = linkUp;\n            return getThis();\n        }\n\n        @Override\n        public EthernetInterfaceStatus build() {\n            withType(NetworkInterfaceType.ETHERNET);\n            return new EthernetInterfaceStatus(this);\n        }\n\n        @Override\n        public EthernetInterfaceStatusBuilder getThis() {\n            return this;\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + Objects.hash(this.linkUp);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj) || getClass() != obj.getClass()) {\n            return false;\n        }\n        EthernetInterfaceStatus other = (EthernetInterfaceStatus) obj;\n        return this.linkUp == other.linkUp;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/ethernet/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides classes for describing the status of an Ethernet interface.\n *\n */\npackage org.eclipse.kura.net.status.ethernet;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/loopback/LoopbackInterfaceStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.loopback;\n\nimport org.eclipse.kura.net.status.NetworkInterfaceStatus;\nimport org.eclipse.kura.net.status.NetworkInterfaceType;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Class that contains specific properties to describe the status of a\n * Loopback interface.\n *\n */\n@ProviderType\npublic class LoopbackInterfaceStatus extends NetworkInterfaceStatus {\n\n    private LoopbackInterfaceStatus(LoopbackInterfaceStatusBuilder builder) {\n        super(builder);\n    }\n\n    public static LoopbackInterfaceStatusBuilder builder() {\n        return new LoopbackInterfaceStatusBuilder();\n    }\n\n    public static class LoopbackInterfaceStatusBuilder\n            extends NetworkInterfaceStatusBuilder<LoopbackInterfaceStatusBuilder> {\n\n        @Override\n        public LoopbackInterfaceStatus build() {\n            withType(NetworkInterfaceType.LOOPBACK);\n            return new LoopbackInterfaceStatus(this);\n        }\n\n        @Override\n        public LoopbackInterfaceStatusBuilder getThis() {\n            return this;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/loopback/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides classes for describing the status of a Loopback interface.\n *\n */\npackage org.eclipse.kura.net.status.loopback;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/AccessTechnology.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The specific technology types used when a modem is connected or registered to\n * a network.\n *\n */\npublic enum AccessTechnology {\n\n    UNKNOWN,\n    POTS,\n    GSM,\n    GSM_COMPACT,\n    GPRS,\n    EDGE,\n    UMTS,\n    HSDPA,\n    HSUPA,\n    HSPA,\n    HSPA_PLUS,\n    ONEXRTT,\n    EVDO0,\n    EVDOA,\n    EVDOB,\n    LTE,\n    FIVEGNR,\n    LTE_CAT_M,\n    LTE_NB_IOT,\n    ANY;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/Bearer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class describes the Bearer or Context associated to a modem connection.\n *\n */\n@ProviderType\npublic class Bearer {\n\n    private final String name;\n    private final boolean connected;\n    private final String apn;\n    private final Set<BearerIpType> ipTypes;\n    private final long bytesTransmitted;\n    private final long bytesReceived;\n\n    public Bearer(String name, boolean connected, String apn, Set<BearerIpType> ipTypes, long bytesTransmitted,\n            long bytesReceived) {\n        super();\n        this.name = name;\n        this.connected = connected;\n        this.apn = apn;\n        this.ipTypes = ipTypes;\n        this.bytesTransmitted = bytesTransmitted;\n        this.bytesReceived = bytesReceived;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public boolean isConnected() {\n        return this.connected;\n    }\n\n    public String getApn() {\n        return this.apn;\n    }\n\n    public Set<BearerIpType> getIpTypes() {\n        return this.ipTypes;\n    }\n\n    public long getBytesTransmitted() {\n        return this.bytesTransmitted;\n    }\n\n    public long getBytesReceived() {\n        return this.bytesReceived;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.apn, this.bytesReceived, this.bytesTransmitted, this.connected, this.ipTypes,\n                this.name);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        Bearer other = (Bearer) obj;\n        return Objects.equals(this.apn, other.apn) && this.bytesReceived == other.bytesReceived\n                && this.bytesTransmitted == other.bytesTransmitted && this.connected == other.connected\n                && Objects.equals(this.ipTypes, other.ipTypes) && Objects.equals(this.name, other.name);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/BearerIpType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The type of Bearer or Context associated to a modem connection.\n *\n */\npublic enum BearerIpType {\n\n    NONE,\n    IPV4,\n    IPV6,\n    IPV4V6,\n    NON_IP,\n    ANY;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ESimStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The status of an ESIM.\n *\n */\npublic enum ESimStatus {\n\n    UNKNOWN,\n    NO_PROFILES,\n    WITH_PROFILES;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemBand.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The radio bands supported by a modem when connected to a mobile network.\n *\n */\npublic enum ModemBand {\n    UNKNOWN,\n    EGSM,\n    DCS,\n    PCS,\n    G850,\n    UTRAN_1,\n    UTRAN_3,\n    UTRAN_4,\n    UTRAN_6,\n    UTRAN_5,\n    UTRAN_8,\n    UTRAN_9,\n    UTRAN_2,\n    UTRAN_7,\n    G450,\n    G480,\n    G750,\n    G380,\n    G410,\n    G710,\n    G810,\n    EUTRAN_1,\n    EUTRAN_2,\n    EUTRAN_3,\n    EUTRAN_4,\n    EUTRAN_5,\n    EUTRAN_6,\n    EUTRAN_7,\n    EUTRAN_8,\n    EUTRAN_9,\n    EUTRAN_10,\n    EUTRAN_11,\n    EUTRAN_12,\n    EUTRAN_13,\n    EUTRAN_14,\n    EUTRAN_17,\n    EUTRAN_18,\n    EUTRAN_19,\n    EUTRAN_20,\n    EUTRAN_21,\n    EUTRAN_22,\n    EUTRAN_23,\n    EUTRAN_24,\n    EUTRAN_25,\n    EUTRAN_26,\n    EUTRAN_27,\n    EUTRAN_28,\n    EUTRAN_29,\n    EUTRAN_30,\n    EUTRAN_31,\n    EUTRAN_32,\n    EUTRAN_33,\n    EUTRAN_34,\n    EUTRAN_35,\n    EUTRAN_36,\n    EUTRAN_37,\n    EUTRAN_38,\n    EUTRAN_39,\n    EUTRAN_40,\n    EUTRAN_41,\n    EUTRAN_42,\n    EUTRAN_43,\n    EUTRAN_44,\n    EUTRAN_45,\n    EUTRAN_46,\n    EUTRAN_47,\n    EUTRAN_48,\n    EUTRAN_49,\n    EUTRAN_50,\n    EUTRAN_51,\n    EUTRAN_52,\n    EUTRAN_53,\n    EUTRAN_54,\n    EUTRAN_55,\n    EUTRAN_56,\n    EUTRAN_57,\n    EUTRAN_58,\n    EUTRAN_59,\n    EUTRAN_60,\n    EUTRAN_61,\n    EUTRAN_62,\n    EUTRAN_63,\n    EUTRAN_64,\n    EUTRAN_65,\n    EUTRAN_66,\n    EUTRAN_67,\n    EUTRAN_68,\n    EUTRAN_69,\n    EUTRAN_70,\n    EUTRAN_71,\n    EUTRAN_85,\n    CDMA_BC0,\n    CDMA_BC1,\n    CDMA_BC2,\n    CDMA_BC3,\n    CDMA_BC4,\n    CDMA_BC5,\n    CDMA_BC6,\n    CDMA_BC7,\n    CDMA_BC8,\n    CDMA_BC9,\n    CDMA_BC10,\n    CDMA_BC11,\n    CDMA_BC12,\n    CDMA_BC13,\n    CDMA_BC14,\n    CDMA_BC15,\n    CDMA_BC16,\n    CDMA_BC17,\n    CDMA_BC18,\n    CDMA_BC19,\n    UTRAN_10,\n    UTRAN_11,\n    UTRAN_12,\n    UTRAN_13,\n    UTRAN_14,\n    UTRAN_19,\n    UTRAN_20,\n    UTRAN_21,\n    UTRAN_22,\n    UTRAN_25,\n    UTRAN_26,\n    UTRAN_32,\n    ANY,\n    NGRAN_1,\n    NGRAN_2,\n    NGRAN_3,\n    NGRAN_5,\n    NGRAN_7,\n    NGRAN_8,\n    NGRAN_12,\n    NGRAN_13,\n    NGRAN_14,\n    NGRAN_18,\n    NGRAN_20,\n    NGRAN_25,\n    NGRAN_26,\n    NGRAN_28,\n    NGRAN_29,\n    NGRAN_30,\n    NGRAN_34,\n    NGRAN_38,\n    NGRAN_39,\n    NGRAN_40,\n    NGRAN_41,\n    NGRAN_48,\n    NGRAN_50,\n    NGRAN_51,\n    NGRAN_53,\n    NGRAN_65,\n    NGRAN_66,\n    NGRAN_70,\n    NGRAN_71,\n    NGRAN_74,\n    NGRAN_75,\n    NGRAN_76,\n    NGRAN_77,\n    NGRAN_78,\n    NGRAN_79,\n    NGRAN_80,\n    NGRAN_81,\n    NGRAN_82,\n    NGRAN_83,\n    NGRAN_84,\n    NGRAN_86,\n    NGRAN_89,\n    NGRAN_90,\n    NGRAN_91,\n    NGRAN_92,\n    NGRAN_93,\n    NGRAN_94,\n    NGRAN_95,\n    NGRAN_257,\n    NGRAN_258,\n    NGRAN_260,\n    NGRAN_261;\n}"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemCapability.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The generic access technologies families supported by a modem.\n *\n */\npublic enum ModemCapability {\n\n    /** The modem has no capabilities. */\n    NONE,\n    /**\n     * The modem supports the Plain Old Telephone Service (analog wired telephone\n     * network).\n     */\n    POTS,\n    /** The modem supports EVDO revision 0, A or B. */\n    EVDO,\n    /**\n     * The modem supports at least one of GSM, GPRS, EDGE, UMTS, HSDPA, HSUPA or\n     * HSPA+ technologies.\n     */\n    GSM_UMTS,\n    /** The modem has LTE capabilities */\n    LTE,\n    /** The modem supports Iridium technology. */\n    IRIDIUM,\n    /** The modem supports 5GNR. */\n    FIVE_GNR,\n    /** The modem supports TDS. */\n    TDS,\n    /** The modem supports all capabilities. */\n    ANY;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemConnectionStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The status of a modem.\n *\n */\npublic enum ModemConnectionStatus {\n    /** The modem is unavailable */\n    FAILED,\n    /** The modem is in an unknown state. */\n    UNKNOWN,\n    /** The modem is being initialised. */\n    INITIALIZING,\n    /** The modem is locked. */\n    LOCKED,\n    /** The modem is disabled and powered off. */\n    DISABLED,\n    /** The modem is disabling. */\n    DISABLING,\n    /** The modem is enabling. */\n    ENABLING,\n    /** The modem is enabled but not registered to a network provider. */\n    ENABLED,\n    /** The modem is searching for a network provider. */\n    SEARCHING,\n    /** The modem is registered to a network provider. */\n    REGISTERED,\n    /** The modem is disconnecting. */\n    DISCONNECTING,\n    /** The modem is connecting. */\n    CONNECTING,\n    /** The modem is connected. */\n    CONNECTED;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemGpsMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.net.status.modem;\n\n/*\n * The GPS mode supported by the modem.\n *\n * @since 2.8\n */\npublic enum ModemGpsMode {\n    /*\n     * Unmanaged GPS mode. In this mode the GPS device of the modem will be setup but not directly managed, therefore\n     * freeing the serial port for other services to use.\n     */\n    UNMANAGED,\n    /*\n     * Managed GPS mode. In this mode the GPS device of the modem will be setup and directly managed (typically by\n     * ModemManager) therefore the serial port won't be available for other services to use.\n     */\n    MANAGED_GPS\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemInterfaceStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.eclipse.kura.net.modem.ModemConnectionType;\nimport org.eclipse.kura.net.status.NetworkInterfaceStatus;\nimport org.eclipse.kura.net.status.NetworkInterfaceType;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Class that contains specific properties to describe the status of a\n * Modem interface.\n *\n */\n@ProviderType\npublic class ModemInterfaceStatus extends NetworkInterfaceStatus {\n\n    private final String model;\n    private final String manufacturer;\n    private final String serialNumber;\n    private final String softwareRevision;\n    private final String hardwareRevision;\n    private final String primaryPort;\n    private final Map<String, ModemPortType> ports;\n    private final List<Set<ModemCapability>> supportedModemCapabilities;\n    private final Set<ModemCapability> currentModemCapabilities;\n    private final ModemPowerState powerState;\n    private final Set<ModemModePair> supportedModes;\n    private final ModemModePair currentModes;\n    private final Set<ModemBand> supportedBands;\n    private final Set<ModemBand> currentBands;\n    private final boolean gpsSupported;\n    private final Set<ModemGpsMode> supportedGpsModes;\n    private final List<Sim> availableSims;\n    private final boolean simLocked;\n    private final List<Bearer> bearers;\n    private final ModemConnectionType connectionType;\n    private final ModemConnectionStatus connectionStatus;\n    private final Set<AccessTechnology> accessTechnologies;\n    private final int signalQuality;\n    private final int signalStrength;\n    private final RegistrationStatus registrationStatus;\n    private final String operatorName;\n\n    private ModemInterfaceStatus(ModemInterfaceStatusBuilder builder) {\n        super(builder);\n        this.model = builder.model;\n        this.manufacturer = builder.manufacturer;\n        this.serialNumber = builder.serialNumber;\n        this.softwareRevision = builder.softwareRevision;\n        this.hardwareRevision = builder.hardwareRevision;\n        this.primaryPort = builder.primaryPort;\n        this.ports = builder.ports;\n        this.supportedModemCapabilities = builder.supportedModemCapabilities;\n        this.currentModemCapabilities = builder.currentModemCapabilities;\n        this.powerState = builder.powerState;\n        this.supportedModes = builder.supportedModes;\n        this.currentModes = builder.currentModes;\n        this.supportedBands = builder.supportedBands;\n        this.currentBands = builder.currentBands;\n        this.gpsSupported = builder.gpsSupported;\n        this.supportedGpsModes = builder.supportedGpsModes;\n        this.availableSims = builder.availableSims;\n        this.simLocked = builder.simLocked;\n        this.bearers = builder.bearers;\n        this.connectionType = builder.connectionType;\n        this.connectionStatus = builder.connectionStatus;\n        this.accessTechnologies = builder.accessTechnologies;\n        this.signalQuality = builder.signalQuality;\n        this.registrationStatus = builder.registrationStatus;\n        this.operatorName = builder.operatorName;\n        this.signalStrength = builder.signalStrength;\n    }\n\n    public String getModel() {\n        return this.model;\n    }\n\n    public String getManufacturer() {\n        return this.manufacturer;\n    }\n\n    public String getSerialNumber() {\n        return this.serialNumber;\n    }\n\n    public String getSoftwareRevision() {\n        return this.softwareRevision;\n    }\n\n    public String getHardwareRevision() {\n        return this.hardwareRevision;\n    }\n\n    public String getPrimaryPort() {\n        return this.primaryPort;\n    }\n\n    public Map<String, ModemPortType> getPorts() {\n        return this.ports;\n    }\n\n    /**\n     * @deprecated use {@link ModemInterfaceStatus#getAllSupportedModemCapabilities()} instead.\n     *             This method returns only the first ModemCapability if any.\n     * @since 2.8\n     */\n    @Deprecated\n    public Set<ModemCapability> getSupportedModemCapabilities() {\n        if (!this.supportedModemCapabilities.isEmpty()) {\n            return this.supportedModemCapabilities.get(0);\n        } else {\n            return new HashSet<ModemCapability>();\n        }\n    }\n\n    /**\n     * @since 2.8\n     */\n    public List<Set<ModemCapability>> getAllSupportedModemCapabilities() {\n        return this.supportedModemCapabilities;\n    }\n\n    public Set<ModemCapability> getCurrentModemCapabilities() {\n        return this.currentModemCapabilities;\n    }\n\n    public ModemPowerState getPowerState() {\n        return this.powerState;\n    }\n\n    public Set<ModemModePair> getSupportedModes() {\n        return this.supportedModes;\n    }\n\n    public ModemModePair getCurrentModes() {\n        return this.currentModes;\n    }\n\n    public Set<ModemBand> getSupportedBands() {\n        return this.supportedBands;\n    }\n\n    public Set<ModemBand> getCurrentBands() {\n        return this.currentBands;\n    }\n\n    public Boolean isGpsSupported() {\n        return this.gpsSupported;\n    }\n\n    /*\n     * @since 2.8\n     */\n    public Set<ModemGpsMode> getSupporteGpsModes() {\n        return this.supportedGpsModes;\n    }\n\n    public List<Sim> getAvailableSims() {\n        return this.availableSims;\n    }\n\n    public boolean isSimLocked() {\n        return this.simLocked;\n    }\n\n    public List<Bearer> getBearers() {\n        return this.bearers;\n    }\n\n    public ModemConnectionType getConnectionType() {\n        return this.connectionType;\n    }\n\n    public ModemConnectionStatus getConnectionStatus() {\n        return this.connectionStatus;\n    }\n\n    public Set<AccessTechnology> getAccessTechnologies() {\n        return this.accessTechnologies;\n    }\n\n    public int getSignalQuality() {\n        return this.signalQuality;\n    }\n\n    public RegistrationStatus getRegistrationStatus() {\n        return this.registrationStatus;\n    }\n\n    public String getOperatorName() {\n        return this.operatorName;\n    }\n\n    public int getSignalStrength() {\n        return this.signalStrength;\n    }\n\n    public static ModemInterfaceStatusBuilder builder() {\n        return new ModemInterfaceStatusBuilder();\n    }\n\n    public static class ModemInterfaceStatusBuilder extends NetworkInterfaceStatusBuilder<ModemInterfaceStatusBuilder> {\n\n        private static final String NA = \"N/A\";\n        private String model = NA;\n        private String manufacturer = NA;\n        private String serialNumber = NA;\n        private String softwareRevision = NA;\n        private String hardwareRevision = NA;\n        private String primaryPort = NA;\n        private Map<String, ModemPortType> ports = Collections.emptyMap();\n        private List<Set<ModemCapability>> supportedModemCapabilities = new ArrayList<>();\n        private Set<ModemCapability> currentModemCapabilities = EnumSet.of(ModemCapability.NONE);\n        private ModemPowerState powerState = ModemPowerState.UNKNOWN;\n        private Set<ModemModePair> supportedModes = Collections.emptySet();\n        private ModemModePair currentModes = new ModemModePair(Collections.emptySet(), ModemMode.NONE);\n        private Set<ModemBand> supportedBands = EnumSet.of(ModemBand.UNKNOWN);\n        private Set<ModemBand> currentBands = EnumSet.of(ModemBand.UNKNOWN);\n        private boolean gpsSupported = false;\n        private Set<ModemGpsMode> supportedGpsModes = Collections.emptySet();\n        private List<Sim> availableSims = Collections.emptyList();\n        private boolean simLocked = false;\n        private List<Bearer> bearers = Collections.emptyList();\n        private ModemConnectionType connectionType = ModemConnectionType.DirectIP;\n        private ModemConnectionStatus connectionStatus = ModemConnectionStatus.UNKNOWN;\n        private Set<AccessTechnology> accessTechnologies = EnumSet.of(AccessTechnology.UNKNOWN);\n        private int signalQuality = 0;\n        private int signalStrength = -113;\n        private RegistrationStatus registrationStatus = RegistrationStatus.UNKNOWN;\n        private String operatorName = NA;\n\n        public ModemInterfaceStatusBuilder withModel(String model) {\n            this.model = model;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withManufacturer(String manufacturer) {\n            this.manufacturer = manufacturer;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withSerialNumber(String serialNumber) {\n            this.serialNumber = serialNumber;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withSoftwareRevision(String softwareRevision) {\n            this.softwareRevision = softwareRevision;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withHardwareRevision(String hardwareRevision) {\n            this.hardwareRevision = hardwareRevision;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withPrimaryPort(String primaryPort) {\n            this.primaryPort = primaryPort;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withPorts(Map<String, ModemPortType> ports) {\n            this.ports = ports;\n            return getThis();\n        }\n\n        /**\n         * @deprecated To add all the supported capabilities, call this method multiple times with every set of\n         *             ModemCapability.\n         *             Instead use\n         *             {@link ModemInterfaceStatus#withAllSupportedModemCapabilities(List<Set<ModemCapability>>\n         *             supportedModemCapabilities)} to add the ModemCapabilities all at once.\n         * @since 2.8\n         */\n        @Deprecated\n        public ModemInterfaceStatusBuilder withSupportedModemCapabilities(\n                Set<ModemCapability> supportedModemCapabilities) {\n            this.supportedModemCapabilities.add(supportedModemCapabilities);\n            return getThis();\n        }\n\n        /**\n         * @since 2.8\n         */\n        public ModemInterfaceStatusBuilder withAllSupportedModemCapabilities(\n                List<Set<ModemCapability>> supportedModemCapabilities) {\n            this.supportedModemCapabilities = supportedModemCapabilities;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withCurrentModemCapabilities(Set<ModemCapability> currentModemCapabilities) {\n            this.currentModemCapabilities = currentModemCapabilities;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withPowerState(ModemPowerState powerState) {\n            this.powerState = powerState;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withSupportedModes(Set<ModemModePair> supportedModes) {\n            this.supportedModes = supportedModes;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withCurrentModes(ModemModePair currentModes) {\n            this.currentModes = currentModes;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withSupportedBands(Set<ModemBand> supportedBands) {\n            this.supportedBands = supportedBands;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withCurrentBands(Set<ModemBand> currentBands) {\n            this.currentBands = currentBands;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withGpsSupported(Boolean gpsSupported) {\n            this.gpsSupported = gpsSupported;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withSupportedGpsModes(Set<ModemGpsMode> supportedGpsModes) {\n            this.supportedGpsModes = supportedGpsModes;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withAvailableSims(List<Sim> availableSims) {\n            this.availableSims = availableSims;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withSimLocked(boolean simLocked) {\n            this.simLocked = simLocked;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withBearers(List<Bearer> bearers) {\n            this.bearers = bearers;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withConnectionType(ModemConnectionType connectionType) {\n            this.connectionType = connectionType;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withConnectionStatus(ModemConnectionStatus connectionStatus) {\n            this.connectionStatus = connectionStatus;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withAccessTechnologies(Set<AccessTechnology> accessTechnologies) {\n            this.accessTechnologies = accessTechnologies;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withSignalQuality(int signalQuality) {\n            this.signalQuality = signalQuality;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withSignalStrength(int signalStrength) {\n            this.signalStrength = signalStrength;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withRegistrationStatus(RegistrationStatus registrationStatus) {\n            this.registrationStatus = registrationStatus;\n            return getThis();\n        }\n\n        public ModemInterfaceStatusBuilder withOperatorName(String operatorName) {\n            this.operatorName = operatorName;\n            return getThis();\n        }\n\n        @Override\n        public ModemInterfaceStatus build() {\n            withType(NetworkInterfaceType.MODEM);\n            return new ModemInterfaceStatus(this);\n        }\n\n        @Override\n        public ModemInterfaceStatusBuilder getThis() {\n            return this;\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + Objects.hash(this.accessTechnologies, this.availableSims, this.bearers,\n                this.connectionStatus, this.connectionType, this.currentBands, this.currentModemCapabilities,\n                this.currentModes, this.gpsSupported, this.hardwareRevision, this.manufacturer, this.model,\n                this.operatorName, this.ports, this.powerState, this.primaryPort, this.registrationStatus,\n                this.signalStrength, this.serialNumber, this.signalQuality, this.simLocked, this.softwareRevision,\n                this.supportedBands, this.supportedModemCapabilities, this.supportedModes);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj) || getClass() != obj.getClass()) {\n            return false;\n        }\n        ModemInterfaceStatus other = (ModemInterfaceStatus) obj;\n        return Objects.equals(this.accessTechnologies, other.accessTechnologies)\n                && Objects.equals(this.availableSims, other.availableSims)\n                && Objects.equals(this.bearers, other.bearers) && this.connectionStatus == other.connectionStatus\n                && this.connectionType == other.connectionType && Objects.equals(this.currentBands, other.currentBands)\n                && Objects.equals(this.currentModemCapabilities, other.currentModemCapabilities)\n                && Objects.equals(this.currentModes, other.currentModes) && this.gpsSupported == other.gpsSupported\n                && Objects.equals(this.hardwareRevision, other.hardwareRevision)\n                && Objects.equals(this.manufacturer, other.manufacturer) && Objects.equals(this.model, other.model)\n                && Objects.equals(this.operatorName, other.operatorName) && Objects.equals(this.ports, other.ports)\n                && this.powerState == other.powerState && Objects.equals(this.primaryPort, other.primaryPort)\n                && this.registrationStatus == other.registrationStatus && this.signalStrength == other.signalStrength\n                && Objects.equals(this.serialNumber, other.serialNumber) && this.signalQuality == other.signalQuality\n                && this.simLocked == other.simLocked && Objects.equals(this.softwareRevision, other.softwareRevision)\n                && Objects.equals(this.supportedBands, other.supportedBands)\n                && Objects.equals(this.supportedModemCapabilities, other.supportedModemCapabilities)\n                && Objects.equals(this.supportedModes, other.supportedModes);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The generic access mode a modem supports.\n *\n */\npublic enum ModemMode {\n    NONE,\n    CS,\n    MODE_2G,\n    MODE_3G,\n    MODE_4G,\n    MODE_5G,\n    ANY;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemModePair.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\nimport java.util.Objects;\nimport java.util.Set;\n\n/**\n * This class represents a pair of Modem Mode list and a preferred one.\n *\n */\npublic class ModemModePair {\n\n    private final Set<ModemMode> modes;\n    private final ModemMode preferredMode;\n\n    public ModemModePair(Set<ModemMode> modes, ModemMode preferredMode) {\n        this.modes = modes;\n        this.preferredMode = preferredMode;\n    }\n\n    public Set<ModemMode> getModes() {\n        return this.modes;\n    }\n\n    public ModemMode getPreferredMode() {\n        return this.preferredMode;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.modes, this.preferredMode);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        ModemModePair other = (ModemModePair) obj;\n        return Objects.equals(this.modes, other.modes) && this.preferredMode == other.preferredMode;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemPortType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The type of a modem port.\n *\n */\npublic enum ModemPortType {\n\n    UNKNOWN,\n    NET,\n    AT,\n    QCDM,\n    GPS,\n    QMI,\n    MBIM,\n    AUDIO,\n    IGNORED;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemPowerState.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The power state of a modem.\n *\n */\npublic enum ModemPowerState {\n\n    UNKNOWN,\n    OFF,\n    LOW,\n    ON;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/RegistrationStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The registration status of a modem when connected to a mobile network.\n *\n */\npublic enum RegistrationStatus {\n\n    IDLE,\n    HOME,\n    SEARCHING,\n    DENIED,\n    UNKNOWN,\n    ROAMING,\n    HOME_SMS_ONLY,\n    ROAMING_SMS_ONLY,\n    EMERGENCY_ONLY,\n    HOME_CSFB_NOT_PREFERRED,\n    ROAMING_CSFB_NOT_PREFERRED,\n    ATTACHED_RLOS;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/Sim.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\nimport java.util.Objects;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class contains all relevant properties to describe a SIM (Subscriber\n * Identity Module).\n *\n */\n@ProviderType\npublic class Sim {\n\n    private final boolean active;\n    private final boolean primary;\n    private final String iccid;\n    private final String imsi;\n    private final String eid;\n    private final String operatorName;\n    private final String operatorIdentifier;\n    private final SimType simType;\n    private final ESimStatus eSimStatus;\n\n    public Sim(SimBuilder builder) {\n        this.active = builder.active;\n        this.primary = builder.primary;\n        this.iccid = builder.iccid;\n        this.imsi = builder.imsi;\n        this.eid = builder.eid;\n        this.operatorName = builder.operatorName;\n        this.operatorIdentifier = builder.operatorIdentifier;\n        this.simType = builder.simType;\n        this.eSimStatus = builder.eSimStatus;\n    }\n\n    public boolean isActive() {\n        return this.active;\n    }\n\n    public boolean isPrimary() {\n        return this.primary;\n    }\n\n    public String getIccid() {\n        return this.iccid;\n    }\n\n    public String getImsi() {\n        return this.imsi;\n    }\n\n    public String getEid() {\n        return this.eid;\n    }\n\n    public String getOperatorName() {\n        return this.operatorName;\n    }\n\n    /**\n     * \n     * @since 2.8\n     */\n    public String getOperatorIdentifier() {\n        return this.operatorIdentifier;\n    }\n\n    public SimType getSimType() {\n        return this.simType;\n    }\n\n    public ESimStatus geteSimStatus() {\n        return this.eSimStatus;\n    }\n\n    public static SimBuilder builder() {\n        return new SimBuilder();\n    }\n\n    public static final class SimBuilder {\n\n        private boolean active;\n        private boolean primary;\n        private String iccid = \"NA\";\n        private String imsi = \"NA\";\n        private String eid = \"NA\";\n        private String operatorName = \"NA\";\n        private String operatorIdentifier = \"NA\";\n        private SimType simType = SimType.UNKNOWN;\n        private ESimStatus eSimStatus = ESimStatus.UNKNOWN;\n\n        private SimBuilder() {\n        }\n\n        public SimBuilder withActive(boolean active) {\n            this.active = active;\n            return this;\n        }\n\n        public SimBuilder withPrimary(boolean primary) {\n            this.primary = primary;\n            return this;\n        }\n\n        public SimBuilder withIccid(String iccid) {\n            this.iccid = iccid;\n            return this;\n        }\n\n        public SimBuilder withImsi(String imsi) {\n            this.imsi = imsi;\n            return this;\n        }\n\n        public SimBuilder withEid(String eid) {\n            this.eid = eid;\n            return this;\n        }\n\n        public SimBuilder withOperatorName(String operatorName) {\n            this.operatorName = operatorName;\n            return this;\n        }\n\n        /**\n         * \n         * @since 2.8\n         */\n        public SimBuilder withOperatorIdentifier(String operatorIdentifier) {\n            this.operatorIdentifier = operatorIdentifier;\n            return this;\n        }\n\n        public SimBuilder withSimType(SimType simType) {\n            this.simType = simType;\n            return this;\n        }\n\n        public SimBuilder withESimStatus(ESimStatus eSimStatus) {\n            this.eSimStatus = eSimStatus;\n            return this;\n        }\n\n        public Sim build() {\n            return new Sim(this);\n        }\n\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.active, this.primary, this.eSimStatus, this.eid, this.iccid, this.imsi,\n                this.operatorName, this.operatorIdentifier, this.simType);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        Sim other = (Sim) obj;\n        return this.active == other.active && this.primary == other.primary && this.eSimStatus == other.eSimStatus\n                && Objects.equals(this.eid, other.eid) && Objects.equals(this.iccid, other.iccid)\n                && Objects.equals(this.imsi, other.imsi) && Objects.equals(this.operatorName, other.operatorName)\n                && Objects.equals(this.operatorIdentifier, other.operatorIdentifier) && this.simType == other.simType;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/SimType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.modem;\n\n/**\n * The SIM (Subscriber Identity Module) type.\n *\n */\npublic enum SimType {\n\n    UNKNOWN,\n    PHYSICAL,\n    ESIM;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides classes for describing the status of a modem interface.\n *\n */\npackage org.eclipse.kura.net.status.modem;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides interfaces and classes for describing the network status of a\n * device.\n *\n */\npackage org.eclipse.kura.net.status;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/vlan/VlanInterfaceStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Areti and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Areti\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.vlan;\n\nimport java.util.Objects;\n\nimport org.eclipse.kura.net.status.NetworkInterfaceStatus;\nimport org.eclipse.kura.net.status.NetworkInterfaceType;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Class that contains specific properties to describe the status of a\n * Vlan.\n *\n */\n@ProviderType\npublic class VlanInterfaceStatus extends NetworkInterfaceStatus {\n\n    private final String parentInterface;\n    private final int vlanId;\n    \n    private VlanInterfaceStatus(VlanInterfaceStatusBuilder builder) {\n        super(builder);\n        this.vlanId = builder.vlanId;\n        this.parentInterface = builder.parentInterface;\n    }\n\n    public int getVlanId() {\n        return this.vlanId;\n    }\n\n    public String getParentInterface() {\n        return this.parentInterface;\n    }\n    \n    public static VlanInterfaceStatusBuilder builder() {\n        return new VlanInterfaceStatusBuilder();\n    }\n\n    public static class VlanInterfaceStatusBuilder\n        extends NetworkInterfaceStatusBuilder<VlanInterfaceStatusBuilder> {\n        \n        private String parentInterface;\n        private int vlanId;\n        \n        public VlanInterfaceStatusBuilder withParentInterface(String parentInterface) {\n            this.parentInterface = parentInterface;\n            return getThis();\n        }\n        \n        public VlanInterfaceStatusBuilder withVlanId(int vlanId) {\n            this.vlanId = vlanId;\n            return getThis();\n        }\n        \n        public VlanInterfaceStatus build() {\n            withType(NetworkInterfaceType.VLAN);\n            return new VlanInterfaceStatus(this);\n        }\n        \n        public VlanInterfaceStatusBuilder getThis() {\n            return this;\n        }\n    }\n    \n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + Objects.hash(this.vlanId, this.parentInterface);\n        return result;\n    }\n    \n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj) || getClass() != obj.getClass()) {\n            return false;\n        }\n        VlanInterfaceStatus other = (VlanInterfaceStatus) obj;\n        return this.vlanId == other.vlanId \n                && Objects.equals(this.parentInterface, other.getParentInterface());\n    }\n    \n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/vlan/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Areti and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Areti\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides classes for describing the status of a Vlan.\n *\n */\npackage org.eclipse.kura.net.status.vlan;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiAccessPoint.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.wifi;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class describes a Wifi Access Point.\n * It can be used both for describing a detected AP after a WiFi scan when in\n * Station mode and the provided AP when in Master (or Access Point) mode.\n *\n */\n@ProviderType\npublic class WifiAccessPoint {\n\n    private final String ssid;\n    private final byte[] hardwareAddress;\n    private final WifiChannel channel;\n    private final WifiMode mode;\n    private final long maxBitrate;\n    private final int signalQuality;\n    private final int signalStrength;\n    private final Set<WifiSecurity> wpaSecurity;\n    private final Set<WifiSecurity> rsnSecurity;\n    private final Set<WifiFlag> flags;\n\n    private WifiAccessPoint(WifiAccessPointBuilder builder) {\n        this.ssid = builder.ssid;\n        this.hardwareAddress = builder.hardwareAddress;\n        this.channel = builder.channel;\n        this.mode = builder.mode;\n        this.maxBitrate = builder.maxBitrate;\n        this.signalQuality = builder.signalQuality;\n        this.signalStrength = builder.signalStrength;\n        this.wpaSecurity = builder.wpaSecurity;\n        this.rsnSecurity = builder.rsnSecurity;\n        this.flags = builder.flags;\n    }\n\n    /**\n     * Return the Service Set IDentifier of the WiFi network.\n     * \n     * @return a string representing the ssid\n     */\n    public String getSsid() {\n        return this.ssid;\n    }\n\n    /**\n     * Return the Basic Service Set IDentifier of the WiFi access point.\n     * \n     * @return a string representing the the bssid\n     */\n    public byte[] getHardwareAddress() {\n        return this.hardwareAddress;\n    }\n\n    /**\n     * Return the {@link WifiChannel} used by the WiFi access point.\n     * \n     * @return a {@link WifiChannel} object\n     */\n    public WifiChannel getChannel() {\n        return this.channel;\n    }\n\n    /**\n     * Return the {@link WifiMode} of the wireless interface.\n     * \n     * @return a {@link WifiMode} entry\n     */\n    public WifiMode getMode() {\n        return this.mode;\n    }\n\n    /**\n     * Return the maximum bitrate this access point is capable of.\n     * \n     * @return a long value representing the bitrate\n     */\n    public long getMaxBitrate() {\n        return this.maxBitrate;\n    }\n\n    /**\n     * Return the current signal quality of the access point in percentage.\n     * \n     * @return an integer value between 0 and 100\n     */\n    public int getSignalQuality() {\n        return this.signalQuality;\n    }\n\n    /**\n     * Return the current signal strength of the access point in dBm.\n     * \n     * @return an integer value representing the rssi\n     */\n    public int getSignalStrength() {\n        return this.signalStrength;\n    }\n\n    /**\n     * Return the WPA capabilities of the access point.\n     * \n     * @return a set of {@link WifiSecurity} representing the capabilities\n     */\n    public Set<WifiSecurity> getWpaSecurity() {\n        return this.wpaSecurity;\n    }\n\n    /**\n     * Return the RSN capabilities of the access point.\n     * \n     * @return a set of {@link WifiSecurity} representing the capabilities\n     */\n    public Set<WifiSecurity> getRsnSecurity() {\n        return this.rsnSecurity;\n    }\n\n    /**\n     * Return the capabilities of the access point.\n     * \n     * @return a set of {@link WifiFlag} representing the capabilities\n     * \n     * @since 2.8\n     */\n    public Set<WifiFlag> getFlags() {\n        return this.flags;\n    }\n\n    public static WifiAccessPointBuilder builder() {\n        return new WifiAccessPointBuilder();\n    }\n\n    public static final class WifiAccessPointBuilder {\n\n        private String ssid;\n        private byte[] hardwareAddress;\n        private WifiChannel channel;\n        private WifiMode mode;\n        private long maxBitrate;\n        private int signalQuality;\n        private int signalStrength;\n        private Set<WifiSecurity> wpaSecurity = Collections.emptySet();\n        private Set<WifiSecurity> rsnSecurity = Collections.emptySet();\n        private Set<WifiFlag> flags = Collections.emptySet();\n\n        private WifiAccessPointBuilder() {\n        }\n\n        public WifiAccessPointBuilder withSsid(String ssid) {\n            this.ssid = ssid;\n            return this;\n        }\n\n        public WifiAccessPointBuilder withHardwareAddress(byte[] hardwareAddress) {\n            this.hardwareAddress = hardwareAddress;\n            return this;\n        }\n\n        public WifiAccessPointBuilder withChannel(WifiChannel channel) {\n            this.channel = channel;\n            return this;\n        }\n\n        public WifiAccessPointBuilder withMode(WifiMode mode) {\n            this.mode = mode;\n            return this;\n        }\n\n        public WifiAccessPointBuilder withMaxBitrate(long maxBitrate) {\n            this.maxBitrate = maxBitrate;\n            return this;\n        }\n\n        public WifiAccessPointBuilder withSignalQuality(int signalQuality) {\n            this.signalQuality = signalQuality;\n            return this;\n        }\n\n        public WifiAccessPointBuilder withSignalStrength(int signalStrength) {\n            this.signalStrength = signalStrength;\n            return this;\n        }\n\n        public WifiAccessPointBuilder withWpaSecurity(Set<WifiSecurity> wpaSecurity) {\n            this.wpaSecurity = wpaSecurity;\n            return this;\n        }\n\n        public WifiAccessPointBuilder withRsnSecurity(Set<WifiSecurity> rsnSecurity) {\n            this.rsnSecurity = rsnSecurity;\n            return this;\n        }\n\n        public WifiAccessPointBuilder withFlags(Set<WifiFlag> flags) {\n            this.flags = flags;\n            return this;\n        }\n\n        public WifiAccessPoint build() {\n            return new WifiAccessPoint(this);\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + Arrays.hashCode(this.hardwareAddress);\n        result = prime * result + Objects.hash(this.channel, this.maxBitrate, this.mode, this.rsnSecurity,\n                this.signalQuality, this.signalStrength, this.ssid, this.wpaSecurity, this.flags);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        WifiAccessPoint other = (WifiAccessPoint) obj;\n        return Objects.equals(this.channel, other.channel) && Arrays.equals(this.hardwareAddress, other.hardwareAddress)\n                && this.maxBitrate == other.maxBitrate && this.mode == other.mode\n                && Objects.equals(this.rsnSecurity, other.rsnSecurity) && this.signalQuality == other.signalQuality\n                && Objects.equals(this.ssid, other.ssid) && Objects.equals(this.signalStrength, other.signalStrength)\n                && Objects.equals(this.wpaSecurity, other.wpaSecurity) && Objects.equals(this.flags, other.flags);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiCapability.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.wifi;\n\n/**\n * The capability of a WiFi interface.\n *\n */\npublic enum WifiCapability {\n    /** The device has no encryption/authentication capabilities */\n    NONE,\n    /** The device supports 40/64-bit WEP encryption. */\n    CIPHER_WEP40,\n    /** The device supports 104/128-bit WEP encryption. */\n    CIPHER_WEP104,\n    /** The device supports the TKIP encryption. */\n    CIPHER_TKIP,\n    /** The device supports the AES/CCMP encryption. */\n    CIPHER_CCMP,\n    /** The device supports the WPA1 encryption/authentication protocol. */\n    WPA,\n    /** The device supports the WPA2/RSN encryption/authentication protocol. */\n    RSN,\n    /** The device supports Access Point mode. */\n    AP,\n    /** The device supports Ad-Hoc mode. */\n    ADHOC,\n    /** The device reports frequency capabilities. */\n    FREQ_VALID,\n    /** The device supports 2.4GHz frequencies. */\n    FREQ_2GHZ,\n    /** The device supports 5GHz frequencies. */\n    FREQ_5GHZ,\n    /** The device supports mesh points. */\n    MESH,\n    /** The device supports WPA2 in IBSS networks */\n    IBSS_RSN;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiChannel.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.wifi;\n\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represent a WiFi channel, providing the channel number, frequency,\n * status and other useful informations.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class WifiChannel {\n\n    private final int channel;\n    private final int frequency;\n    private final Optional<Boolean> disabled;\n    private final Optional<Float> attenuation;\n    private final Optional<Boolean> noInitiatingRadiation;\n    private final Optional<Boolean> radarDetection;\n\n    private WifiChannel(Builder builder) {\n        this.channel = builder.channel;\n        this.frequency = builder.frequency;\n        this.disabled = builder.disabled;\n        this.attenuation = builder.attenuation;\n        this.noInitiatingRadiation = builder.noInitiatingRadiation;\n        this.radarDetection = builder.radarDetection;\n    }\n\n    public int getChannel() {\n        return this.channel;\n    }\n\n    public int getFrequency() {\n        return this.frequency;\n    }\n\n    public Optional<Float> getAttenuation() {\n        return this.attenuation;\n    }\n\n    public Optional<Boolean> getNoInitiatingRadiation() {\n        return this.noInitiatingRadiation;\n    }\n\n    public Optional<Boolean> getRadarDetection() {\n        return this.radarDetection;\n    }\n\n    public Optional<Boolean> getDisabled() {\n        return this.disabled;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.attenuation, this.channel, this.disabled, this.frequency, this.noInitiatingRadiation,\n                this.radarDetection);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        WifiChannel other = (WifiChannel) obj;\n        return Objects.equals(this.attenuation, other.attenuation) && this.channel == other.channel\n                && Objects.equals(this.disabled, other.disabled) && this.frequency == other.frequency\n                && Objects.equals(this.noInitiatingRadiation, other.noInitiatingRadiation)\n                && Objects.equals(this.radarDetection, other.radarDetection);\n    }\n\n    public static Builder builder(final int channel, final int frequency) {\n        return new Builder(channel, frequency);\n    }\n\n    public static final class Builder {\n\n        private int channel;\n        private int frequency;\n        private Optional<Boolean> disabled = Optional.empty();\n        private Optional<Float> attenuation = Optional.empty();\n        private Optional<Boolean> noInitiatingRadiation = Optional.empty();\n        private Optional<Boolean> radarDetection = Optional.empty();\n\n        private Builder(final int channel, final int frequency) {\n            this.channel = channel;\n            this.frequency = frequency;\n        }\n\n        public Builder withChannel(int channel) {\n            this.channel = channel;\n            return this;\n        }\n\n        public Builder withFrequency(int frequency) {\n            this.frequency = frequency;\n            return this;\n        }\n\n        public Builder withDisabled(final boolean disabled) {\n            this.disabled = Optional.of(disabled);\n            return this;\n        }\n\n        public Builder withAttenuation(final float attenuation) {\n            this.attenuation = Optional.of(attenuation);\n            return this;\n        }\n\n        public Builder withNoInitiatingRadiation(final boolean noInitiatingRadiation) {\n            this.noInitiatingRadiation = Optional.of(noInitiatingRadiation);\n            return this;\n        }\n\n        public Builder withRadarDetection(final boolean radarDetection) {\n            this.radarDetection = Optional.of(radarDetection);\n            return this;\n        }\n\n        public WifiChannel build() {\n            return new WifiChannel(this);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiFlag.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.wifi;\n\n/**\n * Flags describing the capabilities of an Access Point.\n * \n * @since 2.8\n */\npublic enum WifiFlag {\n    /** None */\n    NONE,\n    /** Supports authentication and encryption */\n    PRIVACY,\n    /** Supports WPS */\n    WPS,\n    /** Supports push-button based WPS */\n    WPS_PBC,\n    /** Supports PIN based WPS */\n    WPS_PIN;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiInterfaceStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.wifi;\n\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.net.status.NetworkInterfaceStatus;\nimport org.eclipse.kura.net.status.NetworkInterfaceType;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Class that contains specific properties to describe the status of a\n * WiFi interface.\n *\n */\n@ProviderType\npublic class WifiInterfaceStatus extends NetworkInterfaceStatus {\n\n    private final Set<WifiCapability> capabilities;\n    private final List<WifiChannel> channels;\n    private final String countryCode;\n    private final WifiMode mode;\n    private final Optional<WifiAccessPoint> activeWifiAccessPoint;\n    private final List<WifiAccessPoint> availableWifiAccessPoints;\n\n    private WifiInterfaceStatus(WifiInterfaceStatusBuilder builder) {\n        super(builder);\n        this.capabilities = builder.capabilities;\n        this.channels = builder.channels;\n        this.countryCode = builder.countryCode;\n        this.mode = builder.mode;\n        this.activeWifiAccessPoint = builder.currentWifiAccessPoint;\n        this.availableWifiAccessPoints = builder.availableWifiAccessPoints;\n    }\n\n    public Set<WifiCapability> getCapabilities() {\n        return this.capabilities;\n    }\n\n    public List<WifiChannel> getChannels() {\n        return this.channels;\n    }\n\n    public String getCountryCode() {\n        return this.countryCode;\n    }\n\n    public WifiMode getMode() {\n        return this.mode;\n    }\n\n    public Optional<WifiAccessPoint> getActiveWifiAccessPoint() {\n        return this.activeWifiAccessPoint;\n    }\n\n    public List<WifiAccessPoint> getAvailableWifiAccessPoints() {\n        return this.availableWifiAccessPoints;\n    }\n\n    public static WifiInterfaceStatusBuilder builder() {\n        return new WifiInterfaceStatusBuilder();\n    }\n\n    public static class WifiInterfaceStatusBuilder extends NetworkInterfaceStatusBuilder<WifiInterfaceStatusBuilder> {\n\n        private Set<WifiCapability> capabilities = EnumSet.of(WifiCapability.NONE);\n        private List<WifiChannel> channels = Collections.emptyList();\n        private String countryCode = \"00\";\n        private WifiMode mode = WifiMode.UNKNOWN;\n        private Optional<WifiAccessPoint> currentWifiAccessPoint = Optional.empty();\n        private List<WifiAccessPoint> availableWifiAccessPoints = Collections.emptyList();\n\n        public WifiInterfaceStatusBuilder withCapabilities(Set<WifiCapability> capabilities) {\n            this.capabilities = capabilities;\n            return this;\n        }\n\n        public WifiInterfaceStatusBuilder withWifiChannels(List<WifiChannel> channels) {\n            this.channels = channels;\n            return this;\n        }\n\n        public WifiInterfaceStatusBuilder withCountryCode(String countryCode) {\n            this.countryCode = countryCode;\n            return this;\n        }\n\n        public WifiInterfaceStatusBuilder withMode(WifiMode mode) {\n            this.mode = mode;\n            return this;\n        }\n\n        public WifiInterfaceStatusBuilder withActiveWifiAccessPoint(Optional<WifiAccessPoint> currentWifiAccessPoint) {\n            this.currentWifiAccessPoint = currentWifiAccessPoint;\n            return this;\n        }\n\n        public WifiInterfaceStatusBuilder withAvailableWifiAccessPoints(\n                List<WifiAccessPoint> availableWifiAccessPoints) {\n            this.availableWifiAccessPoints = availableWifiAccessPoints;\n            return this;\n        }\n\n        @Override\n        public WifiInterfaceStatus build() {\n            withType(NetworkInterfaceType.WIFI);\n            return new WifiInterfaceStatus(this);\n        }\n\n        @Override\n        public WifiInterfaceStatusBuilder getThis() {\n            return this;\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + Objects.hash(this.activeWifiAccessPoint, this.availableWifiAccessPoints,\n                this.capabilities, this.countryCode, this.mode, this.channels);\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj) || getClass() != obj.getClass()) {\n            return false;\n        }\n        WifiInterfaceStatus other = (WifiInterfaceStatus) obj;\n        return Objects.equals(this.activeWifiAccessPoint, other.activeWifiAccessPoint)\n                && Objects.equals(this.availableWifiAccessPoints, other.availableWifiAccessPoints)\n                && Objects.equals(this.capabilities, other.capabilities)\n                && Objects.equals(this.countryCode, other.countryCode) && this.mode == other.mode\n                && Objects.equals(this.channels, other.channels);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.wifi;\n\n/**\n * Modes of operation for WiFi interfaces\n */\npublic enum WifiMode {\n    /** Mode is unknown. */\n    UNKNOWN,\n    /** Uncoordinated network without central infrastructure. */\n    ADHOC,\n    /** Client mode - Coordinated network with one or more central controllers. */\n    INFRA,\n    /**\n     * Access Point Mode - Coordinated network with one or more central controllers.\n     */\n    MASTER,\n    /** IEEE 802.11s mesh network. */\n    MESH;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiRadioMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.wifi;\n\n/**\n * Types of WiFi radio modes\n */\npublic enum WifiRadioMode {\n\n    UNKNOWN,\n    RADIO_MODE_80211A,\n    RADIO_MODE_80211B,\n    RADIO_MODE_80211G,\n    RADIO_MODE_80211NHT20,\n    RADIO_MODE_80211NHT40_BELOW,\n    RADIO_MODE_80211NHT40_ABOVE,\n    RADIO_MODE_80211_AC;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiSecurity.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.status.wifi;\n\n/**\n * Flags describing the security capabilities of an Access Point.\n */\npublic enum WifiSecurity {\n    /** None */\n    NONE,\n    /** Supports pairwise 40-bit WEP encryption. */\n    PAIR_WEP40,\n    /** Supports pairwise 104-bit WEP encryption. */\n    PAIR_WEP104,\n    /** Supports pairwise TKIP encryption. */\n    PAIR_TKIP,\n    /** Supports pairwise CCMP encryption. */\n    PAIR_CCMP,\n    /** Supports a group 40-bit WEP cipher. */\n    GROUP_WEP40,\n    /** Supports a group 104-bit WEP cipher. */\n    GROUP_WEP104,\n    /** Supports a group TKIP cipher. */\n    GROUP_TKIP,\n    /** Supports a group CCMP cipher. */\n    GROUP_CCMP,\n    /** Supports PSK key management. */\n    KEY_MGMT_PSK,\n    /** Supports 802.1x key management. */\n    KEY_MGMT_802_1X,\n    /** Supports WPA/RSN Simultaneous Authentication of Equals. */\n    KEY_MGMT_SAE,\n    /** Supports WPA/RSN Opportunistic Wireless Encryption. */\n    KEY_MGMT_OWE,\n    /** Supports WPA/RSN Opportunistic Wireless Encryption transition mode. */\n    KEY_MGMT_OWE_TM,\n    /** Supports WPA3 Enterprise Suite-B 192 bit mode */\n    KEY_MGMT_EAP_SUITE_B_192;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides classes for describing the status of a WiFi interface.\n *\n */\npackage org.eclipse.kura.net.status.wifi;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/vlan/VlanInterface.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Areti and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Areti\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.vlan;\n\nimport java.util.List;\n\nimport org.eclipse.kura.net.NetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Network interface for Vlans.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.6\n */\n@ProviderType\npublic interface VlanInterface<T extends NetInterfaceAddress> extends NetInterface<T> {\n\n    /**\n     * Indicates Vlan configuration flags.\n     *\n     * @return\n     */\n    public int getFlags();\n    \n    /**\n     * Indicates the underlying physical interface to the Vlan.\n     *\n     * @return\n     */\n    public String getParentInterface();\n    \n    /**\n     * Indicates the configured Vlan tag.\n     *\n     * @return\n     */\n    public int getVlanId();\n    \n    /**\n     * Indicates configured ingress priority map.\n     *\n     * @return\n     */\n    public List<String> getIngressMap();\n    \n    /**\n     * Indicates configured egress priority map.\n     *\n     * @return\n     */\n    public List<String> getEgressMap();\n     \n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/vlan/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Areti and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Areti\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides interfaces for instances and configurations of  Vlan.\n *\n */\npackage org.eclipse.kura.net.vlan;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiAccessPoint.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport java.util.EnumSet;\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The WifiAccessPoint models an access point for a Wifi network.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface WifiAccessPoint {\n\n    /**\n     * The Service Set Identifier identifying the access point.\n     *\n     * @return\n     */\n    public String getSSID();\n\n    /**\n     * The hardware address (BSSID) of the access point.\n     *\n     * @return\n     */\n    public byte[] getHardwareAddress();\n\n    /**\n     * The radio channel frequency in use by the access point, in MHz.\n     *\n     * @return\n     */\n    public long getFrequency();\n\n    /**\n     * \n     *\n     * The Wi-Fi channel number in use by the access point.\n     * \n     * @return Wi-Fi channel number\n     * @since 2.2\n     */\n    public int getChannel();\n\n    /**\n     * \n     * \n     * Describes the operating mode of the access point.\n     *\n     * @return\n     */\n    public WifiMode getMode();\n\n    /**\n     * The bitrates this access point is capable of, in kilobits/second (Kb/s).\n     *\n     * @return\n     */\n    public List<Long> getBitrate();\n\n    /**\n     * The current signal quality of the access point, in percent.\n     *\n     * @return\n     */\n    public int getStrength();\n\n    /**\n     * Describes the access point's capabilities according to WPA (Wifi Protected Access).\n     *\n     * @return\n     */\n    public EnumSet<WifiSecurity> getWpaSecurity();\n\n    /**\n     * Describes the access point's capabilities according to the RSN (Robust Secure Network) protocol.\n     *\n     * @return\n     */\n    public EnumSet<WifiSecurity> getRsnSecurity();\n\n    /**\n     * Describes the access point's capabilities\n     *\n     * @return\n     */\n    public List<String> getCapabilities();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiAccessPointAddedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * Emitted when a new access point is found by the device.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic class WifiAccessPointAddedEvent extends Event {\n\n    /** Topic of the WifiAccessPointAddedEvent */\n    public static final String NETWORK_EVENT_ACCESSPOINT_ADDED_TOPIC = \"org/eclipse/kura/net/NetworkEvent/AccessPoint/ADDED\";\n\n    /** Name of the property to access the network interface name */\n    public static final String NETWORK_EVENT_INTERFACE_PROPERTY = \"network.interface\";\n\n    /** Name of the property to access the access point */\n    public static final String NETWORK_EVENT_ACCESS_POINT_PROPERTY = \"network.access.point\";\n\n    public WifiAccessPointAddedEvent(Map<String, ?> properties) {\n        super(NETWORK_EVENT_ACCESSPOINT_ADDED_TOPIC, properties);\n    }\n\n    /**\n     * Returns the network interface name.\n     *\n     * @return\n     */\n    public String getInterfaceName() {\n        return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the added access point.\n     *\n     * @return\n     */\n    public WifiAccessPoint getAccessPoint() {\n        return (WifiAccessPoint) getProperty(NETWORK_EVENT_ACCESS_POINT_PROPERTY);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiAccessPointRemovedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * Emitted when an access point disappears from view of the device.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic class WifiAccessPointRemovedEvent extends Event {\n\n    /** Topic of the WifiAccessPointAddedEvent */\n    public static final String NETWORK_EVENT_ACCESSPOINT_REMOVED_TOPIC = \"org/eclipse/kura/net/NetworkEvent/AccessPoint/REMOVED\";\n\n    /** Name of the property to access the network interface name */\n    public static final String NETWORK_EVENT_INTERFACE_PROPERTY = \"network.interface\";\n\n    /** Name of the property to access the access point */\n    public static final String NETWORK_EVENT_ACCESS_POINT_PROPERTY = \"network.access.point\";\n\n    public WifiAccessPointRemovedEvent(Map<String, ?> properties) {\n        super(NETWORK_EVENT_ACCESSPOINT_REMOVED_TOPIC, properties);\n    }\n\n    /**\n     * Returns the network interface name.\n     *\n     * @return\n     */\n    public String getInterfaceName() {\n        return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the removed access point.\n     *\n     * @return\n     */\n    public WifiAccessPoint getAccessPoint() {\n        return (WifiAccessPoint) getProperty(NETWORK_EVENT_ACCESS_POINT_PROPERTY);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiBgscan.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Background Scan container class\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class WifiBgscan {\n\n    private WifiBgscanModule module = null;\n    private int shortInterval = 0;\n    private int longInterval = 0;\n    private int rssiThreshold = 0;\n\n    public WifiBgscan(WifiBgscanModule module, int shortInterval, int rssiThreshold, int longInterval) {\n\n        this.module = module;\n        this.shortInterval = shortInterval;\n        this.rssiThreshold = rssiThreshold;\n        this.longInterval = longInterval;\n    }\n\n    public WifiBgscan(WifiBgscan bgscan) {\n\n        this.module = bgscan.module;\n        this.shortInterval = bgscan.shortInterval;\n        this.rssiThreshold = bgscan.rssiThreshold;\n        this.longInterval = bgscan.longInterval;\n    }\n\n    public WifiBgscan(String str) {\n\n        if (str == null || str.length() == 0) {\n            this.module = WifiBgscanModule.NONE;\n        } else {\n            String[] sa = str.split(\":\");\n            if (sa[0].equals(\"simple\")) {\n                this.module = WifiBgscanModule.SIMPLE;\n            } else if (sa[0].equals(\"learn\")) {\n                this.module = WifiBgscanModule.LEARN;\n            }\n\n            this.shortInterval = Integer.parseInt(sa[1]);\n            this.rssiThreshold = Integer.parseInt(sa[2]);\n            this.longInterval = Integer.parseInt(sa[3]);\n        }\n    }\n\n    public WifiBgscanModule getModule() {\n        return this.module;\n    }\n\n    public int getShortInterval() {\n        return this.shortInterval;\n    }\n\n    public int getLongInterval() {\n        return this.longInterval;\n    }\n\n    public int getRssiThreshold() {\n        return this.rssiThreshold;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + this.longInterval;\n        result = prime * result + (this.module == null ? 0 : this.module.hashCode());\n        result = prime * result + this.rssiThreshold;\n        result = prime * result + this.shortInterval;\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        WifiBgscan other = (WifiBgscan) obj;\n        if (this.longInterval != other.longInterval) {\n            return false;\n        }\n        if (this.module != other.module) {\n            return false;\n        }\n        if (this.rssiThreshold != other.rssiThreshold) {\n            return false;\n        }\n        if (this.shortInterval != other.shortInterval) {\n            return false;\n        }\n        return true;\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see java.lang.Object#toString()\n     */\n    @Override\n    public String toString() {\n\n        StringBuffer sb = new StringBuffer();\n        if (this.module == WifiBgscanModule.SIMPLE) {\n            sb.append(\"simple:\");\n        } else if (this.module == WifiBgscanModule.LEARN) {\n            sb.append(\"learn:\");\n        } else {\n            sb.append(\"\");\n            return sb.toString();\n        }\n\n        sb.append(this.shortInterval);\n        sb.append(':');\n        sb.append(this.rssiThreshold);\n        sb.append(':');\n        sb.append(this.longInterval);\n\n        return sb.toString();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiBgscanModule.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\n/**\n * Module for background scan\n */\npublic enum WifiBgscanModule {\n\n    NONE(0x00),\n    SIMPLE(0x01),\n    LEARN(0x02);\n\n    private int code;\n\n    private WifiBgscanModule(int code) {\n        this.code = code;\n    }\n\n    public static WifiBgscanModule parseCode(int code) {\n        for (WifiBgscanModule module : WifiBgscanModule.values()) {\n            if (module.code == code) {\n                return module;\n            }\n        }\n        return null;\n    }\n\n    public static int getCode(WifiBgscanModule modules) {\n        for (WifiBgscanModule module : WifiBgscanModule.values()) {\n            if (module == modules) {\n                return module.code;\n            }\n        }\n        return -1;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiChannel.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Sterwen-Technology and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Sterwen-Technology\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.net.wifi;\n\nimport java.util.Objects;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Wifi channel and Frequency in MHz\n * \n * @since 2.2\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class WifiChannel {\n\n    /** Wifi channel **/\n    private Integer channel;\n\n    /** Wifi frequency in MHz **/\n    private Integer frequency;\n\n    private Float attenuation;\n\n    private Boolean noInitiatingRadiation;\n\n    private Boolean radarDetection;\n\n    private Boolean disabled;\n\n    public WifiChannel(int channel, Integer frequency) {\n        this.channel = channel;\n        this.frequency = frequency;\n    }\n\n    public Integer getChannel() {\n        return channel;\n    }\n\n    public void setChannel(Integer channel) {\n        this.channel = channel;\n    }\n\n    public Integer getFrequency() {\n        return frequency;\n    }\n\n    public void setFrequency(Integer frequency) {\n        this.frequency = frequency;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public Boolean isNoInitiatingRadiation() {\n        return noInitiatingRadiation;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public void setNoInitiatingRadiation(Boolean noInitiatingRadiation) {\n        this.noInitiatingRadiation = noInitiatingRadiation;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public Boolean isRadarDetection() {\n        return radarDetection;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public void setRadarDetection(Boolean radarDetection) {\n        this.radarDetection = radarDetection;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public Boolean isDisabled() {\n        return disabled;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public void setDisabled(Boolean disabled) {\n        this.disabled = disabled;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public Float getAttenuation() {\n        return attenuation;\n    }\n\n    /**\n     * @since 2.3\n     */\n    public void setAttenuation(Float attenuation) {\n        this.attenuation = attenuation;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(channel, frequency);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        WifiChannel other = (WifiChannel) obj;\n        return Objects.equals(channel, other.channel) && Objects.equals(frequency, other.frequency);\n    }\n\n    @Override\n    public String toString() {\n        return \"WifiChannel [channel=\" + channel + \", frequency=\" + frequency + \", attenuation=\" + attenuation\n                + \", noInitiatingRadiation=\" + noInitiatingRadiation + \", radarDetection=\" + radarDetection\n                + \", disabled=\" + disabled + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiCiphers.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\n/**\n * Wifi Ciphers enum\n */\npublic enum WifiCiphers {\n\n    CCMP_TKIP(0x00),\n    TKIP(0x01),\n    CCMP(0x02);\n\n    private int code;\n\n    private WifiCiphers(int code) {\n        this.code = code;\n    }\n\n    public static WifiCiphers parseCode(int code) {\n        for (WifiCiphers cipher : WifiCiphers.values()) {\n            if (cipher.code == code) {\n                return cipher;\n            }\n        }\n\n        return null;\n    }\n\n    public static int getCode(WifiCiphers ciphers) {\n        for (WifiCiphers cipher : WifiCiphers.values()) {\n            if (cipher == ciphers) {\n                return cipher.code;\n            }\n        }\n\n        return -1;\n    }\n\n    public static String toString(WifiCiphers ciphers) {\n\n        String ret = null;\n        for (WifiCiphers cipher : WifiCiphers.values()) {\n            if (cipher == ciphers) {\n                if (cipher == WifiCiphers.CCMP_TKIP) {\n                    ret = \"CCMP TKIP\";\n                } else if (cipher == WifiCiphers.TKIP) {\n                    ret = \"TKIP\";\n                } else if (cipher == WifiCiphers.CCMP) {\n                    ret = \"CCMP\";\n                }\n            }\n        }\n\n        return ret;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiClientMonitorListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * @deprecated since 3.0\n */\n@ConsumerType\n@Deprecated\npublic interface WifiClientMonitorListener {\n\n    /**\n     * @since 2.0\n     */\n    public void setWifiSignalLevel(String interfaceName, int signalLevel);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiClientMonitorService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Marker interface for wifi client monitoring service\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic interface WifiClientMonitorService {\n\n    public void registerListener(WifiClientMonitorListener listener);\n\n    public void unregisterListener(WifiClientMonitorListener listener);\n\n    /**\n     * Return the signal level on the given wireless interface\n     * \n     * @param interfaceName\n     *                      the name of the wireless interface\n     * @param ssid\n     *                      the name of the ssid the interface is attached to\n     * @return an integer number representing the rssi\n     * @throws KuraException\n     * \n     * @deprecated since 2.4. Use {@link getSignalLevel(String interfaceName, String\n     *             ssid, boolean recompute)} instead.\n     */\n    @Deprecated\n    public int getSignalLevel(String interfaceName, String ssid) throws KuraException;\n\n    /**\n     * Return the signal level on the given wireless interface\n     * \n     * @param interfaceName\n     *                      the name of the wireless interface\n     * @param ssid\n     *                      the name of the ssid the interface is attached to\n     * @param recompute\n     *                      if set to true, the rssi is recomputed. Otherwise a\n     *                      cached value is returned\n     * @return an integer number representing the rssi\n     * @throws KuraException\n     * \n     * @since 2.4\n     */\n    public int getSignalLevel(String interfaceName, String ssid, boolean recompute) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Sterwen-Technology\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.net.NetConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Configuration for a wifi interface based on IPv4 addresses.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class WifiConfig implements NetConfig {\n\n    /** Mode for the configuration **/\n    private WifiMode mode;\n\n    /** SSID of the the wifi interface **/\n    private String ssid;\n\n    /** Channel(s) supported by the wifi interface **/\n    private int[] channels;\n\n    /** Security mode of the interface **/\n    private WifiSecurity security;\n\n    /** Supported pairwise ciphers **/\n    private WifiCiphers pairwiseCiphers;\n\n    /** Supported group ciphers **/\n    private WifiCiphers groupCiphers;\n\n    /** The passkey for the wifi interface **/\n    private Password passkey;\n\n    /** The hardware mode **/\n    private String hwMode;\n\n    /** Radio mode **/\n    private WifiRadioMode radioMode;\n\n    /** Background scan **/\n    private WifiBgscan bgscan;\n\n    /** Ping Access Point **/\n    private boolean pingAccessPoint = false;\n\n    /** Ignore SSID **/\n    private boolean ignoreSSID;\n\n    /** The driver of the wifi interface **/\n    private String driver;\n\n    /** Channels Frequencies **/\n    List<WifiChannel> channelFrequencies;\n\n    /** Wifi Country Code **/\n    private String wifiCountryCode;\n\n    public WifiConfig() {\n        this(WifiMode.UNKNOWN, \"\", new int[] { 1 }, WifiSecurity.NONE, \"\", \"b\", null);\n    }\n\n    /**\n     * @deprecated since 2.3. Use {@link WifiConfig(WifiMode mode, String ssid, int[] channels, WifiSecurity security,\n     *             String passkey, String hwMode, WifiBgscan bgscan)}\n     */\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    @Deprecated\n    public WifiConfig(WifiMode mode, String ssid, int[] channels, WifiSecurity security, String passkey, String hwMode,\n            boolean broadcast, WifiBgscan bgscan) {\n        this(mode, ssid, channels, security, passkey, hwMode, bgscan);\n    }\n\n    /**\n     * @since 2.3\n     *\n     * @param mode\n     *            for the configuration as {@link WifiMode}\n     * @param ssid\n     *            of the the wifi interface\n     * @param channels\n     *            supported by the wifi interface\n     * @param security\n     *            mode of the interface as {@link WifiSecurity}\n     * @param passkey\n     *            for the wifi interface\n     * @param hwMode\n     *            the hardware mode\n     * @param bgscan\n     *            the background scan\n     */\n    public WifiConfig(WifiMode mode, String ssid, int[] channels, WifiSecurity security, String passkey, String hwMode,\n            WifiBgscan bgscan) {\n        this.mode = mode;\n        this.ssid = ssid;\n        this.channels = channels;\n        this.security = security;\n        this.passkey = new Password(passkey);\n        this.hwMode = hwMode;\n        this.bgscan = bgscan;\n        this.pairwiseCiphers = WifiCiphers.CCMP_TKIP;\n        this.groupCiphers = WifiCiphers.CCMP_TKIP;\n        this.radioMode = WifiRadioMode.RADIO_MODE_80211b;\n        this.ignoreSSID = false;\n        this.channelFrequencies = new ArrayList<>();\n        this.wifiCountryCode = \"00\";\n    }\n\n    public WifiMode getMode() {\n        return this.mode;\n    }\n\n    public void setMode(WifiMode mode) {\n        this.mode = mode;\n    }\n\n    public String getSSID() {\n        return this.ssid;\n    }\n\n    public void setSSID(String ssid) {\n        this.ssid = ssid;\n    }\n\n    public String getDriver() {\n        return this.driver;\n    }\n\n    public void setDriver(String driver) {\n        this.driver = driver;\n    }\n\n    public int[] getChannels() {\n        return this.channels;\n    }\n\n    public void setChannels(int[] channels) {\n        this.channels = channels;\n    }\n\n    public WifiSecurity getSecurity() {\n        return this.security;\n    }\n\n    public void setSecurity(WifiSecurity security) {\n        this.security = security;\n    }\n\n    public WifiCiphers getPairwiseCiphers() {\n        return this.pairwiseCiphers;\n    }\n\n    public void setPairwiseCiphers(WifiCiphers pairwise) {\n        this.pairwiseCiphers = pairwise;\n    }\n\n    public WifiCiphers getGroupCiphers() {\n        return this.groupCiphers;\n    }\n\n    public void setGroupCiphers(WifiCiphers group) {\n        this.groupCiphers = group;\n    }\n\n    public Password getPasskey() {\n        return this.passkey;\n    }\n\n    public void setPasskey(String key) {\n        if (key != null) {\n            Password psswd = new Password(key);\n            this.passkey = psswd;\n        }\n    }\n\n    public String getHardwareMode() {\n        return this.hwMode;\n    }\n\n    public void setHardwareMode(String hwMode) {\n        this.hwMode = hwMode;\n    }\n\n    public WifiRadioMode getRadioMode() {\n        return this.radioMode;\n    }\n\n    public void setRadioMode(WifiRadioMode radioMode) {\n        this.radioMode = radioMode;\n    }\n\n    /**\n     * @deprecated since 2.3\n     */\n    @Deprecated\n    public boolean getBroadcast() {\n        return false;\n    }\n\n    /**\n     * @deprecated since 2.3\n     */\n    @Deprecated\n    public void setBroadcast(boolean broadcast) {\n        // Do nothing...\n    }\n\n    public WifiBgscan getBgscan() {\n        return this.bgscan;\n    }\n\n    public void setBgscan(WifiBgscan bgscan) {\n        this.bgscan = bgscan;\n    }\n\n    public boolean pingAccessPoint() {\n        return this.pingAccessPoint;\n    }\n\n    public void setPingAccessPoint(boolean pingAP) {\n        this.pingAccessPoint = pingAP;\n    }\n\n    public boolean ignoreSSID() {\n        return this.ignoreSSID;\n    }\n\n    public void setIgnoreSSID(boolean ignoreSSID) {\n        this.ignoreSSID = ignoreSSID;\n    }\n\n    /**\n     * Get the Wi-Fi country code\n     *\n     * @return Wi-Fi country code in ISO 3166-1 alpha-2\n     * @since 2.2\n     */\n    public String getWifiCountryCode() {\n        return this.wifiCountryCode;\n    }\n\n    /**\n     * Set the Wi-Fi country code\n     *\n     * @param wifiCountryCode\n     *            Wi-Fi Country code in ISO 3166-1 alpha-2 format\n     * @since 2.2\n     */\n    public void setWifiCountryCode(String wifiCountryCode) {\n        this.wifiCountryCode = wifiCountryCode;\n    }\n\n    /**\n     * Get the list of Wi-Fi channels and frequencies\n     *\n     * @return List of Wi-Fi channels and frequencies\n     * @since 2.2\n     */\n    public List<WifiChannel> getChannelFrequencies() {\n        return this.channelFrequencies;\n    }\n\n    /**\n     * Set the list of channel frequencies\n     *\n     * @param channelFrequencies\n     *            list of Wi-Fi channels and relative frequencies\n     * @since 2.2\n     */\n    public void setChannelFrequencies(List<WifiChannel> channelFrequencies) {\n        this.channelFrequencies = channelFrequencies;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 29;\n        int result = super.hashCode();\n\n        result = prime * result + (this.mode == null ? 0 : this.mode.hashCode());\n        result = prime * result + (this.ssid == null ? 0 : this.ssid.hashCode());\n        result = prime * result + (this.driver == null ? 0 : this.driver.hashCode());\n        result = prime * result + (this.wifiCountryCode == null ? 0 : this.wifiCountryCode.hashCode());\n\n        if (this.channels != null) {\n            for (int channel : this.channels) {\n                result = prime * result + channel;\n            }\n        } else {\n            result = prime * result;\n        }\n\n        if (this.channelFrequencies != null) {\n            for (WifiChannel wc : this.channelFrequencies) {\n                result = prime * result + wc.hashCode();\n            }\n        } else {\n            result = prime * result;\n        }\n\n        result = prime * result + (this.security == null ? 0 : this.security.hashCode());\n        result = prime * result + (this.passkey == null ? 0 : this.passkey.hashCode());\n        result = prime * result + (this.hwMode == null ? 0 : this.hwMode.hashCode());\n        result = prime * result + (this.radioMode == null ? 0 : this.radioMode.hashCode());\n\n        result = prime * result + (this.pairwiseCiphers == null ? 0 : WifiCiphers.getCode(this.pairwiseCiphers));\n\n        result = prime * result + (this.groupCiphers == null ? 0 : WifiCiphers.getCode(this.groupCiphers));\n\n        if (this.bgscan != null) {\n\n            result = prime * result\n                    + (this.bgscan.getModule() == null ? 0 : WifiBgscanModule.getCode(this.bgscan.getModule()));\n\n            result = prime * result + this.bgscan.getRssiThreshold();\n\n            result = prime * result + this.bgscan.getShortInterval();\n\n            result = prime * result + this.bgscan.getLongInterval();\n        } else {\n            result = prime * result;\n        }\n\n        result = prime * result + (this.pingAccessPoint ? 1 : 0);\n\n        result = prime * result + (this.ignoreSSID ? 1 : 0);\n\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (!(obj instanceof WifiConfig)) {\n            return false;\n        }\n\n        WifiConfig other = (WifiConfig) obj;\n\n        if (!compare(this.mode, other.mode) || !compare(this.ssid, other.ssid) || !compare(this.driver, other.driver)\n                || !Arrays.equals(this.channels, other.channels)) {\n            return false;\n        }\n        if (!compare(this.wifiCountryCode, other.wifiCountryCode)) {\n            return false;\n        }\n        if (!compare(this.security, other.security)) {\n            return false;\n        }\n        if (!compare(this.pairwiseCiphers, other.pairwiseCiphers)) {\n            return false;\n        }\n        if (!compare(this.groupCiphers, other.groupCiphers)) {\n            return false;\n        }\n        if (!compare(this.passkey.toString(), other.passkey.toString())) {\n            return false;\n        }\n        if (!compare(this.hwMode, other.hwMode)) {\n            return false;\n        }\n        if (!compare(this.radioMode, other.radioMode)) {\n            return false;\n        }\n        if (!compare(this.bgscan, other.bgscan)) {\n            return false;\n        }\n        if (this.pingAccessPoint != other.pingAccessPoint()) {\n            return false;\n        }\n        if (this.ignoreSSID != other.ignoreSSID()) {\n            return false;\n        }\n        return true;\n    }\n\n    private boolean compare(Object obj1, Object obj2) {\n        return obj1 == null ? obj2 == null : obj1.equals(obj2);\n    }\n\n    @Override\n    public boolean isValid() {\n        return this.mode != null;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"WifiConfig [\");\n        if (this.mode != null) {\n            sb.append(\"mode: \").append(this.mode).append(\" :: \");\n        }\n        if (this.ssid != null) {\n            sb.append(\"ssid: \").append(this.ssid).append(\" :: \");\n        }\n        sb.append(\"ignoreSSID: \").append(this.ignoreSSID).append(\" :: \");\n\n        if (this.driver != null) {\n            sb.append(\"driver: \").append(this.driver).append(\" :: \");\n        }\n        if (this.channels != null && this.channels.length > 0) {\n            sb.append(\"channels: \");\n            for (int i = 0; i < this.channels.length; i++) {\n                sb.append(this.channels[i]);\n                if (i + i < this.channels.length) {\n                    sb.append(\",\");\n                }\n            }\n            sb.append(\" :: \");\n        }\n        if (this.security != null) {\n            sb.append(\"security: \").append(this.security).append(\" :: \");\n        }\n        if (this.pairwiseCiphers != null) {\n            sb.append(\"pairwiseCiphers: \").append(this.pairwiseCiphers).append(\" :: \");\n        }\n        if (this.groupCiphers != null) {\n            sb.append(\"groupCiphers: \").append(this.groupCiphers).append(\" :: \");\n        }\n        if (this.passkey != null) {\n            sb.append(\"passkey: \").append(this.passkey).append(\" :: \");\n        }\n        if (this.hwMode != null) {\n            sb.append(\"hwMode: \").append(this.hwMode).append(\" :: \");\n        }\n        if (this.radioMode != null) {\n            sb.append(\"radioMode: \").append(this.radioMode).append(\" :: \");\n        }\n        if (this.bgscan != null) {\n            sb.append(\"bgscan: \").append(this.bgscan).append(\" :: \");\n        }\n        if (this.wifiCountryCode != null) {\n            sb.append(\"countryCode: \").append(this.wifiCountryCode).append(\" :: \");\n        }\n        if (this.channelFrequencies != null) {\n            sb.append(\"channelFrequencies: \");\n            int i = 0;\n            for (WifiChannel wc : this.channelFrequencies) {\n                sb.append(wc);\n                if (i++ != this.channelFrequencies.size() - 1) {\n                    sb.append(\",\");\n                }\n            }\n        }\n        sb.append(\"]\");\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiHotspotInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport java.util.EnumSet;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n * @deprecated since 3.0\n */\n@ProviderType\n@Deprecated\npublic class WifiHotspotInfo {\n\n    private final String ssid;\n    private final String macAddress;\n    private final int signalLevel;\n    private final int channel;\n    private final int frequency;\n    private final WifiSecurity security;\n    private EnumSet<WifiSecurity> pairCiphers;\n    private EnumSet<WifiSecurity> groupCiphers;\n\n    public WifiHotspotInfo(String ssid, String macAddress, int signalLevel, int channel, int frequency,\n            WifiSecurity security) {\n        super();\n        this.ssid = ssid;\n        this.macAddress = macAddress;\n        this.signalLevel = signalLevel;\n        this.channel = channel;\n        this.frequency = frequency;\n        this.security = security;\n    }\n\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    public WifiHotspotInfo(String ssid, String macAddress, int signalLevel, int channel, int frequency,\n            WifiSecurity security, EnumSet<WifiSecurity> pairCiphers, EnumSet<WifiSecurity> groupCiphers) {\n        this(ssid, macAddress, signalLevel, channel, frequency, security);\n        this.pairCiphers = pairCiphers;\n        this.groupCiphers = groupCiphers;\n    }\n\n    public String getSsid() {\n        return this.ssid;\n    }\n\n    public String getMacAddress() {\n        return this.macAddress;\n    }\n\n    public int getSignalLevel() {\n        return this.signalLevel;\n    }\n\n    public int getChannel() {\n        return this.channel;\n    }\n\n    public int getFrequency() {\n        return this.frequency;\n    }\n\n    public WifiSecurity getSecurity() {\n        return this.security;\n    }\n\n    public EnumSet<WifiSecurity> getPairCiphers() {\n        return this.pairCiphers;\n    }\n\n    public EnumSet<WifiSecurity> getGroupCiphers() {\n        return this.groupCiphers;\n    }\n\n    /**\n     * @since 1.2\n     */\n    public void setPairCiphers(EnumSet<WifiSecurity> pairCiphers) {\n        this.pairCiphers = pairCiphers;\n    }\n\n    /**\n     * @since 1.2\n     */\n    public void setGroupCiphers(EnumSet<WifiSecurity> groupCiphers) {\n        this.groupCiphers = groupCiphers;\n    }\n\n    @Override\n    public String toString() {\n\n        StringBuilder sb = new StringBuilder();\n        sb.append(this.macAddress);\n        sb.append(\" :: \");\n        sb.append(this.ssid);\n        sb.append(\" :: \");\n        sb.append(this.signalLevel);\n        sb.append(\" :: \");\n        sb.append(this.channel);\n        sb.append(\" :: \");\n        sb.append(this.frequency);\n        sb.append(\" :: \");\n        sb.append(this.security);\n\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiInterface.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport java.util.List;\nimport java.util.Set;\n\nimport org.eclipse.kura.net.NetInterface;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Wifi interface\n *\n * @param <T>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface WifiInterface<T extends WifiInterfaceAddress> extends NetInterface<T> {\n\n    /**\n     * Flags describing the capabilities of a wireless device.\n     */\n    public enum Capability {\n        /** no capabilities supported */\n        NONE,\n        /** The device supports the 40-bit WEP cipher. */\n        CIPHER_WEP40,\n        /** The device supports the 104-bit WEP cipher. */\n        CIPHER_WEP104,\n        /** The device supports the TKIP cipher. */\n        CIPHER_TKIP,\n        /** The device supports the CCMP cipher. */\n        CIPHER_CCMP,\n        /** The device supports the WPA encryption/authentication protocol. */\n        WPA,\n        /** The device supports the RSN encryption/authentication protocol. */\n        RSN,\n        /**\n         * The device supports the Automatic Channel Selection.\n         *\n         * @since 2.3\n         */\n        ACS,\n        /**\n         * The device supports the Dynamic Frequencies Selection.\n         *\n         * @since 2.3\n         */\n        DFS,\n        /**\n         * The device supports Very High Throughput.\n         *\n         * @since 2.3\n         */\n        VHT;\n    }\n\n    /**\n     * Returns the the capabilities of the wireless device.\n     *\n     * @return\n     * @since 2.0\n     */\n    public Set<Capability> getCapabilities();\n\n    /**\n     * Returns a List of all InterfaceAddresses of this network interface.\n     *\n     * @return a List object with all or a subset of the InterfaceAddresss of this network interface\n     */\n    @Override\n    public List<T> getNetInterfaceAddresses();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiInterfaceAddress.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Interface for wifi status information\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface WifiInterfaceAddress extends NetInterfaceAddress {\n\n    /**\n     * The operating mode of the wireless device.\n     *\n     * @return\n     */\n    public WifiMode getMode();\n\n    /**\n     * The bit rate currently used by the wireless device, in kilobits/second (Kb/s).\n     *\n     * @return\n     */\n    public long getBitrate();\n\n    /**\n     * Returns the WifiAccessPoint that this InterfaceAddress was acquired from when in managed mode.\n     * Returns a WifiAccessPoint representing itself when in master mode.\n     *\n     * @return the WifiAccessPoint\n     */\n    public WifiAccessPoint getWifiAccessPoint();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiInterfaceAddressConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport java.util.List;\n\nimport org.eclipse.kura.net.NetConfig;\nimport org.eclipse.kura.net.NetInterfaceAddressConfig;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Contains both the wifi interface status as well as all current configurations\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface WifiInterfaceAddressConfig extends WifiInterfaceAddress, NetInterfaceAddressConfig {\n\n    /**\n     * Returns a List of NetConfig Objects associated with a given WifiInterfaceAddressConfig\n     * for a given WifiInterface\n     *\n     * @return the NetConfig Objects associated with the WifiInterfaceAddressConfig\n     */\n    @Override\n    public List<NetConfig> getConfigs();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\n/**\n * Modes of operation for wifi interfaces\n */\npublic enum WifiMode {\n    /** Mode is unknown. */\n    UNKNOWN(0x00),\n    /** Uncoordinated network without central infrastructure. */\n    ADHOC(0x01),\n    /** Client mode - Coordinated network with one or more central controllers. */\n    INFRA(0x02),\n    /** Access Point Mode - Coordinated network with one or more central controllers. */\n    MASTER(0x03);\n\n    private int code;\n\n    private WifiMode(int code) {\n        this.code = code;\n    }\n\n    public static WifiMode parseCode(int code) {\n        for (WifiMode mode : WifiMode.values()) {\n            if (mode.code == code) {\n                return mode;\n            }\n        }\n\n        return null;\n    }\n\n    public static int getCode(WifiMode wifiMode) {\n        for (WifiMode mode : WifiMode.values()) {\n            if (mode == wifiMode) {\n                return mode.code;\n            }\n        }\n        return -1;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiPassword.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.Password;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class WifiPassword extends Password {\n\n    /**\n     * WifiPassword constructor\n     *\n     * @param password\n     *            - WiFi password as {@link String}\n     */\n    public WifiPassword(String password) {\n        super(password);\n    }\n\n    /**\n     * WifiPassword constructor\n     *\n     * @param password\n     *            - - WiFi password as {@link char[]}\n     */\n    public WifiPassword(char[] password) {\n        super(password);\n    }\n\n    /**\n     * Validates WiFi password\n     *\n     * @param wifiSecurity\n     *            - WiFi security as {@link WifiSecurity}\n     * @throws KuraException\n     */\n    public void validate(WifiSecurity wifiSecurity) throws KuraException {\n        if (getPassword() == null) {\n            throw KuraException.internalError(\"the passwd can not be null\");\n        }\n        String passKey = new String(getPassword()).trim();\n        if (wifiSecurity == WifiSecurity.SECURITY_WEP) {\n            if (passKey.length() == 10) {\n                // check to make sure it is all hex\n                try {\n                    Long.parseLong(passKey, 16);\n                } catch (Exception e) {\n                    throw KuraException.internalError(\n                            \"the WEP key (passwd) must be all HEX characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f\");\n                }\n            } else if (passKey.length() == 26) {\n                String part1 = passKey.substring(0, 13);\n                String part2 = passKey.substring(13);\n\n                try {\n                    Long.parseLong(part1, 16);\n                    Long.parseLong(part2, 16);\n                } catch (Exception e) {\n                    throw KuraException.internalError(\n                            \"the WEP key (passwd) must be all HEX characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f\");\n                }\n            } else if (passKey.length() == 32) {\n                String part1 = passKey.substring(0, 10);\n                String part2 = passKey.substring(10, 20);\n                String part3 = passKey.substring(20);\n                try {\n                    Long.parseLong(part1, 16);\n                    Long.parseLong(part2, 16);\n                    Long.parseLong(part3, 16);\n                } catch (Exception e) {\n                    throw KuraException.internalError(\n                            \"the WEP key (passwd) must be all HEX characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f\");\n                }\n            } else if (!(passKey.length() == 5 || passKey.length() == 13 || passKey.length() == 16)) {\n                // not 5, 13, or 16 ASCII characters\n                throw KuraException\n                        .internalError(\"the WEP key (passwd) must be 10, 26, or 32 HEX characters in length\");\n            }\n        } else if (wifiSecurity == WifiSecurity.SECURITY_WPA || wifiSecurity == WifiSecurity.SECURITY_WPA2\n                || wifiSecurity == WifiSecurity.SECURITY_WPA_WPA2) {\n            if (passKey.length() < 8 || passKey.length() > 63) {\n                throw KuraException.internalError(\n                        \"the WPA passphrase (passwd) must be between 8 (inclusive) and 63 (inclusive) characters in length: \"\n                                + passKey);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiRadioMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\n/**\n * Types of wifi radio modes\n */\npublic enum WifiRadioMode {\n\n    RADIO_MODE_80211a(0x00),\n    RADIO_MODE_80211b(0x01),\n    RADIO_MODE_80211g(0x02),\n    RADIO_MODE_80211nHT20(0x03),\n    RADIO_MODE_80211nHT40below(0x04),\n    RADIO_MODE_80211nHT40above(0x05),\n    /**\n     * @since 2.3\n     */\n    RADIO_MODE_80211_AC(0x06);\n\n    private int code;\n\n    private WifiRadioMode(int code) {\n        this.code = code;\n    }\n\n    public static WifiRadioMode parseCode(int code) {\n        for (WifiRadioMode mode : WifiRadioMode.values()) {\n            if (mode.code == code) {\n                return mode;\n            }\n        }\n\n        return null;\n    }\n\n    public static int getCode(WifiRadioMode radioMode) {\n        for (WifiRadioMode mode : WifiRadioMode.values()) {\n            if (mode == radioMode) {\n                return mode.code;\n            }\n        }\n\n        return -1;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiSecurity.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.net.wifi;\n\n/**\n * Flags describing the security capabilities of an access point.\n */\npublic enum WifiSecurity {\n\n    /** None */\n    NONE(0x0),\n    /** Supports pairwise 40-bit WEP encryption. */\n    PAIR_WEP40(0x1),\n    /** Supports pairwise 104-bit WEP encryption. */\n    PAIR_WEP104(0x2),\n    /** Supports pairwise TKIP encryption. */\n    PAIR_TKIP(0x4),\n    /** Supports pairwise CCMP encryption. */\n    PAIR_CCMP(0x8),\n    /** Supports a group 40-bit WEP cipher. */\n    GROUP_WEP40(0x10),\n    /** Supports a group 104-bit WEP cipher. */\n    GROUP_WEP104(0x20),\n    /** Supports a group TKIP cipher. */\n    GROUP_TKIP(0x40),\n    /** Supports a group CCMP cipher. */\n    GROUP_CCMP(0x80),\n    /** Supports PSK key management. */\n    KEY_MGMT_PSK(0x100),\n    /** Supports 802.1x key management. */\n    KEY_MGMT_802_1X(0x200),\n    /** Supports no encryption. */\n    SECURITY_NONE(0x400),\n    /** Supports WEP encryption. */\n    SECURITY_WEP(0x800),\n    /** Supports WPA encryption. */\n    SECURITY_WPA(0x1000),\n    /** Supports WPA2 encryption. */\n    SECURITY_WPA2(0x2000),\n    /** Supports WPA and WPA2 encryption. */\n    SECURITY_WPA_WPA2(0x4000),\n    /** Supports WPA2 WPA3 enterprise. */\n    SECURITY_WPA2_WPA3_ENTERPRISE(0x8000),\n    /**\n     * @since 3.0\n     *        Supports WPA3 encryption.\n     */\n    SECURITY_WPA3(0x10000),\n    /**\n     * @since 3.0\n     *        Supports WPA2 and WPA3 encryption.\n     */\n    SECURITY_WPA2_WPA3(0x20000);\n\n    private int code;\n\n    private WifiSecurity(int code) {\n        this.code = code;\n    }\n\n    public static WifiSecurity parseCode(int code) {\n        for (WifiSecurity mode : WifiSecurity.values()) {\n            if (mode.code == code) {\n                return mode;\n            }\n        }\n\n        return null;\n    }\n\n    public static int getCode(WifiSecurity security) {\n        for (WifiSecurity mode : WifiSecurity.values()) {\n            if (mode == security) {\n                return mode.code;\n            }\n        }\n\n        return -1;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides interfaces for instances and configurations of wifi devices.\n *\n */\npackage org.eclipse.kura.net.wifi;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n *\n *******************************************************************************/\n/**\n * Contains the necessary classes for the framework related exceptions and error codes\n */\npackage org.eclipse.kura;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/GNSSType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.position;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic enum GNSSType {\n\n    UNKNOWN(\"Unknown\"),\n    OTHER(\"Other\"),\n    BEIDOU(\"Beidou\"),\n    GALILEO(\"Galileo\"),\n    GLONASS(\"Glonass\"),\n    GPS(\"Gps\"),\n    IRNSS(\"IRNSS\"),\n    QZSS(\"QZSS\");\n\n    private String value;\n\n    private static Map<String, GNSSType> valuesMap = new HashMap<>();\n\n    static {\n        for (GNSSType type : GNSSType.values()) {\n            valuesMap.put(type.getValue(), type);\n        }\n    }\n\n    private GNSSType(String value) {\n        this.value = value;\n    }\n\n    public String getValue() {\n        return this.value;\n    }\n\n    public static GNSSType fromValue(String value) {\n        return valuesMap.get(value);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/NmeaPosition.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.position;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The NmeaPosition class is similar to org.osgi.util.position.Position but with different units\n * and more fields.<br>\n * The following fields are equivalent to org.osgi.util.position.Position fields but in more typical\n * units (degrees instead of radians):\n * <ul>\n * <li>Longitude in degrees\n * <li>Latitude in degrees\n * <li>Track in degrees\n * <li>Altitude in meters\n * <li>Speed in m/s (this field has different getters to retrieved value in m/s, km/h or mph)\n * </ul>\n * It adds to the OSGI Position class the following fields:<br>\n * <ul>\n * <li>Fix Quality (from GPGGA)\n * <li>Number of Satellites (from GPGGA)\n * <li>DOP : Horizontal dilution of position (from GPGGA)\n * <li>3D fix (from GPGSA)\n * <li>PRNs of sats used for fix (from GPGSA)\n * <li>PDOP : Dilution of precision (from GPGSA)\n * <li>HDOP : Horizontal Dilution of precision (from GPGSA)\n * <li>VDOP : Vertical Dilution of precision (from GPGSA)\n * <li>validFix : indicator of fix validity = A:active or V:void\n * <li>latitudeHemisphere : hemisphere of the latitude = N or S\n * <li>longitudeHemisphere : hemisphere of the longitude = E or W\n * </ul>\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class NmeaPosition {\n\n    private static final double MS_TO_KMH = 3.6;\n    private static final double MS_TO_MPH = 2.24;\n\n    private double latitudeDegrees;\n    private double longitudeDegrees;\n    private double altitudeMeters;\n    private double speedMetersPerSecond;\n    private double trackDegrees;\n    private int fixQuality;\n    private int nrSatellites;\n    private double mDOP;\n    private double mPDOP;\n    private double mHDOP;\n    private double mVDOP;\n    private int m3Dfix;\n    private char validFix;\n    private char latitudeHemisphere;\n    private char longitudeHemisphere;\n\n    public NmeaPosition(double latDegrees, double lonDegrees, double altDegrees, double speedMps, double trackDegrees) {\n        this(latDegrees, lonDegrees, altDegrees, speedMps, trackDegrees, 0, 0, 0.0, 0.0, 0.0, 0.0, 0, '0', '0', '0');\n    }\n\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    public NmeaPosition(double latDegrees, double lonDegrees, double altDegrees, double speedMps, double trackDegrees,\n            int fixQuality, int nrSatellites, double dop, double pdop, double hdop, double vdop, int fix3D) {\n        this(latDegrees, lonDegrees, altDegrees, speedMps, trackDegrees, fixQuality, nrSatellites, dop, pdop, hdop,\n                vdop, fix3D, '0', '0', '0');\n    }\n\n    /**\n     * @since 2.0\n     */\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    public NmeaPosition(double latDegrees, double lonDegrees, double altDegrees, double speedMps, double trackDegrees,\n            int fixQuality, int nrSatellites, double dop, double pdop, double hdop, double vdop, int fix3D, char validF,\n            char hemiLat, char hemiLon) {\n        this.latitudeDegrees = latDegrees;\n        this.longitudeDegrees = lonDegrees;\n        this.altitudeMeters = altDegrees;\n        this.speedMetersPerSecond = speedMps;\n        this.trackDegrees = trackDegrees;\n        this.fixQuality = fixQuality;\n        this.nrSatellites = nrSatellites;\n        this.mDOP = dop;\n        this.mPDOP = pdop;\n        this.mHDOP = hdop;\n        this.mVDOP = vdop;\n        this.m3Dfix = fix3D;\n        this.validFix = validF;\n        this.latitudeHemisphere = hemiLat;\n        this.longitudeHemisphere = hemiLon;\n    }\n\n    /**\n     * Return the latitude in degrees\n     */\n    public double getLatitude() {\n        return this.latitudeDegrees;\n    }\n\n    public void setLatitude(double latitude) {\n        this.latitudeDegrees = latitude;\n    }\n\n    /**\n     * Return the longitude in degrees\n     */\n    public double getLongitude() {\n        return this.longitudeDegrees;\n    }\n\n    public void setLongitude(double longitude) {\n        this.longitudeDegrees = longitude;\n    }\n\n    /**\n     * Return the altitude in meters\n     */\n    public double getAltitude() {\n        return this.altitudeMeters;\n    }\n\n    public void setAltitude(double altitude) {\n        this.altitudeMeters = altitude;\n    }\n\n    /**\n     * Return the speed in km/h\n     */\n    public double getSpeedKmh() {\n        return this.speedMetersPerSecond * MS_TO_KMH;\n    }\n\n    /**\n     * Return the speed in mph\n     */\n    public double getSpeedMph() {\n        return this.speedMetersPerSecond * MS_TO_MPH;\n    }\n\n    /**\n     * Return the speed in m/s\n     */\n    public double getSpeed() {\n        return this.speedMetersPerSecond;\n    }\n\n    public void setSpeed(double speed) {\n        this.speedMetersPerSecond = speed;\n    }\n\n    /**\n     * Return the track in degrees\n     */\n    public double getTrack() {\n        return this.trackDegrees;\n    }\n\n    public void setTrack(double track) {\n        this.trackDegrees = track;\n    }\n\n    public int getFixQuality() {\n        return this.fixQuality;\n    }\n\n    public void setFixQuality(int fixQuality) {\n        this.fixQuality = fixQuality;\n    }\n\n    public int getNrSatellites() {\n        return this.nrSatellites;\n    }\n\n    public void setNrSatellites(int nrSatellites) {\n        this.nrSatellites = nrSatellites;\n    }\n\n    public double getDOP() {\n        return this.mDOP;\n    }\n\n    public void setDOP(double dop) {\n        this.mDOP = dop;\n    }\n\n    public double getPDOP() {\n        return this.mPDOP;\n    }\n\n    public void setPDOP(double pdop) {\n        this.mPDOP = pdop;\n    }\n\n    public double getHDOP() {\n        return this.mHDOP;\n    }\n\n    public void setHDOP(double hdop) {\n        this.mHDOP = hdop;\n    }\n\n    public double getVDOP() {\n        return this.mVDOP;\n    }\n\n    public void setVDOP(double vdop) {\n        this.mVDOP = vdop;\n    }\n\n    public int get3Dfix() {\n        return this.m3Dfix;\n    }\n\n    public void set3Dfix(int fix3D) {\n        this.m3Dfix = fix3D;\n    }\n\n    /**\n     * @since 2.0\n     */\n    public char getValidFix() {\n        return this.validFix;\n    }\n\n    /**\n     * @since 2.0\n     */\n    public void setValidFix(char validFix) {\n        this.validFix = validFix;\n    }\n\n    /**\n     * @since 2.0\n     */\n    public char getLatitudeHemisphere() {\n        return this.latitudeHemisphere;\n    }\n\n    /**\n     * @since 2.0\n     */\n    public void setLatitudeHemisphere(char latitudeHemisphere) {\n        this.latitudeHemisphere = latitudeHemisphere;\n    }\n\n    /**\n     * @since 2.0\n     */\n    public char getLongitudeHemisphere() {\n        return this.longitudeHemisphere;\n    }\n\n    /**\n     * @since 2.0\n     */\n    public void setLongitudeHemisphere(char longitudeHemisphere) {\n        this.longitudeHemisphere = longitudeHemisphere;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.position;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class PositionException extends Exception {\n\n    private static final long serialVersionUID = 2611760893640245224L;\n\n    public PositionException() {\n        // TODO Auto-generated constructor stub\n    }\n\n    public PositionException(String message) {\n        super(message);\n        // TODO Auto-generated constructor stub\n    }\n\n    public PositionException(Throwable cause) {\n        super(cause);\n        // TODO Auto-generated constructor stub\n    }\n\n    public PositionException(String message, Throwable cause) {\n        super(message, cause);\n        // TODO Auto-generated constructor stub\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.position;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n@ConsumerType\npublic interface PositionListener {\n\n    public void newNmeaSentence(String nmeaSentence);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionLockedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.position;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * PositionLockedEvent is raised when a valid GPS position has been acquired.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class PositionLockedEvent extends Event {\n\n    /** Topic of the PositionLockedEvent */\n    public static final String POSITION_LOCKED_EVENT_TOPIC = \"org/eclipse/kura/position/locked\";\n\n    public PositionLockedEvent(Map<String, ?> properties) {\n        super(POSITION_LOCKED_EVENT_TOPIC, properties);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionLostEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.position;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * PositionLostEvent is raised when GPS position has been lost.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class PositionLostEvent extends Event {\n\n    /** Topic of the PositionLostEvent */\n    public static final String POSITION_LOST_EVENT_TOPIC = \"org/eclipse/kura/position/lost\";\n\n    public PositionLostEvent(Map<String, ?> properties) {\n        super(POSITION_LOST_EVENT_TOPIC, properties);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.position;\n\nimport java.time.LocalDateTime;\nimport java.util.Set;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.util.position.Position;\n\n/**\n * This interface provides methods getting a geographic position.\n * The OSGI Position class represents a geographic location, based on the WGS84 System\n * (World Geodetic System 1984).\n * <p>\n * Position(Measurement lat, Measurement lon, Measurement alt, Measurement speed, Measurement track)\n * <p>\n * The interface also return a NmeaPosition, subclass of Position\n *\n * @see org.eclipse.kura.position.NmeaPosition NmeaPosition\n * @see org.osgi.util.position.Position Position\n * @see org.osgi.util.measurement.Measurement Measurement\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface PositionService {\n\n    /**\n     * Returns the current geographic position.<br>\n     * The org.osgi.util.measurement.Measurement class is used to represent the values that make up a position:\n     * <ul>\n     * <li>getLongitude() : returns the longitude of this position in radians. Can be null.\n     * <li>getLatitude() : returns the latitude of this position in radians. Can be null.\n     * <li>getSpeed() : returns the ground speed of this position in meters per second. Can be null.\n     * <li>getTrack() : Returns the track of this position in radians as a compass heading. The track is the\n     * extrapolation of\n     * previous previously measured positions to a future position. Can be null.\n     * </ul>\n     *\n     * @see org.osgi.util.position.Position Position\n     */\n    public Position getPosition();\n\n    /**\n     * Returns the current NMEA geographic position.\n     * <ul>\n     * <li>getLongitude() : returns the longitude of this position in degrees.\n     * <li>getLatitude() : returns the latitude of this position in degrees.\n     * <li>getSpeedKmh() : returns the ground speed of this position in km/h.\n     * <li>getSpeedMph() : returns the ground speed of this position in mph.\n     * <li>getTrack() : Returns the track of this position in degrees as a compass heading.\n     * </ul>\n     *\n     * @see org.eclipse.kura.position.NmeaPosition NmeaPosition\n     * \n     * @deprecated Since 2.3 use {@link #getPosition()}. Access to underlying gps data layer is discouraged.\n     * \n     */\n    @Deprecated\n    public NmeaPosition getNmeaPosition();\n\n    /**\n     * Returns the current NMEA time from GGA or ZDA sentence\n     * \n     * @throws UnsupportedOperetaionException\n     *             {@link PositionServiceProvider} could not support this method.\n     * \n     * @deprecated Since 2.3 use {@link #getDateTime()}. Access to underlying gps data layer is discouraged.\n     * \n     */\n    @Deprecated\n    public String getNmeaTime();\n\n    /**\n     * Returns the current NMEA date from ZDA sentence\n     * \n     * @throws UnsupportedOperetaionException\n     *             {@link PositionServiceProvider} could not support this method.\n     * \n     * @deprecated Since 2.3 use {@link #getDateTime()}. Access to underlying gps data layer is discouraged.\n     * \n     */\n    @Deprecated\n    public String getNmeaDate();\n\n    /**\n     * Returns the current date from {@link PositionServiceProvider}. Returned DateTime is in UTC TimeZone.\n     *\n     * @since 2.3\n     */\n    public LocalDateTime getDateTime();\n\n    /**\n     * Returns true if a valid geographic position has been received.\n     */\n    public boolean isLocked();\n\n    /**\n     * @deprecated since version 2.3\n     *             Returns the last sentence received from the gps.\n     */\n    @Deprecated\n    public String getLastSentence();\n\n    /**\n     * Returns the GNSS System used to get the position information @reference GNSSType. Could be one or more system\n     * (eg: GPS + GLONASS).\n     * \n     * If empty, no recognized GNSS System Type is available.\n     * \n     * @since 2.8\n     */\n    public Set<GNSSType> getGnssTypes();\n\n    /**\n     * Registers position listener\n     *\n     * @param listenerId\n     *            - listener ID as {@link String}\n     * @param positionListener\n     *            - position listener as {@link PositionListener}\n     */\n    public void registerListener(String listenerId, PositionListener positionListener);\n\n    /**\n     * Unregisters position listener\n     *\n     * @param listenerId\n     *            - listener ID as {@link String}\n     */\n    public void unregisterListener(String listenerId);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Contains service to acquire global position.\n *\n */\npackage org.eclipse.kura.position;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/FloodingProtectionConfigurationChangeEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.security;\n\nimport java.util.Map;\n\nimport org.osgi.service.event.Event;\n\n/**\n * @since 2.2\n */\npublic class FloodingProtectionConfigurationChangeEvent extends Event {\n\n    public static final String FP_EVENT_CONFIG_CHANGE_TOPIC = \"org/eclipse/kura/floodingprotection/event/FP_EVENT_CONFIG_CHANGE_TOPIC\";\n\n    public FloodingProtectionConfigurationChangeEvent(Map<String, ?> properties) {\n        super(FP_EVENT_CONFIG_CHANGE_TOPIC, properties);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/FloodingProtectionConfigurationService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.security;\n\nimport java.util.Set;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface is used to provide the configuration for the flooding protection.\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.2\n */\n@ProviderType\npublic interface FloodingProtectionConfigurationService {\n\n    /**\n     * Return a set of IPv4 firewall rules for the filter table needed to implement the flooding protection.\n     * \n     * @return the set of rules\n     */\n    public Set<String> getFloodingProtectionFilterRules();\n\n    /**\n     * Return a set of IPv4 firewall rules for the nat table needed to implement the flooding protection.\n     * \n     * @return the set of rules\n     */\n    public Set<String> getFloodingProtectionNatRules();\n\n    /**\n     * Return a set of IPv4 firewall rules for the mangle table needed to implement the flooding protection.\n     * \n     * @return the sets of rules\n     */\n    public Set<String> getFloodingProtectionMangleRules();\n\n    /**\n     * Return a set of IPv6 firewall rules for the filter table needed to implement the flooding protection.\n     * \n     * @return the set of rules\n     * @since 2.6\n     */\n    public Set<String> getFloodingProtectionFilterRulesIPv6();\n\n    /**\n     * Return a set of IPv6 firewall rules for the nat table needed to implement the flooding protection.\n     * \n     * @return the set of rules\n     * @since 2.6\n     */\n    public Set<String> getFloodingProtectionNatRulesIPv6();\n\n    /**\n     * Return a set of IPv6 firewall rules for the mangle table needed to implement the flooding protection.\n     * \n     * @return the sets of rules\n     * @since 2.6\n     */\n    public Set<String> getFloodingProtectionMangleRulesIPv6();\n}"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/SecurityService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.security;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface SecurityService {\n\n    /**\n     * This method allows the reload of the security policy's fingerprint\n     *\n     * @throws KuraException\n     *         in case an error is raised during the calculation of the fingerprint and the consequent storage.\n     */\n    public void reloadSecurityPolicyFingerprint() throws KuraException;\n\n    /**\n     * This method allows the reload of the command line fingerprint\n     *\n     * @throws KuraException\n     *         in case an error is raised during the calculation of the fingerprint and the consequent storage.\n     */\n    public void reloadCommandLineFingerprint() throws KuraException;\n\n    /**\n     * This method returns a boolean that specifies if the debugging is permitted\n     *\n     * @return true if the debug is permitted. False otherwise.\n     */\n    public boolean isDebugEnabled();\n\n    /**\n     * This method allows to apply the default production security policy available in the system. The changes are\n     * persistent and remain in effect after a framework restart.\n     *\n     * @throws KuraException\n     *         in case an error is raised during the application of the default production security policy.\n     * @since 2.7\n     */\n    public void applyDefaultProductionSecurityPolicy() throws KuraException;\n\n    /**\n     * This method allows to apply the user provided security policy. The changes are persistent and remain in effect\n     * after a framework restart.\n     *\n     * @param securityPolicy\n     *         the security policy to be applied\n     * @throws KuraException\n     *         in case an error is raised during the application of the security policy.\n     * @since 2.7\n     */\n    public void applySecurityPolicy(String securityPolicy) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/ThreatManagerService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.security;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This marker interface is used to group the services that manage the network threats.\n * \n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.2\n */\n@ProviderType\npublic interface ThreatManagerService {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/keystore/KeystoreChangedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n *******************************************************************************/\npackage org.eclipse.kura.security.keystore;\n\nimport java.util.Collections;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * A OSGi EventAdmin <code>Event</code> sent to report a change in a keystore managed by a {@link KeystoreService}.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.2\n */\n@ProviderType\npublic class KeystoreChangedEvent extends Event {\n\n    /**\n     * The EventAdmin topic of this event.\n     */\n    public static final String EVENT_TOPIC = \"org/eclipse/kura/security/keystore/KeystoreChangedEvent/KEYSTORE_CHANGED\";\n\n    /**\n     * The key of a Event property containing the kura.service.pid of the sender {@link KeystoreService}\n     */\n    public static final String SENDER_PID_PROPERTY_KEY = \"sender.pid\";\n\n    public KeystoreChangedEvent(final String keystoreServicePid) {\n        super(EVENT_TOPIC, Collections.singletonMap(SENDER_PID_PROPERTY_KEY, keystoreServicePid));\n    }\n\n    /**\n     * Returns the kura.service.pid of the sender {@link KeystoreService}.\n     * \n     * @return the kura.service.pid of the sender {@link KeystoreService}.\n     */\n    public String getSenderPid() {\n        return (String) getProperty(SENDER_PID_PROPERTY_KEY);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/keystore/KeystoreInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n *******************************************************************************/\npackage org.eclipse.kura.security.keystore;\n\n/**\n * Identifies a keystore with its name.\n * Further keystore information can be added (type, size...).\n *\n * @since 2.2\n */\npublic class KeystoreInfo {\n\n    private final String keystoreServicePid;\n    private String type;\n    private int size;\n\n    public KeystoreInfo(String keystoreServicePid) {\n        this.keystoreServicePid = keystoreServicePid;\n    }\n\n    public String getKeystoreServicePid() {\n        return this.keystoreServicePid;\n    }\n\n    public String getType() {\n        return this.type;\n    }\n\n    public void setType(String type) {\n        this.type = type;\n    }\n\n    public int getSize() {\n        return this.size;\n    }\n\n    public void setSize(int size) {\n        this.size = size;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/keystore/KeystoreService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.security.keystore;\n\nimport java.security.KeyPair;\nimport java.security.KeyStore;\nimport java.security.KeyStore.Entry;\nimport java.security.SecureRandom;\nimport java.security.cert.CRL;\nimport java.security.cert.CertStore;\nimport java.security.cert.X509CRL;\nimport java.security.spec.AlgorithmParameterSpec;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.net.ssl.KeyManager;\nimport javax.security.auth.x500.X500Principal;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Provides a list of APIs useful to manage and abstract key objects and certificates\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 2.2\n */\n@ProviderType\npublic interface KeystoreService {\n\n    /**\n     * Returns the managed {@link KeyStore}\n     *\n     * @return\n     * @throws KuraException\n     *             when the keystore does not exist or cannot be loaded\n     */\n    public KeyStore getKeyStore() throws KuraException;\n\n    /**\n     * Returns the entry object specified by the provided alias\n     *\n     * @param alias\n     * @return\n     * @throws KuraException\n     * @throws IllegalArgumentException\n     *             if the specified alias is null\n     */\n    public Entry getEntry(String alias) throws KuraException;\n\n    /**\n     * Stores the specified entry with the defined alias to the managed keystore\n     *\n     * @param alias\n     * @param entry\n     * @throws KuraException\n     *             if the entry could not be set or the keystore could not be persisted\n     * @throws IllegalArgumentException\n     *             if one of the arguments is null\n     */\n    public void setEntry(String alias, Entry entry) throws KuraException;\n\n    /**\n     * Returns the map representing the entries associated with the corresponding aliases in the keystore\n     *\n     * @return\n     * @throws KuraException\n     *             if the entries could not be retrieved\n     */\n    public Map<String, Entry> getEntries() throws KuraException;\n\n    /**\n     * Deletes the entry identified by the specified alias, if it exists.\n     *\n     * @param alias\n     * @throws KuraException\n     *             if the entry could not be deleted or the managed keystore could not be persisted after the change\n     * @throws IllegalArgumentException\n     *             if the specified alias is null\n     */\n    public void deleteEntry(String alias) throws KuraException;\n\n    /**\n     * Returns one key manager for each type of key material.\n     *\n     * @param algorithm\n     * @return a list of key manager\n     * @throws KuraException\n     *             if the provided algorithm is not supported or does not exist or if the associated keystore cannot be\n     *             accessed\n     * @throws IllegalArgumentException\n     *             if the algorithm is null\n     */\n    public List<KeyManager> getKeyManagers(String algorithm) throws KuraException;\n\n    /**\n     * Returns one key manager for each type of key material using the Java Security API Provider matching the given name.\n     *\n     * @param algorithm\n     * @param provider\n     *            the name of the Provider to be used\n     * @return a list of key manager\n     * @throws KuraException\n     *             if the provided algorithm/provider is not supported or does not exist or if the associated keystore\n     *             cannot be\n     *             accessed\n     * @throws IllegalArgumentException\n     *             if algorithm or provider is null\n     * \n     * @since 2.8\n     */\n    public List<KeyManager> getKeyManagers(String algorithm, String provider) throws KuraException;\n\n    /**\n     * Creates and persists a new keypair in the managed keystore using the specified alias.\n     *\n     * @param alias\n     * @param algorithm\n     * @param keySize\n     * @param signatureAlgorithm\n     * @param attributes\n     * @throws KuraException\n     *             if the keypair cannot be created or the keypair cannot be added to the managed keystore\n     * @throws IllegalArgumentException\n     *             if one of the arguments is null or empty\n     */\n    public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes)\n            throws KuraException;\n\n    /**\n     * Creates and persists a new keypair in the managed keystore using the specified alias.\n     *\n     * @param alias\n     * @param algorithm\n     * @param keySize\n     * @param signatureAlgorithm\n     * @param attributes\n     * @param secureRandom\n     * @throws KuraException\n     *             if the keypair cannot be created or the keypair cannot be added to the managed keystore\n     * @throws IllegalArgumentException\n     *             if one of the arguments is null or empty\n     */\n    public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes,\n            SecureRandom secureRandom) throws KuraException;\n\n    /**\n     * Creates and persists a new keypair in the managed keystore using the specified alias.\n     *\n     * @param alias\n     *            a string that will be used to identify the certificate in a key store.\n     * @param algorithm\n     *            a string indicating the algorithm used to generate the keypair.\n     * @param algorithmParameter\n     *            a set of algorithm parameters passed to the keypair generator.\n     * @param signatureAlgorithm\n     *            a string indicating the signature algorithm used to sign the certificate containing the generated\n     *            keypair.\n     * @param attributes\n     *            a string representing the X.500 Distinguished Name to include in the generated certificate.\n     * @param secureRandom\n     *            the RNG (Random Number Generator) to use in the keypair generator.\n     * @throws KuraException\n     *             if the keypair cannot be created or the keypair cannot be added to the managed keystore\n     * @throws IllegalArgumentException\n     *             if one of the arguments is null or empty\n     *\n     * @since 2.4\n     */\n    public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter,\n            String signatureAlgorithm, String attributes, SecureRandom secureRandom) throws KuraException;\n\n    /**\n     * Creates and persists a new keypair in the managed keystore using the specified alias.\n     *\n     * @param alias\n     *            a string that will be used to identify the certificate in a key store.\n     * @param algorithm\n     *            a string indicating the algorithm used to generate the keypair.\n     * @param algorithmParameter\n     *            a set of algorithm parameters passed to the keypair generator.\n     * @param signatureAlgorithm\n     *            a string indicating the signature algorithm used to sign the certificate containing the generated\n     *            keypair.\n     * @param attributes\n     *            a string representing the X.500 Distinguished Name to include in the generated certificate.\n     * @throws KuraException\n     *             if the keypair cannot be created or the keypair cannot be added to the managed keystore\n     * @throws IllegalArgumentException\n     *             if one of the arguments is null or empty\n     * @since 2.4\n     */\n    public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter,\n            String signatureAlgorithm, String attributes) throws KuraException;\n\n    /**\n     * Creates and returns a CSR for the given keypair based on the provided principal and signer algorithm selected.\n     *\n     * @param keyPair\n     *            a keypair holding the private and public key.\n     * @param principal\n     *            an X500Name containing the subject associated with the request we are building.\n     * @param signerAlg\n     *            a String representing the signer algorithm used to sign the certificate signing request.\n     * @return the Certificate Signing Request in PEM format.\n     * @throws KuraException\n     *             if the CSR cannot be computed or if it cannot be encoded\n     * @throws IllegalArgumentException\n     *             if one of the arguments is null or empty\n     */\n    public String getCSR(KeyPair keyPair, X500Principal principal, String signerAlg) throws KuraException;\n\n    /**\n     * Creates and returns a CSR for the given keypair based on the provided principal and signer algorithm selected.\n     *\n     * @param alias\n     *            a string that will be used to identify the entity in the keystore holding the private and public keys.\n     * @param principal\n     *            an X500Name containing the subject associated with the request we are building.\n     * @param signerAlg\n     *            a String representing the signer algorithm used to sign the certificate signing request.\n     * @return the Certificate Signing Request in PEM format.\n     * @throws KuraException\n     *             if the alias does not correspond to a managed entry of the keystore, it refers to an entry that\n     *             cannot be used to obtain a CSR or the CSR cannot be computed or encoded\n     * @throws IllegalArgumentException\n     *             if one of the arguments is null or empty\n     */\n    public String getCSR(String alias, X500Principal principal, String signerAlg) throws KuraException;\n\n    /**\n     * Returns the list of all the aliases corresponding to the keystore service managed objects\n     *\n     * @return\n     * @throws KuraException\n     *             if the list of aliases cannot be retrieved\n     */\n    public List<String> getAliases() throws KuraException;\n\n    /**\n     * Returns a list of the current cached CRLs.\n     *\n     * @return a list of the current cached CRLs.\n     * @throws KuraException\n     *             if the list cannot be retrieved\n     */\n    public Collection<CRL> getCRLs() throws KuraException;\n\n    /**\n     * Returns a <code>CertStore</code> containing the cached CRLs.\n     *\n     * @return a <code>CertStore</code> containing the cached CRLs.\n     * @throws KuraException\n     *             if the <code>CertStore</code> cannot be created.\n     */\n    public CertStore getCRLStore() throws KuraException;\n\n    /**\n     * Add a <code>X509CRL</code> to the CRLs list.\n     *\n     * @param crl\n     *            a <code>X509CRL</code> to be stored\n     * @throws KuraException\n     *             if the <code>X509CRL</code> cannot be added.\n     *\n     * @since 2.4\n     */\n    public void addCRL(X509CRL crl) throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/keystore/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides security related APIs for key management\n *\n */\npackage org.eclipse.kura.security.keystore;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides security related APIs\n *\n */\npackage org.eclipse.kura.security;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/TamperDetectionProperties.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.security.tamper.detection;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Defines some well known keys for the properties returned by {@link TamperStatus#getProperties()}.\n *\n * @since 2.2\n */\n@ProviderType\npublic enum TamperDetectionProperties {\n\n    /**\n     * Allows to specify a timestamp for the tamper event, if known.\n     * The property value must be a <code>long</code> representing the UNIX timestamp of the event.\n     */\n    TIMESTAMP_PROPERTY_KEY(\"timestamp\");\n\n    private final String value;\n\n    private TamperDetectionProperties(final String value) {\n        this.value = value;\n    }\n\n    public String getValue() {\n        return this.value;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/TamperDetectionService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.security.tamper.detection;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Specifies a service that implements tamper detection features.\n * This service introduces the concept of tamper status. The definition of tamper status depends on the implementation,\n * for example a device might be considered to be tampered if its external enclosure has been opened.\n * The tamper status is represented by the {@link TamperStatus} class.\n * The tamper status can be reset by calling the {@link TamperDetectionService#resetTamperStatus()} method.\n * This service must also generate {@link TamperEvent} EventAdmin events in particular conditions, see the corresponding\n * Javadoc for more details.\n *\n * @since 2.2\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface TamperDetectionService {\n\n    /**\n     * Returns an user friendly name describing this service.\n     * \n     * @return an user friendly name describing this service.\n     */\n    public String getDisplayName();\n\n    /**\n     * Returns the current {@link TamperStatus}.\n     *\n     * @return the current {@link TamperStatus}.\n     * @throws KuraException\n     *             in case of an implementation failure in determining the tamper status.\n     */\n    public TamperStatus getTamperStatus() throws KuraException;\n\n    /**\n     * Allows to reset the tamper state. After this method returns, the result of calling\n     * {@link TamperDetectionService#getTamperStatus()} should have the tamper flag set to false, until the next tamper\n     * event is detected.\n     *\n     * @throws KuraException\n     *             in case of reset implementation failure.\n     */\n    public void resetTamperStatus() throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/TamperEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.security.tamper.detection;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.osgi.service.event.Event;\n\n/**\n * Represents a EventAdmin event that reports a change in tamper status.\n * The changes that can originate a {@link TamperEvent} are the following:\n *\n * <ul>\n * <li>The tamper status flag changes. This can happen because a tamper event has been detected by the implementation or\n * the tamper status has been reset by the user. In this case the implementation must send an event.</li>\n * <li>The tamper status properties change. In this case sending the event is optional.</li>\n * </ul>\n *\n * This class contains a {@link TamperStatus} instance representing the new status.\n *\n * @since 2.2\n * @noimplement This interface is not intended to be implemented by clients.\n */\npublic class TamperEvent extends Event {\n\n    /**\n     * The EventAdmin topic of this event.\n     */\n    public static final String TAMPER_EVENT_TOPIC = \"org/eclipse/kura/security/tamper/detection/TamperEvent/TAMPER_STATUS_CHANGED\";\n    /**\n     * The key of a Event property containing the new {@link TamperStatus}\n     */\n    public static final String TAMPER_STATUS_PROPERTY_KEY = \"tamper.status\";\n    /**\n     * The key of a Event property containing the kura.service.pid of the sender {@link TamperDetectionService}\n     */\n    public static final String SENDER_PID_PROPERTY_KEY = \"sender.pid\";\n\n    /**\n     * Creates a new {@link TamperEvent} instance.\n     * \n     * @param tamperDetectionKuraServicePid\n     *            the kura.service.pid of the sender {@link TamperDetectionService}.\n     *\n     * @param tamperStatus\n     *            the new {@link TamperStatus}, cannot be <code>null</code>.\n     */\n    public TamperEvent(final String tamperDetectionServicePid, final TamperStatus tamperStatus) {\n        super(TAMPER_EVENT_TOPIC, buildEventProperties(tamperDetectionServicePid, tamperStatus));\n    }\n\n    /**\n     * Returns the new {@link TamperStatus}.\n     *\n     * @return the new {@link TamperStatus}, cannot be <code>null</code>.\n     */\n    public TamperStatus getTamperStatus() {\n        return (TamperStatus) getProperty(TAMPER_STATUS_PROPERTY_KEY);\n    }\n\n    /**\n     * Returns the kura.service.pid of the sender {@link TamperDetectionService}.\n     * \n     * @return the kura.service.pid of the sender {@link TamperDetectionService}.\n     */\n    public String getSenderPid() {\n        return (String) getProperty(SENDER_PID_PROPERTY_KEY);\n    }\n\n    private static Map<String, Object> buildEventProperties(final String tamperDetectionServicePid,\n            final TamperStatus tamperStatus) {\n        final Map<String, Object> properties = new HashMap<>();\n\n        properties.put(TAMPER_STATUS_PROPERTY_KEY, requireNonNull(tamperStatus, \"Tamper status cannot be null\"));\n        properties.put(SENDER_PID_PROPERTY_KEY,\n                requireNonNull(tamperDetectionServicePid, \"Tamper detection service pid cannot be null\"));\n\n        return properties;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/TamperStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.security.tamper.detection;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.eclipse.kura.type.TypedValue;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents the device tamper status.\n * This includes a boolean flag that indicates if the device has been tampered or not and some properties.\n * The properties indicated in the {@link TamperDetectionProperties} enumeration are well known.\n *\n * @since 2.2\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic class TamperStatus {\n\n    private final boolean isDeviceTampered;\n    private final Map<String, TypedValue<?>> properties;\n\n    /**\n     * Creates a new {@link TamperStatus} instance.\n     *\n     * @param isDeviceTampered\n     *            the current tamper status.\n     * @param properties\n     *            the additional properties, can be <code>null</code>.\n     */\n    public TamperStatus(boolean isDeviceTampered, Map<String, TypedValue<?>> properties) {\n        this.isDeviceTampered = isDeviceTampered;\n        this.properties = properties != null ? Collections.unmodifiableMap(properties) : Collections.emptyMap();\n    }\n\n    /**\n     * Indicates if the device is tampered or not.\n     *\n     * @return a <code>boolean</code> indicating if the device is tampered or not\n     */\n    public boolean isDeviceTampered() {\n        return this.isDeviceTampered;\n    }\n\n    /**\n     * Returns additional properties describing the tamper status.\n     *\n     * @return the additional properties, the result is never <code>null</code> but can be empty.\n     */\n    public Map<String, TypedValue<?>> getProperties() {\n        return this.properties;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Defines APIs for tamper detection.\n *\n * @since 2.2\n */\npackage org.eclipse.kura.security.tamper.detection;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ssl/SslManagerService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.ssl;\n\nimport java.io.IOException;\nimport java.security.GeneralSecurityException;\nimport java.security.PrivateKey;\nimport java.security.cert.Certificate;\nimport java.security.cert.X509Certificate;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSocketFactory;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The SslManagerService is responsible to manage the configuration of the SSL connections.\n * It provide APIs to manage the trust certificates and the private keys and public certificates\n * and enforces best practices that are not enabled by default in the Java VM.\n * For example, it enables Hostname Verification, disables the legacy SSL-2.0-compatible Client Hello,\n * and disable the Nagle algorithm.\n * Its implementation is configurable exposing the possibility to express the allowed SSL protocols,\n * the allowed cipher suites, and the location of the Trust Store and the Key Store files.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface SslManagerService {\n\n    /**\n     * Returns an SSLContext based on the current configuration of the SslManagerService and applying\n     * best practices like Hostname Verification and disables the legacy SSL-2.0-compatible Client Hello.<br>\n     * If the SslManagerService configuration contains a path to a custom Trust store, then it will be used.\n     * If not, the Java VM default Trust Store will be used.<br>\n     * If the SslManagerService configuration contains a path to a custom Key store, then it will be used.\n     * If not, no Key store will be specified..<br>\n     *\n     * @return the SSLContext\n     * @since 2.2\n     */\n    public SSLContext getSSLContext() throws GeneralSecurityException, IOException;\n\n    /**\n     * Returns an SSLContext based on the current configuration of the SslManagerService and applying\n     * best practices like Hostname Verification and disables the legacy SSL-2.0-compatible Client Hello.<br>\n     * If the SslManagerService configuration contains a path to a custom Trust store, then it will be used.\n     * If not, the Java VM default Trust Store will be used.<br>\n     * If the SslManagerService configuration contains a path to a custom Key store, and such store contains\n     * a KeyEntry with the alias \"keyAlias\" then a KeyStore with the only such KeyEntry will be used.\n     * If no custom store is configured or it does not contain the \"keyAlias\" specified, no Key store will be\n     * specified..<br>\n     *\n     * @param keyAlias\n     *            alias of the entry in the KeyStore to be used for the returned SSLSocketFactory\n     * @return the SSLContext\n     * @since 2.2\n     */\n    public SSLContext getSSLContext(String keyAlias) throws GeneralSecurityException, IOException;\n\n    /**\n     * Shorthand for getSSLContext().getSocketFactory().\n     *\n     * @return the SSLSocketFactory\n     */\n    public SSLSocketFactory getSSLSocketFactory() throws GeneralSecurityException, IOException;\n\n    /**\n     * Shorthand for getSSLContext(String).getSocketFactory().\n     *\n     * @param keyAlias\n     *            alias of the entry in the KeyStore to be used for the returned SSLSocketFactory\n     * @return the SSLSocketFactory\n     */\n    public SSLSocketFactory getSSLSocketFactory(String keyAlias) throws GeneralSecurityException, IOException;\n\n    /**\n     * Shorthand for getSSLContext(String, String, String, String, char[], String).getSocketFactory().\n     *\n     * @param protocol\n     *            the protocol to use to initialize the SSLContext - e.g. TLSv1.2\n     * @param cipherSuites\n     *            allowed cipher suites for the returned SSLSocketFactory\n     * @param trustStorePath\n     *            Location of the Java keystore file containing the collection of CA certificates trusted by this\n     *            application process (trust store). Key store type is expected to be JKS.\n     * @param keyStorePath\n     *            Location of the Java keystore file containing an application process's own certificate and private\n     *            key. Key store type is expected to be JKS.\n     * @param keyStorePassword\n     *            Password to access the private key from the keystore file.\n     * @param keyAlias\n     *            alias of the entry in the KeyStore to be used for the returned SSLSocketFactory\n     * @return the SSLSocketFactory\n     * @deprecated The methods that allow to explicitly specify a keystore should not be used anymore.\n     */\n    @Deprecated\n    public SSLSocketFactory getSSLSocketFactory(String protocol, String cipherSuites, String trustStorePath,\n            String keyStorePath, char[] keyStorePassword, String keyAlias) throws GeneralSecurityException, IOException;\n\n    /**\n     * Shorthand for getSSLContext(String, String, String, String, char[], String, boolean).getSocketFactory().\n     *\n     * @param protocol\n     *            the protocol to use to initialize the SSLContext - e.g. TLSv1.2\n     * @param cipherSuites\n     *            allowed cipher suites for the returned SSLSocketFactory\n     * @param trustStorePath\n     *            Location of the Java keystore file containing the collection of CA certificates trusted by this\n     *            application process (trust store). Key store type is expected to be JKS.\n     * @param keyStorePath\n     *            Location of the Java keystore file containing an application process's own certificate and private\n     *            key. Key store type is expected to be JKS.\n     * @param keyStorePassword\n     *            Password to access the private key from the keystore file.\n     * @param keyAlias\n     *            alias of the entry in the KeyStore to be used for the returned SSLSocketFactory\n     * @param hostnameVerification\n     *            enable server Hostname Verification\n     * @return the SSLSocketFactory\n     * @deprecated The methods that allow to explicitly specify a keystore should not be used anymore.\n     */\n    @Deprecated\n    public SSLSocketFactory getSSLSocketFactory(String protocol, String cipherSuites, String trustStorePath,\n            String keyStorePath, char[] keyStorePassword, String keyAlias, boolean hostnameVerification)\n            throws GeneralSecurityException, IOException;\n\n    /**\n     * Returns the X509 Certificates installed in the currently configured trust store.\n     * If the SslManagerService configuration contains a path to a custom trust store, then the returned certificates\n     * are the ones installed in such store.\n     * Otherwise the default Java VM trust store will be listed.\n     *\n     * @return the X509Certificates\n     * @deprecated\n     */\n    @Deprecated\n    public X509Certificate[] getTrustCertificates() throws GeneralSecurityException, IOException;\n\n    /**\n     * Installs the specified X509 certificate in the currently configured trust store.\n     * If the SslManagerService configuration contains a path to a custom trust store, then the certificate will be\n     * installed in such store.\n     * Otherwise the certificate will be installed in the default Java VM trust store.\n     *\n     * @param x509crt\n     *            certificate to be installed\n     * @deprecated\n     */\n    @Deprecated\n    public void installTrustCertificate(String alias, X509Certificate x509crt)\n            throws GeneralSecurityException, IOException;\n\n    /**\n     * Deletes the X509 certificate with the specified Common Name (cn) from the currently configured trust store.\n     * If the SslManagerService configuration contains a path to a custom trust store, then the certificate will be\n     * deleted from such store.\n     * Otherwise the certificate will be deleted from the default Java VM trust store.\n     *\n     * @param alias\n     * @deprecated\n     */\n    @Deprecated\n    public void deleteTrustCertificate(String alias) throws GeneralSecurityException, IOException;\n\n    /**\n     * Installs a private key and the correspondent public certificate chains in the configured key store with the\n     * defined alias.\n     *\n     * @param alias\n     *            that is a string that will be used to identify the certificates in the key store\n     * @param privateKey\n     *            that represents PrivateKey object\n     * @param password\n     *            that represents the password used to encode the keys in the key store\n     * @param publicCerts\n     *            that represents an array of Certificate objects that contain the public certificate chain\n     * @deprecated\n     */\n    @Deprecated\n    public void installPrivateKey(String alias, PrivateKey privateKey, char[] password, Certificate[] publicCerts)\n            throws GeneralSecurityException, IOException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ssl/SslServiceListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.ssl;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * Listener interface to be implemented by applications that needs to be notified of events in the\n * {@link SslManagerService}.\n * All registered listeners are called synchronously by the {@link SslManagerService} at the occurrence of the event.\n * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this\n * interface.\n */\n@ConsumerType\npublic interface SslServiceListener {\n\n    /**\n     * Notifies the {@link SslManagerService} has received a configuration update and it has applied the new\n     * configuration\n     */\n    public void onConfigurationUpdated();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ssl/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides SSL-related APIs\n *\n */\npackage org.eclipse.kura.ssl;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/status/CloudConnectionStatusComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.status;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * This interface must be implemented by classes which want to trigger a status change on the\n * {@link CloudConnectionStatusService}\n */\n@ConsumerType\npublic interface CloudConnectionStatusComponent {\n\n    /**\n     * Returns the notification priority for this Component. Usually a constant.<br>\n     * Priorities range from {@code Integer.MIN_VALUE} to {@code Integer.MAX_VALUE}.<br>\n     * <br>\n     * Several constants are available for most used priorities:<br>\n     * <table summary=\"\">\n     * <tbody>\n     * <tr>\n     * <td>{@code CloudConnectionStatusService.PRIORITY_MAX}</td>\n     * <td>Maximum priority</td>\n     * </tr>\n     * <tr>\n     * <td>{@code CloudConnectionStatusService.PRIORITY_CRITICAL}</td>\n     * <td>400</td>\n     * </tr>\n     * <tr>\n     * <td>{@code CloudConnectionStatusService.PRIORITY_HIGH}</td>\n     * <td>300</td>\n     * </tr>\n     * <tr>\n     * <td>{@code CloudConnectionStatusService.PRIORITY_MEDIUM}</td>\n     * <td>200</td>\n     * </tr>\n     * <tr>\n     * <td>{@code CloudConnectionStatusService.PRIORITY_LOW}</td>\n     * <td>100</td>\n     * </tr>\n     * <tr>\n     * <td>{@code CloudConnectionStatusService.PRIORITY_MIN}</td>\n     * <td>Minimum priority</td>\n     * </tr>\n     * </tbody>\n     * </table>\n     *\n     * @return An Integer indicating the priority for this component\n     */\n    public int getNotificationPriority();\n\n    /**\n     * Invoked by {@link CloudConnectionStatusService} to retrieve the current {@link CloudConnectionStatusEnum} status\n     * for this component\n     *\n     * @return {@link CloudConnectionStatusEnum} representing the current status of the component\n     */\n    public CloudConnectionStatusEnum getNotificationStatus();\n\n    /**\n     * Invoked internally by {@link CloudConnectionStatusService} to persist the status of the component\n     *\n     * @param status\n     *            New status of this component\n     */\n    public void setNotificationStatus(CloudConnectionStatusEnum status);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/status/CloudConnectionStatusEnum.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.status;\n\n/**\n * Enum used to store the status of the notification for a {@link CloudConnectionStatusComponent}\n *\n */\npublic enum CloudConnectionStatusEnum {\n    OFF,\n    FAST_BLINKING,\n    SLOW_BLINKING,\n    HEARTBEAT,\n    ON;\n\n    /**\n     * Delays in ms for Fast Blinking\n     */\n    public static final int FAST_BLINKING_ON_TIME = 100;\n    public static final int FAST_BLINKING_OFF_TIME = 100;\n\n    /**\n     * Delays in ms for Slow Blinking\n     */\n    public static final int SLOW_BLINKING_ON_TIME = 300;\n    public static final int SLOW_BLINKING_OFF_TIME = 300;\n\n    /**\n     * Delays in ms for Heartbeat\n     */\n    public static final int HEARTBEAT_SYSTOLE_DURATION = 150;\n    public static final int HEARTBEAT_DIASTOLE_DURATION = 150;\n    public static final int HEARTBEAT_PAUSE_DURATION = 600;\n\n    /**\n     * Delay in ms for periodic check on fixed statuses (On, Off)\n     */\n    public static final int PERIODIC_STATUS_CHECK_DELAY = 5000;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/status/CloudConnectionStatusService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.status;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The CloudConnectionStatusService is responsible for updating the user on the connection status of the framework.\n * Default implementation will link the status to a LED or to the log file.<br>\n * The service stores an internal list of {@link CloudConnectionStatusComponent} which represents all the elements\n * that are responsible of notifying the connection status.<br>\n * <br>\n *\n * Each {@link CloudConnectionStatusComponent} is assigned with a priority and a status (\n * {@link CloudConnectionStatusEnum}).\n * The Service shows the status of the highest priority CloudConnectionStatusComponent registered in the list.<br>\n * <br>\n * In order to use the service, a class must implement the {@link CloudConnectionStatusComponent} interface and register\n * itself in the Service component registry using the {@code register(CloudConnectionStatusComponent c)} method.<br>\n * <br>\n * Unregistering the class from the Service registry will trigger a status switch to the previous priority found in the\n * Service component registry.<br>\n * <br>\n * A call to {@code updateStatus(...)} will trigger an internal status change for the relevant component, and the\n * Service will trigger a status change for the highest priority component only if needed.<br>\n * <br>\n * <h2>Default implementation</h2>\n * The default implementation is a Factory Component. A new instance of a {@link CloudConnectionStatusService} will be\n * instantiated for each communication stack.\n * The default CloudConnectionStatusService will have its <b>kura.service.pid</b> equals to\n * <b>org.eclipse.kura.status.CloudConnectionStatusService</b><br>\n * Subsequent Communication Stacks will instantiate a relevant CloudConnectionStatusService with the appropriate\n * postfix.<br>\n * e.g. The CloudConnectionStatusService for a Communication Stack generated by a\n * org.eclipse.kura.cloud.CloudService-foo will have its kura.service.pid equals to\n * org.eclipse.kura.status.CloudConnectionStatusService-foo<br>\n * <br>\n * Configuration for a specific CloudConnectionStatusService can be found in the kura.properties file.<br>\n * The configuration is defined by a key value pair, where key is a URL-like string defining the service, and value is\n * the entity responsible to show the Cloud Connection Status.\n * It can be either a LED, the system log or none.\n * Configuration for specific instances of the CloudConnectionStatusService is achieved by correctly formatting the\n * URL-like key.<br>\n * The default configuration is stored under the key <b>ccs.status.notification.url</b><br>\n * Configuration for specific communication stacks include the stack postfix in the URL-like key.<br>\n * <br>\n * e.g. The key-value pair to link the CloudConnectionStatusService generated for the \"foo\" stack (see above) to LED\n * number 25 would be:<br>\n * <b>ccs.status.notification.url.foo=ccs:led:25</b><br>\n * Same configuration, but linking the status to the system log, would be:<br>\n * <b>ccs.status.notification.url.foo=ccs:log</b>\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface CloudConnectionStatusService {\n\n    /**\n     * Maximum priority for the notification. There should be only one StatusDisplayComponent at the same time\n     * using this priority.\n     */\n    public static final int PRIORITY_MAX = Integer.MAX_VALUE;\n\n    /**\n     * Priorities are evaluated in ascending order.\n     * The Service will use the status of the registered component with highest priority\n     */\n    public static final int PRIORITY_CRITICAL = 400;\n    public static final int PRIORITY_HIGH = 300;\n    public static final int PRIORITY_MEDIUM = 200;\n    public static final int PRIORITY_LOW = 100;\n\n    /**\n     * Minimum priority for the notification. There should be at least and only one StatusDisplayComponent at the same\n     * time using this priority.\n     */\n    public static final int PRIORITY_MIN = Integer.MIN_VALUE;\n\n    /**\n     * Registers a {@link CloudConnectionStatusComponent} in the component registry of the Service\n     *\n     * @param component\n     *            CloudConnectionStatusComponent to be registered in the registry\n     */\n    public void register(CloudConnectionStatusComponent component);\n\n    /**\n     * Unregisters a {@link CloudConnectionStatusComponent} from the component registry of the Service\n     *\n     * @param component\n     *            CloudConnectionStatusComponent to be unregistered from the registry\n     */\n    public void unregister(CloudConnectionStatusComponent component);\n\n    /**\n     * Updates the status of a {@link CloudConnectionStatusComponent} in the registry.\n     * Implementation should also set the internal status of the CloudConnectionStatus component so to persist it.\n     *\n     * @param component\n     *            {@link CloudConnectionStatusComponent} for which the status has to be changed\n     * @param status\n     *            {@link CloudConnectionStatusEnum} representing the new status of the component\n     * @return false if an error occurs, true otherwise\n     */\n    public boolean updateStatus(CloudConnectionStatusComponent component, CloudConnectionStatusEnum status);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/status/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides service to notify the status of the connection to the cloud.\n *\n */\npackage org.eclipse.kura.status;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/ExtendedProperties.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.system;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a set of properties that can be returned by custom {@link SystemService} implementations to provide\n * additional\n * informations about the system that are not specified by the {@link SystemService} interface.\n * The extended properties are organized in named groups, as specified by the {@link ExtendedPropertyGroup}\n * interface.\n * The number of returned groups, their names and contained property keys and values are not specified by Kura APIs.\n * \n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.2\n */\n@ProviderType\npublic class ExtendedProperties {\n\n    private final String version;\n    private final List<ExtendedPropertyGroup> groups;\n\n    /**\n     * Creates a new {@link ExtendedProperties} instance.\n     * \n     * @param version\n     *            the version\n     * @param groups\n     *            the property groups\n     */\n    public ExtendedProperties(final String version, final List<ExtendedPropertyGroup> groups) {\n        if (requireNonNull(version, \"version cannot be null\").trim().isEmpty()) {\n            throw new IllegalArgumentException(\"version cannot be empty\");\n        }\n\n        this.version = version;\n        this.groups = Collections.unmodifiableList(requireNonNull(groups, \"groups cannot be null\"));\n    }\n\n    /**\n     * Returns the version\n     * \n     * @return the version\n     */\n    public String getVersion() {\n        return version;\n    }\n\n    /**\n     * Returns the property group list\n     * \n     * @return the property group list\n     */\n    public List<ExtendedPropertyGroup> getPropertyGroups() {\n        return groups;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/ExtendedPropertyGroup.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.system;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents an extended property group.\n * An extended property group has a name and some properties.\n * \n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.2\n */\n@ProviderType\npublic class ExtendedPropertyGroup {\n\n    private final String name;\n    private final Map<String, String> properties;\n\n    /**\n     * Creates a new {@link ExtendedPropertyGroup} instance.\n     * \n     * @param name\n     *            the group name, must not be null or empty\n     * @param properties\n     *            the property map, must not be null\n     */\n    public ExtendedPropertyGroup(final String name, final Map<String, String> properties) {\n        if (requireNonNull(name, \"name cannot be null\").trim().isEmpty()) {\n            throw new IllegalArgumentException(\"name cannot be empty\");\n        }\n\n        this.name = name;\n        this.properties = Collections.unmodifiableMap(requireNonNull(properties, \"properties cannot be null\"));\n    }\n\n    /**\n     * Returns the group name.\n     * \n     * @return the group name.\n     */\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Returns the group properties.\n     * \n     * @return the group properties.\n     */\n    public Map<String, String> getProperties() {\n        return properties;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/InternetConnectionStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.system;\n\n/**\n * Represents the status of the internet connection.\n * \n * @since 3.0\n */\npublic enum InternetConnectionStatus {\n\n    UNAVAILABLE,\n    IP_ONLY,\n    FULL\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/SystemAdminService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.system;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Service to perform basic system tasks.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface SystemAdminService {\n\n    /**\n     * Gets the amount of time this device has been up in milliseconds.\n     *\n     * @return How long this device has been up in milliseconds.\n     */\n    public String getUptime();\n\n    /**\n     * Reboots the device.\n     */\n    public void reboot();\n\n    /**\n     * Synchronizes data on flash with memory.\n     */\n    public void sync();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/SystemResourceInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.system;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents all the information needed to identify and represent a System Resource.\n * A System Resource is every package or component of the system where the framework is running.\n * This information, for example, can be used to create an inventory of the System Resources\n * installed in the host system running the framework.\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class SystemResourceInfo {\n\n    private final String name;\n    private final String version;\n    private final SystemResourceType type;\n\n    /**\n     * Creates a new {@link SystemResourceInfo} instance.\n     *\n     * @param name\n     *            a string representing the resource name\n     */\n    public SystemResourceInfo(String name) {\n        this(name, \"Unknown\", SystemResourceType.UNKNOWN);\n    }\n\n    /**\n     * Creates a new {@link SystemResourceInfo} instance.\n     *\n     * @param name\n     *            a string representing the resource name\n     * @param version\n     *            a string representing the resource version\n     * @param type\n     *            a string representing the resource type\n     */\n    public SystemResourceInfo(String name, String version, String type) {\n        this(name, version, SystemResourceType.valueOf(type));\n    }\n\n    /**\n     * Creates a new {@link SystemResourceInfo} instance.\n     *\n     * @param name\n     *            a string representing the resource name\n     * @param version\n     *            a string representing the resource version\n     * @param type\n     *            a {@link SystemResourceType} representing the resource type\n     */\n    public SystemResourceInfo(String name, String version, SystemResourceType type) {\n        this.name = name;\n        this.version = version;\n        this.type = type;\n    }\n\n    /**\n     * Returns the resource name\n     *\n     * @return the resource name\n     */\n    public String getName() {\n        return this.name;\n    }\n\n    /**\n     * Returns the resource version\n     *\n     * @return the resource version\n     */\n    public String getVersion() {\n        return this.version;\n    }\n\n    /**\n     * Returns the resource type\n     *\n     * @return the resource type as {@link SystemResourceType}\n     */\n    public SystemResourceType getType() {\n        return this.type;\n    }\n\n    /**\n     * Returns the resource type\n     *\n     * @return the resource type as {@link String}\n     */\n    public String getTypeString() {\n        return this.type.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/SystemResourceType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.system;\n\n/**\n * An enum representing the supported System Resource Types\n *\n * @noextend This class is not intended to be subclassed by clients.\n * @since 2.2\n */\npublic enum SystemResourceType {\n\n    BUNDLE,\n    DP,\n    RPM,\n    DEB,\n    DOCKER,\n    /**\n     * @since 2.4\n     */\n    CONTAINER_IMAGE,\n    APK,\n    UNKNOWN;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/SystemService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.system;\n\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Properties;\n\nimport org.eclipse.kura.KuraProcessExecutionErrorException;\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.framework.Bundle;\n\n/**\n * Service to provide basic system information including Operating System\n * information, JVM information and filesystem information.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface SystemService {\n\n    public static final String KURA_CONFIG = \"kura.configuration\";\n    public static final String KURA_PROPS_FILE = \"kura.properties\";\n    public static final String KURA_CUSTOM_CONFIG = \"kura.custom.configuration\";\n    public static final String KURA_CUSTOM_PROPS_FILE = \"kura_custom.properties\";\n    public static final String OS_CLOUDBEES = \"Linux (Cloudbees)\";\n    public static final String OS_LINUX = \"Linux\";\n    public static final String OS_MAC_OSX = \"Mac OS X\";\n    public static final String UNKNOWN = \"UNKNOWN\";\n    public static final String UNSUPPORTED = \"UNSUPPORTED\";\n\n    public static final String KEY_KURA_NAME = \"kura.name\";\n    public static final String KEY_KURA_VERSION = \"kura.version\";\n\n    /**\n     * @since 2.2\n     */\n    public static final String KEY_KURA_NET_VIRTUAL_DEVICES_CONFIG = \"kura.net.virtual.devices.config\";\n    /**\n     * @since 2.0\n     */\n    public static final String KEY_KURA_FRAMEWORK_CONFIG_DIR = \"kura.framework.config\";\n    /**\n     * @since 2.0\n     */\n    public static final String KEY_KURA_USER_CONFIG_DIR = \"kura.user.config\";\n    /**\n     * @since 1.3\n     */\n    public static final String KEY_KURA_MARKETPLACE_COMPATIBILITY_VERSION = \"kura.marketplace.compatibility.version\";\n    public static final String KEY_DEVICE_NAME = \"kura.device.name\";\n    public static final String KEY_PLATFORM = \"kura.platform\";\n    public static final String KEY_MODEL_ID = \"kura.model.id\";\n    public static final String KEY_MODEL_NAME = \"kura.model.name\";\n    public static final String KEY_PART_NUMBER = \"kura.partNumber\";\n    public static final String KEY_SERIAL_NUM = \"kura.serialNumber\";\n    public static final String KEY_BIOS_VERSION = \"kura.bios.version\";\n    public static final String KEY_FIRMWARE_VERSION = \"kura.firmware.version\";\n    public static final String KEY_PRIMARY_NET_IFACE = \"kura.primary.network.interface\";\n    public static final String KEY_KURA_HOME_DIR = \"kura.home\";\n    public static final String KEY_KURA_PLUGINS_DIR = \"kura.plugins\";\n    /**\n     * @since 1.2\n     */\n    public static final String KEY_KURA_PACKAGES_DIR = \"kura.packages\";\n    public static final String KEY_KURA_DATA_DIR = \"kura.data\";\n    public static final String KEY_KURA_TMP_DIR = \"kura.tmp\";\n    public static final String KEY_KURA_SNAPSHOTS_DIR = \"kura.snapshots\";\n    public static final String KEY_KURA_SNAPSHOTS_COUNT = \"kura.snapshots.count\";\n    public static final String KEY_KURA_HAVE_NET_ADMIN = \"kura.have.net.admin\";\n    public static final String KEY_KURA_HAVE_WEB_INTER = \"kura.have.web.inter\";\n    public static final String KEY_KURA_STYLE_DIR = \"kura.style.dir\";\n    public static final String KEY_KURA_WIFI_TOP_CHANNEL = \"kura.wifi.top.channel\";\n    public static final String KEY_KURA_KEY_STORE_PWD = \"kura.ssl.keyStorePassword\";\n    public static final String KEY_KURA_TRUST_STORE_PWD = \"kura.ssl.trustStorePassword\";\n    public static final String KEY_FILE_COMMAND_ZIP_MAX_SIZE = \"file.command.zip.max.size\";\n    public static final String KEY_FILE_COMMAND_ZIP_MAX_NUMBER = \"file.command.zip.max.number\";\n    public static final String KEY_OS_ARCH = \"os.arch\";\n    public static final String KEY_OS_NAME = \"os.name\";\n    public static final String KEY_OS_VER = \"os.version\";\n    public static final String KEY_OS_DISTRO = \"os.distribution\";\n    public static final String KEY_OS_DISTRO_VER = \"os.distribution.version\";\n    public static final String KEY_JAVA_VERSION = \"java.runtime.version\";\n    public static final String KEY_JAVA_VENDOR = \"java.runtime.name\";\n    public static final String KEY_JAVA_VM_NAME = \"java.vm.name\";\n    public static final String KEY_JAVA_VM_VERSION = \"java.vm.version\";\n    public static final String KEY_JAVA_VM_INFO = \"java.vm.info\";\n    public static final String KEY_OSGI_FW_NAME = \"org.osgi.framework.vendor\";\n    public static final String KEY_OSGI_FW_VERSION = \"org.osgi.framework.version\";\n    public static final String KEY_JAVA_HOME = \"java.home\";\n    public static final String KEY_FILE_SEP = \"file.separator\";\n    public static final String CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE = \"console.device.management.service.ignore\";\n\n    /**\n     * @since 2.2\n     */\n    public static final String KEY_COMMAND_USER = \"kura.command.user\";\n\n    /**\n     * @since 2.2\n     */\n    public static final String KEY_CPU_VERSION = \"cpu.version\";\n\n    /**\n     * @since 2.2\n     */\n    public static final String KEY_LEGACY_BT_BEACON_SCAN = \"kura.legacy.bluetooth.beacon.scan\";\n\n    /**\n     * @since 2.3\n     */\n    public static final String KEY_LEGACY_PPP_LOGGING = \"kura.legacy.ppp.logging.enabled\";\n\n    /**\n     * @since 2.6\n     */\n    public static final String KEY_JAVA_VM_VENDOR = \"java.vm.vendor\";\n\n    /**\n     * @since 2.6\n     */\n    public static final String KEY_JDK_VENDOR_VERSION = \"jdk.vendor.version\";\n\n    /**\n     * @since 2.8\n     */\n    public static final String KEY_DEFAULT_LOG_MANAGER = \"kura.default.log.manager\";\n\n    /**\n     * @since 3.0\n     */\n    public static final String KEY_WPA3_WIFI_SECURITY_ENABLE = \"kura.wpa3.wifi.security.enable\";\n\n    /**\n     * @since 3.0\n     */\n    public static final String KEY_NETWORK_CONFIGURATION_TIMEOUT = \"kura.network.configuration.timeout\";\n\n    /**\n     * @since 3.0 Hostname used to verify internet connection status.\n     */\n    public static final String KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST = \"kura.internet.check.hostname\";\n\n    /**\n     * @since 3.0 Address in a format according to system IP version available (e.g. 198.41.30.198 in IPv4 or\n     *        ::ffff:c629:1ec6 in IPv6) required to verify the internet connection status.\n     *        In order to use the functionality, an IPv6-only system must override this property with an IPv6 address.\n     */\n    public static final String KEY_INTERNET_CONNECTION_STATUS_CHECK_IP = \"kura.internet.check.ip\";\n\n    /**\n     * @deprecated\n     */\n    @Deprecated\n    public static final String DB_URL_PROPNAME = \"db.service.hsqldb.url\";\n\n    /**\n     * @deprecated\n     */\n    @Deprecated\n    public static final String DB_WRITE_DELAY_MILLIES_PROPNAME = \"db.service.hsqldb.write_delay_millis\";\n\n    /**\n     * @deprecated\n     */\n    @Deprecated\n    public static final String DB_LOG_DATA_PROPNAME = \"db.service.hsqldb.log_data\";\n\n    /**\n     * @deprecated\n     */\n    @Deprecated\n    public static final String DB_CACHE_ROWS_PROPNAME = \"db.service.hsqldb.cache_rows\";\n\n    /**\n     * @deprecated\n     */\n    @Deprecated\n    public static final String DB_LOB_FILE_PROPNAME = \"db.service.hsqldb.lob_file_scale\";\n\n    /**\n     * @deprecated\n     */\n    @Deprecated\n    public static final String DB_DEFRAG_LIMIT_PROPNAME = \"db.service.hsqldb.defrag_limit\";\n\n    /**\n     * @deprecated\n     */\n    @Deprecated\n    public static final String DB_LOG_SIZE_PROPNAME = \"db.service.hsqldb.log_size\";\n\n    /**\n     * @deprecated\n     */\n    @Deprecated\n    public static final String DB_NIO_PROPNAME = \"db.service.hsqldb.nio_data_file\";\n\n    /**\n     * Gets the primary MAC address of the system\n     *\n     * @return\n     */\n    public String getPrimaryMacAddress();\n\n    /**\n     * Gets the name of the 'primary' network interface.\n     *\n     * @return\n     */\n    public String getPrimaryNetworkInterfaceName();\n\n    /**\n     * Gets the platform name Kura is running on. This could be catalyst, duracor1200, helios, isis, proteus, etc.\n     *\n     * @return The platform name.\n     */\n    public String getPlatform();\n\n    /**\n     * Gets the model identification of the device.\n     *\n     * @return Model ID.\n     */\n    public String getModelId();\n\n    /**\n     * Gets the model name of the device.\n     *\n     * @return Model name.\n     */\n    public String getModelName();\n\n    /**\n     * Gets the part number.\n     *\n     * @return Part number.\n     */\n    public String getPartNumber();\n\n    /**\n     * Gets the serial number of the device.\n     *\n     * @return Serial number.\n     */\n    public String getSerialNumber();\n\n    /**\n     * Returns a friendly name assigned to this device.\n     *\n     * @return\n     */\n    public String getDeviceName();\n\n    /**\n     * Gets the BIOS version of the device.\n     *\n     * @return BIOS version.\n     */\n    public String getBiosVersion();\n\n    /**\n     * Gets the firmware version.\n     *\n     * @return Firmware version.\n     */\n    public String getFirmwareVersion();\n\n    /**\n     * Gets the Operating System architecture for the system.\n     *\n     * @return The Operating System architecture as defined by the Java System property os.arch.\n     */\n    public String getOsArch();\n\n    /**\n     * Gets the Operating System name for the system.\n     *\n     * @return The Operating System name as defined by the Java System property os.name.\n     */\n    public String getOsName();\n\n    /**\n     * Gets the Operating System version for the system.\n     *\n     * @return The Operating System version as defined by the Java System property os.version.\n     */\n    public String getOsVersion();\n\n    /**\n     * Gets the Operating System Distribution name if appropriate.\n     *\n     * @return A String representing the Operating System Distribution name if appropriate.\n     */\n    public String getOsDistro();\n\n    /**\n     * Gets the Operating System Distribution version if appropriate.\n     *\n     * @return A String representing the Operating System Distribution version if appropriate.\n     */\n    public String getOsDistroVersion();\n\n    /**\n     * Gets the vendor of the Java VM that is currently being used.\n     *\n     * @return The Java Runtime version as defined by the Java System property java.vendor.\n     */\n    public String getJavaVendor();\n\n    /**\n     * Gets the Java version that is currently being used.\n     *\n     * @return The Java version as defined by the Java System property java.version.\n     */\n    public String getJavaVersion();\n\n    /**\n     * Gets the Java Virtual Machine name that is currently being used.\n     *\n     * @return The Java Virtual Machine name as defined by the Java System property java.vm.name.\n     */\n    public String getJavaVmName();\n\n    /**\n     * Gets the Java Virtual Machine version that is currently being used.\n     *\n     * @return The Java Virtual Machine version as defined by the Java System property java.vm.version.\n     */\n    public String getJavaVmVersion();\n\n    /**\n     * Gets the Java Virtual Machine information that is currently being used.\n     * Indicates if virtual machine was built with just-in-time-compiler support.\n     * Values are \"mixed mode\" or \"interpreter loop\".\n     *\n     * @return The Java Virtual Machine version as defined by the Java System\n     *         property java.vm.info.\n     */\n    public String getJavaVmInfo();\n\n    /**\n     * Gets the name of the OSGI Framework that is currently being used.\n     *\n     * @return The OSGI Framework Name as defined by the System property osgi.framework.name.\n     */\n    public String getOsgiFwName();\n\n    /**\n     * Gets the version of the OSGI Framework that is currently being used.\n     *\n     * @return The OSGI Framework Version as defined by the System property osgi.framework.version.\n     */\n    public String getOsgiFwVersion();\n\n    /**\n     * Gets the system file separator used by the filesystem.\n     *\n     * @return The system file separator used by the system.\n     */\n    public String getFileSeparator();\n\n    /**\n     * Gets the location where the JVM is stored in the filesystem.\n     *\n     * @return The location of the root JVM directory.\n     */\n    public String getJavaHome();\n\n    /**\n     * Gets the product version for this unit.\n     *\n     * The product version is defined in the kura.version property of the kura.properties file\n     * located in the ${BASE_DIR}/${KURA_SYMLINK}/kura directory.\n     *\n     * @return The Kura version string as denoted in kura.version property of the kura.properties file.\n     */\n    public String getKuraVersion();\n\n    /**\n     * Gets the location where Kura stores the framework configuration files in the filesystem.\n     *\n     * @since 2.0\n     * @return The framework configuration files directory.\n     */\n    public String getKuraFrameworkConfigDirectory();\n\n    /**\n     * Gets the location where Kura stores the user configuration files in the filesystem.\n     *\n     * @since 2.0\n     * @return The user configuration files directory.\n     */\n    public String getKuraUserConfigDirectory();\n\n    /**\n     * Gets the Eclipse Marketplace compatibility product version for this unit.\n     *\n     * The marketplace compatibility product version is defined in the {@code kura.marketplace.compatibility.version}\n     * property of the kura.properties file located in the ${BASE_DIR}/${KURA_SYMLINK}/kura directory.\n     * If the variable {@code kura.marketplace.compatibility.version} cannot be located, it defaults to the value\n     * specified by {@link #getKuraVersion()}.\n     *\n     * @since 1.3\n     * @return The marketplace compatibility Kura version string.\n     */\n    public String getKuraMarketplaceCompatibilityVersion();\n\n    /**\n     * Gets the location where the Kura root directory is stored in the filesystem.\n     *\n     * @return The root Kura directory.\n     */\n    public String getKuraHome();\n\n    /**\n     * Gets the location where all volatile Kura specific configuration and status information should be stored.\n     *\n     * The convention for each bundle that has filesystem dependencies is for those filesystem components\n     * to be stored in the configuration directory root followed by a file separator followed by the project\n     * name that needs some configuration. This will keep separate configuration components tied to their\n     * appropriate projects.\n     *\n     * @return The location of the volatile Kura configuration and status directory root.\n     */\n    public String getKuraTemporaryConfigDirectory();\n\n    /**\n     * Gets the location where all Configuration Snapshots will be stored.\n     * It is recommended for this directory not to be volatile so that the configuration\n     * information can survive reboots and service configuration can be restored.\n     *\n     * @return The location of the volatile Kura configuration and status directory root.\n     */\n    public String getKuraSnapshotsDirectory();\n\n    /**\n     * Returns the maximum number of snapshots to be retained in the file system.\n     * When the maximum number is reached, a garbage collector will delete the older snapshots.\n     *\n     * @return maximum number of snapshots to be retained.\n     */\n    public int getKuraSnapshotsCount();\n\n    /**\n     * Gets the location where all custom style information is stored.\n     *\n     * @return The location of the custom style directory.\n     */\n    public String getKuraStyleDirectory();\n\n    /**\n     * Gets the last wifi channel allowed for this device. In the U.S. this should be\n     * 11. In most of Europe this should be 13.\n     *\n     * @return The last wifi channel allowed for this device (usually 11 or 13)\n     */\n    public int getKuraWifiTopChannel();\n\n    public String getKuraWebEnabled();\n\n    /**\n     * Gets the location where all Kura persistent data should be stored.\n     *\n     * @return The location of the persistent Kura data directory root.\n     */\n    public String getKuraDataDirectory();\n\n    /**\n     * Returns the size in MegaBytes of the maximum file upload size permitted by the local file servlet\n     *\n     * @return The maximum size (in mega bytes) of files that can be uploaded using the command file upload function\n     */\n    public int getFileCommandZipMaxUploadSize();\n\n    /**\n     * Returns the maximum number of files that can be uploaded by the local file servlet\n     *\n     * @return The maximum number of files that can be uploaded using the command file upload function\n     */\n    public int getFileCommandZipMaxUploadNumber();\n\n    /**\n     * Returns all KuraProperties for this system. The returned instances is\n     * initialized by loading the kura.properties file. Properties defined at\n     * the System level - for example using the java -D command line flag -\n     * are used to overwrite the values loaded from the kura.properties file\n     * in a hierarchical configuration fashion.\n     */\n    public Properties getProperties();\n\n    /**\n     * Returns the OSGi bundles currently installed\n     *\n     * @return the list of the installed bundles\n     */\n    public Bundle[] getBundles();\n\n    /**\n     * Returns the system packages currently installed\n     *\n     * @return the list of the installed packages\n     * @throws KuraProcessExecutionErrorException\n     * @since 2.2\n     */\n    public List<SystemResourceInfo> getSystemPackages() throws KuraProcessExecutionErrorException;\n\n    /**\n     * Returns the number of processors visible to this Java platform.\n     *\n     * @return\n     */\n    public int getNumberOfProcessors();\n\n    /**\n     * Returns the total memory visible to this Java instance in kilobytes.\n     *\n     * @return\n     */\n    public long getTotalMemory();\n\n    /**\n     * Returns the free memory for Java instance in kilobytes.\n     *\n     * @return\n     */\n    public long getFreeMemory();\n\n    /**\n     * Returns the password to access the private key from the keystore file.\n     *\n     * @return\n     */\n    public char[] getJavaKeyStorePassword();\n\n    /**\n     * Returns the password to unlock the trust store keystore file.\n     *\n     * @return\n     */\n    public char[] getJavaTrustStorePassword();\n\n    /**\n     * Returns a list of services that should be ignored by the Cloud services\n     *\n     * @return\n     */\n    public List<String> getDeviceManagementServiceIgnore();\n\n    /**\n     * Returns the device hostname\n     *\n     * @return a String that represents the device hostname\n     * @since 2.0\n     */\n    public String getHostname();\n\n    /**\n     * Returns the default configuration for virtual network interfaces\n     *\n     * @return a String that represent the default configuration for virtual interfaces\n     * @since 2.2\n     */\n    public String getNetVirtualDevicesConfig();\n\n    /**\n     * Gets the user to be used for running commands.\n     *\n     * @since 2.2\n     * @return command user\n     */\n    public String getCommandUser();\n\n    /**\n     * Gets the CPU version of the device.\n     *\n     * @since 2.2\n     * @return CPU version\n     */\n    public String getCpuVersion();\n\n    /**\n     * Returns a set of {@link ExtendedProperties}.\n     *\n     * @since 2.2\n     * @return the extended properties, or empty if the SystemService implementation does not provide extended\n     *         properties.\n     */\n    public Optional<ExtendedProperties> getExtendedProperties();\n\n    /**\n     * Returns the configuration for the bluetooth beacon scan.\n     * If true, the legacy \"hcitool\" is used for beacon scanning.\n     *\n     * @since 2.2\n     * @return if the legacy beacon scan has to be used\n     */\n    public boolean isLegacyBluetoothBeaconScan();\n\n    /**\n     * Returns true (default) if the PPP logging in separate log file in /var/log is enabled.\n     *\n     * @since 2.3\n     * @return true if separate log file in /var/log is required\n     */\n    public boolean isLegacyPPPLoggingEnabled();\n\n    /**\n     * Gets the Java Virtual Machine implementation vendor that is currently being\n     * used.\n     *\n     * @since 2.6\n     * @return the Java Virtual Machine version as defined by the Java System\n     *         property java.vm.vendor.\n     */\n    public String getJavaVmVendor();\n\n    /**\n     *\n     *\n     * @since 2.6\n     * @return the String representing the Java System property jdk.vendor.version.\n     */\n    public String getJdkVendorVersion();\n\n    /**\n     * Returns the name of the default LogManager, if any.\n     *\n     * @since 2.8\n     * @return the optional default LogManager\n     */\n    public Optional<String> getDefaultLogManager();\n\n    /**\n     * Returns true if the WPA3 WiFi Security is enabled on this device.\n     * The default is false.\n     *\n     * @since 3.0\n     * @return true if the WPA3 WiFi Security is enabled\n     */\n    public boolean isWPA3WifiSecurityEnabled();\n\n    /**\n     * Returns the timeout in seconds used for applying a network configuration.\n     *\n     * @since 3.0\n     * @return the timeout value in seconds\n     */\n    public int getNetworkConfigurationTimeout();\n\n    /**\n     * Indicates whether or not the device is connected to the internet and the status.\n     * The status is updated every 30 seconds and the verification process uses an ICMP request.\n     *\n     * @since 3.0\n     * @return the {@link InternetConnectionStatus}\n     */\n    public InternetConnectionStatus getInternetConnectionStatus();\n\n    /**\n     * Return the inet address used to check the internet connection. Must support ICMP protocol.\n     *\n     * @since 3.0\n     * @return the inet address used to check the internet connection. Default value is 198.41.30.198 (current\n     *         eclipse.org IP address, which may change over time; this value should be updated if the eclipse.org IP\n     *         changes)\n     */\n    public String getInternetConnectionStatusCheckIp();\n\n    /**\n     * Returns the hostname used to check the internet connection. Must support ICMP protocol.\n     *\n     * @since 3.0\n     * @return the hostname address used to check the internet connection. Default value is eclipse.org\n     */\n    public String getInternetConnectionStatusCheckHost();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Contains services to get system information and perform basic system tasks.\n *\n */\npackage org.eclipse.kura.system;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/BooleanValue.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.type;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.type.DataType.BOOLEAN;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents a {@link Boolean} value as a {@link TypedValue}.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class BooleanValue implements TypedValue<Boolean> {\n\n    /**\n     * The actual contained value that will be represented as\n     * {@link TypedValue}.\n     */\n    private final boolean value;\n\n    /**\n     * Instantiates a new boolean value.\n     *\n     * @param value\n     *            the value\n     */\n    public BooleanValue(final boolean value) {\n        this.value = value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int compareTo(final TypedValue<Boolean> otherTypedValue) {\n        requireNonNull(otherTypedValue, \"Typed Value cannot be null\");\n        return this.value == otherTypedValue.getValue() ? 0 : this.value ? 1 : -1;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public boolean equals(final Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (this.getClass() != obj.getClass()) {\n            return false;\n        }\n        final BooleanValue other = (BooleanValue) obj;\n        if (this.value != other.value) {\n            return false;\n        }\n        return true;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public DataType getType() {\n        return BOOLEAN;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public Boolean getValue() {\n        return this.value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.value ? 1231 : 1237);\n        return result;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"BooleanValue [value=\" + this.value + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/ByteArrayValue.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.type;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.type.DataType.BYTE_ARRAY;\n\nimport java.util.Arrays;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents a {@link Byte[]} value as a {@link TypedValue}.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class ByteArrayValue implements TypedValue<byte[]> {\n\n    /**\n     * The actual contained value that will be represented as\n     * {@link TypedValue}.\n     */\n    private final byte[] value;\n\n    /**\n     * Instantiates a new byte array value.\n     *\n     * @param value\n     *            the value\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public ByteArrayValue(final byte[] value) {\n        requireNonNull(value, \"Provided Typed Value cannot be null\");\n        this.value = value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int compareTo(final TypedValue<byte[]> otherTypedValue) {\n        requireNonNull(otherTypedValue, \"Typed Value cannot be null\");\n        final byte[] otherValue = otherTypedValue.getValue();\n        for (int i = 0, j = 0; i < this.value.length && j < otherValue.length; i++, j++) {\n            final int a = this.value[i] & 0xff;\n            final int b = otherValue[j] & 0xff;\n            if (a != b) {\n                return a - b;\n            }\n        }\n        return this.value.length - otherValue.length;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public boolean equals(final Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (this.getClass() != obj.getClass()) {\n            return false;\n        }\n        final ByteArrayValue other = (ByteArrayValue) obj;\n        if (!Arrays.equals(this.value, other.value)) {\n            return false;\n        }\n        return true;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public DataType getType() {\n        return BYTE_ARRAY;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public byte[] getValue() {\n        return this.value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + Arrays.hashCode(this.value);\n        return result;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"ByteArrayValue [value=\" + Arrays.toString(this.value) + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/DataType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.type;\n\n/**\n * This contains all the required data type constants required for representing\n * Java data types as {@link TypedValue}\n *\n * @since 1.2\n */\npublic enum DataType {\n\n    BOOLEAN,\n\n    BYTE_ARRAY,\n\n    DOUBLE,\n\n    INTEGER,\n\n    LONG,\n\n    FLOAT,\n\n    STRING;\n\n    /**\n     * Converts {@code stringDataType}, if possible, to the related {@link DataType}.\n     *\n     * @param stringDataType\n     *            String that we want to use to get the respective {@link DataType}.\n     * @return a DataType that corresponds to the String passed as argument.\n     * @throws IllegalArgumentException\n     *             if the passed string does not correspond to an existing {@link DataType}.\n     */\n    public static DataType getDataType(String stringDataType) {\n        if (INTEGER.name().equalsIgnoreCase(stringDataType)) {\n            return INTEGER;\n        }\n        if (FLOAT.name().equalsIgnoreCase(stringDataType)) {\n            return FLOAT;\n        }\n        if (DOUBLE.name().equalsIgnoreCase(stringDataType)) {\n            return DOUBLE;\n        }\n        if (LONG.name().equalsIgnoreCase(stringDataType)) {\n            return LONG;\n        }\n        if (BYTE_ARRAY.name().equalsIgnoreCase(stringDataType)) {\n            return BYTE_ARRAY;\n        }\n        if (BOOLEAN.name().equalsIgnoreCase(stringDataType)) {\n            return BOOLEAN;\n        }\n        if (STRING.name().equalsIgnoreCase(stringDataType)) {\n            return STRING;\n        }\n\n        throw new IllegalArgumentException(\"Cannot convert to DataType\");\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/DoubleValue.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.type;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.type.DataType.DOUBLE;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents a {@link Double} value as a {@link TypedValue}.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class DoubleValue implements TypedValue<Double> {\n\n    /**\n     * The actual contained value that will be represented as\n     * {@link TypedValue}.\n     */\n    private final double value;\n\n    /**\n     * Instantiates a new double value.\n     *\n     * @param value\n     *            the value\n     */\n    public DoubleValue(final double value) {\n        this.value = value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int compareTo(final TypedValue<Double> otherTypedValue) {\n        requireNonNull(otherTypedValue, \"Typed Value cannot be null\");\n        return Double.valueOf(this.value).compareTo(otherTypedValue.getValue());\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public boolean equals(final Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (this.getClass() != obj.getClass()) {\n            return false;\n        }\n        final DoubleValue other = (DoubleValue) obj;\n        if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value)) {\n            return false;\n        }\n        return true;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public DataType getType() {\n        return DOUBLE;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public Double getValue() {\n        return this.value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        long temp;\n        temp = Double.doubleToLongBits(this.value);\n        result = prime * result + (int) (temp ^ temp >>> 32);\n        return result;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"DoubleValue [value=\" + this.value + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/FloatValue.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.type;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.type.DataType.FLOAT;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents a {@link Float} value as a {@link TypedValue}.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class FloatValue implements TypedValue<Float> {\n\n    /**\n     * The actual contained value that will be represented as\n     * {@link TypedValue}.\n     */\n    private final float value;\n\n    /**\n     * Instantiates a new {@link Float} value.\n     *\n     * @param value\n     *            the value\n     */\n    public FloatValue(final float value) {\n        this.value = value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int compareTo(final TypedValue<Float> otherTypedValue) {\n        requireNonNull(otherTypedValue, \"Typed Value cannot be null\");\n        return Float.valueOf(this.value).compareTo(otherTypedValue.getValue());\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof FloatValue)) {\n            return false;\n        }\n        FloatValue other = (FloatValue) obj;\n        if (Float.floatToIntBits(this.value) != Float.floatToIntBits(other.value)) {\n            return false;\n        }\n        return true;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public DataType getType() {\n        return FLOAT;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public Float getValue() {\n        return this.value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + Float.floatToIntBits(this.value);\n        return result;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"FloatValue [value=\" + this.value + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/IntegerValue.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.type;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.type.DataType.INTEGER;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents a {@link Integer} value as a {@link TypedValue}.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class IntegerValue implements TypedValue<Integer> {\n\n    /**\n     * The actual contained value that will be represented as\n     * {@link TypedValue}.\n     */\n    private final int value;\n\n    /**\n     * Instantiates a new integer value.\n     *\n     * @param value\n     *            the value\n     */\n    public IntegerValue(final int value) {\n        this.value = value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int compareTo(final TypedValue<Integer> otherTypedValue) {\n        requireNonNull(otherTypedValue, \"Typed Value cannot be null\");\n        return Integer.valueOf(this.value).compareTo(otherTypedValue.getValue());\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public boolean equals(final Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (this.getClass() != obj.getClass()) {\n            return false;\n        }\n        final IntegerValue other = (IntegerValue) obj;\n        if (this.value != other.value) {\n            return false;\n        }\n        return true;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public DataType getType() {\n        return INTEGER;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public Integer getValue() {\n        return this.value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + this.value;\n        return result;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"IntegerValue [value=\" + this.value + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/LongValue.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.type;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.type.DataType.LONG;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents a {@link Long} value as a {@link TypedValue}.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class LongValue implements TypedValue<Long> {\n\n    /**\n     * The actual contained value that will be represented as\n     * {@link TypedValue}.\n     */\n    private final long value;\n\n    /**\n     * Instantiates a new long value.\n     *\n     * @param value\n     *            the value\n     */\n    public LongValue(final long value) {\n        this.value = value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int compareTo(final TypedValue<Long> otherTypedValue) {\n        requireNonNull(otherTypedValue, \"Typed Value cannot be null\");\n        return Long.valueOf(this.value).compareTo(otherTypedValue.getValue());\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public boolean equals(final Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (this.getClass() != obj.getClass()) {\n            return false;\n        }\n        final LongValue other = (LongValue) obj;\n        if (this.value != other.value) {\n            return false;\n        }\n        return true;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public DataType getType() {\n        return LONG;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public Long getValue() {\n        return this.value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (int) (this.value ^ this.value >>> 32);\n        return result;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"LongValue [value=\" + this.value + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/StringValue.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.type;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.type.DataType.STRING;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.Nullable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This class represents a {@link String} value as a {@link TypedValue}.\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class StringValue implements TypedValue<String> {\n\n    /**\n     * The actual contained value that will be represented as\n     * {@link TypedValue}.\n     */\n    private final String value;\n\n    /**\n     * Instantiates a new string value.\n     *\n     * @param value\n     *            the value\n     */\n    public StringValue(@Nullable final String value) {\n        this.value = value == null ? \"\" : value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int compareTo(final TypedValue<String> otherTypedValue) {\n        requireNonNull(otherTypedValue, \"Typed Value cannot be null\");\n        return this.value.compareTo(otherTypedValue.getValue());\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public boolean equals(final Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (this.getClass() != obj.getClass()) {\n            return false;\n        }\n        final StringValue other = (StringValue) obj;\n        if (this.value == null) {\n            if (other.value != null) {\n                return false;\n            }\n        } else if (!this.value.equals(other.value)) {\n            return false;\n        }\n        return true;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public DataType getType() {\n        return STRING;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String getValue() {\n        return this.value;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.value == null ? 0 : this.value.hashCode());\n        return result;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"StringValue [value=\" + this.value + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/TypedValue.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.type;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface wraps a Java data type with its represented value format\n *\n * @param <T>\n *            The Java Value Type to be represented\n *\n * @see TypedValues\n * @see BooleanValue\n * @see ByteArrayValue\n * @see FloatValue\n * @see DoubleValue\n * @see IntegerValue\n * @see StringValue\n * @see DataType\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n */\n@ProviderType\npublic interface TypedValue<T> extends Comparable<TypedValue<T>> {\n\n    /**\n     * Returns the data type of the represented value\n     *\n     * @return the datatype as associated\n     */\n    public DataType getType();\n\n    /**\n     * Returns the actual value as represented\n     *\n     * @return the value as associated\n     */\n    public T getValue();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/TypedValues.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.type;\n\nimport java.util.Base64;\nimport java.util.Base64.Decoder;\nimport java.util.Objects;\n\nimport org.eclipse.kura.annotation.Nullable;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Class TypedValues is an utility class to quickly create different\n * {@link TypedValue}\n *\n * @since 1.2\n */\n@ProviderType\npublic final class TypedValues {\n\n    private static final Decoder BASE64_DECODER = Base64.getDecoder();\n\n    private TypedValues() {\n        // Static Factory Methods container. No need to instantiate.\n    }\n\n    /**\n     * Creates new boolean value.\n     *\n     * @param value\n     *            the primitive boolean value\n     * @return the boolean value represented as {@link TypedValue}\n     */\n    public static BooleanValue newBooleanValue(final boolean value) {\n        return new BooleanValue(value);\n    }\n\n    /**\n     * Creates new byte array value.\n     *\n     * @param value\n     *            the primitive byte array value\n     * @return the byte array value represented as {@link TypedValue}\n     * @throws org.eclipse.kura.KuraRuntimeException\n     *             if the argument is null\n     */\n    public static ByteArrayValue newByteArrayValue(final byte[] value) {\n        return new ByteArrayValue(value);\n    }\n\n    /**\n     * Creates new float value.\n     *\n     * @param value\n     *            the primitive float value\n     * @return the float value represented as {@link TypedValue}\n     */\n    public static FloatValue newFloatValue(final float value) {\n        return new FloatValue(value);\n    }\n\n    /**\n     * Creates new double value.\n     *\n     * @param value\n     *            the primitive double value\n     * @return the double value represented as {@link TypedValue}\n     */\n    public static DoubleValue newDoubleValue(final double value) {\n        return new DoubleValue(value);\n    }\n\n    /**\n     * Creates new integer value.\n     *\n     * @param value\n     *            the primitive integer value\n     * @return the integer value represented as {@link TypedValue}\n     */\n    public static IntegerValue newIntegerValue(final int value) {\n        return new IntegerValue(value);\n    }\n\n    /**\n     * Creates new long value.\n     *\n     * @param value\n     *            the primitive long value\n     * @return the long value represented as {@link TypedValue}\n     */\n    public static LongValue newLongValue(final long value) {\n        return new LongValue(value);\n    }\n\n    /**\n     * Creates new string value.\n     *\n     * @param value\n     *            the string value to be represented as {@link TypedValue}\n     * @return the string value represented as {@link TypedValue}\n     */\n    public static StringValue newStringValue(@Nullable final String value) {\n        return new StringValue(value);\n    }\n\n    /**\n     * Creates new TypedValue inferring the type from the argument.\n     *\n     * @param value\n     *            an object that needs to be represented as {@link TypedValue}\n     * @return a {@link TypedValue} that represents the conversion of {@code value}\n     * @throws IllegalArgumentException\n     *             if {@code value} cannot be represented as {@link TypedValue}\n     */\n    public static TypedValue<?> newTypedValue(final Object value) {\n        if (value instanceof Boolean) {\n            return newBooleanValue((Boolean) value);\n        } else if (value instanceof byte[]) {\n            return newByteArrayValue((byte[]) value);\n        } else if (value instanceof Float) {\n            return newFloatValue((Float) value);\n        } else if (value instanceof Double) {\n            return newDoubleValue((Double) value);\n        } else if (value instanceof Integer) {\n            return newIntegerValue((Integer) value);\n        } else if (value instanceof Long) {\n            return newLongValue((Long) value);\n        } else if (value instanceof String) {\n            return newStringValue((String) value);\n        }\n\n        throw new IllegalArgumentException(\"Cannot convert to TypedValue\");\n    }\n\n    /**\n     * Parses a TypedValue of given type from a String.\n     *\n     * @param value\n     *            the String to be parsed into a {@link TypedValue}\n     * @param type\n     *            the {@link DataType} of the returned {@link TypedValue}\n     * @return a {@link TypedValue} that represents the conversion of {@code value}\n     * @throws IllegalArgumentException\n     *             if {@code value} cannot be represented as {@link TypedValue}\n     */\n    public static TypedValue<?> parseTypedValue(final DataType type, final String value) {\n        Objects.requireNonNull(value, \"value cannot be null\");\n        try {\n            switch (type) {\n            case BOOLEAN:\n                return newBooleanValue(Boolean.parseBoolean(value));\n            case BYTE_ARRAY:\n                return TypedValues.newByteArrayValue(BASE64_DECODER.decode(value));\n            case DOUBLE:\n                return newDoubleValue(Double.parseDouble(value));\n            case FLOAT:\n                return newFloatValue(Float.parseFloat(value));\n            case INTEGER:\n                return newIntegerValue(Integer.parseInt(value));\n            case LONG:\n                return newLongValue(Long.parseLong(value));\n            case STRING:\n                return newStringValue(value);\n            default:\n            }\n        } catch (Exception e) {\n        }\n        throw new IllegalArgumentException(value + \" cannot be converted into a TypedValue of type \" + type);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\n/**\n * This package provides wrapper value types which represents actual Java value\n * types as {@link org.eclipse.kura.type.TypedValue} and all utility classes\n * comprising necessary static factory methods\n *\n * @since 1.0.10\n */\npackage org.eclipse.kura.type;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/AbstractUsbDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Base class for USB devices\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic abstract class AbstractUsbDevice implements UsbDevice {\n\n    /** The vendor ID of the USB device **/\n    private final String vendorId;\n\n    /** The product ID of the USB device **/\n    private final String productId;\n\n    /** The manufacturer name **/\n    private final String manufacturerName;\n\n    /** The product name **/\n    private final String productName;\n\n    private final String usbBusNumber;\n    private final String usbDevicePath;\n\n    public AbstractUsbDevice(String vendorId, String productId, String manufacturerName, String productName,\n            String usbBusNumber, String usbDevicePath) {\n        this.vendorId = vendorId;\n        this.productId = productId;\n        this.manufacturerName = manufacturerName;\n        this.productName = productName;\n        this.usbBusNumber = usbBusNumber;\n        this.usbDevicePath = usbDevicePath;\n    }\n\n    public AbstractUsbDevice(AbstractUsbDevice usbDevice) {\n        this.vendorId = usbDevice.getVendorId();\n        this.productId = usbDevice.getProductId();\n        this.manufacturerName = usbDevice.getManufacturerName();\n        this.productName = usbDevice.getProductName();\n        this.usbBusNumber = usbDevice.getUsbBusNumber();\n        this.usbDevicePath = usbDevice.getUsbDevicePath();\n    }\n\n    @Override\n    public String getVendorId() {\n        return this.vendorId;\n    }\n\n    @Override\n    public String getProductId() {\n        return this.productId;\n    }\n\n    @Override\n    public String getManufacturerName() {\n        return this.manufacturerName;\n    }\n\n    @Override\n    public String getProductName() {\n        return this.productName;\n    }\n\n    @Override\n    public String getUsbBusNumber() {\n        return this.usbBusNumber;\n    }\n\n    @Override\n    public String getUsbDevicePath() {\n        return this.usbDevicePath;\n    }\n\n    @Override\n    public String getUsbPort() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(this.usbBusNumber).append(\"-\").append(this.usbDevicePath);\n        return sb.toString();\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.manufacturerName == null ? 0 : this.manufacturerName.hashCode());\n        result = prime * result + (this.productId == null ? 0 : this.productId.hashCode());\n        result = prime * result + (this.productName == null ? 0 : this.productName.hashCode());\n        result = prime * result + (this.usbBusNumber == null ? 0 : this.usbBusNumber.hashCode());\n        result = prime * result + (this.usbDevicePath == null ? 0 : this.usbDevicePath.hashCode());\n        result = prime * result + (this.vendorId == null ? 0 : this.vendorId.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        AbstractUsbDevice other = (AbstractUsbDevice) obj;\n        if (this.manufacturerName == null) {\n            if (other.manufacturerName != null) {\n                return false;\n            }\n        } else if (!this.manufacturerName.equals(other.manufacturerName)) {\n            return false;\n        }\n        if (this.productId == null) {\n            if (other.productId != null) {\n                return false;\n            }\n        } else if (!this.productId.equals(other.productId)) {\n            return false;\n        }\n        if (this.productName == null) {\n            if (other.productName != null) {\n                return false;\n            }\n        } else if (!this.productName.equals(other.productName)) {\n            return false;\n        }\n        if (this.usbBusNumber == null) {\n            if (other.usbBusNumber != null) {\n                return false;\n            }\n        } else if (!this.usbBusNumber.equals(other.usbBusNumber)) {\n            return false;\n        }\n        if (this.usbDevicePath == null) {\n            if (other.usbDevicePath != null) {\n                return false;\n            }\n        } else if (!this.usbDevicePath.equals(other.usbDevicePath)) {\n            return false;\n        }\n        if (this.vendorId == null) {\n            if (other.vendorId != null) {\n                return false;\n            }\n        } else if (!this.vendorId.equals(other.vendorId)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbBlockDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Representation of a USB block device. This includes storage type USB devices.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class UsbBlockDevice extends AbstractUsbDevice {\n\n    private final String deviceNode;\n\n    public UsbBlockDevice(String vendorId, String productId, String manufacturerName, String productName,\n            String usbBusNumber, String usbDevicePath, String deviceNode) {\n        super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath);\n        this.deviceNode = deviceNode;\n    }\n\n    public String getDeviceNode() {\n        return this.deviceNode;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + (this.deviceNode == null ? 0 : this.deviceNode.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj)) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        UsbBlockDevice other = (UsbBlockDevice) obj;\n        if (this.deviceNode == null) {\n            if (other.deviceNode != null) {\n                return false;\n            }\n        } else if (!this.deviceNode.equals(other.deviceNode)) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        return \"UsbBlockDevice [getDeviceNode()=\" + getDeviceNode() + \", getVendorId()=\" + getVendorId()\n                + \", getProductId()=\" + getProductId() + \", getManufacturerName()=\" + getManufacturerName()\n                + \", getProductName()=\" + getProductName() + \", getUsbBusNumber()=\" + getUsbBusNumber()\n                + \", getUsbDevicePath()=\" + getUsbDevicePath() + \", getUsbPort()=\" + getUsbPort() + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Interface for all USB devices\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface UsbDevice {\n\n    /**\n     * The vendor ID of the device\n     *\n     * @return The vendor ID of the device\n     */\n    public String getVendorId();\n\n    /**\n     * The product ID of the device\n     *\n     * @return The product ID of the device\n     */\n    public String getProductId();\n\n    /**\n     * The manufacturer name of the device\n     *\n     * @return The manufacturer name of the device\n     */\n    public String getManufacturerName();\n\n    /**\n     * The product name of the device\n     *\n     * @return The product name of the device\n     */\n    public String getProductName();\n\n    /**\n     * The USB bus number of the device\n     *\n     * @return The USB bus number of the device\n     */\n    public String getUsbBusNumber();\n\n    /**\n     * The USB device path\n     *\n     * @return The USB device path\n     */\n    public String getUsbDevicePath();\n\n    /**\n     * The complete USB port (USB bus number plus USB device path)\n     *\n     * @return The complete USB port (USB bus number plus USB device path)\n     */\n    public String getUsbPort();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDeviceAddedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * An event raised when a new USB device has been added to the system.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class UsbDeviceAddedEvent extends Event implements UsbDeviceEvent {\n\n    /** Topic of the UsbDeviceAddedEvent */\n    public static final String USB_EVENT_DEVICE_ADDED_TOPIC = \"org/eclipse/kura/usb/NetworkEvent/device/ADDED\";\n\n    public UsbDeviceAddedEvent(Map<String, ?> properties) {\n        super(USB_EVENT_DEVICE_ADDED_TOPIC, properties);\n    }\n\n    /**\n     * Returns the name of the USB port.\n     *\n     * @return\n     */\n    public String getUsbPort() {\n        return (String) getProperty(USB_EVENT_USB_PORT_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB resource associated with this device.\n     *\n     * @return\n     */\n    public String getUsbResource() {\n        return (String) getProperty(USB_EVENT_RESOURCE_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB vendor ID associated with this device.\n     *\n     * @return\n     */\n    public String getUsbVendorId() {\n        return (String) getProperty(USB_EVENT_VENDOR_ID_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB product ID associated with this device.\n     *\n     * @return\n     */\n    public String getUsbProductId() {\n        return (String) getProperty(USB_EVENT_PRODUCT_ID_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB manufacturer name associated with this device.\n     *\n     * @return\n     */\n    public String getUsbManufacturerName() {\n        return (String) getProperty(USB_EVENT_MANUFACTURER_NAME_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB product name associated with this device.\n     *\n     * @return\n     */\n    public String getUsbProductName() {\n        return (String) getProperty(USB_EVENT_PRODUCT_NAME_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB bus number associated with this device.\n     *\n     * @return\n     */\n    public String getUsbBusNumber() {\n        return (String) getProperty(USB_EVENT_BUS_NUMBER_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB device path associated with this device.\n     *\n     * @return\n     */\n    public String getUsbDevicePath() {\n        return (String) getProperty(USB_EVENT_DEVICE_PATH_PROPERTY);\n    }\n\n    /**\n     * Returns the USB device type.\n     *\n     * @return UsbDeviceType or null if the property is not set\n     * @since 1.4\n     */\n    public UsbDeviceType getUsbDeviceType() {\n        return (UsbDeviceType) getProperty(USB_EVENT_DEVICE_TYPE_PROPERTY);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDeviceEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\n@SuppressWarnings(\"checkstyle:interfaceIsType\")\npublic interface UsbDeviceEvent {\n\n    /** Name of the property to access the USB port of this device **/\n    public static final String USB_EVENT_USB_PORT_PROPERTY = \"usb.port\";\n\n    /**\n     * Name of the property to access the resource name associated with this USB device (e.g. /dev/ttyUSB3, eth3, etc\n     * depending on the device type)\n     */\n    public static final String USB_EVENT_RESOURCE_PROPERTY = \"usb.resource\";\n\n    /** Name of the property to access the vendor id **/\n    public static final String USB_EVENT_VENDOR_ID_PROPERTY = \"usb.vendor.id\";\n\n    /** Name of the property to access the product id **/\n    public static final String USB_EVENT_PRODUCT_ID_PROPERTY = \"usb.product.id\";\n\n    /** Name of the property to access the manufacturer name **/\n    public static final String USB_EVENT_MANUFACTURER_NAME_PROPERTY = \"usb.manufacturer.name\";\n\n    /** Name of the property to access the product name **/\n    public static final String USB_EVENT_PRODUCT_NAME_PROPERTY = \"usb.product.name\";\n\n    /** Name of the property to access the USB bus number **/\n    public static final String USB_EVENT_BUS_NUMBER_PROPERTY = \"usb.bus.number\";\n\n    /** Name of the property to access the USB device path **/\n    public static final String USB_EVENT_DEVICE_PATH_PROPERTY = \"usb.device.path\";\n\n    /**\n     * Name of the property to access the USB device type\n     *\n     * @since 1.4\n     **/\n    public static final String USB_EVENT_DEVICE_TYPE_PROPERTY = \"usb.device.type\";\n\n    /**\n     * Name of the property to access the interface number of a USB device\n     *\n     * @since 1.4\n     **/\n    public static final String USB_EVENT_USB_INTERFACE_NUMBER = \"usb.interface.number\";\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDeviceRemovedEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport java.util.Map;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.event.Event;\n\n/**\n * An event raised when a USB device has been removed from the system.\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class UsbDeviceRemovedEvent extends Event implements UsbDeviceEvent {\n\n    /** Topic of the UsbDeviceRemovedEvent */\n    public static final String USB_EVENT_DEVICE_REMOVED_TOPIC = \"org/eclipse/kura/usb/NetworkEvent/device/REMOVED\";\n\n    public UsbDeviceRemovedEvent(Map<String, ?> properties) {\n        super(USB_EVENT_DEVICE_REMOVED_TOPIC, properties);\n    }\n\n    /**\n     * Returns the name of the USB port.\n     *\n     * @return\n     */\n    public String getUsbPort() {\n        return (String) getProperty(USB_EVENT_USB_PORT_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB resource associated with this device.\n     *\n     * @return\n     */\n    public String getUsbResource() {\n        return (String) getProperty(USB_EVENT_RESOURCE_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB vendor ID associated with this device.\n     *\n     * @return\n     */\n    public String getUsbVendorId() {\n        return (String) getProperty(USB_EVENT_VENDOR_ID_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB product ID associated with this device.\n     *\n     * @return\n     */\n    public String getUsbProductId() {\n        return (String) getProperty(USB_EVENT_PRODUCT_ID_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB manufacturer name associated with this device.\n     *\n     * @return\n     */\n    public String getUsbManufacturerName() {\n        return (String) getProperty(USB_EVENT_MANUFACTURER_NAME_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB product name associated with this device.\n     *\n     * @return\n     */\n    public String getUsbProductName() {\n        return (String) getProperty(USB_EVENT_PRODUCT_NAME_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB bus number associated with this device.\n     *\n     * @return\n     */\n    public String getUsbBusNumber() {\n        return (String) getProperty(USB_EVENT_BUS_NUMBER_PROPERTY);\n    }\n\n    /**\n     * Returns the name of the USB device path associated with this device.\n     *\n     * @return\n     */\n    public String getUsbDevicePath() {\n        return (String) getProperty(USB_EVENT_DEVICE_PATH_PROPERTY);\n    }\n\n    /**\n     * Returns the USB device type.\n     *\n     * @return UsbDeviceType or null if the property is not set\n     * @since 1.4\n     */\n    public UsbDeviceType getUsbDeviceType() {\n        return (UsbDeviceType) getProperty(USB_EVENT_DEVICE_TYPE_PROPERTY);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDeviceType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.usb;\n\n/**\n * UsbDeviceType represents the type of USB device.\n * Possible values are:\n * UsbBlockDevice, UsbModemDevice, UsbNetDevice and UsbTtyDevice\n *\n * @since 1.4\n */\npublic enum UsbDeviceType {\n\n    USB_BLOCK_DEVICE,\n    USB_MODEM_DEVICE,\n    USB_NET_DEVICE,\n    USB_TTY_DEVICE\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbModemDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\n\nimport org.eclipse.kura.net.modem.ModemDevice;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Representation of USB modem devices\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class UsbModemDevice extends AbstractUsbDevice implements ModemDevice {\n\n    /** The TTY devices associated with modem **/\n    private final ArrayList<TtyDev> ttyDevs;\n\n    /** The block devices associated with the modem **/\n    private final ArrayList<String> blockDevs;\n\n    public UsbModemDevice(String vendorId, String productId, String manufacturerName, String productName,\n            String usbBusNumber, String usbDevicePath) {\n        super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath);\n\n        this.ttyDevs = new ArrayList<>();\n        this.blockDevs = new ArrayList<>();\n    }\n\n    public UsbModemDevice(AbstractUsbDevice usbDevice) {\n        super(usbDevice);\n\n        this.ttyDevs = new ArrayList<>();\n        this.blockDevs = new ArrayList<>();\n    }\n\n    @Override\n    public List<String> getSerialPorts() {\n        List<String> serialPorts = new ArrayList<>();\n        for (TtyDev dev : this.ttyDevs) {\n            serialPorts.add(dev.getPortName());\n        }\n        return serialPorts;\n    }\n\n    /**\n     * Return a list of tty devices, sorted in a way to facilitate the client code identifying dedicated devices,\n     * e.g. for AT commands, PPP link or NMEA sentences, based on their position in the list.\n     * Originally, only the tty name was used for the comparison. This proved to be wrong as a tty name does reliably\n     * identify the USB interface number (bInterfaceNumber) of the tty device.\n     * To preserve the API contract, the tty devices can be added specifying the USB interface number and this will be\n     * used to sort the list.\n     *\n     * @return sorted list of tty devices\n     */\n    public List<String> getTtyDevs() {\n        return getSerialPorts();\n    }\n\n    /**\n     * @return sorted list of block devices\n     */\n    public List<String> getBlockDevs() {\n        return Collections.unmodifiableList(this.blockDevs);\n    }\n\n    /**\n     * Adds a tty device identified by its name and USB interface number (bInterfaceNumber).\n     * The devices will be sorted by the interface number. If this is missing, the name will be used.\n     *\n     * @since 1.4\n     *\n     * @param ttyDev\n     *            the name of the tty device\n     * @param interfaceNumber\n     *            the number of the interface as described by the bInterfaceNumber property\n     */\n    public void addTtyDev(String ttyDev, Integer interfaceNumber) {\n        TtyDev dev = new TtyDev(ttyDev, interfaceNumber);\n        if (!this.ttyDevs.contains(dev)) {\n            this.ttyDevs.add(new TtyDev(ttyDev, interfaceNumber));\n            Collections.sort(this.ttyDevs, new TtyDevComparator());\n        }\n    }\n\n    /**\n     * @deprecated this method is deprecated in favor of addTtyDev(String ttyDev, Integer interfaceNumber)\n     */\n    @Deprecated\n    public void addTtyDev(String ttyDev) {\n        addTtyDev(ttyDev, null);\n    }\n\n    /**\n     * Adds a block device identified by its name. The block devices will be sorted by the name.\n     *\n     * @param blockDev\n     *            the name of the block device\n     */\n    public void addBlockDev(String blockDev) {\n        if (!this.blockDevs.contains(blockDev)) {\n            this.blockDevs.add(blockDev);\n            Collections.sort(this.blockDevs, new DevNameComparator());\n        }\n    }\n\n    /**\n     * Remove a tty device form the list.\n     *\n     * @param ttyDev\n     *            the name of the tty device\n     * @return true if the list contained the specified device\n     */\n    public boolean removeTtyDev(String ttyDev) {\n        return this.ttyDevs.remove(new TtyDev(ttyDev));\n    }\n\n    /**\n     * Remove a block device form the list.\n     *\n     * @param blockDev\n     *            the name of the block device\n     * @return true if the list contained the specified device\n     */\n    public boolean removeBlockDev(String blockDev) {\n        return this.blockDevs.remove(blockDev);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 37;\n        int result = super.hashCode();\n        result = prime * result + (this.ttyDevs == null ? 0 : this.ttyDevs.hashCode());\n        result = prime * result + (this.blockDevs == null ? 0 : this.blockDevs.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj)) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        UsbModemDevice other = (UsbModemDevice) obj;\n        if (this.ttyDevs == null) {\n            if (other.ttyDevs != null) {\n                return false;\n            }\n        } else if (!this.ttyDevs.equals(other.ttyDevs)) {\n            return false;\n        }\n        if (this.blockDevs == null) {\n            if (other.blockDevs != null) {\n                return false;\n            }\n        } else if (!this.blockDevs.equals(other.blockDevs)) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"UsbModem [\");\n        sb.append(\"vendorId=\").append(getVendorId());\n        sb.append(\", productId=\").append(getProductId());\n        sb.append(\", manufName=\").append(getManufacturerName());\n        sb.append(\", productName=\").append(getProductName());\n        sb.append(\", usbPort=\").append(getUsbPort());\n        sb.append(\", ttyDevs=\").append(this.ttyDevs.toString());\n        sb.append(\", blockDevs=\").append(this.blockDevs.toString());\n        sb.append(\"]\");\n\n        return sb.toString();\n    }\n\n    private class DevNameComparator implements Comparator<String> {\n\n        @Override\n        /**\n         * Split the device name into the digit and non-digit portions and compare separately\n         * i.e. for \"/dev/ttyUSB9\" and \"/dev/ttyUSB10\", the \"/dev/ttyUSB\" parts are first compared\n         * then the \"9\" and \"10\" are compared numerically.\n         */\n        public int compare(String dev1, String dev2) {\n            int digitPos1 = getDigitPosition(dev1);\n            int digitPos2 = getDigitPosition(dev2);\n\n            String text1 = dev1.substring(0, digitPos1);\n            String text2 = dev2.substring(0, digitPos2);\n\n            String num1 = dev1.substring(digitPos1, dev1.length());\n            String num2 = dev2.substring(digitPos2, dev2.length());\n\n            // Compare text portion\n            int textCompare = text1.compareTo(text2);\n            if (textCompare != 0) {\n                return textCompare;\n            }\n\n            // Compare numerical portion\n            if (num1 == null || num1.isEmpty()) {\n                if (num2 == null || num2.isEmpty()) {\n                    return 0;\n                } else {\n                    return -1;\n                }\n            } else if (num2 == null || num2.isEmpty()) {\n                return 1;\n            }\n\n            Integer int1 = Integer.parseInt(num1);\n            Integer int2 = Integer.parseInt(num2);\n            return int1.compareTo(int2);\n        }\n\n        private int getDigitPosition(String devName) {\n            int pos = devName.length();\n\n            for (int i = devName.length() - 1; i >= 0; i--) {\n                if (Character.isDigit(devName.charAt(i))) {\n                    pos = i;\n                } else {\n                    break;\n                }\n            }\n\n            return pos;\n        }\n    }\n\n    private static class TtyDev {\n\n        private final String portName;\n        private Integer interfaceNumber;\n\n        public TtyDev(String portName) {\n            this.portName = portName;\n        }\n\n        public TtyDev(String portName, Integer interfaceNumber) {\n            this.portName = portName;\n            this.interfaceNumber = interfaceNumber;\n        }\n\n        public String getPortName() {\n            return this.portName;\n        }\n\n        public Integer getInterfaceNumber() {\n            return this.interfaceNumber;\n        }\n\n        @Override\n        public String toString() {\n            String number = this.interfaceNumber != null ? this.interfaceNumber.toString() : \"null\";\n            return \"TtyDev [portName=\" + this.portName + \", interfaceNumber=\" + number + \"]\";\n        }\n\n        @Override\n        public int hashCode() {\n            final int prime = 31;\n            int result = 1;\n            result = prime * result + (this.portName == null ? 0 : this.portName.hashCode());\n            return result;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (obj == null) {\n                return false;\n            }\n            if (getClass() != obj.getClass()) {\n                return false;\n            }\n            TtyDev other = (TtyDev) obj;\n            if (this.portName == null) {\n                if (other.portName != null) {\n                    return false;\n                }\n            } else if (!this.portName.equals(other.portName)) {\n                return false;\n            }\n            return true;\n        }\n\n    }\n\n    private class TtyDevComparator implements Comparator<TtyDev> {\n\n        @Override\n        /**\n         * If the devices have an interface number, use it for comparing.\n         * Otherwise use the port names.\n         * Note: this comparator imposes orderings that are inconsistent with equals. The comparison will be performed\n         * on the interface numbers if present, while the equals method is based only on the port names.\n         */\n        public int compare(TtyDev dev1, TtyDev dev2) {\n            if (dev1.getInterfaceNumber() != null && dev2.getInterfaceNumber() != null) {\n                return dev1.getInterfaceNumber().compareTo(dev2.getInterfaceNumber());\n            } else {\n                return new DevNameComparator().compare(dev1.getPortName(), dev2.getPortName());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbNetDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Representation of USB network devices\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class UsbNetDevice extends AbstractUsbDevice {\n\n    /** The interface name associated with this device **/\n    private final String interfaceName;\n\n    public UsbNetDevice(String vendorId, String productId, String manufacturerName, String productName,\n            String usbBusNumber, String usbDevicePath, String interfaceName) {\n        super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath);\n        this.interfaceName = interfaceName;\n    }\n\n    public String getInterfaceName() {\n        return this.interfaceName;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + (this.interfaceName == null ? 0 : this.interfaceName.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj)) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        UsbNetDevice other = (UsbNetDevice) obj;\n        if (this.interfaceName == null) {\n            if (other.interfaceName != null) {\n                return false;\n            }\n        } else if (!this.interfaceName.equals(other.interfaceName)) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        return \"UsbNetDevice [getInterfaceName()=\" + getInterfaceName() + \", getVendorId()=\" + getVendorId()\n                + \", getProductId()=\" + getProductId() + \", getManufacturerName()=\" + getManufacturerName()\n                + \", getProductName()=\" + getProductName() + \", getUsbBusNumber()=\" + getUsbBusNumber()\n                + \", getUsbDevicePath()=\" + getUsbDevicePath() + \", getUsbPort()=\" + getUsbPort() + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport java.util.List;\n\nimport javax.usb.UsbServices;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * OSGi interface for getting JSR-80 javax.usb.UsbServices currently available in the system.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface UsbService {\n\n    /**\n     * Gets the UsbServices currently available as specified by JSR-80 in the javax.usb\n     *\n     * @return The currently available javax.usb.UsbServices\n     * @throws KuraException\n     */\n    public UsbServices getUsbServices() throws KuraException;\n\n    /**\n     * Gets the USB devices on the gateway\n     *\n     * @return The currently attached USB devices\n     */\n    public List<? extends UsbDevice> getUsbDevices();\n\n    /**\n     * Gets the USB block devices on the gateway\n     *\n     * @return The currently attached USB block devices\n     */\n    public List<UsbBlockDevice> getUsbBlockDevices();\n\n    /**\n     * Gets the USB network devices on the gateway\n     *\n     * @return The currently attached USB network devices\n     */\n    public List<UsbNetDevice> getUsbNetDevices();\n\n    /**\n     * Gets the USB TTY devices on the gateway\n     *\n     * @return The currently attached USB TTY devices\n     */\n    public List<UsbTtyDevice> getUsbTtyDevices();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbTtyDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.usb;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Representation of USB TTY devices\n *\n * @noextend This class is not intended to be subclassed by clients.\n */\n@ProviderType\npublic class UsbTtyDevice extends AbstractUsbDevice {\n\n    /** The device node of the TTY device **/\n    private final String deviceNode;\n    private final Integer interfaceNumber;\n\n    public UsbTtyDevice(String vendorId, String productId, String manufacturerName, String productName,\n            String usbBusNumber, String usbDevicePath, String deviceNode) {\n        super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath);\n        this.deviceNode = deviceNode;\n        this.interfaceNumber = null;\n    }\n\n    /**\n     * @since 1.4\n     */\n    @SuppressWarnings(\"checkstyle:parameterNumber\")\n    public UsbTtyDevice(String vendorId, String productId, String manufacturerName, String productName,\n            String usbBusNumber, String usbDevicePath, String deviceNode, Integer interfaceNumber) {\n        super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath);\n        this.deviceNode = deviceNode;\n        this.interfaceNumber = interfaceNumber;\n    }\n\n    /**\n     * Returns the tty device node name\n     *\n     * @return the device node\n     */\n    public String getDeviceNode() {\n        return this.deviceNode;\n    }\n\n    /**\n     * Returns the tty interface number\n     *\n     * @since 1.4\n     *\n     * @return the interface number\n     */\n    public Integer getInterfaceNumber() {\n        return this.interfaceNumber;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + (this.deviceNode == null ? 0 : this.deviceNode.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj)) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        UsbTtyDevice other = (UsbTtyDevice) obj;\n        if (this.deviceNode == null) {\n            if (other.deviceNode != null) {\n                return false;\n            }\n        } else if (!this.deviceNode.equals(other.deviceNode)) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        String number = getInterfaceNumber() != null ? getInterfaceNumber().toString() : \"null\";\n        return \"UsbTtyDevice [getDeviceNode()=\" + getDeviceNode() + \", getVendorId()=\" + getVendorId()\n                + \", getProductId()=\" + getProductId() + \", getManufacturerName()=\" + getManufacturerName()\n                + \", getProductName()=\" + getProductName() + \", getUsbBusNumber()=\" + getUsbBusNumber()\n                + \", getUsbDevicePath()=\" + getUsbDevicePath() + \", getUsbPort()=\" + getUsbPort()\n                + \", getInterfaceNumber()=\" + number + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides services and interfaces for finding and managing USB devices within the system.\n *\n */\npackage org.eclipse.kura.usb;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/watchdog/CriticalComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.watchdog;\n\nimport org.osgi.annotation.versioning.ConsumerType;\n\n/**\n * CriticalComponent is an interface that can be used to denote a component of functionality that is\n * 'critical' to the nature of the system. If a component implements CriticalComponent then it must\n * state its name as well as its criticalComponentTimeout. The name is a unique identifier in the\n * system. The timeout is a length of time in milliseconds that the CriticalComponent must check in\n * with the {@link WatchdogService}. If the CriticalComponent goes for a time period of greater\n * than this timeout, based on the (@link WatchdogService } configuration it will perform some action\n * (such as rebooting the system).\n *\n */\n@ConsumerType\npublic interface CriticalComponent {\n\n    /**\n     * The unique identifier for this CriticalComponent\n     *\n     * @return a identifier unique to the {@link WatchdogService }\n     */\n    public String getCriticalComponentName();\n\n    /**\n     * The maximum amount of time in milliseconds that the CriticalComponent should check in\n     * with the {@link WatchdogService} before the WatchdogService reboots the device.\n     *\n     * @return the timeout in milliseconds\n     */\n    public int getCriticalComponentTimeout();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/watchdog/WatchdogService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.watchdog;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface provides methods for starting, stopping, and updating a\n * hardware watchdog present on the system. Updating the watchdog, once\n * started, prevents the system from rebooting.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface WatchdogService {\n\n    /**\n     * Starts the hardware watchdog on the device. If a timeout value has not been\n     * set, the watchdog will use its default timeout.<br>\n     * This call is no longer used. The life-cycle of the watchdog is controlled\n     * by the configuration parameters of the WatchdogSerivce. The API call\n     * is retained for compatibility reasons.\n     */\n    @Deprecated\n    public void startWatchdog();\n\n    /**\n     * Stops the hardware Watchdog on the device\n     * This call is no longer used. The life-cycle of the watchdog is controlled\n     * by the configuration parameters of the WatchdogSerivce. The API call\n     * is retained for compatibility reasons.\n     */\n    @Deprecated\n    public void stopWatchdog();\n\n    /**\n     * Returns the timeout value for the hardware watchdog in increments of milliseconds.\n     *\n     * @return An int representing the hardware timeout value in milliseconds.\n     */\n    public int getHardwareTimeout();\n\n    /**\n     * Register a critical service with the Critical Service Check-in.\n     * Once registered, the critical service must call the checkin()\n     * method (at a frequency higher than 1/timeout) to prevent a system reboot.\n     *\n     * @param criticalComponent\n     *            The CriticalComponent to be registered.\n     */\n    @Deprecated\n    public void registerCriticalService(CriticalComponent criticalComponent);\n\n    /**\n     * Unregister a critical service with the Critical Service Check-in.\n     * Once unregistered, the critical service will no longer call the\n     * checkin() method.\n     *\n     * @param criticalComponent\n     *            The CriticalComponent to be unregistered.\n     */\n    @Deprecated\n    public void unregisterCriticalService(CriticalComponent criticalComponent);\n\n    /**\n     * Register a critical component with the WatchdogService Check-in.\n     * Once registered, the critical component must call the checkin()\n     * method (at a frequency higher than 1/timeout) to prevent a system reboot.\n     *\n     * @param criticalComponent\n     *            The CriticalComponent to be registered.\n     */\n    public void registerCriticalComponent(CriticalComponent criticalComponent);\n\n    /**\n     * Unregister a critical component with the WatchdogService Check-in.\n     * Once unregistered, the critical component will no longer call the\n     * checkin() method.\n     *\n     * @param criticalComponent\n     *            The CriticalComponent to be unregistered.\n     */\n    public void unregisterCriticalComponent(CriticalComponent criticalComponent);\n\n    /**\n     * Returns the list of the currently registered CriticalComponents\n     *\n     * @return A List of CriticalComponents\n     */\n    public List<CriticalComponent> getCriticalComponents();\n\n    /**\n     * This method is used to notify the Watchdog Service that a critical service\n     * has 'checked in' and the reboot timer should be reset.\n     *\n     * @param criticalComponent\n     *            The criticalComponent to be updated.\n     */\n    public void checkin(CriticalComponent criticalComponent);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/watchdog/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n *\n */\n/**\n * Provides service for controlling hardware watchdog timer.\n *\n */\npackage org.eclipse.kura.watchdog;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.wire;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * WireComponent is a marker interface representing a generic identity for\n * {@link WireEmitter}s and {@link WireReceiver}s. A Wire Component is a\n * generalization of a component responsible for producing data also known as\n * {@code WireEmitter} and/or consuming data also known as {@code WireReceiver}.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n */\n@ProviderType\npublic interface WireComponent {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.wire;\n\nimport static java.util.Objects.requireNonNull;\n\nimport org.eclipse.kura.annotation.NotThreadSafe;\nimport org.eclipse.kura.annotation.Nullable;\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.wireadmin.Wire;\n\n/**\n * The Class {@link WireConfiguration} represents a wiring configuration between a Wire\n * Emitter and a Wire Receiver. In a Wire Graph in Kura Wires, the connection that\n * connect two different Wire Components is known as {@link WireConfiguration}.\n * <br/>\n * <br/>\n * Two {@link WireConfiguration}s with equal {@code Emitter PID} and {@code Receiver PID}\n * are considered to be equal {@link WireConfiguration} instances and it is validated through\n * its {@link WireConfiguration#equals(Object)} and {@link WireConfiguration#hashCode()}\n * methods' contract and hence, it is suitable to be used with hash based collections.\n *\n * @see Wire\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@NotThreadSafe\n@ProviderType\npublic class WireConfiguration {\n\n    private final String emitterPid;\n\n    @Nullable\n    private String filter;\n\n    private final String receiverPid;\n\n    @Nullable\n    private Wire wire;\n\n    /**\n     * Instantiates a new {@link WireConfiguration}.\n     *\n     * @param emitterPid\n     *            the Wire Emitter PID\n     * @param receiverPid\n     *            the Wire Receiver PID\n     * @throws NullPointerException\n     *             if any of the arguments is null\n     */\n    public WireConfiguration(final String emitterPid, final String receiverPid) {\n        requireNonNull(emitterPid, \"Emitter PID cannot be null\");\n        requireNonNull(receiverPid, \"Receiver PID cannot be null\");\n\n        this.emitterPid = emitterPid;\n        this.receiverPid = receiverPid;\n    }\n\n    /**\n     * Gets the Wire Emitter PID.\n     *\n     * @return the Wire Emitter PID\n     */\n    public String getEmitterPid() {\n        return this.emitterPid;\n    }\n\n    /**\n     * Gets the associated filter.\n     *\n     * @return the filter\n     */\n    public String getFilter() {\n        return this.filter;\n    }\n\n    /**\n     * Gets the Wire Receiver PID.\n     *\n     * @return the Wire Receiver PID\n     */\n    public String getReceiverPid() {\n        return this.receiverPid;\n    }\n\n    /**\n     * Gets the associated {@link org.osgi.service.wireadmin.WireAdmin}' {@link Wire} instance.\n     *\n     * @return the {@link Wire} instance\n     */\n    public Wire getWire() {\n        return this.wire;\n    }\n\n    /**\n     * Sets the filter for this {@link WireConfiguration}\n     *\n     * @param filter\n     *            the new filter\n     */\n    public void setFilter(final String filter) {\n        this.filter = filter;\n    }\n\n    /**\n     * Sets the {@link Wire} instance.\n     *\n     * @param wire\n     *            the new {@link Wire} instance\n     */\n    public void setWire(final Wire wire) {\n        this.wire = wire;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public boolean equals(final Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (this.getClass() != obj.getClass()) {\n            return false;\n        }\n        final WireConfiguration other = (WireConfiguration) obj;\n        if (this.emitterPid == null) {\n            if (other.emitterPid != null) {\n                return false;\n            }\n        } else if (!this.emitterPid.equals(other.emitterPid)) {\n            return false;\n        }\n        if (this.receiverPid == null) {\n            if (other.receiverPid != null) {\n                return false;\n            }\n        } else if (!this.receiverPid.equals(other.receiverPid)) {\n            return false;\n        }\n        return true;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.emitterPid == null ? 0 : this.emitterPid.hashCode());\n        result = prime * result + (this.receiverPid == null ? 0 : this.receiverPid.hashCode());\n        return result;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String toString() {\n        return \"WireConfiguration [emitterPid=\" + this.emitterPid + \", filter=\" + this.filter + \", receiverPid=\"\n                + this.receiverPid + \", wire=\" + this.wire + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireEmitter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.wire;\n\nimport org.osgi.annotation.versioning.ConsumerType;\nimport org.osgi.service.wireadmin.Producer;\n\n/**\n * The WireEmitter is a marker interface which represents a wire component which\n * is a data producer that can produce values. The produced values can be used\n * by other {@link WireReceiver} components if it is wired with each other.\n *\n * @since 1.2\n */\n@ConsumerType\npublic interface WireEmitter extends WireComponent, Producer {\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireEnvelope.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.wire;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.wireadmin.BasicEnvelope;\n\n/**\n * The Class WireEnvelope represents a composite envelope to be used as an\n * abstract data to be transmitted between the wire emitter and the wire\n * receiver\n *\n * @see org.osgi.service.wireadmin.Envelope\n * @see BasicEnvelope\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class WireEnvelope extends BasicEnvelope {\n\n    /**\n     * The scope as agreed by the composite producer and consumer. This remains same\n     * for all the Kura Wires communications.\n     */\n    private static final String SCOPE = \"WIRES\";\n\n    /**\n     * Instantiates a new WireEnvelope.\n     *\n     * @param emitterPid\n     *            the wire emitter PID\n     * @param wireRecords\n     *            the {@link WireRecord}s\n     */\n    public WireEnvelope(final String emitterPid, final List<WireRecord> wireRecords) {\n        super(Collections.unmodifiableList(wireRecords), emitterPid, SCOPE);\n    }\n\n    /**\n     * Gets the wire emitter PID.\n     *\n     * @return the wire emitter PID\n     */\n    public String getEmitterPid() {\n        return (String) getIdentification();\n    }\n\n    /**\n     * Gets the {@link WireRecord}s.\n     *\n     * @return the {@link WireRecord}s\n     */\n    @SuppressWarnings(\"unchecked\")\n    public List<WireRecord> getRecords() {\n        return (List<WireRecord>) getValue();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireHelperService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.wire;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.framework.ServiceReference;\n\n/**\n * The interface WireHelperService is an service utility API to provide quick\n * and necessary operations for Kura Wires topology.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n */\n@ProviderType\npublic interface WireHelperService {\n\n    /**\n     * Retrieves the Kura Service PID (kura.service.pid) of the wire component\n     *\n     * @param wireComponent\n     *            the wire component\n     * @return the Service PID of the provided wire component or {@code null} if\n     *         the provided Wire Component PID is not associated with any\n     *         available Wire Component in the OSGi service registry\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public String getPid(final WireComponent wireComponent);\n\n    /**\n     * Retrieves the OSGi Component Service PID (service.pid) of the provided\n     * wire component PID\n     *\n     * @param wireComponentPid\n     *            the wire component PID (kura.service.pid)\n     * @return the Service PID of the provided wire component or {@code null} if\n     *         the provided Wire Component PID is not associated with any\n     *         available Wire Component in the OSGi service registry\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public String getServicePid(final String wireComponentPid);\n\n    /**\n     * Retrieves the OSGi Component Service PID (service.pid) of the wire\n     * component\n     *\n     * @param wireComponent\n     *            the wire component\n     * @return the Service PID of the provided wire component or {@code null} if\n     *         the provided Wire Component PID is not associated with any\n     *         available Wire Component in the OSGi service registry\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public String getServicePid(final WireComponent wireComponent);\n\n    /**\n     * Checks whether the provided Wire Component PID belongs to a Wire Emitter\n     *\n     * @param wireComponentPid\n     *            the wire component PID (kura.service.pid)\n     * @return true if the provided Wire Component PID belongs to a Wire Emitter\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public boolean isEmitter(final String wireComponentPid);\n\n    /**\n     * Checks whether the provided Wire Component PID belongs to a Wire Receiver\n     *\n     * @param wireComponentPid\n     *            the wire component PID (kura.service.pid)\n     * @return true if the provided Wire Component PID belongs to a Wire\n     *         Receiver\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public boolean isReceiver(final String wireComponentPid);\n\n    /**\n     * Returns a Wire Support instance of the provided wire component\n     *\n     * @param wireComponent\n     *            the wire component\n     * @param wireComponentRef\n     *            the {@link ServiceReference} that contains the metadata/configuration related to the wireComponent\n     * @return the wire support instance\n     * @throws NullPointerException\n     *             if the argument is null\n     * @since 2.0\n     */\n    public WireSupport newWireSupport(WireComponent wireComponent, ServiceReference<WireComponent> wireComponentRef);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireReceiver.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.wire;\n\nimport org.osgi.annotation.versioning.ConsumerType;\nimport org.osgi.service.wireadmin.Consumer;\n\n/**\n * The WireReceiver interface Represents a wire component which is a data\n * consumer that can receive produced or emitted values from upstream\n * {@link WireEmitter}.\n *\n * @since 1.2\n */\n@ConsumerType\npublic interface WireReceiver extends WireComponent, Consumer {\n\n    /**\n     * Triggers when the wire component receives a {@link WireEnvelope}\n     *\n     * @param wireEnvelope\n     *            the received {@link WireEnvelope}\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public void onWireReceive(WireEnvelope wireEnvelope);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireRecord.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.wire;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.eclipse.kura.annotation.Immutable;\nimport org.eclipse.kura.annotation.ThreadSafe;\nimport org.eclipse.kura.type.TypedValue;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Class WireRecord represents a record to be transmitted during wire\n * communication between wire emitter and wire receiver\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.2\n */\n@Immutable\n@ThreadSafe\n@ProviderType\npublic class WireRecord {\n\n    private final Map<String, TypedValue<?>> properties;\n\n    /**\n     * Instantiates a new {@link WireRecord}.\n     *\n     * @param properties\n     *            Map that represents the key-value pairs\n     * @throws NullPointerException\n     *             if any of the argument is null\n     */\n    public WireRecord(final Map<String, TypedValue<?>> properties) {\n        requireNonNull(properties, \"Properties cannot be null\");\n\n        this.properties = Collections.unmodifiableMap(properties);\n    }\n\n    /**\n     * Returns the properties stored in this {@link WireRecord}\n     *\n     * @return the fields\n     */\n    public Map<String, TypedValue<?>> getProperties() {\n        return this.properties;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireSupport.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\npackage org.eclipse.kura.wire;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.wireadmin.Consumer;\nimport org.osgi.service.wireadmin.Producer;\n\n/**\n * The interface WireSupport is responsible for managing incoming as well as\n * outgoing wires of the contained Wire Component. This is also used to perform\n * wire related operations for instance, emit and receive {@link WireRecord}s.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.2\n */\n@ProviderType\npublic interface WireSupport extends Producer, Consumer {\n\n    /**\n     * Emit the provided {@link WireRecord}s\n     *\n     * @param wireRecords\n     *            a List of {@link WireRecord} objects that will be sent to the receiver.\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public void emit(List<WireRecord> wireRecords);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/BarrierAggregatorFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A marker interface for a factory that returns a {@link PortAggregator} that acts as a barrier for a provided set of\n * input ports.\n * The barrier behaves as follows:\n *\n * <ul>\n * <li>It maintains, for each port, a slot that can contain a WireEnvelope.</li>\n * <li>When a WireEnvelope is received on a port, the corresponding slot is filled with it. If the slot is not empty,\n * its content is replaced</li>\n * <li>When all slots are filled, their contents are provided to the registered callback.</li>\n * <li>The slots are cleared when the callback returns.</li>\n * </ul>\n *\n * @since 1.4\n */\n@ProviderType\npublic interface BarrierAggregatorFactory extends PortAggregatorFactory {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/CachingAggregatorFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * A marker interface for a factory that returns a {@link PortAggregator} that acts as a cache for a provided set of\n * input ports.\n * The cache behaves as follows:\n *\n * <ul>\n * <li>It maintains, for each port, a slot that can contain a WireEnvelope.</li>\n * <li>When a WireEnvelope is received on a port, the corresponding slot is filled with it. If the slot is not empty,\n * its content is replaced</li>\n * <li>When a WireEnvelope is received, the current contents of the slots are provided to the registered callback, even\n * if some of the slots are empty.</li>\n * <li>The slots are never cleared.</li>\n * </ul>\n *\n * @since 1.4\n */\n@ProviderType\npublic interface CachingAggregatorFactory extends PortAggregatorFactory {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/Constants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\n/**\n * Wire Graph related constants.\n *\n * @since 1.4\n */\npublic enum Constants {\n\n    WIRE_EMITTER_PORT_PROP_NAME(\"emitter.port\"),\n    WIRE_RECEIVER_PORT_PROP_NAME(\"receiver.port\"),\n    RECEIVER_PORT_COUNT_PROP_NAME(\"receiver.port.count\"),\n    EMITTER_PORT_COUNT_PROP_NAME(\"emitter.port.count\"),\n    RECEIVER_KURA_SERVICE_PID_PROP_NAME(\"receiver.kura.service.pid\"),\n    EMITTER_KURA_SERVICE_PID_PROP_NAME(\"emitter.kura.service.pid\");\n\n    private final String value;\n\n    private Constants(String v) {\n        this.value = v;\n    }\n\n    public String value() {\n        return this.value;\n    }\n\n    public static Constants fromValue(String v) {\n        for (Constants c : Constants.values()) {\n            if (c.value.equals(v)) {\n                return c;\n            }\n        }\n        throw new IllegalArgumentException(v);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/EmitterPort.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface represents an emitter port\n *\n * @since 1.4\n */\n@ProviderType\npublic interface EmitterPort extends Port {\n\n    /**\n     * This methods is invoked with the {@link WireEnvelope} that has to be sent to the other end of the wire.\n     *\n     * @param wireEnvelope\n     *            the message that needs to be sent.\n     */\n    public void emit(WireEnvelope wireEnvelope);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/MultiportWireConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport org.eclipse.kura.wire.WireConfiguration;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This POJO is used to represent, in the Wires context, the configuration of a Wire used in a multi-port composer.\n *\n * @since 1.4\n */\n@ProviderType\npublic class MultiportWireConfiguration extends WireConfiguration {\n\n    private int emitterPort;\n    private int receiverPort;\n\n    public MultiportWireConfiguration(String emitterPid, String receiverPid, int emitterPort, int receiverPort) {\n        super(emitterPid, receiverPid);\n        this.emitterPort = emitterPort;\n        this.receiverPort = receiverPort;\n    }\n\n    public int getEmitterPort() {\n        return this.emitterPort;\n    }\n\n    public void setEmitterPort(int emitterPort) {\n        this.emitterPort = emitterPort;\n    }\n\n    public int getReceiverPort() {\n        return this.receiverPort;\n    }\n\n    public void setReceiverPort(int receiverPort) {\n        this.receiverPort = receiverPort;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = super.hashCode();\n        result = prime * result + this.emitterPort;\n        result = prime * result + this.receiverPort;\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!super.equals(obj)) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        MultiportWireConfiguration other = (MultiportWireConfiguration) obj;\n        if (this.emitterPort != other.emitterPort) {\n            return false;\n        }\n        if (this.receiverPort != other.receiverPort) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/MultiportWireSupport.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport java.util.List;\n\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.eclipse.kura.wire.WireSupport;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface extends {@link WireSupport} to provide multi-port support in Wires.\n *\n * @since 1.4\n */\n@ProviderType\npublic interface MultiportWireSupport extends WireSupport {\n\n    /**\n     * Returns the list of EmitterPorts of a Wire Component\n     *\n     * @return a list of {@link EmitterPort}\n     */\n    public List<EmitterPort> getEmitterPorts();\n\n    /**\n     * Returns the list of ReceiverPorts associated to a Wire Component\n     *\n     * @return a list of {@link ReceiverPort}\n     */\n    public List<ReceiverPort> getReceiverPorts();\n\n    /**\n     * This method allows to create a {@link WireEnvelope} from the list of {@link WireRecord} passed as an argument.\n     *\n     * @param records\n     *            a list of {@link WireRecord}s that will be wrapped into a {@link WireEnvelope}\n     * @return a {@link WireEnvelope} that wraps the list of {@link WireRecord}s passed.\n     */\n    public WireEnvelope createWireEnvelope(List<WireRecord> records);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/Port.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\nimport org.osgi.service.wireadmin.Wire;\n\n/**\n * This interface represents the port(s) associated to a Wire Component.\n *\n * @since 1.4\n */\n@ProviderType\npublic interface Port {\n\n    /**\n     * This method returns the list of {@link Wire}s connected to this {@link Port}\n     *\n     * @return the list of {@link Wire} connected to this {@link Port}\n     */\n    public List<Wire> listConnectedWires();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/PortAggregator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Allows to implement an aggregation strategy for a given set of ports. See {@link BarrierAggregatorFactory} and\n * {@link CachingAggregatorFactory} for examples of possible strategies.\n *\n * @since 1.4\n */\n@ProviderType\npublic interface PortAggregator {\n\n    public void onWireReceive(Consumer<List<WireEnvelope>> envelopes);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/PortAggregatorFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n *\n * Defines a factory service API that can be used to instantiate a specific {@link PortAggregator} strategy.\n *\n * @since 1.4\n */\n@ProviderType\npublic interface PortAggregatorFactory {\n\n    public PortAggregator build(List<ReceiverPort> ports);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/ReceiverPort.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport java.util.function.Consumer;\n\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface marks the ports that are receiver ports of the associated Wire Component.\n *\n * @since 1.4\n */\n@ProviderType\npublic interface ReceiverPort extends Port {\n\n    public void onWireReceive(Consumer<WireEnvelope> consumer);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireComponentConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Class represents the single Wire Graph Component configuration. It\n * contains the component configuration description and additional properties\n * that can be used for the component displaying in the composer.<br>\n * <br>\n *\n * @see ComponentConfiguration\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.4\n */\n@ProviderType\npublic class WireComponentConfiguration {\n\n    private final ComponentConfiguration configuration;\n    private final Map<String, Object> properties;\n\n    public WireComponentConfiguration(ComponentConfiguration configuration, Map<String, Object> properties) {\n        this.configuration = configuration;\n        this.properties = Collections.unmodifiableMap(properties);\n    }\n\n    public ComponentConfiguration getConfiguration() {\n        return this.configuration;\n    }\n\n    public Map<String, Object> getProperties() {\n        return this.properties;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireComponentDefinition.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * @noextend This class is not intended to be extended by clients.\n * @since 1.4\n */\n@ProviderType\npublic class WireComponentDefinition {\n\n    private String factoryPid;\n\n    private int minInputPorts;\n    private int maxInputPorts;\n    private int defaultInputPorts;\n\n    private int minOutputPorts;\n    private int maxOutputPorts;\n    private int defaultOutputPorts;\n\n    private Map<Integer, String> inputPortNames;\n    private Map<Integer, String> outputPortNames;\n\n    private ComponentConfiguration componentOCD;\n\n    public String getFactoryPid() {\n        return this.factoryPid;\n    }\n\n    public void setFactoryPid(String factoryPid) {\n        this.factoryPid = factoryPid;\n    }\n\n    public int getMinInputPorts() {\n        return this.minInputPorts;\n    }\n\n    public void setMinInputPorts(int minInputPorts) {\n        this.minInputPorts = minInputPorts;\n    }\n\n    public int getMaxInputPorts() {\n        return this.maxInputPorts;\n    }\n\n    public void setMaxInputPorts(int maxInputPorts) {\n        this.maxInputPorts = maxInputPorts;\n    }\n\n    public int getDefaultInputPorts() {\n        return this.defaultInputPorts;\n    }\n\n    public void setDefaultInputPorts(int defaultInputPorts) {\n        this.defaultInputPorts = defaultInputPorts;\n    }\n\n    public int getMinOutputPorts() {\n        return this.minOutputPorts;\n    }\n\n    public void setMinOutputPorts(int minOutputPorts) {\n        this.minOutputPorts = minOutputPorts;\n    }\n\n    public int getMaxOutputPorts() {\n        return this.maxOutputPorts;\n    }\n\n    public void setMaxOutputPorts(int maxOutputPorts) {\n        this.maxOutputPorts = maxOutputPorts;\n    }\n\n    public int getDefaultOutputPorts() {\n        return this.defaultOutputPorts;\n    }\n\n    public void setDefaultOutputPorts(int defaultOutputPorts) {\n        this.defaultOutputPorts = defaultOutputPorts;\n    }\n\n    public Map<Integer, String> getInputPortNames() {\n        return this.inputPortNames;\n    }\n\n    public void setInputPortNames(Map<Integer, String> inputPortNames) {\n        this.inputPortNames = inputPortNames;\n    }\n\n    public Map<Integer, String> getOutputPortNames() {\n        return this.outputPortNames;\n    }\n\n    public void setOutputPortNames(Map<Integer, String> outputPortNames) {\n        this.outputPortNames = outputPortNames;\n    }\n\n    public ComponentConfiguration getComponentOCD() {\n        return this.componentOCD;\n    }\n\n    public void setComponentOCD(ComponentConfiguration componentOCD) {\n        this.componentOCD = componentOCD;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireComponentDefinitionService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This WireComponentDefinitionService allows to fetch the {@link WireComponentDefinition}s of the registered Wire\n * Components.\n *\n * @since 1.4\n */\n@ProviderType\npublic interface WireComponentDefinitionService {\n\n    /**\n     * This method allows to list the {@link WireComponentDefinition}s for the registered Wire Components.\n     *\n     * @return a list of registered {@link WireComponentDefinition}s\n     * @throws KuraException\n     *             if the get operation fails.\n     */\n    public List<WireComponentDefinition> getComponentDefinitions() throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireGraphConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * The Class represents the entire Wire Graph. It contains both the list of\n * components and the list of arcs that represent the current Wire Graph.<br>\n * <br>\n *\n * @see WireComponentConfiguration\n * @see org.eclipse.kura.wire.WireConfiguration\n *\n * @noextend This class is not intended to be extended by clients.\n * @since 1.4\n */\n@ProviderType\npublic class WireGraphConfiguration {\n\n    private final List<WireComponentConfiguration> wireComponentConfigurations;\n    private final List<MultiportWireConfiguration> wireConfigurations;\n\n    public WireGraphConfiguration(List<WireComponentConfiguration> wireComponentConfigurations,\n            List<MultiportWireConfiguration> wireConfigurations) {\n        this.wireComponentConfigurations = Collections.unmodifiableList(wireComponentConfigurations);\n        this.wireConfigurations = Collections.unmodifiableList(wireConfigurations);\n    }\n\n    public List<WireComponentConfiguration> getWireComponentConfigurations() {\n        return this.wireComponentConfigurations;\n    }\n\n    public List<MultiportWireConfiguration> getWireConfigurations() {\n        return this.wireConfigurations;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireGraphService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.graph;\n\nimport org.eclipse.kura.KuraException;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * This interface provides all the needed methods to interact with the\n * WireGraph.\n *\n * @noimplement This interface is not intended to be implemented by clients.\n * @since 1.4\n */\n@ProviderType\npublic interface WireGraphService {\n\n    /**\n     * This method allows to create and update the graph, by providing a\n     * {@link WireGraphConfiguration}.\n     *\n     * @param graphConfiguration\n     *            A {@link WireGraphConfiguration} object that represents an updated\n     *            status of the Wire Graph\n     * @throws {@link\n     *             KuraException} if the update operation fails\n     */\n    public void update(WireGraphConfiguration graphConfiguration) throws KuraException;\n\n    /**\n     * This method allows to delete the current Wire Graph.\n     *\n     * @throws {@link\n     *             KuraException} if the delete operation fails\n     */\n    public void delete() throws KuraException;\n\n    /**\n     * This method returns the current Wire Graph configuration.\n     *\n     * @return a {@link WireGraphConfiguration} object that represents the current\n     *         configuration of the Wire Graph\n     * @throws {@link\n     *             KuraException} if the get operation fails\n     */\n    public WireGraphConfiguration get() throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n/**\n * Provides all the necessary APIs and classes to manipulate Kura Wires Graph\n *\n * @since 1.4\n */\npackage org.eclipse.kura.wire.graph;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/multiport/MultiportWireEmitter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.multiport;\n\nimport org.eclipse.kura.wire.WireComponent;\nimport org.osgi.annotation.versioning.ConsumerType;\nimport org.osgi.service.wireadmin.Producer;\n\n/**\n * The MultiportWireEmitter is a marker interface which represents a wire component which\n * is a data producer that can produce values. The produced values can be used\n * by other {@link org.eclipse.kura.wire.WireReceiver} components if it is wired with each other.\n *\n * @since 1.4\n */\n@ConsumerType\npublic interface MultiportWireEmitter extends Producer, WireComponent {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/multiport/MultiportWireReceiver.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.wire.multiport;\n\nimport org.eclipse.kura.wire.WireComponent;\nimport org.osgi.annotation.versioning.ConsumerType;\nimport org.osgi.service.wireadmin.Consumer;\n\n/**\n * The MultiportWireReceiver interface Represents a wire component which is a data\n * consumer that can receive produced or emitted values from upstream\n * {@link org.eclipse.kura.wire.WireEmitter}.\n *\n * @since 1.4\n */\n@ConsumerType\npublic interface MultiportWireReceiver extends Consumer, WireComponent {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/multiport/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n/**\n * Provides all the necessary APIs and classes to manipulate Kura Multiport Wire Components\n *\n * @since 1.4\n */\npackage org.eclipse.kura.wire.multiport;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n ******************************************************************************/\n/**\n * Provides all necessary APIs and all utility classes comprising necessary\n * static factory methods to manipulate Kura Wires topology\n *\n * @since 1.0.10\n */\npackage org.eclipse.kura.wire;\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/store/provider/QueryableWireRecordStoreProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.wire.store.provider;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a store that is capable to perform queries defined in an\n * implementation specific language and return the result in terms of a list of\n * {@link WireRecord}s.\n * \n * @since 2.5\n * @noextend This class is not intended to be extended by clients.\n */\n@ProviderType\npublic interface QueryableWireRecordStoreProvider {\n\n    /**\n     * Perform the given query specified in an implementation defined language.\n     * \n     * @param query\n     *              the query to be run\n     * @return a List of WireRecords that contains the result of the query\n     * @throws KuraStoreException\n     */\n    public List<WireRecord> performQuery(String query) throws KuraStoreException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/store/provider/WireRecordStore.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.wire.store.provider;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a store that is capable to perform queries defined in an\n * implementation specific language and return the result in terms of a list of\n * {@link WireRecord}s.\n * \n * @since 2.5\n * @noimplement This interface is not intended to be implemented by clients.\n */\n@ProviderType\npublic interface WireRecordStore {\n\n    /**\n     * Removes all records in the store except the most recent\n     * <code>noOfRecordsToKeep</code>.\n     * \n     * @param noOfRecordsToKeep\n     *            the no of records to keep in the table\n     * @throws KuraStoreException\n     */\n    public void truncate(int noOfRecordsToKeep) throws KuraStoreException;\n\n    /**\n     * Returns the number of records currently in the store.\n     * \n     * @return the no of records currently in the store\n     * @throws KuraStoreException\n     */\n    public int getSize() throws KuraStoreException;\n\n    /**\n     * Insert the provided list of {@link WireRecord} instances in the store.\n     * \n     * @param records\n     *            the list of records to be inserted\n     * @throws KuraStoreException\n     */\n    public void insertRecords(List<WireRecord> records) throws KuraStoreException;\n\n    /**\n     * \n     * Closes the store, releasing any runtime resource allocated for it.\n     */\n    public void close();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/store/provider/WireRecordStoreProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.wire.store.provider;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.connection.listener.ConnectionListener;\nimport org.osgi.annotation.versioning.ProviderType;\n\n/**\n * Represents a service that allows to create {@link WireRecordStore} instances.\n * \n * @since 2.5\n * @noextend This class is not intended to be extended by clients.\n */\n@ProviderType\npublic interface WireRecordStoreProvider {\n\n    /**\n     * Opens or creates a {@link WireRecordStore} instance with the given name. Invoking\n     * this method could allocate the resources required to support the returned {@link WireRecordStore} instance (for\n     * example tables in a RDBMS).*\n     * \n     * @param name\n     *            the store name\n     * @return the result {@link WireRecordStore}.\n     * @throws KuraStoreException\n     */\n    public WireRecordStore openWireRecordStore(String name) throws KuraStoreException;\n\n    /**\n     * Adds a {@link ConnectionListener}. A typical behavior of a client of this listener is to close the currently\n     * open\n     * {@link WireRecordStore} instances when a {@link ConnectionListener#disconnected()} event is received.\n     *\n     * @param listener\n     *            to add\n     *\n     * @since 2.5.0\n     */\n    public void addListener(ConnectionListener listener);\n\n    /**\n     * Removes a {@link ConnectionListener}\n     *\n     * @param listener\n     *            to remove\n     *\n     * @since 2.5.0\n     */\n    public void removeListener(ConnectionListener listener);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/store/provider/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n/**\n * Provides APIs to implement a Wire Record store.\n *\n * @since 2.5\n */\npackage org.eclipse.kura.wire.store.provider;"
  },
  {
    "path": "kura/org.eclipse.kura.api/src/main/resources/org/eclipse/kura/core/messages/KuraExceptionMessagesBundle.properties",
    "content": "#\n# Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#  Red Hat Inc\n#\n\nCONFIGURATION_ERROR=Configuration Error: {0}\nINTERNAL_ERROR=An internal error occurred. {0}\nPORT_IN_USE=The port is in use. {0}\nSECURITY_EXCEPTION=The current subject is not authorized to perform this operation. {0}\nCONFIGURATION_ATTRIBUTE_UNDEFINED=The configuration attribute {0} is undefined.\nCONFIGURATION_ATTRIBUTE_INVALID=The configuration attribute {0} cannot accept value {1}: {2}.\nCONFIGURATION_REQUIRED_ATTRIBUTE_MISSING=The configuration attribute {0} is required and no value has been specified.\nCONFIGURATION_UPDATE=Error updating Configuration of ConfigurableComponent {0}\nCONFIGURATION_SNAPSHOT_NOT_FOUND=Configuration snapshot {0} was not found.\nCONFIGURATION_SNAPSHOT_LISTING=Error Listing Snapshots.\nCONFIGURATION_SNAPSHOT_LOADING=Error Loading Snapshot\nCONFIGURATION_SNAPSHOT_TAKING=Error Taking Snapshot.\nCONFIGURATION_ROLLBACK=Error rolling back to snapshot.\nPARTIAL_SUCCESS=The operation succeeded only partially.\nNOT_CONNECTED=Not connected.\nTIMED_OUT=Timeout occurred while waiting for the operation to complete.\nCONNECTION_FAILED=\"Connection failed. {0}\"\nTOO_MANY_INFLIGHT_MESSAGES=\"Too many in-flight messages.\"\nSTORE_ERROR=\"Error performing operation on store. {0}\"\nENCODE_ERROR=\"Error encoding {0}.\"\nDECODER_ERROR=\"Error decoding {0}.\"\nINVALID_METRIC_EXCEPTION=Metric {0} is invalid.\nINVALID_MESSAGE_EXCEPTION=Message or its encoding is invalid.\nUNAVAILABLE_DEVICE=Device {0} is unavailable.\nCLOSED_DEVICE=Device {0} is closed.\nGPIO_EXCEPTION=Error accessing GPIO resource. {0}\nOS_COMMAND_ERROR=Command ''{0}'' exited with code {1}.\nPROCESS_EXECUTION_ERROR=Unable to execute system process {0}\nSUBSCRIPTION_ERROR=Error processing subscription for {0}\nBLE_NOTIFICATION_ERROR=Error during BLE notification.\nBLE_CONNECTION_ERROR=Error during BLE connection.\nBLE_PAIR_ERROR=Error during BLE pairing.\nBLE_RESOURCE_NOT_FOUND=BLE resource not found.\nBLE_IO_ERROR=Error during BLE IO activity.\nBLE_COMMAND_ERROR=Error executing ''{0}'' command.\nBLE_DISCOVERY_ERROR=Error during discovery procedure.\nSERIAL_PORT_INVALID_CONFIGURATION=The serial port ha an invalid configuration. {0}\nSERIAL_PORT_NOT_EXISTING=The serial port does not exist. {0}\nOPERATION_NOT_SUPPORTED=Operation {0} not supported.\nINVALID_PARAMETER=Invalid parameter. {0}\nBLE_REMOVE_ERROR=Error during device remove.\nBAD_REQUEST=Bad request. {0}\nNOT_FOUND=Not found.\nSERVICE_UNAVAILABLE=Service unavailable. {0}.\nDISCONNECTION_FAILED=Disconnection failed."
  },
  {
    "path": "kura/org.eclipse.kura.camel/.gitignore",
    "content": "/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.camel\nBundle-SymbolicName: org.eclipse.kura.camel;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: javax.script,\n org.apache.camel;version=\"[2.21.0,3.0.0)\",\n org.apache.camel.builder;version=\"[2.21.0,3.0.0)\",\n org.apache.camel.core.osgi;version=\"[2.21.0,3.0.0)\",\n org.apache.camel.impl;version=\"[2.21.0,3.0.0)\",\n org.apache.camel.model;version=\"[2.21.0,3.0.0)\",\n org.apache.camel.spi;version=\"[2.21.0,3.0.0)\",\n org.apache.camel.util.function;version=\"[2.21,3.0)\",\n org.apache.commons.io.input;version=\"[2.4,3.0)\";resolution:=optional,\n org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.cloud;version=\"[1.1,1.2)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.type;version=\"[1.1,2.0)\",\n org.eclipse.kura.util.base;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.osgi;version=\"[1.0,2.0)\",\n org.eclipse.kura.wire;version=\"[2.0,3.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.wireadmin;version=\"[1.0,2.0)\",\n org.osgi.util.tracker;version=\"1.5.0\",\n org.slf4j;version=\"1.7.0\"\nExport-Package: org.eclipse.kura.camel;version=\"1.1.0\",\n org.eclipse.kura.camel.bean;version=\"1.1.0\";uses:=\"org.eclipse.kura.message\",\n org.eclipse.kura.camel.camelcloud;version=\"1.1.0\";uses:=\"org.apache.camel,org.eclipse.kura.cloud\",\n org.eclipse.kura.camel.cloud;version=\"1.1.0\";\n  uses:=\"org.apache.camel,\n   org.apache.camel.impl,\n   org.apache.camel.spi,\n   org.eclipse.kura.camel.internal.cloud,\n   org.eclipse.kura.message,\n   org.eclipse.kura.cloud\",\n org.eclipse.kura.camel.component;version=\"1.1.0\";\n  uses:=\"org.osgi.framework,\n   org.apache.camel.builder,\n   org.eclipse.kura.camel.runner,\n   org.apache.camel,\n   org.eclipse.kura.configuration\",\n org.eclipse.kura.camel.router;version=\"1.1.0\";uses:=\"org.osgi.framework,org.apache.camel,org.eclipse.kura.camel.component\",\n org.eclipse.kura.camel.runner;version=\"1.1.0\";\n  uses:=\"org.osgi.framework,\n   org.apache.camel.builder,\n   org.apache.camel,\n   org.apache.camel.spi,\n   javax.script,\n   org.apache.camel.model\",\n org.eclipse.kura.camel.type;version=\"1.1.0\";uses:=\"org.eclipse.kura.message\",\n org.eclipse.kura.camel.utils;version=\"1.1.0\";uses:=\"org.apache.camel\"\nService-Component: OSGI-INF/*.xml\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/META-INF/services/org/apache/camel/TypeConverter",
    "content": "org.eclipse.kura.camel.type.TypeConverter"
  },
  {
    "path": "kura/org.eclipse.kura.camel/OSGI-INF/kuraCloudResolver.properties",
    "content": "component=kura-cloud"
  },
  {
    "path": "kura/org.eclipse.kura.camel/OSGI-INF/kuraCloudResolver.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.camel.KuraCloudComponentResolver\">\n   <implementation class=\"org.eclipse.kura.camel.cloud.KuraCloudComponentResolver\"/>\n   <service>\n      <provide interface=\"org.apache.camel.spi.ComponentResolver\"/>\n   </service>\n   <properties entry=\"OSGI-INF/kuraCloudResolver.properties\"/>\n   <reference bind=\"setCloudService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.cloud.CloudService\" name=\"CloudService\" policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.camel/build.properties",
    "content": "#\n# Copyright (c) 2016, 2020 Red Hat Inc and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Red Hat Inc\n#\n\nsource.. = src/main/java/\noutput.. = target/classes\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html,\\\n               OSGI-INF/\n\nsrc.includes = about.html\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- \n  \tCopyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\t Red Hat Inc\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.camel</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.camel.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/bean/PayloadFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.bean;\n\nimport java.util.Date;\n\nimport org.eclipse.kura.message.KuraPayload;\n\npublic class PayloadFactory {\n\n    public KuraPayload create(final String key, final Object value) {\n        final KuraPayload result = new KuraPayload();\n        result.setTimestamp(new Date());\n        result.addMetric(key, value);\n        return result;\n    }\n\n    public KuraPayload create(final Date timestamp) {\n        final KuraPayload result = new KuraPayload();\n        result.setTimestamp(timestamp);\n        return result;\n    }\n\n    public KuraPayload append(final KuraPayload payload, final String key, final Object value) {\n        payload.addMetric(key, value);\n        return payload;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/camelcloud/CamelCloudService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.camelcloud;\n\nimport org.eclipse.kura.cloud.CloudService;\n\n/**\n * An extension interface adding Camel specific functionality to the {@link CloudService} interface\n */\npublic interface CamelCloudService extends CloudService {\n\n    void registerBaseEndpoint(String applicationId, String baseEndpoint);\n\n    void release(String applicationId);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/camelcloud/DefaultCamelCloudService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.camelcloud;\n\nimport static org.apache.camel.ServiceStatus.Started;\n\nimport java.util.LinkedList;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport org.apache.camel.CamelContext;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.camel.internal.camelcloud.CamelCloudClient;\nimport org.eclipse.kura.cloud.CloudClient;\n\n/**\n * A default implementation of the {@link CamelCloudService}\n */\npublic class DefaultCamelCloudService implements CamelCloudService {\n\n    private final CamelContext camelContext;\n\n    private final Map<String, CloudClient> clients = new ConcurrentHashMap<>();\n\n    private final Map<String, String> baseEndpoints = new ConcurrentHashMap<>();\n\n    public DefaultCamelCloudService(CamelContext camelContext) {\n        this.camelContext = camelContext;\n    }\n\n    @Override\n    public CloudClient newCloudClient(String applicationId) throws KuraException {\n        String baseEndpoint = this.baseEndpoints.get(applicationId);\n        if (baseEndpoint == null) {\n            baseEndpoint = \"vm:%s\";\n        }\n        final CloudClient cloudClient = new CamelCloudClient(this, this.camelContext, applicationId, baseEndpoint);\n        this.clients.put(applicationId, cloudClient);\n        return cloudClient;\n    }\n\n    @Override\n    public String[] getCloudApplicationIdentifiers() {\n        return this.clients.keySet().toArray(new String[0]);\n    }\n\n    @Override\n    public boolean isConnected() {\n        return this.camelContext.getStatus() == Started;\n    }\n\n    @Override\n    public void registerBaseEndpoint(String applicationId, String baseEndpoint) {\n        this.baseEndpoints.put(applicationId, baseEndpoint);\n    }\n\n    @Override\n    public void release(String applicationId) {\n        CloudClient client = this.clients.remove(applicationId);\n        if (client != null) {\n            client.release();\n        }\n    }\n\n    public void dispose() {\n        final LinkedList<Exception> errors = new LinkedList<>();\n        for (CloudClient client : this.clients.values()) {\n            try {\n                client.release();\n            } catch (Exception e) {\n                errors.add(e);\n            }\n        }\n        this.clients.clear();\n\n        if (!errors.isEmpty()) {\n            final Exception first = errors.pollFirst();\n            errors.forEach(first::addSuppressed);\n            throw new RuntimeException(first);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/camelcloud/KuraCloudClientConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.camelcloud;\n\n/**\n * Kura cloud constants\n */\npublic final class KuraCloudClientConstants {\n\n    public static final String TOPIC = \"topic\";\n\n    public static final String APPLICATION_ID = \"applicationId\";\n\n    public static final String CAMEL_KURA_CLOUD = \"CamelKuraCloudService\";\n\n    public static final String CAMEL_KURA_CLOUD_TOPIC = CAMEL_KURA_CLOUD + \".topic\";\n\n    public static final String CAMEL_KURA_CLOUD_QOS = CAMEL_KURA_CLOUD + \".qos\";\n\n    public static final String CAMEL_KURA_CLOUD_RETAIN = CAMEL_KURA_CLOUD + \".retain\";\n\n    public static final String CAMEL_KURA_CLOUD_PRIORITY = CAMEL_KURA_CLOUD + \".priority\";\n\n    public static final String CAMEL_KURA_CLOUD_CONTROL = CAMEL_KURA_CLOUD + \".control\";\n\n    public static final String CAMEL_KURA_CLOUD_DEVICEID = CAMEL_KURA_CLOUD + \".deviceId\";\n\n    public static final String CAMEL_KURA_CLOUD_MESSAGEID = CAMEL_KURA_CLOUD + \".messageId\";\n\n    private KuraCloudClientConstants() {\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/camelcloud/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n/**\n * Support for implementing a {@link org.eclipse.kura.cloud.CloudService} based on Apache Camel\n */\npackage org.eclipse.kura.camel.camelcloud;\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud;\n\nimport static org.eclipse.kura.camel.internal.utils.KuraServiceFactory.retrieveService;\n\nimport java.util.Map;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.Endpoint;\nimport org.apache.camel.impl.DefaultComponent;\nimport org.eclipse.kura.camel.internal.cloud.CloudClientCache;\nimport org.eclipse.kura.camel.internal.cloud.CloudClientCacheImpl;\nimport org.eclipse.kura.cloud.CloudService;\n\n/**\n * The Camel component for providing \"kura-cloud\"\n */\npublic class KuraCloudComponent extends DefaultComponent {\n\n    public static final String DEFAULT_NAME = \"kura-cloud\";\n\n    private CloudService cloudService;\n    private CloudClientCache cache;\n\n    public KuraCloudComponent() {\n        super();\n    }\n\n    // Constructors\n\n    public KuraCloudComponent(final CamelContext context) {\n        super(context);\n    }\n\n    public KuraCloudComponent(final CamelContext context, final CloudService cloudService) {\n        super(context);\n        this.cloudService = cloudService;\n    }\n\n    @Override\n    protected void doStart() throws Exception {\n        final CloudService cloudServiceInstance = lookupCloudService();\n\n        if (cloudServiceInstance == null) {\n            throw new IllegalStateException(\n                    \"'cloudService' is not set and not found in Camel context service registry\");\n        }\n\n        this.cache = new CloudClientCacheImpl(cloudServiceInstance);\n\n        super.doStart();\n    }\n\n    @Override\n    protected void doStop() throws Exception {\n        super.doStop();\n        if (this.cache != null) {\n            this.cache.close();\n            this.cache = null;\n        }\n    }\n\n    // Operations\n\n    @Override\n    protected Endpoint createEndpoint(String uri, String remain, Map<String, Object> parameters) throws Exception {\n        final KuraCloudEndpoint kuraCloudEndpoint = new KuraCloudEndpoint(uri, this, this.cache);\n\n        final String[] res = remain.split(\"/\", 2);\n        if (res.length < 2) {\n            throw new IllegalArgumentException(\"Wrong kura-cloud URI format. Should be: kura-cloud:app/topic\");\n        }\n        parameters.put(KuraCloudConstants.APPLICATION_ID, res[0]);\n        parameters.put(KuraCloudConstants.TOPIC, res[1]);\n\n        setProperties(kuraCloudEndpoint, parameters);\n\n        return kuraCloudEndpoint;\n    }\n\n    protected CloudService lookupCloudService() {\n        if (this.cloudService == null) {\n            this.cloudService = retrieveService(CloudService.class, getCamelContext().getRegistry());\n        }\n        return this.cloudService;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudComponentResolver.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.Component;\nimport org.apache.camel.spi.ComponentResolver;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A resolver for \"kura-cloud\"\n * <p>\n * This resolver will register to any instance of {@link CloudService} and\n * wrap it into a {@link KuraCloudComponent} instance.\n * </p>\n * <p>\n * If you need finer grained control, consider using the {@link org.eclipse.kura.camel.runner.CamelRunner} mechanism.\n * </p>\n */\npublic class KuraCloudComponentResolver implements ComponentResolver {\n\n    private static final Logger logger = LoggerFactory.getLogger(KuraCloudComponentResolver.class);\n\n    private CloudService cloudService;\n\n    public void setCloudService(final CloudService cloudService) {\n        this.cloudService = cloudService;\n    }\n\n    @Override\n    public Component resolveComponent(final String name, final CamelContext context) throws Exception {\n        switch (name) {\n        case KuraCloudComponent.DEFAULT_NAME:\n            final KuraCloudComponent component = new KuraCloudComponent(context, this.cloudService);\n            logger.debug(\"Created new cloud component: {}\", component);\n            return component;\n        default:\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud;\n\n/**\n * Kura cloud constants\n */\npublic final class KuraCloudConstants {\n\n    public static final String TOPIC = \"topic\";\n    public static final String APPLICATION_ID = \"applicationId\";\n\n    public static final String CAMEL_KURA_CLOUD = \"CamelKuraCloud\";\n    public static final String CAMEL_KURA_CLOUD_TOPIC = CAMEL_KURA_CLOUD + \".topic\";\n    public static final String CAMEL_KURA_CLOUD_QOS = CAMEL_KURA_CLOUD + \".qos\";\n    public static final String CAMEL_KURA_CLOUD_RETAIN = CAMEL_KURA_CLOUD + \".retain\";\n    public static final String CAMEL_KURA_CLOUD_PRIORITY = CAMEL_KURA_CLOUD + \".priority\";\n    public static final String CAMEL_KURA_CLOUD_CONTROL = CAMEL_KURA_CLOUD + \".control\";\n    public static final String CAMEL_KURA_CLOUD_DEVICEID = CAMEL_KURA_CLOUD + \".deviceId\";\n\n    private KuraCloudConstants() {\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudConsumer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud;\n\nimport static org.apache.camel.builder.ExchangeBuilder.anExchange;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_TOPIC;\n\nimport org.apache.camel.Endpoint;\nimport org.apache.camel.Exchange;\nimport org.apache.camel.Processor;\nimport org.apache.camel.impl.DefaultConsumer;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloud.CloudClientListener;\nimport org.eclipse.kura.message.KuraPayload;\n\n/**\n * Consumer implementation for {@link KuraCloudComponent}\n */\npublic class KuraCloudConsumer extends DefaultConsumer implements CloudClientListener {\n\n    private final CloudClient cloudClient;\n\n    public KuraCloudConsumer(final Endpoint endpoint, final Processor processor, final CloudClient cloudClient) {\n        super(endpoint, processor);\n        this.cloudClient = cloudClient;\n    }\n\n    // Life-cycle\n\n    @Override\n    protected void doStart() throws Exception {\n        super.doStart();\n\n        this.log.debug(\"Starting CloudClientListener.\");\n\n        this.cloudClient.addCloudClientListener(this);\n        if (this.cloudClient.isConnected()) {\n            performSubscribe();\n        }\n    }\n\n    @Override\n    protected void doStop() throws Exception {\n        try {\n            this.cloudClient.unsubscribe(getEndpoint().getTopic());\n        } catch (final Exception e) {\n            this.log.info(\"Failed to unsubscribe\", e);\n        }\n        this.cloudClient.removeCloudClientListener(this);\n        this.log.debug(\"Stopping CloudClientListener.\");\n        super.doStop();\n    }\n\n    // CloudClientListener callbacks\n\n    @Override\n    public void onControlMessageArrived(final String deviceId, final String appTopic, final KuraPayload msg,\n            final int qos, final boolean retain) {\n        onInternalMessageArrived(deviceId, appTopic, msg, qos, retain, true);\n    }\n\n    @Override\n    public void onMessageArrived(final String deviceId, final String appTopic, final KuraPayload msg, final int qos,\n            final boolean retain) {\n        onInternalMessageArrived(deviceId, appTopic, msg, qos, retain, false);\n    }\n\n    @Override\n    public void onConnectionLost() {\n        this.log.debug(\"Executing empty 'onConnectionLost' callback.\");\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        this.log.debug(\"Executing 'onConnectionEstablished'.\");\n        performSubscribe();\n    }\n\n    private void performSubscribe() {\n        try {\n            this.log.debug(\"Perform subscribe: {} / {}\", this.cloudClient, getEndpoint().getTopic());\n            this.cloudClient.subscribe(getEndpoint().getTopic(), 0);\n        } catch (final KuraException e) {\n            this.log.warn(\"Failed to subscribe\", e);\n        }\n    }\n\n    @Override\n    public void onMessageConfirmed(final int messageId, final String appTopic) {\n        this.log.debug(\"Executing empty 'onMessageConfirmed' callback with message ID {} and application topic {}.\",\n                messageId, appTopic);\n    }\n\n    @Override\n    public void onMessagePublished(final int messageId, final String appTopic) {\n        this.log.debug(\"Executing empty 'onMessagePublished' callback with message ID {} and application topic {}.\",\n                messageId, appTopic);\n    }\n\n    // Helpers\n\n    private void onInternalMessageArrived(final String deviceId, final String appTopic, final KuraPayload message,\n            final int qos, final boolean retain, final boolean control) {\n        this.log.debug(\"Received message with deviceId {}, application topic {}.\", deviceId, appTopic);\n\n        final Exchange exchange = anExchange(getEndpoint().getCamelContext()) //\n                .withBody(message) //\n                .withHeader(CAMEL_KURA_CLOUD_TOPIC, appTopic) //\n                .withHeader(CAMEL_KURA_CLOUD_DEVICEID, deviceId) //\n                .withHeader(CAMEL_KURA_CLOUD_QOS, qos) //\n                .withHeader(CAMEL_KURA_CLOUD_CONTROL, control) //\n                .withHeader(CAMEL_KURA_CLOUD_RETAIN, retain) //\n                .build();\n\n        exchange.setFromEndpoint(getEndpoint());\n\n        try {\n            getProcessor().process(exchange);\n        } catch (final Exception e) {\n            handleException(\"Error while processing an incoming message:\", e);\n        }\n    }\n\n    // Getters\n\n    @Override\n    public KuraCloudEndpoint getEndpoint() {\n        return (KuraCloudEndpoint) super.getEndpoint();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudEndpoint.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud;\n\nimport org.apache.camel.Consumer;\nimport org.apache.camel.Processor;\nimport org.apache.camel.impl.DefaultEndpoint;\nimport org.apache.camel.spi.UriEndpoint;\nimport org.apache.camel.spi.UriParam;\nimport org.eclipse.kura.camel.internal.cloud.CloudClientCache;\nimport org.eclipse.kura.camel.internal.cloud.CloudClientCache.CloudClientHandle;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Endpoint implementation for {@link KuraCloudComponent}\n */\n@UriEndpoint(scheme = \"kura-cloud\", title = \"Kura Cloud\", label = \"iot,kura,cloud\", syntax = \"kura-cloud:applicationId/appTopic\")\npublic class KuraCloudEndpoint extends DefaultEndpoint {\n\n    private static final Logger logger = LoggerFactory.getLogger(KuraCloudEndpoint.class);\n\n    @UriParam(defaultValue = \"\")\n    private String applicationId = \"\";\n\n    @UriParam(defaultValue = \"\")\n    private String topic = \"\";\n\n    @UriParam(defaultValue = \"0\")\n    private int qos;\n\n    @UriParam(defaultValue = \"false\")\n    private boolean retain = false;\n\n    @UriParam(defaultValue = \"5\")\n    private int priority = 5;\n\n    @UriParam(defaultValue = \"false\")\n    private boolean control = false;\n\n    @UriParam(defaultValue = \"\")\n    private String deviceId;\n\n    private CloudClientHandle cloudClientHandle;\n\n    private final CloudClientCache cache;\n\n    public KuraCloudEndpoint(String uri, KuraCloudComponent kuraCloudComponent, CloudClientCache cache) {\n        super(uri, kuraCloudComponent);\n        this.cache = cache;\n    }\n\n    @Override\n    protected void doStart() throws Exception {\n        synchronized (this) {\n            this.cloudClientHandle = this.cache.getOrCreate(this.applicationId);\n            logger.debug(\"CloudClient {} -> {}\", this.applicationId, this.cloudClientHandle.getClient());\n        }\n        super.doStart();\n    }\n\n    @Override\n    protected void doStop() throws Exception {\n        super.doStop();\n\n        synchronized (this) {\n            if (this.cloudClientHandle != null) {\n                this.cloudClientHandle.close();\n                this.cloudClientHandle = null;\n            }\n        }\n    }\n\n    @Override\n    public Consumer createConsumer(Processor processor) throws Exception {\n        return new KuraCloudConsumer(this, processor, this.cloudClientHandle.getClient());\n    }\n\n    @Override\n    public KuraCloudProducer createProducer() throws Exception {\n        return new KuraCloudProducer(this, this.cloudClientHandle.getClient());\n    }\n\n    @Override\n    public boolean isSingleton() {\n        return true;\n    }\n\n    @Override\n    public KuraCloudComponent getComponent() {\n        return (KuraCloudComponent) super.getComponent();\n    }\n\n    public String getTopic() {\n        return this.topic;\n    }\n\n    public void setTopic(String topic) {\n        this.topic = topic;\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    public void setQos(int qos) {\n        this.qos = qos;\n    }\n\n    public boolean isRetain() {\n        return this.retain;\n    }\n\n    public void setRetain(boolean retain) {\n        this.retain = retain;\n    }\n\n    public int getPriority() {\n        return this.priority;\n    }\n\n    public void setPriority(int priority) {\n        this.priority = priority;\n    }\n\n    public boolean isControl() {\n        return this.control;\n    }\n\n    public void setControl(boolean control) {\n        this.control = control;\n    }\n\n    public String getApplicationId() {\n        return this.applicationId;\n    }\n\n    public void setApplicationId(String applicationId) {\n        this.applicationId = applicationId;\n    }\n\n    public String getDeviceId() {\n        return this.deviceId;\n    }\n\n    public void setDeviceId(String deviceId) {\n        this.deviceId = deviceId;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudProducer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud;\n\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_TOPIC;\n\nimport org.apache.camel.Exchange;\nimport org.apache.camel.Message;\nimport org.apache.camel.impl.DefaultProducer;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.message.KuraPayload;\n\n/**\n * Producer implementation for {@link KuraCloudComponent}\n */\npublic class KuraCloudProducer extends DefaultProducer {\n\n    // Visible for testing\n    CloudClient cloudClient;\n\n    public KuraCloudProducer(KuraCloudEndpoint endpoint, CloudClient cloudClient) {\n        super(endpoint);\n        this.cloudClient = cloudClient;\n    }\n\n    @Override\n    public void process(Exchange exchange) throws Exception {\n        Message in = exchange.getIn();\n\n        String topic = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_TOPIC, String.class), getEndpoint().getTopic());\n        int qos = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_QOS, Integer.class), getEndpoint().getQos());\n        int priority = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_PRIORITY, Integer.class),\n                getEndpoint().getPriority());\n        boolean retain = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_RETAIN, Boolean.class), getEndpoint().isRetain());\n        boolean control = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_CONTROL, Boolean.class),\n                getEndpoint().isControl());\n        String deviceId = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_DEVICEID, String.class),\n                getEndpoint().getDeviceId());\n\n        Object body = in.getBody();\n        if (body == null) {\n            throw new RuntimeException(\"Cannot produce null payload.\");\n        }\n\n        if (!(body instanceof KuraPayload)) {\n            KuraPayload payload = new KuraPayload();\n            if (body instanceof byte[]) {\n                payload.setBody((byte[]) body);\n            } else {\n                byte[] payloadBytes = in.getBody(byte[].class);\n                if (payloadBytes != null) {\n                    payload.setBody(in.getBody(byte[].class));\n                } else {\n                    payload.setBody(in.getBody(String.class).getBytes());\n                }\n            }\n            body = payload;\n        }\n\n        if (control) {\n            if (deviceId != null) {\n                this.cloudClient.controlPublish(deviceId, topic, (KuraPayload) body, qos, retain, priority);\n            } else {\n                this.cloudClient.controlPublish(topic, (KuraPayload) body, qos, retain, priority);\n            }\n        } else {\n            this.cloudClient.publish(topic, (KuraPayload) body, qos, retain, priority);\n        }\n    }\n\n    // Getters\n\n    @Override\n    public KuraCloudEndpoint getEndpoint() {\n        return (KuraCloudEndpoint) super.getEndpoint();\n    }\n\n    // Helpers\n\n    private static <T> T firstNotNull(T first, T second) {\n        return first != null ? first : second;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n/**\n * Functionality to support access to {@link org.eclipse.kura.cloud.CloudService} instances from Apache Camel\n */\npackage org.eclipse.kura.camel.cloud;\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/AbstractCamelComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.component;\n\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.Map;\n\nimport org.apache.camel.CamelContext;\nimport org.eclipse.kura.camel.runner.CamelRunner;\nimport org.eclipse.kura.camel.runner.CamelRunner.Builder;\nimport org.eclipse.kura.camel.runner.ContextFactory;\nimport org.eclipse.kura.camel.runner.ContextLifecycleListener;\nimport org.eclipse.kura.util.base.StringUtil;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * An abstract base Camel component for the use inside of Kura\n * <p>\n * This class intended to be subclasses and customized according to needs.\n * </p>\n */\npublic abstract class AbstractCamelComponent {\n\n    static final String PROP_DISABLE_JMX = \"org.eclipse.kura.camel.component.disableJmx\";\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractCamelComponent.class);\n\n    protected CamelRunner runner;\n\n    private ServiceRegistration<CamelContext> registration;\n\n    protected void start(final Map<String, Object> properties) throws Exception {\n        logger.info(\"Starting camel router\");\n\n        final String kuraServiceId = Configuration.asString(properties, \"camel.context.id\");\n        final String contextId;\n\n        if (kuraServiceId == null) { // allow disabling by setting an empty string\n            contextId = Configuration.asString(properties, \"kura.service.pid\");\n        } else {\n            contextId = kuraServiceId;\n        }\n\n        // create and configure\n\n        final Builder builder = new CamelRunner.Builder(getBundleContext());\n        builder.contextFactory(getContextFactory());\n        builder.disableJmx(Boolean.getBoolean(PROP_DISABLE_JMX));\n        builder.addBeforeStart(this::beforeStart);\n\n        if (!StringUtil.isNullOrEmpty(kuraServiceId) || !StringUtil.isNullOrEmpty(contextId)) {\n            builder.addLifecycleListener(new ContextLifecycleListener() {\n\n                @Override\n                public void started(final CamelContext camelContext) throws Exception {\n                    AbstractCamelComponent.this.started(camelContext, kuraServiceId, contextId);\n                }\n\n                @Override\n                public void stopping(final CamelContext camelContext) throws Exception {\n                    AbstractCamelComponent.this.stopping();\n                }\n\n            });\n        }\n\n        customizeBuilder(builder, properties);\n\n        this.runner = builder.build();\n\n        // start\n\n        this.runner.start();\n    }\n\n    protected void started(final CamelContext camelContext, final String kuraServicePid, final String contextId) {\n\n        // ensure we are reported stopped\n\n        stopping();\n\n        // now start\n\n        final Dictionary<String, Object> properties = new Hashtable<>();\n\n        if (!StringUtil.isNullOrEmpty(kuraServicePid)) {\n            properties.put(\"kura.service.pid\", kuraServicePid);\n        }\n\n        if (!StringUtil.isNullOrEmpty(contextId)) {\n            properties.put(Constants.SERVICE_PID, contextId);\n            properties.put(\"camel.context.id\", contextId);\n        }\n\n        // register\n\n        this.registration = getBundleContext().registerService(CamelContext.class, camelContext, properties);\n\n        logger.info(\"Registered camel context: {}\", this.registration);\n    }\n\n    protected void stopping() {\n\n        if (this.registration != null) {\n\n            logger.info(\"Unregister camel context: {}\", this.registration);\n\n            this.registration.unregister();\n            this.registration = null;\n        }\n\n    }\n\n    /**\n     * Customize the builder before it creates the runner\n     * <br>\n     * The default implementation is empty\n     *\n     * @param builder\n     *            the builder\n     * @param properties\n     *            the properties provided to the {@link #start(Map)} method\n     */\n    protected void customizeBuilder(final Builder builder, final Map<String, Object> properties) {\n    }\n\n    protected void stop() throws Exception {\n        logger.info(\"Stopping camel router\");\n\n        // stopping\n\n        if (this.runner != null) {\n            this.runner.stop();\n            this.runner = null;\n        }\n    }\n\n    /**\n     * Get the Camel context\n     *\n     * @return the camel context or {@code null} if the context is not started\n     */\n    public CamelContext getCamelContext() {\n        final CamelRunner camelRunner = this.runner;\n        return camelRunner != null ? camelRunner.getCamelContext() : null;\n    }\n\n    /**\n     * Called before the context is started\n     *\n     * @param camelContext\n     *            the Camel context which is being prepared for starting\n     */\n    protected void beforeStart(final CamelContext camelContext) {\n    }\n\n    protected ContextFactory getContextFactory() {\n        return CamelRunner.createOsgiFactory(getBundleContext());\n    }\n\n    protected BundleContext getBundleContext() {\n        return FrameworkUtil.getBundle(AbstractCamelComponent.class).getBundleContext();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/AbstractJavaCamelComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n\npackage org.eclipse.kura.camel.component;\n\nimport static java.lang.Boolean.getBoolean;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.builder.RouteBuilder;\nimport org.eclipse.kura.camel.runner.CamelRunner;\nimport org.eclipse.kura.camel.runner.CamelRunner.Builder;\nimport org.eclipse.kura.camel.runner.ContextFactory;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * An abstract base class for implementing a {@link ConfigurableComponent} using\n * the Java DSL\n * <p>\n * This class intended to be subclasses and customized according to needs.\n * </p>\n * <p>\n * <strong>Note:</strong> This class is intended to be used as <em>OSGi Service\n * Component</em>. The methods {@link #start()} and {@link #stop()} have to be configured\n * accordingly.\n * </p>\n * <p>\n * The lifecycle methods of this class declare annotations based on {@link org.osgi.service.component.annotations}.\n * However those annotations are only discovered during build time. They are declared in order\n * to provide proper support when annotation based tooling is used. Otherwise those methods must be\n * mapped manually in the DS declaration.\n * </p>\n */\npublic abstract class AbstractJavaCamelComponent extends RouteBuilder implements ConfigurableComponent {\n\n    private static final String PROP_DISABLE_JMX = AbstractCamelComponent.PROP_DISABLE_JMX;\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractJavaCamelComponent.class);\n\n    protected CamelRunner runner;\n\n    protected void start() throws Exception {\n        logger.info(\"Starting camel router\");\n\n        // create and configure\n\n        final Builder builder = new CamelRunner.Builder();\n        builder.contextFactory(getContextFactory());\n        builder.disableJmx(getBoolean(PROP_DISABLE_JMX));\n        builder.addBeforeStart(camelContext -> {\n            beforeStart(camelContext);\n            camelContext.addRoutes(AbstractJavaCamelComponent.this);\n        });\n\n        this.runner = builder.build();\n\n        // start\n\n        this.runner.start();\n    }\n\n    protected void stop() throws Exception {\n        logger.info(\"Stopping camel router\");\n\n        // stopping\n\n        if (this.runner != null) {\n            this.runner.stop();\n            this.runner = null;\n        }\n    }\n\n    /**\n     * Called before the context is started\n     *\n     * @param camelContext\n     *            the Camel context which is being prepared for starting\n     */\n    protected void beforeStart(final CamelContext camelContext) {\n    }\n\n    protected ContextFactory getContextFactory() {\n        return CamelRunner.createOsgiFactory(getBundleContext());\n    }\n\n    protected BundleContext getBundleContext() {\n        return FrameworkUtil.getBundle(AbstractCamelComponent.class).getBundleContext();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/AbstractXmlCamelComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n\npackage org.eclipse.kura.camel.component;\n\nimport static org.eclipse.kura.camel.component.Configuration.asString;\n\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.osgi.framework.BundleContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * An abstract base class for implementing a {@link ConfigurableComponent} using\n * configured XML\n * <p>\n * This class intended to be subclasses and customized according to needs.\n * </p>\n * <p>\n * <strong>Note:</strong> This class is intended to be used as <em>OSGi Service\n * Component</em>. There the methods {@link #activate(BundleContext, Map)},\n * {@link #modified(Map)} and {@link #deactivate(BundleContext)} need to be\n * configured accordingly.\n * </p>\n * <p>\n * The lifecycle methods of this class declare annotations based on {@link org.osgi.service.component.annotations}.\n * However those annotations are only discovered during build time. They are declared in order\n * to provide proper support when annotation based tooling is used. Otherwise those methods must be\n * mapped manually in the DS declaration.\n * </p>\n */\npublic abstract class AbstractXmlCamelComponent extends AbstractCamelComponent implements ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractXmlCamelComponent.class);\n    private final String xmlDataProperty;\n\n    public AbstractXmlCamelComponent(final String xmlDataProperty) {\n        Objects.requireNonNull(xmlDataProperty);\n\n        this.xmlDataProperty = xmlDataProperty;\n    }\n\n    protected void activate(final BundleContext context, final Map<String, Object> properties) throws Exception {\n        try {\n            start(properties);\n\n            // apply current routes\n            applyRoutes(properties);\n        } catch (Exception e) {\n            logger.warn(\"Problem activating component\", e);\n            // we need to suppress exceptions during start\n            // otherwise Kura cannot configure us anymore\n        }\n    }\n\n    protected void deactivate(final BundleContext context) throws Exception {\n        try {\n            stop();\n        } catch (Exception e) {\n            logger.warn(\"Problem deactivating component\", e);\n            throw e;\n        }\n    }\n\n    protected void modified(final Map<String, Object> properties) throws Exception {\n        logger.debug(\"Updating properties: {}\", properties);\n        try {\n            if (isRestartNeeded(properties)) {\n                logger.info(\"Need restart\");\n                stop();\n                start(properties);\n            }\n\n            // apply current routes\n\n            applyRoutes(properties);\n        } catch (Exception e) {\n            logger.warn(\"Problem updating component\", e);\n            throw e;\n        }\n    }\n\n    private void applyRoutes(final Map<String, Object> properties) throws Exception {\n        this.runner.setRoutes(asString(properties, this.xmlDataProperty));\n    }\n\n    protected boolean isRestartNeeded(final Map<String, Object> properties) {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/Configuration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.component;\n\nimport java.util.Map;\n\n/**\n * A few helper methods for consuming configuration from a properties map\n */\npublic final class Configuration {\n\n    private Configuration() {\n    }\n\n    /**\n     * Get a string value, defaulting to {@code null}\n     *\n     * @param properties\n     *            the properties to read from, may be {@code null}\n     * @param key\n     *            the key to read, may be {@code null}\n     * @return the string value or {@code null}\n     */\n    public static String asString(final Map<String, ?> properties, final String key) {\n        return asString(properties, key, null);\n    }\n\n    /**\n     * Get a string value\n     *\n     * @param properties\n     *            the properties to read from, may be {@code null}\n     * @param key\n     *            the key to read, may be {@code null}\n     * @param defaultValue\n     *            the default value, may be {@code null}\n     * @return the string value or the default value\n     */\n    public static String asString(final Map<String, ?> properties, final String key, final String defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (value instanceof String) {\n            return (String) value;\n        }\n\n        return defaultValue;\n    }\n\n    /**\n     * Get a string value, unless it is empty\n     * <p>\n     * If the properties map contains the string, but the string is empty by {@link String#isEmpty()}, then\n     * also the default value will be returned.\n     * </p>\n     *\n     * @param properties\n     *            the properties to read from, may be {@code null}\n     * @param key\n     *            the key to read, may be {@code null}\n     * @param defaultValue\n     *            the default value, may be {@code null}\n     * @return the string value or the default value\n     */\n    public static String asStringNotEmpty(final Map<String, ?> properties, final String key, final String defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (!(value instanceof String)) {\n            return defaultValue;\n        }\n\n        String stringValue = (String) value;\n        if (stringValue.isEmpty()) {\n            return defaultValue;\n        }\n\n        return stringValue;\n    }\n\n    public static Integer asInteger(final Map<String, ?> properties, final String key) {\n        return asInteger(properties, key, null);\n    }\n\n    public static Integer asInteger(final Map<String, ?> properties, final String key, final Integer defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (value instanceof Number) {\n            return ((Number) value).intValue();\n        }\n\n        return defaultValue;\n    }\n\n    public static int asInt(final Map<String, ?> properties, final String key, final int defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (value instanceof Number) {\n            return ((Number) value).intValue();\n        }\n\n        return defaultValue;\n    }\n\n    public static Long asLong(final Map<String, ?> properties, final String key) {\n        return asLong(properties, key, null);\n    }\n\n    public static Long asLong(final Map<String, ?> properties, final String key, final Long defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (value instanceof Number) {\n            return ((Number) value).longValue();\n        }\n\n        return defaultValue;\n    }\n\n    public static long asLong(final Map<String, ?> properties, final String key, final long defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (value instanceof Number) {\n            return ((Number) value).longValue();\n        }\n\n        return defaultValue;\n    }\n\n    public static Double asDouble(final Map<String, ?> properties, final String key) {\n        return asDouble(properties, key, null);\n    }\n\n    public static Double asDouble(final Map<String, ?> properties, final String key, final Double defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (value instanceof Number) {\n            return ((Number) value).doubleValue();\n        }\n\n        return defaultValue;\n    }\n\n    public static double asDouble(final Map<String, ?> properties, final String key, final double defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (value instanceof Number) {\n            return ((Number) value).doubleValue();\n        }\n\n        return defaultValue;\n    }\n\n    /**\n     * Get a boolean parameter from the configuration\n     *\n     * @param properties\n     *            the configuration\n     * @param key\n     *            the key to fetch\n     * @return the boolean value from the configuration, or {@code false} if the property set is {@code null}, the\n     *         property is not set or it is not boolean\n     */\n    public static boolean asBoolean(Map<String, ?> properties, String key) {\n        return asBoolean(properties, key, false);\n    }\n\n    public static Boolean asBoolean(Map<String, ?> properties, String key, Boolean defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (value instanceof Boolean) {\n            return (Boolean) value;\n        }\n\n        return defaultValue;\n    }\n\n    public static boolean asBoolean(Map<String, ?> properties, String key, boolean defaultValue) {\n        if (properties == null) {\n            return defaultValue;\n        }\n\n        final Object value = properties.get(key);\n        if (value instanceof Boolean) {\n            return (Boolean) value;\n        }\n\n        return defaultValue;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n/**\n * Components for building Kura application based on Apache Camel™\n * <p>\n * This package provides a few classes which are intended as based classes\n * helping to implement simple Camel based components.\n * </p>\n */\npackage org.eclipse.kura.camel.component;"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/internal/camelcloud/CamelCloudClient.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.internal.camelcloud;\n\nimport static java.lang.String.format;\nimport static java.util.Objects.requireNonNull;\nimport static org.apache.camel.ServiceStatus.Started;\nimport static org.eclipse.kura.KuraErrorCode.CONFIGURATION_ERROR;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_MESSAGEID;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Random;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.ExecutorService;\nimport java.util.function.IntSupplier;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.Exchange;\nimport org.apache.camel.Processor;\nimport org.apache.camel.ProducerTemplate;\nimport org.apache.camel.StartupListener;\nimport org.apache.camel.builder.RouteBuilder;\nimport org.apache.camel.impl.DefaultShutdownStrategy;\nimport org.apache.camel.spi.ShutdownStrategy;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.camel.camelcloud.CamelCloudService;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloud.CloudClientListener;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A Kura {@link CloudClient} based in Apache Camel\n */\npublic class CamelCloudClient implements CloudClient {\n\n    private static final Logger logger = LoggerFactory.getLogger(CamelCloudClient.class);\n\n    private final CamelCloudService cloudService;\n\n    private final CamelContext camelContext;\n\n    private final ProducerTemplate producerTemplate;\n\n    private final List<CloudClientListener> cloudClientListeners = new CopyOnWriteArrayList<>();\n\n    private final String applicationId;\n\n    private final String baseEndpoint;\n\n    private final ExecutorService executorService;\n\n    private final Random messageIdRandom = new Random();\n\n    private final IntSupplier messageIdGenerator = () -> Math.abs(this.messageIdRandom.nextInt());\n\n    public CamelCloudClient(CamelCloudService cloudService, CamelContext camelContext, String applicationId,\n            String baseEndpoint) {\n        this.cloudService = cloudService;\n        this.camelContext = camelContext;\n        this.producerTemplate = camelContext.createProducerTemplate();\n        this.applicationId = applicationId;\n        this.baseEndpoint = baseEndpoint;\n        this.executorService = camelContext.getExecutorServiceManager().newThreadPool(this,\n                \"CamelCloudClient/\" + applicationId, 0, 1);\n    }\n\n    public CamelCloudClient(CamelCloudService cloudService, CamelContext camelContext, String applicationId) {\n        this(cloudService, camelContext, applicationId, \"vm:%s\");\n    }\n\n    // Cloud client API\n\n    @Override\n    public String getApplicationId() {\n        return this.applicationId;\n    }\n\n    @Override\n    public void release() {\n        this.cloudService.release(this.applicationId);\n        this.camelContext.getExecutorServiceManager().shutdown(this.executorService);\n    }\n\n    @Override\n    public boolean isConnected() {\n        return this.camelContext.getStatus() == Started;\n    }\n\n    @Override\n    public int publish(String topic, KuraPayload kuraPayload, int qos, boolean retain) throws KuraException {\n        return publish(topic, kuraPayload, qos, retain, 5);\n    }\n\n    @Override\n    public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain)\n            throws KuraException {\n        return doPublish(false, deviceId, appTopic, payload, qos, retain, 5);\n    }\n\n    @Override\n    public int publish(String topic, KuraPayload kuraPayload, int qos, boolean retain, int priority)\n            throws KuraException {\n        return doPublish(false, null, topic, kuraPayload, qos, retain, priority);\n    }\n\n    @Override\n    public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain, int priority)\n            throws KuraException {\n        return doPublish(false, deviceId, appTopic, payload, qos, retain, priority);\n    }\n\n    @Override\n    public int publish(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraException {\n        KuraPayload kuraPayload = new KuraPayload();\n        kuraPayload.setBody(payload);\n        return publish(topic, kuraPayload, qos, retain, priority);\n    }\n\n    @Override\n    public int publish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraException {\n        KuraPayload kuraPayload = new KuraPayload();\n        kuraPayload.setBody(payload);\n        return publish(deviceId, appTopic, kuraPayload, qos, retain, priority);\n    }\n\n    @Override\n    public int controlPublish(String topic, KuraPayload payload, int qos, boolean retain, int priority)\n            throws KuraException {\n        return doPublish(true, null, topic, payload, qos, retain, priority);\n    }\n\n    @Override\n    public int controlPublish(String deviceId, String topic, KuraPayload kuraPayload, int qos, boolean retain,\n            int priority) throws KuraException {\n        return doPublish(true, deviceId, topic, kuraPayload, qos, retain, priority);\n    }\n\n    @Override\n    public int controlPublish(String deviceId, String topic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraException {\n        KuraPayload kuraPayload = new KuraPayload();\n        kuraPayload.setBody(payload);\n        return doPublish(true, deviceId, topic, kuraPayload, qos, retain, priority);\n    }\n\n    @Override\n    public void subscribe(String topic, int qos) throws KuraException {\n        forkSubscribe(false, null, topic, qos);\n    }\n\n    @Override\n    public void subscribe(String deviceId, String appTopic, int qos) throws KuraException {\n        forkSubscribe(false, deviceId, appTopic, qos);\n    }\n\n    @Override\n    public void controlSubscribe(String topic, int qos) throws KuraException {\n        forkSubscribe(true, null, topic, qos);\n    }\n\n    @Override\n    public void controlSubscribe(String deviceId, String appTopic, int qos) throws KuraException {\n        forkSubscribe(true, deviceId, appTopic, qos);\n    }\n\n    @Override\n    public void unsubscribe(String topic) throws KuraException {\n        doUnsubscribe(null, topic);\n    }\n\n    @Override\n    public void unsubscribe(String deviceId, String appTopic) throws KuraException {\n        doUnsubscribe(deviceId, appTopic);\n    }\n\n    @Override\n    public void controlUnsubscribe(String topic) throws KuraException {\n        doUnsubscribe(null, topic);\n    }\n\n    @Override\n    public void controlUnsubscribe(String deviceId, String appTopic) throws KuraException {\n        doUnsubscribe(deviceId, appTopic);\n    }\n\n    @Override\n    public void addCloudClientListener(CloudClientListener cloudClientListener) {\n        this.cloudClientListeners.add(cloudClientListener);\n    }\n\n    @Override\n    public void removeCloudClientListener(CloudClientListener cloudClientListener) {\n        this.cloudClientListeners.remove(cloudClientListener);\n    }\n\n    @Override\n    public List<Integer> getUnpublishedMessageIds() throws KuraException {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<Integer> getInFlightMessageIds() throws KuraException {\n        return Collections.emptyList();\n    }\n\n    @Override\n    public List<Integer> getDroppedInFlightMessageIds() throws KuraException {\n        return Collections.emptyList();\n    }\n\n    // Helpers\n\n    private void doUnsubscribe(String deviceId, String topic) throws KuraException {\n        final String internalQueue = buildTopicName(deviceId, topic);\n\n        try {\n            ShutdownStrategy strategy = this.camelContext.getShutdownStrategy();\n            if (strategy instanceof DefaultShutdownStrategy) {\n                if (((DefaultShutdownStrategy) strategy).getCurrentShutdownTaskFuture() != null) {\n                    logger.info(\"Skipping cleanup of '{}' since the camel context is being shut down\", internalQueue);\n                    // we are \"in shutdown\" and would deadlock\n                    return;\n                }\n            }\n\n            // perform shutdown\n\n            this.camelContext.stopRoute(internalQueue);\n            this.camelContext.removeRoute(internalQueue);\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.SUBSCRIPTION_ERROR, e, internalQueue);\n        }\n    }\n\n    private String buildTopicName(final String deviceId, final String topic) {\n        requireNonNull(topic, \"'topic' must not be null\");\n\n        if (deviceId == null) {\n            return String.format(\"%s:%s\", this.applicationId, topic);\n        } else {\n            return String.format(\"%s:%s:%s\", deviceId, this.applicationId, topic);\n        }\n    }\n\n    private int doPublish(boolean isControl, String deviceId, String topic, KuraPayload kuraPayload, int qos,\n            boolean retain, int priority) throws KuraException {\n        final String target = target(buildTopicName(deviceId, topic));\n        final int kuraMessageId = this.messageIdGenerator.getAsInt();\n\n        final Map<String, Object> headers = new HashMap<>();\n        headers.put(CAMEL_KURA_CLOUD_CONTROL, isControl);\n        headers.put(CAMEL_KURA_CLOUD_MESSAGEID, kuraMessageId);\n        headers.put(CAMEL_KURA_CLOUD_DEVICEID, deviceId);\n        headers.put(CAMEL_KURA_CLOUD_QOS, qos);\n        headers.put(CAMEL_KURA_CLOUD_RETAIN, retain);\n        headers.put(CAMEL_KURA_CLOUD_PRIORITY, priority);\n\n        logger.trace(\"Publishing: {} -> {} / {}\", target, kuraPayload, this.camelContext);\n\n        this.producerTemplate.sendBodyAndHeaders(target, kuraPayload, headers);\n\n        return kuraMessageId;\n    }\n\n    private void forkSubscribe(final boolean isControl, final String deviceId, final String topic, final int qos)\n            throws KuraException {\n        /*\n         * This construct is needed due to CAMEL-10206\n         *\n         * It does fork off the subscription process, which actually creates a\n         * new camel route, into the background since we currently may be in the\n         * process of starting the camel context. If that is the case then the\n         * newly added route won't be started since the camel context is in the\n         * \"starting\" mode. Events won't get processed.\n         *\n         * So we do fork off the subscription process after the camel context\n         * has been started. The executor is needed since, according to the\n         * camel javadoc on StartupListener, the camel context may still be in\n         * \"starting\" mode when the \"onCamelContextStarted\" method is called.\n         */\n        try {\n            this.camelContext.addStartupListener(new StartupListener() {\n\n                @Override\n                public void onCamelContextStarted(CamelContext context, boolean alreadyStarted) throws Exception {\n                    CamelCloudClient.this.executorService.submit(new Callable<Void>() {\n\n                        @Override\n                        public Void call() throws Exception {\n                            doSubscribe(isControl, deviceId, topic, qos);\n                            return null;\n                        }\n                    });\n                }\n            });\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.SUBSCRIPTION_ERROR, e, buildTopicName(deviceId, topic));\n        }\n    }\n\n    private void doSubscribe(final boolean isControl, String deviceId, final String topic, final int qos)\n            throws KuraException {\n        logger.debug(\"About to subscribe to topic {}:{} with QOS {}.\", deviceId, topic, qos);\n        final String internalQueue = buildTopicName(deviceId, topic);\n        logger.debug(\"\\tInternal target: {} / {}\", target(internalQueue), this.camelContext);\n        try {\n            this.camelContext.addRoutes(new RouteBuilder() {\n\n                @Override\n                public void configure() throws Exception {\n                    from(target(internalQueue)).routeId(internalQueue).process(new Processor() {\n\n                        @Override\n                        public void process(Exchange exchange) throws Exception {\n                            logger.debug(\"Processing: {}\", exchange);\n                            for (CloudClientListener listener : CamelCloudClient.this.cloudClientListeners) {\n                                logger.debug(\"\\t{}\", listener);\n                                Object body = exchange.getIn().getBody();\n                                KuraPayload payload;\n                                if (body instanceof KuraPayload) {\n                                    payload = (KuraPayload) body;\n                                } else {\n                                    payload = new KuraPayload();\n                                    payload.setBody(getContext().getTypeConverter().convertTo(byte[].class, body));\n                                }\n                                String deviceId = exchange.getIn().getHeader(CAMEL_KURA_CLOUD_DEVICEID, String.class);\n                                int qos = exchange.getIn().getHeader(CAMEL_KURA_CLOUD_QOS, 0, int.class);\n                                listener.onMessageArrived(deviceId, \"camel\", payload, qos, true);\n                            }\n                        }\n                    });\n                }\n            });\n        } catch (Exception e) {\n            logger.warn(\"Error while adding subscription route. Rethrowing root cause.\");\n            throw new KuraException(CONFIGURATION_ERROR, e);\n        }\n    }\n\n    private String target(String topic) {\n        if (this.baseEndpoint.contains(\"%s\")) {\n            return format(this.baseEndpoint, topic);\n        }\n        return this.baseEndpoint + topic;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/internal/cloud/CloudClientCache.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.internal.cloud;\n\nimport org.eclipse.kura.cloud.CloudClient;\n\npublic interface CloudClientCache {\n\n    interface CloudClientHandle extends AutoCloseable {\n\n        CloudClient getClient();\n    }\n\n    CloudClientHandle getOrCreate(String applicationId);\n\n    void close();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/internal/cloud/CloudClientCacheImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.internal.cloud;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudClientCacheImpl implements CloudClientCache {\n\n    private final class CloudClientHandleImplementation implements CloudClientHandle {\n\n        private final String applicationId;\n\n        private final CloudClient client;\n\n        public CloudClientHandleImplementation(String applicationId, CloudClient client) {\n            this.applicationId = applicationId;\n            this.client = client;\n        }\n\n        @Override\n        public void close() throws Exception {\n            removeHandle(CloudClientHandleImplementation.this, this.applicationId, this.client);\n        }\n\n        @Override\n        public CloudClient getClient() {\n            return this.client;\n        }\n    }\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudClientCacheImpl.class);\n\n    private final CloudService cloudService;\n\n    private final Map<String, Set<CloudClientHandle>> cache = new HashMap<>();\n\n    public CloudClientCacheImpl(CloudService cloudService) {\n        this.cloudService = cloudService;\n    }\n\n    @Override\n    public synchronized CloudClientHandle getOrCreate(final String applicationId) {\n        try {\n            Set<CloudClientHandle> set = this.cache.get(applicationId);\n            if (set == null) {\n                logger.debug(\"CloudClient for application ID {} not found. Creating new one.\", applicationId);\n                set = new HashSet<>();\n                this.cache.put(applicationId, set);\n            } else {\n                logger.debug(\"CloudClient for application ID {} ... cache hit.\", applicationId);\n            }\n\n            boolean created = false;\n            CloudClient client = null;\n            try {\n\n                if (set.isEmpty()) {\n                    logger.debug(\"Creating new cloud client for: {}\", applicationId);\n                    created = true;\n                    client = this.cloudService.newCloudClient(applicationId);\n                } else {\n                    client = set.iterator().next().getClient();\n                    logger.debug(\"Re-using cloud client: {} -> {}\", applicationId, client);\n                }\n\n                try {\n                    final CloudClientHandle handle = new CloudClientHandleImplementation(applicationId, client);\n                    set.add(handle);\n                    return handle;\n                } finally {\n                    // mark as returned\n                    client = null;\n                }\n            } finally {\n                if (created && client != null) {\n                    // clean up leaked resource\n                    client.release();\n                }\n            }\n\n        } catch (KuraException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private void removeHandle(CloudClientHandle handle, String applicationId, CloudClient client) {\n\n        logger.debug(\"Remove handle: {}\", handle);\n\n        final Set<CloudClientHandle> set;\n\n        synchronized (this) {\n            set = this.cache.get(applicationId);\n            if (set == null) {\n                return;\n            }\n\n            set.remove(handle); // don't process result, we clean up anyway\n\n            if (set.isEmpty()) {\n                logger.debug(\"Removing last handle for: {}\", applicationId);\n                this.cache.remove(applicationId);\n            }\n        }\n\n        if (set.isEmpty()) {\n            // release outside of lock\n            logger.debug(\"Releasing client: {} / {}\", applicationId, client);\n            client.release();\n        }\n    }\n\n    @Override\n    public void close() {\n        final List<CloudClientHandle> handles = new ArrayList<>();\n        synchronized (this) {\n            for (final Set<CloudClientHandle> set : this.cache.values()) {\n                handles.addAll(set);\n            }\n            this.cache.clear();\n        }\n\n        // release outside the lock\n\n        final Set<CloudClient> clients = new HashSet<>();\n        for (final CloudClientHandle handle : handles) {\n\n            final CloudClient client = handle.getClient();\n\n            if (clients.add(client)) {\n                client.release();\n                logger.info(\"Closing client: {}\", client);\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/internal/utils/KuraServiceFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.internal.utils;\n\nimport static org.slf4j.LoggerFactory.getLogger;\n\nimport java.util.Set;\n\nimport org.apache.camel.spi.Registry;\nimport org.slf4j.Logger;\n\npublic final class KuraServiceFactory {\n\n    // Logger\n\n    private static final Logger logger = getLogger(KuraServiceFactory.class);\n\n    // Constructors\n\n    private KuraServiceFactory() {\n    }\n\n    // Operations\n\n    public static <T> T retrieveService(final Class<T> clazz, final Registry registry) {\n        if (registry == null) {\n            throw new IllegalArgumentException(\"Registry cannot be null.\");\n        }\n\n        Set<T> servicesFromRegistry = registry.findByType(clazz);\n        if (servicesFromRegistry.size() == 1) {\n            T service = servicesFromRegistry.iterator().next();\n            logger.info(\"Found Kura \" + clazz.getCanonicalName()\n                    + \" in the registry. Kura component will use that instance.\");\n            return service;\n        } else if (servicesFromRegistry.size() > 1) {\n            throw new IllegalStateException(\"Too many \" + clazz.getCanonicalName() + \" services found in a registry: \"\n                    + servicesFromRegistry.size());\n        } else {\n            throw new IllegalArgumentException(\n                    \"No \" + clazz.getCanonicalName() + \" service instance found in a registry.\");\n        }\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n/**\n * Basic Apache Camel™ functionality\n * <p>\n * For information on how to create a component based on Apache Camel see:\n * </p>\n * <ul>\n * <li>{@link org.eclipse.kura.camel.runner.CamelRunner}</li>\n * <li>{@link org.eclipse.kura.camel.component}</li>\n * </ul>\n */\npackage org.eclipse.kura.camel;\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/router/CamelRouter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.camel.router;\n\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.apache.camel.CamelContext;\nimport org.eclipse.kura.camel.component.AbstractXmlCamelComponent;\nimport org.osgi.framework.BundleActivator;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceReference;\n\n/**\n * The class provides a compatibility layer for the older API\n *\n * @deprecated Use the {@link org.eclipse.kura.camel.runner.CamelRunner}, one of the abstract implementations from\n *             {@link org.eclipse.kura.camel.component} or the native\n *             {@link org.apache.camel.core.osgi.OsgiDefaultCamelContext}\n */\n@Deprecated\npublic abstract class CamelRouter extends AbstractXmlCamelComponent implements BundleActivator {\n\n    protected CamelContext camelContext;\n\n    public CamelRouter() {\n        super(\"camel.route.xml\");\n    }\n\n    @Override\n    protected void activate(BundleContext context, Map<String, Object> properties) throws Exception {\n        super.activate(context, properties);\n        this.camelContext = getCamelContext();\n    }\n\n    @Override\n    protected void deactivate(BundleContext context) throws Exception {\n        this.camelContext = null;\n        super.deactivate(context);\n    }\n\n    protected <T> T service(Class<T> serviceType) {\n        Objects.requireNonNull(serviceType);\n\n        final ServiceReference<T> reference = getBundleContext().getServiceReference(serviceType);\n        return reference == null ? null : getBundleContext().getService(reference);\n    }\n\n    protected <T> T requiredService(final Class<T> serviceType) {\n        Objects.requireNonNull(serviceType);\n\n        final ServiceReference<T> reference = getBundleContext().getServiceReference(serviceType);\n        if (reference == null) {\n            throw new IllegalStateException(\"Cannot find service: \" + serviceType.getName());\n        }\n\n        return getBundleContext().getService(reference);\n    }\n\n    protected String camelXmlRoutesPid() {\n        return \"kura.camel\";\n    }\n\n    protected String camelXmlRoutesProperty() {\n        return \"kura.camel.\" + FrameworkUtil.getBundle(this.getClass()).getSymbolicName() + \".route\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/router/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n/**\n * Old Camel API of Kura\n *\n * @deprecated For alternatives see the deprecation note of {@link CamelRouter}\n */\npackage org.eclipse.kura.camel.router;\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/AbstractRoutesProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport static org.eclipse.kura.camel.runner.CamelRunner.removeMissingRoutes;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.model.RoutesDefinition;\n\npublic abstract class AbstractRoutesProvider implements RoutesProvider {\n\n    @Override\n    public void applyRoutes(final CamelContext camelContext) throws Exception {\n\n        final RoutesDefinition routes = getRoutes(camelContext);\n\n        removeMissingRoutes(camelContext, routes.getRoutes());\n\n        camelContext.addRouteDefinitions(routes.getRoutes());\n    }\n\n    protected abstract RoutesDefinition getRoutes(CamelContext camelContext) throws Exception;\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/BeforeStart.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport org.apache.camel.CamelContext;\n\n@FunctionalInterface\npublic interface BeforeStart {\n\n    public void beforeStart(CamelContext camelContext) throws Exception;\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/BuilderRoutesProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.builder.RouteBuilder;\n\npublic class BuilderRoutesProvider implements RoutesProvider {\n\n    private final RouteBuilder builder;\n\n    public BuilderRoutesProvider(final RouteBuilder builder) throws Exception {\n        this.builder = builder;\n    }\n\n    @Override\n    public void applyRoutes(CamelContext camelContext) throws Exception {\n        CamelRunner.removeMissingRoutes(camelContext, this.builder.getRouteCollection().getRoutes());\n        camelContext.addRoutes(this.builder);\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/CamelRunner.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.Route;\nimport org.apache.camel.builder.RouteBuilder;\nimport org.apache.camel.core.osgi.OsgiDefaultCamelContext;\nimport org.apache.camel.core.osgi.OsgiServiceRegistry;\nimport org.apache.camel.impl.CompositeRegistry;\nimport org.apache.camel.impl.SimpleRegistry;\nimport org.apache.camel.model.OptionalIdentifiedDefinition;\nimport org.apache.camel.model.RouteDefinition;\nimport org.apache.camel.model.RoutesDefinition;\nimport org.apache.camel.spi.ComponentResolver;\nimport org.apache.camel.spi.LanguageResolver;\nimport org.apache.camel.spi.Registry;\nimport org.apache.camel.util.function.ThrowingBiConsumer;\nimport org.eclipse.kura.camel.cloud.KuraCloudComponent;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A lifecycle manager for running a CamelContext\n * <p>\n * Use the {@link Builder} class to create instances of the {@link CamelRunner}.\n * </p>\n */\npublic class CamelRunner {\n\n    private static final Logger logger = LoggerFactory.getLogger(CamelRunner.class);\n\n    /**\n     * Creates a new {@link ContextFactory} backed by {@link OsgiDefaultCamelContext}\n     *\n     * @param bundleContext\n     *            the bundle context to use\n     * @return a context factory creating {@link OsgiDefaultCamelContext}s\n     */\n    public static ContextFactory createOsgiFactory(final BundleContext bundleContext) {\n        Objects.requireNonNull(bundleContext);\n\n        return registry -> new OsgiDefaultCamelContext(bundleContext, registry);\n    }\n\n    /**\n     * Creates a new {@link RegistryFactory} backed by {@link OsgiServiceRegistry}\n     *\n     * @param bundleContext\n     *            the bundle context to use\n     * @return a registry factory creating {@link OsgiServiceRegistry}s\n     */\n    public static RegistryFactory createOsgiRegistry(final BundleContext bundleContext) {\n        Objects.requireNonNull(bundleContext);\n\n        return () -> new OsgiServiceRegistry(bundleContext);\n    }\n\n    public static RegistryFactory createOsgiRegistry(final BundleContext bundleContext,\n            final Map<String, Object> services) {\n        Objects.requireNonNull(bundleContext);\n\n        if (services == null || services.isEmpty()) {\n            return createOsgiRegistry(bundleContext);\n        }\n\n        return () -> {\n            final List<Registry> registries = new LinkedList<>();\n\n            // add simple registry\n\n            final SimpleRegistry simple = new SimpleRegistry();\n            simple.putAll(services);\n\n            registries.add(simple);\n\n            // add OSGi registry\n\n            registries.add(new OsgiServiceRegistry(bundleContext));\n\n            // return composite\n\n            return new CompositeRegistry(registries);\n        };\n    }\n\n    /**\n     * A builder for creating {@link CamelRunner} instances\n     */\n    public static final class Builder {\n\n        private final BundleContext bundleContext;\n\n        private RegistryFactory registryFactory;\n\n        private ContextFactory contextFactory;\n\n        private final List<ServiceDependency<?, CamelContext>> dependencies;\n\n        private final List<BeforeStart> beforeStarts;\n\n        private final List<ContextLifecycleListener> lifecycleListeners;\n\n        private boolean disableJmx = true;\n\n        private int shutdownTimeout = 5;\n\n        public Builder() {\n            this(FrameworkUtil.getBundle(CamelRunner.class).getBundleContext());\n        }\n\n        public Builder(final BundleContext bundleContext) {\n            Objects.requireNonNull(bundleContext);\n\n            this.bundleContext = bundleContext;\n\n            this.registryFactory = createOsgiRegistry(bundleContext);\n            this.contextFactory = createOsgiFactory(bundleContext);\n\n            this.dependencies = new LinkedList<>();\n            this.beforeStarts = new LinkedList<>();\n            this.lifecycleListeners = new LinkedList<>();\n        }\n\n        public Builder(final Builder other) {\n            Objects.requireNonNull(other);\n\n            this.bundleContext = other.bundleContext;\n            this.registryFactory = other.registryFactory;\n            this.contextFactory = other.contextFactory;\n            this.dependencies = new LinkedList<>(other.dependencies);\n            this.beforeStarts = new LinkedList<>(other.beforeStarts);\n            this.lifecycleListeners = new LinkedList<>(other.lifecycleListeners);\n            this.disableJmx = other.disableJmx;\n            this.shutdownTimeout = other.shutdownTimeout;\n        }\n\n        /**\n         * Disable the use of JMX in the CamelContext\n         * <p>\n         * JMX is disabled by default.\n         * </p>\n         *\n         * @param disableJmx\n         *            whether JMX should be disabled or not\n         * @return the builder instance\n         */\n        public Builder disableJmx(final boolean disableJmx) {\n            this.disableJmx = disableJmx;\n            return this;\n        }\n\n        /**\n         * The shutdown timeout\n         * <p>\n         * This defaults to 5 seconds\n         * </p>\n         *\n         * @param shutdownTimeout\n         *            The shutdown timeout in seconds\n         * @return the builder instance\n         */\n        public Builder shutdownTimeout(final int shutdownTimeout) {\n            this.shutdownTimeout = shutdownTimeout;\n            return this;\n        }\n\n        public Builder osgiContext(final BundleContext bundleContext) {\n            Objects.requireNonNull(bundleContext);\n\n            return contextFactory(createOsgiFactory(bundleContext));\n        }\n\n        public Builder registryFactory(final RegistryFactory registryFactory) {\n            Objects.requireNonNull(registryFactory);\n\n            this.registryFactory = registryFactory;\n            return this;\n        }\n\n        public Builder contextFactory(final ContextFactory contextFactory) {\n            Objects.requireNonNull(contextFactory);\n\n            this.contextFactory = contextFactory;\n            return this;\n        }\n\n        public <T> Builder dependOn(final Filter filter, final ServiceConsumer<T, CamelContext> consumer) {\n            return dependOn(null, filter, consumer);\n        }\n\n        public <T> Builder dependOn(BundleContext bundleContext, final Filter filter,\n                final ServiceConsumer<T, CamelContext> consumer) {\n            Objects.requireNonNull(filter);\n            Objects.requireNonNull(consumer);\n\n            if (bundleContext == null) {\n                bundleContext = Builder.this.bundleContext;\n            }\n\n            this.dependencies.add(new DefaultServiceDependency<>(bundleContext, filter, consumer));\n\n            return this;\n        }\n\n        /**\n         * Depend on a specific {@link CloudService} instance\n         * <p>\n         * If a filter is specified then it will be combined with the filter for the object class of the\n         * {@link CloudService}.\n         * If the filter expression is omitted then only the object class filter will be used.\n         * </p>\n         *\n         * @param bundleContext\n         *            the bundle context to use for service lookup\n         * @param filter\n         *            the filter expression to use searching for the cloud service instance\n         * @param consumer\n         *            the consumer processing the service instance\n         * @return the builder instance\n         */\n        public Builder cloudService(BundleContext bundleContext, final String filter,\n                final ServiceConsumer<CloudService, CamelContext> consumer) {\n            final String baseFilter = String.format(\"(%s=%s)\", Constants.OBJECTCLASS, CloudService.class.getName());\n\n            try {\n                if (filter != null && !filter.trim().isEmpty()) {\n                    // combined filter\n                    final Filter f = FrameworkUtil.createFilter(String.format(\"(&%s%s)\", baseFilter, filter));\n                    return dependOn(bundleContext, f, consumer);\n                } else {\n                    // empty custom filter, so only filter for class name\n                    return dependOn(bundleContext, FrameworkUtil.createFilter(baseFilter), consumer);\n                }\n            } catch (InvalidSyntaxException e) {\n                throw new RuntimeException(\"Failed to parse filter\", e);\n            }\n        }\n\n        /**\n         * Depend on a specific {@link CloudService} instance\n         * <p>\n         * The cloud service will be injected into the camel context as component \"kura-cloud\".\n         * </p>\n         * <p>\n         * If a filter is specified then it will be combined with the filter for the object class of the\n         * {@link CloudService}.\n         * If the filter expression is omitted then only the object class filter will be used.\n         * </p>\n         *\n         * @param filter\n         *            optional filter expression\n         * @return the builder instance\n         */\n        public Builder cloudService(final String filter) {\n            return cloudService((BundleContext) null, filter, addAsCloudComponent(\"kura-cloud\"));\n        }\n\n        /**\n         * Depend on a specific {@link CloudService} instance by key and value\n         * <p>\n         * This is a convenience method for {@link #cloudService(String)}. It will effectively call\n         * this method with a filter of {@code \"(\" + attribute + \"=\" + value + \")\"}\n         * </p>\n         *\n         * @param attribute\n         *            the OSGi attribute to look for\n         * @param value\n         *            the value the OSGi must have\n         * @return the builder instance\n         */\n        public Builder cloudService(final String attribute, final String value) {\n            Objects.requireNonNull(attribute);\n            Objects.requireNonNull(value);\n\n            return cloudService(String.format(\"(%s=%s)\", attribute, value));\n        }\n\n        /**\n         * Require a Camel component to be registered with OSGi before starting\n         *\n         * @param componentName\n         *            the component name (e.g. \"timer\")\n         * @return the builder instance\n         */\n        public Builder requireComponent(final String componentName) {\n            try {\n                final String filterString = String.format(\"(&(%s=%s)(%s=%s))\", Constants.OBJECTCLASS,\n                        ComponentResolver.class.getName(), \"component\", componentName);\n                final Filter filter = FrameworkUtil.createFilter(filterString);\n                dependOn(filter, (context, service) -> {\n                });\n            } catch (InvalidSyntaxException e) {\n                throw new IllegalArgumentException(String.format(\"Illegal component name: '%s'\", componentName), e);\n            }\n\n            return this;\n        }\n\n        /**\n         * Require a Camel language to be registered with OSGi before starting\n         *\n         * @param languageName\n         *            the language name (e.g. \"javaScript\")\n         * @return the builder instance\n         */\n        public Builder requireLanguage(final String languageName) {\n            try {\n                final String filterString = String.format(\"(&(%s=%s)(%s=%s))\", Constants.OBJECTCLASS,\n                        LanguageResolver.class.getName(), \"language\", languageName);\n                final Filter filter = FrameworkUtil.createFilter(filterString);\n                dependOn(filter, (context, service) -> {\n                });\n            } catch (InvalidSyntaxException e) {\n                throw new IllegalArgumentException(String.format(\"Illegal languageName name: '%s'\", languageName), e);\n            }\n\n            return this;\n        }\n\n        public static ServiceConsumer<CloudService, CamelContext> addAsCloudComponent(final String componentName) {\n            return (context, service) -> context.addComponent(componentName, new KuraCloudComponent(context, service));\n        }\n\n        /**\n         * Add an operation which will be executed before the Camel context is started\n         *\n         * @param beforeStart\n         *            the action to start\n         * @return the builder instance\n         */\n        public Builder addBeforeStart(final BeforeStart beforeStart) {\n            Objects.requireNonNull(beforeStart);\n\n            this.beforeStarts.add(beforeStart);\n\n            return this;\n        }\n\n        /**\n         * Add a context lifecylce listener.\n         *\n         * @param listener\n         *            The listener to add\n         * @return the builder instance\n         */\n        public Builder addLifecycleListener(final ContextLifecycleListener listener) {\n            Objects.requireNonNull(listener);\n\n            this.lifecycleListeners.add(listener);\n\n            return this;\n        }\n\n        /**\n         * Build the actual CamelRunner instance based on the current configuration of the builder instance\n         * <p>\n         * Modifications which will be made to the builder after the {@link #build()} method was called will\n         * no affect the created CamelRunner instance. It is possible though to call the {@link #build()} method\n         * multiple times.\n         * </p>\n         *\n         * @return the new instance\n         */\n        public CamelRunner build() {\n            final List<BeforeStart> beforeStartsTemp = new ArrayList<>(this.beforeStarts);\n            final List<ServiceDependency<?, CamelContext>> dependenciesTemp = new ArrayList<>(this.dependencies);\n\n            if (this.disableJmx) {\n                beforeStartsTemp.add(CamelContext::disableJMX);\n            }\n            if (this.shutdownTimeout > 0) {\n                final int shutdownTimeoutTemp = this.shutdownTimeout;\n                beforeStartsTemp.add(camelContext -> {\n                    camelContext.getShutdownStrategy().setTimeUnit(TimeUnit.SECONDS);\n                    camelContext.getShutdownStrategy().setTimeout(shutdownTimeoutTemp);\n                });\n            }\n            return new CamelRunner(this.registryFactory, this.contextFactory, beforeStartsTemp, this.lifecycleListeners,\n                    dependenciesTemp);\n        }\n    }\n\n    private final RegistryFactory registryFactory;\n    private final ContextFactory contextFactory;\n    private final List<BeforeStart> beforeStarts;\n    private final List<ContextLifecycleListener> lifecycleListeners;\n    private final List<ServiceDependency<?, CamelContext>> dependencies;\n\n    private CamelContext context;\n    private RoutesProvider routes = EmptyRoutesProvider.INSTANCE;\n    private DependencyRunner<CamelContext> dependencyRunner;\n\n    private CamelRunner(final RegistryFactory registryFactory, final ContextFactory contextFactory,\n            final List<BeforeStart> beforeStarts, final List<ContextLifecycleListener> lifecycleListeners,\n            final List<ServiceDependency<?, CamelContext>> dependencies) {\n        this.registryFactory = registryFactory;\n        this.contextFactory = contextFactory;\n        this.beforeStarts = beforeStarts;\n        this.lifecycleListeners = lifecycleListeners;\n        this.dependencies = dependencies;\n    }\n\n    private Registry createRegistry() {\n        return this.registryFactory.createRegistry();\n    }\n\n    private CamelContext createContext(final Registry registry) {\n        return this.contextFactory.createContext(registry);\n    }\n\n    /**\n     * Start the camel runner instance\n     * <p>\n     * This may not start the camel context right away if there are unresolved dependencies\n     * </p>\n     */\n    public void start() {\n\n        stop();\n\n        logger.info(\"Starting...\");\n\n        this.dependencyRunner = new DependencyRunner<>(this.dependencies,\n                new DependencyRunner.Listener<CamelContext>() {\n\n                    @Override\n                    public void ready(final List<ServiceDependency.Handle<CamelContext>> dependencies) {\n                        try {\n                            startCamel(dependencies);\n                        } catch (Exception e) {\n                            logger.warn(\"Failed to start context\", e);\n                        }\n                    }\n\n                    @Override\n                    public void notReady() {\n                        try {\n                            stopCamel();\n                        } catch (Exception e) {\n                            logger.warn(\"Failed to stop context\", e);\n                        }\n                    }\n                });\n        this.dependencyRunner.start();\n    }\n\n    /**\n     * Stop the camel runner instance\n     */\n    public void stop() {\n\n        if (this.dependencyRunner != null) {\n            logger.info(\"Stopping...\");\n            this.dependencyRunner.stop();\n            this.dependencyRunner = null;\n        }\n    }\n\n    protected void startCamel(final List<ServiceDependency.Handle<CamelContext>> dependencies) throws Exception {\n\n        if (this.context != null) {\n            logger.warn(\"Camel already running\");\n            return;\n        }\n\n        final Registry registry = createRegistry();\n\n        final CamelContext camelContext = createContext(registry);\n        beforeStart(camelContext);\n\n        for (final ServiceDependency.Handle<CamelContext> dep : dependencies) {\n            dep.consume(camelContext);\n        }\n\n        this.context = camelContext;\n\n        this.routes.applyRoutes(this.context);\n        this.context.start();\n\n        fireLifecycle(this.context, ContextLifecycleListener::started);\n    }\n\n    protected void stopCamel() throws Exception {\n        if (this.context != null) {\n\n            fireLifecycle(this.context, ContextLifecycleListener::stopping);\n\n            this.context.stop();\n            this.context = null;\n\n        }\n    }\n\n    private void beforeStart(final CamelContext context) throws Exception {\n        logger.debug(\"Running before starts...\");\n\n        for (final BeforeStart beforeStart : this.beforeStarts) {\n            beforeStart.beforeStart(context);\n        }\n    }\n\n    private void fireLifecycle(final CamelContext context,\n            final ThrowingBiConsumer<ContextLifecycleListener, CamelContext, Exception> consumer) {\n\n        for (final ContextLifecycleListener listener : this.lifecycleListeners) {\n\n            try {\n                consumer.accept(listener, context);\n            } catch (Exception e) {\n                logger.warn(\"Failed to call listener\", e);\n            }\n\n        }\n\n    }\n\n    /**\n     * Remove a set of routes from the context\n     * <p>\n     * This is a helper method intended to be used by implementations of {@link RoutesProvider}.\n     * </p>\n     *\n     * @param context\n     *            the context to work on\n     * @param removedRouteIds\n     *            the ID to remove\n     */\n    public static void removeRoutes(final CamelContext context, final Set<String> removedRouteIds) {\n        Objects.requireNonNull(context);\n        Objects.requireNonNull(removedRouteIds);\n\n        for (final String id : removedRouteIds) {\n            try {\n                logger.debug(\"Stopping route: {}\", id);\n                context.stopRoute(id);\n                logger.debug(\"Removing route: {}\", id);\n                context.removeRoute(id);\n            } catch (Exception e) {\n                logger.warn(\"Failed to remove route: {}\", id, e);\n            }\n        }\n    }\n\n    /**\n     * Remove all routes from the context which are not in the new set\n     * <p>\n     * This is a helper method intended to be used by implementations of {@link RoutesProvider}.\n     * </p>\n     *\n     * @param context\n     *            the context to work on\n     * @param routes\n     *            the collection of new routes\n     */\n    public static void removeMissingRoutes(final CamelContext context, final Collection<RouteDefinition> routes) {\n        Objects.requireNonNull(context);\n        Objects.requireNonNull(routes);\n\n        // gather new IDs\n\n        final Set<String> newRouteIds = fromDefs(routes);\n\n        // eval removed\n\n        final Set<String> removedRouteIds = new HashSet<>(fromRoutes(context.getRoutes()));\n        removedRouteIds.removeAll(newRouteIds);\n\n        // remove from running context\n\n        removeRoutes(context, removedRouteIds);\n    }\n\n    /**\n     * Remove all routes of a context\n     *\n     * @param context\n     *            the context to work on\n     */\n    public static void removeAllRoutes(final CamelContext context) {\n        Objects.requireNonNull(context);\n\n        // remove all routes\n\n        removeRoutes(context, fromDefs(context.getRouteDefinitions()));\n    }\n\n    /**\n     * Clear all routes from the context\n     */\n    public void clearRoutes() {\n        setRoutes(EmptyRoutesProvider.INSTANCE);\n    }\n\n    /**\n     * Replace the current set of route with an new one\n     *\n     * @param routes\n     *            the new set of routes, may be {@code null}\n     */\n    public void setRoutes(final RoutesProvider routes) {\n\n        if (routes == null) {\n            clearRoutes();\n            return;\n        }\n\n        this.routes = routes;\n\n        final CamelContext camelContext = this.context;\n        if (camelContext != null) {\n            try {\n                this.routes.applyRoutes(camelContext);\n            } catch (final Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    /**\n     * Replace the current set of route with an new one\n     *\n     * @param xml\n     *            the new set of routes, may be {@code null}\n     */\n    public void setRoutes(final String xml) throws Exception {\n        logger.info(\"Setting routes...\");\n\n        if (xml == null || xml.trim().isEmpty()) {\n            clearRoutes();\n        } else {\n            setRoutes(new XmlRoutesProvider(xml));\n        }\n    }\n\n    /**\n     * Replace the current set of route with an new one\n     *\n     * @param routes\n     *            the new set of routes, may be {@code null}\n     */\n    public void setRoutes(final RoutesDefinition routes) throws Exception {\n        logger.info(\"Setting routes...\");\n\n        if (routes == null) {\n            clearRoutes();\n            return;\n        }\n\n        setRoutes(new SimpleRoutesProvider(routes));\n    }\n\n    /**\n     * Replace the current set of route with an new one\n     *\n     * @param routeBuilder\n     *            the new set of routes, may be {@code null}\n     */\n    public void setRoutes(final RouteBuilder routeBuilder) throws Exception {\n        logger.info(\"Setting routes...\");\n\n        if (routeBuilder == null) {\n            clearRoutes();\n            return;\n        }\n\n        setRoutes(new BuilderRoutesProvider(routeBuilder));\n    }\n\n    static Set<String> fromRoutes(final Collection<Route> routes) {\n        final Set<String> result = new HashSet<>(routes.size());\n\n        for (final Route route : routes) {\n            result.add(route.getId());\n        }\n\n        return result;\n    }\n\n    private static <T extends OptionalIdentifiedDefinition<T>> Set<String> fromDefs(final Collection<T> defs) {\n        Objects.requireNonNull(defs);\n\n        final Set<String> result = new HashSet<>(defs.size());\n\n        for (final T def : defs) {\n            final String id = def.getId();\n            if (id != null) {\n                result.add(def.getId());\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * Get the camel context\n     * <p>\n     * <strong>Note: </strong> This method may return {@code null} even after the {@link #start()} method was called\n     * if there are unresolved dependencies for the runner.\n     * </p>\n     *\n     * @return the camel context, if the camel context is currently not running then {@code null} is being returned\n     */\n    public CamelContext getCamelContext() {\n        return this.context;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ContextFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.spi.Registry;\n\npublic interface ContextFactory {\n\n    public CamelContext createContext(Registry registry);\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ContextLifecycleListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport org.apache.camel.CamelContext;\n\npublic interface ContextLifecycleListener {\n\n    public void started(CamelContext camelContext) throws Exception;\n\n    public void stopping(CamelContext camelContext) throws Exception;\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/DefaultServiceDependency.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport java.util.Objects;\nimport java.util.TreeMap;\n\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\n\npublic class DefaultServiceDependency<T, C> implements ServiceDependency<T, C> {\n\n    private final class HandleImpl implements Handle<C> {\n\n        private final BundleContext bundleContext;\n        private final ServiceConsumer<T, C> consumer;\n\n        private final TreeMap<ServiceReference<T>, T> services = new TreeMap<>();\n\n        private final ServiceTracker<T, T> tracker;\n\n        private Runnable runnable;\n\n        private final ServiceTrackerCustomizer<T, T> customizer = new ServiceTrackerCustomizer<T, T>() {\n\n            @Override\n            public T addingService(ServiceReference<T> reference) {\n                return adding(reference);\n            }\n\n            @Override\n            public void modifiedService(ServiceReference<T> reference, T service) {\n            }\n\n            @Override\n            public void removedService(ServiceReference<T> reference, T service) {\n                removed(reference, service);\n            }\n        };\n\n        public HandleImpl(BundleContext bundleContext, Filter filter, Runnable runnable,\n                final ServiceConsumer<T, C> consumer) {\n            this.bundleContext = bundleContext;\n            this.consumer = consumer;\n            this.runnable = runnable;\n\n            this.tracker = new ServiceTracker<>(bundleContext, filter, HandleImpl.this.customizer);\n            this.tracker.open();\n        }\n\n        protected T adding(final ServiceReference<T> reference) {\n            final T service = this.bundleContext.getService(reference);\n            this.services.put(reference, service);\n            triggerUpdate();\n            return service;\n        }\n\n        protected void removed(final ServiceReference<T> reference, final T service) {\n            this.bundleContext.ungetService(reference);\n            this.services.remove(reference);\n            triggerUpdate();\n        }\n\n        private void triggerUpdate() {\n            final Runnable runnableTemp = this.runnable;\n            if (runnableTemp != null) {\n                runnableTemp.run();\n            }\n        }\n\n        @Override\n        public void stop() {\n            this.runnable = null;\n            this.tracker.close();\n        }\n\n        @Override\n        public boolean isSatisfied() {\n            return !this.services.isEmpty();\n        }\n\n        @Override\n        public void consume(C context) {\n            this.consumer.consume(context, this.services.firstEntry().getValue());\n        }\n\n        @Override\n        public String toString() {\n            return String.format(\"[Service - filter: %s]\", DefaultServiceDependency.this.filter);\n        }\n\n    }\n\n    private final BundleContext bundleContext;\n\n    private final Filter filter;\n\n    private final ServiceConsumer<T, C> consumer;\n\n    public DefaultServiceDependency(final BundleContext bundleContext, final Filter filter,\n            final ServiceConsumer<T, C> consumer) {\n        Objects.requireNonNull(bundleContext);\n        Objects.requireNonNull(filter);\n\n        this.bundleContext = bundleContext;\n        this.filter = filter;\n        this.consumer = consumer;\n    }\n\n    @Override\n    public Handle<C> start(final Runnable runnable) {\n        Objects.requireNonNull(runnable);\n\n        return new HandleImpl(this.bundleContext, this.filter, runnable, this.consumer);\n\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/DependencyRunner.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport org.eclipse.kura.camel.runner.ServiceDependency.Handle;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class DependencyRunner<C> {\n\n    private static final Logger logger = LoggerFactory.getLogger(DependencyRunner.class);\n\n    public interface Listener<C> {\n\n        public void ready(List<Handle<C>> dependencies);\n\n        public void notReady();\n    }\n\n    private final ArrayList<ServiceDependency<?, C>> dependencies;\n    private final DependencyRunner.Listener<C> listener;\n\n    private List<Handle<C>> dependencyHandles;\n\n    private boolean lastState = false;\n\n    private final Runnable update = new Runnable() {\n\n        @Override\n        public void run() {\n            DependencyRunner.this.update();\n        }\n    };\n    private boolean working;\n\n    public DependencyRunner(final List<ServiceDependency<?, C>> dependencies,\n            final DependencyRunner.Listener<C> listener) {\n        Objects.requireNonNull(dependencies);\n        Objects.requireNonNull(listener);\n\n        this.dependencies = new ArrayList<>(dependencies);\n        this.listener = listener;\n    }\n\n    public void start() {\n        this.working = true;\n\n        try {\n            this.dependencyHandles = new LinkedList<>();\n            for (final ServiceDependency<?, C> dep : this.dependencies) {\n                this.dependencyHandles.add(dep.start(this.update));\n            }\n        } finally {\n            this.working = false;\n        }\n\n        // trigger first time\n\n        if (isReady()) {\n            triggerUpdate(true);\n        }\n    }\n\n    public void stop() {\n        this.working = true;\n        try {\n            for (final Handle<C> dep : this.dependencyHandles) {\n                dep.stop();\n            }\n        } finally {\n            this.working = false;\n        }\n\n        triggerUpdate(false);\n    }\n\n    private void update() {\n        logger.debug(\"update\");\n\n        if (this.working) {\n            logger.debug(\"update - start/stop in progress\");\n            return;\n        }\n\n        boolean state = isReady();\n        triggerUpdate(state);\n    }\n\n    private void triggerUpdate(final boolean state) {\n        logger.debug(\"triggerUpdate - state: {}, lastState: {}\", state, this.lastState);\n\n        if (this.lastState == state) {\n            return;\n        }\n\n        this.lastState = state;\n\n        if (state) {\n            this.listener.ready(Collections.unmodifiableList(this.dependencyHandles));\n        } else {\n            this.listener.notReady();\n        }\n    }\n\n    private boolean isReady() {\n        for (final Handle<C> dep : this.dependencyHandles) {\n            boolean satisfied = dep.isSatisfied();\n            logger.debug(\"Dependency - {}, satisied: {}\", dep, satisfied);\n            if (!satisfied) {\n                return false;\n            }\n        }\n        return true;\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/EmptyRoutesProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport org.apache.camel.CamelContext;\n\npublic class EmptyRoutesProvider implements RoutesProvider {\n\n    public static final EmptyRoutesProvider INSTANCE = new EmptyRoutesProvider();\n\n    private EmptyRoutesProvider() {\n    }\n\n    @Override\n    public void applyRoutes(final CamelContext camelContext) throws Exception {\n        CamelRunner.removeRoutes(camelContext, CamelRunner.fromRoutes(camelContext.getRoutes()));\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/RegistryFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport org.apache.camel.spi.Registry;\n\npublic interface RegistryFactory {\n\n    public Registry createRegistry();\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/RoutesProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport org.apache.camel.CamelContext;\n\n@FunctionalInterface\npublic interface RoutesProvider {\n\n    /**\n     * Apply the desired state of camel routes to the context\n     * <p>\n     * <strong>Note: </strong> This method may need to stop and remove\n     * routes which are no longer used\n     * </p>\n     *\n     * @param camelContext\n     *            the context the routes should by applied to\n     * @throws Exception\n     *             if anything goes wrong\n     */\n    public void applyRoutes(CamelContext camelContext) throws Exception;\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ScriptRunner.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport java.util.Objects;\nimport java.util.concurrent.Callable;\n\nimport javax.script.Bindings;\nimport javax.script.ScriptContext;\nimport javax.script.ScriptEngine;\nimport javax.script.ScriptEngineManager;\nimport javax.script.ScriptException;\n\n/**\n * A runner for scripts which takes care of class loader issues in OSGi\n * <br>\n * This class helps running java.script script inside an OSGi container.\n * There are some oddities of Rhino and Nashorn this runner takes care of\n * so that at least the standard \"JavaScript\" language works inside of OSGi.\n * <br>\n * In order to execute a script use:\n * <pre>\n * ScriptRunner runner = ScriptRunner.create(ServiceClass.class.getClassLoader(), \"JavaScript\", \"callFooBar();\" );\n * runner.run();\n * </pre>\n */\npublic abstract class ScriptRunner {\n\n    private static class EvalScriptRunner extends ScriptRunner {\n\n        private final ClassLoader classLoader;\n        private final ScriptEngine engine;\n        private final String script;\n\n        public EvalScriptRunner(final ClassLoader classLoader, final ScriptEngine engine, final String script) {\n            this.classLoader = classLoader;\n            this.engine = engine;\n            this.script = script;\n        }\n\n        @Override\n        public Object run() throws ScriptException {\n            return runWithClassLoader(this.classLoader, new Callable<Object>() {\n\n                @Override\n                public Object call() throws Exception {\n                    return EvalScriptRunner.this.engine.eval(EvalScriptRunner.this.script);\n                }\n            });\n        }\n\n        @Override\n        public Object run(final Bindings bindings) throws ScriptException {\n            return runWithClassLoader(this.classLoader, new Callable<Object>() {\n\n                @Override\n                public Object call() throws Exception {\n                    return EvalScriptRunner.this.engine.eval(EvalScriptRunner.this.script, bindings);\n                }\n            });\n        }\n\n        @Override\n        public Object run(final ScriptContext context) throws ScriptException {\n            return runWithClassLoader(this.classLoader, new Callable<Object>() {\n\n                @Override\n                public Object call() throws Exception {\n                    return EvalScriptRunner.this.engine.eval(EvalScriptRunner.this.script, context);\n                }\n            });\n        }\n    }\n\n    private ScriptRunner() {\n    }\n\n    public abstract Object run() throws ScriptException;\n\n    public abstract Object run(Bindings bindings) throws ScriptException;\n\n    public abstract Object run(ScriptContext context) throws ScriptException;\n\n    public static ScriptRunner create(final ClassLoader classLoader, final String scriptEngineName, final String script)\n            throws ScriptException {\n\n        final ScriptEngine engine = createEngine(classLoader, scriptEngineName);\n        return new EvalScriptRunner(classLoader, engine, script);\n\n    }\n\n    private static ScriptEngineManager createManager(final ClassLoader classLoader) throws ScriptException {\n        return runWithClassLoader(classLoader, new Callable<ScriptEngineManager>() {\n\n            @Override\n            public ScriptEngineManager call() throws Exception {\n                // passing null here since this will trigger\n                // the script engine lookup to use java basic\n                // support for JavaScript\n                return new ScriptEngineManager(null);\n            }\n        });\n    }\n\n    private static ScriptEngine createEngine(final ClassLoader classLoader, final ScriptEngineManager manager,\n            final String engineName) throws ScriptException {\n        Objects.requireNonNull(manager);\n        Objects.requireNonNull(engineName);\n\n        return runWithClassLoader(classLoader, new Callable<ScriptEngine>() {\n\n            @Override\n            public ScriptEngine call() throws Exception {\n                return manager.getEngineByName(engineName);\n            }\n        });\n    }\n\n    private static ScriptEngine createEngine(final ClassLoader classLoader, final String engineName)\n            throws ScriptException {\n        return createEngine(classLoader, createManager(classLoader), engineName);\n    }\n\n    /**\n     * Run a Callable while swapping the context class loader\n     *\n     * @param classLoader\n     *            the class loader to set while calling the code\n     * @param code\n     *            the code to call\n     * @return the return value of the code\n     * @throws ScriptException\n     *             if anything goes wrong\n     */\n    public static <T> T runWithClassLoader(final ClassLoader classLoader, final Callable<T> code)\n            throws ScriptException {\n        if (classLoader == null) {\n            try {\n                return code.call();\n            } catch (ScriptException e) {\n                throw e;\n            } catch (Exception e) {\n                throw new ScriptException(e);\n            }\n        }\n\n        final ClassLoader ccl = Thread.currentThread().getContextClassLoader();\n        Thread.currentThread().setContextClassLoader(classLoader);\n        try {\n            return code.call();\n        } catch (ScriptException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new ScriptException(e);\n        } finally {\n            Thread.currentThread().setContextClassLoader(ccl);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ServiceConsumer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\n@FunctionalInterface\npublic interface ServiceConsumer<T, C> {\n\n    public void consume(C context, T service);\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ServiceDependency.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\npublic interface ServiceDependency<T, C> {\n\n    public interface Handle<C> {\n\n        public void stop();\n\n        public boolean isSatisfied();\n\n        public void consume(C context);\n    }\n\n    public Handle<C> start(Runnable runnable);\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/SimpleRoutesProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport java.util.Objects;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.model.RoutesDefinition;\n\npublic class SimpleRoutesProvider extends AbstractRoutesProvider {\n\n    private final RoutesDefinition routes;\n\n    public SimpleRoutesProvider(RoutesDefinition routes) {\n        Objects.requireNonNull(routes);\n        this.routes = routes;\n    }\n\n    @Override\n    protected RoutesDefinition getRoutes(final CamelContext camelContext) throws Exception {\n        return this.routes;\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/XmlRoutesProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.InputStream;\nimport java.io.Reader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Objects;\nimport java.util.function.Supplier;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.model.RoutesDefinition;\nimport org.apache.commons.io.input.ReaderInputStream;\n\npublic class XmlRoutesProvider extends AbstractRoutesProvider {\n\n    private final Supplier<InputStream> inputStreamProvider;\n\n    public XmlRoutesProvider(final String xml) {\n        Objects.requireNonNull(xml);\n        this.inputStreamProvider = () -> new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));\n    }\n\n    private XmlRoutesProvider(final Supplier<InputStream> inputStreamProvider) {\n        Objects.requireNonNull(inputStreamProvider);\n        this.inputStreamProvider = inputStreamProvider;\n    }\n\n    @Override\n    protected RoutesDefinition getRoutes(final CamelContext camelContext) throws Exception {\n        try (final InputStream in = this.inputStreamProvider.get()) {\n            return camelContext.loadRoutesDefinition(in);\n        }\n    }\n\n    public static XmlRoutesProvider fromString(final String xml) {\n        return new XmlRoutesProvider(xml);\n    }\n\n    public static XmlRoutesProvider fromReader(final Supplier<Reader> reader) {\n        Objects.requireNonNull(reader);\n        return new XmlRoutesProvider(() -> new ReaderInputStream(reader.get(), StandardCharsets.UTF_8));\n    }\n\n    public static XmlRoutesProvider fromInputStream(final Supplier<InputStream> inputStream) {\n        return new XmlRoutesProvider(inputStream);\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n/**\n * Functionality for running a Camel context\n * <p>\n * The main class to create, run and update a {@link org.apache.camel.CamelContext}\n * is the {@link org.eclipse.kura.camel.runner.CamelRunner} which\n * is being created using a {@link org.eclipse.kura.camel.runner.CamelRunner.Builder}\n * </p>\n */\npackage org.eclipse.kura.camel.runner;\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/type/TypeConverter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.type;\n\nimport static org.eclipse.kura.type.TypedValues.newTypedValue;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.camel.Converter;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.type.TypedValue;\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.eclipse.kura.wire.WireRecord;\n\n@Converter\npublic final class TypeConverter {\n\n    private static final WireRecord[] EMPTY_RECORDS = new WireRecord[0];\n\n    private TypeConverter() {\n    }\n\n    @Converter\n    public static KuraPayload fromMap(final Map<String, ?> data) {\n        if (data == null) {\n            return null;\n        }\n\n        final KuraPayload result = new KuraPayload();\n        result.setTimestamp(new Date());\n\n        for (final Map.Entry<String, ?> entry : data.entrySet()) {\n            result.addMetric(entry.getKey(), entry.getValue());\n        }\n\n        return result;\n    }\n\n    @Converter\n    public static WireRecord[] recordsFromEnvelope(final WireEnvelope envelope) {\n        return recordsFromList(envelope.getRecords());\n    }\n\n    @Converter\n    public static WireRecord[] recordsFromRecord(final WireRecord record) {\n        return new WireRecord[] { record };\n    }\n\n    @Converter\n    public static WireRecord[] recordsFromList(final List<WireRecord> records) {\n        return records.toArray(new WireRecord[records.size()]);\n    }\n\n    @Converter\n    public static WireRecord[] recordsFromMap(final Map<?, ?> map) {\n\n        if (map.isEmpty()) {\n            return EMPTY_RECORDS;\n        }\n\n        final Map<String, TypedValue<?>> result = new HashMap<>();\n\n        for (final Map.Entry<?, ?> entry : map.entrySet()) {\n            final Object keyValue = entry.getKey();\n            if (keyValue == null) {\n                continue;\n            }\n\n            if (entry.getValue() instanceof TypedValue<?>) {\n                result.put(keyValue.toString(), (TypedValue<?>) entry.getValue());\n            } else {\n                result.put(keyValue.toString(), newTypedValue(entry.getValue()));\n            }\n        }\n\n        return recordsFromRecord(new WireRecord(result));\n    }\n\n    @Converter\n    public static Map<?, ?> mapFromRecord(final WireRecord record) {\n\n        final Map<Object, Object> result = new HashMap<>(record.getProperties().size());\n\n        for (final Map.Entry<String, TypedValue<?>> entry : record.getProperties().entrySet()) {\n            result.put(entry.getKey(), entry.getValue().getValue());\n        }\n\n        return result;\n\n    }\n\n    @Converter\n    public static Map<?, ?> mapFromRecords(final WireRecord[] records) {\n\n        final Map<Object, Object> result = new HashMap<>();\n\n        for (final WireRecord record : records) {\n            for (final Map.Entry<String, TypedValue<?>> entry : record.getProperties().entrySet()) {\n                result.put(entry.getKey(), entry.getValue().getValue());\n            }\n        }\n\n        return result;\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/type/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n/**\n * Type converters for Camel\n */\npackage org.eclipse.kura.camel.type;\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/utils/CamelContexts.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.utils;\n\nimport static org.eclipse.kura.camel.runner.ScriptRunner.create;\n\nimport javax.script.ScriptException;\nimport javax.script.SimpleBindings;\n\nimport org.apache.camel.CamelContext;\nimport org.eclipse.kura.camel.runner.ScriptRunner;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic final class CamelContexts {\n\n    private static final Logger logger = LoggerFactory.getLogger(CamelContexts.class);\n\n    private CamelContexts() {\n    }\n\n    /**\n     * Run an init script on a camel context\n     * \n     * @param context\n     *            the context to work on\n     * @param initCode\n     *            the init code, may be {@code null} or empty\n     * @param classLoader\n     *            the classloader to use for the script engine, may be {@code null}\n     * @throws ScriptException\n     *             if calling the script fails\n     */\n    public static void scriptInitCamelContext(final CamelContext context, final String initCode,\n            final ClassLoader classLoader) throws ScriptException {\n\n        // pre-flight check\n\n        if (initCode == null || initCode.isEmpty()) {\n            return;\n        }\n\n        try {\n\n            // setup runner\n\n            final ScriptRunner runner = create(classLoader, \"JavaScript\", initCode);\n\n            // setup arguments\n\n            final SimpleBindings bindings = new SimpleBindings();\n            bindings.put(\"camelContext\", context);\n\n            // perform call\n\n            runner.run(bindings);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to run init code\", e);\n            throw e;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/utils/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n/**\n * Camel utilities\n */\npackage org.eclipse.kura.camel.utils;\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Camel Cloud Factory\nBundle-SymbolicName: org.eclipse.kura.camel.cloud.factory;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: javax.script,\n org.apache.camel;version=\"[2.17.0,3.0.0)\",\n org.apache.camel.core.osgi;version=\"[2.17.0,3.0.0)\",\n org.apache.camel.impl;version=\"[2.17.0,3.0.0)\",\n org.apache.camel.model;version=\"[2.17.0,3.0.0)\",\n org.apache.camel.support;version=\"[2.17.0,3.0.0)\",\n org.eclipse.kura;version=\"[1.2,2.0)\",\n org.eclipse.kura.camel.bean;version=\"[1.1,2.0)\",\n org.eclipse.kura.camel.camelcloud;version=\"[1.1,2.0)\",\n org.eclipse.kura.camel.cloud;version=\"[1.1,2.0)\",\n org.eclipse.kura.camel.component;version=\"[1.1,2.0)\",\n org.eclipse.kura.camel.runner;version=\"[1.1,2.0)\",\n org.eclipse.kura.camel.utils;version=\"[1.1,2.0)\",\n org.eclipse.kura.cloud;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloud.factory;version=\"[1.1,1.2)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.configuration;version=\"[2.0,3.0)\",\n org.eclipse.kura.core.configuration.metatype;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.7.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.7.0\"\nService-Component: OSGI-INF/factory.xml,\n OSGI-INF/serviceFactory.xml\nDynamicImport-Package: *\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/OSGI-INF/factory.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" immediate=\"true\" modified=\"modified\" name=\"org.eclipse.kura.camel.cloud.factory.CamelFactory\">\n   <implementation class=\"org.eclipse.kura.camel.cloud.factory.internal.CamelFactory\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/OSGI-INF/metatype/org.eclipse.kura.camel.cloud.factory.CamelFactory.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2016, 2020 Red Hat Inc and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Red Hat Inc\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.camel.cloud.factory.CamelFactory\"\n         name=\"Camel Cloud Client\" \n         description=\"Camel Cloud Client factory\">\n        \n         <AD id=\"xml\"\n            name=\"Router XML\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"true\"\n            description=\"The camel XML router configuration|TextArea\"/>\n            \n        <AD id=\"initCode\"\n            name=\"JavaScript init code\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"false\"\n            description=\"JavaScript code which is called when the router is initialized first. The camel context is avaiable in the variable 'camelContext'.|TextArea\"/>\n            \n        <AD id=\"enableJmx\"\n            name=\"Enable Camel JMX support\"\n            type=\"Boolean\"\n            cardinality=\"1\"\n            required=\"true\"\n            default=\"true\"\n            description=\"This setting controls if JMX support for the Camel context will be activated or not.\"/>\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.camel.cloud.factory.CamelFactory\" factoryPid=\"org.eclipse.kura.camel.cloud.factory.CamelFactory\">\n        <Object ocdref=\"org.eclipse.kura.camel.cloud.factory.CamelFactory\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/OSGI-INF/serviceFactory.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" configuration-policy=\"optional\" immediate=\"true\" name=\"org.eclipse.kura.camel.cloud.factory.CamelCloudServiceFactory\">\n   <implementation class=\"org.eclipse.kura.camel.cloud.factory.internal.CamelCloudServiceFactory\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloud.factory.CloudServiceFactory\"/>\n   </service>\n   <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.camel.cloud.factory.CamelFactory\"/>\n   <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.camel.cloud.factory.CamelFactory(\\-[a-zA-Z0-9]+)?$\"/>   \n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.camel.cloud.factory.CamelManager\"/>\n   <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/build.properties",
    "content": "output.. = target/classes\nbin.includes = META-INF/,\\\n               .,\\\n               about.html,\\\n               OSGI-INF/\nsource.. = src/\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- \n  Copyright (c) 2016, 2024 Red Hat Inc and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Red Hat Inc\n \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.camel.cloud.factory</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.camel.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/src/org/eclipse/kura/camel/cloud/factory/internal/CamelCloudServiceFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud.factory.internal;\n\nimport static org.eclipse.kura.camel.cloud.factory.internal.CamelFactory.FACTORY_ID;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.camel.component.Configuration;\nimport org.eclipse.kura.cloud.factory.CloudServiceFactory;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * An implementation of {@link CloudServiceFactory} based on Apache Camel\n */\npublic class CamelCloudServiceFactory implements CloudServiceFactory {\n\n    private static final Logger logger = LoggerFactory.getLogger(CamelCloudServiceFactory.class);\n\n    public static final String PID = \"org.eclipse.kura.camel.cloud.factory.CamelCloudServiceFactory\";\n\n    private ConfigurationService configurationService;\n\n    public void setConfigurationService(final ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    /**\n     * Add a new CamelFactory\n     *\n     * @param userPid\n     *            the PID as entered by the user\n     * @param properties\n     *            the provided configuration properties\n     * @throws KuraException\n     *             if anything goes wrong\n     */\n    protected void add(final String pid, final Map<String, Object> properties) throws KuraException {\n        logger.info(\"Add: {}\", pid);\n\n        final Map<String, Object> props = new HashMap<>();\n\n        String xml = Configuration.asString(properties, \"xml\");\n        if (xml == null || xml.trim().isEmpty()) {\n            xml = \"<routes xmlns=\\\"http://camel.apache.org/schema/spring\\\"></routes>\";\n        }\n\n        props.put(\"xml\", xml);\n\n        final Integer serviceRanking = Configuration.asInteger(properties, \"serviceRanking\");\n        if (serviceRanking != null) {\n            props.put(\"serviceRanking\", serviceRanking);\n        }\n\n        props.put(\"cloud.service.pid\", pid);\n\n        this.configurationService.createFactoryConfiguration(FACTORY_ID, fromUserPid(pid), props, true);\n    }\n\n    private static String fromUserPid(final String pid) {\n        Objects.requireNonNull(pid);\n        return pid + \"-CloudFactory\";\n    }\n\n    private static String fromInternalPid(final String pid) {\n        Objects.requireNonNull(pid);\n        return pid.replaceAll(\"-CloudFactory$\", \"\");\n    }\n\n    /**\n     * Enumerate all registered CamelFactory instances\n     *\n     * @return a PID (<code>kura.service.pid</code>) set of all registered CamelFactory instances\n     */\n    public static Set<String> lookupIds() {\n        final Set<String> ids = new TreeSet<>();\n        try {\n\n            final Collection<ServiceReference<CamelFactory>> refs = FrameworkUtil\n                    .getBundle(CamelCloudServiceFactory.class).getBundleContext()\n                    .getServiceReferences(CamelFactory.class, null);\n            if (refs != null) {\n                for (final ServiceReference<CamelFactory> ref : refs) {\n                    addService(ref, ids);\n                }\n            }\n        } catch (final InvalidSyntaxException e) {\n        }\n        return ids;\n    }\n\n    private static void addService(final ServiceReference<CamelFactory> ref, final Set<String> ids) {\n        final Object kpid = ref.getProperty(\"kura.service.pid\");\n        if (kpid instanceof String) {\n            ids.add((String) kpid);\n        }\n    }\n\n    /**\n     * Provide a common way to delete camel factory configurations\n     * <p>\n     * Right now this is a rather slim implementation used by CamelFactory and the CamelManager\n     * </p>\n     *\n     * @param configurationService\n     *            the configuration service to use\n     * @param pid\n     *            the PID to delete\n     */\n    static void delete(final ConfigurationService configurationService, final String pid) {\n        try {\n            configurationService.deleteFactoryConfiguration(pid, true);\n        } catch (final KuraException e) {\n            logger.warn(\"Failed to delete: {}\", pid, e);\n        }\n    }\n\n    @Override\n    public void createConfiguration(final String pid) throws KuraException {\n        add(pid, Collections.<String, Object>emptyMap());\n    }\n\n    @Override\n    public void deleteConfiguration(final String pid) throws KuraException {\n        delete(this.configurationService, fromUserPid(pid));\n    }\n\n    @Override\n    public String getFactoryPid() {\n        return FACTORY_ID;\n    }\n\n    @Override\n    public List<String> getStackComponentsPids(final String pid) throws KuraException {\n        return Collections.singletonList(fromUserPid(pid));\n    }\n\n    @Override\n    public Set<String> getManagedCloudServicePids() throws KuraException {\n        final Set<String> result = new HashSet<>();\n\n        for (final ComponentConfiguration cc : this.configurationService.getComponentConfigurations()) {\n            if (cc.getDefinition() != null && FACTORY_ID.equals(cc.getDefinition().getId())) {\n                result.add(fromInternalPid(cc.getPid()));\n            }\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/src/org/eclipse/kura/camel/cloud/factory/internal/CamelFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud.factory.internal;\n\nimport static org.eclipse.kura.camel.component.Configuration.asBoolean;\nimport static org.eclipse.kura.camel.component.Configuration.asString;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.osgi.framework.FrameworkUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A Kura component which takes care of creating a {@link org.eclipse.kura.cloud.CloudService} based in Apache Camel\n * <p>\n * This component does not directly register as {@link org.eclipse.kura.cloud.CloudService}, but can be managed\n * through the Kura configuration system and will forward this configuration to the\n * {@link XmlCamelCloudService} which will take care of the lifecycle of the Camel context.\n * </p>\n */\npublic class CamelFactory implements ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(CamelFactory.class);\n\n    public static final String FACTORY_ID = \"org.eclipse.kura.camel.cloud.factory.CamelFactory\";\n\n    private XmlCamelCloudService service;\n\n    private ServiceConfiguration configuration;\n\n    public void activate(final Map<String, Object> properties) throws Exception {\n        setFromProperties(properties);\n    }\n\n    public void modified(final Map<String, Object> properties) throws Exception {\n        setFromProperties(properties);\n    }\n\n    private void setFromProperties(final Map<String, Object> properties) throws Exception {\n        final String pid = asString(properties, \"cloud.service.pid\");\n\n        final ServiceConfiguration serviceConfiguration = new ServiceConfiguration();\n        serviceConfiguration.setXml(asString(properties, \"xml\"));\n        serviceConfiguration.setInitCode(asString(properties, \"initCode\"));\n        serviceConfiguration.setEnableJmx(asBoolean(properties, \"enableJmx\", true));\n\n        createService(pid, serviceConfiguration);\n    }\n\n    public void deactivate() {\n        if (this.service != null) {\n            try {\n                this.service.stop();\n            } catch (Exception e) {\n                logger.warn(\"Failed to stop\", e);\n            }\n            this.service = null;\n        }\n    }\n\n    private void createService(final String pid, final ServiceConfiguration configuration) throws Exception {\n        if (pid == null) {\n            return;\n        }\n\n        if (this.configuration == configuration) {\n            // null to null?\n            return;\n        }\n        if (this.configuration != null && this.configuration.equals(configuration)) {\n            // no change\n            return;\n        }\n\n        // stop old service\n\n        if (this.service != null) {\n            this.service.stop();\n            this.service = null;\n        }\n\n        // start new service\n        if (configuration.isValid()) {\n            this.service = new XmlCamelCloudService(FrameworkUtil.getBundle(CamelFactory.class).getBundleContext(), pid,\n                    configuration);\n            this.service.start();\n        }\n\n        this.configuration = configuration;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/src/org/eclipse/kura/camel/cloud/factory/internal/ServiceConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud.factory.internal;\n\n/**\n * The configuration of a Camel based {@link org.eclipse.kura.cloud.CloudService} instance\n */\npublic class ServiceConfiguration {\n\n    private String xml;\n    private String initCode;\n    private boolean enableJmx;\n\n    /**\n     * Set the router XML\n     *\n     * @param xml\n     *            must not be {@code null}\n     */\n    public void setXml(String xml) {\n        this.xml = xml;\n    }\n\n    public String getXml() {\n        return this.xml;\n    }\n\n    public void setInitCode(String initCode) {\n        this.initCode = initCode;\n    }\n\n    public String getInitCode() {\n        return this.initCode;\n    }\n\n    public void setEnableJmx(boolean enableJmx) {\n        this.enableJmx = enableJmx;\n    }\n\n    public boolean isEnableJmx() {\n        return enableJmx;\n    }\n\n    public boolean isValid() {\n        if (this.xml == null || this.xml.trim().isEmpty()) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.enableJmx ? 1231 : 1237);\n        result = prime * result + (this.initCode == null ? 0 : this.initCode.hashCode());\n        result = prime * result + (this.xml == null ? 0 : this.xml.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        ServiceConfiguration other = (ServiceConfiguration) obj;\n        if (this.enableJmx != other.enableJmx) {\n            return false;\n        }\n        if (this.initCode == null) {\n            if (other.initCode != null) {\n                return false;\n            }\n        } else if (!this.initCode.equals(other.initCode)) {\n            return false;\n        }\n        if (this.xml == null) {\n            if (other.xml != null) {\n                return false;\n            }\n        } else if (!this.xml.equals(other.xml)) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.cloud.factory/src/org/eclipse/kura/camel/cloud/factory/internal/XmlCamelCloudService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.cloud.factory.internal;\n\nimport static org.apache.camel.ServiceStatus.Started;\nimport static org.eclipse.kura.camel.cloud.factory.internal.CamelCloudServiceFactory.PID;\nimport static org.eclipse.kura.camel.cloud.factory.internal.CamelFactory.FACTORY_ID;\nimport static org.eclipse.kura.camel.utils.CamelContexts.scriptInitCamelContext;\nimport static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID;\nimport static org.osgi.framework.Constants.SERVICE_PID;\n\nimport java.io.ByteArrayInputStream;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\n\nimport javax.script.ScriptException;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.ServiceStatus;\nimport org.apache.camel.core.osgi.OsgiDefaultCamelContext;\nimport org.apache.camel.core.osgi.OsgiServiceRegistry;\nimport org.apache.camel.impl.CompositeRegistry;\nimport org.apache.camel.impl.SimpleRegistry;\nimport org.apache.camel.model.RoutesDefinition;\nimport org.eclipse.kura.camel.bean.PayloadFactory;\nimport org.eclipse.kura.camel.camelcloud.DefaultCamelCloudService;\nimport org.eclipse.kura.camel.cloud.KuraCloudComponent;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceRegistration;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * An service managing a single Camel context as {@link CloudService}\n * <p>\n * This service component does manage the lifecycle of a single {@link DefaultCamelCloudService}\n * instance. It will instantiate the Camel context and register the {@link CloudService} instance\n * with OSGi.\n * </p>\n */\npublic class XmlCamelCloudService {\n\n    private static final Logger logger = LoggerFactory.getLogger(XmlCamelCloudService.class);\n\n    private final BundleContext context;\n\n    private final String pid;\n\n    private final ServiceConfiguration configuration;\n\n    private DefaultCamelCloudService service;\n\n    private OsgiDefaultCamelContext router;\n\n    private ServiceRegistration<CloudService> handle;\n\n    public XmlCamelCloudService(final BundleContext context, final String pid,\n            final ServiceConfiguration configuration) {\n        this.context = context;\n        this.pid = pid;\n        this.configuration = configuration;\n    }\n\n    public void start() throws Exception {\n\n        // new registry\n\n        final SimpleRegistry simpleRegistry = new SimpleRegistry();\n        simpleRegistry.put(\"payloadFactory\", new PayloadFactory());\n\n        final CompositeRegistry registry = new CompositeRegistry();\n        registry.addRegistry(new OsgiServiceRegistry(this.context));\n        registry.addRegistry(simpleRegistry);\n\n        // new router\n\n        this.router = new OsgiDefaultCamelContext(this.context, registry);\n        if (!configuration.isEnableJmx()) {\n            this.router.disableJMX();\n        }\n\n        // call init code\n\n        callInitCode(this.router);\n\n        // new cloud service\n\n        this.service = new DefaultCamelCloudService(this.router);\n\n        // set up\n\n        final KuraCloudComponent cloudComponent = new KuraCloudComponent(this.router, this.service);\n        this.router.addComponent(\"kura-cloud\", cloudComponent);\n\n        final RoutesDefinition routesDefinition = this.router\n                .loadRoutesDefinition(new ByteArrayInputStream(this.configuration.getXml().getBytes()));\n        this.router.addRouteDefinitions(routesDefinition.getRoutes());\n\n        // start\n\n        logger.debug(\"Starting router...\");\n        this.router.start();\n        final ServiceStatus status = this.router.getStatus();\n        logger.debug(\"Starting router... {} ({}, {})\", status, status == Started, this.service.isConnected());\n\n        // register\n\n        final Dictionary<String, Object> props = new Hashtable<>();\n        props.put(SERVICE_PID, this.pid);\n        props.put(\"service.factoryPid\", FACTORY_ID);\n        props.put(KURA_SERVICE_PID, this.pid);\n        props.put(\"kura.cloud.service.factory.pid\", PID);\n\n        this.handle = this.context.registerService(CloudService.class, this.service, props);\n    }\n\n    public void stop() throws Exception {\n        if (this.handle != null) {\n            this.handle.unregister();\n            this.handle = null;\n        }\n        if (this.service != null) {\n            this.service.dispose();\n            this.service = null;\n        }\n        if (this.router != null) {\n            this.router.stop();\n            this.router = null;\n        }\n    }\n\n    private void callInitCode(final CamelContext router) throws ScriptException {\n        scriptInitCamelContext(router, configuration.getInitCode(), XmlCamelCloudService.class.getClassLoader());\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.xml/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.xml/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Plain XML router component\nBundle-SymbolicName: org.eclipse.kura.camel.xml\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.apache.camel;version=\"[2.17.0,3.0.0)\",\n org.eclipse.kura.camel.bean;version=\"[1.1,2.0)\",\n org.eclipse.kura.camel.component;version=\"[1.1,2.0)\",\n org.eclipse.kura.camel.runner;version=\"[1.1,2.0)\",\n org.eclipse.kura.camel.utils;version=\"[1.1,2.0)\",\n org.eclipse.kura.cloud;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.7.0\",\n org.slf4j;version=\"1.7.0\"\nService-Component: OSGI-INF/xmlRouter.xml\nBundle-ActivationPolicy: lazy\nDynamicImport-Package: *\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.xml/OSGI-INF/metatype/org.eclipse.kura.camel.xml.XmlRouterComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.camel.xml.XmlRouterComponent\"\n         name=\"Camel XML router\" description=\"Configurable Camel-based XML router\">\n\n        <Icon resource=\"OSGI-INF/logo.png\" size=\"32\" />\n\n        <AD id=\"xml.data\" name=\"Router XML\"\n            description=\"Camel XML route definitions|TextArea\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"false\"\n            max=\"2147483647\"\n            default='&lt;routes xmlns=&quot;http://camel.apache.org/schema/spring&quot;&gt;&#10;\n\t&lt;route id=&quot;route1&quot;&gt;&#10;\n        &lt;from uri=&quot;kura-cloud:myapp/xmltopic&quot;/&gt;&#10;\n        &lt;to uri=&quot;log:MESSAGE_FROM_CLOUD&quot;/&gt;&#10;\n    &lt;/route&gt;&#10;\n&lt;/routes&gt;'/>\n\n        <AD id=\"component.prereqs\" name=\"Required Camel Components\"\n            description=\"A comma separated list of Camel components which are required in order to start up this setup (e.g. amqp, stream)\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"false\"\n            max=\"2147483647\"\n            />\n\n        <AD id=\"language.prereqs\" name=\"Required Camel Languages\"\n            description=\"A comma separated list of Camel languages which are required in order to start up this setup (e.g. javaScript)\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"false\"\n            max=\"2147483647\"\n            />\n\n        <AD id=\"cloudService.prereqs\" name=\"Cloud Service Mappings\"\n            description=\"A comma separated list of entries in the format name=filter or name=kura-pid, mapping cloud service instances to component names. (e.g. cloud=org.eclipse.kura.cloud.CloudService)\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"false\"\n            max=\"2147483647\"\n            />\n\n        <AD id=\"initCode\"\n            name=\"JavaScript init code (Java 8 only)\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"false\"\n            description=\"JavaScript code which is called when the router is initialized first. The camel context is available in the variable 'camelContext'. Warning: this feature only works on JRE with Nashorn (Java &lt; 15).|TextArea\"/>\n\n        <AD id=\"disableJmx\"\n            name=\"Disable JMX\"\n            type=\"Boolean\"\n            cardinality=\"1\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Disable the JMX integration for this Camel context\"/>\n\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.camel.xml.XmlRouterComponent\" factoryPid=\"org.eclipse.kura.camel.xml.XmlRouterComponent\">\n        <Object ocdref=\"org.eclipse.kura.camel.xml.XmlRouterComponent\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.xml/OSGI-INF/xmlRouter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" immediate=\"true\" modified=\"modified\" name=\"org.eclipse.kura.camel.xml.XmlRouterComponent\">\n   <implementation class=\"org.eclipse.kura.camel.xml.XmlRouterComponent\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.xml/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.camel.xml/build.properties",
    "content": "output.. = target/classes\nsource.. = src/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.xml/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- \n  Copyright (c) 2016, 2024 Red Hat Inc and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Red Hat Inc\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.camel.xml</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.xml/src/org/eclipse/kura/camel/xml/XmlRouterComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.xml;\n\nimport static java.lang.String.format;\nimport static org.eclipse.kura.camel.component.Configuration.asBoolean;\nimport static org.eclipse.kura.camel.component.Configuration.asString;\nimport static org.eclipse.kura.camel.runner.CamelRunner.createOsgiRegistry;\nimport static org.eclipse.kura.camel.utils.CamelContexts.scriptInitCamelContext;\nimport static org.osgi.framework.FrameworkUtil.getBundle;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.eclipse.kura.camel.bean.PayloadFactory;\nimport org.eclipse.kura.camel.component.AbstractXmlCamelComponent;\nimport org.eclipse.kura.camel.component.Configuration;\nimport org.eclipse.kura.camel.runner.CamelRunner.Builder;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.FrameworkUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * A ready to run XML based Apache Camel component\n *\n * @noextend This class is not intended to be extended\n */\npublic class XmlRouterComponent extends AbstractXmlCamelComponent {\n\n    private static final String TOKEN_PATTERN = \"\\\\s*,\\\\s*\";\n\n    private static final Logger logger = LoggerFactory.getLogger(XmlRouterComponent.class);\n\n    private static final String CLOUD_SERVICE_PREREQS = \"cloudService.prereqs\";\n    private static final String COMPONENT_PREREQS = \"component.prereqs\";\n    private static final String LANGUAGE_PREREQS = \"language.prereqs\";\n    private static final String DISABLE_JMX = \"disableJmx\";\n    private static final String INIT_CODE = \"initCode\";\n\n    private final BundleContext bundleContext;\n\n    private Set<String> requiredComponents = new HashSet<>();\n    private Set<String> requiredLanguages = new HashSet<>();\n\n    private Map<String, String> cloudServiceRequirements = new HashMap<>();\n    private String initCode = \"\";\n\n    private boolean disableJmx;\n\n    public XmlRouterComponent() {\n        super(\"xml.data\");\n        this.bundleContext = FrameworkUtil.getBundle(XmlRouterComponent.class).getBundleContext();\n    }\n\n    @Override\n    protected void customizeBuilder(final Builder builder, final Map<String, Object> properties) {\n\n        // JMX\n\n        final boolean disableJmxTemp = asBoolean(properties, DISABLE_JMX, false);\n        builder.disableJmx(disableJmxTemp);\n\n        // parse configuration\n\n        final Set<String> newRequiredComponents = parseRequirements(asString(properties, COMPONENT_PREREQS));\n        final Set<String> newRequiredLanguages = parseRequirements(asString(properties, LANGUAGE_PREREQS));\n\n        final Map<String, String> cloudServiceRequirementsTemp = parseCloudServiceRequirements(\n                asString(properties, CLOUD_SERVICE_PREREQS));\n\n        final String initCodeTemp = parseInitCode(properties);\n\n        // set component requirements\n\n        logger.debug(\"Setting new component requirements\");\n        for (final String component : newRequiredComponents) {\n            logger.debug(\"Require component: {}\", component);\n            builder.requireComponent(component);\n        }\n\n        logger.debug(\"Setting new language requirements\");\n        for (final String language : newRequiredLanguages) {\n            logger.debug(\"Require language: {}\", language);\n            builder.requireLanguage(language);\n        }\n\n        // set cloud service requirements\n\n        logger.debug(\"Setting new cloud service requirements\");\n        for (final Map.Entry<String, String> entry : cloudServiceRequirementsTemp.entrySet()) {\n            final String filter;\n            if (entry.getValue().startsWith(\"(\")) {\n                filter = entry.getValue();\n            } else {\n                filter = format(\"(&(%s=%s)(kura.service.pid=%s))\", Constants.OBJECTCLASS, CloudService.class.getName(),\n                        entry.getValue());\n            }\n            builder.cloudService(null, filter, Builder.addAsCloudComponent(entry.getKey()));\n        }\n\n        if (!initCodeTemp.isEmpty()) {\n\n            // call init code before context start\n\n            builder.addBeforeStart(camelContext -> {\n                scriptInitCamelContext(camelContext, initCodeTemp, XmlRouterComponent.class.getClassLoader());\n            });\n        }\n\n        // build registry\n\n        final BundleContext ctx = getBundle(XmlRouterComponent.class).getBundleContext();\n        final Map<String, Object> services = new HashMap<>();\n        services.put(\"payloadFactory\", new PayloadFactory());\n        builder.registryFactory(createOsgiRegistry(ctx, services));\n\n        // assign new state\n\n        this.requiredComponents = newRequiredComponents;\n        this.requiredLanguages = newRequiredLanguages;\n        this.cloudServiceRequirements = cloudServiceRequirementsTemp;\n        this.initCode = initCodeTemp;\n        this.disableJmx = disableJmxTemp;\n    }\n\n    @Override\n    protected boolean isRestartNeeded(final Map<String, Object> properties) {\n\n        final boolean disableJmxTemp = asBoolean(properties, DISABLE_JMX, false);\n\n        final Set<String> newRequiredComponents = parseRequirements(asString(properties, COMPONENT_PREREQS));\n\n        final Map<String, String> cloudServiceRequirementsTemp = parseCloudServiceRequirements(\n                asString(properties, CLOUD_SERVICE_PREREQS));\n\n        final String initCodeTemp = parseInitCode(properties);\n\n        if (this.disableJmx != disableJmxTemp) {\n            logger.debug(\"Require restart due to '{}' change\", DISABLE_JMX);\n            return true;\n        }\n\n        if (!this.requiredComponents.equals(newRequiredComponents)) {\n            logger.debug(\"Require restart due to '{}' change\", COMPONENT_PREREQS);\n            return true;\n        }\n\n        if (!this.requiredLanguages.equals(newRequiredComponents)) {\n            logger.debug(\"Require restart due to '{}' change\", LANGUAGE_PREREQS);\n            return true;\n        }\n\n        if (!this.cloudServiceRequirements.equals(cloudServiceRequirementsTemp)) {\n            logger.debug(\"Require restart due to '{}' change\", CLOUD_SERVICE_PREREQS);\n            return true;\n        }\n\n        if (!this.initCode.equals(initCodeTemp)) {\n            logger.debug(\"Require restart due to '{}' change\", INIT_CODE);\n            return true;\n        }\n\n        return false;\n    }\n\n    private static Map<String, String> parseCloudServiceRequirements(final String value) {\n        if (value == null || value.trim().isEmpty()) {\n            return Collections.emptyMap();\n        }\n\n        final Map<String, String> result = new HashMap<>();\n\n        for (final String tok : value.split(TOKEN_PATTERN)) {\n            logger.debug(\"Testing - '{}'\", tok);\n\n            final String[] s = tok.split(\"=\", 2);\n            if (s.length != 2) {\n                continue;\n            }\n\n            logger.debug(\"CloudService - '{}' -> '{}'\", s[0], s[1]);\n            result.put(s[0], s[1]);\n        }\n\n        return result;\n    }\n\n    private static Set<String> parseRequirements(final String value) {\n        if (value == null || value.trim().isEmpty()) {\n            return Collections.emptySet();\n        }\n\n        return new HashSet<>(Arrays.asList(value.split(TOKEN_PATTERN)));\n    }\n\n    private static String parseInitCode(final Map<String, Object> properties) {\n        return Configuration.asString(properties, INIT_CODE, \"\");\n    }\n\n    @Override\n    protected BundleContext getBundleContext() {\n        return this.bundleContext;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.camel.xml/src/org/eclipse/kura/camel/xml/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n/**\n * A ready-to-run Apache Camel XML router component\n */\npackage org.eclipse.kura.camel.xml;\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.cloud.base.provider\nBundle-SymbolicName: org.eclipse.kura.cloud.base.provider;singleton:=true\nBundle-Version: 1.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura.core.data;version=\"1.3.0\",\n org.eclipse.kura.core.data.util;version=\"1.0.0\";x-internal:=true\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.connection.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.util;version=\"[2.0,3.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.data;version=\"[1.1,2.0)\",\n org.eclipse.kura.data.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.data.transport.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.db;version=\"[2.0,3.0)\",\n org.eclipse.kura.message.store;version=\"[1.0,2.0)\",\n org.eclipse.kura.message.store.provider;version=\"[1.0,1.1)\",\n org.eclipse.kura.ssl;version=\"[2.1,3.0)\",\n org.eclipse.kura.status;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.4,2.0)\",\n org.eclipse.kura.util.message.store;version=\"[1.0,1.1)\",\n org.eclipse.kura.util.store.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.watchdog;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.4.0\",\n org.osgi.util.tracker;version=\"1.5.0\",\n org.quartz;version=\"2.3.2\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .,\n lib/org.eclipse.paho.client.mqttv3-1.2.1.k2.jar\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/OSGI-INF/data.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"false\" modified=\"updated\" name=\"org.eclipse.kura.data.DataService\">\n   <implementation class=\"org.eclipse.kura.core.data.DataServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.data.DataService\"/>\n   </service>\n   \n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   \n   <reference name=\"DataTransportService\"\n              bind=\"setDataTransportService\" \n              unbind=\"unsetDataTransportService\" \n              cardinality=\"1..1\" \n              policy=\"static\" \n              interface=\"org.eclipse.kura.data.DataTransportService\"/>\n   <reference name=\"CloudConnectionStatusService\"\n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"setCloudConnectionStatusService\"\n              unbind=\"unsetCloudConnectionStatusService\"\n              interface=\"org.eclipse.kura.status.CloudConnectionStatusService\"/>\n   <reference name=\"DataServiceListener\"\n              policy=\"dynamic\"\n              cardinality=\"0..n\"\n              interface=\"org.eclipse.kura.data.DataServiceListener\"/>\n   <reference name=\"WatchdogService\"\n   \t\t\t  bind=\"setWatchdogService\" \n   \t\t\t  unbind=\"unsetWatchdogService\"\n   \t\t\t  cardinality=\"1..1\" \n   \t\t\t  interface=\"org.eclipse.kura.watchdog.WatchdogService\"  \n   \t\t\t  policy=\"static\"/>   \n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/OSGI-INF/metatype/org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n     Benjamin Cabé <benjamin@eclipse.org>\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\" \n         name=\"MqttDataTransport\" \n         description=\"The MqttDataTransport provides an MQTT connection. Its configuration parameters are used to determine the MQTT broker and the credentials to connect to the broker.\">\n\n        <Icon resource=\"MqttDataTransport\" size=\"32\"/>\n                \n        <AD id=\"broker-url\"\n            name=\"Broker-url\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"mqtt://broker-url:1883/\" \n            description=\"URL of the MQTT broker to connect to, specifying protocol, hostname and port (for example mqtt://your.broker.url:1883/ ). Supported protocols are mqtt, mqtts, ws and wss.\"/>\n\n        <AD id=\"topic.context.account-name\"\n            name=\"Topic Context Account-Name\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"account-name\"\n            description=\"The value of this attribute will replace the '#account-name' token found in publishing topics. For connections to remote management servers, this is generally the name of the server side account.\"/>\n\n        <AD id=\"username\"  \n            name=\"Username\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"username\" \n            description=\"Username to be used when connecting to the MQTT broker.\"/>\n\n        <AD id=\"password\"  \n            name=\"Password\"\n            type=\"Password\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"password\" \n            description=\"Password to be used when connecting to the MQTT broker.\"/>\n\n        <AD id=\"client-id\"\n            name=\"Client-id\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"\" \n            description=\"Client identifier to be used when connecting to the MQTT broker. The identifier has to be unique within your account. Characters '/', '+', '#' and '.' are invalid and they will be replaced by '-'. If left empty, this is automatically determined by the client software as the MAC address of the main network interface (in general uppercase and without ':').\"/>\n        \n        <AD id=\"keep-alive\"  \n            name=\"Keep-alive\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"30\"\n            description=\"Frequency in seconds for the periodic MQTT PING message.\"/>\n            \n        <AD id=\"timeout\"\n            name=\"Timeout\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"10\"\n            description=\"Timeout used for all interactions with the MQTT broker.\"/>\n\n        <AD id=\"clean-session\"\n            name=\"Clean-session\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"MQTT Clean Session flag.\"/>\n            \n        <AD id=\"lwt.topic\"\n            name=\"LWT Topic\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"$EDC/#account-name/#client-id/MQTT/LWT\"\n            description=\"MQTT Last Will and Testament topic. The tokens '#account-name' and '#client-id' will be replaced by the values of the properties topic.context.account-name and client-id\"/>\n            \n        <AD id=\"lwt.payload\"\n            name=\"LWT Payload\"\n            type=\"String\"\n            cardinality=\"0\"\n            default=\"\"\n            required=\"false\"\n            description=\"MQTT Last Will and Testament payload as a string.\"/>\n            \n        <AD id=\"lwt.qos\"  \n            name=\"LWT Qos\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"0\"\n            description=\"MQTT Last Will and Testament QoS (0..2).\">\n            <Option label=\"0\" value=\"0\"/>\n            <Option label=\"1\" value=\"1\"/>\n            <Option label=\"2\" value=\"2\"/>\n        </AD>\n            \n        <AD id=\"lwt.retain\"\n            name=\"LWT Retain\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"false\"\n            description=\"MQTT Last Will and Testament Retain flag.\"/>\n            \n        <AD id=\"in-flight.persistence\"\n            name=\"In-flight Persistence\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"memory\"\n            description=\"Storage type where in-flight messages are persisted across reconnections.\">\n           <Option label=\"file\" value=\"file\"/>\n           <Option label=\"memory\" value=\"memory\"/>\n        </AD>\n            \n        <AD id=\"protocol-version\"  \n            name=\"Protocol-version\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"4\"\n            description=\"MQTT Protocol Version.\">\n            <Option label=\"3.1\" value=\"3\"/>\n            <Option label=\"3.1.1\" value=\"4\"/>\n        </AD>\n        \n        <AD id=\"SslManagerService.target\"\n            name=\"SslManagerService Target Filter\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)\"\n            description=\"Specifies, as an OSGi target filter, the pid of the SslManagerService used to create SSL connections.\"/>\n        \n        </OCD>\n    <Designate pid = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\" factoryPid = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\">\n        <Object ocdref=\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/OSGI-INF/metatype/org.eclipse.kura.data.DataService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.data.DataService\"\n        name=\"DataService\"\n        description=\"DataService provides auto-connect, reconnect on connection drops and storing of outgoing messages.\">\n\n        <Icon resource=\"DataService\" size=\"32\" />\n\n        <AD id=\"connect.auto-on-startup\"\n            name=\"Connect Auto-on-startup\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Enable automatic connect of the Data Publishers on startup and after a disconnection.\" />\n\n        <AD id=\"connect.retry-interval\"\n            name=\"Connect Retry-interval\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"60\"\n            min=\"1\"\n            description=\"Frequency in seconds to retry a connection of the Data Publishers after a disconnect (Minimum value 1).\" />\n\n        <AD id=\"enable.recovery.on.connection.failure\"\n            name=\"Enable Recovery On Connection Failure\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Enables the recovery feature on connection failure. If the device is not able to connect to a remote cloud platform, the service will wait for a specified amount of connection retries. If the recovery fails, the device will be rebooted. Being based on the Watchdog service, it needs to be activated as well.\" />\n\n        <AD id=\"connection.recovery.max.failures\"\n            name=\"Connection Recovery Max Failures\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"10\"\n            min=\"1\"\n            description=\"Number of failures in Data Publishers connection before forcing a reboot.\" />\n\n        <AD id=\"disconnect.quiesce-timeout\"\n            name=\"Disconnect Quiesce-timeout\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"10\"\n            min=\"0\"\n            description=\"Timeout used to try to complete the delivery of stored messages before forcing a disconnect of the Data Publisher.\" />\n\n        <AD id=\"store.db.service.pid\"\n            name=\"Message Store Provider Service PID\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"org.eclipse.kura.db.H2DbService\"\n            description=\"The Kura service pid of the Message Store instance to be used. The pid of the default instance is org.eclipse.kura.db.H2DbService.\" />\n\n        <AD id=\"store.housekeeper-interval\"\n            name=\"Store Housekeeper-interval\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"900\"\n            min=\"5\"\n            description=\"Interval in seconds used to run the Data Store housekeeper task (min 5).\" />\n\n        <AD id=\"store.purge-age\"\n            name=\"Store Purge-age\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"60\"\n            min=\"5\"\n            description=\"Age in seconds of completed messages (either published with QoS = 0 or confirmed with QoS > 0) after which they are deleted (min 5).\" />\n\n        <AD id=\"store.capacity\"\n            name=\"Store Capacity\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"10000\"\n            min=\"1\"\n            description=\"Maximum number of messages persisted in the Data Store. The limit does not apply to messages with the priority less than 2. These priority levels are reserved to the framework which uses it for life-cycle messages - birth and death certificates - and replies to request/response flows.\" />\n\n        <AD id=\"in-flight-messages.republish-on-new-session\"\n            name=\"In-flight-messages Republish-on-new-session\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"Whether to republish in-flight messages on a new MQTT session.\" />\n\n        <AD id=\"in-flight-messages.max-number\"\n            name=\"In-flight-messages Max-number\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"9\"\n            min=\"1\"\n            max=\"10\"\n            description=\"The maximum number of in-flight messages.\" />\n\n        <AD id=\"in-flight-messages.congestion-timeout\"\n            name=\"In-flight-messages Congestion-timeout\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            min=\"0\"\n            description=\"Timeouts the in-flight messages congestion condition. The service will force a disconnect attempting to reconnect (0 to disable).\" />\n\n        <AD id=\"enable.rate.limit\"\n            name=\"Enable Rate Limit\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"Enables the token bucket message rate limiting.\" />\n\n        <AD id=\"rate.limit.average\"\n            name=\"Rate Limit Average\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"1\"\n            min=\"1\"\n            description=\"The average message publish rate in number of messages per unit of time (e.g. 10 messages per MINUTE). This parameter has some limitations described on the data service configuration page in the official product documentation.\" />\n\n        <AD id=\"rate.limit.time.unit\"\n            name=\"Rate Limit Time Unit\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"SECONDS\"\n            description=\"The time unit for the rate.limit.average.\">\n            <Option label=\"SECONDS\" value=\"SECONDS\" />\n            <Option label=\"MINUTES\" value=\"MINUTES\" />\n            <Option label=\"HOURS\" value=\"HOURS\" />\n            <Option label=\"DAYS\" value=\"DAYS\" />\n        </AD>\n\n        <AD id=\"rate.limit.burst.size\"\n            name=\"Rate Limit Burst Size\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"1\"\n            min=\"1\"\n            description=\"The token bucket burst size.\" />\n\n        <AD id=\"connection.schedule.enabled\"\n            name=\"Enable Connection Schedule\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Enables or disables the connection scheduling feature.\" />\n\n        <AD id=\"connection.schedule.expression\"\n            name=\"Connection Schedule CRON Expression\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0 0 0 ? * * *\"\n            description=\"A CRON expression that specifies the instants when the gateway should perform a connection attempt. This parameter is only used if Enable Connection Schedule is set to true. The default expression schedules a connection every day at midnight.\" />\n\n        <AD id=\"connection.schedule.priority.override.enable\"\n            name=\"Allow priority message to overide connection schedule\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Allows messages beyond a specified priority to force a connection and be sent regardless of connection schedule.\" />\n\n        <AD id=\"connection.schedule.priority.override.threshold\"\n            name=\"Message schedule priority override threshold\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"1\"\n            description=\"A message with a priority equal to or less than this threshold will cause the framework to automatically re-connect and send regardless of the connection schedule.\" />\n\n        <AD id=\"connection.schedule.inactivity.interval.seconds\"\n            name=\"Connection Schedule Disconnect Inactivity Interval Seconds\"\n            type=\"Long\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"60\"\n            min=\"1\"\n            description=\"Specifies an inactivity timeout in seconds. If the timeout expires, the cloud connection will be automatically closed. This timeout is delayed for the specified amount of seconds every time a new message is published. This parameter is only used if Enable Connection Schedule is set to true.\" />\n\n        <AD id=\"maximum.payload.size\"\n            name=\"Maximum Payload Size\"\n            type=\"Long\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"16777216\"\n            min=\"0\"\n            description=\"The maximum allowed size in bytes for the message payload.\" />\n\n    </OCD>\n    <Designate pid=\"org.eclipse.kura.data.DataService\"\n        factoryPid=\"org.eclipse.kura.data.DataService\">\n        <Object ocdref=\"org.eclipse.kura.data.DataService\" />\n    </Designate>\n</MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/OSGI-INF/mqttDataTransport.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"false\" modified=\"updated\" name=\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\">\n   <implementation class=\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.data.DataTransportService\"/>\n      <provide interface=\"org.eclipse.kura.ssl.SslServiceListener\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   \n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   \n   <reference name=\"SystemService\" \n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"setSystemService\"\n              unbind=\"unsetSystemService\"\n              interface=\"org.eclipse.kura.system.SystemService\"/>\n   <reference name=\"SslManagerService\" \n              policy=\"dynamic\"\n              cardinality=\"0..1\"\n              bind=\"setSslManagerService\"\n              unbind=\"unsetSslManagerService\"\n              interface=\"org.eclipse.kura.ssl.SslManagerService\"/>\n   <reference name=\"CryptoService\" \n              interface=\"org.eclipse.kura.crypto.CryptoService\" \n              bind=\"setCryptoService\" \n              unbind=\"unsetCryptoService\"\n              cardinality=\"1..1\" \n              policy=\"static\"/>\n   <reference name=\"CloudConnectionStatusService\"   \n       \t\t  policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"setCloudConnectionStatusService\"\n              unbind=\"unsetCloudConnectionStatusService\"\n              interface=\"org.eclipse.kura.status.CloudConnectionStatusService\"/>\n   <reference name=\"DataTransportListener\"\n              policy=\"dynamic\"\n              cardinality=\"0..n\"\n              interface=\"org.eclipse.kura.data.DataTransportListener\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/build.properties",
    "content": "#\n#  Copyright (c) 2024 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/,\\\n           src/main/resources/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               lib/org.eclipse.paho.client.mqttv3-1.2.1.k2.jar\nadditional.bundles = slf4j.api,\\\n                     org.eclipse.osgi,\\\n                     org.eclipse.equinox.io,\\\n                     org.eclipse.kura.api,\\\n                     org.apache.logging.log4j.api\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <!--\n    The dependency is committed in lib/.\n    Adding to the dependencies section for tracking it and make it parsable from BOM tools\n    -->\n    <dependencies>\n        <dependency>\n            <groupId>org.eclipse.paho</groupId>\n            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>\n        </dependency>\n    </dependencies>\n\n    <artifactId>org.eclipse.kura.cloud.base.provider</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n\n</project>"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/AlwaysConnectedStrategy.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.data;\n\npublic class AlwaysConnectedStrategy implements AutoConnectStrategy {\n\n    private final ConnectionManager connectionManager;\n\n    public AlwaysConnectedStrategy(final ConnectionManager connectionManager) {\n        this.connectionManager = connectionManager;\n        connectionManager.startConnectionTask();\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        // do nothing\n    }\n\n    @Override\n    public void onDisconnecting() {\n        // do nothing\n    }\n\n    @Override\n    public void onDisconnected() {\n        connectionManager.startConnectionTask();\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        connectionManager.stopConnectionTask();\n        connectionManager.startConnectionTask();\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n        // do nothing\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        // do nothing\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        // do nothing\n    }\n\n    @Override\n    public void shutdown() {\n        connectionManager.stopConnectionTask();\n    }\n\n    @Override\n    public void onPublishRequested(String topic, byte[] payload, int qos, boolean retain, int priority) {\n        // do nothing\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/AutoConnectStrategy.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.data;\n\nimport java.util.Optional;\n\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.eclipse.kura.message.store.StoredMessage;\n\ninterface AutoConnectStrategy extends DataServiceListener {\n\n    public void shutdown();\n\n    public void onPublishRequested(String topic, byte[] payload, int qos, boolean retain, int priority);\n\n    interface ConnectionManager {\n\n        void startConnectionTask();\n\n        void stopConnectionTask();\n\n        void disconnect();\n\n        Optional<StoredMessage> getNextMessage();\n\n        boolean hasInFlightMessages();\n\n        boolean isConnected();\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataMessage.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data;\n\nimport java.util.Arrays;\nimport java.util.Date;\n\n/**\n * DataMessage is a message that is currently transiting through the DataService.\n * It is a wrapper class over the message payload as produced by the client application\n * but it also capture all the state information of the message through its\n * DataService life-cycle of: stored -> published -> confirmed.\n */\npublic class DataMessage {\n\n    private int id;\n    private String topic;\n    private int qos;\n    private boolean retain;\n    private Date createdOn;\n    private Date publishedOn;\n    private int publishedMessageId;\n    private Date confirmedOn;\n    private byte[] payload;\n    private int priority;\n    private String sessionId;\n    private Date droppedOn;\n\n    public DataMessage() {\n    }\n\n    public DataMessage(Builder b) {\n        this.id = b.id;\n        this.topic = b.topic;\n        this.qos = b.qos;\n        this.retain = b.retain;\n        this.createdOn = b.createdOn;\n        this.publishedOn = b.publishedOn;\n        this.publishedMessageId = b.publishedMessageId;\n\n        this.confirmedOn = b.confirmedOn;\n        this.payload = b.payload;\n        this.priority = b.priority;\n        this.sessionId = b.sessionId;\n        this.droppedOn = b.droppedOn;\n    }\n\n    public int getId() {\n        return this.id;\n    }\n\n    public String getTopic() {\n        return this.topic;\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    public boolean isRetain() {\n        return this.retain;\n    }\n\n    public Date getCreatedOn() {\n        return this.createdOn;\n    }\n\n    public Date getPublishedOn() {\n        return this.publishedOn;\n    }\n\n    public int getPublishedMessageId() {\n        return this.publishedMessageId;\n    }\n\n    public void setPublishedMessageId(int publishedMessageId) {\n        this.publishedMessageId = publishedMessageId;\n    }\n\n    public Date getConfirmedOn() {\n        return this.confirmedOn;\n    }\n\n    public byte[] getPayload() {\n        return this.payload;\n    }\n\n    public int getPriority() {\n        return this.priority;\n    }\n\n    public String getSessionId() {\n        return this.sessionId;\n    }\n\n    public Date droppedOn() {\n        return this.droppedOn;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder(\"DataMessage [id=\").append(this.id).append(\", topic=\")\n                .append(this.topic).append(\", qos=\").append(this.qos).append(\", retain=\").append(this.retain)\n                .append(\", createdOn=\").append(this.createdOn).append(\", publishedOn=\").append(this.publishedOn)\n                .append(\", publishedMessageId=\").append(this.publishedMessageId).append(\", confirmedOn=\")\n                .append(this.confirmedOn).append(\", payload=\").append(Arrays.toString(this.payload))\n                .append(\", priority=\").append(this.priority).append(\", sessionId=\").append(this.sessionId)\n                .append(\", droppedOn=\").append(this.droppedOn).append(\"]\");\n\n        return builder.toString();\n    }\n\n    public static class Builder {\n\n        private final int id;\n        private String topic;\n        private int qos;\n        private boolean retain;\n        private Date createdOn;\n        private Date publishedOn;\n        private int publishedMessageId;\n        private Date confirmedOn;\n        private byte[] payload;\n        private int priority;\n        private String sessionId;\n        private Date droppedOn;\n\n        public Builder(int id) {\n            this.id = id;\n        }\n\n        public Builder withTopic(String topic) {\n            this.topic = topic;\n            return this;\n        }\n\n        public Builder withQos(int qos) {\n            this.qos = qos;\n            return this;\n        }\n\n        public Builder withRetain(boolean retain) {\n            this.retain = retain;\n            return this;\n        }\n\n        public Builder withCreatedOn(Date createdOn) {\n            this.createdOn = createdOn;\n            return this;\n        }\n\n        public Builder withPublishedOn(Date publishedOn) {\n            this.publishedOn = publishedOn;\n            return this;\n        }\n\n        public Builder withPublishedMessageId(int publishedMessageId) {\n            this.publishedMessageId = publishedMessageId;\n            return this;\n        }\n\n        public Builder withConfirmedOn(Date confirmedOn) {\n            this.confirmedOn = confirmedOn;\n            return this;\n        }\n\n        public Builder withPayload(byte[] payload) {\n            this.payload = payload;\n            return this;\n        }\n\n        public Builder withPriority(int priority) {\n            this.priority = priority;\n            return this;\n        }\n\n        public Builder withSessionId(String sessionId) {\n            this.sessionId = sessionId;\n            return this;\n        }\n\n        public Builder withDroppedOn(Date droppedOn) {\n            this.droppedOn = droppedOn;\n            return this;\n        }\n\n        public int getId() {\n            return this.id;\n        }\n\n        public String getTopic() {\n            return this.topic;\n        }\n\n        public int getQos() {\n            return this.qos;\n        }\n\n        public boolean getRetain() {\n            return this.retain;\n        }\n\n        public Date getCreatedOn() {\n            return this.createdOn;\n        }\n\n        public Date getPublishedOn() {\n            return this.publishedOn;\n        }\n\n        public int getPublishedMessageId() {\n            return this.publishedMessageId;\n        }\n\n        public Date getConfirmedOn() {\n            return this.confirmedOn;\n        }\n\n        public byte[] getPayload() {\n            return this.payload;\n        }\n\n        public int getPriority() {\n            return this.priority;\n        }\n\n        public String getSessionId() {\n            return this.sessionId;\n        }\n\n        public Date getDroppedOn() {\n            return this.droppedOn;\n        }\n\n        public DataMessage build() {\n            return new DataMessage(this);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data;\n\nimport java.security.SecureRandom;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Random;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraNotConnectedException;\nimport org.eclipse.kura.KuraStoreCapacityReachedException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.KuraTooManyInflightMessagesException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.connection.listener.ConnectionListener;\nimport org.eclipse.kura.core.data.store.MessageStoreState;\nimport org.eclipse.kura.core.internal.data.TokenBucket;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.eclipse.kura.message.store.StoredMessage;\nimport org.eclipse.kura.message.store.provider.MessageStore;\nimport org.eclipse.kura.message.store.provider.MessageStoreProvider;\nimport org.eclipse.kura.status.CloudConnectionStatusComponent;\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\nimport org.eclipse.kura.status.CloudConnectionStatusService;\nimport org.eclipse.kura.watchdog.CriticalComponent;\nimport org.eclipse.kura.watchdog.WatchdogService;\nimport org.eclipse.paho.client.mqttv3.MqttException;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.component.ComponentException;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.quartz.CronExpression;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class DataServiceImpl implements DataService, DataTransportListener, ConfigurableComponent,\n        CloudConnectionStatusComponent, CriticalComponent, AutoConnectStrategy.ConnectionManager, ConnectionListener {\n\n    private static final String MESSAGE_STORE_NOT_CONNECTED_MESSAGE = \"Message store instance not connected, not connecting\";\n    public static final String MESSAGE_STORE_NOT_PRESENT_MESSAGE = \"Message store instance not configured properly, not connecting\";\n\n    private static final int RECONNECTION_MIN_DELAY = 1;\n\n    private static final Logger logger = LoggerFactory.getLogger(DataServiceImpl.class);\n\n    private static final int TRANSPORT_TASK_TIMEOUT = 1; // In seconds\n\n    private DataServiceOptions dataServiceOptions;\n\n    private DataTransportService dataTransportService;\n    private DataServiceListenerS dataServiceListeners;\n\n    protected ScheduledExecutorService connectionMonitorExecutor;\n    private ScheduledFuture<?> connectionMonitorFuture;\n\n    // A dedicated executor for the publishing task\n    private ExecutorService publisherExecutor;\n\n    private Optional<MessageStoreState> storeState = Optional.empty();\n\n    private Map<DataTransportToken, Integer> inFlightMsgIds = new ConcurrentHashMap<>();\n\n    private ScheduledExecutorService congestionExecutor;\n    private ScheduledFuture<?> congestionFuture;\n\n    private CloudConnectionStatusService cloudConnectionStatusService;\n    private CloudConnectionStatusEnum notificationStatus = CloudConnectionStatusEnum.OFF;\n\n    private TokenBucket throttle;\n\n    private final Lock lock = new ReentrantLock();\n    private boolean notifyPending;\n    private final Condition lockCondition = this.lock.newCondition();\n\n    private final AtomicBoolean publisherEnabled = new AtomicBoolean();\n\n    private ServiceTracker<Object, Object> dbServiceTracker;\n    private ComponentContext componentContext;\n\n    private WatchdogService watchdogService;\n\n    private AtomicInteger connectionAttempts;\n\n    private Optional<AutoConnectStrategy> autoConnectStrategy = Optional.empty();\n\n    private final Random random = new SecureRandom();\n    private AtomicBoolean disconnectionGuard = new AtomicBoolean();\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        String pid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n        logger.info(\"Activating {}...\", pid);\n\n        this.componentContext = componentContext;\n\n        this.dataServiceOptions = new DataServiceOptions(properties);\n\n        this.connectionMonitorExecutor = Executors.newSingleThreadScheduledExecutor();\n        this.publisherExecutor = Executors.newSingleThreadExecutor();\n        this.congestionExecutor = Executors.newSingleThreadScheduledExecutor();\n\n        createThrottle();\n        submitPublishingWork();\n\n        restartDbServiceTracker(this.dataServiceOptions.getDbServiceInstancePid());\n\n        this.dataServiceListeners = new DataServiceListenerS(componentContext);\n\n        // Register the component in the CloudConnectionStatus Service\n        this.cloudConnectionStatusService.register(this);\n\n        this.dataTransportService.addDataTransportListener(this);\n\n        createAutoConnectStrategy();\n    }\n\n    private void restartDbServiceTracker(String kuraServicePid) {\n        stopDbServiceTracker();\n        try {\n            final Filter filter = FrameworkUtil\n                    .createFilter(\"(\" + ConfigurationService.KURA_SERVICE_PID + \"=\" + kuraServicePid + \")\");\n            this.dbServiceTracker = new ServiceTracker<>(this.componentContext.getBundleContext(), filter,\n                    new ServiceTrackerCustomizer<Object, Object>() {\n\n                        @Override\n                        public Object addingService(ServiceReference<Object> reference) {\n                            logger.info(\"Message store instance found\");\n                            Object service = DataServiceImpl.this.componentContext.getBundleContext()\n                                    .getService(reference);\n\n                            if (service instanceof MessageStoreProvider) {\n                                setMessageStoreProvider((MessageStoreProvider) service);\n                            } else {\n                                DataServiceImpl.this.componentContext.getBundleContext().ungetService(reference);\n                                return null;\n                            }\n\n                            return service;\n                        }\n\n                        @Override\n                        public void modifiedService(ServiceReference<Object> reference, Object service) {\n                            if (service instanceof MessageStoreProvider) {\n                                return;\n                            }\n                            logger.info(\"Message store instance updated, recreating table if needed...\");\n\n                            synchronized (DataServiceImpl.this) {\n                                if (DataServiceImpl.this.storeState.isPresent()) {\n                                    DataServiceImpl.this.storeState.get()\n                                            .update(DataServiceImpl.this.dataServiceOptions);\n                                }\n                            }\n                        }\n\n                        @Override\n                        public void removedService(ServiceReference<Object> reference, Object service) {\n                            logger.info(\"Message store instance removed\");\n                            unsetMessageStoreProvider();\n                            DataServiceImpl.this.componentContext.getBundleContext().ungetService(reference);\n                        }\n                    });\n            this.dbServiceTracker.open();\n        } catch (InvalidSyntaxException e) {\n            throw new ComponentException(e);\n        }\n    }\n\n    private void stopDbServiceTracker() {\n        if (this.dbServiceTracker != null) {\n            this.dbServiceTracker.close();\n            this.dbServiceTracker = null;\n        }\n    }\n\n    private synchronized void startDbStore() {\n        try {\n            List<StoredMessage> inFlightMsgs = Collections.emptyList();\n            // The initial list of in-flight messages\n            if (DataServiceImpl.this.storeState.isPresent()) {\n                inFlightMsgs = this.storeState.get().getOrOpenMessageStore().getInFlightMessages();\n            }\n\n            // The map associating a DataTransportToken with a message ID\n            this.inFlightMsgIds = new ConcurrentHashMap<>();\n\n            if (inFlightMsgs != null) {\n                for (StoredMessage message : inFlightMsgs) {\n\n                    final Optional<DataTransportToken> token = message.getDataTransportToken();\n\n                    if (!token.isPresent()) {\n                        logger.warn(\"In-flight message has no associated DataTransportToken\");\n                        continue;\n                    }\n\n                    this.inFlightMsgIds.put(token.get(), message.getId());\n\n                    logger.debug(\"Restored in-fligh messages from store. Topic: {}, ID: {}, MQTT message ID: {}\",\n                            message.getTopic(), message.getId(), token.get().getMessageId());\n                }\n            }\n        } catch (KuraStoreException e) {\n            logger.error(\"Failed to start store\", e);\n            DataServiceImpl.this.disconnectDataTransportAndLog(e);\n        }\n    }\n\n    public synchronized void updated(Map<String, Object> properties) {\n        logger.info(\"Updating {}...\", properties.get(ConfigurationService.KURA_SERVICE_PID));\n\n        shutdownAutoConnectStrategy();\n        stopConnectionTask();\n\n        final String oldDbServicePid = this.dataServiceOptions.getDbServiceInstancePid();\n\n        this.dataServiceOptions = new DataServiceOptions(properties);\n\n        createThrottle();\n\n        final String currentDbServicePid = this.dataServiceOptions.getDbServiceInstancePid();\n\n        if (oldDbServicePid.equals(currentDbServicePid)) {\n            if (DataServiceImpl.this.storeState.isPresent()) {\n                this.storeState.get().update(this.dataServiceOptions);\n            }\n        } else {\n            restartDbServiceTracker(currentDbServicePid);\n        }\n\n        createAutoConnectStrategy();\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.info(\"Deactivating {}...\", this.dataServiceOptions.getKuraServicePid());\n\n        shutdownAutoConnectStrategy();\n        this.connectionMonitorExecutor.shutdownNow();\n\n        this.congestionExecutor.shutdownNow();\n\n        disconnect();\n\n        // Await termination of the publisher executor tasks\n        try {\n            // Waits to publish latest messages e.g. disconnect message\n            Thread.sleep(TRANSPORT_TASK_TIMEOUT * 1000L);\n\n            // Clean publisher thread shutdown\n            this.publisherEnabled.set(false);\n            signalPublisher();\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            logger.info(\"Interrupted\", e);\n        }\n        this.publisherExecutor.shutdownNow();\n\n        this.dataTransportService.removeDataTransportListener(this);\n\n        if (storeState.isPresent()) {\n            this.storeState.get().shutdown();\n        }\n\n        stopDbServiceTracker();\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setDataTransportService(DataTransportService dataTransportService) {\n        this.dataTransportService = dataTransportService;\n    }\n\n    public void unsetDataTransportService(DataTransportService dataTransportService) {\n        this.dataTransportService = null;\n    }\n\n    public synchronized void setMessageStoreProvider(MessageStoreProvider messageStoreProvider) {\n        this.storeState = Optional.of(new MessageStoreState(messageStoreProvider, this.dataServiceOptions));\n        messageStoreProvider.addListener(this);\n        startDbStore();\n        signalPublisher();\n    }\n\n    public synchronized void unsetMessageStoreProvider() {\n        disconnect();\n\n        if (this.storeState.isPresent()) {\n            this.storeState.get().getMessageStoreProvider().removeListener(this);\n            this.storeState.get().shutdown();\n            this.storeState = Optional.empty();\n        }\n\n    }\n\n    public void setCloudConnectionStatusService(CloudConnectionStatusService cloudConnectionStatusService) {\n        this.cloudConnectionStatusService = cloudConnectionStatusService;\n    }\n\n    public void unsetCloudConnectionStatusService(CloudConnectionStatusService cloudConnectionStatusService) {\n        this.cloudConnectionStatusService = null;\n    }\n\n    public void setWatchdogService(WatchdogService watchdogService) {\n        this.watchdogService = watchdogService;\n    }\n\n    public void unsetWatchdogService(WatchdogService watchdogService) {\n        this.watchdogService = null;\n    }\n\n    @Override\n    public void addDataServiceListener(DataServiceListener listener) {\n        this.dataServiceListeners.add(listener);\n    }\n\n    @Override\n    public void removeDataServiceListener(DataServiceListener listener) {\n        this.dataServiceListeners.remove(listener);\n    }\n\n    @Override\n    public void onConnectionEstablished(boolean newSession) {\n\n        logger.info(\"Notified connected\");\n        this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.ON);\n\n        // On a new session all messages the were in-flight in the previous session\n        // would be lost and never confirmed by the DataPublisherService.\n        //\n        // If the DataPublisherService is configured with Clean Start flag set to true,\n        // then the session and connection boundaries are the same.\n        // Otherwise, a session spans multiple connections as far as the client connects\n        // to the same broker instance with the same client ID.\n        //\n        // We have two options here:\n        // Forget them.\n        // Unpublish them so they will be republished on the new session.\n        //\n        // The latter has the potential drawback that duplicates can be generated with\n        // any QoS.\n        // This can occur for example if the DataPublisherService is connecting with a\n        // different client ID\n        // or to a different broker URL resolved to the same broker instance.\n        //\n        // Also note that unpublished messages will be republished accordingly to their\n        // original priority. Thus a message reordering may occur too.\n        // Even if we artificially upgraded the priority of unpublished messages to -1\n        // so to\n        // republish them first, their relative order would not necessarily match the\n        // order\n        // in the DataPublisherService persistence.\n\n        if (newSession) {\n            unpublishOrDropInFlightMessages(this.dataServiceOptions.isPublishInFlightMessages());\n        }\n\n        // Notify the listeners\n        this.dataServiceListeners.onConnectionEstablished();\n\n        signalPublisher();\n    }\n\n    private void unpublishOrDropInFlightMessages(boolean publishInFlightMessages) {\n\n        if (publishInFlightMessages && this.storeState.isPresent()) {\n            logger.info(\"New session established. Unpublishing all in-flight messages. Disregarding the QoS level, \"\n                    + \"this may cause duplicate messages.\");\n            try {\n                this.storeState.get().getOrOpenMessageStore().unpublishAllInFlighMessages();\n                this.inFlightMsgIds.clear();\n            } catch (KuraStoreException e) {\n                logger.error(\"Failed to unpublish in-flight messages\", e);\n                DataServiceImpl.this.disconnectDataTransportAndLog(e);\n            }\n        } else if (this.storeState.isPresent()) {\n            logger.info(\"New session established. Dropping all in-flight messages.\");\n            try {\n                this.storeState.get().getOrOpenMessageStore().dropAllInFlightMessages();\n                this.inFlightMsgIds.clear();\n            } catch (KuraStoreException e) {\n                logger.error(\"Failed to drop in-flight messages\", e);\n                DataServiceImpl.this.disconnectDataTransportAndLog(e);\n            }\n        }\n\n    }\n\n    @Override\n    public void onDisconnecting() {\n        logger.info(\"Notified disconnecting\");\n\n        // Notify the listeners\n        this.dataServiceListeners.onDisconnecting();\n    }\n\n    @Override\n    public void onDisconnected() {\n        logger.info(\"Notified disconnected\");\n        this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.OFF);\n\n        // Notify the listeners\n        this.dataServiceListeners.onDisconnected();\n    }\n\n    @Override\n    public void onConfigurationUpdating(boolean wasConnected) {\n        logger.info(\"Notified DataTransportService configuration updating...\");\n        this.dataTransportService.disconnect(0);\n    }\n\n    @Override\n    public void onConfigurationUpdated(boolean wasConnected) {\n        logger.info(\"Notified DataTransportService configuration updated.\");\n        shutdownAutoConnectStrategy();\n        createAutoConnectStrategy();\n        if (!this.autoConnectStrategy.isPresent() && wasConnected) {\n            try {\n                connect();\n            } catch (KuraConnectException e) {\n                logger.error(\"Error during re-connect after configuration update.\", e);\n            }\n        }\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        logger.info(\"connectionLost\");\n\n        // Notify the listeners\n        this.dataServiceListeners.onConnectionLost(cause);\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n\n        logger.debug(\"Message arrived on topic: {}\", topic);\n\n        // Notify the listeners\n        this.dataServiceListeners.onMessageArrived(topic, payload, qos, retained);\n\n        signalPublisher();\n    }\n\n    @Override\n    // It's very important that the publishInternal and messageConfirmed methods are\n    // synchronized\n    public synchronized void onMessageConfirmed(DataTransportToken token) {\n\n        logger.debug(\"Confirmed message with MQTT message ID: {} on session ID: {}\", token.getMessageId(),\n                token.getSessionId());\n\n        Integer messageId = this.inFlightMsgIds.remove(token);\n        if (messageId == null) {\n            logger.info(\n                    \"Confirmed message published with MQTT message ID: {} not tracked in the map of in-flight messages\",\n                    token.getMessageId());\n        } else {\n\n            Optional<StoredMessage> confirmedMessage = Optional.empty();\n            try {\n                logger.info(\"Confirmed message ID: {} to store\", messageId);\n                if (this.storeState.isPresent()) {\n                    this.storeState.get().getOrOpenMessageStore().markAsConfirmed(messageId);\n                    confirmedMessage = this.storeState.get().getOrOpenMessageStore().get(messageId);\n                }\n            } catch (KuraStoreException e) {\n                logger.error(\"Cannot confirm message to store\", e);\n                disconnectDataTransportAndLog(e);\n            }\n\n            // Notify the listeners\n            if (confirmedMessage.isPresent()) {\n                String topic = confirmedMessage.get().getTopic();\n                this.dataServiceListeners.onMessageConfirmed(messageId, topic);\n            } else {\n                logger.error(\"Confirmed Message with ID {} could not be loaded from the DataStore.\", messageId);\n            }\n        }\n\n        if (this.inFlightMsgIds.size() < this.dataServiceOptions.getMaxInFlightMessages()) {\n            handleInFlightDecongestion();\n        }\n\n        signalPublisher();\n    }\n\n    private void disconnectDataTransportAndLog(Throwable e) {\n\n        if (e instanceof KuraStoreCapacityReachedException) {\n            return;\n        }\n\n        if (this.disconnectionGuard.compareAndSet(false, true)) {\n            logger.error(\"Disconnecting the DataTransportService, cause: {}\", e.getMessage());\n            this.disconnect();\n            this.disconnectionGuard.set(false);\n        }\n\n    }\n\n    @Override\n    public void connect() throws KuraConnectException {\n        shutdownAutoConnectStrategy();\n\n        if (!this.storeState.isPresent()) {\n            throw new KuraConnectException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE);\n        }\n\n        try {\n            this.storeState.get().getOrOpenMessageStore();\n        } catch (KuraStoreException e) {\n            throw new KuraConnectException(e, MESSAGE_STORE_NOT_CONNECTED_MESSAGE);\n        }\n\n        if (!this.dataTransportService.isConnected()) {\n            this.dataTransportService.connect();\n        }\n    }\n\n    @Override\n    public boolean isConnected() {\n        return this.dataTransportService.isConnected();\n    }\n\n    @Override\n    public boolean isAutoConnectEnabled() {\n        return this.dataServiceOptions.isAutoConnect();\n    }\n\n    @Override\n    public int getRetryInterval() {\n        return this.dataServiceOptions.getConnectDelay();\n    }\n\n    @Override\n    public void disconnect(long quiesceTimeout) {\n        shutdownAutoConnectStrategy();\n        this.dataTransportService.disconnect(quiesceTimeout);\n    }\n\n    @Override\n    public void subscribe(String topic, int qos) throws KuraException {\n        this.dataTransportService.subscribe(topic, qos);\n    }\n\n    @Override\n    public void unsubscribe(String topic) throws KuraException {\n        this.dataTransportService.unsubscribe(topic);\n    }\n\n    @Override\n    public int publish(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException {\n\n        if (priority < 0) {\n            throw new IllegalArgumentException(\"Priority cannot be negative\");\n        }\n\n        if (payload != null && (long) payload.length > this.dataServiceOptions.getMaximumPayloadSizeBytes()) {\n            throw new KuraStoreException(\"Payload size exceeds configured limit\");\n        }\n\n        if (this.autoConnectStrategy.isPresent()) {\n            this.autoConnectStrategy.get().onPublishRequested(topic, payload, qos, retain, priority);\n        }\n\n        if (this.storeState.isPresent()) {\n\n            try {\n                logger.info(\"Storing message on topic: {}, priority: {}\", topic, priority);\n\n                final MessageStore currentStore = this.storeState.get().getOrOpenMessageStore();\n                final int messageId;\n\n                synchronized (currentStore) {\n                    // Priority 0 are used for life-cycle messages like birth and death\n                    // certificates.\n                    // Priority 1 are used for remove management by Cloudlet applications.\n                    // For those messages, bypass the maximum message count check of the DB cache.\n                    // We want to publish those message even if the DB is full, so allow their\n                    // storage.\n                    if (priority != 0 && priority != 1) {\n                        int count = currentStore.getMessageCount();\n                        logger.debug(\"Store message count: {}\", count);\n                        if (count >= this.dataServiceOptions.getStoreCapacity()) {\n                            logger.error(\"Store capacity exceeded\");\n                            throw new KuraStoreCapacityReachedException(\"Store capacity exceeded\");\n                        }\n                    }\n\n                    messageId = currentStore.store(topic, payload, qos, retain, priority);\n                    logger.info(\"Stored message on topic: {}, priority: {}\", topic, priority);\n                }\n\n                signalPublisher();\n\n                return messageId;\n            } catch (KuraStoreException e) {\n                disconnectDataTransportAndLog(e);\n                throw e;\n            }\n\n        } else {\n            KuraStoreException e = new KuraStoreException(MESSAGE_STORE_NOT_PRESENT_MESSAGE);\n            disconnectDataTransportAndLog(e);\n            throw e;\n        }\n\n    }\n\n    @Override\n    public List<Integer> getUnpublishedMessageIds(String topicRegex) throws KuraStoreException {\n        if (this.storeState.isPresent()) {\n            List<StoredMessage> messages = this.storeState.get().getOrOpenMessageStore().getUnpublishedMessages();\n            return buildMessageIds(messages, topicRegex);\n        } else {\n            KuraStoreException e = new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE);\n            disconnectDataTransportAndLog(e);\n            throw e;\n\n        }\n    }\n\n    @Override\n    public List<Integer> getInFlightMessageIds(String topicRegex) throws KuraStoreException {\n        if (this.storeState.isPresent()) {\n            List<StoredMessage> messages = this.storeState.get().getOrOpenMessageStore().getInFlightMessages();\n            return buildMessageIds(messages, topicRegex);\n        } else {\n            KuraStoreException e = new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE);\n            disconnectDataTransportAndLog(e);\n            throw e;\n        }\n    }\n\n    @Override\n    public List<Integer> getDroppedInFlightMessageIds(String topicRegex) throws KuraStoreException {\n\n        if (this.storeState.isPresent()) {\n            List<StoredMessage> messages = this.storeState.get().getOrOpenMessageStore().getDroppedMessages();\n            return buildMessageIds(messages, topicRegex);\n        } else {\n            KuraStoreException e = new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE);\n            disconnectDataTransportAndLog(e);\n            throw e;\n        }\n    }\n\n    private void signalPublisher() {\n        this.lock.lock();\n        this.notifyPending = true;\n        this.lockCondition.signal();\n        this.lock.unlock();\n    }\n\n    private void createAutoConnectStrategy() {\n        if (!this.dataServiceOptions.isAutoConnect()) {\n            return;\n        }\n\n        final Optional<AutoConnectStrategy> currentStrategy = this.autoConnectStrategy;\n\n        if (currentStrategy.isPresent()) {\n            return;\n        }\n\n        final Optional<CronExpression> schedule = this.dataServiceOptions.getConnectionScheduleExpression();\n\n        final AutoConnectStrategy strategy;\n\n        if (!this.dataServiceOptions.isConnectionScheduleEnabled() || !schedule.isPresent()) {\n            strategy = new AlwaysConnectedStrategy(this);\n        } else {\n            strategy = new ScheduleStrategy(schedule.get(), this.dataServiceOptions, this);\n        }\n\n        this.autoConnectStrategy = Optional.of(strategy);\n        this.dataServiceListeners.prepend(strategy);\n\n    }\n\n    private void shutdownAutoConnectStrategy() {\n        final Optional<AutoConnectStrategy> currentStrategy = this.autoConnectStrategy;\n\n        if (currentStrategy.isPresent()) {\n            currentStrategy.get().shutdown();\n            this.dataServiceListeners.remove(currentStrategy.get());\n            this.autoConnectStrategy = Optional.empty();\n        }\n    }\n\n    private void startConnectionMonitorTask() {\n        if (this.connectionMonitorFuture != null && !this.connectionMonitorFuture.isDone()) {\n            logger.info(\"Reconnect task already running\");\n        }\n\n        //\n        // Establish a reconnect Thread based on the reconnect interval\n        boolean autoConnect = this.dataServiceOptions.isAutoConnect();\n        int reconnectInterval = this.dataServiceOptions.getConnectDelay();\n        if (autoConnect) {\n\n            if (this.dataServiceOptions.isConnectionRecoveryEnabled()) {\n                this.watchdogService.registerCriticalComponent(this);\n                this.watchdogService.checkin(this);\n                this.connectionAttempts = new AtomicInteger(0);\n            }\n\n            // Change notification status to slow blinking when connection is expected to\n            // happen in the future\n            this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.SLOW_BLINKING);\n            // add a delay on the reconnect\n            int maxDelay = reconnectInterval / 5;\n            maxDelay = maxDelay > 0 ? maxDelay : 1;\n\n            int initialDelay = Math.max(this.random.nextInt(maxDelay), RECONNECTION_MIN_DELAY);\n\n            logger.info(\"Starting reconnect task with initial delay {}\", initialDelay);\n            this.connectionMonitorFuture = this.connectionMonitorExecutor.scheduleAtFixedRate(new ReconnectTask(),\n                    initialDelay, reconnectInterval, TimeUnit.SECONDS);\n        } else {\n            // Change notification status to off. Connection is not expected to happen in\n            // the future\n            this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.OFF);\n            unregisterAsCriticalComponent();\n        }\n    }\n\n    private void createThrottle() {\n        if (this.dataServiceOptions.isRateLimitEnabled()) {\n            int publishRate = this.dataServiceOptions.getRateLimitAverageRate();\n            int burstLength = this.dataServiceOptions.getRateLimitBurstSize();\n\n            long publishPeriod = this.dataServiceOptions.getRateLimitTimeUnit() / publishRate;\n\n            logger.info(\"Get Throttle with burst length {} and send a message every {} nanoseconds\", burstLength,\n                    publishPeriod);\n            this.throttle = new TokenBucket(burstLength, publishPeriod);\n        }\n    }\n\n    private void stopConnectionMonitorTask() {\n        if (this.connectionMonitorFuture != null && !this.connectionMonitorFuture.isDone()) {\n\n            logger.info(\"Reconnect task running. Stopping it\");\n\n            this.connectionMonitorFuture.cancel(true);\n        }\n        unregisterAsCriticalComponent();\n    }\n\n    private void unregisterAsCriticalComponent() {\n        this.watchdogService.unregisterCriticalComponent(this);\n    }\n\n    @Override\n    public void disconnect() {\n        long millis = this.dataServiceOptions.getDisconnectDelay() * 1000L;\n        this.dataTransportService.disconnect(millis);\n    }\n\n    private void submitPublishingWork() {\n        this.publisherEnabled.set(true);\n\n        this.publisherExecutor.execute(new PublishManager());\n    }\n\n    private List<Integer> buildMessageIds(List<StoredMessage> messages, String topicRegex) {\n        Pattern topicPattern = Pattern.compile(topicRegex);\n        List<Integer> ids = new ArrayList<>();\n\n        if (messages != null) {\n            for (StoredMessage message : messages) {\n                String topic = message.getTopic();\n                if (topicPattern.matcher(topic).matches()) {\n                    ids.add(message.getId());\n                }\n            }\n        }\n\n        return ids;\n    }\n\n    private void handleInFlightDecongestion() {\n        if (this.congestionFuture != null && !this.congestionFuture.isDone()) {\n            this.congestionFuture.cancel(true);\n        }\n    }\n\n    @Override\n    public int getNotificationPriority() {\n        return CloudConnectionStatusService.PRIORITY_LOW;\n    }\n\n    @Override\n    public CloudConnectionStatusEnum getNotificationStatus() {\n        return this.notificationStatus;\n    }\n\n    @Override\n    public void setNotificationStatus(CloudConnectionStatusEnum status) {\n        this.notificationStatus = status;\n    }\n\n    private final class ReconnectTask implements Runnable {\n\n        @Override\n        public void run() {\n            Thread.currentThread().setName(\n                    \"DataServiceImpl:ReconnectTask:\" + DataServiceImpl.this.dataServiceOptions.getKuraServicePid());\n            boolean connected = false;\n            try {\n                if (!DataServiceImpl.this.storeState.isPresent()) {\n                    logger.warn(MESSAGE_STORE_NOT_CONNECTED_MESSAGE);\n                    throw new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE);\n                }\n\n                DataServiceImpl.this.storeState.get().getOrOpenMessageStore();\n\n                logger.info(\"Connecting...\");\n                if (DataServiceImpl.this.dataTransportService.isConnected()) {\n                    logger.info(\"Already connected. Reconnect task will be terminated.\");\n\n                } else {\n                    DataServiceImpl.this.dataTransportService.connect();\n                    logger.info(\"Connected. Reconnect task will be terminated.\");\n                }\n                connected = true;\n            } catch (KuraConnectException | KuraStoreException e) {\n                logger.warn(\"Connection attempt failed with exception {}\", e.getClass().getSimpleName(), e);\n\n                if (DataServiceImpl.this.dataServiceOptions.isConnectionRecoveryEnabled()) {\n\n                    if (isAuthenticationException(e) || e instanceof KuraStoreException\n                            || DataServiceImpl.this.connectionAttempts\n                                    .getAndIncrement() < DataServiceImpl.this.dataServiceOptions\n                                            .getRecoveryMaximumAllowedFailures()) {\n                        logger.info(\"Checkin done.\");\n                        DataServiceImpl.this.watchdogService.checkin(DataServiceImpl.this);\n                    } else {\n                        logger.info(\"Maximum number of connection attempts reached. Requested reboot...\");\n                    }\n                }\n            } finally {\n                if (connected) {\n                    unregisterAsCriticalComponent();\n                    // Throwing an exception will suppress subsequent executions of this periodic\n                    // task.\n                    throw new RuntimeException(\"Connected. Reconnect task will be terminated.\");\n                }\n            }\n        }\n\n        private boolean isAuthenticationException(KuraException e) {\n            boolean authenticationException = false;\n            if (e.getCause() instanceof MqttException) {\n                MqttException mqttException = (MqttException) e.getCause();\n                if (mqttException.getReasonCode() == MqttException.REASON_CODE_FAILED_AUTHENTICATION\n                        || mqttException.getReasonCode() == MqttException.REASON_CODE_INVALID_CLIENT_ID\n                        || mqttException.getReasonCode() == MqttException.REASON_CODE_NOT_AUTHORIZED) {\n                    logger.info(\"Authentication exception encountered.\");\n                    authenticationException = true;\n                }\n            }\n            return authenticationException;\n        }\n    }\n\n    private final class PublishManager implements Runnable {\n\n        @Override\n        public void run() {\n            Thread.currentThread().setName(\"DataServiceImpl:Submit\");\n            while (DataServiceImpl.this.publisherEnabled.get()) {\n                long sleepingTime = -1;\n                boolean messagePublished = false;\n\n                if (DataServiceImpl.this.dataTransportService.isConnected()) {\n                    try {\n                        if (DataServiceImpl.this.storeState.isPresent()) {\n                            final Optional<StoredMessage> message = DataServiceImpl.this.storeState.get()\n                                    .getOrOpenMessageStore().getNextMessage();\n\n                            if (message.isPresent()) {\n                                checkInFlightMessages(message.get());\n\n                                if (DataServiceImpl.this.dataServiceOptions.isRateLimitEnabled()\n                                        && message.get().getPriority() >= 5) {\n                                    messagePublished = publishMessageTokenBucket(message.get());\n                                    sleepingTime = DataServiceImpl.this.throttle.getTokenWaitTime();\n                                } else {\n                                    publishMessageUnbound(message.get());\n                                    messagePublished = true;\n                                }\n                            }\n                        }\n                    } catch (KuraNotConnectedException e) {\n                        logger.info(\"DataPublisherService is not connected\");\n                    } catch (KuraTooManyInflightMessagesException e) {\n                        logger.info(\"Too many in-flight messages\");\n                        handleInFlightCongestion();\n                    } catch (Exception e) {\n                        logger.error(\"Probably an unrecoverable exception\", e);\n                    }\n                } else {\n                    logger.info(\"DataPublisherService not connected\");\n                }\n\n                if (!messagePublished) {\n                    suspendPublisher(sleepingTime, TimeUnit.NANOSECONDS);\n                }\n            }\n            logger.debug(\"Exited publisher loop.\");\n        }\n\n        private void checkInFlightMessages(StoredMessage message) throws KuraTooManyInflightMessagesException {\n            if (message.getQos() > 0 && DataServiceImpl.this.inFlightMsgIds\n                    .size() >= DataServiceImpl.this.dataServiceOptions.getMaxInFlightMessages()) {\n                logger.warn(\"The configured maximum number of in-flight messages has been reached\");\n                throw new KuraTooManyInflightMessagesException(\"Too many in-flight messages\");\n            }\n        }\n\n        private void suspendPublisher(long timeout, TimeUnit timeUnit) {\n            if (!DataServiceImpl.this.publisherEnabled.get()) {\n                return;\n            }\n            try {\n                DataServiceImpl.this.lock.lock();\n                if (!DataServiceImpl.this.notifyPending) {\n                    if (timeout == -1) {\n                        logger.debug(\"Suspending publishing thread indefinitely\");\n                        DataServiceImpl.this.lockCondition.await();\n                    } else {\n                        logger.debug(\"Suspending publishing thread for {} nanoseconds\", timeout);\n                        DataServiceImpl.this.lockCondition.await(timeout, timeUnit);\n                    }\n                }\n                DataServiceImpl.this.notifyPending = false;\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            } finally {\n                DataServiceImpl.this.lock.unlock();\n            }\n        }\n\n        private void publishMessageUnbound(StoredMessage message) throws KuraException {\n            publishInternal(message);\n            // Notify the listeners\n            DataServiceImpl.this.dataServiceListeners.onMessagePublished(message.getId(), message.getTopic());\n        }\n\n        private boolean publishMessageTokenBucket(StoredMessage message) throws KuraException {\n            boolean tokenAvailable = DataServiceImpl.this.throttle.getToken();\n\n            if (tokenAvailable) {\n                publishMessageUnbound(message);\n                return true;\n            }\n            return false;\n        }\n\n        private void handleInFlightCongestion() {\n            int timeout = DataServiceImpl.this.dataServiceOptions.getInFlightMessagesCongestionTimeout();\n\n            // Do not schedule more that one task at a time\n            if (timeout != 0 && (DataServiceImpl.this.congestionFuture == null\n                    || DataServiceImpl.this.congestionFuture.isDone())) {\n                logger.warn(\"In-flight message congestion timeout started\");\n                DataServiceImpl.this.congestionFuture = DataServiceImpl.this.congestionExecutor.schedule(() -> {\n                    Thread.currentThread().setName(\"DataServiceImpl:InFlightCongestion\");\n                    logger.warn(\"In-flight message congestion timeout elapsed. Disconnecting and reconnecting again\");\n                    disconnect();\n                    startConnectionMonitorTask();\n                }, timeout, TimeUnit.SECONDS);\n            }\n        }\n\n        // It's very important that the publishInternal and messageConfirmed methods are\n        // synchronized\n        private synchronized void publishInternal(StoredMessage message) throws KuraException {\n\n            String topic = message.getTopic();\n            byte[] payload = message.getPayload();\n            int qos = message.getQos();\n            boolean retain = message.isRetain();\n            int msgId = message.getId();\n\n            logger.debug(\"Publishing message with ID: {} on topic: {}, priority: {}\", msgId, topic,\n                    message.getPriority());\n\n            DataTransportToken token = DataServiceImpl.this.dataTransportService.publish(topic, payload, qos, retain);\n\n            if (DataServiceImpl.this.storeState.isPresent()) {\n                try {\n                    if (token == null) {\n                        DataServiceImpl.this.storeState.get().getOrOpenMessageStore().markAsPublished(msgId);\n                        logger.debug(\"Published message with ID: {}\", msgId);\n                    } else {\n\n                        // Check if the token is already tracked in the map (in which case we are in\n                        // trouble)\n                        Integer trackedMsgId = DataServiceImpl.this.inFlightMsgIds.get(token);\n                        if (trackedMsgId != null) {\n                            logger.error(\"Token already tracked: {} - {}\", token.getSessionId(), token.getMessageId());\n                        }\n\n                        DataServiceImpl.this.inFlightMsgIds.put(token, msgId);\n                        DataServiceImpl.this.storeState.get().getOrOpenMessageStore().markAsPublished(msgId, token);\n                        logger.debug(\"Published message with ID: {} and MQTT message ID: {}\", msgId,\n                                token.getMessageId());\n                    }\n\n                } catch (KuraStoreException e) {\n                    DataServiceImpl.this.disconnectDataTransportAndLog(e);\n                }\n\n            } else {\n                throw new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE);\n            }\n\n        }\n    }\n\n    @Override\n    public String getCriticalComponentName() {\n        return \"DataServiceImpl\";\n    }\n\n    @Override\n    public int getCriticalComponentTimeout() {\n        return this.dataServiceOptions.getCriticalComponentTimeout();\n    }\n\n    public Map<String, String> getConnectionInfo() {\n        Map<String, String> result = new HashMap<>();\n        result.put(\"Broker URL\", this.dataTransportService.getBrokerUrl());\n        result.put(\"Account\", this.dataTransportService.getAccountName());\n        result.put(\"Username\", this.dataTransportService.getUsername());\n        result.put(\"Client ID\", this.dataTransportService.getClientId());\n        return result;\n    }\n\n    @Override\n    public void startConnectionTask() {\n        if (!this.dataTransportService.isConnected()) {\n            startConnectionMonitorTask();\n        }\n    }\n\n    @Override\n    public void stopConnectionTask() {\n        stopConnectionMonitorTask();\n    }\n\n    @Override\n    public boolean hasInFlightMessages() {\n        return !this.inFlightMsgIds.isEmpty();\n    }\n\n    @Override\n    public Optional<StoredMessage> getNextMessage() {\n        Optional<StoredMessage> message = Optional.empty();\n        try {\n            if (DataServiceImpl.this.storeState.isPresent()) {\n                message = DataServiceImpl.this.storeState.get().getOrOpenMessageStore().getNextMessage();\n            } else {\n                throw new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE);\n            }\n        } catch (Exception e) {\n            DataServiceImpl.this.disconnectDataTransportAndLog(e);\n            logger.error(\"Probably an unrecoverable exception\", e);\n        }\n        return message;\n    }\n\n    @Override\n    public void connected() {\n        logger.info(\"Message store with PID {} connected.\", this.dataServiceOptions.getDbServiceInstancePid());\n        if (this.connectionMonitorFuture != null && !this.connectionMonitorFuture.isDone()) {\n            stopConnectionTask();\n            startConnectionTask();\n        }\n\n    }\n\n    @Override\n    public void disconnected() {\n        logger.info(\"Message store with PID {} disconnected.\", this.dataServiceOptions.getDbServiceInstancePid());\n        if (this.storeState.isPresent()) {\n            this.storeState.get().shutdown();\n        }\n        if (this.dataTransportService.isConnected()) {\n            this.disconnect();\n            logger.info(\"Message store disconnected. Trying to shutdown the DataTransportService.\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataServiceListenerS.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data;\n\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/*\n * The following represents an exception to Semantic Versioning conventions.\n * Though the class implements the org.eclipse.kura.data.listener.DataServiceListener API,\n * it is actually an API consumer (it calls into the API implementors).\n */\nclass DataServiceListenerS implements DataServiceListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(DataServiceListenerS.class);\n\n    private static final String DATA_SERVICE_LISTENER_REFERENCE = \"DataServiceListener\";\n\n    private final ComponentContext ctx;\n    private final List<DataServiceListener> listeners;\n\n    public DataServiceListenerS(ComponentContext ctx) {\n        this.ctx = ctx;\n        // thread-safe list implementation\n        this.listeners = new CopyOnWriteArrayList<>();\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataServiceListener) service).onConnectionEstablished();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onConnectionEstablished\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataServiceListener listener : this.listeners) {\n                try {\n                    listener.onConnectionEstablished();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onConnectionEstablished\");\n        }\n    }\n\n    @Override\n    public void onDisconnecting() {\n        Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataServiceListener) service).onDisconnecting();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onDisconnecting\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataServiceListener listener : this.listeners) {\n                try {\n                    listener.onDisconnecting();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onDisconnecting\");\n        }\n    }\n\n    @Override\n    public void onDisconnected() {\n        Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataServiceListener) service).onDisconnected();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onDisconnected\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataServiceListener listener : this.listeners) {\n                try {\n                    listener.onDisconnected();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onDisconnected\");\n        }\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataServiceListener) service).onConnectionLost(cause);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onConnectionLost\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataServiceListener listener : this.listeners) {\n                try {\n                    listener.onConnectionLost(cause);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onConnectionLost\");\n        }\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n        Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataServiceListener) service).onMessageArrived(topic, payload, qos,\n                            retained);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onMessageArrived\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataServiceListener listener : this.listeners) {\n                try {\n                    listener.onMessageArrived(topic, payload, qos, retained);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onMessageArrived\");\n        }\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataServiceListener) service).onMessagePublished(messageId, topic);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onMessagePublished\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataServiceListener listener : this.listeners) {\n                try {\n                    listener.onMessagePublished(messageId, topic);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onMessagePublished\");\n        }\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataServiceListener) service).onMessageConfirmed(messageId, topic);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onMessageConfirmed\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataServiceListener listener : this.listeners) {\n                try {\n                    listener.onMessageConfirmed(messageId, topic);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onMessageConfirmed\");\n        }\n    }\n\n    public void prepend(DataServiceListener listener) {\n        this.listeners.add(0, listener);\n    }\n\n    public void add(DataServiceListener listener) {\n        this.listeners.add(listener);\n    }\n\n    public void remove(DataServiceListener listener) {\n        this.listeners.remove(listener);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.quartz.CronExpression;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static java.util.Objects.requireNonNull;\n\npublic class DataServiceOptions {\n\n    private static final Logger logger = LoggerFactory.getLogger(DataServiceOptions.class);\n\n    private static final String AUTOCONNECT_PROP_NAME = \"connect.auto-on-startup\";\n    private static final String CONNECT_DELAY_PROP_NAME = \"connect.retry-interval\";\n    private static final String DISCONNECT_DELAY_PROP_NAME = \"disconnect.quiesce-timeout\";\n    private static final String STORE_DB_SERVICE_INSTANCE_PROP_NAME = \"store.db.service.pid\";\n    private static final String STORE_HOUSEKEEPER_INTERVAL_PROP_NAME = \"store.housekeeper-interval\";\n    private static final String STORE_PURGE_AGE_PROP_NAME = \"store.purge-age\";\n    private static final String STORE_CAPACITY_PROP_NAME = \"store.capacity\";\n    private static final String REPUBLISH_IN_FLIGHT_MSGS_PROP_NAME = \"in-flight-messages.republish-on-new-session\";\n    private static final String MAX_IN_FLIGHT_MSGS_PROP_NAME = \"in-flight-messages.max-number\";\n    private static final String IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_PROP_NAME = \"in-flight-messages.congestion-timeout\";\n    private static final String RATE_LIMIT_ENABLE_PROP_NAME = \"enable.rate.limit\";\n    private static final String RATE_LIMIT_AVERAGE_RATE_PROP_NAME = \"rate.limit.average\";\n    private static final String RATE_LIMIT_TIME_UNIT_PROP_NAME = \"rate.limit.time.unit\";\n    private static final String RATE_LIMIT_BURST_SIZE_PROP_NAME = \"rate.limit.burst.size\";\n    private static final String RECOVERY_ENABLE_PROP_NAME = \"enable.recovery.on.connection.failure\";\n    private static final String RECOVERY_MAX_FAILURES_PROP_NAME = \"connection.recovery.max.failures\";\n    private static final String CONNECTION_SCHEDULE_ENABLED = \"connection.schedule.enabled\";\n    private static final String CONNECTION_SCHECULE_EXPRESSION = \"connection.schedule.expression\";\n    private static final String CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS = \"connection.schedule.inactivity.interval.seconds\";\n    private static final String CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE = \"connection.schedule.priority.override.enable\";\n    private static final String CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD = \"connection.schedule.priority.override.threshold\";\n    private static final String MAXIMUM_PAYLOAD_SIZE = \"maximum.payload.size\";\n\n    private static final boolean AUTOCONNECT_PROP_DEFAULT = false;\n    private static final int CONNECT_DELAY_DEFAULT = 60;\n    private static final int DISCONNECT_DELAY_DEFAULT = 10;\n    private static final String DB_SERVICE_INSTANCE_DEFAULT = \"org.eclipse.kura.db.H2DbService\";\n    private static final int STORE_HOUSEKEEPER_INTERVAL_DEFAULT = 900;\n    private static final int STORE_PURGE_AGE_DEFAULT = 60;\n    private static final int STORE_CAPACITY_DEFAULT = 10000;\n    private static final boolean REPUBLISH_IN_FLIGHT_MSGS_DEFAULT = true;\n    private static final int MAX_IN_FLIGHT_MSGS_DEFAULT = 9;\n    private static final int IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_DEFAULT = 0;\n    private static final boolean RATE_LIMIT_ENABLE_DEFAULT = true;\n    private static final int RATE_LIMIT_AVERAGE_RATE_DEFAULT = 1;\n    private static final String RATE_LIMIT_TIME_UNIT_DEFAULT = \"SECONDS\";\n    private static final int RATE_LIMIT_BURST_SIZE_DEFAULT = 1;\n    private static final boolean RECOVERY_ENABLE_DEFAULT = true;\n    private static final int RECOVERY_MAX_FAILURES_DEFAULT = 10;\n    private static final boolean CONNECTION_SCHEDULE_ENABLED_DEFAULT = false;\n    private static final long CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS_DEFAULT = 60;\n    private static final boolean CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE_DEFAULT = false;\n    private static final int CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD_DEFAULT = 1;\n    private static final long MAXIMUM_PAYLOAD_SIZE_DEFAULT = 16777216;\n\n    private static final int CONNECT_CRITICAL_COMPONENT_TIMEOUT_MULTIPLIER = 5000;\n\n    private final Map<String, Object> properties;\n\n    DataServiceOptions(Map<String, Object> properties) {\n        requireNonNull(properties, \"Required not null\");\n        this.properties = Collections.unmodifiableMap(properties);\n    }\n\n    public int getStoreHousekeeperInterval() {\n        return (int) this.properties.getOrDefault(STORE_HOUSEKEEPER_INTERVAL_PROP_NAME,\n                STORE_HOUSEKEEPER_INTERVAL_DEFAULT);\n    }\n\n    public int getStorePurgeAge() {\n        return (int) this.properties.getOrDefault(STORE_PURGE_AGE_PROP_NAME, STORE_PURGE_AGE_DEFAULT);\n    }\n\n    public int getStoreCapacity() {\n        return (int) this.properties.getOrDefault(STORE_CAPACITY_PROP_NAME, STORE_CAPACITY_DEFAULT);\n    }\n\n    public boolean isPublishInFlightMessages() {\n        return (boolean) this.properties.getOrDefault(REPUBLISH_IN_FLIGHT_MSGS_PROP_NAME,\n                REPUBLISH_IN_FLIGHT_MSGS_DEFAULT);\n    }\n\n    public int getMaxInFlightMessages() {\n        return (int) this.properties.getOrDefault(MAX_IN_FLIGHT_MSGS_PROP_NAME, MAX_IN_FLIGHT_MSGS_DEFAULT);\n    }\n\n    public int getInFlightMessagesCongestionTimeout() {\n        return (int) this.properties.getOrDefault(IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_PROP_NAME,\n                IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_DEFAULT);\n    }\n\n    public boolean isAutoConnect() {\n        return (boolean) this.properties.getOrDefault(AUTOCONNECT_PROP_NAME, AUTOCONNECT_PROP_DEFAULT);\n    }\n\n    public int getConnectDelay() {\n        return (int) this.properties.getOrDefault(CONNECT_DELAY_PROP_NAME, CONNECT_DELAY_DEFAULT);\n    }\n\n    public int getDisconnectDelay() {\n        return (int) this.properties.getOrDefault(DISCONNECT_DELAY_PROP_NAME, DISCONNECT_DELAY_DEFAULT);\n    }\n\n    public boolean isRateLimitEnabled() {\n        return (boolean) this.properties.getOrDefault(RATE_LIMIT_ENABLE_PROP_NAME, RATE_LIMIT_ENABLE_DEFAULT);\n    }\n\n    public int getRateLimitAverageRate() {\n        return (int) this.properties.getOrDefault(RATE_LIMIT_AVERAGE_RATE_PROP_NAME, RATE_LIMIT_AVERAGE_RATE_DEFAULT);\n    }\n\n    public int getRateLimitBurstSize() {\n        return (int) this.properties.getOrDefault(RATE_LIMIT_BURST_SIZE_PROP_NAME, RATE_LIMIT_BURST_SIZE_DEFAULT);\n    }\n\n    public long getRateLimitTimeUnit() {\n        String timeUnitString = (String) this.properties.getOrDefault(RATE_LIMIT_TIME_UNIT_PROP_NAME,\n                RATE_LIMIT_TIME_UNIT_DEFAULT);\n        TimeUnit timeUnit;\n\n        if (TimeUnit.MILLISECONDS.name().equals(timeUnitString)) {\n            timeUnit = TimeUnit.MILLISECONDS;\n        } else if (TimeUnit.SECONDS.name().equals(timeUnitString)) {\n            timeUnit = TimeUnit.SECONDS;\n        } else if (TimeUnit.MINUTES.name().equals(timeUnitString)) {\n            timeUnit = TimeUnit.MINUTES;\n        } else if (TimeUnit.HOURS.name().equals(timeUnitString)) {\n            timeUnit = TimeUnit.HOURS;\n        } else if (TimeUnit.DAYS.name().equals(timeUnitString)) {\n            timeUnit = TimeUnit.DAYS;\n        } else {\n            throw new IllegalArgumentException(\"Illegal time unit\");\n        }\n\n        return timeUnit.toNanos(1);\n    }\n\n    public String getDbServiceInstancePid() {\n        return (String) this.properties.getOrDefault(STORE_DB_SERVICE_INSTANCE_PROP_NAME, DB_SERVICE_INSTANCE_DEFAULT);\n    }\n\n    public String getKuraServicePid() {\n        return (String) this.properties.get(ConfigurationService.KURA_SERVICE_PID);\n    }\n\n    public boolean isConnectionRecoveryEnabled() {\n        return (boolean) this.properties.getOrDefault(RECOVERY_ENABLE_PROP_NAME, RECOVERY_ENABLE_DEFAULT);\n    }\n\n    public int getRecoveryMaximumAllowedFailures() {\n        return (int) this.properties.getOrDefault(RECOVERY_MAX_FAILURES_PROP_NAME, RECOVERY_MAX_FAILURES_DEFAULT);\n    }\n\n    public int getCriticalComponentTimeout() {\n        return getConnectDelay() * CONNECT_CRITICAL_COMPONENT_TIMEOUT_MULTIPLIER;\n    }\n\n    public boolean isConnectionScheduleEnabled() {\n        return (boolean) this.properties.getOrDefault(CONNECTION_SCHEDULE_ENABLED, CONNECTION_SCHEDULE_ENABLED_DEFAULT);\n    }\n\n    public Optional<CronExpression> getConnectionScheduleExpression() {\n\n        if (!this.isConnectionScheduleEnabled()) {\n            return Optional.empty();\n        }\n\n        try {\n            return Optional.of(new CronExpression((String) this.properties.get(CONNECTION_SCHECULE_EXPRESSION)));\n        } catch (final Exception e) {\n            logger.warn(\"failed to parse connection schedule expression\", e);\n            return Optional.empty();\n        }\n    }\n\n    public long getConnectionScheduleDisconnectDelay() {\n        return (long) this.properties.getOrDefault(CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS,\n                CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS_DEFAULT);\n    }\n\n    public boolean isConnectionSchedulePriorityOverrideEnabled() {\n        return (Boolean) this.properties.getOrDefault(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE,\n                CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE_DEFAULT) && isConnectionScheduleEnabled()\n                && getConnectionScheduleExpression().isPresent();\n    }\n\n    public int getConnectionSchedulePriorityOverridePriority() {\n\n        return (Integer) this.properties.getOrDefault(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD,\n                CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD_DEFAULT);\n\n    }\n\n    public long getMaximumPayloadSizeBytes() {\n        try {\n            return (long) this.properties.getOrDefault(MAXIMUM_PAYLOAD_SIZE, MAXIMUM_PAYLOAD_SIZE_DEFAULT);\n        } catch (final Exception e) {\n            return MAXIMUM_PAYLOAD_SIZE_DEFAULT;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataStore.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.db.H2DbService;\n\n/**\n * DataStore implementation have the responsibility of doing the bookkeeping of\n * the messages that are in transient in the system. A message in the system\n * normally flows through the following states: stored -> published ->\n * confirmed (or dropped). The data store should be able to store messages, track and update\n * their state, and perform certain queries for messages in a given state.\n */\npublic interface DataStore {\n\n    public void start(H2DbService dbService, int houseKeeperInterval, int purgeAge, int capacity)\n            throws KuraStoreException;\n\n    public void update(int houseKeeperInterval, int purgeAge, int capacity);\n\n    public void stop();\n\n    /**\n     * Stores an MQTT message for deferred publication. An identifier is always\n     * generated and returned, even for messages published with QoS = 0. The\n     * store policy is FIFO within each priority level, 0 being the highest\n     * priority.\n     *\n     * @param topic\n     * @param payload\n     * @param qos\n     * @param retain\n     * @param priority\n     * @return\n     * @throws KuraStoreException\n     */\n    public DataMessage store(String topic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraStoreException;\n\n    /**\n     * Acknowledges the publication of the DataMessage with the given ID\n     * associating it to the protocol (e.g. MQTT) message ID (QoS > 0).\n     *\n     * @param msgId\n     * @param publishedMsgId\n     * @param sessionId\n     *            TODO\n     * @throws KuraStoreException\n     */\n    public void published(int msgId, int publishedMsgId, String sessionId) throws KuraStoreException;\n\n    /**\n     * Acknowledges the publication of the DataMessage with the given ID. This\n     * is typically called for messages published with QoS = 0.\n     *\n     * @param msgId\n     * @param publishedMsgId\n     * @throws KuraStoreException\n     */\n    public void published(int msgId) throws KuraStoreException;\n\n    /**\n     * Acknowledges the delivery of the DataMessage published with the given\n     * protocol (e.g. MQTT) message ID. This method is only called for messages\n     * published with QoS > 0.\n     *\n     * @param msgId\n     * @throws KuraStoreException\n     */\n    public void confirmed(int msgId) throws KuraStoreException;\n\n    /**\n     * Gets the next unpublished message. Messages with higher\n     * priority (0 is the highest priority) are returned first. Within each\n     * priority level the oldest unpublished message is returned first.\n     *\n     * @return\n     * @throws KuraStoreException\n     */\n    public DataMessage getNextMessage() throws KuraStoreException;\n\n    /**\n     * Returns a message from the DataStore by its message id.\n     *\n     * @param msgId\n     *            ID of the message to be loaded\n     * @return Loaded message or null if not found.\n     * @throws KuraStoreException\n     */\n    public DataMessage get(int msgId) throws KuraStoreException;\n\n    /**\n     * Finds the list of all unpublished messages and returns them WITHOUT loading the payload.\n     *\n     * @return\n     * @throws KuraStoreException\n     */\n    public List<DataMessage> allUnpublishedMessagesNoPayload() throws KuraStoreException;\n\n    /**\n     * Finds the list of all published but not yet confirmed messages and returns them WITHOUT loading the payload.\n     * These are only messages published with QoS > 0.\n     * Messages published with QoS = 0 do not belong to the results list.\n     *\n     * @return\n     * @throws KuraStoreException\n     */\n    public List<DataMessage> allInFlightMessagesNoPayload() throws KuraStoreException;\n\n    /**\n     * Finds the list of all published messages that will not be confirmed and returns them WITHOUT loading the payload.\n     * These are only messages published with QoS > 0.\n     * Messages published with QoS = 0 do not belong to the results list.\n     *\n     * @return\n     */\n    public List<DataMessage> allDroppedInFlightMessagesNoPayload() throws KuraStoreException;\n\n    /**\n     * Marks all in-flight messages as unpublished.\n     *\n     * @throws KuraStoreException\n     */\n    public void unpublishAllInFlighMessages() throws KuraStoreException;\n\n    /**\n     * Drops all in-flight messages.\n     *\n     * @throws KuraStoreException\n     */\n    public void dropAllInFlightMessages() throws KuraStoreException;\n\n    /**\n     * Deletes stale messages.\n     * These are either published messages with QoS = 0 or confirmed messages with QoS > 0, whose age exceeds the\n     * argument.\n     *\n     * @param purgeAge\n     * @throws KuraStoreException\n     */\n    public void deleteStaleMessages(int purgeAge) throws KuraStoreException;\n\n    /**\n     * Checks and attempts to repair the store.\n     *\n     * @throws KuraStoreException\n     */\n    public void repair() throws KuraStoreException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/ScheduleStrategy.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.data;\n\nimport java.util.Date;\nimport java.util.Optional;\nimport java.util.OptionalLong;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Supplier;\nimport java.util.function.UnaryOperator;\n\nimport org.eclipse.kura.message.store.StoredMessage;\nimport org.quartz.CronExpression;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ScheduleStrategy implements AutoConnectStrategy {\n\n    private static final Logger logger = LoggerFactory.getLogger(ScheduleStrategy.class);\n\n    private final ScheduledExecutorService executor;\n\n    private final CronExpression expression;\n    private final long disconnectTimeoutMs;\n    private final ConnectionManager connectionManager;\n    private final Supplier<Date> currentTimeProvider;\n    private State state;\n\n    private Optional<ScheduledFuture<?>> timeout = Optional.empty();\n    private DataServiceOptions dataServiceOptions;\n\n    public ScheduleStrategy(final CronExpression expression, DataServiceOptions dataServiceOptions,\n            final ConnectionManager connectionManager) {\n        this(expression, dataServiceOptions.getConnectionScheduleDisconnectDelay() * 1000, connectionManager,\n                Executors.newSingleThreadScheduledExecutor(),\n                Date::new, dataServiceOptions);\n    }\n\n    public ScheduleStrategy(final CronExpression expression, final long disconnectTimeoutMs,\n            final ConnectionManager connectionManager, final ScheduledExecutorService executor,\n            final Supplier<Date> currentTimeProvider, DataServiceOptions dataServiceOptions) {\n        this.expression = expression;\n        this.disconnectTimeoutMs = disconnectTimeoutMs;\n        this.connectionManager = connectionManager;\n        this.state = new AwaitConnectTime();\n        this.executor = executor;\n        this.currentTimeProvider = currentTimeProvider;\n        this.dataServiceOptions = dataServiceOptions;\n\n        updateState(State::onEnterState);\n        executor.scheduleWithFixedDelay(new TimeShiftDetector(60000), 0, 1, TimeUnit.MINUTES);\n    }\n\n    private interface State {\n        public default State onEnterState() {\n            return this;\n        }\n\n        public default State onConnectionEstablished() {\n            return this;\n        }\n\n        public default State onMessageEvent() {\n            return this;\n        }\n\n        public default State onConnectionLost() {\n            return this;\n        }\n\n        public default State onTimeout() {\n            return this;\n        }\n\n        public default State onPublish(String topic, byte[] payload, int qos, boolean retain, int priority) {\n            return this;\n        }\n    }\n\n    private class AwaitConnectTime implements State {\n\n        @Override\n        public State onEnterState() {\n\n            Optional<StoredMessage> dm = connectionManager.getNextMessage();\n\n            if (dm.isPresent()\n                    && dm.get().getPriority() <= dataServiceOptions.getConnectionSchedulePriorityOverridePriority()) {\n                logger.info(\n                        \"Priority message sent while disconnecting. Initiating Connection to send message with a high priority.\");\n                return new AwaitConnect();\n            }\n\n            final Date now = currentTimeProvider.get();\n\n            final Date nextTick = expression.getNextValidTimeAfter(now);\n\n            final long delay = Math.max(1, nextTick.getTime() - now.getTime());\n\n            logger.info(\"Connection scheduled at {} in {} ms\", nextTick, delay);\n\n            rescheduleTimeout(delay);\n\n            return this;\n        }\n\n        @Override\n        public State onTimeout() {\n\n            return new AwaitConnect();\n        }\n\n        @Override\n        public State onPublish(String topic, byte[] payload, int qos, boolean retain, int priority) {\n\n            if (dataServiceOptions.isConnectionSchedulePriorityOverrideEnabled()\n                    && priority <= dataServiceOptions.getConnectionSchedulePriorityOverridePriority()\n                    && !connectionManager.isConnected()) {\n                logger.info(\"Initiating Connection to send message with a high priority.\");\n\n                return new AwaitConnect();\n            }\n\n            return this;\n        }\n\n    }\n\n    private class AwaitConnect implements State {\n\n        @Override\n        public State onEnterState() {\n            if (connectionManager.isConnected()) {\n                return new AwaitDisconnectTime();\n            } else {\n                connectionManager.startConnectionTask();\n                return this;\n            }\n        }\n\n        @Override\n        public State onConnectionLost() {\n            connectionManager.startConnectionTask();\n            return this;\n        }\n\n        @Override\n        public State onConnectionEstablished() {\n            return new AwaitDisconnectTime();\n        }\n\n    }\n\n    private class AwaitDisconnectTime implements State {\n\n        @Override\n        public State onEnterState() {\n            return onMessageEvent();\n        }\n\n        @Override\n        public State onConnectionLost() {\n            return new AwaitConnect();\n        }\n\n        @Override\n        public State onMessageEvent() {\n\n            rescheduleTimeout(disconnectTimeoutMs);\n\n            return this;\n        }\n\n        @Override\n        public State onTimeout() {\n            if (connectionManager.hasInFlightMessages()) {\n                return this;\n            } else {\n                return new AwaitDisconnect();\n            }\n        }\n    }\n\n    private class AwaitDisconnect implements State {\n\n        @Override\n        public State onEnterState() {\n            connectionManager.stopConnectionTask();\n            connectionManager.disconnect();\n            return this;\n        }\n\n        @Override\n        public State onConnectionLost() {\n            return new AwaitConnectTime();\n        }\n\n        @Override\n        public State onMessageEvent() {\n            return this;\n        }\n    }\n\n    private void rescheduleTimeout(final long timeoutMs) {\n        cancelTimeout();\n\n        this.timeout = Optional.of(executor.schedule(() -> updateState(State::onTimeout), timeoutMs,\n                TimeUnit.MILLISECONDS));\n    }\n\n    private void cancelTimeout() {\n        final Optional<ScheduledFuture<?>> currentFuture = this.timeout;\n\n        if (currentFuture.isPresent()) {\n            currentFuture.get().cancel(false);\n        }\n    }\n\n    private void updateState(final UnaryOperator<State> transition) {\n        executor.execute(() -> updateStateInternal(transition));\n    }\n\n    private void updateStateInternal(final UnaryOperator<State> transitionFunction) {\n        final Optional<ScheduledFuture<?>> currentFuture = this.timeout;\n\n        final State nextState = transitionFunction.apply(this.state);\n\n        if (nextState != this.state) {\n            logger.info(\"State change: {} -> {}\", state.getClass().getSimpleName(),\n                    nextState.getClass().getSimpleName());\n            currentFuture.ifPresent(c -> c.cancel(false));\n\n            this.state = nextState;\n            updateStateInternal(State::onEnterState);\n        }\n    }\n\n    private class TimeShiftDetector implements Runnable {\n        private OptionalLong previousTimestamp = OptionalLong.empty();\n        private final long expectedDelay;\n\n        public TimeShiftDetector(final long expectedTickRate) {\n            this.expectedDelay = expectedTickRate;\n        }\n\n        public void run() {\n            final long now = System.currentTimeMillis();\n\n            final OptionalLong previous = this.previousTimestamp;\n\n            if (!previous.isPresent()) {\n                this.previousTimestamp = OptionalLong.of(now);\n                return;\n            }\n\n            if (now < previous.getAsLong() || Math.abs((now - previous.getAsLong()) - expectedDelay) > 60000) {\n                logger.warn(\"Time shift detected, reinitializing connection schedule\");\n                updateState(c -> new AwaitConnectTime());\n            }\n\n            this.previousTimestamp = OptionalLong.of(now);\n\n        }\n\n    }\n\n    @Override\n    public void shutdown() {\n        executor.execute(() -> {\n            cancelTimeout();\n            executor.shutdown();\n        });\n\n        try {\n            executor.awaitTermination(30, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            logger.warn(\"Interrupted while waiting for executor shutdown\");\n        }\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        updateState(State::onConnectionEstablished);\n    }\n\n    @Override\n    public void onDisconnecting() {\n        // no need\n    }\n\n    @Override\n    public void onDisconnected() {\n        updateState(State::onConnectionLost);\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        updateState(State::onConnectionLost);\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n        // no need\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        updateState(State::onMessageEvent);\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        updateState(State::onMessageEvent);\n    }\n\n    @Override\n    public void onPublishRequested(String topic, byte[] payload, int qos, boolean retain, int priority) {\n        this.updateState(c -> this.state.onPublish(topic, payload, qos, retain, priority));\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/store/HouseKeeperTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data.store;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Housekeeper Task which periodically purges confirmed messages from the local\n * database.\n * It also contains the total number of messages in the system to a given cap.\n */\npublic class HouseKeeperTask implements Runnable {\n\n    private static final Logger logger = LoggerFactory.getLogger(HouseKeeperTask.class);\n\n    private final int purgeAge;\n    private final MessageStoreState store;\n\n    public HouseKeeperTask(MessageStoreState store, int purgeAge) {\n        this.purgeAge = purgeAge;\n        this.store = store;\n    }\n\n    @Override\n    public void run() {\n        try {\n            Thread.currentThread().setName(getClass().getSimpleName());\n            logger.info(\"HouseKeeperTask started.\");\n\n            //\n            // delete all confirmed messages\n            logger.info(\"HouseKeeperTask: Delete confirmed messages...\");\n            this.store.getOrOpenMessageStore().deleteStaleMessages(this.purgeAge);\n\n            logger.info(\"HouseKeeperTask ended.\");\n        } catch (KuraStoreException me) { // do not throw the exception as that will stop future executions\n            logger.warn(\"HouseCleaningTask exception\", me);\n        } catch (Throwable t) { // do not throw the exception as that will stop future executions\n            if (t instanceof InterruptedException) {\n                logger.info(\"HouseCleaningTask stopped\");\n            } else {\n                logger.warn(\"HouseCleaningTask exception\", t);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/store/MessageStoreState.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.data.store;\n\nimport java.util.Optional;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.core.data.DataServiceOptions;\nimport org.eclipse.kura.message.store.provider.MessageStore;\nimport org.eclipse.kura.message.store.provider.MessageStoreProvider;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class MessageStoreState {\n\n    private static final Logger logger = LoggerFactory.getLogger(MessageStoreState.class);\n\n    private final MessageStoreProvider messageStoreProvider;\n\n    private DataServiceOptions options;\n    private Optional<MessageStore> messageStore = Optional.empty();\n    private Optional<ScheduledExecutorService> houseKeeperExecutor = Optional.empty();\n\n    public MessageStoreState(final MessageStoreProvider messageStoreProvider, final DataServiceOptions options) {\n\n        this.messageStoreProvider = messageStoreProvider;\n\n        update(options);\n    }\n\n    public synchronized void update(final DataServiceOptions dataServiceOptions) {\n        this.options = dataServiceOptions;\n\n        shutdown();\n\n        if (!this.houseKeeperExecutor.isPresent()) {\n            this.houseKeeperExecutor = Optional.of(Executors.newSingleThreadScheduledExecutor());\n            this.houseKeeperExecutor.get().scheduleWithFixedDelay(\n                    new HouseKeeperTask(this, dataServiceOptions.getStorePurgeAge()), 1, // start in one second\n                    dataServiceOptions.getStoreHousekeeperInterval(), // repeat every retryInterval until we stopped.\n                    TimeUnit.SECONDS);\n        }\n    }\n\n    public MessageStoreProvider getMessageStoreProvider() {\n        return messageStoreProvider;\n    }\n\n    public synchronized MessageStore getOrOpenMessageStore() throws KuraStoreException {\n        if (this.messageStore.isPresent()) {\n            return this.messageStore.get();\n        }\n\n        return this.openMessageStore();\n    }\n\n    public synchronized MessageStore openMessageStore() throws KuraStoreException {\n\n        final MessageStore result = this.messageStoreProvider.openMessageStore(this.options.getKuraServicePid());\n\n        this.messageStore = Optional.of(result);\n\n        return result;\n    }\n\n    public synchronized void shutdown() {\n        if (this.houseKeeperExecutor.isPresent()) {\n            this.houseKeeperExecutor.get().shutdown();\n            try {\n                this.houseKeeperExecutor.get().awaitTermination(30, TimeUnit.SECONDS);\n            } catch (final InterruptedException e) {\n                logger.warn(\"Interrupted while waiting for housekeeper task shutdown\", e);\n                Thread.currentThread().interrupt();\n            }\n            this.houseKeeperExecutor = Optional.empty();\n        }\n\n        if (this.messageStore.isPresent()) {\n            this.messageStore.get().close();\n            this.messageStore = Optional.empty();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/transport/mqtt/DataTransportListenerS.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data.transport.mqtt;\n\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/*\n * The following represents an exception to Semantic Versioning conventions.\n * Though the class implements the org.eclipse.kura.data.transport.listener.DataTransportListener API,\n * it is actually an API consumer (it calls into the API implementors).\n */\nclass DataTransportListenerS implements DataTransportListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(DataTransportListenerS.class);\n\n    private static final String DATA_TRANSPORT_LISTENER_REFERENCE = \"DataTransportListener\";\n\n    private final ComponentContext ctx;\n    private final List<DataTransportListener> listeners;\n\n    public DataTransportListenerS(ComponentContext ctx) {\n        this.ctx = ctx;\n        this.listeners = new CopyOnWriteArrayList<>();\n    }\n\n    @Override\n    public void onConnectionEstablished(boolean newSession) {\n        Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataTransportListener) service).onConnectionEstablished(newSession);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onConnectionEstablished\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataTransportListener listener : this.listeners) {\n                try {\n                    listener.onConnectionEstablished(newSession);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onConnectionEstablished\");\n        }\n    }\n\n    @Override\n    public void onDisconnecting() {\n        Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataTransportListener) service).onDisconnecting();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onDisconnecting\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataTransportListener listener : this.listeners) {\n                try {\n                    listener.onDisconnecting();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onDisconnecting\");\n        }\n    }\n\n    @Override\n    public void onDisconnected() {\n        Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataTransportListener) service).onDisconnected();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onDisconnected\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataTransportListener listener : this.listeners) {\n                try {\n                    listener.onDisconnected();\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onDisconnected\");\n        }\n    }\n\n    @Override\n    public void onConfigurationUpdating(boolean wasConnected) {\n        Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataTransportListener) service).onConfigurationUpdating(wasConnected);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onConfigurationUpdating\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataTransportListener listener : this.listeners) {\n                try {\n                    listener.onConfigurationUpdating(wasConnected);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onConfigurationUpdating\");\n        }\n    }\n\n    @Override\n    public void onConfigurationUpdated(boolean wasConnected) {\n        Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataTransportListener) service).onConfigurationUpdated(wasConnected);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onConfigurationUpdated\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataTransportListener listener : this.listeners) {\n                try {\n                    listener.onConfigurationUpdated(wasConnected);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onConfigurationUpdated\");\n        }\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataTransportListener) service).onConnectionLost(cause);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onConnectionLost\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataTransportListener listener : this.listeners) {\n                try {\n                    listener.onConnectionLost(cause);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onConnectionLost\");\n        }\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n        Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataTransportListener) service).onMessageArrived(topic, payload, qos,\n                            retained);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onMessageArrived\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataTransportListener listener : this.listeners) {\n                try {\n                    listener.onMessageArrived(topic, payload, qos, retained);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onMessageArrived\");\n        }\n    }\n\n    @Override\n    public void onMessageConfirmed(DataTransportToken token) {\n        Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE);\n        if (services != null) {\n            for (Object service : services) {\n                try {\n                    ((org.eclipse.kura.data.DataTransportListener) service).onMessageConfirmed(token);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.debug(\"No registered listener services. Ignoring onMessageConfirmed\");\n        }\n\n        if (!this.listeners.isEmpty()) {\n            for (DataTransportListener listener : this.listeners) {\n                try {\n                    listener.onMessageConfirmed(token);\n                } catch (Throwable t) {\n                    logger.warn(\"Unexpected Throwable\", t);\n                }\n            }\n        } else {\n            logger.warn(\"No registered listeners. Ignoring onMessageConfirmed\");\n        }\n    }\n\n    public void add(DataTransportListener listener) {\n        this.listeners.add(listener);\n    }\n\n    public void remove(DataTransportListener listener) {\n        this.listeners.remove(listener);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/transport/mqtt/MqttClientConfiguration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data.transport.mqtt;\n\nimport org.eclipse.paho.client.mqttv3.MqttConnectOptions;\n\npublic class MqttClientConfiguration {\n\n    private final String brokerUrl;\n    private final String clientId;\n    private final PersistenceType persistenceType;\n    private final MqttConnectOptions connectOptions;\n\n    public enum PersistenceType {\n        FILE,\n        MEMORY\n    }\n\n    public MqttClientConfiguration(String brokerUrl, String clientId, PersistenceType persistenceType,\n            MqttConnectOptions connectOptions) {\n        super();\n        this.brokerUrl = brokerUrl;\n        this.clientId = clientId;\n        this.persistenceType = persistenceType;\n        this.connectOptions = connectOptions;\n    }\n\n    public String getBrokerUrl() {\n        return this.brokerUrl;\n    }\n\n    public String getClientId() {\n        return this.clientId;\n    }\n\n    public PersistenceType getPersistenceType() {\n        return this.persistenceType;\n    }\n\n    public MqttConnectOptions getConnectOptions() {\n        return this.connectOptions;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/transport/mqtt/MqttDataTransport.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.data.transport.mqtt;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport javax.net.ssl.SSLSocketFactory;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraNotConnectedException;\nimport org.eclipse.kura.KuraTimeoutException;\nimport org.eclipse.kura.KuraTooManyInflightMessagesException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.core.data.transport.mqtt.MqttClientConfiguration.PersistenceType;\nimport org.eclipse.kura.core.util.ValidationUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.eclipse.kura.ssl.SslManagerService;\nimport org.eclipse.kura.ssl.SslServiceListener;\nimport org.eclipse.kura.status.CloudConnectionStatusComponent;\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\nimport org.eclipse.kura.status.CloudConnectionStatusService;\nimport org.eclipse.kura.system.SystemService;\nimport org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;\nimport org.eclipse.paho.client.mqttv3.IMqttToken;\nimport org.eclipse.paho.client.mqttv3.MqttAsyncClient;\nimport org.eclipse.paho.client.mqttv3.MqttCallback;\nimport org.eclipse.paho.client.mqttv3.MqttClientPersistence;\nimport org.eclipse.paho.client.mqttv3.MqttConnectOptions;\nimport org.eclipse.paho.client.mqttv3.MqttException;\nimport org.eclipse.paho.client.mqttv3.MqttMessage;\nimport org.eclipse.paho.client.mqttv3.MqttPersistenceException;\nimport org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;\nimport org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@SuppressWarnings(\"java:S2789\")\npublic class MqttDataTransport implements DataTransportService, MqttCallback, ConfigurableComponent, SslServiceListener,\n        CloudConnectionStatusComponent {\n\n    private static final String NOT_CONNECTED_MESSAGE = \"Not connected\";\n\n    private static final String ALREADY_CONNECTED_MESSAGE = \"Already connected\";\n\n    private static final String INVALID_CONFIGURATION_MESSAGE = \"Invalid configuration\";\n\n    private static final Logger logger = LoggerFactory.getLogger(MqttDataTransport.class);\n\n    private static final String MQTT_SCHEME = \"mqtt://\";\n    private static final String MQTTS_SCHEME = \"mqtts://\";\n\n    // '#' followed by one or more non-whitespace but not the '/'\n    private static final String TOPIC_PATTERN_STRING = \"#([^\\\\s/]+)\";\n\n    private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING);\n\n    private static final String MQTT_BROKER_URL_PROP_NAME = \"broker-url\";\n    private static final String MQTT_USERNAME_PROP_NAME = \"username\";\n    private static final String MQTT_PASSWORD_PROP_NAME = \"password\";\n    private static final String MQTT_CLIENT_ID_PROP_NAME = \"client-id\";\n    private static final String MQTT_KEEP_ALIVE_PROP_NAME = \"keep-alive\";\n    private static final String MQTT_CLEAN_SESSION_PROP_NAME = \"clean-session\";\n\n    // All timeouts\n    private static final String MQTT_TIMEOUT_PROP_NAME = \"timeout\";\n\n    private static final String MQTT_DEFAULT_VERSION_PROP_NAME = \"protocol-version\";\n\n    private static final String MQTT_LWT_QOS_PROP_NAME = \"lwt.qos\";\n    private static final String MQTT_LWT_RETAIN_PROP_NAME = \"lwt.retain\";\n    private static final String MQTT_LWT_TOPIC_PROP_NAME = \"lwt.topic\";\n    private static final String MQTT_LWT_PAYLOAD_PROP_NAME = \"lwt.payload\";\n\n    private static final String CLOUD_ACCOUNT_NAME_PROP_NAME = \"topic.context.account-name\";\n\n    private static final String PERSISTENCE_TYPE_PROP_NAME = \"in-flight.persistence\";\n\n    private static final String TOPIC_ACCOUNT_NAME_CTX_NAME = \"account-name\";\n    private static final String TOPIC_DEVICE_ID_CTX_NAME = \"client-id\";\n\n    private static final long MQTT_QUIESCE_TIMEOUT = 2000;\n    private static final long MQTT_DISCONNECT_TIMEOUT = 2000;\n\n    private SystemService systemService;\n    private Optional<SslManagerService> sslManagerService;\n    private CloudConnectionStatusService cloudConnectionStatusService;\n\n    private CloudConnectionStatusEnum notificationStatus = CloudConnectionStatusEnum.OFF;\n\n    private MqttAsyncClient mqttClient;\n\n    private DataTransportListenerS dataTransportListeners;\n\n    private MqttClientConfiguration clientConf;\n    private boolean newSession;\n    private String sessionId;\n\n    private PersistenceType persistenceType;\n    private MqttClientPersistence persistence;\n\n    private final Map<String, String> topicContext = new HashMap<>();\n    private final Map<String, Object> properties = new HashMap<>();\n\n    private CryptoService cryptoService;\n\n    private final Object updateLock = new Object();\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    public void unsetSystemService(SystemService systemService) {\n        this.systemService = null;\n    }\n\n    public void setSslManagerService(SslManagerService sslManagerService) {\n        final boolean update;\n\n        synchronized (this.updateLock) {\n            this.sslManagerService = Optional.of(sslManagerService);\n            update = this.clientConf != null;\n        }\n\n        if (update) {\n            update();\n        }\n    }\n\n    public void unsetSslManagerService(SslManagerService sslManagerService) {\n        synchronized (this.updateLock) {\n            if (Optional.of(sslManagerService).equals(this.sslManagerService)) {\n                this.sslManagerService = Optional.empty();\n            }\n        }\n    }\n\n    public void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void unsetCryptoService(CryptoService cryptoService) {\n        this.cryptoService = null;\n    }\n\n    public void setCloudConnectionStatusService(CloudConnectionStatusService cloudConnectionStatusService) {\n        this.cloudConnectionStatusService = cloudConnectionStatusService;\n    }\n\n    public void unsetCloudConnectionStatusService(CloudConnectionStatusService cloudConnectionStatusService) {\n        this.cloudConnectionStatusService = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        synchronized (this.updateLock) {\n            logger.info(\"Activating {}...\", properties.get(ConfigurationService.KURA_SERVICE_PID));\n\n            // We need to catch the configuration exception and activate anyway.\n            // Otherwise the ConfigurationService will not be able to track us.\n            HashMap<String, Object> decryptedPropertiesMap = new HashMap<>();\n\n            for (Map.Entry<String, Object> entry : properties.entrySet()) {\n                String key = entry.getKey();\n                Object value = entry.getValue();\n                if (key.equals(MQTT_PASSWORD_PROP_NAME)) {\n                    try {\n                        Password decryptedPassword = new Password(\n                                this.cryptoService.decryptAes(((String) value).toCharArray()));\n                        decryptedPropertiesMap.put(key, decryptedPassword);\n                    } catch (Exception e) {\n                        logger.info(\"Password is not encrypted\");\n                        decryptedPropertiesMap.put(key, new Password((String) value));\n                    }\n                } else {\n                    decryptedPropertiesMap.put(key, value);\n                }\n            }\n\n            this.properties.putAll(decryptedPropertiesMap);\n            try {\n                this.clientConf = buildConfiguration(this.properties);\n            } catch (RuntimeException e) {\n                logger.error(\n                        \"Invalid client configuration. Service will not be able to connect until the configuration is updated\",\n                        e);\n            }\n\n            this.dataTransportListeners = new DataTransportListenerS(componentContext);\n\n            // Do nothing waiting for the connect request from the upper layer.\n        }\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.debug(\"Deactivating {}...\", this.properties.get(ConfigurationService.KURA_SERVICE_PID));\n\n        // Before deactivating us, the OSGi container should have first\n        // deactivated all dependent components.\n        // They should be able to complete whatever is needed,\n        // e.g. publishing a special last message,\n        // synchronously in their deactivate method and disconnect us cleanly.\n        // There shouldn't be anything to do here other then\n        // perhaps forcibly disconnecting the MQTT client if not already done.\n        if (isConnected()) {\n            disconnect(0);\n        }\n    }\n\n    public void updated(Map<String, Object> properties) {\n        synchronized (this.updateLock) {\n            logger.info(\"Updating {}...\", properties.get(ConfigurationService.KURA_SERVICE_PID));\n\n            this.properties.clear();\n\n            HashMap<String, Object> decryptedPropertiesMap = new HashMap<>();\n\n            for (Map.Entry<String, Object> entry : properties.entrySet()) {\n                String key = entry.getKey();\n                Object value = entry.getValue();\n                if (key.equals(MQTT_PASSWORD_PROP_NAME)) {\n                    try {\n                        Password decryptedPassword = new Password(\n                                this.cryptoService.decryptAes(((String) value).toCharArray()));\n                        decryptedPropertiesMap.put(key, decryptedPassword);\n                    } catch (Exception e) {\n                        logger.info(\"Password is not encrypted\");\n                        decryptedPropertiesMap.put(key, new Password((String) value));\n                    }\n                } else {\n                    decryptedPropertiesMap.put(key, value);\n                }\n            }\n\n            this.properties.putAll(decryptedPropertiesMap);\n\n        }\n\n        update();\n\n    }\n\n    private void update() {\n        boolean wasConnected = isConnected();\n\n        // First notify the Listeners\n        // We do nothing other than notifying the listeners which may later\n        // request to disconnect and reconnect again.\n        this.dataTransportListeners.onConfigurationUpdating(wasConnected);\n\n        // Then update the configuration\n        // Throwing a RuntimeException here is fine.\n        // Listeners will not be notified of an invalid configuration update.\n        logger.info(\"Building new configuration...\");\n\n        synchronized (this.updateLock) {\n            this.clientConf = buildConfiguration(this.properties);\n        }\n\n        // We do nothing other than notifying the listeners which may later\n        // request to disconnect and reconnect again.\n        this.dataTransportListeners.onConfigurationUpdated(wasConnected);\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public synchronized void connect() throws KuraConnectException {\n        // We treat this as an application bug.\n        if (isConnected()) {\n            logger.error(ALREADY_CONNECTED_MESSAGE);\n            throw new IllegalStateException(ALREADY_CONNECTED_MESSAGE);\n        }\n\n        // Attempt to setup the MQTT session\n\n        try {\n            setupMqttSession();\n        } catch (RuntimeException e) {\n            throw new KuraConnectException(e, \"Unexpected exception setting up MQTT session\");\n        }\n\n        if (this.mqttClient == null) {\n            logger.error(INVALID_CONFIGURATION_MESSAGE);\n            throw new IllegalStateException(INVALID_CONFIGURATION_MESSAGE);\n        }\n\n        logger.info(\"# ------------------------------------------------------------\");\n        logger.info(\"#  Connection Properties\");\n        logger.info(\"#  broker    = {}\", this.clientConf.getBrokerUrl());\n        logger.info(\"#  clientId  = {}\", this.clientConf.getClientId());\n        logger.info(\"#  username  = {}\", this.clientConf.getConnectOptions().getUserName());\n        logger.info(\"#  password  = XXXXXXXXXXXXXX\");\n        logger.info(\"#  keepAlive = {}\", this.clientConf.getConnectOptions().getKeepAliveInterval());\n        logger.info(\"#  timeout   = {}\", this.clientConf.getConnectOptions().getConnectionTimeout());\n        logger.info(\"#  cleanSession    = {}\", this.clientConf.getConnectOptions().isCleanSession());\n        logger.info(\"#  MQTT version    = {}\",\n                getMqttVersionLabel(this.clientConf.getConnectOptions().getMqttVersion()));\n        logger.info(\"#  willDestination = {}\", this.clientConf.getConnectOptions().getWillDestination());\n        logger.info(\"#  willMessage     = {}\", this.clientConf.getConnectOptions().getWillMessage());\n        logger.info(\"#\");\n        logger.info(\"#  Connecting...\");\n\n        // Register the component in the CloudConnectionStatus service\n        this.cloudConnectionStatusService.register(this);\n        // Update status notification service\n        this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.FAST_BLINKING);\n\n        //\n        // connect\n        try {\n            IMqttToken connectToken = this.mqttClient.connect(this.clientConf.getConnectOptions());\n            connectToken.waitForCompletion(getTimeToWaitMillis() * 3);\n            logger.info(\"#  Connected!\");\n            logger.info(\"# ------------------------------------------------------------\");\n\n            // Update status notification service\n            this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.ON);\n\n        } catch (MqttException e) {\n            logger.warn(\"xxxxx  Connect failed. Forcing disconnect. xxxxx\");\n            closeMqttClient();\n\n            // Update status notification service\n            this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.OFF);\n\n            throw new KuraConnectException(e, \"Cannot connect\");\n        } finally {\n            // Always unregister from CloudConnectionStatus service so to switch to the\n            // previous state\n            this.cloudConnectionStatusService.unregister(this);\n        }\n\n        // notify the listeners\n        this.dataTransportListeners.onConnectionEstablished(this.newSession);\n    }\n\n    @Override\n    public boolean isConnected() {\n        if (this.mqttClient != null) {\n            return this.mqttClient.isConnected();\n        }\n        return false;\n    }\n\n    @Override\n    public String getBrokerUrl() {\n        if (this.clientConf != null) {\n            String brokerUrl = this.clientConf.getBrokerUrl();\n            if (brokerUrl != null) {\n                return brokerUrl;\n            }\n        }\n        return \"\";\n    }\n\n    @Override\n    public String getAccountName() {\n        if (this.clientConf != null) {\n            String accountName = this.topicContext.get(TOPIC_ACCOUNT_NAME_CTX_NAME);\n            if (accountName != null) {\n                return accountName;\n            }\n        }\n        return \"\";\n    }\n\n    @Override\n    public String getUsername() {\n        if (this.clientConf != null) {\n            String username = this.clientConf.getConnectOptions().getUserName();\n            if (username != null) {\n                return username;\n            }\n        }\n        return \"\";\n    }\n\n    @Override\n    public String getClientId() {\n        if (this.clientConf != null) {\n            String clientId = this.clientConf.getClientId();\n            if (clientId != null) {\n                return clientId;\n            }\n        }\n        return \"\";\n    }\n\n    @Override\n    public synchronized void disconnect(long quiesceTimeout) {\n        // Disconnect the client if it's connected. If it fails log the\n        // exception.\n        // Don't throw an exception because the caller would not\n        // be able to handle it.\n        if (isConnected()) {\n            logger.info(\"Disconnecting...\");\n\n            //\n            // notify the listeners\n            this.dataTransportListeners.onDisconnecting();\n\n            try {\n                this.mqttClient.disconnect(quiesceTimeout).waitForCompletion(getTimeToWaitMillis());\n                logger.info(\"Disconnected\");\n            } catch (MqttException e) {\n                logger.error(\"Disconnect failed\", e);\n            }\n\n            //\n            // notify the listeners\n            this.dataTransportListeners.onDisconnected();\n        } else {\n            logger.warn(\"MQTT client already disconnected\");\n        }\n    }\n\n    // ---------------------------------------------------------\n    //\n    // Subscription Management Methods\n    //\n    // ---------------------------------------------------------\n\n    @Override\n    public void subscribe(String topic, int qos) throws KuraException {\n\n        if (this.mqttClient == null || !this.mqttClient.isConnected()) {\n            throw new KuraNotConnectedException(NOT_CONNECTED_MESSAGE);\n        }\n\n        topic = replaceTopicVariables(topic);\n\n        logger.info(\"Subscribing to topic: {} with QoS: {}\", topic, qos);\n\n        try {\n            IMqttToken token = this.mqttClient.subscribe(topic, qos);\n            token.waitForCompletion(getTimeToWaitMillis());\n        } catch (MqttException e) {\n            if (e.getReasonCode() == MqttException.REASON_CODE_CLIENT_TIMEOUT) {\n                logger.warn(\"Timeout subscribing to topic: {}\", topic);\n                throw new KuraTimeoutException(\"Timeout subscribing to topic: \" + topic, e);\n            } else {\n                logger.error(\"Cannot subscribe to topic: \" + topic, e);\n                throw KuraException.internalError(e, \"Cannot subscribe to topic: \" + topic);\n            }\n        }\n    }\n\n    @Override\n    public void unsubscribe(String topic) throws KuraException {\n\n        if (this.mqttClient == null || !this.mqttClient.isConnected()) {\n            throw new KuraNotConnectedException(NOT_CONNECTED_MESSAGE);\n        }\n\n        topic = replaceTopicVariables(topic);\n\n        logger.info(\"Unsubscribing to topic: {}\", topic);\n\n        try {\n            IMqttToken token = this.mqttClient.unsubscribe(topic);\n            token.waitForCompletion(getTimeToWaitMillis());\n        } catch (MqttException e) {\n            if (e.getReasonCode() == MqttException.REASON_CODE_CLIENT_TIMEOUT) {\n                logger.warn(\"Timeout unsubscribing to topic: {}\", topic);\n                throw new KuraTimeoutException(\"Timeout unsubscribing to topic: \" + topic, e);\n            } else {\n                logger.error(\"Cannot unsubscribe to topic: \" + topic, e);\n                throw KuraException.internalError(e, \"Cannot unsubscribe to topic: \" + topic);\n            }\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.eclipse.kura.data.DataPublisherService#publish(java.lang.String\n     * , byte[], int, boolean)\n     *\n     * DataConnectException this can be easily recovered connecting the service.\n     * TooManyInflightMessagesException the caller SHOULD retry publishing the\n     * message at a later time. RuntimeException (unchecked) all other\n     * unrecoverable faults that are not recoverable by the caller.\n     */\n    @Override\n    public DataTransportToken publish(String topic, byte[] payload, int qos, boolean retain) throws KuraException {\n\n        if (this.mqttClient == null || !this.mqttClient.isConnected()) {\n            throw new KuraNotConnectedException(NOT_CONNECTED_MESSAGE);\n        }\n\n        topic = replaceTopicVariables(topic);\n\n        logger.info(\"Publishing message on topic: {} with QoS: {}\", topic, qos);\n\n        MqttMessage message = new MqttMessage();\n        message.setPayload(payload);\n        message.setQos(qos);\n        message.setRetained(retain);\n\n        Integer messageId = null;\n        try {\n            IMqttDeliveryToken token = this.mqttClient.publish(topic, message);\n            // At present Paho ALWAYS allocates (gets and increments) internally\n            // a message ID,\n            // even for messages published with QoS == 0.\n            // Of course, for QoS == 0 this \"internal\" message ID will not hit\n            // the wire.\n            // On top of that, messages published with QoS == 0 are confirmed\n            // in the deliveryComplete callback.\n            // Another implementation might behave differently\n            // and only allocate a message ID for messages published with QoS >\n            // 0.\n            // We don't want to rely on this and only return and confirm IDs\n            // of messages published with QoS > 0.\n            logger.debug(\"Published message with ID: {}\", token.getMessageId());\n            if (qos > 0) {\n                messageId = Integer.valueOf(token.getMessageId());\n            }\n        } catch (MqttPersistenceException e) {\n            // This is probably an unrecoverable internal error\n            logger.error(\"Cannot publish on topic: {}\", topic, e);\n            throw new IllegalStateException(\"Cannot publish on topic: \" + topic);\n        } catch (MqttException e) {\n            if (e.getReasonCode() == MqttException.REASON_CODE_MAX_INFLIGHT) {\n                logger.info(\"Too many inflight messages\");\n                throw new KuraTooManyInflightMessagesException(e, \"Too many in-fligh messages\");\n            } else {\n                logger.error(\"Cannot publish on topic: \" + topic, e);\n                throw KuraException.internalError(e, \"Cannot publish on topic: \" + topic);\n            }\n        }\n\n        DataTransportToken token = null;\n        if (messageId != null) {\n            token = new DataTransportToken(messageId, this.sessionId);\n        }\n\n        return token;\n    }\n\n    @Override\n    public void addDataTransportListener(DataTransportListener listener) {\n        this.dataTransportListeners.add(listener);\n    }\n\n    @Override\n    public void removeDataTransportListener(DataTransportListener listener) {\n        this.dataTransportListeners.remove(listener);\n    }\n\n    // ---------------------------------------------------------\n    //\n    // MqttCallback methods\n    //\n    // ---------------------------------------------------------\n    @Override\n    public void connectionLost(final Throwable cause) {\n        logger.warn(\"Connection Lost\", cause);\n\n        // notify the listeners\n        this.dataTransportListeners.onConnectionLost(cause);\n    }\n\n    @Override\n    public void deliveryComplete(IMqttDeliveryToken token) {\n\n        if (token == null) {\n            logger.error(\"null token\");\n            return;\n        }\n\n        // Weird, tokens related to messages published with QoS > 0 have a null\n        // nested message\n\n        MqttMessage msg = null;\n        try {\n            msg = token.getMessage();\n        } catch (MqttException e) {\n            logger.error(\"Cannot get message\", e);\n            return;\n        }\n\n        if (msg != null) {\n            // Note that Paho call this also for messages published with QoS ==\n            // 0.\n            // We don't want to rely on that and we drop asynchronous confirms\n            // for QoS == 0.\n            int qos = msg.getQos();\n\n            if (qos == 0) {\n                logger.debug(\"Ignoring deliveryComplete for messages published with QoS == 0\");\n                return;\n            }\n        }\n\n        int id = token.getMessageId();\n\n        logger.debug(\"Delivery complete for message with ID: {}\", id);\n\n        // FIXME: We should be more selective here and only call the listener\n        // that actually published the message.\n        // Anyway we don't have such a mapping and so the publishers MUST track\n        // their own\n        // identifiers and filter confirms.\n\n        // FIXME: it can happen that the listener that has published the message\n        // has not come up yet.\n        // This is the scenario:\n        // * Paho has some in-flight messages.\n        // * Kura gets stopped, crashes or the power is removed.\n        // * Kura starts again, Paho connects and restores in-flight messages\n        // from its persistence.\n        // * These messages are delivered (this callback gets called) before the\n        // publisher (also a DataPublisherListener)\n        // * has come up (not yet tracked by the OSGi container).\n        // These confirms will be lost!\n\n        // notify the listeners\n        DataTransportToken dataPublisherToken = new DataTransportToken(id, this.sessionId);\n        this.dataTransportListeners.onMessageConfirmed(dataPublisherToken);\n    }\n\n    @Override\n    public void messageArrived(String topic, MqttMessage message) throws Exception {\n\n        logger.debug(\"Message arrived on topic: {}\", topic);\n\n        // FIXME: we should be more selective here and only call the listeners\n        // actually subscribed to this topic.\n        // Anyway we don't have such a mapping so the listeners are responsible\n        // to filter messages.\n\n        // FIXME: the same argument about lost confirms applies to arrived\n        // messages.\n\n        // notify the listeners\n        this.dataTransportListeners.onMessageArrived(topic, message.getPayload(), message.getQos(),\n                message.isRetained());\n    }\n\n    private long getTimeToWaitMillis() {\n        // We use the same value for every timeout\n        return this.clientConf.getConnectOptions().getConnectionTimeout() * 1000L;\n    }\n\n    // ---------------------------------------------------------\n    //\n    // SslServiceListener Overrides\n    //\n    // ---------------------------------------------------------\n    @Override\n    public void onConfigurationUpdated() {\n\n        // The SSL service was updated, build a new socket connection and close the\n        // current SSL client session\n        if (this.mqttClient != null && isSSL(this.mqttClient.getServerURI())) {\n            closeMqttClient();\n        }\n\n        update();\n\n    }\n\n    // ---------------------------------------------------------\n    //\n    // CloudConnectionStatus Overrides\n    //\n    // ---------------------------------------------------------\n    @Override\n    public int getNotificationPriority() {\n        return CloudConnectionStatusService.PRIORITY_MEDIUM;\n    }\n\n    @Override\n    public CloudConnectionStatusEnum getNotificationStatus() {\n        return this.notificationStatus;\n    }\n\n    @Override\n    public void setNotificationStatus(CloudConnectionStatusEnum status) {\n        this.notificationStatus = status;\n    }\n\n    // ---------------------------------------------------------\n    //\n    // Private methods\n    //\n    // ---------------------------------------------------------\n\n    /*\n     * This method builds an internal configuration option needed by the client\n     * to connect. The configuration is assembled from various sources:\n     * component configuration, SystemService, NetworkService, etc. The returned\n     * configuration is valid so no further validation is needed. If a valid\n     * configuration cannot be assembled the method throws a RuntimeException\n     * (assuming that this error is unrecoverable).\n     */\n    private MqttClientConfiguration buildConfiguration(Map<String, Object> properties) {\n\n        MqttClientConfiguration clientConfiguration;\n        MqttConnectOptions conOpt = new MqttConnectOptions();\n        String clientId = null;\n        String brokerUrl = null;\n        try {\n            // Configure the client ID\n            clientId = (String) properties.get(MQTT_CLIENT_ID_PROP_NAME);\n            if (clientId == null || clientId.trim().length() == 0) {\n                clientId = this.systemService.getPrimaryMacAddress();\n            }\n            ValidationUtil.notEmptyOrNull(clientId, \"clientId\");\n\n            // replace invalid token in the client ID as it is used as part of\n            // the topicname space\n            clientId = clientId.replace('/', '-');\n            clientId = clientId.replace('+', '-');\n            clientId = clientId.replace('#', '-');\n            clientId = clientId.replace('.', '-');\n\n            // Configure the broker URL\n            brokerUrl = (String) properties.get(MQTT_BROKER_URL_PROP_NAME);\n            ValidationUtil.notEmptyOrNull(brokerUrl, MQTT_BROKER_URL_PROP_NAME);\n            brokerUrl = brokerUrl.trim();\n\n            brokerUrl = brokerUrl.replaceAll(\"^\" + MQTT_SCHEME, \"tcp://\");\n            brokerUrl = brokerUrl.replaceAll(\"^\" + MQTTS_SCHEME, \"ssl://\");\n\n            brokerUrl = brokerUrl.replaceAll(\"/$\", \"\");\n            ValidationUtil.notEmptyOrNull(brokerUrl, \"brokerUrl\");\n\n            ValidationUtil.notNegative((Integer) properties.get(MQTT_KEEP_ALIVE_PROP_NAME), MQTT_KEEP_ALIVE_PROP_NAME);\n            ValidationUtil.notNegative((Integer) properties.get(MQTT_TIMEOUT_PROP_NAME), MQTT_TIMEOUT_PROP_NAME);\n\n            ValidationUtil.notNull(properties.get(MQTT_CLEAN_SESSION_PROP_NAME), MQTT_CLEAN_SESSION_PROP_NAME);\n\n            String userName = (String) properties.get(MQTT_USERNAME_PROP_NAME);\n            if (userName != null && !userName.isEmpty()) {\n                conOpt.setUserName(userName);\n            }\n\n            Password password = (Password) properties.get(MQTT_PASSWORD_PROP_NAME);\n            if (password != null && password.toString().length() != 0) {\n                conOpt.setPassword(password.getPassword());\n            }\n\n            conOpt.setKeepAliveInterval((Integer) properties.get(MQTT_KEEP_ALIVE_PROP_NAME));\n            conOpt.setConnectionTimeout((Integer) properties.get(MQTT_TIMEOUT_PROP_NAME));\n\n            conOpt.setCleanSession((Boolean) properties.get(MQTT_CLEAN_SESSION_PROP_NAME));\n\n            conOpt.setMqttVersion((Integer) properties.get(MQTT_DEFAULT_VERSION_PROP_NAME));\n            conOpt.setAutomaticReconnect(false);\n\n            synchronized (this.topicContext) {\n                this.topicContext.clear();\n                if (properties.get(CLOUD_ACCOUNT_NAME_PROP_NAME) != null) {\n                    this.topicContext.put(TOPIC_ACCOUNT_NAME_CTX_NAME,\n                            (String) properties.get(CLOUD_ACCOUNT_NAME_PROP_NAME));\n                }\n                this.topicContext.put(TOPIC_DEVICE_ID_CTX_NAME, clientId);\n            }\n\n            String willTopic = (String) properties.get(MQTT_LWT_TOPIC_PROP_NAME);\n            if (!(willTopic == null || willTopic.isEmpty())) {\n                int willQos = 0;\n                boolean willRetain = false;\n\n                String willPayload = (String) properties.get(MQTT_LWT_PAYLOAD_PROP_NAME);\n                if (properties.get(MQTT_LWT_QOS_PROP_NAME) != null) {\n                    willQos = (Integer) properties.get(MQTT_LWT_QOS_PROP_NAME);\n                }\n                if (properties.get(MQTT_LWT_RETAIN_PROP_NAME) != null) {\n                    willRetain = (Boolean) properties.get(MQTT_LWT_RETAIN_PROP_NAME);\n                }\n\n                willTopic = replaceTopicVariables(willTopic);\n\n                byte[] payload = {};\n                if (willPayload != null && !willPayload.isEmpty()) {\n                    payload = willPayload.getBytes(StandardCharsets.UTF_8);\n                }\n\n                conOpt.setWill(willTopic, payload, willQos, willRetain);\n            }\n        } catch (KuraException e) {\n            logger.error(INVALID_CONFIGURATION_MESSAGE);\n            throw new IllegalStateException(\"Invalid MQTT client configuration\", e);\n        }\n\n        //\n        // SSL\n        if (this.sslManagerService == null) {\n            logger.warn(\"SSL Manager Service not yet initialized.\");\n        } else {\n            if (isSSL(brokerUrl)) {\n                if (this.sslManagerService.isPresent()) {\n                    try {\n                        SSLSocketFactory ssf = this.sslManagerService.get().getSSLSocketFactory();\n                        conOpt.setSocketFactory(ssf);\n                    } catch (Exception e) {\n                        logger.error(\"SSL setup failed\", e);\n                        throw new IllegalStateException(\"SSL setup failed\");\n                    }\n                } else {\n                    logger.error(\"SSL Manager Service not selected.\");\n                }\n            }\n\n        }\n\n        String sType = (String) properties.get(PERSISTENCE_TYPE_PROP_NAME);\n        PersistenceType localPersistenceType = null;\n        if (\"file\".equals(sType)) {\n            localPersistenceType = PersistenceType.FILE;\n        } else if (\"memory\".equals(sType)) {\n            localPersistenceType = PersistenceType.MEMORY;\n        } else {\n            throw new IllegalStateException(\n                    \"Invalid MQTT client configuration: persistenceType: \" + localPersistenceType);\n        }\n\n        clientConfiguration = new MqttClientConfiguration(brokerUrl, clientId, localPersistenceType, conOpt);\n\n        return clientConfiguration;\n    }\n\n    private boolean isSSL(String brokerUrl) {\n        return brokerUrl.startsWith(\"ssl\") || brokerUrl.startsWith(\"wss\");\n    }\n\n    private String replaceTopicVariables(String topic) {\n        boolean found;\n        Matcher topicMatcher = TOPIC_PATTERN.matcher(topic);\n        StringBuffer sb = new StringBuffer();\n        do {\n\n            found = topicMatcher.find();\n            if (found) {\n                // By default replace #variable-name (group 0) with itself\n                String replacement = topicMatcher.group(0);\n\n                String variableName = topicMatcher.group(1);\n                synchronized (this.topicContext) {\n                    String value = this.topicContext.get(variableName);\n                    if (value != null) {\n                        replacement = value;\n                    }\n                }\n\n                // Replace #variable-name with the value of the variable\n                topicMatcher.appendReplacement(sb, replacement);\n            }\n        } while (found);\n\n        topicMatcher.appendTail(sb);\n\n        String replacedTopic = sb.toString();\n\n        logger.debug(\"Replaced tokens in topic {} with: {}\", topic, replacedTopic);\n\n        return replacedTopic;\n    }\n\n    private String generateSessionId() {\n        return this.clientConf.getClientId() + \"-\" + this.clientConf.getBrokerUrl();\n    }\n\n    private void setupMqttSession() {\n\n        if (this.clientConf == null) {\n            throw new IllegalStateException(\"Invalid client configuration\");\n        }\n\n        // We need to construct a new client instance only if either the broker URL\n        // or the client ID changes.\n        // We also need to construct a new instance if the persistence type (file or\n        // memory) changes.\n        // We MUST avoid to construct a new client instance every time because\n        // in that case the MQTT message ID is reset to 1.\n        if (this.mqttClient != null) {\n            String brokerUrl = this.mqttClient.getServerURI();\n            String clientId = this.mqttClient.getClientId();\n\n            if (!(brokerUrl.equals(this.clientConf.getBrokerUrl()) && clientId.equals(this.clientConf.getClientId())\n                    && this.persistenceType == this.clientConf.getPersistenceType())) {\n                closeMqttClient();\n            }\n        }\n\n        // Connecting with Clean Session flag set to true always starts\n        // a new session.\n        boolean newSessionTemp = this.clientConf.getConnectOptions().isCleanSession();\n\n        if (this.mqttClient == null) {\n\n            logger.info(\"Creating a new client instance\");\n\n            //\n            // Initialize persistence. This is only useful if the client\n            // connects with\n            // Clean Session flag set to false.\n            //\n            // Note that when using file peristence,\n            // Paho creates a subdirectory persistence whose name is encoded\n            // like this:\n            // cristiano-tcpbroker-stageeveryware-cloudcom1883/\n            // So the persistence is per client ID (cristiano) and broker URL.\n            // If we are connecting to a different broker URL or with a\n            // different client ID,\n            // Paho will create a new subdirectory for this MQTT connection.\n            // Closing the old client instance also deletes the associated\n            // persistence subdirectory.\n            //\n            // The lesson is:\n            // Reconnecting to the same broker URL with the same client ID will\n            // leverage\n            // Paho persistence and the MQTT message ID is always increased (up\n            // to the its maximum).\n            //\n            // Connecting either to a different broker URL or with a different\n            // client ID discards persisted\n            // messages and the MQTT client ID is reset.\n            //\n            // We have a problem here where the DataService needs to track\n            // in-flight messages, possibly\n            // across different MQTT connections.\n            // These messages will never be confirmed on a different connection.\n            // While we can assume that the client ID never changes because it's\n            // typically auto-generated,\n            // we cannot safely assume that the broker URL never changes.\n            //\n            // The above leads to two problems:\n            // The MQTT message ID alone is not sufficient to track an in-flight\n            // message\n            // because it can be reset on a different connection.\n            //\n            // On a different connection the DataService should republish the\n            // in-flight messages because\n            // Paho won't do that.\n\n            PersistenceType newPersistenceType = this.clientConf.getPersistenceType();\n            if (newPersistenceType == PersistenceType.MEMORY) {\n                logger.info(\"Using memory persistence for in-flight messages\");\n                this.persistence = new MemoryPersistence();\n            } else {\n                StringBuffer sb = new StringBuffer();\n                sb.append(this.systemService.getKuraDataDirectory()).append(this.systemService.getFileSeparator())\n                        .append(\"paho-persistence\");\n\n                String dir = sb.toString();\n\n                logger.info(\"Using file persistence for in-flight messages: {}\", dir);\n\n                // Look for \"Close on CONNACK timeout\" FIXME in this file.\n                // Make sure persistence is closed.\n                // This is needed if the previous connect attempt was\n                // forcibly terminated by closing the client.\n                if (this.persistence != null) {\n                    try {\n                        this.persistence.close();\n                    } catch (MqttPersistenceException e) {\n                        logger.warn(\"Failed to close persistence. Ignoring exception.\", e);\n                    }\n                }\n                this.persistence = new MqttDefaultFilePersistence(dir);\n            }\n\n            //\n            // Construct the MqttClient instance\n\n            try {\n                MqttAsyncClient newMqttClient = new MqttAsyncClient(this.clientConf.getBrokerUrl(),\n                        this.clientConf.getClientId(), this.persistence);\n                newMqttClient.setCallback(this);\n                this.mqttClient = newMqttClient;\n            } catch (MqttException e) {\n                logger.error(\"Client instantiation failed\", e);\n                throw new IllegalStateException(\"Client instantiation failed\");\n            }\n\n            this.persistenceType = newPersistenceType;\n\n            if (!this.clientConf.getConnectOptions().isCleanSession()) {\n                // This is tricky.\n                // The purpose of this code is to try to restore pending delivery tokens\n                // from the MQTT client persistence and determine if the next connection\n                // can be considered continuing an existing session.\n                // This is needed to allow the upper layer deciding what to do with the\n                // in-flight messages it is tracking (if any).\n                // If pending delivery tokens are found we assume that the upper layer\n                // is tracking them. In this case we set the newSession flag to false\n                // and notify this in the onConnectionEstablished callback.\n                // The upper layer shouldn't do anything special.\n                //\n                // Otherwise the next upper layer should decide what to do with the\n                // in-flight messages it is tracking (if any), either to republish or\n                // drop them.\n                IMqttDeliveryToken[] pendingDeliveryTokens = this.mqttClient.getPendingDeliveryTokens();\n                if (pendingDeliveryTokens != null && pendingDeliveryTokens.length != 0) {\n                    newSessionTemp = false;\n                }\n            }\n        }\n\n        this.newSession = newSessionTemp;\n        this.sessionId = generateSessionId();\n    }\n\n    private void closeMqttClient() {\n\n        if (this.mqttClient == null) {\n            return;\n        }\n\n        try {\n            logger.info(\"Forcing client disconnect...\");\n            this.mqttClient.disconnectForcibly(MQTT_QUIESCE_TIMEOUT, MQTT_DISCONNECT_TIMEOUT);\n        } catch (Exception e) {\n            logger.warn(\"Cannot force client disconnect\", e);\n        }\n        try {\n            logger.info(\"Closing client...\");\n            // prevent callbacks from a zombie client\n            this.mqttClient.setCallback(null);\n            this.mqttClient.close();\n            logger.info(\"Closed\");\n        } catch (Exception e) {\n            logger.warn(\"Cannot close client\", e);\n        } finally {\n            this.mqttClient = null;\n        }\n    }\n\n    private static String getMqttVersionLabel(int mqttVersion) {\n\n        switch (mqttVersion) {\n        case MqttConnectOptions.MQTT_VERSION_3_1:\n            return \"3.1\";\n        case MqttConnectOptions.MQTT_VERSION_3_1_1:\n            return \"3.1.1\";\n        default:\n            return String.valueOf(mqttVersion);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/util/MqttTopicUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data.util;\n\nimport org.eclipse.paho.client.mqttv3.MqttTopic;\n\npublic final class MqttTopicUtil {\n\n    private MqttTopicUtil() {\n    }\n\n    public static void validate(final String topicString, final boolean wildcardAllowed) {\n        MqttTopic.validate(topicString, wildcardAllowed);\n    }\n\n    public static boolean isMatched(final String topicFilter, final String topicName) {\n        return MqttTopic.isMatched(topicFilter, topicName);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/internal/data/TokenBucket.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.internal.data;\n\npublic class TokenBucket {\n\n    private final int capacity;\n    private final long refillPeriod;\n    private int remainingTokens;\n    private long lastRefillTime;\n\n    public TokenBucket(int capacity, long refillPeriod) {\n        this.capacity = capacity;\n        this.remainingTokens = capacity;\n        this.refillPeriod = refillPeriod;\n        this.lastRefillTime = System.nanoTime();\n    }\n\n    public boolean getToken() {\n        boolean result = false;\n        refill();\n        if (isTokenAvailable()) {\n            this.remainingTokens--;\n            result = true;\n        }\n        return result;\n    }\n\n    private boolean isTokenAvailable() {\n        return this.remainingTokens != 0;\n    }\n\n    private void refill() {\n        long now = System.nanoTime();\n        if (now - this.lastRefillTime >= this.refillPeriod) {\n            this.remainingTokens = (int) Math.min(this.capacity,\n                    this.remainingTokens + (now - this.lastRefillTime) / this.refillPeriod);\n            this.remainingTokens = Math.max(1, this.remainingTokens);\n            this.lastRefillTime += (now - this.lastRefillTime) / this.refillPeriod * this.refillPeriod;\n        }\n    }\n\n    public long getTokenWaitTime() {\n        long now = System.nanoTime();\n        long timeToRefill = this.lastRefillTime + this.refillPeriod - now;\n        return Math.max(0, timeToRefill);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/.gitignore",
    "content": "/target\n/bin\n/lib\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Connection Provider for the Eclipse IoT Cloud Platform\nBundle-SymbolicName: org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .,\n lib/protobuf-java.jar\nBundle-ActivationPolicy: lazy\nImport-Package: com.eclipsesource.json;version=\"0.9.5\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.audit;version=\"[1.0,2.0)\",\n org.eclipse.kura.certificate;version=\"[2.0,3.0)\",\n org.eclipse.kura.cloud;version=\"[1.1,1.2)\",\n org.eclipse.kura.cloudconnection;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.factory;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.publisher;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.subscriber.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.data;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.util;version=\"[2.0,3.0)\",\n org.eclipse.kura.data;version=\"[1.0,2.0)\",\n org.eclipse.kura.data.listener;version=\"[1.0,1.1)\",\n org.eclipse.kura.marshalling;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.5,2.0)\",\n org.eclipse.kura.net;version=\"[2.0,3.0)\",\n org.eclipse.kura.net.modem;version=\"[2.0,3.0)\",\n org.eclipse.kura.net.status;version=\"[1.1,2.0)\",\n org.eclipse.kura.net.status.modem;version=\"[1.0,2.0)\",\n org.eclipse.kura.position;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.3.0\",\n org.osgi.util.measurement;version=\"[1.0,2.0)\",\n org.osgi.util.position;version=\"[1.0,2.0)\",\n org.osgi.util.tracker;version=\"1.5.1\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/cloud.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2018, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\">\n   <implementation class=\"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.CloudConnectionManagerImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.cloud.CloudPayloadProtoBufEncoder\"/>\n      <provide interface=\"org.eclipse.kura.cloud.CloudPayloadProtoBufDecoder\"/>\n      <provide interface=\"org.eclipse.kura.cloudconnection.CloudConnectionManager\"/>\n      <provide interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\"/>\n      <provide interface=\"org.eclipse.kura.cloudconnection.CloudEndpoint\"/>\n   </service>\n   <reference name=\"DataService\" \n              interface=\"org.eclipse.kura.data.DataService\" \n              policy=\"static\" \n              cardinality=\"1..1\" \n              bind=\"setDataService\" \n              unbind=\"unsetDataService\"/>\n   <reference name=\"SystemService\" \n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"setSystemService\"\n              unbind=\"unsetSystemService\"\n              interface=\"org.eclipse.kura.system.SystemService\"/>\n   <reference name=\"SystemAdminService\" \n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"setSystemAdminService\"\n              unbind=\"unsetSystemAdminService\"\n              interface=\"org.eclipse.kura.system.SystemAdminService\"/>\n   <reference name=\"NetworkService\" \n              policy=\"dynamic\" \n              cardinality=\"0..1\" \n              bind=\"setNetworkService\" \n              unbind=\"unsetNetworkService\"\n              interface=\"org.eclipse.kura.net.NetworkService\"/>\n   <reference name=\"PositionService\" \n              cardinality=\"0..1\" \n              bind=\"setPositionService\" \n              interface=\"org.eclipse.kura.position.PositionService\" \n              policy=\"dynamic\" \n              unbind=\"unsetPositionService\"/>\n   <reference name=\"EventAdmin\"              \n              cardinality=\"1..1\" \n              policy=\"static\" \n              bind=\"setEventAdmin\" \n              unbind=\"unsetEventAdmin\"\n              interface=\"org.osgi.service.event.EventAdmin\"/>\n   <reference bind=\"setJsonUnmarshaller\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.marshalling.Unmarshaller\"\n              name=\"Unmarshaller\"\n              policy=\"static\"\n              target=\"(kura.service.pid=org.eclipse.kura.json.marshaller.unmarshaller.provider)\"\n              unbind=\"unsetJsonUnmarshaller\"/>\n   <reference bind=\"setJsonMarshaller\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.marshalling.Marshaller\"\n              name=\"Marshaller\"\n              policy=\"static\"\n              target=\"(kura.service.pid=org.eclipse.kura.json.marshaller.unmarshaller.provider)\"\n              unbind=\"unsetJsonMarshaller\"/>\n   <reference bind=\"setNetworkStatusService\" \n              cardinality=\"0..1\" \n              interface=\"org.eclipse.kura.net.status.NetworkStatusService\" \n              name=\"NetworkStatusService\" \n              policy=\"dynamic\" \n              unbind=\"unsetNetworkStatusService\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   <property name=\"kura.ui.factory.hide\" type=\"Boolean\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/cloudConnectionFactory.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.DefaultCloudConnectionFactory\"> \n   <implementation class=\"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.factory.DefaultCloudConnectionFactory\"/>\n   <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\" unbind=\"unsetConfigurationService\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n   </service>\n   <property name=\"osgi.command.scope\" type=\"String\" value=\"kura.cloud\"/>\n   <property name=\"osgi.command.function\" type=\"String\">\n      createConfiguration\n   </property>\n   <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\"/>\n   <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager(\\-[a-zA-Z0-9]+)?$\"/>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.DefaultCloudConnectionFactory\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/cloudPublisher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n \n   Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\">\n   <implementation class=\"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.publisher.CloudPublisherImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\"/>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n   <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\"/>\n   <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher(\\-[a-zA-Z0-9]+)?$\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\" \n         name=\"CloudPublisher\" \n         description=\"The Eclipse IoT Cloud Publisher provides a service to publish messages to a cloud platform compatible with the Eclipse IoT MQTT topic namespace.\">\n        \n        <AD id=\"semantic.topic\"\n            name=\"Semantic Topic\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"W1/A1/$assetName\"\n            description='The MQTT topic suffix providing the message interpretation. Wildcards can be defined in the topic by specifing a $something in this field. The publisher will try to match \"something\" with a corresponding property in the received KuraMessage. If possible, the $something placeholder will be substituted with the value specified in the KuraMessage received from the user application.'>\n        </AD>\n        \n        <AD id=\"message.type\"\n            name=\"Kind of Message\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"telemetryQos0\"\n            description=\"Type of message to be published.\">\n            <Option label=\"Telemetry QoS 0\" value=\"telemetryQos0\" />\n            <Option label=\"Telemetry QoS 1\" value=\"telemetryQos1\" />\n            <Option label=\"Event\" value=\"events\" />\n            <Option label=\"Alert\" value=\"alerts\" />\n        </AD>\n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\" factoryPid=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\">\n        <Object ocdref=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2018, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\" \n         name=\"Eclipse ConnectionManager\" \n         description=\"The Eclipse IoT ConnectionManager allows for setting a user friendly name for the current device. It also provides the option to compress message payloads to reduce network traffic.\">\n        \n        <AD id=\"device.display-name\"\n            name=\"Device Display-Name\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"device-name\"\n            description=\"Friendly name of the device. Device name is the common name of the device (eg: Reliagate 20-25, Raspberry Pi, etc.). Hostname will use the linux hostname utility. \n            \t\t\t\tCustom allows for defining a unique string. Server defined relies on the remote management server to define a name.\">\n        \t<Option label=\"Set display name as device name\" value=\"device-name\" />\n        \t<Option label=\"Set display name from hostname\" value=\"hostname\" />\n        \t<Option label=\"Custom\" value=\"custom\" />\n        \t<Option label=\"Server defined\" value=\"server\" />\n        </AD>\n        \n        <AD id=\"device.custom-name\"\n        \tname=\"Device Custom-Name\"\n        \ttype=\"String\"\n        \tcardinality=\"0\"\n        \trequired=\"false\"\n        \tdefault=\"\"\n        \tdescription='Custom name for the device. This value is applied ONLY if device.display-name is set to \"Custom\"'>\n        </AD>\n                    \n        <AD id=\"encode.gzip\"\n            name=\"Encode gzip\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"true\"\n            description=\"Compress message payloads before sending them to the remote server to reduce the network traffic.\">\n        </AD>\n        \n        <AD id=\"republish.mqtt.birth.cert.on.gps.lock\"\n            name=\"Republish Mqtt Birth Cert On Gps Lock\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Whether or not to republish the MQTT Birth Certificate on GPS lock event\"/>\n\n        <AD id=\"payload.encoding\"\n            name=\"Payload Encoding\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"kura-protobuf\"\n            description=\"Specify the message payload encoding.\">\n            <Option label=\"Kura Protobuf\" value=\"kura-protobuf\" />\n            <Option label=\"Simple JSON\" value=\"simple-json\" />\n        </AD>\n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\" factoryPid=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\">\n        <Object ocdref=\"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/build.properties",
    "content": "bin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               lib/protobuf-java.jar\nsrc.includes = about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2018, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.google.protobuf</groupId>\n            <artifactId>protobuf-java</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>3.8.1</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <outputDirectory>${project.basedir}/lib</outputDirectory>\n                            <includeArtifactIds>\n                                protobuf-java\n                            </includeArtifactIds>\n                            <stripVersion>true</stripVersion>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <artifactId>maven-clean-plugin</artifactId>\n                <version>3.1.0</version>\n                <configuration>\n                    <filesets>\n                        <fileset>\n                            <directory>lib</directory>\n                        </fileset>\n                    </filesets>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudConnectionManagerImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport static java.util.Objects.nonNull;\nimport static org.eclipse.kura.cloud.CloudPayloadEncoding.KURA_PROTOBUF;\nimport static org.eclipse.kura.cloud.CloudPayloadEncoding.SIMPLE_JSON;\nimport static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.FULL_TOPIC;\nimport static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.PRIORITY;\nimport static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.QOS;\nimport static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.RETAIN;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Date;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraInvalidMessageException;\nimport org.eclipse.kura.certificate.CertificatesService;\nimport org.eclipse.kura.cloud.CloudConnectionEstablishedEvent;\nimport org.eclipse.kura.cloud.CloudConnectionLostEvent;\nimport org.eclipse.kura.cloud.CloudPayloadEncoding;\nimport org.eclipse.kura.cloud.CloudPayloadProtoBufDecoder;\nimport org.eclipse.kura.cloud.CloudPayloadProtoBufEncoder;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.data.DataServiceImpl;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.message.KuraApplicationTopic;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.net.NetworkService;\nimport org.eclipse.kura.net.status.NetworkInterfaceStatus;\nimport org.eclipse.kura.net.status.NetworkInterfaceType;\nimport org.eclipse.kura.net.status.NetworkStatusService;\nimport org.eclipse.kura.net.status.modem.ModemInterfaceStatus;\nimport org.eclipse.kura.net.status.modem.Sim;\nimport org.eclipse.kura.position.PositionLockedEvent;\nimport org.eclipse.kura.position.PositionService;\nimport org.eclipse.kura.system.SystemAdminService;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventAdmin;\nimport org.osgi.service.event.EventConstants;\nimport org.osgi.service.event.EventHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudConnectionManagerImpl\n        implements DataServiceListener, ConfigurableComponent, EventHandler, CloudPayloadProtoBufEncoder,\n        CloudPayloadProtoBufDecoder, RequestHandlerRegistry, CloudConnectionManager, CloudEndpoint {\n\n    private static final String KURA_PAYLOAD = \"KuraPayload\";\n\n    private static final String SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE = \"Cannot setup cloud service connection\";\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudConnectionManagerImpl.class);\n\n    private static final String CONNECTION_EVENT_PID_PROPERTY_KEY = \"cloud.service.pid\";\n\n    static final String EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL = \"org/osgi/service/deployment/INSTALL\";\n    static final String EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL = \"org/osgi/service/deployment/UNINSTALL\";\n\n    private static final int NUM_CONCURRENT_CALLBACKS = 2;\n\n    private static ExecutorService callbackExecutor = Executors.newFixedThreadPool(NUM_CONCURRENT_CALLBACKS);\n\n    private ComponentContext ctx;\n\n    private CloudConnectionManagerOptions options;\n\n    private DataService dataService;\n    private SystemService systemService;\n    private SystemAdminService systemAdminService;\n    private Optional<NetworkService> networkService = Optional.empty();\n    private Optional<PositionService> positionService = Optional.empty();\n    private EventAdmin eventAdmin;\n    private CertificatesService certificatesService;\n    private Unmarshaller jsonUnmarshaller;\n    private Marshaller jsonMarshaller;\n    private Optional<NetworkStatusService> networkStatusService = Optional.empty();\n\n    // package visibility for LifeCyclePayloadBuilder\n    String imei;\n    String iccid;\n    String imsi;\n    String rssi;\n    String modemFwVer;\n\n    private String ownPid;\n\n    private final AtomicInteger messageId;\n\n    private ServiceRegistration<?> cloudServiceRegistration;\n\n    private final Map<String, RequestHandler> registeredRequestHandlers;\n\n    private final Set<CloudConnectionListener> registeredCloudConnectionListeners;\n    private final Set<CloudPublisherDeliveryListener> registeredCloudPublisherDeliveryListeners;\n    private final Set<CloudDeliveryListener> registeredCloudDeliveryListeners;\n\n    private ScheduledFuture<?> scheduledBirthPublisherFuture;\n    private ScheduledExecutorService scheduledBirthPublisher = Executors.newScheduledThreadPool(1);\n\n    public CloudConnectionManagerImpl() {\n        this.messageId = new AtomicInteger();\n        this.registeredCloudConnectionListeners = new CopyOnWriteArraySet<>();\n        this.registeredRequestHandlers = new HashMap<>();\n        this.registeredCloudPublisherDeliveryListeners = new CopyOnWriteArraySet<>();\n        this.registeredCloudDeliveryListeners = new CopyOnWriteArraySet<>();\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setDataService(DataService dataService) {\n        this.dataService = dataService;\n    }\n\n    public void unsetDataService(DataService dataService) {\n        if (this.dataService.equals(dataService)) {\n            this.dataService = null;\n        }\n    }\n\n    public DataService getDataService() {\n        return this.dataService;\n    }\n\n    public void setSystemAdminService(SystemAdminService systemAdminService) {\n        this.systemAdminService = systemAdminService;\n    }\n\n    public void unsetSystemAdminService(SystemAdminService systemAdminService) {\n        if (this.systemAdminService.equals(systemAdminService)) {\n            this.systemAdminService = null;\n        }\n    }\n\n    public SystemAdminService getSystemAdminService() {\n        return this.systemAdminService;\n    }\n\n    public void setSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    public void unsetSystemService(SystemService systemService) {\n        if (this.systemService.equals(systemService)) {\n            this.systemService = null;\n        }\n    }\n\n    public SystemService getSystemService() {\n        return this.systemService;\n    }\n\n    public void setNetworkService(NetworkService networkService) {\n        this.networkService = Optional.of(networkService);\n    }\n\n    public void unsetNetworkService(NetworkService networkService) {\n        if (this.networkService.isPresent() && this.networkService.get().equals(networkService)) {\n            this.networkService = Optional.empty();\n        }\n    }\n\n    public Optional<NetworkService> getNetworkService() {\n        return this.networkService;\n    }\n\n    public void setPositionService(PositionService positionService) {\n        this.positionService = Optional.of(positionService);\n    }\n\n    public void unsetPositionService(PositionService positionService) {\n        if (this.positionService.isPresent() && this.positionService.get().equals(positionService)) {\n            this.positionService = Optional.empty();\n        }\n    }\n\n    public Optional<PositionService> getPositionService() {\n        return this.positionService;\n    }\n\n    public void setEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    public void unsetEventAdmin(EventAdmin eventAdmin) {\n        if (this.eventAdmin.equals(eventAdmin)) {\n            this.eventAdmin = null;\n        }\n    }\n\n    public void setJsonUnmarshaller(Unmarshaller jsonUnmarshaller) {\n        this.jsonUnmarshaller = jsonUnmarshaller;\n    }\n\n    public void unsetJsonUnmarshaller(Unmarshaller jsonUnmarshaller) {\n        if (this.jsonUnmarshaller.equals(jsonUnmarshaller)) {\n            this.jsonUnmarshaller = null;\n        }\n    }\n\n    public void setJsonMarshaller(Marshaller jsonMarshaller) {\n        this.jsonMarshaller = jsonMarshaller;\n    }\n\n    public void unsetJsonMarshaller(Marshaller jsonMarshaller) {\n        if (this.jsonMarshaller.equals(jsonMarshaller)) {\n            this.jsonMarshaller = null;\n        }\n    }\n\n    public void setNetworkStatusService(NetworkStatusService networkStatusService) {\n        this.networkStatusService = Optional.of(networkStatusService);\n    }\n\n    public void unsetNetworkStatusService(NetworkStatusService networkStatusService) {\n        if (this.networkStatusService.isPresent() && this.networkStatusService.get().equals(networkStatusService)) {\n            this.networkStatusService = Optional.empty();\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        this.ownPid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n\n        logger.info(\"activate {}...\", ownPid);\n\n        //\n        // save the bundle context and the properties\n        this.ctx = componentContext;\n        this.options = new CloudConnectionManagerOptions(properties, this.systemService);\n        //\n        // install event listener for GPS locked event\n        Dictionary<String, Object> props = new Hashtable<>();\n        String[] eventTopics = { PositionLockedEvent.POSITION_LOCKED_EVENT_TOPIC, EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL,\n                EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL };\n        props.put(EventConstants.EVENT_TOPIC, eventTopics);\n        this.cloudServiceRegistration = this.ctx.getBundleContext().registerService(EventHandler.class.getName(), this,\n                props);\n\n        this.dataService.addDataServiceListener(this);\n\n        //\n        // Usually the cloud connection is setup in the\n        // onConnectionEstablished callback.\n        // Since the callback may be lost if we are activated\n        // too late (the DataService is already connected) we\n        // setup the cloud connection here.\n        if (isConnected()) {\n            logger.warn(\"DataService is already connected. Publish BIRTH certificate\");\n            try {\n                setupCloudConnection(false);\n            } catch (KuraException e) {\n                logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE, e);\n            }\n        }\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"updated {}...: {}\", properties.get(ConfigurationService.KURA_SERVICE_PID), properties);\n\n        // Update properties and re-publish Birth certificate\n        this.options = new CloudConnectionManagerOptions(properties, this.systemService);\n        if (isConnected()) {\n            try {\n                setupCloudConnection(false);\n            } catch (KuraException e) {\n                logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE);\n            }\n        }\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.info(\"deactivate {}...\", componentContext.getProperties().get(ConfigurationService.KURA_SERVICE_PID));\n\n        if (isConnected()) {\n            try {\n                publishDisconnectCertificate();\n            } catch (KuraException e) {\n                logger.warn(\"Cannot publish disconnect certificate\");\n            }\n        }\n\n        this.dataService.removeDataServiceListener(this);\n\n        this.dataService = null;\n        this.systemService = null;\n        this.systemAdminService = null;\n        this.networkService = null;\n        this.positionService = Optional.empty();\n        this.eventAdmin = null;\n\n        this.cloudServiceRegistration.unregister();\n    }\n\n    @Override\n    public void handleEvent(Event event) {\n        String topic = event.getTopic();\n\n        if (PositionLockedEvent.POSITION_LOCKED_EVENT_TOPIC.contains(topic)) {\n            handlePositionLockedEvent();\n            return;\n        }\n\n        if ((EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL.equals(topic) || EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL.equals(topic))\n                && this.dataService.isConnected()) {\n            logger.debug(\"CloudConnectionManagerImpl: received install/uninstall event, publishing BIRTH.\");\n            tryPublishBirthCertificate(false);\n        }\n    }\n\n    private void handlePositionLockedEvent() {\n        // if we get a position locked event,\n        // republish the birth certificate only if we are configured to\n        logger.info(\"Handling PositionLockedEvent\");\n        if (this.dataService.isConnected() && this.options.getRepubBirthCertOnGpsLock()) {\n            tryPublishBirthCertificate(false);\n        }\n    }\n\n    private void tryPublishBirthCertificate(boolean isNewConnection) {\n        try {\n            publishBirthCertificate(isNewConnection);\n        } catch (KuraException e) {\n            logger.warn(\"Cannot publish birth certificate\", e);\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public boolean isConnected() {\n        return this.dataService != null && this.dataService.isConnected();\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Package APIs\n    //\n    // ----------------------------------------------------------------\n\n    public CloudConnectionManagerOptions getCloudConnectionManagerOptions() {\n        return this.options;\n    }\n\n    public byte[] encodePayload(KuraPayload payload) throws KuraException {\n        byte[] bytes;\n        CloudPayloadEncoding preferencesEncoding = this.options.getPayloadEncoding();\n\n        if (preferencesEncoding == KURA_PROTOBUF) {\n            bytes = encodeProtobufPayload(payload);\n        } else if (preferencesEncoding == SIMPLE_JSON) {\n            bytes = encodeJsonPayload(payload);\n        } else {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD);\n        }\n        return bytes;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // DataServiceListener API\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public void onConnectionEstablished() {\n        try {\n            setupCloudConnection(true);\n        } catch (KuraException e) {\n            logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE);\n        }\n\n        postConnectionStateChangeEvent(true);\n\n        this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onConnectionEstablished);\n    }\n\n    @Override\n    public void onDisconnecting() {\n        // publish disconnect certificate\n        try {\n            publishDisconnectCertificate();\n        } catch (KuraException e) {\n            logger.warn(\"Cannot publish disconnect certificate\");\n        }\n    }\n\n    @Override\n    public void onDisconnected() {\n        // raise event\n        postConnectionStateChangeEvent(false);\n\n        this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onDisconnected);\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        // raise event\n        postConnectionStateChangeEvent(false);\n\n        this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onConnectionLost);\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n        logger.info(\"Message arrived on topic: {}\", topic);\n\n        // notify listeners\n        ControlTopic kuraTopic = new ControlTopic(topic, MessageType.CONTROL.getTopicPrefix());\n\n        KuraPayload kuraPayload = null;\n\n        if (this.options.getPayloadEncoding() == SIMPLE_JSON) {\n            try {\n                kuraPayload = createKuraPayloadFromJson(payload);\n            } catch (KuraException e) {\n                logger.warn(\"Error creating Kura Payload from Json\", e);\n            }\n        } else if (this.options.getPayloadEncoding() == KURA_PROTOBUF) {\n            kuraPayload = createKuraPayloadFromProtoBuf(topic, payload);\n        }\n\n        try {\n            boolean validMessage = isValidMessage(kuraTopic, kuraPayload);\n\n            if (validMessage) {\n                dispatchControlMessage(kuraTopic, kuraPayload);\n            } else {\n                logger.warn(\"Message verification failed! Not valid signature or message not signed.\");\n            }\n\n        } catch (Exception e) {\n            logger.error(\"Error during CloudClientListener notification.\", e);\n        }\n\n    }\n\n    private void dispatchControlMessage(ControlTopic kuraTopic, KuraPayload kuraPayload) {\n\n        String applicationId = kuraTopic.getApplicationId();\n\n        kuraPayload.addMetric(MessageHandlerCallable.METRIC_REQUEST_ID, kuraTopic.getReqId());\n\n        RequestHandler cloudlet = this.registeredRequestHandlers.get(applicationId);\n        if (cloudlet != null) {\n\n            callbackExecutor\n                    .submit(new MessageHandlerCallable(cloudlet, kuraTopic.getApplicationTopic(), kuraPayload, this));\n        }\n    }\n\n    private boolean isValidMessage(KuraApplicationTopic kuraAppTopic, KuraPayload kuraPayload) {\n        if (this.certificatesService == null) {\n            ServiceReference<CertificatesService> sr = this.ctx.getBundleContext()\n                    .getServiceReference(CertificatesService.class);\n            if (sr != null) {\n                this.certificatesService = this.ctx.getBundleContext().getService(sr);\n            }\n        }\n        boolean validMessage = false;\n        if (this.certificatesService == null || this.certificatesService.verifySignature(kuraAppTopic, kuraPayload)) {\n            validMessage = true;\n        }\n        return validMessage;\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        synchronized (this.messageId) {\n            if (this.messageId.get() != -1 && this.messageId.get() == messageId) {\n                if (this.options.getLifeCycleMessageQos() == 0) {\n                    this.messageId.set(-1);\n                }\n                this.messageId.notifyAll();\n            }\n        }\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        synchronized (this.messageId) {\n            if (this.messageId.get() != -1 && this.messageId.get() == messageId) {\n                this.messageId.set(-1);\n                this.messageId.notifyAll();\n            }\n        }\n\n        this.registeredCloudPublisherDeliveryListeners\n                .forEach(deliveryListener -> deliveryListener.onMessageConfirmed(String.valueOf(messageId), topic));\n\n        this.registeredCloudDeliveryListeners\n                .forEach(deliveryListener -> deliveryListener.onMessageConfirmed(String.valueOf(messageId)));\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // CloudPayloadProtoBufEncoder API\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public byte[] getBytes(KuraPayload kuraPayload, boolean gzipped) throws KuraException {\n        CloudPayloadEncoder encoder = new CloudPayloadProtoBufEncoderImpl(kuraPayload);\n        if (gzipped) {\n            encoder = new CloudPayloadGZipEncoder(encoder);\n        }\n\n        byte[] bytes;\n        try {\n            bytes = encoder.getBytes();\n            return bytes;\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD, e);\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // CloudPayloadProtoBufDecoder API\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public KuraPayload buildFromByteArray(byte[] payload) throws KuraException {\n        CloudPayloadProtoBufDecoderImpl encoder = new CloudPayloadProtoBufDecoderImpl(payload);\n        KuraPayload kuraPayload;\n\n        try {\n            kuraPayload = encoder.buildFromByteArray();\n            return kuraPayload;\n        } catch (KuraInvalidMessageException | IOException e) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, KURA_PAYLOAD, e);\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Birth and Disconnect Certificates\n    //\n    // ----------------------------------------------------------------\n\n    private void setupCloudConnection(boolean isNewConnection) throws KuraException {\n        publishBirthCertificate(isNewConnection);\n        setupDeviceSubscriptions();\n    }\n\n    private void setupDeviceSubscriptions() throws KuraException {\n        StringBuilder sbDeviceSubscription = new StringBuilder();\n        sbDeviceSubscription.append(MessageType.CONTROL.getTopicPrefix()).append(this.options.getTopicSeparator())\n                .append(\"+\").append(this.options.getTopicSeparator()).append(\"+\")\n                .append(this.options.getTopicSeparator()).append(\"req\").append(this.options.getTopicSeparator())\n                .append(this.options.getTopicWildCard());\n\n        this.dataService.subscribe(sbDeviceSubscription.toString(), 0);\n    }\n\n    private void publishBirthCertificate(boolean isNewConnection) throws KuraException {\n        if (isFrameworkStopping()) {\n            logger.info(\"framework is stopping.. not republishing birth certificate\");\n            return;\n        }\n\n        readModemProfile();\n        LifecycleMessage birthToPublish = new LifecycleMessage(this.options, this).asBirthCertificateMessage();\n\n        if (isNewConnection) {\n            publishLifeCycleMessage(birthToPublish);\n        } else {\n            publishWithDelay(birthToPublish);\n        }\n    }\n\n    private void publishDisconnectCertificate() throws KuraException {\n        publishLifeCycleMessage(new LifecycleMessage(this.options, this).asDisconnectCertificateMessage());\n    }\n\n    private void publishWithDelay(LifecycleMessage message) {\n        if (Objects.nonNull(this.scheduledBirthPublisherFuture)) {\n            this.scheduledBirthPublisherFuture.cancel(false);\n            logger.debug(\"CloudConnectionManagerImpl: BIRTH message cache timer restarted.\");\n        }\n\n        logger.debug(\"CloudConnectionManagerImpl: BIRTH message cached for 30s.\");\n\n        this.scheduledBirthPublisherFuture = this.scheduledBirthPublisher.schedule(() -> {\n            try {\n                logger.debug(\"CloudConnectionManagerImpl: publishing cached BIRTH message.\");\n                publishLifeCycleMessage(message);\n            } catch (KuraException e) {\n                logger.error(\"Error sending cached BIRTH/APP certificate.\", e);\n            }\n        }, 30L, TimeUnit.SECONDS);\n    }\n\n    private void publishLifeCycleMessage(LifecycleMessage message) throws KuraException {\n        // track the message ID and block until the message\n        // has been published (i.e. written to the socket).\n        synchronized (this.messageId) {\n            this.messageId.set(-1);\n            // add a timestamp to the message\n            KuraPayload payload = message.getPayload();\n            payload.setTimestamp(new Date());\n            byte[] encodedPayload = encodePayload(payload);\n            int localMessageId = this.dataService.publish(message.getTopic(), encodedPayload,\n                    this.options.getLifeCycleMessageQos(), this.options.getLifeCycleMessageRetain(),\n                    this.options.getLifeCycleMessagePriority());\n            this.messageId.set(localMessageId);\n            try {\n                this.messageId.wait(1000);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                logger.info(\"Interrupted while waiting for the message to be published\", e);\n            }\n        }\n    }\n\n    private byte[] encodeProtobufPayload(KuraPayload payload) throws KuraException {\n        byte[] bytes = new byte[0];\n        if (payload == null) {\n            return bytes;\n        }\n\n        CloudPayloadEncoder encoder = new CloudPayloadProtoBufEncoderImpl(payload);\n        if (this.options.getEncodeGzip()) {\n            encoder = new CloudPayloadGZipEncoder(encoder);\n        }\n\n        try {\n            bytes = encoder.getBytes();\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD, e);\n        }\n        return bytes;\n    }\n\n    private byte[] encodeJsonPayload(KuraPayload payload) throws KuraException {\n        return this.jsonMarshaller.marshal(payload).getBytes(StandardCharsets.UTF_8);\n    }\n\n    private KuraPayload createKuraPayloadFromJson(byte[] payload) throws KuraException {\n        return this.jsonUnmarshaller.unmarshal(new String(payload), KuraPayload.class);\n    }\n\n    private KuraPayload createKuraPayloadFromProtoBuf(String topic, byte[] payload) {\n        KuraPayload kuraPayload;\n        try {\n            // try to decode the message into an KuraPayload\n            kuraPayload = new CloudPayloadProtoBufDecoderImpl(payload).buildFromByteArray();\n        } catch (Exception e) {\n            // Wrap the received bytes payload into an KuraPayload\n            logger.debug(\"Received message on topic {} that could not be decoded. Wrapping it into an KuraPayload.\",\n                    topic);\n            kuraPayload = new KuraPayload();\n            kuraPayload.setBody(payload);\n        }\n        return kuraPayload;\n    }\n\n    private void postConnectionStateChangeEvent(final boolean isConnected) {\n\n        final Map<String, Object> eventProperties = Collections.singletonMap(CONNECTION_EVENT_PID_PROPERTY_KEY,\n                (String) this.ctx.getProperties().get(ConfigurationService.KURA_SERVICE_PID));\n\n        final Event event = isConnected ? new CloudConnectionEstablishedEvent(eventProperties)\n                : new CloudConnectionLostEvent(eventProperties);\n        this.eventAdmin.postEvent(event);\n    }\n\n    @Override\n    public void connect() throws KuraConnectException {\n        if (this.dataService != null) {\n            this.dataService.connect();\n        }\n    }\n\n    @Override\n    public void disconnect() {\n        if (this.dataService != null) {\n            this.dataService.disconnect(10);\n        }\n    }\n\n    @Override\n    public Map<String, String> getInfo() {\n        DataServiceImpl dataServiceImpl = (DataServiceImpl) this.dataService;\n        return dataServiceImpl.getConnectionInfo();\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.registeredCloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.registeredCloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    public void registerCloudPublisherDeliveryListener(CloudPublisherDeliveryListener cloudPublisherDeliveryListener) {\n        this.registeredCloudPublisherDeliveryListeners.add(cloudPublisherDeliveryListener);\n    }\n\n    public void unregisterCloudPublisherDeliveryListener(\n            CloudPublisherDeliveryListener cloudPublisherDeliveryListener) {\n        this.registeredCloudPublisherDeliveryListeners.remove(cloudPublisherDeliveryListener);\n    }\n\n    @Override\n    public String publish(KuraMessage message) throws KuraException {\n        Map<String, Object> messageProps = message.getProperties();\n        String fullTopic = (String) messageProps.get(FULL_TOPIC.name());\n        int qos = (Integer) messageProps.get(QOS.name());\n        boolean retain = (Boolean) messageProps.get(RETAIN.name());\n        int priority = (Integer) messageProps.get(PRIORITY.name());\n\n        byte[] appPayload = encodePayload(message.getPayload());\n\n        int id = this.dataService.publish(fullTopic, appPayload, qos, retain, priority);\n\n        if (qos == 0) {\n            return null;\n        }\n        return String.valueOf(id);\n    }\n\n    String getOwnPid() {\n        return ownPid;\n    }\n\n    @Override\n    public void registerSubscriber(Map<String, Object> subscriptionProperties, CloudSubscriberListener subscriber) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void unregisterSubscriber(CloudSubscriberListener subscriberListener) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void registerRequestHandler(String id, RequestHandler requestHandler) throws KuraException {\n        this.registeredRequestHandlers.put(id, requestHandler);\n    }\n\n    @Override\n    public void unregister(String id) throws KuraException {\n        this.registeredRequestHandlers.remove(id);\n    }\n\n    public String getNotificationPublisherPid() {\n        throw new UnsupportedOperationException();\n    }\n\n    public CloudNotificationPublisher getNotificationPublisher() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.registeredCloudDeliveryListeners.add(cloudDeliveryListener);\n\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.registeredCloudDeliveryListeners.remove(cloudDeliveryListener);\n    }\n\n    private boolean isFrameworkStopping() {\n        try {\n            final Bundle ownBundle = FrameworkUtil.getBundle(CloudConnectionManagerImpl.class);\n\n            if (ownBundle == null) {\n                return false; // not running in an OSGi framework? e.g. unit test\n            }\n\n            return ownBundle.getBundleContext().getBundle(0).getState() == Bundle.STOPPING;\n        } catch (final Exception e) {\n            logger.warn(\"unexpected exception while checking if framework is shutting down\", e);\n            return false;\n        }\n    }\n\n    private void readModemProfile() {\n        this.networkStatusService.ifPresent(statusService -> {\n            List<ModemInterfaceStatus> modemStatuses = getModemsStatuses(statusService);\n            if (nonNull(modemStatuses) && !modemStatuses.isEmpty()) {\n                readModemInfos(modemStatuses);\n            } else {\n                this.imei = null;\n                this.iccid = null;\n                this.imsi = null;\n                this.rssi = null;\n                this.modemFwVer = null;\n            }\n        });\n    }\n\n    private List<ModemInterfaceStatus> getModemsStatuses(NetworkStatusService networkStatusService) {\n        List<ModemInterfaceStatus> modemStatuses = new ArrayList<>();\n        try {\n            List<String> interfaceIds = networkStatusService.getInterfaceIds();\n            for (String interfaceId : interfaceIds) {\n                Optional<NetworkInterfaceStatus> networkInterfaceStatus = networkStatusService\n                        .getNetworkStatus(interfaceId);\n                networkInterfaceStatus.ifPresent(state -> {\n                    NetworkInterfaceType type = state.getType();\n                    if (NetworkInterfaceType.MODEM.equals(type)) {\n                        modemStatuses.add((ModemInterfaceStatus) state);\n                    }\n                });\n            }\n        } catch (KuraException e) {\n            logger.error(\"Error reading modem profile\", e);\n        }\n        return modemStatuses;\n    }\n\n    private void readModemInfos(List<ModemInterfaceStatus> modemStatuses) {\n        Collections.sort(modemStatuses, Comparator.comparing(ModemInterfaceStatus::getConnectionStatus));\n        ModemInterfaceStatus modemStatus = modemStatuses.get(modemStatuses.size() - 1);\n        Optional<Sim> activeSim = Optional.empty();\n\n        List<Sim> availableSims = modemStatus.getAvailableSims();\n        for (Sim sim : availableSims) {\n            if (sim.isActive() && sim.isPrimary()) {\n                activeSim = Optional.of(sim);\n            }\n        }\n\n        this.iccid = \"NA\";\n        this.imsi = \"NA\";\n        activeSim.ifPresent(sim -> {\n            this.iccid = sim.getIccid();\n            this.imsi = sim.getImsi();\n        });\n        this.imei = modemStatus.getSerialNumber();\n        this.rssi = String.valueOf(modemStatus.getSignalStrength());\n        this.modemFwVer = modemStatus.getFirmwareVersion();\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudConnectionManagerOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.cloud.CloudPayloadEncoding;\nimport org.eclipse.kura.system.SystemService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudConnectionManagerOptions {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudConnectionManagerOptions.class);\n\n    private static final String TOPIC_SEPARATOR = \"/\";\n    private static final String TOPIC_BIRTH_SUFFIX = \"MQTT/BIRTH\";\n    private static final String TOPIC_DISCONNECT_SUFFIX = \"MQTT/DC\";\n    private static final String TOPIC_APPS_SUFFIX = \"MQTT/APPS\";\n    private static final String TOPIC_WILD_CARD = \"#\";\n\n    private static final String DEVICE_DISPLAY_NAME = \"device.display-name\";\n    private static final String DEVICE_CUSTOM_NAME = \"device.custom-name\";\n    private static final String ENCODE_GZIP = \"encode.gzip\";\n    private static final String REPUB_BIRTH_ON_GPS_LOCK = \"republish.mqtt.birth.cert.on.gps.lock\";\n    private static final String PAYLOAD_ENCODING = \"payload.encoding\";\n\n    private static final int LIFECYCLE_QOS = 1;\n    private static final int LIFECYCLE_PRIORITY = 0;\n    private static final boolean LIFECYCLE_RETAIN = false;\n\n    private final Map<String, Object> properties;\n    private final SystemService systemService;\n\n    CloudConnectionManagerOptions(Map<String, Object> properties, SystemService systemService) {\n        this.properties = properties;\n        this.systemService = systemService;\n    }\n\n    /**\n     * Returns the display name for the device.\n     *\n     * @return a String value.\n     */\n    public String getDeviceDisplayName() {\n        String displayName = \"\";\n        if (this.properties == null) {\n            return displayName;\n        }\n        String deviceDisplayNameOption = (String) this.properties.get(DEVICE_DISPLAY_NAME);\n\n        // Use the device name from SystemService. This should be kura.device.name from\n        // the properties file.\n        if (\"device-name\".equals(deviceDisplayNameOption)) {\n            displayName = this.systemService.getDeviceName();\n        }\n        // Try to get the device hostname\n        else if (\"hostname\".equals(deviceDisplayNameOption)) {\n            displayName = this.systemService.getHostname();\n        }\n        // Return the custom field defined by the user\n        else if (\"custom\".equals(deviceDisplayNameOption)\n                && this.properties.get(DEVICE_CUSTOM_NAME) instanceof String) {\n            displayName = (String) this.properties.get(DEVICE_CUSTOM_NAME);\n        }\n        // Return empty string to the server\n        else if (\"server\".equals(deviceDisplayNameOption)) {\n            displayName = \"\";\n        }\n\n        return displayName;\n    }\n\n    /**\n     * Returns true if the current CloudService configuration\n     * specifies Gzip compression enabled for outgoing payloads.\n     *\n     * @return a boolean value.\n     */\n    public boolean getEncodeGzip() {\n        boolean encodeGzip = false;\n        if (this.properties != null && this.properties.get(ENCODE_GZIP) != null\n                && this.properties.get(ENCODE_GZIP) instanceof Boolean) {\n            encodeGzip = (Boolean) this.properties.get(ENCODE_GZIP);\n        }\n        return encodeGzip;\n    }\n\n    /**\n     * Returns true if the current CloudService configuration\n     * specifies the cloud client should republish the MQTT birth\n     * certificate on GPS lock events.\n     *\n     * @return a boolean value.\n     */\n    public boolean getRepubBirthCertOnGpsLock() {\n        boolean repubBirth = false;\n        if (this.properties != null && this.properties.get(REPUB_BIRTH_ON_GPS_LOCK) != null\n                && this.properties.get(REPUB_BIRTH_ON_GPS_LOCK) instanceof Boolean) {\n            repubBirth = (Boolean) this.properties.get(REPUB_BIRTH_ON_GPS_LOCK);\n        }\n        return repubBirth;\n    }\n\n    /**\n     * This method parses the Cloud Service configuration and returns the selected cloud payload encoding.\n     * By default, this method returns {@link CloudPayloadEncoding} {@code KURA_PROTOBUF}.\n     *\n     * @return a boolean value.\n     */\n    public CloudPayloadEncoding getPayloadEncoding() {\n        CloudPayloadEncoding result = CloudPayloadEncoding.KURA_PROTOBUF;\n        String encodingString = \"\";\n        if (this.properties != null && this.properties.get(PAYLOAD_ENCODING) != null\n                && this.properties.get(PAYLOAD_ENCODING) instanceof String) {\n            encodingString = (String) this.properties.get(PAYLOAD_ENCODING);\n        }\n        try {\n            result = CloudPayloadEncoding.getEncoding(encodingString);\n        } catch (IllegalArgumentException e) {\n            logger.warn(\"Cannot parse the provided payload encoding.\", e);\n        }\n\n        return result;\n    }\n\n    public String getTopicSeparator() {\n        return TOPIC_SEPARATOR;\n    }\n\n    public String getTopicBirthSuffix() {\n        return TOPIC_BIRTH_SUFFIX;\n    }\n\n    public String getTopicDisconnectSuffix() {\n        return TOPIC_DISCONNECT_SUFFIX;\n    }\n\n    public String getTopicAppsSuffix() {\n        return TOPIC_APPS_SUFFIX;\n    }\n\n    public String getTopicWildCard() {\n        return TOPIC_WILD_CARD;\n    }\n\n    public int getLifeCycleMessageQos() {\n        return LIFECYCLE_QOS;\n    }\n\n    public int getLifeCycleMessagePriority() {\n        return LIFECYCLE_PRIORITY;\n    }\n\n    public boolean getLifeCycleMessageRetain() {\n        return LIFECYCLE_RETAIN;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPayloadEncoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport java.io.IOException;\n\n/**\n * Common interface for the PayloadEncoders\n */\n@FunctionalInterface\npublic interface CloudPayloadEncoder {\n\n    public byte[] getBytes() throws IOException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPayloadGZipEncoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport java.io.IOException;\n\nimport org.eclipse.kura.core.util.GZipUtil;\n\npublic class CloudPayloadGZipEncoder implements CloudPayloadEncoder {\n\n    private final CloudPayloadEncoder decorated;\n\n    public CloudPayloadGZipEncoder(CloudPayloadEncoder decorated) {\n        this.decorated = decorated;\n    }\n\n    @Override\n    public byte[] getBytes() throws IOException {\n        byte[] source = this.decorated.getBytes();\n        byte[] compressed = GZipUtil.compress(source);\n\n        // Return gzip compressed data only if shorter than uncompressed one\n        return compressed.length < source.length ? compressed : source;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPayloadProtoBufDecoderImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport java.io.IOException;\nimport java.util.Date;\n\nimport org.eclipse.kura.KuraInvalidMessageException;\nimport org.eclipse.kura.KuraInvalidMetricTypeException;\nimport org.eclipse.kura.core.util.GZipUtil;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.protobuf.ByteString;\nimport com.google.protobuf.InvalidProtocolBufferException;\n\npublic class CloudPayloadProtoBufDecoderImpl {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudPayloadProtoBufDecoderImpl.class);\n\n    private byte[] bytes;\n\n    public CloudPayloadProtoBufDecoderImpl(byte[] bytes) {\n        this.bytes = bytes;\n    }\n\n    /**\n     * Factory method to build an KuraPayload instance from a byte array.\n     *\n     * @param bytes\n     * @return\n     * @throws InvalidProtocolBufferException\n     * @throws IOException\n     */\n    public KuraPayload buildFromByteArray() throws IOException {\n        // Check if a compressed payload and try to decompress it\n        if (GZipUtil.isCompressed(this.bytes)) {\n            try {\n                this.bytes = GZipUtil.decompress(this.bytes);\n            } catch (IOException e) {\n                logger.info(\"Decompression failed\");\n                // do not rethrow the exception here as isCompressed may return some false positives\n            }\n        }\n\n        // build the KuraPayloadProto.KuraPayload\n        KuraPayloadProto.KuraPayload protoMsg = null;\n        try {\n            protoMsg = KuraPayloadProto.KuraPayload.parseFrom(this.bytes);\n        } catch (InvalidProtocolBufferException ipbe) {\n            throw new KuraInvalidMessageException(ipbe);\n        }\n\n        // build the KuraPayload\n        KuraPayload kuraMsg = new KuraPayload();\n\n        // set the timestamp\n        if (protoMsg.hasTimestamp()) {\n            kuraMsg.setTimestamp(new Date(protoMsg.getTimestamp()));\n        }\n\n        // set the position\n        if (protoMsg.hasPosition()) {\n            kuraMsg.setPosition(buildFromProtoBuf(protoMsg.getPosition()));\n        }\n\n        // set the metrics\n        for (int i = 0; i < protoMsg.getMetricCount(); i++) {\n            String name = protoMsg.getMetric(i).getName();\n            try {\n                Object value = getProtoKuraMetricValue(protoMsg.getMetric(i), protoMsg.getMetric(i).getType());\n                kuraMsg.addMetric(name, value);\n            } catch (KuraInvalidMetricTypeException ihte) {\n                logger.warn(\"During deserialization, ignoring metric named: {}. Unrecognized value type: {}\", name,\n                        protoMsg.getMetric(i).getType(), ihte);\n            }\n        }\n\n        // set the body\n        if (protoMsg.hasBody()) {\n            kuraMsg.setBody(protoMsg.getBody().toByteArray());\n        }\n\n        return kuraMsg;\n    }\n\n    private KuraPosition buildFromProtoBuf(KuraPayloadProto.KuraPayload.KuraPosition protoPosition) {\n        KuraPosition position = new KuraPosition();\n\n        if (protoPosition.hasLatitude()) {\n            position.setLatitude(protoPosition.getLatitude());\n        }\n        if (protoPosition.hasLongitude()) {\n            position.setLongitude(protoPosition.getLongitude());\n        }\n        if (protoPosition.hasAltitude()) {\n            position.setAltitude(protoPosition.getAltitude());\n        }\n        if (protoPosition.hasPrecision()) {\n            position.setPrecision(protoPosition.getPrecision());\n        }\n        if (protoPosition.hasHeading()) {\n            position.setHeading(protoPosition.getHeading());\n        }\n        if (protoPosition.hasSpeed()) {\n            position.setSpeed(protoPosition.getSpeed());\n        }\n        if (protoPosition.hasSatellites()) {\n            position.setSatellites(protoPosition.getSatellites());\n        }\n        if (protoPosition.hasStatus()) {\n            position.setStatus(protoPosition.getStatus());\n        }\n        if (protoPosition.hasTimestamp()) {\n            position.setTimestamp(new Date(protoPosition.getTimestamp()));\n        }\n        return position;\n    }\n\n    private Object getProtoKuraMetricValue(KuraPayloadProto.KuraPayload.KuraMetric metric,\n            KuraPayloadProto.KuraPayload.KuraMetric.ValueType type) throws KuraInvalidMetricTypeException {\n        switch (type) {\n\n        case DOUBLE:\n            return metric.getDoubleValue();\n\n        case FLOAT:\n            return metric.getFloatValue();\n\n        case INT64:\n            return metric.getLongValue();\n\n        case INT32:\n            return metric.getIntValue();\n\n        case BOOL:\n            return metric.getBoolValue();\n\n        case STRING:\n            return metric.getStringValue();\n\n        case BYTES:\n            ByteString bs = metric.getBytesValue();\n            return bs.toByteArray();\n\n        default:\n            throw new KuraInvalidMetricTypeException(type);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPayloadProtoBufEncoderImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport java.io.IOException;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraInvalidMetricTypeException;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.protobuf.ByteString;\n\n/**\n * Encodes an KuraPayload class using the Google ProtoBuf binary format.\n */\npublic class CloudPayloadProtoBufEncoderImpl implements CloudPayloadEncoder {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudPayloadProtoBufEncoderImpl.class);\n\n    private final KuraPayload kuraPayload;\n\n    public CloudPayloadProtoBufEncoderImpl(KuraPayload kuraPayload) {\n        this.kuraPayload = kuraPayload;\n    }\n\n    /**\n     * Conversion method to serialize an KuraPayload instance into a byte array.\n     *\n     * @return\n     */\n    @Override\n    public byte[] getBytes() throws IOException {\n        // Build the message\n        KuraPayloadProto.KuraPayload.Builder protoMsg = KuraPayloadProto.KuraPayload.newBuilder();\n\n        // set the timestamp\n        if (this.kuraPayload.getTimestamp() != null) {\n            protoMsg.setTimestamp(this.kuraPayload.getTimestamp().getTime());\n        }\n\n        // set the position\n        if (this.kuraPayload.getPosition() != null) {\n            protoMsg.setPosition(buildPositionProtoBuf());\n        }\n\n        // set the metrics\n        for (final Map.Entry<String, Object> entry : this.kuraPayload.metrics().entrySet()) {\n            final String name = entry.getKey();\n            final Object value = entry.getValue();\n\n            // build a metric\n            try {\n                KuraMetric.Builder metricB = KuraMetric.newBuilder();\n                metricB.setName(name);\n\n                boolean result = setProtoKuraMetricValue(metricB, value);\n                if (result) {\n                    // add it to the message\n                    protoMsg.addMetric(metricB);\n                }\n            } catch (KuraInvalidMetricTypeException e) {\n                logger.error(\"During serialization, ignoring metric named: {}. Unrecognized value type: {}.\", name,\n                        value != null ? value.getClass().getName() : \"<null>\");\n                throw new RuntimeException(e);\n            }\n        }\n\n        // set the body\n        if (this.kuraPayload.getBody() != null) {\n            protoMsg.setBody(ByteString.copyFrom(this.kuraPayload.getBody()));\n        }\n\n        return protoMsg.build().toByteArray();\n    }\n\n    //\n    // Helper methods to convert the KuraMetrics\n    //\n    private KuraPayloadProto.KuraPayload.KuraPosition buildPositionProtoBuf() {\n        KuraPayloadProto.KuraPayload.KuraPosition.Builder protoPos = KuraPayloadProto.KuraPayload.KuraPosition\n                .newBuilder();\n\n        KuraPosition position = this.kuraPayload.getPosition();\n        if (position.getLatitude() != null) {\n            protoPos.setLatitude(position.getLatitude());\n        }\n        if (position.getLongitude() != null) {\n            protoPos.setLongitude(position.getLongitude());\n        }\n        if (position.getAltitude() != null) {\n            protoPos.setAltitude(position.getAltitude());\n        }\n        if (position.getPrecision() != null) {\n            protoPos.setPrecision(position.getPrecision());\n        }\n        if (position.getHeading() != null) {\n            protoPos.setHeading(position.getHeading());\n        }\n        if (position.getSpeed() != null) {\n            protoPos.setSpeed(position.getSpeed());\n        }\n        if (position.getTimestamp() != null) {\n            protoPos.setTimestamp(position.getTimestamp().getTime());\n        }\n        if (position.getSatellites() != null) {\n            protoPos.setSatellites(position.getSatellites());\n        }\n        if (position.getStatus() != null) {\n            protoPos.setStatus(position.getStatus());\n        }\n        return protoPos.build();\n    }\n\n    private static boolean setProtoKuraMetricValue(KuraPayloadProto.KuraPayload.KuraMetric.Builder metric, Object o)\n            throws KuraInvalidMetricTypeException {\n\n        if (o instanceof String) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.STRING);\n            metric.setStringValue((String) o);\n        } else if (o instanceof Double) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE);\n            metric.setDoubleValue((Double) o);\n        } else if (o instanceof Integer) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.INT32);\n            metric.setIntValue((Integer) o);\n        } else if (o instanceof Float) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.FLOAT);\n            metric.setFloatValue((Float) o);\n        } else if (o instanceof Long) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.INT64);\n            metric.setLongValue((Long) o);\n        } else if (o instanceof Boolean) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.BOOL);\n            metric.setBoolValue((Boolean) o);\n        } else if (o instanceof byte[]) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.BYTES);\n            metric.setBytesValue(ByteString.copyFrom((byte[]) o));\n        } else if (o == null) {\n            logger.warn(\"Received a metric with a null value!\");\n            return false;\n        } else {\n            throw new KuraInvalidMetricTypeException(o.getClass().getName());\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPublisherDeliveryListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\npublic interface CloudPublisherDeliveryListener {\n\n    public void onMessageConfirmed(String messageId, String topic);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudServiceLifecycleCertsPolicy.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\n/**\n * This enum provides the necessary constants to denote the policy for the lifecycle messages.\n */\npublic enum CloudServiceLifecycleCertsPolicy {\n\n    DISABLE_PUBLISHING(\"disable\"),\n    PUBLISH_BIRTH_CONNECT_ONLY(\"birth-connect\"),\n    PUBLISH_BIRTH_CONNECT_RECONNECT(\"birth-connect-reconnect\");\n\n    private String birthPolicy;\n\n    private CloudServiceLifecycleCertsPolicy(String policy) {\n        this.birthPolicy = policy;\n    }\n\n    public String getValue() {\n        return this.birthPolicy;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudSubscriptionRecord.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\n\npublic class CloudSubscriptionRecord {\n\n    private final String topic;\n    private final int qos;\n    private final CloudSubscriberListener subscriber;\n\n    public CloudSubscriptionRecord(String topic, int qos, CloudSubscriberListener subscriber) {\n        this.topic = topic;\n        this.qos = qos;\n        this.subscriber = subscriber;\n    }\n\n    public String getTopic() {\n        return this.topic;\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    public CloudSubscriberListener getSubscriber() {\n        return this.subscriber;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/ControlTopic.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType;\nimport org.eclipse.kura.message.KuraApplicationTopic;\n\npublic class ControlTopic extends KuraApplicationTopic {\n\n    private String fullTopic;\n    private String[] topicParts;\n    private String prefix;\n    private String accountName;\n    private String deviceId;\n    private String req;\n    private String reqId;\n\n    public ControlTopic(String fullTopic) {\n        this(fullTopic, MessageType.CONTROL.getTopicPrefix());\n    }\n\n    public ControlTopic(String fullTopic, String controlPrefix) {\n        this.fullTopic = fullTopic;\n        if (fullTopic.compareTo(\"#\") == 0) {\n            return;\n        }\n\n        this.topicParts = fullTopic.split(\"/\");\n        if (this.topicParts.length == 0) {\n            return;\n        }\n\n        // prefix\n        int index = 0;\n        int offset = 0; // skip a slash\n        if (this.topicParts[0].startsWith(controlPrefix)) {\n            this.prefix = this.topicParts[index];\n            offset += this.prefix.length() + 1;\n            index++;\n        }\n\n        // account name\n        if (index < this.topicParts.length) {\n            this.accountName = this.topicParts[index];\n            offset += this.accountName.length() + 1;\n            index++;\n        }\n\n        // deviceId\n        if (index < this.topicParts.length) {\n            this.deviceId = this.topicParts[index];\n            offset += this.deviceId.length() + 1;\n            index++;\n        }\n\n        // req\n        // to skip?\n        if (index < this.topicParts.length) {\n            this.req = this.topicParts[index];\n            offset += this.req.length() + 1;\n            index++;\n        }\n\n        // reqId\n        if (index < this.topicParts.length) {\n            this.reqId = this.topicParts[index];\n            offset += this.reqId.length() + 1;\n            index++;\n        }\n\n        // applicationId\n        if (index < this.topicParts.length) {\n            this.applicationId = this.topicParts[index];\n            offset += this.applicationId.length() + 1;\n            index++;\n        }\n        if (offset < this.fullTopic.length()) {\n            this.applicationTopic = this.fullTopic.substring(offset);\n        }\n    }\n\n    public String getFullTopic() {\n        return this.fullTopic;\n    }\n\n    public String[] getTopicParts() {\n        return this.topicParts;\n    }\n\n    public String getPrefix() {\n        return this.prefix;\n    }\n\n    public String getAccountName() {\n        return this.accountName;\n    }\n\n    public String getDeviceId() {\n        return this.deviceId;\n    }\n\n    public String getReqId() {\n        return this.reqId;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/LifeCyclePayloadBuilder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.core.util.NetUtil;\nimport org.eclipse.kura.message.KuraBirthPayload;\nimport org.eclipse.kura.message.KuraBirthPayload.KuraBirthPayloadBuilder;\nimport org.eclipse.kura.message.KuraDeviceProfile;\nimport org.eclipse.kura.message.KuraDisconnectPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.eclipse.kura.net.NetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.eclipse.kura.net.NetworkService;\nimport org.eclipse.kura.position.PositionService;\nimport org.eclipse.kura.system.SystemAdminService;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.util.position.Position;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Utility class to build lifecycle payload messages.\n */\npublic class LifeCyclePayloadBuilder {\n\n    private static final String ERROR = \"ERROR\";\n\n    private static final Logger logger = LoggerFactory.getLogger(LifeCyclePayloadBuilder.class);\n\n    private static final String UNKNOWN = \"UNKNOWN\";\n\n    private final CloudConnectionManagerImpl cloudConnectionManagerImpl;\n\n    LifeCyclePayloadBuilder(CloudConnectionManagerImpl cloudConnectionManagerImpl) {\n        this.cloudConnectionManagerImpl = cloudConnectionManagerImpl;\n    }\n\n    public KuraBirthPayload buildBirthPayload() {\n        // build device profile\n        KuraDeviceProfile deviceProfile = buildDeviceProfile();\n\n        // build accept encoding\n        String acceptEncoding = buildAcceptEncoding();\n\n        // build device name\n        CloudConnectionManagerOptions cso = this.cloudConnectionManagerImpl.getCloudConnectionManagerOptions();\n        String deviceName = cso.getDeviceDisplayName();\n        if (deviceName == null) {\n            deviceName = this.cloudConnectionManagerImpl.getSystemService().getDeviceName();\n        }\n\n        String payloadEncoding = this.cloudConnectionManagerImpl.getCloudConnectionManagerOptions().getPayloadEncoding()\n                .name();\n\n        // build birth certificate\n        KuraBirthPayloadBuilder birthPayloadBuilder = new KuraBirthPayloadBuilder();\n        birthPayloadBuilder.withUptime(deviceProfile.getUptime()).withDisplayName(deviceName)\n                .withModelName(deviceProfile.getModelName()).withModelId(deviceProfile.getModelId())\n                .withPartNumber(deviceProfile.getPartNumber()).withSerialNumber(deviceProfile.getSerialNumber())\n                .withFirmwareVersion(deviceProfile.getFirmwareVersion()).withBiosVersion(deviceProfile.getBiosVersion())\n                .withCpuVersion(deviceProfile.getCpuVersion()).withOs(deviceProfile.getOs())\n                .withOsVersion(deviceProfile.getOsVersion()).withJvmName(deviceProfile.getJvmName())\n                .withJvmVersion(deviceProfile.getJvmVersion()).withJvmProfile(deviceProfile.getJvmProfile())\n                .withKuraVersion(deviceProfile.getApplicationFrameworkVersion())\n                .withConnectionInterface(deviceProfile.getConnectionInterface())\n                .withConnectionIp(deviceProfile.getConnectionIp()).withAcceptEncoding(acceptEncoding)\n                .withAvailableProcessors(deviceProfile.getAvailableProcessors())\n                .withTotalMemory(deviceProfile.getTotalMemory()).withOsArch(deviceProfile.getOsArch())\n                .withOsgiFramework(deviceProfile.getOsgiFramework())\n                .withOsgiFrameworkVersion(deviceProfile.getOsgiFrameworkVersion()).withPayloadEncoding(payloadEncoding)\n                .withJvmVendor(deviceProfile.getJvmVendor()).withJdkVendorVersion(deviceProfile.getJdkVendorVersion());\n\n        if (this.cloudConnectionManagerImpl.imei != null && this.cloudConnectionManagerImpl.imei.length() > 0\n                && !this.cloudConnectionManagerImpl.imei.equals(ERROR)) {\n            birthPayloadBuilder.withModemImei(this.cloudConnectionManagerImpl.imei);\n        }\n        if (this.cloudConnectionManagerImpl.iccid != null && this.cloudConnectionManagerImpl.iccid.length() > 0\n                && !this.cloudConnectionManagerImpl.iccid.equals(ERROR)) {\n            birthPayloadBuilder.withModemIccid(this.cloudConnectionManagerImpl.iccid);\n        }\n\n        if (this.cloudConnectionManagerImpl.imsi != null && this.cloudConnectionManagerImpl.imsi.length() > 0\n                && !this.cloudConnectionManagerImpl.imsi.equals(ERROR)) {\n            birthPayloadBuilder.withModemImsi(this.cloudConnectionManagerImpl.imsi);\n        }\n\n        if (this.cloudConnectionManagerImpl.rssi != null && this.cloudConnectionManagerImpl.rssi.length() > 0) {\n            birthPayloadBuilder.withModemRssi(this.cloudConnectionManagerImpl.rssi);\n        }\n\n        if (this.cloudConnectionManagerImpl.modemFwVer != null\n                && this.cloudConnectionManagerImpl.modemFwVer.length() > 0\n                && !this.cloudConnectionManagerImpl.modemFwVer.equals(ERROR)) {\n            birthPayloadBuilder.withModemFirmwareVersion(this.cloudConnectionManagerImpl.modemFwVer);\n        }\n\n        if (deviceProfile.getLatitude() != null && deviceProfile.getLongitude() != null) {\n            KuraPosition kuraPosition = new KuraPosition();\n            kuraPosition.setLatitude(deviceProfile.getLatitude());\n            kuraPosition.setLongitude(deviceProfile.getLongitude());\n            kuraPosition.setAltitude(deviceProfile.getAltitude());\n            birthPayloadBuilder.withPosition(kuraPosition);\n        }\n\n        return birthPayloadBuilder.build();\n    }\n\n    public KuraDisconnectPayload buildDisconnectPayload() {\n        SystemService systemService = this.cloudConnectionManagerImpl.getSystemService();\n        SystemAdminService sysAdminService = this.cloudConnectionManagerImpl.getSystemAdminService();\n        CloudConnectionManagerOptions cloudOptions = this.cloudConnectionManagerImpl.getCloudConnectionManagerOptions();\n\n        // build device name\n        String deviceName = cloudOptions.getDeviceDisplayName();\n        if (deviceName == null) {\n            deviceName = systemService.getDeviceName();\n        }\n\n        return new KuraDisconnectPayload(sysAdminService.getUptime(), deviceName);\n    }\n\n    public KuraDeviceProfile buildDeviceProfile() {\n        SystemService systemService = this.cloudConnectionManagerImpl.getSystemService();\n        SystemAdminService sysAdminService = this.cloudConnectionManagerImpl.getSystemAdminService();\n        Optional<NetworkService> networkService = this.cloudConnectionManagerImpl.getNetworkService();\n        Optional<PositionService> positionService = this.cloudConnectionManagerImpl.getPositionService();\n\n        //\n        // get the network information\n        StringBuilder sbConnectionIp = new StringBuilder();\n        StringBuilder sbConnectionInterface = new StringBuilder();\n        networkService.ifPresent(ns -> {\n            try {\n                List<NetInterface<? extends NetInterfaceAddress>> nis = ns.getActiveNetworkInterfaces();\n                if (!nis.isEmpty()) {\n                    for (NetInterface<? extends NetInterfaceAddress> ni : nis) {\n                        List<? extends NetInterfaceAddress> nias = ni.getNetInterfaceAddresses();\n                        if (nias != null && !nias.isEmpty()) {\n                            sbConnectionInterface.append(buildConnectionInterface(ni)).append(\",\");\n                            sbConnectionIp.append(buildConnectionIp(ni)).append(\",\");\n                        }\n                    }\n\n                    // Remove trailing comma\n                    sbConnectionIp.deleteCharAt(sbConnectionIp.length() - 1);\n                    sbConnectionInterface.deleteCharAt(sbConnectionInterface.length() - 1);\n                }\n            } catch (Exception se) {\n                logger.warn(\"Error while getting ConnetionIP and ConnectionInterface\", se);\n            }\n        });\n\n        String connectionIp = !sbConnectionIp.isEmpty() ? sbConnectionIp.toString() : UNKNOWN;\n        String connectionInterface = !sbConnectionInterface.isEmpty() ? sbConnectionInterface.toString() : UNKNOWN;\n\n        //\n        // get the position information\n        double latitude = 0.0;\n        double longitude = 0.0;\n        double altitude = 0.0;\n        if (positionService.isPresent()) {\n            Position position = positionService.get().getPosition();\n            if (position != null) {\n                latitude = Math.toDegrees(position.getLatitude().getValue());\n                longitude = Math.toDegrees(position.getLongitude().getValue());\n                altitude = position.getAltitude().getValue();\n            } else {\n                logger.warn(\"Unresolved PositionService reference.\");\n            }\n        }\n\n        return buildKuraDeviceProfile(systemService, sysAdminService, connectionIp, connectionInterface, latitude,\n                longitude, altitude);\n    }\n\n    private KuraDeviceProfile buildKuraDeviceProfile(SystemService systemService, SystemAdminService sysAdminService,\n            String connectionIp, String connectionInterface, double latitude, double longitude, double altitude) {\n        KuraDeviceProfile kuraDeviceProfile = new KuraDeviceProfile();\n        kuraDeviceProfile.setUptime(sysAdminService.getUptime());\n        kuraDeviceProfile.setDisplayName(systemService.getDeviceName());\n        kuraDeviceProfile.setModelName(systemService.getModelName());\n        kuraDeviceProfile.setModelId(systemService.getModelId());\n        kuraDeviceProfile.setPartNumber(systemService.getPartNumber());\n        kuraDeviceProfile.setSerialNumber(systemService.getSerialNumber());\n        kuraDeviceProfile.setFirmwareVersion(systemService.getFirmwareVersion());\n        kuraDeviceProfile.setBiosVersion(systemService.getBiosVersion());\n        kuraDeviceProfile.setOs(systemService.getOsName());\n        kuraDeviceProfile.setOsVersion(systemService.getOsVersion());\n        kuraDeviceProfile.setCpuVersion(systemService.getCpuVersion());\n        kuraDeviceProfile.setJvmName(systemService.getJavaVmName());\n        kuraDeviceProfile.setJvmVersion(systemService.getJavaVmVersion() + \" \" + systemService.getJavaVmInfo());\n        kuraDeviceProfile.setJvmProfile(systemService.getJavaVendor() + \" \" + systemService.getJavaVersion());\n        kuraDeviceProfile.setApplicationFramework(KuraDeviceProfile.DEFAULT_APPLICATION_FRAMEWORK);\n        kuraDeviceProfile.setApplicationFrameworkVersion(systemService.getKuraVersion());\n        kuraDeviceProfile.setConnectionInterface(connectionInterface);\n        kuraDeviceProfile.setConnectionIp(connectionIp);\n        kuraDeviceProfile.setLatitude(latitude);\n        kuraDeviceProfile.setLongitude(longitude);\n        kuraDeviceProfile.setAltitude(altitude);\n        kuraDeviceProfile.setAvailableProcessors(String.valueOf(systemService.getNumberOfProcessors()));\n        kuraDeviceProfile.setTotalMemory(String.valueOf(systemService.getTotalMemory()));\n        kuraDeviceProfile.setOsArch(systemService.getOsArch());\n        kuraDeviceProfile.setOsgiFramework(systemService.getOsgiFwName());\n        kuraDeviceProfile.setOsgiFrameworkVersion(systemService.getOsgiFwVersion());\n        kuraDeviceProfile.setJvmVendor(systemService.getJavaVmVendor());\n        kuraDeviceProfile.setJdkVendorVersion(systemService.getJdkVendorVersion());\n        return kuraDeviceProfile;\n    }\n\n    private String buildConnectionIp(NetInterface<? extends NetInterfaceAddress> ni) {\n        String connectionIp = UNKNOWN;\n        List<? extends NetInterfaceAddress> nias = ni.getNetInterfaceAddresses();\n        if (nias != null && !nias.isEmpty() && nias.get(0).getAddress() != null) {\n            connectionIp = nias.get(0).getAddress().getHostAddress();\n        }\n        return connectionIp;\n    }\n\n    private String buildConnectionInterface(NetInterface<? extends NetInterfaceAddress> ni) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(ni.getName()).append(\" (\").append(NetUtil.hardwareAddressToString(ni.getHardwareAddress()))\n                .append(\")\");\n        return sb.toString();\n    }\n\n    private String buildAcceptEncoding() {\n        String acceptEncoding = \"\";\n        CloudConnectionManagerOptions options = this.cloudConnectionManagerImpl.getCloudConnectionManagerOptions();\n        if (options.getEncodeGzip()) {\n            acceptEncoding = \"gzip\";\n        }\n        return acceptEncoding;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/LifecycleMessage.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType;\nimport org.eclipse.kura.message.KuraPayload;\n\npublic class LifecycleMessage {\n    \n    private StringBuilder topicBuilder;\n    private CloudConnectionManagerOptions options;\n    private LifeCyclePayloadBuilder payloadBuilder;\n    private KuraPayload payload;\n\n    public LifecycleMessage(CloudConnectionManagerOptions options, CloudConnectionManagerImpl cloudServiceImpl) {\n        this.options = options;\n\n        this.topicBuilder = new StringBuilder(MessageType.EVENT.getTopicPrefix());\n        this.topicBuilder.append(this.options.getTopicSeparator()).append(this.options.getTopicSeparator())\n                .append(this.options.getTopicSeparator());\n        \n        this.payloadBuilder = new LifeCyclePayloadBuilder(cloudServiceImpl);\n    }\n\n    public LifecycleMessage asBirthCertificateMessage() {\n        this.topicBuilder.append(this.options.getTopicBirthSuffix());\n        this.payload = this.payloadBuilder.buildBirthPayload();\n        return this;\n    }\n\n    public LifecycleMessage asDisconnectCertificateMessage() {\n        this.topicBuilder.append(this.options.getTopicDisconnectSuffix());\n        this.payload = this.payloadBuilder.buildDisconnectPayload();\n        return this;\n    }\n\n    public String getTopic() {\n        return this.topicBuilder.toString();\n    }\n\n    public KuraPayload getPayload() {\n        return this.payload;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/MessageHandlerCallable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud;\n\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerContextConstants.NOTIFICATION_PUBLISHER_PID;\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Callable;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.audit.AuditConstants;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.audit.AuditContext.Scope;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerContext;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class MessageHandlerCallable implements Callable<Void> {\n\n    private static final Logger auditLogger = LoggerFactory.getLogger(\"AuditLogger\");\n    private static final Logger logger = LoggerFactory.getLogger(MessageHandlerCallable.class);\n\n    private static final Pattern RESOURCES_DELIM = Pattern.compile(\"/\");\n\n    public static final String METRIC_REQUEST_ID = \"request.id\";\n    public static final String REQUESTER_CLIENT_ID = \"requester.client.id\";\n\n    public static final String METRIC_RESPONSE_CODE = \"response.code\";\n    public static final String METRIC_EXCEPTION_MSG = \"response.exception.message\";\n    public static final String METRIC_EXCEPTION_STACK = \"response.exception.stack\";\n\n    public static final int RESPONSE_CODE_OK = 200;\n    public static final int RESPONSE_CODE_BAD_REQUEST = 400;\n    public static final int RESPONSE_CODE_NOTFOUND = 404;\n    public static final int RESPONSE_CODE_ERROR = 500;\n\n    protected static final int DFLT_PUB_QOS = 0;\n    protected static final boolean DFLT_RETAIN = false;\n    protected static final int DFLT_PRIORITY = 1;\n\n    private final RequestHandler cloudApp;\n    private final String appTopic;\n    private final KuraPayload kuraMessage;\n    private final CloudConnectionManagerImpl cloudConnectionManager;\n    private final RequestHandlerContext requestHandlerContext;\n\n    public MessageHandlerCallable(RequestHandler cloudApp, String appTopic, KuraPayload msg,\n            CloudConnectionManagerImpl cloudConnectionManager) {\n        super();\n        this.cloudApp = cloudApp;\n        this.appTopic = appTopic;\n        this.kuraMessage = msg;\n        this.cloudConnectionManager = cloudConnectionManager;\n\n        String notificationPublisherPid = null; // TODO: this.cloudConnectionManager.getNotificationPublisherPid();\n        CloudNotificationPublisher notificationPublisher = null; // TODO:\n                                                                 // this.cloudConnectionManager.getNotificationPublisher();\n        Map<String, String> contextProperties = new HashMap<>();\n        contextProperties.put(NOTIFICATION_PUBLISHER_PID.name(), notificationPublisherPid);\n\n        this.requestHandlerContext = new RequestHandlerContext(notificationPublisher, contextProperties);\n    }\n\n    @Override\n    public Void call() throws Exception {\n        logger.debug(\"Control Arrived on topic: {}\", this.appTopic);\n\n        String requestId = (String) this.kuraMessage.getMetric(METRIC_REQUEST_ID);\n        if (requestId == null) {\n        if(logger.isDebugEnabled()) {\n            logger.debug(\"Request Id is null\"); \n        }\n            throw new ParseException(\"Not a valid request payload\", 0);\n        }\n\n        // Prepare the default response\n        KuraPayload reqPayload = this.kuraMessage;\n        KuraMessage response;\n\n        final Map<String, String> auditProperties = new HashMap<>();\n\n        auditProperties.put(AuditConstants.KEY_ENTRY_POINT.getValue(), \"EclipseIoTCloudConnectionService\");\n        auditProperties.put(\"cloud.app.topic\", appTopic);\n        auditProperties.put(\"cloud.connection.pid\", cloudConnectionManager.getOwnPid());\n\n        try (final Scope scope = AuditContext.openScope(new AuditContext(auditProperties))) {\n            try {\n                Iterator<String> resources = RESOURCES_DELIM.splitAsStream(this.appTopic).iterator();\n\n                if (!resources.hasNext()) {\n                    throw new IllegalArgumentException();\n                }\n\n                String method = resources.next();\n\n                Map<String, Object> reqResources = getMessageResources(resources);\n\n                KuraMessage reqMessage = new KuraMessage(reqPayload, reqResources);\n\n                switch (method) {\n                case \"GET\":\n                    logger.debug(\"Handling GET request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doGet(this.requestHandlerContext, reqMessage);\n                    break;\n\n                case \"PUT\":\n                    logger.debug(\"Handling PUT request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doPut(this.requestHandlerContext, reqMessage);\n                    break;\n\n                case \"POST\":\n                    logger.debug(\"Handling POST request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doPost(this.requestHandlerContext, reqMessage);\n                    break;\n\n                case \"DEL\":\n                    logger.debug(\"Handling DEL request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doDel(this.requestHandlerContext, reqMessage);\n                    break;\n\n                case \"EXEC\":\n                    logger.debug(\"Handling EXEC request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doExec(this.requestHandlerContext, reqMessage);\n                    break;\n\n                default:\n                    logger.error(\"Bad request topic: {}\", this.appTopic);\n                    KuraPayload payload = new KuraPayload();\n                    response = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST);\n                    break;\n                }\n            } catch (IllegalArgumentException e) {\n                logger.error(\"Bad request topic: {}\", this.appTopic);\n                KuraPayload payload = new KuraPayload();\n                response = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST);\n            } catch (KuraException e) {\n                logger.error(\"Error handling request topic: {}\", this.appTopic, e);\n                response = manageException(e);\n            }\n\n            final Object responseCode = response.getPayload().getMetric(METRIC_RESPONSE_CODE);\n            final boolean isSuccessful = responseCode instanceof Integer && ((Integer) responseCode) / 200 == 1;\n\n            if (isSuccessful) {\n                auditLogger.info(\"{} CloudCall - Success - Execute RequestHandler call\", AuditContext.currentOrInternal());\n            } else {\n                auditLogger.warn(\"{} CloudCall - Failure - Execute RequestHandler call\", AuditContext.currentOrInternal());\n            }\n\n            buildResponseMessage(requestId, response);\n        }\n        return null;\n    }\n\n    private void buildResponseMessage(String requestId, KuraMessage response) {\n        try {\n            response.getPayload().setTimestamp(new Date());\n\n            DataService dataService = this.cloudConnectionManager.getDataService();\n            String fullTopic = encodeTopic(requestId,\n                    String.valueOf(response.getPayload().getMetric(METRIC_RESPONSE_CODE)));\n            byte[] appPayload = this.cloudConnectionManager.encodePayload(response.getPayload());\n            dataService.publish(fullTopic, appPayload, DFLT_PUB_QOS, DFLT_RETAIN, DFLT_PRIORITY);\n        } catch (KuraException e) {\n            logger.error(\"Error publishing response for topic: {}\\n{}\", this.appTopic, e);\n        }\n    }\n\n    private KuraMessage manageException(KuraException e) {\n        KuraMessage message;\n        KuraPayload payload = new KuraPayload();\n        setException(payload, e);\n        if (e.getCode().equals(KuraErrorCode.BAD_REQUEST)) {\n            message = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST);\n        } else if (e.getCode().equals(KuraErrorCode.NOT_FOUND)) {\n            message = setResponseCode(payload, RESPONSE_CODE_NOTFOUND);\n        } else {\n            message = setResponseCode(payload, RESPONSE_CODE_ERROR);\n        }\n        return message;\n    }\n\n    private Map<String, Object> getMessageResources(Iterator<String> iter) {\n        List<String> resourcesList = new ArrayList<>();\n        while (iter.hasNext()) {\n            resourcesList.add(iter.next());\n        }\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(ARGS_KEY.value(), resourcesList);\n        return properties;\n    }\n\n    public KuraMessage setResponseCode(KuraPayload payload, int responseCode) {\n        payload.addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode));\n        return new KuraMessage(payload);\n    }\n\n    public void setException(KuraPayload payload, Throwable t) {\n        if (t != null) {\n            payload.addMetric(METRIC_EXCEPTION_MSG, t.getMessage());\n            payload.addMetric(METRIC_EXCEPTION_STACK, stackTraceAsString(t));\n        }\n    }\n\n    private String stackTraceAsString(Throwable t) {\n        StringWriter sw = new StringWriter();\n        PrintWriter pw = new PrintWriter(sw);\n        t.printStackTrace(pw);\n        return sw.toString();\n    }\n\n    private String encodeTopic(String requestId, String responseCode) {\n        CloudConnectionManagerOptions options = this.cloudConnectionManager.getCloudConnectionManagerOptions();\n        String topicSeparator = options.getTopicSeparator();\n        StringBuilder sb = new StringBuilder();\n\n        // fixed response topic subsection\n        sb.append(MessageType.CONTROL.getTopicPrefix()).append(topicSeparator).append(topicSeparator)\n                .append(topicSeparator).append(\"res\");\n\n        // variable response topic part\n        sb.append(topicSeparator).append(requestId).append(topicSeparator).append(responseCode);\n\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/factory/DefaultCloudConnectionFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.factory;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.component.ComponentConstants;\n\n/**\n * The Kura default {@link CloudConnectionFactory} implements a three layer stack architecture.\n * Each layer is an OSGi Declarative Services Factory Component and provides a service as follows:\n *\n * <table>\n * <thead>\n * <tr>\n * <th>Factory PID</th>\n * <th>Service interface</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr>\n * <td>org.eclipse.kura.cloud.CloudService</td>\n * <td>{@link DataService}</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.data.DataService</td>\n * <td>{@link DataService}</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</td>\n * <td>{@link DataTransportService}</td>\n * </tr>\n * </tbody>\n * </table>\n * <br>\n * When a new CloudService is created the factory creates also a DataService and a DataTransportService.\n * Since the <i>pid</i> parameter of {@link #createConfiguration(String)} only specifies the PID of\n * the CloudService layer, a convention is needed to derive the PIDs of the lower layers.\n * <br>\n * <br>\n * The default stack instance is special.\n * For backward compatibility the PIDs of the default stack must be as follows:\n *\n * <table>\n * <thead>\n * <tr>\n * <th>PID (kura.service.pid)</th>\n * <th>Factory PID</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr>\n * <td>org.eclipse.kura.cloud.CloudService</td>\n * <td>org.eclipse.kura.cloud.CloudService</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.data.DataService</td>\n * <td>org.eclipse.kura.data.DataService</td>\n * </tr>\n * <tr>\n * <td></td>\n * <td>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</td>\n * </tr>\n * </tbody>\n * </table>\n * <br>\n *\n * For other stack instances the convention used to generate the PIDs for the lower layers is\n * to use the sub string in the CloudService PID starting after the first occurrence of the '-' character and append\n * the sub string to the PIDs of the default stack above, for example:\n *\n * <table>\n * <thead>\n * <tr>\n * <th>PID (kura.service.pid)</th>\n * <th>Factory PID</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr>\n * <td>org.eclipse.kura.cloud.CloudService-2</td>\n * <td>org.eclipse.kura.cloud.CloudService</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.data.DataService-2</td>\n * <td>org.eclipse.kura.data.DataService</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-2</td>\n * <td>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</td>\n * </tr>\n * </tbody>\n * </table>\n * <br>\n * The (configuration of) layer instances of each stack are persisted to Kura snapshot and\n * recreated at every Kura start.\n * On startup every stack must be properly reassembled with the right layer instances.\n * <br>\n * This can be achieved using a standard OSGi Declarative Services magic property set in a layer configuration\n * specifying the layer dependency on a specific PID of its next lower layer.\n * The following example shows this selective dependency mechanism for the DataService and MqttDataTransport services.\n * <br>\n * The DataService component definition specifies a dependency on a DataTransportService as follows:\n *\n * <pre>\n * &ltreference name=\"DataTransportService\"\n *              bind=\"setDataTransportService\"\n *              unbind=\"unsetDataTransportService\"\n *              cardinality=\"1..1\"\n *              policy=\"static\"\n *              interface=\"org.eclipse.kura.data.DataTransportService\"/&gt\n * </pre>\n *\n * <br>\n * The DataService with PID <i>org.eclipse.kura.data.DataService-2</i> needs to be activated\n * only when its dependency on a specific DataTransportService with\n * PID <i>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-2</i> is satisfied.\n * <br>\n * The OSGi Declarative Services specification provides a magic <i>&ltreference name&gt.target</i>\n * property that can be set at runtime to specify a selective dependency.\n * <br>\n * In the above example the <i>org.eclipse.kura.data.DataService-2</i> component instance will have a\n * <i>DataTransportService.target</i> property set to the value:\n *\n * <pre>\n * (kura.service.pid = org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport - 2)\n * </pre>\n *\n * <br>\n */\npublic class DefaultCloudConnectionFactory implements CloudConnectionFactory {\n\n    private static final String FACTORY_PID = \"org.eclipse.kura.cloud.mqtt.eclipseiot.internal.cloud.factory.DefaultCloudServiceFactory\";\n\n    // The following constants must match the factory component definitions\n    private static final String CLOUD_SERVICE_FACTORY_PID = \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\";\n    private static final String DATA_SERVICE_FACTORY_PID = \"org.eclipse.kura.data.DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    private static final String CLOUD_SERVICE_PID = \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager\";\n    private static final String DATA_SERVICE_PID = \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_PID = \"org.eclipse.kura.cloudconnection.eclipseiot.mqtt.MqttDataTransport\";\n\n    private static final String DATA_SERVICE_REFERENCE_NAME = \"DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = \"DataTransportService\";\n\n    private static final String REFERENCE_TARGET_VALUE_FORMAT = \"(\" + ConfigurationService.KURA_SERVICE_PID + \"=%s)\";\n\n    private static final Pattern MANAGED_CLOUD_SERVICE_PID_PATTERN = Pattern.compile(\n            \"^org\\\\.eclipse\\\\.kura\\\\.cloudconnection\\\\.eclipseiot\\\\.mqtt\\\\.ConnectionManager(-[a-zA-Z0-9]+)?$\");\n\n    private ConfigurationService configurationService;\n\n    protected void setConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    protected void unsetConfigurationService(ConfigurationService configurationService) {\n        if (configurationService == this.configurationService) {\n            this.configurationService = null;\n        }\n    }\n\n    @Override\n    public String getFactoryPid() {\n        return CLOUD_SERVICE_FACTORY_PID;\n    }\n\n    @Override\n    public void createConfiguration(String pid) throws KuraException {\n        String[] parts = pid.split(\"-\");\n        if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) {\n            String suffix = null;\n            if (parts.length > 1) {\n                suffix = parts[1];\n            }\n\n            String dataServicePid = DATA_SERVICE_PID;\n            String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID;\n            if (suffix != null) {\n                dataServicePid += \"-\" + suffix;\n                dataTransportServicePid += \"-\" + suffix;\n            }\n\n            // create the CloudService layer and set the selective dependency on the DataService PID\n            Map<String, Object> cloudServiceProperties = new HashMap<>();\n            String name = DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n            cloudServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataServicePid));\n            cloudServiceProperties.put(KURA_CLOUD_CONNECTION_FACTORY_PID, FACTORY_PID);\n\n            this.configurationService.createFactoryConfiguration(CLOUD_SERVICE_FACTORY_PID, pid, cloudServiceProperties,\n                    false);\n\n            // create the DataService layer and set the selective dependency on the DataTransportService PID\n            Map<String, Object> dataServiceProperties = new HashMap<>();\n            name = DATA_TRANSPORT_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n            dataServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid));\n\n            this.configurationService.createFactoryConfiguration(DATA_SERVICE_FACTORY_PID, dataServicePid,\n                    dataServiceProperties, false);\n\n            // create the DataTransportService layer and take a snapshot\n            this.configurationService.createFactoryConfiguration(DATA_TRANSPORT_SERVICE_FACTORY_PID,\n                    dataTransportServicePid, null, true);\n        } else {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Invalid PID '{}'\", pid);\n        }\n    }\n\n    @Override\n    public void deleteConfiguration(String pid) throws KuraException {\n        String[] parts = pid.split(\"-\");\n        if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) {\n            String suffix = null;\n            if (parts.length > 1) {\n                suffix = parts[1];\n            }\n\n            String dataServicePid = DATA_SERVICE_PID;\n            String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID;\n            if (suffix != null) {\n                dataServicePid += \"-\" + suffix;\n                dataTransportServicePid += \"-\" + suffix;\n            }\n\n            this.configurationService.deleteFactoryConfiguration(pid, false);\n            this.configurationService.deleteFactoryConfiguration(dataServicePid, false);\n            this.configurationService.deleteFactoryConfiguration(dataTransportServicePid, true);\n        }\n    }\n\n    @Override\n    public List<String> getStackComponentsPids(String pid) throws KuraException {\n        List<String> componentPids = new ArrayList<>();\n        String[] parts = pid.split(\"-\");\n        if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) {\n            String suffix = null;\n            if (parts.length > 1) {\n                suffix = parts[1];\n            }\n\n            String dataServicePid = DATA_SERVICE_PID;\n            String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID;\n            if (suffix != null) {\n                dataServicePid += \"-\" + suffix;\n                dataTransportServicePid += \"-\" + suffix;\n            }\n\n            componentPids.add(pid);\n            componentPids.add(dataServicePid);\n            componentPids.add(dataTransportServicePid);\n            return componentPids;\n        } else {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Invalid PID '{}'\", pid);\n        }\n    }\n\n    @Override\n    public Set<String> getManagedCloudConnectionPids() throws KuraException {\n\n        final BundleContext context = FrameworkUtil.getBundle(DefaultCloudConnectionFactory.class).getBundleContext();\n\n        try {\n            return context.getServiceReferences(CloudConnectionManager.class, null).stream().filter(ref -> {\n                final Object kuraServicePid = ref.getProperty(ConfigurationService.KURA_SERVICE_PID);\n\n                if (!(kuraServicePid instanceof String)) {\n                    return false;\n                }\n\n                return MANAGED_CLOUD_SERVICE_PID_PATTERN.matcher((String) kuraServicePid).matches()\n                        && FACTORY_PID.equals(ref.getProperty(KURA_CLOUD_CONNECTION_FACTORY_PID));\n            }).map(ref -> (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID)).collect(Collectors.toSet());\n        } catch (InvalidSyntaxException e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, e);\n        }\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/publisher/CloudPublisherImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.publisher;\n\nimport static java.util.Objects.nonNull;\nimport static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.FULL_TOPIC;\nimport static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.PRIORITY;\nimport static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.QOS;\nimport static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.RETAIN;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.CloudConnectionManagerImpl;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.CloudConnectionManagerOptions;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.CloudPublisherDeliveryListener;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudPublisherImpl\n        implements CloudPublisher, ConfigurableComponent, CloudConnectionListener, CloudPublisherDeliveryListener {\n\n    private final class CloudConnectionManagerTrackerCustomizer\n            implements ServiceTrackerCustomizer<CloudConnectionManager, CloudConnectionManager> {\n\n        @Override\n        public CloudConnectionManager addingService(final ServiceReference<CloudConnectionManager> reference) {\n            CloudConnectionManager tempCloudService = CloudPublisherImpl.this.bundleContext.getService(reference);\n\n            if (tempCloudService instanceof CloudConnectionManagerImpl) {\n                CloudPublisherImpl.this.cloudConnectionImpl = (CloudConnectionManagerImpl) tempCloudService;\n                CloudPublisherImpl.this.cloudConnectionImpl.registerCloudConnectionListener(CloudPublisherImpl.this);\n                CloudPublisherImpl.this.cloudConnectionImpl\n                        .registerCloudPublisherDeliveryListener(CloudPublisherImpl.this);\n                return tempCloudService;\n            } else {\n                CloudPublisherImpl.this.bundleContext.ungetService(reference);\n            }\n\n            return null;\n        }\n\n        @Override\n        public void removedService(final ServiceReference<CloudConnectionManager> reference,\n                final CloudConnectionManager service) {\n            CloudPublisherImpl.this.cloudConnectionImpl.unregisterCloudConnectionListener(CloudPublisherImpl.this);\n            CloudPublisherImpl.this.cloudConnectionImpl\n                    .unregisterCloudPublisherDeliveryListener(CloudPublisherImpl.this);\n            CloudPublisherImpl.this.cloudConnectionImpl = null;\n        }\n\n        @Override\n        public void modifiedService(ServiceReference<CloudConnectionManager> reference,\n                CloudConnectionManager service) {\n            // Not needed\n        }\n    }\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudPublisherImpl.class);\n\n    private static final String TOPIC_PATTERN_STRING = \"\\\\$([^\\\\s/]+)\";\n    private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING);\n\n    private final Set<CloudConnectionListener> cloudConnectionListeners = new CopyOnWriteArraySet<>();\n    private final Set<CloudDeliveryListener> cloudDeliveryListeners = new CopyOnWriteArraySet<>();\n\n    private ServiceTrackerCustomizer<CloudConnectionManager, CloudConnectionManager> cloudConnectionManagerTrackerCustomizer;\n    private ServiceTracker<CloudConnectionManager, CloudConnectionManager> cloudConnectionManagerTracker;\n\n    private CloudPublisherOptions cloudPublisherOptions;\n    private CloudConnectionManagerImpl cloudConnectionImpl;\n    private BundleContext bundleContext;\n\n    private final ExecutorService worker = Executors.newCachedThreadPool();\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        logger.debug(\"Activating Cloud Publisher...\");\n        this.bundleContext = componentContext.getBundleContext();\n\n        this.cloudPublisherOptions = new CloudPublisherOptions(properties);\n\n        this.cloudConnectionManagerTrackerCustomizer = new CloudConnectionManagerTrackerCustomizer();\n        initCloudConnectionManagerTracking();\n\n        logger.debug(\"Activating Cloud Publisher... Done\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.debug(\"Updating Cloud Publisher...\");\n\n        this.cloudPublisherOptions = new CloudPublisherOptions(properties);\n\n        if (nonNull(this.cloudConnectionManagerTracker)) {\n            this.cloudConnectionManagerTracker.close();\n        }\n        initCloudConnectionManagerTracking();\n\n        logger.debug(\"Updating Cloud Publisher... Done\");\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.debug(\"Deactivating Cloud Publisher...\");\n\n        if (nonNull(this.cloudConnectionManagerTracker)) {\n            this.cloudConnectionManagerTracker.close();\n        }\n\n        this.worker.shutdown();\n        logger.debug(\"Deactivating Cloud Publisher... Done\");\n    }\n\n    @Override\n    public String publish(KuraMessage message) throws KuraException {\n        if (this.cloudConnectionImpl == null) {\n            logger.info(\"Null cloud service\");\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, \"The Cloud Service is null.\");\n        }\n\n        if (message == null) {\n            logger.warn(\"Received null message!\");\n            throw new IllegalArgumentException();\n        }\n\n        MessageType messageType = this.cloudPublisherOptions.getMessageType();\n\n        String fullTopic = encodeFullTopic(message, messageType.getTopicPrefix());\n\n        int qos = messageType.getQos();\n        boolean retain = false;\n        int priority = messageType.getPriority();\n\n        Map<String, Object> publishMessageProps = new HashMap<>();\n        publishMessageProps.put(FULL_TOPIC.name(), fullTopic);\n        publishMessageProps.put(QOS.name(), qos);\n        publishMessageProps.put(RETAIN.name(), retain);\n        publishMessageProps.put(PRIORITY.name(), priority);\n\n        KuraMessage publishMessage = new KuraMessage(message.getPayload(), publishMessageProps);\n\n        return this.cloudConnectionImpl.publish(publishMessage);\n    }\n\n    private String encodeFullTopic(KuraMessage message, String topicPrefix) {\n        String fullTopic = encodeTopic(topicPrefix, this.cloudPublisherOptions.getSemanticTopic());\n        return fillTopicPlaceholders(fullTopic, message);\n    }\n\n    private void initCloudConnectionManagerTracking() {\n        String selectedCloudServicePid = this.cloudPublisherOptions.getCloudServicePid();\n        String filterString = String.format(\"(&(%s=%s)(kura.service.pid=%s))\", Constants.OBJECTCLASS,\n                CloudConnectionManager.class.getName(), selectedCloudServicePid);\n        Filter filter = null;\n        try {\n            filter = this.bundleContext.createFilter(filterString);\n        } catch (InvalidSyntaxException e) {\n            logger.error(\"Filter setup exception \", e);\n        }\n        this.cloudConnectionManagerTracker = new ServiceTracker<>(this.bundleContext, filter,\n                this.cloudConnectionManagerTrackerCustomizer);\n        this.cloudConnectionManagerTracker.open();\n    }\n\n    private String encodeTopic(String topicPrefix, String semanticTopic) {\n        CloudConnectionManagerOptions options = this.cloudConnectionImpl.getCloudConnectionManagerOptions();\n        String topicSeparator = options.getTopicSeparator();\n\n        StringBuilder sb = new StringBuilder();\n\n        sb.append(topicPrefix).append(topicSeparator).append(topicSeparator);\n\n        if (semanticTopic != null && !semanticTopic.isEmpty()) {\n            sb.append(topicSeparator).append(semanticTopic);\n        }\n\n        return sb.toString();\n    }\n\n    private String fillTopicPlaceholders(String semanticTopic, KuraMessage message) {\n        Matcher matcher = TOPIC_PATTERN.matcher(semanticTopic);\n        StringBuffer buffer = new StringBuffer();\n\n        while (matcher.find()) {\n            Map<String, Object> properties = message.getProperties();\n            if (properties.containsKey(matcher.group(1))) {\n                String replacement = matcher.group(0);\n\n                Object value = properties.get(matcher.group(1));\n                if (replacement != null) {\n                    matcher.appendReplacement(buffer, value.toString());\n                }\n            }\n        }\n        matcher.appendTail(buffer);\n        return buffer.toString();\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    @Override\n    public void onDisconnected() {\n        this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onDisconnected));\n    }\n\n    @Override\n    public void onConnectionLost() {\n        this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionLost));\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionEstablished));\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.add(cloudDeliveryListener);\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.remove(cloudDeliveryListener);\n    }\n\n    @Override\n    public void onMessageConfirmed(String messageId, String topic) {\n        CloudConnectionManagerOptions options = this.cloudConnectionImpl.getCloudConnectionManagerOptions();\n        String topicSeparator = options.getTopicSeparator();\n\n        String[] semanticTopicElements = this.cloudPublisherOptions.getSemanticTopic().split(topicSeparator);\n\n        int index = getSemanticTopicComparisonOffset(semanticTopicElements);\n        String semanticTopicComparisonElement = semanticTopicElements[index];\n\n        String[] messageSemanticTopicElements = getMessageSemanticTopicElements(topic, topicSeparator,\n                semanticTopicComparisonElement);\n        if (messageSemanticTopicElements.length == 0) {\n            return;\n        }\n\n        index = 0;\n        for (String semanticTopicElement : semanticTopicElements) {\n            if (!semanticTopicElement.equals(messageSemanticTopicElements[index])) {\n                return;\n            }\n            index++;\n        }\n\n        this.cloudDeliveryListeners\n                .forEach(deliveryListener -> this.worker.execute(() -> deliveryListener.onMessageConfirmed(messageId)));\n    }\n\n    private String[] getMessageSemanticTopicElements(String topic, String topicSeparator,\n            String semanticTopicComparisonElement) {\n        int messagePostfixTopicOffset = topic.indexOf(semanticTopicComparisonElement);\n        if (messagePostfixTopicOffset >= 0) {\n            String messagePostfixTopic = topic.substring(messagePostfixTopicOffset, topic.length());\n            return messagePostfixTopic.split(topicSeparator);\n        }\n        return new String[0];\n    }\n\n    private int getSemanticTopicComparisonOffset(String[] semanticTopicElements) {\n        int index = 0;\n        for (String semanticTopicElement : semanticTopicElements) {\n            if (semanticTopicElement.startsWith(\"$\")) {\n                index++;\n            } else {\n                break;\n            }\n        }\n        return index;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/publisher/CloudPublisherOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.publisher;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType;\n\npublic class CloudPublisherOptions {\n\n    private static final Property<String> PROPERTY_CLOUD_SERVICE_PID = new Property<>(\n            CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(),\n            \"org.eclipse.kura.cloud.mqtt.eclipseiot.CloudService\");\n    private static final Property<String> PROPERTY_SEMANTIC_TOPIC = new Property<>(\"semantic.topic\",\n            \"W1/A1/$assetName\");\n    private static final Property<Integer> PROPERTY_QOS = new Property<>(\"qos\", 0);\n    private static final Property<String> PROPERTY_MESSAGE_TYPE = new Property<>(\"message.type\", \"telemetryQos0\");\n\n    private final String cloudServicePid;\n    private final String semanticTopic;\n    private final int qos;\n    private final String messageType;\n\n    public CloudPublisherOptions(final Map<String, Object> properties) {\n        this.cloudServicePid = PROPERTY_CLOUD_SERVICE_PID.get(properties);\n        this.semanticTopic = PROPERTY_SEMANTIC_TOPIC.get(properties);\n        this.qos = PROPERTY_QOS.get(properties);\n        this.messageType = PROPERTY_MESSAGE_TYPE.get(properties);\n    }\n\n    public String getCloudServicePid() {\n        return this.cloudServicePid;\n    }\n\n    public String getSemanticTopic() {\n        return this.semanticTopic;\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    public MessageType getMessageType() {\n        return MessageType.fromValue(this.messageType);\n    }\n\n    private static final class Property<T> {\n\n        private final String key;\n        private final T defaultValue;\n\n        public Property(final String key, final T defaultValue) {\n            this.key = key;\n            this.defaultValue = defaultValue;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public T get(final Map<String, Object> properties) {\n            final Object value = properties.get(this.key);\n\n            if (this.defaultValue.getClass().isInstance(value)) {\n                return (T) value;\n            }\n            return this.defaultValue;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/message/MessageConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message;\n\npublic enum MessageConstants {\n\n    FULL_TOPIC,\n    QOS,\n    RETAIN,\n    PRIORITY,\n    CONTROL;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/message/MessageType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message;\n\npublic enum MessageType {\n\n    TELEMETRY_QOS_0(\"telemetryQos0\", 0, 7, \"t\"),\n    TELEMETRY_QOS_1(\"telemetryQos1\", 1, 7, \"t\"),\n    EVENT(\"event\", 1, 5, \"e\"),\n    ALERT(\"alert\", 1, 2, \"a\"),\n    CONTROL(\"control\", 0, 2, \"c\");\n\n    private String type;\n    private int qos;\n    private int priority;\n    private String topicPrefix;\n\n    private MessageType(String type, int qos, int priority, String topicPrefix) {\n        this.type = type;\n        this.qos = qos;\n        this.priority = priority;\n        this.topicPrefix = topicPrefix;\n    }\n\n    public String getType() {\n        return this.type;\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    public int getPriority() {\n        return this.priority;\n    }\n\n    public String getTopicPrefix() {\n        return this.topicPrefix;\n    }\n\n    public static MessageType fromValue(String v) {\n        for (MessageType mt : MessageType.values()) {\n            if (mt.type.equals(v)) {\n                return mt;\n            }\n        }\n        throw new IllegalArgumentException(v);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/message/protobuf/KuraPayloadProto.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// NO CHECKED-IN PROTOBUF GENCODE\n// source: kurapayload.proto\n// Protobuf Java Version: 4.29.3\n\npackage org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf;\n\npublic final class KuraPayloadProto {\n  private KuraPayloadProto() {}\n  static {\n    com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n      com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n      /* major= */ 4,\n      /* minor= */ 29,\n      /* patch= */ 3,\n      /* suffix= */ \"\",\n      KuraPayloadProto.class.getName());\n  }\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistryLite registry) {\n  }\n\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistry registry) {\n    registerAllExtensions(\n        (com.google.protobuf.ExtensionRegistryLite) registry);\n  }\n  public interface KuraPayloadOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload)\n      com.google.protobuf.GeneratedMessage.\n          ExtendableMessageOrBuilder<KuraPayload> {\n\n    /**\n     * <code>optional int64 timestamp = 1;</code>\n     * @return Whether the timestamp field is set.\n     */\n    boolean hasTimestamp();\n    /**\n     * <code>optional int64 timestamp = 1;</code>\n     * @return The timestamp.\n     */\n    long getTimestamp();\n\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     * @return Whether the position field is set.\n     */\n    boolean hasPosition();\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     * @return The position.\n     */\n    org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition();\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     */\n    org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder();\n\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    java.util.List<org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> \n        getMetricList();\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index);\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    int getMetricCount();\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    java.util.List<? extends org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> \n        getMetricOrBuilderList();\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder(\n        int index);\n\n    /**\n     * <code>optional bytes body = 5001;</code>\n     * @return Whether the body field is set.\n     */\n    boolean hasBody();\n    /**\n     * <code>optional bytes body = 5001;</code>\n     * @return The body.\n     */\n    com.google.protobuf.ByteString getBody();\n  }\n  /**\n   * Protobuf type {@code kuradatatypes.KuraPayload}\n   */\n  public static final class KuraPayload extends\n      com.google.protobuf.GeneratedMessage.ExtendableMessage<\n        KuraPayload> implements\n      // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload)\n      KuraPayloadOrBuilder {\n  private static final long serialVersionUID = 0L;\n    static {\n      com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n        com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n        /* major= */ 4,\n        /* minor= */ 29,\n        /* patch= */ 3,\n        /* suffix= */ \"\",\n        KuraPayload.class.getName());\n    }\n    // Use KuraPayload.newBuilder() to construct.\n    private KuraPayload(com.google.protobuf.GeneratedMessage.ExtendableBuilder<org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload, ?> builder) {\n      super(builder);\n    }\n    private KuraPayload() {\n      metric_ = java.util.Collections.emptyList();\n      body_ = com.google.protobuf.ByteString.EMPTY;\n    }\n\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.Builder.class);\n    }\n\n    public interface KuraMetricOrBuilder extends\n        // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload.KuraMetric)\n        com.google.protobuf.MessageOrBuilder {\n\n      /**\n       * <code>required string name = 1;</code>\n       * @return Whether the name field is set.\n       */\n      boolean hasName();\n      /**\n       * <code>required string name = 1;</code>\n       * @return The name.\n       */\n      java.lang.String getName();\n      /**\n       * <code>required string name = 1;</code>\n       * @return The bytes for name.\n       */\n      com.google.protobuf.ByteString\n          getNameBytes();\n\n      /**\n       * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n       * @return Whether the type field is set.\n       */\n      boolean hasType();\n      /**\n       * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n       * @return The type.\n       */\n      org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType();\n\n      /**\n       * <code>optional double double_value = 3;</code>\n       * @return Whether the doubleValue field is set.\n       */\n      boolean hasDoubleValue();\n      /**\n       * <code>optional double double_value = 3;</code>\n       * @return The doubleValue.\n       */\n      double getDoubleValue();\n\n      /**\n       * <code>optional float float_value = 4;</code>\n       * @return Whether the floatValue field is set.\n       */\n      boolean hasFloatValue();\n      /**\n       * <code>optional float float_value = 4;</code>\n       * @return The floatValue.\n       */\n      float getFloatValue();\n\n      /**\n       * <code>optional int64 long_value = 5;</code>\n       * @return Whether the longValue field is set.\n       */\n      boolean hasLongValue();\n      /**\n       * <code>optional int64 long_value = 5;</code>\n       * @return The longValue.\n       */\n      long getLongValue();\n\n      /**\n       * <code>optional int32 int_value = 6;</code>\n       * @return Whether the intValue field is set.\n       */\n      boolean hasIntValue();\n      /**\n       * <code>optional int32 int_value = 6;</code>\n       * @return The intValue.\n       */\n      int getIntValue();\n\n      /**\n       * <code>optional bool bool_value = 7;</code>\n       * @return Whether the boolValue field is set.\n       */\n      boolean hasBoolValue();\n      /**\n       * <code>optional bool bool_value = 7;</code>\n       * @return The boolValue.\n       */\n      boolean getBoolValue();\n\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return Whether the stringValue field is set.\n       */\n      boolean hasStringValue();\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return The stringValue.\n       */\n      java.lang.String getStringValue();\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return The bytes for stringValue.\n       */\n      com.google.protobuf.ByteString\n          getStringValueBytes();\n\n      /**\n       * <code>optional bytes bytes_value = 9;</code>\n       * @return Whether the bytesValue field is set.\n       */\n      boolean hasBytesValue();\n      /**\n       * <code>optional bytes bytes_value = 9;</code>\n       * @return The bytesValue.\n       */\n      com.google.protobuf.ByteString getBytesValue();\n    }\n    /**\n     * Protobuf type {@code kuradatatypes.KuraPayload.KuraMetric}\n     */\n    public static final class KuraMetric extends\n        com.google.protobuf.GeneratedMessage implements\n        // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload.KuraMetric)\n        KuraMetricOrBuilder {\n    private static final long serialVersionUID = 0L;\n      static {\n        com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n          com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n          /* major= */ 4,\n          /* minor= */ 29,\n          /* patch= */ 3,\n          /* suffix= */ \"\",\n          KuraMetric.class.getName());\n      }\n      // Use KuraMetric.newBuilder() to construct.\n      private KuraMetric(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n        super(builder);\n      }\n      private KuraMetric() {\n        name_ = \"\";\n        type_ = 0;\n        stringValue_ = \"\";\n        bytesValue_ = com.google.protobuf.ByteString.EMPTY;\n      }\n\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder.class);\n      }\n\n      /**\n       * Protobuf enum {@code kuradatatypes.KuraPayload.KuraMetric.ValueType}\n       */\n      public enum ValueType\n          implements com.google.protobuf.ProtocolMessageEnum {\n        /**\n         * <code>DOUBLE = 0;</code>\n         */\n        DOUBLE(0),\n        /**\n         * <code>FLOAT = 1;</code>\n         */\n        FLOAT(1),\n        /**\n         * <code>INT64 = 2;</code>\n         */\n        INT64(2),\n        /**\n         * <code>INT32 = 3;</code>\n         */\n        INT32(3),\n        /**\n         * <code>BOOL = 4;</code>\n         */\n        BOOL(4),\n        /**\n         * <code>STRING = 5;</code>\n         */\n        STRING(5),\n        /**\n         * <code>BYTES = 6;</code>\n         */\n        BYTES(6),\n        ;\n\n        static {\n          com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n            com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n            /* major= */ 4,\n            /* minor= */ 29,\n            /* patch= */ 3,\n            /* suffix= */ \"\",\n            ValueType.class.getName());\n        }\n        /**\n         * <code>DOUBLE = 0;</code>\n         */\n        public static final int DOUBLE_VALUE = 0;\n        /**\n         * <code>FLOAT = 1;</code>\n         */\n        public static final int FLOAT_VALUE = 1;\n        /**\n         * <code>INT64 = 2;</code>\n         */\n        public static final int INT64_VALUE = 2;\n        /**\n         * <code>INT32 = 3;</code>\n         */\n        public static final int INT32_VALUE = 3;\n        /**\n         * <code>BOOL = 4;</code>\n         */\n        public static final int BOOL_VALUE = 4;\n        /**\n         * <code>STRING = 5;</code>\n         */\n        public static final int STRING_VALUE = 5;\n        /**\n         * <code>BYTES = 6;</code>\n         */\n        public static final int BYTES_VALUE = 6;\n\n\n        public final int getNumber() {\n          return value;\n        }\n\n        /**\n         * @param value The numeric wire value of the corresponding enum entry.\n         * @return The enum associated with the given numeric wire value.\n         * @deprecated Use {@link #forNumber(int)} instead.\n         */\n        @java.lang.Deprecated\n        public static ValueType valueOf(int value) {\n          return forNumber(value);\n        }\n\n        /**\n         * @param value The numeric wire value of the corresponding enum entry.\n         * @return The enum associated with the given numeric wire value.\n         */\n        public static ValueType forNumber(int value) {\n          switch (value) {\n            case 0: return DOUBLE;\n            case 1: return FLOAT;\n            case 2: return INT64;\n            case 3: return INT32;\n            case 4: return BOOL;\n            case 5: return STRING;\n            case 6: return BYTES;\n            default: return null;\n          }\n        }\n\n        public static com.google.protobuf.Internal.EnumLiteMap<ValueType>\n            internalGetValueMap() {\n          return internalValueMap;\n        }\n        private static final com.google.protobuf.Internal.EnumLiteMap<\n            ValueType> internalValueMap =\n              new com.google.protobuf.Internal.EnumLiteMap<ValueType>() {\n                public ValueType findValueByNumber(int number) {\n                  return ValueType.forNumber(number);\n                }\n              };\n\n        public final com.google.protobuf.Descriptors.EnumValueDescriptor\n            getValueDescriptor() {\n          return getDescriptor().getValues().get(ordinal());\n        }\n        public final com.google.protobuf.Descriptors.EnumDescriptor\n            getDescriptorForType() {\n          return getDescriptor();\n        }\n        public static final com.google.protobuf.Descriptors.EnumDescriptor\n            getDescriptor() {\n          return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDescriptor().getEnumTypes().get(0);\n        }\n\n        private static final ValueType[] VALUES = values();\n\n        public static ValueType valueOf(\n            com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n          if (desc.getType() != getDescriptor()) {\n            throw new java.lang.IllegalArgumentException(\n              \"EnumValueDescriptor is not for this type.\");\n          }\n          return VALUES[desc.getIndex()];\n        }\n\n        private final int value;\n\n        private ValueType(int value) {\n          this.value = value;\n        }\n\n        // @@protoc_insertion_point(enum_scope:kuradatatypes.KuraPayload.KuraMetric.ValueType)\n      }\n\n      private int bitField0_;\n      public static final int NAME_FIELD_NUMBER = 1;\n      @SuppressWarnings(\"serial\")\n      private volatile java.lang.Object name_ = \"\";\n      /**\n       * <code>required string name = 1;</code>\n       * @return Whether the name field is set.\n       */\n      @java.lang.Override\n      public boolean hasName() {\n        return ((bitField0_ & 0x00000001) != 0);\n      }\n      /**\n       * <code>required string name = 1;</code>\n       * @return The name.\n       */\n      @java.lang.Override\n      public java.lang.String getName() {\n        java.lang.Object ref = name_;\n        if (ref instanceof java.lang.String) {\n          return (java.lang.String) ref;\n        } else {\n          com.google.protobuf.ByteString bs = \n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            name_ = s;\n          }\n          return s;\n        }\n      }\n      /**\n       * <code>required string name = 1;</code>\n       * @return The bytes for name.\n       */\n      @java.lang.Override\n      public com.google.protobuf.ByteString\n          getNameBytes() {\n        java.lang.Object ref = name_;\n        if (ref instanceof java.lang.String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          name_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n\n      public static final int TYPE_FIELD_NUMBER = 2;\n      private int type_ = 0;\n      /**\n       * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n       * @return Whether the type field is set.\n       */\n      @java.lang.Override public boolean hasType() {\n        return ((bitField0_ & 0x00000002) != 0);\n      }\n      /**\n       * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n       * @return The type.\n       */\n      @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType() {\n        org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType result = org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(type_);\n        return result == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE : result;\n      }\n\n      public static final int DOUBLE_VALUE_FIELD_NUMBER = 3;\n      private double doubleValue_ = 0D;\n      /**\n       * <code>optional double double_value = 3;</code>\n       * @return Whether the doubleValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasDoubleValue() {\n        return ((bitField0_ & 0x00000004) != 0);\n      }\n      /**\n       * <code>optional double double_value = 3;</code>\n       * @return The doubleValue.\n       */\n      @java.lang.Override\n      public double getDoubleValue() {\n        return doubleValue_;\n      }\n\n      public static final int FLOAT_VALUE_FIELD_NUMBER = 4;\n      private float floatValue_ = 0F;\n      /**\n       * <code>optional float float_value = 4;</code>\n       * @return Whether the floatValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasFloatValue() {\n        return ((bitField0_ & 0x00000008) != 0);\n      }\n      /**\n       * <code>optional float float_value = 4;</code>\n       * @return The floatValue.\n       */\n      @java.lang.Override\n      public float getFloatValue() {\n        return floatValue_;\n      }\n\n      public static final int LONG_VALUE_FIELD_NUMBER = 5;\n      private long longValue_ = 0L;\n      /**\n       * <code>optional int64 long_value = 5;</code>\n       * @return Whether the longValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasLongValue() {\n        return ((bitField0_ & 0x00000010) != 0);\n      }\n      /**\n       * <code>optional int64 long_value = 5;</code>\n       * @return The longValue.\n       */\n      @java.lang.Override\n      public long getLongValue() {\n        return longValue_;\n      }\n\n      public static final int INT_VALUE_FIELD_NUMBER = 6;\n      private int intValue_ = 0;\n      /**\n       * <code>optional int32 int_value = 6;</code>\n       * @return Whether the intValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasIntValue() {\n        return ((bitField0_ & 0x00000020) != 0);\n      }\n      /**\n       * <code>optional int32 int_value = 6;</code>\n       * @return The intValue.\n       */\n      @java.lang.Override\n      public int getIntValue() {\n        return intValue_;\n      }\n\n      public static final int BOOL_VALUE_FIELD_NUMBER = 7;\n      private boolean boolValue_ = false;\n      /**\n       * <code>optional bool bool_value = 7;</code>\n       * @return Whether the boolValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasBoolValue() {\n        return ((bitField0_ & 0x00000040) != 0);\n      }\n      /**\n       * <code>optional bool bool_value = 7;</code>\n       * @return The boolValue.\n       */\n      @java.lang.Override\n      public boolean getBoolValue() {\n        return boolValue_;\n      }\n\n      public static final int STRING_VALUE_FIELD_NUMBER = 8;\n      @SuppressWarnings(\"serial\")\n      private volatile java.lang.Object stringValue_ = \"\";\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return Whether the stringValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasStringValue() {\n        return ((bitField0_ & 0x00000080) != 0);\n      }\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return The stringValue.\n       */\n      @java.lang.Override\n      public java.lang.String getStringValue() {\n        java.lang.Object ref = stringValue_;\n        if (ref instanceof java.lang.String) {\n          return (java.lang.String) ref;\n        } else {\n          com.google.protobuf.ByteString bs = \n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            stringValue_ = s;\n          }\n          return s;\n        }\n      }\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return The bytes for stringValue.\n       */\n      @java.lang.Override\n      public com.google.protobuf.ByteString\n          getStringValueBytes() {\n        java.lang.Object ref = stringValue_;\n        if (ref instanceof java.lang.String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          stringValue_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n\n      public static final int BYTES_VALUE_FIELD_NUMBER = 9;\n      private com.google.protobuf.ByteString bytesValue_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>optional bytes bytes_value = 9;</code>\n       * @return Whether the bytesValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasBytesValue() {\n        return ((bitField0_ & 0x00000100) != 0);\n      }\n      /**\n       * <code>optional bytes bytes_value = 9;</code>\n       * @return The bytesValue.\n       */\n      @java.lang.Override\n      public com.google.protobuf.ByteString getBytesValue() {\n        return bytesValue_;\n      }\n\n      private byte memoizedIsInitialized = -1;\n      @java.lang.Override\n      public final boolean isInitialized() {\n        byte isInitialized = memoizedIsInitialized;\n        if (isInitialized == 1) return true;\n        if (isInitialized == 0) return false;\n\n        if (!hasName()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n        if (!hasType()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n        memoizedIsInitialized = 1;\n        return true;\n      }\n\n      @java.lang.Override\n      public void writeTo(com.google.protobuf.CodedOutputStream output)\n                          throws java.io.IOException {\n        if (((bitField0_ & 0x00000001) != 0)) {\n          com.google.protobuf.GeneratedMessage.writeString(output, 1, name_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n          output.writeEnum(2, type_);\n        }\n        if (((bitField0_ & 0x00000004) != 0)) {\n          output.writeDouble(3, doubleValue_);\n        }\n        if (((bitField0_ & 0x00000008) != 0)) {\n          output.writeFloat(4, floatValue_);\n        }\n        if (((bitField0_ & 0x00000010) != 0)) {\n          output.writeInt64(5, longValue_);\n        }\n        if (((bitField0_ & 0x00000020) != 0)) {\n          output.writeInt32(6, intValue_);\n        }\n        if (((bitField0_ & 0x00000040) != 0)) {\n          output.writeBool(7, boolValue_);\n        }\n        if (((bitField0_ & 0x00000080) != 0)) {\n          com.google.protobuf.GeneratedMessage.writeString(output, 8, stringValue_);\n        }\n        if (((bitField0_ & 0x00000100) != 0)) {\n          output.writeBytes(9, bytesValue_);\n        }\n        getUnknownFields().writeTo(output);\n      }\n\n      @java.lang.Override\n      public int getSerializedSize() {\n        int size = memoizedSize;\n        if (size != -1) return size;\n\n        size = 0;\n        if (((bitField0_ & 0x00000001) != 0)) {\n          size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeEnumSize(2, type_);\n        }\n        if (((bitField0_ & 0x00000004) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(3, doubleValue_);\n        }\n        if (((bitField0_ & 0x00000008) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeFloatSize(4, floatValue_);\n        }\n        if (((bitField0_ & 0x00000010) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt64Size(5, longValue_);\n        }\n        if (((bitField0_ & 0x00000020) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt32Size(6, intValue_);\n        }\n        if (((bitField0_ & 0x00000040) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeBoolSize(7, boolValue_);\n        }\n        if (((bitField0_ & 0x00000080) != 0)) {\n          size += com.google.protobuf.GeneratedMessage.computeStringSize(8, stringValue_);\n        }\n        if (((bitField0_ & 0x00000100) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeBytesSize(9, bytesValue_);\n        }\n        size += getUnknownFields().getSerializedSize();\n        memoizedSize = size;\n        return size;\n      }\n\n      @java.lang.Override\n      public boolean equals(final java.lang.Object obj) {\n        if (obj == this) {\n         return true;\n        }\n        if (!(obj instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric)) {\n          return super.equals(obj);\n        }\n        org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric other = (org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric) obj;\n\n        if (hasName() != other.hasName()) return false;\n        if (hasName()) {\n          if (!getName()\n              .equals(other.getName())) return false;\n        }\n        if (hasType() != other.hasType()) return false;\n        if (hasType()) {\n          if (type_ != other.type_) return false;\n        }\n        if (hasDoubleValue() != other.hasDoubleValue()) return false;\n        if (hasDoubleValue()) {\n          if (java.lang.Double.doubleToLongBits(getDoubleValue())\n              != java.lang.Double.doubleToLongBits(\n                  other.getDoubleValue())) return false;\n        }\n        if (hasFloatValue() != other.hasFloatValue()) return false;\n        if (hasFloatValue()) {\n          if (java.lang.Float.floatToIntBits(getFloatValue())\n              != java.lang.Float.floatToIntBits(\n                  other.getFloatValue())) return false;\n        }\n        if (hasLongValue() != other.hasLongValue()) return false;\n        if (hasLongValue()) {\n          if (getLongValue()\n              != other.getLongValue()) return false;\n        }\n        if (hasIntValue() != other.hasIntValue()) return false;\n        if (hasIntValue()) {\n          if (getIntValue()\n              != other.getIntValue()) return false;\n        }\n        if (hasBoolValue() != other.hasBoolValue()) return false;\n        if (hasBoolValue()) {\n          if (getBoolValue()\n              != other.getBoolValue()) return false;\n        }\n        if (hasStringValue() != other.hasStringValue()) return false;\n        if (hasStringValue()) {\n          if (!getStringValue()\n              .equals(other.getStringValue())) return false;\n        }\n        if (hasBytesValue() != other.hasBytesValue()) return false;\n        if (hasBytesValue()) {\n          if (!getBytesValue()\n              .equals(other.getBytesValue())) return false;\n        }\n        if (!getUnknownFields().equals(other.getUnknownFields())) return false;\n        return true;\n      }\n\n      @java.lang.Override\n      public int hashCode() {\n        if (memoizedHashCode != 0) {\n          return memoizedHashCode;\n        }\n        int hash = 41;\n        hash = (19 * hash) + getDescriptor().hashCode();\n        if (hasName()) {\n          hash = (37 * hash) + NAME_FIELD_NUMBER;\n          hash = (53 * hash) + getName().hashCode();\n        }\n        if (hasType()) {\n          hash = (37 * hash) + TYPE_FIELD_NUMBER;\n          hash = (53 * hash) + type_;\n        }\n        if (hasDoubleValue()) {\n          hash = (37 * hash) + DOUBLE_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getDoubleValue()));\n        }\n        if (hasFloatValue()) {\n          hash = (37 * hash) + FLOAT_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + java.lang.Float.floatToIntBits(\n              getFloatValue());\n        }\n        if (hasLongValue()) {\n          hash = (37 * hash) + LONG_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              getLongValue());\n        }\n        if (hasIntValue()) {\n          hash = (37 * hash) + INT_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + getIntValue();\n        }\n        if (hasBoolValue()) {\n          hash = (37 * hash) + BOOL_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n              getBoolValue());\n        }\n        if (hasStringValue()) {\n          hash = (37 * hash) + STRING_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + getStringValue().hashCode();\n        }\n        if (hasBytesValue()) {\n          hash = (37 * hash) + BYTES_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + getBytesValue().hashCode();\n        }\n        hash = (29 * hash) + getUnknownFields().hashCode();\n        memoizedHashCode = hash;\n        return hash;\n      }\n\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          java.nio.ByteBuffer data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          java.nio.ByteBuffer data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          com.google.protobuf.ByteString data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          com.google.protobuf.ByteString data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(byte[] data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          byte[] data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(java.io.InputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          java.io.InputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input, extensionRegistry);\n      }\n\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseDelimitedFrom(java.io.InputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseDelimitedWithIOException(PARSER, input);\n      }\n\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseDelimitedFrom(\n          java.io.InputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          com.google.protobuf.CodedInputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input, extensionRegistry);\n      }\n\n      @java.lang.Override\n      public Builder newBuilderForType() { return newBuilder(); }\n      public static Builder newBuilder() {\n        return DEFAULT_INSTANCE.toBuilder();\n      }\n      public static Builder newBuilder(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric prototype) {\n        return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n      }\n      @java.lang.Override\n      public Builder toBuilder() {\n        return this == DEFAULT_INSTANCE\n            ? new Builder() : new Builder().mergeFrom(this);\n      }\n\n      @java.lang.Override\n      protected Builder newBuilderForType(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        Builder builder = new Builder(parent);\n        return builder;\n      }\n      /**\n       * Protobuf type {@code kuradatatypes.KuraPayload.KuraMetric}\n       */\n      public static final class Builder extends\n          com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n          // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload.KuraMetric)\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder {\n        public static final com.google.protobuf.Descriptors.Descriptor\n            getDescriptor() {\n          return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor;\n        }\n\n        @java.lang.Override\n        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n            internalGetFieldAccessorTable() {\n          return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable\n              .ensureFieldAccessorsInitialized(\n                  org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder.class);\n        }\n\n        // Construct using org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.newBuilder()\n        private Builder() {\n\n        }\n\n        private Builder(\n            com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n          super(parent);\n\n        }\n        @java.lang.Override\n        public Builder clear() {\n          super.clear();\n          bitField0_ = 0;\n          name_ = \"\";\n          type_ = 0;\n          doubleValue_ = 0D;\n          floatValue_ = 0F;\n          longValue_ = 0L;\n          intValue_ = 0;\n          boolValue_ = false;\n          stringValue_ = \"\";\n          bytesValue_ = com.google.protobuf.ByteString.EMPTY;\n          return this;\n        }\n\n        @java.lang.Override\n        public com.google.protobuf.Descriptors.Descriptor\n            getDescriptorForType() {\n          return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor;\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstanceForType() {\n          return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance();\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric build() {\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result = buildPartial();\n          if (!result.isInitialized()) {\n            throw newUninitializedMessageException(result);\n          }\n          return result;\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric buildPartial() {\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric(this);\n          if (bitField0_ != 0) { buildPartial0(result); }\n          onBuilt();\n          return result;\n        }\n\n        private void buildPartial0(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result) {\n          int from_bitField0_ = bitField0_;\n          int to_bitField0_ = 0;\n          if (((from_bitField0_ & 0x00000001) != 0)) {\n            result.name_ = name_;\n            to_bitField0_ |= 0x00000001;\n          }\n          if (((from_bitField0_ & 0x00000002) != 0)) {\n            result.type_ = type_;\n            to_bitField0_ |= 0x00000002;\n          }\n          if (((from_bitField0_ & 0x00000004) != 0)) {\n            result.doubleValue_ = doubleValue_;\n            to_bitField0_ |= 0x00000004;\n          }\n          if (((from_bitField0_ & 0x00000008) != 0)) {\n            result.floatValue_ = floatValue_;\n            to_bitField0_ |= 0x00000008;\n          }\n          if (((from_bitField0_ & 0x00000010) != 0)) {\n            result.longValue_ = longValue_;\n            to_bitField0_ |= 0x00000010;\n          }\n          if (((from_bitField0_ & 0x00000020) != 0)) {\n            result.intValue_ = intValue_;\n            to_bitField0_ |= 0x00000020;\n          }\n          if (((from_bitField0_ & 0x00000040) != 0)) {\n            result.boolValue_ = boolValue_;\n            to_bitField0_ |= 0x00000040;\n          }\n          if (((from_bitField0_ & 0x00000080) != 0)) {\n            result.stringValue_ = stringValue_;\n            to_bitField0_ |= 0x00000080;\n          }\n          if (((from_bitField0_ & 0x00000100) != 0)) {\n            result.bytesValue_ = bytesValue_;\n            to_bitField0_ |= 0x00000100;\n          }\n          result.bitField0_ |= to_bitField0_;\n        }\n\n        @java.lang.Override\n        public Builder mergeFrom(com.google.protobuf.Message other) {\n          if (other instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric) {\n            return mergeFrom((org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric)other);\n          } else {\n            super.mergeFrom(other);\n            return this;\n          }\n        }\n\n        public Builder mergeFrom(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric other) {\n          if (other == org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance()) return this;\n          if (other.hasName()) {\n            name_ = other.name_;\n            bitField0_ |= 0x00000001;\n            onChanged();\n          }\n          if (other.hasType()) {\n            setType(other.getType());\n          }\n          if (other.hasDoubleValue()) {\n            setDoubleValue(other.getDoubleValue());\n          }\n          if (other.hasFloatValue()) {\n            setFloatValue(other.getFloatValue());\n          }\n          if (other.hasLongValue()) {\n            setLongValue(other.getLongValue());\n          }\n          if (other.hasIntValue()) {\n            setIntValue(other.getIntValue());\n          }\n          if (other.hasBoolValue()) {\n            setBoolValue(other.getBoolValue());\n          }\n          if (other.hasStringValue()) {\n            stringValue_ = other.stringValue_;\n            bitField0_ |= 0x00000080;\n            onChanged();\n          }\n          if (other.hasBytesValue()) {\n            setBytesValue(other.getBytesValue());\n          }\n          this.mergeUnknownFields(other.getUnknownFields());\n          onChanged();\n          return this;\n        }\n\n        @java.lang.Override\n        public final boolean isInitialized() {\n          if (!hasName()) {\n            return false;\n          }\n          if (!hasType()) {\n            return false;\n          }\n          return true;\n        }\n\n        @java.lang.Override\n        public Builder mergeFrom(\n            com.google.protobuf.CodedInputStream input,\n            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n          if (extensionRegistry == null) {\n            throw new java.lang.NullPointerException();\n          }\n          try {\n            boolean done = false;\n            while (!done) {\n              int tag = input.readTag();\n              switch (tag) {\n                case 0:\n                  done = true;\n                  break;\n                case 10: {\n                  name_ = input.readBytes();\n                  bitField0_ |= 0x00000001;\n                  break;\n                } // case 10\n                case 16: {\n                  int tmpRaw = input.readEnum();\n                  org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType tmpValue =\n                      org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(tmpRaw);\n                  if (tmpValue == null) {\n                    mergeUnknownVarintField(2, tmpRaw);\n                  } else {\n                    type_ = tmpRaw;\n                    bitField0_ |= 0x00000002;\n                  }\n                  break;\n                } // case 16\n                case 25: {\n                  doubleValue_ = input.readDouble();\n                  bitField0_ |= 0x00000004;\n                  break;\n                } // case 25\n                case 37: {\n                  floatValue_ = input.readFloat();\n                  bitField0_ |= 0x00000008;\n                  break;\n                } // case 37\n                case 40: {\n                  longValue_ = input.readInt64();\n                  bitField0_ |= 0x00000010;\n                  break;\n                } // case 40\n                case 48: {\n                  intValue_ = input.readInt32();\n                  bitField0_ |= 0x00000020;\n                  break;\n                } // case 48\n                case 56: {\n                  boolValue_ = input.readBool();\n                  bitField0_ |= 0x00000040;\n                  break;\n                } // case 56\n                case 66: {\n                  stringValue_ = input.readBytes();\n                  bitField0_ |= 0x00000080;\n                  break;\n                } // case 66\n                case 74: {\n                  bytesValue_ = input.readBytes();\n                  bitField0_ |= 0x00000100;\n                  break;\n                } // case 74\n                default: {\n                  if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                    done = true; // was an endgroup tag\n                  }\n                  break;\n                } // default:\n              } // switch (tag)\n            } // while (!done)\n          } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n            throw e.unwrapIOException();\n          } finally {\n            onChanged();\n          } // finally\n          return this;\n        }\n        private int bitField0_;\n\n        private java.lang.Object name_ = \"\";\n        /**\n         * <code>required string name = 1;</code>\n         * @return Whether the name field is set.\n         */\n        public boolean hasName() {\n          return ((bitField0_ & 0x00000001) != 0);\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @return The name.\n         */\n        public java.lang.String getName() {\n          java.lang.Object ref = name_;\n          if (!(ref instanceof java.lang.String)) {\n            com.google.protobuf.ByteString bs =\n                (com.google.protobuf.ByteString) ref;\n            java.lang.String s = bs.toStringUtf8();\n            if (bs.isValidUtf8()) {\n              name_ = s;\n            }\n            return s;\n          } else {\n            return (java.lang.String) ref;\n          }\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @return The bytes for name.\n         */\n        public com.google.protobuf.ByteString\n            getNameBytes() {\n          java.lang.Object ref = name_;\n          if (ref instanceof String) {\n            com.google.protobuf.ByteString b = \n                com.google.protobuf.ByteString.copyFromUtf8(\n                    (java.lang.String) ref);\n            name_ = b;\n            return b;\n          } else {\n            return (com.google.protobuf.ByteString) ref;\n          }\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @param value The name to set.\n         * @return This builder for chaining.\n         */\n        public Builder setName(\n            java.lang.String value) {\n          if (value == null) { throw new NullPointerException(); }\n          name_ = value;\n          bitField0_ |= 0x00000001;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearName() {\n          name_ = getDefaultInstance().getName();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @param value The bytes for name to set.\n         * @return This builder for chaining.\n         */\n        public Builder setNameBytes(\n            com.google.protobuf.ByteString value) {\n          if (value == null) { throw new NullPointerException(); }\n          name_ = value;\n          bitField0_ |= 0x00000001;\n          onChanged();\n          return this;\n        }\n\n        private int type_ = 0;\n        /**\n         * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n         * @return Whether the type field is set.\n         */\n        @java.lang.Override public boolean hasType() {\n          return ((bitField0_ & 0x00000002) != 0);\n        }\n        /**\n         * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n         * @return The type.\n         */\n        @java.lang.Override\n        public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType() {\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType result = org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(type_);\n          return result == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE : result;\n        }\n        /**\n         * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n         * @param value The type to set.\n         * @return This builder for chaining.\n         */\n        public Builder setType(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType value) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          bitField0_ |= 0x00000002;\n          type_ = value.getNumber();\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearType() {\n          bitField0_ = (bitField0_ & ~0x00000002);\n          type_ = 0;\n          onChanged();\n          return this;\n        }\n\n        private double doubleValue_ ;\n        /**\n         * <code>optional double double_value = 3;</code>\n         * @return Whether the doubleValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasDoubleValue() {\n          return ((bitField0_ & 0x00000004) != 0);\n        }\n        /**\n         * <code>optional double double_value = 3;</code>\n         * @return The doubleValue.\n         */\n        @java.lang.Override\n        public double getDoubleValue() {\n          return doubleValue_;\n        }\n        /**\n         * <code>optional double double_value = 3;</code>\n         * @param value The doubleValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setDoubleValue(double value) {\n\n          doubleValue_ = value;\n          bitField0_ |= 0x00000004;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional double double_value = 3;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearDoubleValue() {\n          bitField0_ = (bitField0_ & ~0x00000004);\n          doubleValue_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private float floatValue_ ;\n        /**\n         * <code>optional float float_value = 4;</code>\n         * @return Whether the floatValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasFloatValue() {\n          return ((bitField0_ & 0x00000008) != 0);\n        }\n        /**\n         * <code>optional float float_value = 4;</code>\n         * @return The floatValue.\n         */\n        @java.lang.Override\n        public float getFloatValue() {\n          return floatValue_;\n        }\n        /**\n         * <code>optional float float_value = 4;</code>\n         * @param value The floatValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setFloatValue(float value) {\n\n          floatValue_ = value;\n          bitField0_ |= 0x00000008;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional float float_value = 4;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearFloatValue() {\n          bitField0_ = (bitField0_ & ~0x00000008);\n          floatValue_ = 0F;\n          onChanged();\n          return this;\n        }\n\n        private long longValue_ ;\n        /**\n         * <code>optional int64 long_value = 5;</code>\n         * @return Whether the longValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasLongValue() {\n          return ((bitField0_ & 0x00000010) != 0);\n        }\n        /**\n         * <code>optional int64 long_value = 5;</code>\n         * @return The longValue.\n         */\n        @java.lang.Override\n        public long getLongValue() {\n          return longValue_;\n        }\n        /**\n         * <code>optional int64 long_value = 5;</code>\n         * @param value The longValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setLongValue(long value) {\n\n          longValue_ = value;\n          bitField0_ |= 0x00000010;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional int64 long_value = 5;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearLongValue() {\n          bitField0_ = (bitField0_ & ~0x00000010);\n          longValue_ = 0L;\n          onChanged();\n          return this;\n        }\n\n        private int intValue_ ;\n        /**\n         * <code>optional int32 int_value = 6;</code>\n         * @return Whether the intValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasIntValue() {\n          return ((bitField0_ & 0x00000020) != 0);\n        }\n        /**\n         * <code>optional int32 int_value = 6;</code>\n         * @return The intValue.\n         */\n        @java.lang.Override\n        public int getIntValue() {\n          return intValue_;\n        }\n        /**\n         * <code>optional int32 int_value = 6;</code>\n         * @param value The intValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setIntValue(int value) {\n\n          intValue_ = value;\n          bitField0_ |= 0x00000020;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional int32 int_value = 6;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearIntValue() {\n          bitField0_ = (bitField0_ & ~0x00000020);\n          intValue_ = 0;\n          onChanged();\n          return this;\n        }\n\n        private boolean boolValue_ ;\n        /**\n         * <code>optional bool bool_value = 7;</code>\n         * @return Whether the boolValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasBoolValue() {\n          return ((bitField0_ & 0x00000040) != 0);\n        }\n        /**\n         * <code>optional bool bool_value = 7;</code>\n         * @return The boolValue.\n         */\n        @java.lang.Override\n        public boolean getBoolValue() {\n          return boolValue_;\n        }\n        /**\n         * <code>optional bool bool_value = 7;</code>\n         * @param value The boolValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setBoolValue(boolean value) {\n\n          boolValue_ = value;\n          bitField0_ |= 0x00000040;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional bool bool_value = 7;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearBoolValue() {\n          bitField0_ = (bitField0_ & ~0x00000040);\n          boolValue_ = false;\n          onChanged();\n          return this;\n        }\n\n        private java.lang.Object stringValue_ = \"\";\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @return Whether the stringValue field is set.\n         */\n        public boolean hasStringValue() {\n          return ((bitField0_ & 0x00000080) != 0);\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @return The stringValue.\n         */\n        public java.lang.String getStringValue() {\n          java.lang.Object ref = stringValue_;\n          if (!(ref instanceof java.lang.String)) {\n            com.google.protobuf.ByteString bs =\n                (com.google.protobuf.ByteString) ref;\n            java.lang.String s = bs.toStringUtf8();\n            if (bs.isValidUtf8()) {\n              stringValue_ = s;\n            }\n            return s;\n          } else {\n            return (java.lang.String) ref;\n          }\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @return The bytes for stringValue.\n         */\n        public com.google.protobuf.ByteString\n            getStringValueBytes() {\n          java.lang.Object ref = stringValue_;\n          if (ref instanceof String) {\n            com.google.protobuf.ByteString b = \n                com.google.protobuf.ByteString.copyFromUtf8(\n                    (java.lang.String) ref);\n            stringValue_ = b;\n            return b;\n          } else {\n            return (com.google.protobuf.ByteString) ref;\n          }\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @param value The stringValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setStringValue(\n            java.lang.String value) {\n          if (value == null) { throw new NullPointerException(); }\n          stringValue_ = value;\n          bitField0_ |= 0x00000080;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearStringValue() {\n          stringValue_ = getDefaultInstance().getStringValue();\n          bitField0_ = (bitField0_ & ~0x00000080);\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @param value The bytes for stringValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setStringValueBytes(\n            com.google.protobuf.ByteString value) {\n          if (value == null) { throw new NullPointerException(); }\n          stringValue_ = value;\n          bitField0_ |= 0x00000080;\n          onChanged();\n          return this;\n        }\n\n        private com.google.protobuf.ByteString bytesValue_ = com.google.protobuf.ByteString.EMPTY;\n        /**\n         * <code>optional bytes bytes_value = 9;</code>\n         * @return Whether the bytesValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasBytesValue() {\n          return ((bitField0_ & 0x00000100) != 0);\n        }\n        /**\n         * <code>optional bytes bytes_value = 9;</code>\n         * @return The bytesValue.\n         */\n        @java.lang.Override\n        public com.google.protobuf.ByteString getBytesValue() {\n          return bytesValue_;\n        }\n        /**\n         * <code>optional bytes bytes_value = 9;</code>\n         * @param value The bytesValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setBytesValue(com.google.protobuf.ByteString value) {\n          if (value == null) { throw new NullPointerException(); }\n          bytesValue_ = value;\n          bitField0_ |= 0x00000100;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional bytes bytes_value = 9;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearBytesValue() {\n          bitField0_ = (bitField0_ & ~0x00000100);\n          bytesValue_ = getDefaultInstance().getBytesValue();\n          onChanged();\n          return this;\n        }\n\n        // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload.KuraMetric)\n      }\n\n      // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload.KuraMetric)\n      private static final org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric DEFAULT_INSTANCE;\n      static {\n        DEFAULT_INSTANCE = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric();\n      }\n\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstance() {\n        return DEFAULT_INSTANCE;\n      }\n\n      private static final com.google.protobuf.Parser<KuraMetric>\n          PARSER = new com.google.protobuf.AbstractParser<KuraMetric>() {\n        @java.lang.Override\n        public KuraMetric parsePartialFrom(\n            com.google.protobuf.CodedInputStream input,\n            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n          Builder builder = newBuilder();\n          try {\n            builder.mergeFrom(input, extensionRegistry);\n          } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n            throw e.setUnfinishedMessage(builder.buildPartial());\n          } catch (com.google.protobuf.UninitializedMessageException e) {\n            throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n          } catch (java.io.IOException e) {\n            throw new com.google.protobuf.InvalidProtocolBufferException(e)\n                .setUnfinishedMessage(builder.buildPartial());\n          }\n          return builder.buildPartial();\n        }\n      };\n\n      public static com.google.protobuf.Parser<KuraMetric> parser() {\n        return PARSER;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Parser<KuraMetric> getParserForType() {\n        return PARSER;\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstanceForType() {\n        return DEFAULT_INSTANCE;\n      }\n\n    }\n\n    public interface KuraPositionOrBuilder extends\n        // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload.KuraPosition)\n        com.google.protobuf.MessageOrBuilder {\n\n      /**\n       * <code>required double latitude = 1;</code>\n       * @return Whether the latitude field is set.\n       */\n      boolean hasLatitude();\n      /**\n       * <code>required double latitude = 1;</code>\n       * @return The latitude.\n       */\n      double getLatitude();\n\n      /**\n       * <code>required double longitude = 2;</code>\n       * @return Whether the longitude field is set.\n       */\n      boolean hasLongitude();\n      /**\n       * <code>required double longitude = 2;</code>\n       * @return The longitude.\n       */\n      double getLongitude();\n\n      /**\n       * <code>optional double altitude = 3;</code>\n       * @return Whether the altitude field is set.\n       */\n      boolean hasAltitude();\n      /**\n       * <code>optional double altitude = 3;</code>\n       * @return The altitude.\n       */\n      double getAltitude();\n\n      /**\n       * <pre>\n       * dilution of precision of the current satellite fix. \n       * </pre>\n       *\n       * <code>optional double precision = 4;</code>\n       * @return Whether the precision field is set.\n       */\n      boolean hasPrecision();\n      /**\n       * <pre>\n       * dilution of precision of the current satellite fix. \n       * </pre>\n       *\n       * <code>optional double precision = 4;</code>\n       * @return The precision.\n       */\n      double getPrecision();\n\n      /**\n       * <pre>\n       * heading in degrees\n       * </pre>\n       *\n       * <code>optional double heading = 5;</code>\n       * @return Whether the heading field is set.\n       */\n      boolean hasHeading();\n      /**\n       * <pre>\n       * heading in degrees\n       * </pre>\n       *\n       * <code>optional double heading = 5;</code>\n       * @return The heading.\n       */\n      double getHeading();\n\n      /**\n       * <pre>\n       * meters per second\n       * </pre>\n       *\n       * <code>optional double speed = 6;</code>\n       * @return Whether the speed field is set.\n       */\n      boolean hasSpeed();\n      /**\n       * <pre>\n       * meters per second\n       * </pre>\n       *\n       * <code>optional double speed = 6;</code>\n       * @return The speed.\n       */\n      double getSpeed();\n\n      /**\n       * <code>optional int64 timestamp = 7;</code>\n       * @return Whether the timestamp field is set.\n       */\n      boolean hasTimestamp();\n      /**\n       * <code>optional int64 timestamp = 7;</code>\n       * @return The timestamp.\n       */\n      long getTimestamp();\n\n      /**\n       * <pre>\n       * number satellites locked by the GPS device\n       * </pre>\n       *\n       * <code>optional int32 satellites = 8;</code>\n       * @return Whether the satellites field is set.\n       */\n      boolean hasSatellites();\n      /**\n       * <pre>\n       * number satellites locked by the GPS device\n       * </pre>\n       *\n       * <code>optional int32 satellites = 8;</code>\n       * @return The satellites.\n       */\n      int getSatellites();\n\n      /**\n       * <pre>\n       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n       * </pre>\n       *\n       * <code>optional int32 status = 9;</code>\n       * @return Whether the status field is set.\n       */\n      boolean hasStatus();\n      /**\n       * <pre>\n       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n       * </pre>\n       *\n       * <code>optional int32 status = 9;</code>\n       * @return The status.\n       */\n      int getStatus();\n    }\n    /**\n     * Protobuf type {@code kuradatatypes.KuraPayload.KuraPosition}\n     */\n    public static final class KuraPosition extends\n        com.google.protobuf.GeneratedMessage implements\n        // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload.KuraPosition)\n        KuraPositionOrBuilder {\n    private static final long serialVersionUID = 0L;\n      static {\n        com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n          com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n          /* major= */ 4,\n          /* minor= */ 29,\n          /* patch= */ 3,\n          /* suffix= */ \"\",\n          KuraPosition.class.getName());\n      }\n      // Use KuraPosition.newBuilder() to construct.\n      private KuraPosition(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n        super(builder);\n      }\n      private KuraPosition() {\n      }\n\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder.class);\n      }\n\n      private int bitField0_;\n      public static final int LATITUDE_FIELD_NUMBER = 1;\n      private double latitude_ = 0D;\n      /**\n       * <code>required double latitude = 1;</code>\n       * @return Whether the latitude field is set.\n       */\n      @java.lang.Override\n      public boolean hasLatitude() {\n        return ((bitField0_ & 0x00000001) != 0);\n      }\n      /**\n       * <code>required double latitude = 1;</code>\n       * @return The latitude.\n       */\n      @java.lang.Override\n      public double getLatitude() {\n        return latitude_;\n      }\n\n      public static final int LONGITUDE_FIELD_NUMBER = 2;\n      private double longitude_ = 0D;\n      /**\n       * <code>required double longitude = 2;</code>\n       * @return Whether the longitude field is set.\n       */\n      @java.lang.Override\n      public boolean hasLongitude() {\n        return ((bitField0_ & 0x00000002) != 0);\n      }\n      /**\n       * <code>required double longitude = 2;</code>\n       * @return The longitude.\n       */\n      @java.lang.Override\n      public double getLongitude() {\n        return longitude_;\n      }\n\n      public static final int ALTITUDE_FIELD_NUMBER = 3;\n      private double altitude_ = 0D;\n      /**\n       * <code>optional double altitude = 3;</code>\n       * @return Whether the altitude field is set.\n       */\n      @java.lang.Override\n      public boolean hasAltitude() {\n        return ((bitField0_ & 0x00000004) != 0);\n      }\n      /**\n       * <code>optional double altitude = 3;</code>\n       * @return The altitude.\n       */\n      @java.lang.Override\n      public double getAltitude() {\n        return altitude_;\n      }\n\n      public static final int PRECISION_FIELD_NUMBER = 4;\n      private double precision_ = 0D;\n      /**\n       * <pre>\n       * dilution of precision of the current satellite fix. \n       * </pre>\n       *\n       * <code>optional double precision = 4;</code>\n       * @return Whether the precision field is set.\n       */\n      @java.lang.Override\n      public boolean hasPrecision() {\n        return ((bitField0_ & 0x00000008) != 0);\n      }\n      /**\n       * <pre>\n       * dilution of precision of the current satellite fix. \n       * </pre>\n       *\n       * <code>optional double precision = 4;</code>\n       * @return The precision.\n       */\n      @java.lang.Override\n      public double getPrecision() {\n        return precision_;\n      }\n\n      public static final int HEADING_FIELD_NUMBER = 5;\n      private double heading_ = 0D;\n      /**\n       * <pre>\n       * heading in degrees\n       * </pre>\n       *\n       * <code>optional double heading = 5;</code>\n       * @return Whether the heading field is set.\n       */\n      @java.lang.Override\n      public boolean hasHeading() {\n        return ((bitField0_ & 0x00000010) != 0);\n      }\n      /**\n       * <pre>\n       * heading in degrees\n       * </pre>\n       *\n       * <code>optional double heading = 5;</code>\n       * @return The heading.\n       */\n      @java.lang.Override\n      public double getHeading() {\n        return heading_;\n      }\n\n      public static final int SPEED_FIELD_NUMBER = 6;\n      private double speed_ = 0D;\n      /**\n       * <pre>\n       * meters per second\n       * </pre>\n       *\n       * <code>optional double speed = 6;</code>\n       * @return Whether the speed field is set.\n       */\n      @java.lang.Override\n      public boolean hasSpeed() {\n        return ((bitField0_ & 0x00000020) != 0);\n      }\n      /**\n       * <pre>\n       * meters per second\n       * </pre>\n       *\n       * <code>optional double speed = 6;</code>\n       * @return The speed.\n       */\n      @java.lang.Override\n      public double getSpeed() {\n        return speed_;\n      }\n\n      public static final int TIMESTAMP_FIELD_NUMBER = 7;\n      private long timestamp_ = 0L;\n      /**\n       * <code>optional int64 timestamp = 7;</code>\n       * @return Whether the timestamp field is set.\n       */\n      @java.lang.Override\n      public boolean hasTimestamp() {\n        return ((bitField0_ & 0x00000040) != 0);\n      }\n      /**\n       * <code>optional int64 timestamp = 7;</code>\n       * @return The timestamp.\n       */\n      @java.lang.Override\n      public long getTimestamp() {\n        return timestamp_;\n      }\n\n      public static final int SATELLITES_FIELD_NUMBER = 8;\n      private int satellites_ = 0;\n      /**\n       * <pre>\n       * number satellites locked by the GPS device\n       * </pre>\n       *\n       * <code>optional int32 satellites = 8;</code>\n       * @return Whether the satellites field is set.\n       */\n      @java.lang.Override\n      public boolean hasSatellites() {\n        return ((bitField0_ & 0x00000080) != 0);\n      }\n      /**\n       * <pre>\n       * number satellites locked by the GPS device\n       * </pre>\n       *\n       * <code>optional int32 satellites = 8;</code>\n       * @return The satellites.\n       */\n      @java.lang.Override\n      public int getSatellites() {\n        return satellites_;\n      }\n\n      public static final int STATUS_FIELD_NUMBER = 9;\n      private int status_ = 0;\n      /**\n       * <pre>\n       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n       * </pre>\n       *\n       * <code>optional int32 status = 9;</code>\n       * @return Whether the status field is set.\n       */\n      @java.lang.Override\n      public boolean hasStatus() {\n        return ((bitField0_ & 0x00000100) != 0);\n      }\n      /**\n       * <pre>\n       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n       * </pre>\n       *\n       * <code>optional int32 status = 9;</code>\n       * @return The status.\n       */\n      @java.lang.Override\n      public int getStatus() {\n        return status_;\n      }\n\n      private byte memoizedIsInitialized = -1;\n      @java.lang.Override\n      public final boolean isInitialized() {\n        byte isInitialized = memoizedIsInitialized;\n        if (isInitialized == 1) return true;\n        if (isInitialized == 0) return false;\n\n        if (!hasLatitude()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n        if (!hasLongitude()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n        memoizedIsInitialized = 1;\n        return true;\n      }\n\n      @java.lang.Override\n      public void writeTo(com.google.protobuf.CodedOutputStream output)\n                          throws java.io.IOException {\n        if (((bitField0_ & 0x00000001) != 0)) {\n          output.writeDouble(1, latitude_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n          output.writeDouble(2, longitude_);\n        }\n        if (((bitField0_ & 0x00000004) != 0)) {\n          output.writeDouble(3, altitude_);\n        }\n        if (((bitField0_ & 0x00000008) != 0)) {\n          output.writeDouble(4, precision_);\n        }\n        if (((bitField0_ & 0x00000010) != 0)) {\n          output.writeDouble(5, heading_);\n        }\n        if (((bitField0_ & 0x00000020) != 0)) {\n          output.writeDouble(6, speed_);\n        }\n        if (((bitField0_ & 0x00000040) != 0)) {\n          output.writeInt64(7, timestamp_);\n        }\n        if (((bitField0_ & 0x00000080) != 0)) {\n          output.writeInt32(8, satellites_);\n        }\n        if (((bitField0_ & 0x00000100) != 0)) {\n          output.writeInt32(9, status_);\n        }\n        getUnknownFields().writeTo(output);\n      }\n\n      @java.lang.Override\n      public int getSerializedSize() {\n        int size = memoizedSize;\n        if (size != -1) return size;\n\n        size = 0;\n        if (((bitField0_ & 0x00000001) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(1, latitude_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(2, longitude_);\n        }\n        if (((bitField0_ & 0x00000004) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(3, altitude_);\n        }\n        if (((bitField0_ & 0x00000008) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(4, precision_);\n        }\n        if (((bitField0_ & 0x00000010) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(5, heading_);\n        }\n        if (((bitField0_ & 0x00000020) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(6, speed_);\n        }\n        if (((bitField0_ & 0x00000040) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt64Size(7, timestamp_);\n        }\n        if (((bitField0_ & 0x00000080) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt32Size(8, satellites_);\n        }\n        if (((bitField0_ & 0x00000100) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt32Size(9, status_);\n        }\n        size += getUnknownFields().getSerializedSize();\n        memoizedSize = size;\n        return size;\n      }\n\n      @java.lang.Override\n      public boolean equals(final java.lang.Object obj) {\n        if (obj == this) {\n         return true;\n        }\n        if (!(obj instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition)) {\n          return super.equals(obj);\n        }\n        org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition other = (org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition) obj;\n\n        if (hasLatitude() != other.hasLatitude()) return false;\n        if (hasLatitude()) {\n          if (java.lang.Double.doubleToLongBits(getLatitude())\n              != java.lang.Double.doubleToLongBits(\n                  other.getLatitude())) return false;\n        }\n        if (hasLongitude() != other.hasLongitude()) return false;\n        if (hasLongitude()) {\n          if (java.lang.Double.doubleToLongBits(getLongitude())\n              != java.lang.Double.doubleToLongBits(\n                  other.getLongitude())) return false;\n        }\n        if (hasAltitude() != other.hasAltitude()) return false;\n        if (hasAltitude()) {\n          if (java.lang.Double.doubleToLongBits(getAltitude())\n              != java.lang.Double.doubleToLongBits(\n                  other.getAltitude())) return false;\n        }\n        if (hasPrecision() != other.hasPrecision()) return false;\n        if (hasPrecision()) {\n          if (java.lang.Double.doubleToLongBits(getPrecision())\n              != java.lang.Double.doubleToLongBits(\n                  other.getPrecision())) return false;\n        }\n        if (hasHeading() != other.hasHeading()) return false;\n        if (hasHeading()) {\n          if (java.lang.Double.doubleToLongBits(getHeading())\n              != java.lang.Double.doubleToLongBits(\n                  other.getHeading())) return false;\n        }\n        if (hasSpeed() != other.hasSpeed()) return false;\n        if (hasSpeed()) {\n          if (java.lang.Double.doubleToLongBits(getSpeed())\n              != java.lang.Double.doubleToLongBits(\n                  other.getSpeed())) return false;\n        }\n        if (hasTimestamp() != other.hasTimestamp()) return false;\n        if (hasTimestamp()) {\n          if (getTimestamp()\n              != other.getTimestamp()) return false;\n        }\n        if (hasSatellites() != other.hasSatellites()) return false;\n        if (hasSatellites()) {\n          if (getSatellites()\n              != other.getSatellites()) return false;\n        }\n        if (hasStatus() != other.hasStatus()) return false;\n        if (hasStatus()) {\n          if (getStatus()\n              != other.getStatus()) return false;\n        }\n        if (!getUnknownFields().equals(other.getUnknownFields())) return false;\n        return true;\n      }\n\n      @java.lang.Override\n      public int hashCode() {\n        if (memoizedHashCode != 0) {\n          return memoizedHashCode;\n        }\n        int hash = 41;\n        hash = (19 * hash) + getDescriptor().hashCode();\n        if (hasLatitude()) {\n          hash = (37 * hash) + LATITUDE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getLatitude()));\n        }\n        if (hasLongitude()) {\n          hash = (37 * hash) + LONGITUDE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getLongitude()));\n        }\n        if (hasAltitude()) {\n          hash = (37 * hash) + ALTITUDE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getAltitude()));\n        }\n        if (hasPrecision()) {\n          hash = (37 * hash) + PRECISION_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getPrecision()));\n        }\n        if (hasHeading()) {\n          hash = (37 * hash) + HEADING_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getHeading()));\n        }\n        if (hasSpeed()) {\n          hash = (37 * hash) + SPEED_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getSpeed()));\n        }\n        if (hasTimestamp()) {\n          hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              getTimestamp());\n        }\n        if (hasSatellites()) {\n          hash = (37 * hash) + SATELLITES_FIELD_NUMBER;\n          hash = (53 * hash) + getSatellites();\n        }\n        if (hasStatus()) {\n          hash = (37 * hash) + STATUS_FIELD_NUMBER;\n          hash = (53 * hash) + getStatus();\n        }\n        hash = (29 * hash) + getUnknownFields().hashCode();\n        memoizedHashCode = hash;\n        return hash;\n      }\n\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          java.nio.ByteBuffer data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          java.nio.ByteBuffer data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          com.google.protobuf.ByteString data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          com.google.protobuf.ByteString data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(byte[] data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          byte[] data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(java.io.InputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          java.io.InputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input, extensionRegistry);\n      }\n\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseDelimitedFrom(java.io.InputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseDelimitedWithIOException(PARSER, input);\n      }\n\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseDelimitedFrom(\n          java.io.InputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          com.google.protobuf.CodedInputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input);\n      }\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input, extensionRegistry);\n      }\n\n      @java.lang.Override\n      public Builder newBuilderForType() { return newBuilder(); }\n      public static Builder newBuilder() {\n        return DEFAULT_INSTANCE.toBuilder();\n      }\n      public static Builder newBuilder(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition prototype) {\n        return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n      }\n      @java.lang.Override\n      public Builder toBuilder() {\n        return this == DEFAULT_INSTANCE\n            ? new Builder() : new Builder().mergeFrom(this);\n      }\n\n      @java.lang.Override\n      protected Builder newBuilderForType(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        Builder builder = new Builder(parent);\n        return builder;\n      }\n      /**\n       * Protobuf type {@code kuradatatypes.KuraPayload.KuraPosition}\n       */\n      public static final class Builder extends\n          com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n          // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload.KuraPosition)\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder {\n        public static final com.google.protobuf.Descriptors.Descriptor\n            getDescriptor() {\n          return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor;\n        }\n\n        @java.lang.Override\n        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n            internalGetFieldAccessorTable() {\n          return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable\n              .ensureFieldAccessorsInitialized(\n                  org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder.class);\n        }\n\n        // Construct using org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.newBuilder()\n        private Builder() {\n\n        }\n\n        private Builder(\n            com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n          super(parent);\n\n        }\n        @java.lang.Override\n        public Builder clear() {\n          super.clear();\n          bitField0_ = 0;\n          latitude_ = 0D;\n          longitude_ = 0D;\n          altitude_ = 0D;\n          precision_ = 0D;\n          heading_ = 0D;\n          speed_ = 0D;\n          timestamp_ = 0L;\n          satellites_ = 0;\n          status_ = 0;\n          return this;\n        }\n\n        @java.lang.Override\n        public com.google.protobuf.Descriptors.Descriptor\n            getDescriptorForType() {\n          return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor;\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstanceForType() {\n          return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance();\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition build() {\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result = buildPartial();\n          if (!result.isInitialized()) {\n            throw newUninitializedMessageException(result);\n          }\n          return result;\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition buildPartial() {\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition(this);\n          if (bitField0_ != 0) { buildPartial0(result); }\n          onBuilt();\n          return result;\n        }\n\n        private void buildPartial0(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result) {\n          int from_bitField0_ = bitField0_;\n          int to_bitField0_ = 0;\n          if (((from_bitField0_ & 0x00000001) != 0)) {\n            result.latitude_ = latitude_;\n            to_bitField0_ |= 0x00000001;\n          }\n          if (((from_bitField0_ & 0x00000002) != 0)) {\n            result.longitude_ = longitude_;\n            to_bitField0_ |= 0x00000002;\n          }\n          if (((from_bitField0_ & 0x00000004) != 0)) {\n            result.altitude_ = altitude_;\n            to_bitField0_ |= 0x00000004;\n          }\n          if (((from_bitField0_ & 0x00000008) != 0)) {\n            result.precision_ = precision_;\n            to_bitField0_ |= 0x00000008;\n          }\n          if (((from_bitField0_ & 0x00000010) != 0)) {\n            result.heading_ = heading_;\n            to_bitField0_ |= 0x00000010;\n          }\n          if (((from_bitField0_ & 0x00000020) != 0)) {\n            result.speed_ = speed_;\n            to_bitField0_ |= 0x00000020;\n          }\n          if (((from_bitField0_ & 0x00000040) != 0)) {\n            result.timestamp_ = timestamp_;\n            to_bitField0_ |= 0x00000040;\n          }\n          if (((from_bitField0_ & 0x00000080) != 0)) {\n            result.satellites_ = satellites_;\n            to_bitField0_ |= 0x00000080;\n          }\n          if (((from_bitField0_ & 0x00000100) != 0)) {\n            result.status_ = status_;\n            to_bitField0_ |= 0x00000100;\n          }\n          result.bitField0_ |= to_bitField0_;\n        }\n\n        @java.lang.Override\n        public Builder mergeFrom(com.google.protobuf.Message other) {\n          if (other instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition) {\n            return mergeFrom((org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition)other);\n          } else {\n            super.mergeFrom(other);\n            return this;\n          }\n        }\n\n        public Builder mergeFrom(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition other) {\n          if (other == org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance()) return this;\n          if (other.hasLatitude()) {\n            setLatitude(other.getLatitude());\n          }\n          if (other.hasLongitude()) {\n            setLongitude(other.getLongitude());\n          }\n          if (other.hasAltitude()) {\n            setAltitude(other.getAltitude());\n          }\n          if (other.hasPrecision()) {\n            setPrecision(other.getPrecision());\n          }\n          if (other.hasHeading()) {\n            setHeading(other.getHeading());\n          }\n          if (other.hasSpeed()) {\n            setSpeed(other.getSpeed());\n          }\n          if (other.hasTimestamp()) {\n            setTimestamp(other.getTimestamp());\n          }\n          if (other.hasSatellites()) {\n            setSatellites(other.getSatellites());\n          }\n          if (other.hasStatus()) {\n            setStatus(other.getStatus());\n          }\n          this.mergeUnknownFields(other.getUnknownFields());\n          onChanged();\n          return this;\n        }\n\n        @java.lang.Override\n        public final boolean isInitialized() {\n          if (!hasLatitude()) {\n            return false;\n          }\n          if (!hasLongitude()) {\n            return false;\n          }\n          return true;\n        }\n\n        @java.lang.Override\n        public Builder mergeFrom(\n            com.google.protobuf.CodedInputStream input,\n            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n          if (extensionRegistry == null) {\n            throw new java.lang.NullPointerException();\n          }\n          try {\n            boolean done = false;\n            while (!done) {\n              int tag = input.readTag();\n              switch (tag) {\n                case 0:\n                  done = true;\n                  break;\n                case 9: {\n                  latitude_ = input.readDouble();\n                  bitField0_ |= 0x00000001;\n                  break;\n                } // case 9\n                case 17: {\n                  longitude_ = input.readDouble();\n                  bitField0_ |= 0x00000002;\n                  break;\n                } // case 17\n                case 25: {\n                  altitude_ = input.readDouble();\n                  bitField0_ |= 0x00000004;\n                  break;\n                } // case 25\n                case 33: {\n                  precision_ = input.readDouble();\n                  bitField0_ |= 0x00000008;\n                  break;\n                } // case 33\n                case 41: {\n                  heading_ = input.readDouble();\n                  bitField0_ |= 0x00000010;\n                  break;\n                } // case 41\n                case 49: {\n                  speed_ = input.readDouble();\n                  bitField0_ |= 0x00000020;\n                  break;\n                } // case 49\n                case 56: {\n                  timestamp_ = input.readInt64();\n                  bitField0_ |= 0x00000040;\n                  break;\n                } // case 56\n                case 64: {\n                  satellites_ = input.readInt32();\n                  bitField0_ |= 0x00000080;\n                  break;\n                } // case 64\n                case 72: {\n                  status_ = input.readInt32();\n                  bitField0_ |= 0x00000100;\n                  break;\n                } // case 72\n                default: {\n                  if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                    done = true; // was an endgroup tag\n                  }\n                  break;\n                } // default:\n              } // switch (tag)\n            } // while (!done)\n          } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n            throw e.unwrapIOException();\n          } finally {\n            onChanged();\n          } // finally\n          return this;\n        }\n        private int bitField0_;\n\n        private double latitude_ ;\n        /**\n         * <code>required double latitude = 1;</code>\n         * @return Whether the latitude field is set.\n         */\n        @java.lang.Override\n        public boolean hasLatitude() {\n          return ((bitField0_ & 0x00000001) != 0);\n        }\n        /**\n         * <code>required double latitude = 1;</code>\n         * @return The latitude.\n         */\n        @java.lang.Override\n        public double getLatitude() {\n          return latitude_;\n        }\n        /**\n         * <code>required double latitude = 1;</code>\n         * @param value The latitude to set.\n         * @return This builder for chaining.\n         */\n        public Builder setLatitude(double value) {\n\n          latitude_ = value;\n          bitField0_ |= 0x00000001;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required double latitude = 1;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearLatitude() {\n          bitField0_ = (bitField0_ & ~0x00000001);\n          latitude_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double longitude_ ;\n        /**\n         * <code>required double longitude = 2;</code>\n         * @return Whether the longitude field is set.\n         */\n        @java.lang.Override\n        public boolean hasLongitude() {\n          return ((bitField0_ & 0x00000002) != 0);\n        }\n        /**\n         * <code>required double longitude = 2;</code>\n         * @return The longitude.\n         */\n        @java.lang.Override\n        public double getLongitude() {\n          return longitude_;\n        }\n        /**\n         * <code>required double longitude = 2;</code>\n         * @param value The longitude to set.\n         * @return This builder for chaining.\n         */\n        public Builder setLongitude(double value) {\n\n          longitude_ = value;\n          bitField0_ |= 0x00000002;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required double longitude = 2;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearLongitude() {\n          bitField0_ = (bitField0_ & ~0x00000002);\n          longitude_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double altitude_ ;\n        /**\n         * <code>optional double altitude = 3;</code>\n         * @return Whether the altitude field is set.\n         */\n        @java.lang.Override\n        public boolean hasAltitude() {\n          return ((bitField0_ & 0x00000004) != 0);\n        }\n        /**\n         * <code>optional double altitude = 3;</code>\n         * @return The altitude.\n         */\n        @java.lang.Override\n        public double getAltitude() {\n          return altitude_;\n        }\n        /**\n         * <code>optional double altitude = 3;</code>\n         * @param value The altitude to set.\n         * @return This builder for chaining.\n         */\n        public Builder setAltitude(double value) {\n\n          altitude_ = value;\n          bitField0_ |= 0x00000004;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional double altitude = 3;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearAltitude() {\n          bitField0_ = (bitField0_ & ~0x00000004);\n          altitude_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double precision_ ;\n        /**\n         * <pre>\n         * dilution of precision of the current satellite fix. \n         * </pre>\n         *\n         * <code>optional double precision = 4;</code>\n         * @return Whether the precision field is set.\n         */\n        @java.lang.Override\n        public boolean hasPrecision() {\n          return ((bitField0_ & 0x00000008) != 0);\n        }\n        /**\n         * <pre>\n         * dilution of precision of the current satellite fix. \n         * </pre>\n         *\n         * <code>optional double precision = 4;</code>\n         * @return The precision.\n         */\n        @java.lang.Override\n        public double getPrecision() {\n          return precision_;\n        }\n        /**\n         * <pre>\n         * dilution of precision of the current satellite fix. \n         * </pre>\n         *\n         * <code>optional double precision = 4;</code>\n         * @param value The precision to set.\n         * @return This builder for chaining.\n         */\n        public Builder setPrecision(double value) {\n\n          precision_ = value;\n          bitField0_ |= 0x00000008;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * dilution of precision of the current satellite fix. \n         * </pre>\n         *\n         * <code>optional double precision = 4;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearPrecision() {\n          bitField0_ = (bitField0_ & ~0x00000008);\n          precision_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double heading_ ;\n        /**\n         * <pre>\n         * heading in degrees\n         * </pre>\n         *\n         * <code>optional double heading = 5;</code>\n         * @return Whether the heading field is set.\n         */\n        @java.lang.Override\n        public boolean hasHeading() {\n          return ((bitField0_ & 0x00000010) != 0);\n        }\n        /**\n         * <pre>\n         * heading in degrees\n         * </pre>\n         *\n         * <code>optional double heading = 5;</code>\n         * @return The heading.\n         */\n        @java.lang.Override\n        public double getHeading() {\n          return heading_;\n        }\n        /**\n         * <pre>\n         * heading in degrees\n         * </pre>\n         *\n         * <code>optional double heading = 5;</code>\n         * @param value The heading to set.\n         * @return This builder for chaining.\n         */\n        public Builder setHeading(double value) {\n\n          heading_ = value;\n          bitField0_ |= 0x00000010;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * heading in degrees\n         * </pre>\n         *\n         * <code>optional double heading = 5;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearHeading() {\n          bitField0_ = (bitField0_ & ~0x00000010);\n          heading_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double speed_ ;\n        /**\n         * <pre>\n         * meters per second\n         * </pre>\n         *\n         * <code>optional double speed = 6;</code>\n         * @return Whether the speed field is set.\n         */\n        @java.lang.Override\n        public boolean hasSpeed() {\n          return ((bitField0_ & 0x00000020) != 0);\n        }\n        /**\n         * <pre>\n         * meters per second\n         * </pre>\n         *\n         * <code>optional double speed = 6;</code>\n         * @return The speed.\n         */\n        @java.lang.Override\n        public double getSpeed() {\n          return speed_;\n        }\n        /**\n         * <pre>\n         * meters per second\n         * </pre>\n         *\n         * <code>optional double speed = 6;</code>\n         * @param value The speed to set.\n         * @return This builder for chaining.\n         */\n        public Builder setSpeed(double value) {\n\n          speed_ = value;\n          bitField0_ |= 0x00000020;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * meters per second\n         * </pre>\n         *\n         * <code>optional double speed = 6;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearSpeed() {\n          bitField0_ = (bitField0_ & ~0x00000020);\n          speed_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private long timestamp_ ;\n        /**\n         * <code>optional int64 timestamp = 7;</code>\n         * @return Whether the timestamp field is set.\n         */\n        @java.lang.Override\n        public boolean hasTimestamp() {\n          return ((bitField0_ & 0x00000040) != 0);\n        }\n        /**\n         * <code>optional int64 timestamp = 7;</code>\n         * @return The timestamp.\n         */\n        @java.lang.Override\n        public long getTimestamp() {\n          return timestamp_;\n        }\n        /**\n         * <code>optional int64 timestamp = 7;</code>\n         * @param value The timestamp to set.\n         * @return This builder for chaining.\n         */\n        public Builder setTimestamp(long value) {\n\n          timestamp_ = value;\n          bitField0_ |= 0x00000040;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional int64 timestamp = 7;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearTimestamp() {\n          bitField0_ = (bitField0_ & ~0x00000040);\n          timestamp_ = 0L;\n          onChanged();\n          return this;\n        }\n\n        private int satellites_ ;\n        /**\n         * <pre>\n         * number satellites locked by the GPS device\n         * </pre>\n         *\n         * <code>optional int32 satellites = 8;</code>\n         * @return Whether the satellites field is set.\n         */\n        @java.lang.Override\n        public boolean hasSatellites() {\n          return ((bitField0_ & 0x00000080) != 0);\n        }\n        /**\n         * <pre>\n         * number satellites locked by the GPS device\n         * </pre>\n         *\n         * <code>optional int32 satellites = 8;</code>\n         * @return The satellites.\n         */\n        @java.lang.Override\n        public int getSatellites() {\n          return satellites_;\n        }\n        /**\n         * <pre>\n         * number satellites locked by the GPS device\n         * </pre>\n         *\n         * <code>optional int32 satellites = 8;</code>\n         * @param value The satellites to set.\n         * @return This builder for chaining.\n         */\n        public Builder setSatellites(int value) {\n\n          satellites_ = value;\n          bitField0_ |= 0x00000080;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * number satellites locked by the GPS device\n         * </pre>\n         *\n         * <code>optional int32 satellites = 8;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearSatellites() {\n          bitField0_ = (bitField0_ & ~0x00000080);\n          satellites_ = 0;\n          onChanged();\n          return this;\n        }\n\n        private int status_ ;\n        /**\n         * <pre>\n         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n         * </pre>\n         *\n         * <code>optional int32 status = 9;</code>\n         * @return Whether the status field is set.\n         */\n        @java.lang.Override\n        public boolean hasStatus() {\n          return ((bitField0_ & 0x00000100) != 0);\n        }\n        /**\n         * <pre>\n         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n         * </pre>\n         *\n         * <code>optional int32 status = 9;</code>\n         * @return The status.\n         */\n        @java.lang.Override\n        public int getStatus() {\n          return status_;\n        }\n        /**\n         * <pre>\n         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n         * </pre>\n         *\n         * <code>optional int32 status = 9;</code>\n         * @param value The status to set.\n         * @return This builder for chaining.\n         */\n        public Builder setStatus(int value) {\n\n          status_ = value;\n          bitField0_ |= 0x00000100;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n         * </pre>\n         *\n         * <code>optional int32 status = 9;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearStatus() {\n          bitField0_ = (bitField0_ & ~0x00000100);\n          status_ = 0;\n          onChanged();\n          return this;\n        }\n\n        // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload.KuraPosition)\n      }\n\n      // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload.KuraPosition)\n      private static final org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition DEFAULT_INSTANCE;\n      static {\n        DEFAULT_INSTANCE = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition();\n      }\n\n      public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstance() {\n        return DEFAULT_INSTANCE;\n      }\n\n      private static final com.google.protobuf.Parser<KuraPosition>\n          PARSER = new com.google.protobuf.AbstractParser<KuraPosition>() {\n        @java.lang.Override\n        public KuraPosition parsePartialFrom(\n            com.google.protobuf.CodedInputStream input,\n            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n          Builder builder = newBuilder();\n          try {\n            builder.mergeFrom(input, extensionRegistry);\n          } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n            throw e.setUnfinishedMessage(builder.buildPartial());\n          } catch (com.google.protobuf.UninitializedMessageException e) {\n            throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n          } catch (java.io.IOException e) {\n            throw new com.google.protobuf.InvalidProtocolBufferException(e)\n                .setUnfinishedMessage(builder.buildPartial());\n          }\n          return builder.buildPartial();\n        }\n      };\n\n      public static com.google.protobuf.Parser<KuraPosition> parser() {\n        return PARSER;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Parser<KuraPosition> getParserForType() {\n        return PARSER;\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstanceForType() {\n        return DEFAULT_INSTANCE;\n      }\n\n    }\n\n    private int bitField0_;\n    public static final int TIMESTAMP_FIELD_NUMBER = 1;\n    private long timestamp_ = 0L;\n    /**\n     * <code>optional int64 timestamp = 1;</code>\n     * @return Whether the timestamp field is set.\n     */\n    @java.lang.Override\n    public boolean hasTimestamp() {\n      return ((bitField0_ & 0x00000001) != 0);\n    }\n    /**\n     * <code>optional int64 timestamp = 1;</code>\n     * @return The timestamp.\n     */\n    @java.lang.Override\n    public long getTimestamp() {\n      return timestamp_;\n    }\n\n    public static final int POSITION_FIELD_NUMBER = 2;\n    private org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition position_;\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     * @return Whether the position field is set.\n     */\n    @java.lang.Override\n    public boolean hasPosition() {\n      return ((bitField0_ & 0x00000002) != 0);\n    }\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     * @return The position.\n     */\n    @java.lang.Override\n    public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition() {\n      return position_ == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_;\n    }\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     */\n    @java.lang.Override\n    public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder() {\n      return position_ == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_;\n    }\n\n    public static final int METRIC_FIELD_NUMBER = 5000;\n    @SuppressWarnings(\"serial\")\n    private java.util.List<org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> metric_;\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public java.util.List<org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> getMetricList() {\n      return metric_;\n    }\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public java.util.List<? extends org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> \n        getMetricOrBuilderList() {\n      return metric_;\n    }\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public int getMetricCount() {\n      return metric_.size();\n    }\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index) {\n      return metric_.get(index);\n    }\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder(\n        int index) {\n      return metric_.get(index);\n    }\n\n    public static final int BODY_FIELD_NUMBER = 5001;\n    private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY;\n    /**\n     * <code>optional bytes body = 5001;</code>\n     * @return Whether the body field is set.\n     */\n    @java.lang.Override\n    public boolean hasBody() {\n      return ((bitField0_ & 0x00000004) != 0);\n    }\n    /**\n     * <code>optional bytes body = 5001;</code>\n     * @return The body.\n     */\n    @java.lang.Override\n    public com.google.protobuf.ByteString getBody() {\n      return body_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      if (hasPosition()) {\n        if (!getPosition().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      for (int i = 0; i < getMetricCount(); i++) {\n        if (!getMetric(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      if (!extensionsAreInitialized()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      com.google.protobuf.GeneratedMessage\n        .ExtendableMessage.ExtensionSerializer\n          extensionWriter = newExtensionSerializer();\n      if (((bitField0_ & 0x00000001) != 0)) {\n        output.writeInt64(1, timestamp_);\n      }\n      if (((bitField0_ & 0x00000002) != 0)) {\n        output.writeMessage(2, getPosition());\n      }\n      extensionWriter.writeUntil(5000, output);\n      for (int i = 0; i < metric_.size(); i++) {\n        output.writeMessage(5000, metric_.get(i));\n      }\n      if (((bitField0_ & 0x00000004) != 0)) {\n        output.writeBytes(5001, body_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) != 0)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, timestamp_);\n      }\n      if (((bitField0_ & 0x00000002) != 0)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(2, getPosition());\n      }\n      for (int i = 0; i < metric_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(5000, metric_.get(i));\n      }\n      if (((bitField0_ & 0x00000004) != 0)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5001, body_);\n      }\n      size += extensionsSerializedSize();\n      size += getUnknownFields().getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload)) {\n        return super.equals(obj);\n      }\n      org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload other = (org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload) obj;\n\n      if (hasTimestamp() != other.hasTimestamp()) return false;\n      if (hasTimestamp()) {\n        if (getTimestamp()\n            != other.getTimestamp()) return false;\n      }\n      if (hasPosition() != other.hasPosition()) return false;\n      if (hasPosition()) {\n        if (!getPosition()\n            .equals(other.getPosition())) return false;\n      }\n      if (!getMetricList()\n          .equals(other.getMetricList())) return false;\n      if (hasBody() != other.hasBody()) return false;\n      if (hasBody()) {\n        if (!getBody()\n            .equals(other.getBody())) return false;\n      }\n      if (!getUnknownFields().equals(other.getUnknownFields())) return false;\n      if (!getExtensionFields().equals(other.getExtensionFields()))\n        return false;\n      return true;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      if (hasTimestamp()) {\n        hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER;\n        hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n            getTimestamp());\n      }\n      if (hasPosition()) {\n        hash = (37 * hash) + POSITION_FIELD_NUMBER;\n        hash = (53 * hash) + getPosition().hashCode();\n      }\n      if (getMetricCount() > 0) {\n        hash = (37 * hash) + METRIC_FIELD_NUMBER;\n        hash = (53 * hash) + getMetricList().hashCode();\n      }\n      if (hasBody()) {\n        hash = (37 * hash) + BODY_FIELD_NUMBER;\n        hash = (53 * hash) + getBody().hashCode();\n      }\n      hash = hashFields(hash, getExtensionFields());\n      hash = (29 * hash) + getUnknownFields().hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseWithIOException(PARSER, input);\n    }\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseWithIOException(PARSER, input);\n    }\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code kuradatatypes.KuraPayload}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload, Builder> implements\n        // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload)\n        org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayloadOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.Builder.class);\n      }\n\n      // Construct using org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage\n                .alwaysUseFieldBuilders) {\n          getPositionFieldBuilder();\n          getMetricFieldBuilder();\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        bitField0_ = 0;\n        timestamp_ = 0L;\n        position_ = null;\n        if (positionBuilder_ != null) {\n          positionBuilder_.dispose();\n          positionBuilder_ = null;\n        }\n        if (metricBuilder_ == null) {\n          metric_ = java.util.Collections.emptyList();\n        } else {\n          metric_ = null;\n          metricBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        body_ = com.google.protobuf.ByteString.EMPTY;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor;\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstanceForType() {\n        return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload build() {\n        org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload buildPartial() {\n        org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload result = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload(this);\n        buildPartialRepeatedFields(result);\n        if (bitField0_ != 0) { buildPartial0(result); }\n        onBuilt();\n        return result;\n      }\n\n      private void buildPartialRepeatedFields(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload result) {\n        if (metricBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) != 0)) {\n            metric_ = java.util.Collections.unmodifiableList(metric_);\n            bitField0_ = (bitField0_ & ~0x00000004);\n          }\n          result.metric_ = metric_;\n        } else {\n          result.metric_ = metricBuilder_.build();\n        }\n      }\n\n      private void buildPartial0(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload result) {\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) != 0)) {\n          result.timestamp_ = timestamp_;\n          to_bitField0_ |= 0x00000001;\n        }\n        if (((from_bitField0_ & 0x00000002) != 0)) {\n          result.position_ = positionBuilder_ == null\n              ? position_\n              : positionBuilder_.build();\n          to_bitField0_ |= 0x00000002;\n        }\n        if (((from_bitField0_ & 0x00000008) != 0)) {\n          result.body_ = body_;\n          to_bitField0_ |= 0x00000004;\n        }\n        result.bitField0_ |= to_bitField0_;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload) {\n          return mergeFrom((org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload other) {\n        if (other == org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.getDefaultInstance()) return this;\n        if (other.hasTimestamp()) {\n          setTimestamp(other.getTimestamp());\n        }\n        if (other.hasPosition()) {\n          mergePosition(other.getPosition());\n        }\n        if (metricBuilder_ == null) {\n          if (!other.metric_.isEmpty()) {\n            if (metric_.isEmpty()) {\n              metric_ = other.metric_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n            } else {\n              ensureMetricIsMutable();\n              metric_.addAll(other.metric_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.metric_.isEmpty()) {\n            if (metricBuilder_.isEmpty()) {\n              metricBuilder_.dispose();\n              metricBuilder_ = null;\n              metric_ = other.metric_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n              metricBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getMetricFieldBuilder() : null;\n            } else {\n              metricBuilder_.addAllMessages(other.metric_);\n            }\n          }\n        }\n        if (other.hasBody()) {\n          setBody(other.getBody());\n        }\n        this.mergeExtensionFields(other);\n        this.mergeUnknownFields(other.getUnknownFields());\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        if (hasPosition()) {\n          if (!getPosition().isInitialized()) {\n            return false;\n          }\n        }\n        for (int i = 0; i < getMetricCount(); i++) {\n          if (!getMetric(i).isInitialized()) {\n            return false;\n          }\n        }\n        if (!extensionsAreInitialized()) {\n          return false;\n        }\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        if (extensionRegistry == null) {\n          throw new java.lang.NullPointerException();\n        }\n        try {\n          boolean done = false;\n          while (!done) {\n            int tag = input.readTag();\n            switch (tag) {\n              case 0:\n                done = true;\n                break;\n              case 8: {\n                timestamp_ = input.readInt64();\n                bitField0_ |= 0x00000001;\n                break;\n              } // case 8\n              case 18: {\n                input.readMessage(\n                    getPositionFieldBuilder().getBuilder(),\n                    extensionRegistry);\n                bitField0_ |= 0x00000002;\n                break;\n              } // case 18\n              case 40002: {\n                org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric m =\n                    input.readMessage(\n                        org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.parser(),\n                        extensionRegistry);\n                if (metricBuilder_ == null) {\n                  ensureMetricIsMutable();\n                  metric_.add(m);\n                } else {\n                  metricBuilder_.addMessage(m);\n                }\n                break;\n              } // case 40002\n              case 40010: {\n                body_ = input.readBytes();\n                bitField0_ |= 0x00000008;\n                break;\n              } // case 40010\n              default: {\n                if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                  done = true; // was an endgroup tag\n                }\n                break;\n              } // default:\n            } // switch (tag)\n          } // while (!done)\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          throw e.unwrapIOException();\n        } finally {\n          onChanged();\n        } // finally\n        return this;\n      }\n      private int bitField0_;\n\n      private long timestamp_ ;\n      /**\n       * <code>optional int64 timestamp = 1;</code>\n       * @return Whether the timestamp field is set.\n       */\n      @java.lang.Override\n      public boolean hasTimestamp() {\n        return ((bitField0_ & 0x00000001) != 0);\n      }\n      /**\n       * <code>optional int64 timestamp = 1;</code>\n       * @return The timestamp.\n       */\n      @java.lang.Override\n      public long getTimestamp() {\n        return timestamp_;\n      }\n      /**\n       * <code>optional int64 timestamp = 1;</code>\n       * @param value The timestamp to set.\n       * @return This builder for chaining.\n       */\n      public Builder setTimestamp(long value) {\n\n        timestamp_ = value;\n        bitField0_ |= 0x00000001;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 timestamp = 1;</code>\n       * @return This builder for chaining.\n       */\n      public Builder clearTimestamp() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        timestamp_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition position_;\n      private com.google.protobuf.SingleFieldBuilder<\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder> positionBuilder_;\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       * @return Whether the position field is set.\n       */\n      public boolean hasPosition() {\n        return ((bitField0_ & 0x00000002) != 0);\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       * @return The position.\n       */\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition() {\n        if (positionBuilder_ == null) {\n          return position_ == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_;\n        } else {\n          return positionBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public Builder setPosition(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition value) {\n        if (positionBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          position_ = value;\n        } else {\n          positionBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000002;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public Builder setPosition(\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder builderForValue) {\n        if (positionBuilder_ == null) {\n          position_ = builderForValue.build();\n        } else {\n          positionBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000002;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public Builder mergePosition(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition value) {\n        if (positionBuilder_ == null) {\n          if (((bitField0_ & 0x00000002) != 0) &&\n            position_ != null &&\n            position_ != org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance()) {\n            getPositionBuilder().mergeFrom(value);\n          } else {\n            position_ = value;\n          }\n        } else {\n          positionBuilder_.mergeFrom(value);\n        }\n        if (position_ != null) {\n          bitField0_ |= 0x00000002;\n          onChanged();\n        }\n        return this;\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public Builder clearPosition() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        position_ = null;\n        if (positionBuilder_ != null) {\n          positionBuilder_.dispose();\n          positionBuilder_ = null;\n        }\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder getPositionBuilder() {\n        bitField0_ |= 0x00000002;\n        onChanged();\n        return getPositionFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder() {\n        if (positionBuilder_ != null) {\n          return positionBuilder_.getMessageOrBuilder();\n        } else {\n          return position_ == null ?\n              org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_;\n        }\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder> \n          getPositionFieldBuilder() {\n        if (positionBuilder_ == null) {\n          positionBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder>(\n                  getPosition(),\n                  getParentForChildren(),\n                  isClean());\n          position_ = null;\n        }\n        return positionBuilder_;\n      }\n\n      private java.util.List<org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> metric_ =\n        java.util.Collections.emptyList();\n      private void ensureMetricIsMutable() {\n        if (!((bitField0_ & 0x00000004) != 0)) {\n          metric_ = new java.util.ArrayList<org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric>(metric_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> metricBuilder_;\n\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public java.util.List<org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> getMetricList() {\n        if (metricBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(metric_);\n        } else {\n          return metricBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public int getMetricCount() {\n        if (metricBuilder_ == null) {\n          return metric_.size();\n        } else {\n          return metricBuilder_.getCount();\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index) {\n        if (metricBuilder_ == null) {\n          return metric_.get(index);\n        } else {\n          return metricBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder setMetric(\n          int index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) {\n        if (metricBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMetricIsMutable();\n          metric_.set(index, value);\n          onChanged();\n        } else {\n          metricBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder setMetric(\n          int index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          metric_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          metricBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addMetric(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) {\n        if (metricBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMetricIsMutable();\n          metric_.add(value);\n          onChanged();\n        } else {\n          metricBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addMetric(\n          int index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) {\n        if (metricBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMetricIsMutable();\n          metric_.add(index, value);\n          onChanged();\n        } else {\n          metricBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addMetric(\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          metric_.add(builderForValue.build());\n          onChanged();\n        } else {\n          metricBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addMetric(\n          int index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          metric_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          metricBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addAllMetric(\n          java.lang.Iterable<? extends org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> values) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, metric_);\n          onChanged();\n        } else {\n          metricBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder clearMetric() {\n        if (metricBuilder_ == null) {\n          metric_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000004);\n          onChanged();\n        } else {\n          metricBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder removeMetric(int index) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          metric_.remove(index);\n          onChanged();\n        } else {\n          metricBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder getMetricBuilder(\n          int index) {\n        return getMetricFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder(\n          int index) {\n        if (metricBuilder_ == null) {\n          return metric_.get(index);  } else {\n          return metricBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public java.util.List<? extends org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> \n           getMetricOrBuilderList() {\n        if (metricBuilder_ != null) {\n          return metricBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(metric_);\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder addMetricBuilder() {\n        return getMetricFieldBuilder().addBuilder(\n            org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance());\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder addMetricBuilder(\n          int index) {\n        return getMetricFieldBuilder().addBuilder(\n            index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance());\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public java.util.List<org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder> \n           getMetricBuilderList() {\n        return getMetricFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> \n          getMetricFieldBuilder() {\n        if (metricBuilder_ == null) {\n          metricBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder>(\n                  metric_,\n                  ((bitField0_ & 0x00000004) != 0),\n                  getParentForChildren(),\n                  isClean());\n          metric_ = null;\n        }\n        return metricBuilder_;\n      }\n\n      private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>optional bytes body = 5001;</code>\n       * @return Whether the body field is set.\n       */\n      @java.lang.Override\n      public boolean hasBody() {\n        return ((bitField0_ & 0x00000008) != 0);\n      }\n      /**\n       * <code>optional bytes body = 5001;</code>\n       * @return The body.\n       */\n      @java.lang.Override\n      public com.google.protobuf.ByteString getBody() {\n        return body_;\n      }\n      /**\n       * <code>optional bytes body = 5001;</code>\n       * @param value The body to set.\n       * @return This builder for chaining.\n       */\n      public Builder setBody(com.google.protobuf.ByteString value) {\n        if (value == null) { throw new NullPointerException(); }\n        body_ = value;\n        bitField0_ |= 0x00000008;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bytes body = 5001;</code>\n       * @return This builder for chaining.\n       */\n      public Builder clearBody() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        body_ = getDefaultInstance().getBody();\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload)\n    }\n\n    // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload)\n    private static final org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload();\n    }\n\n    public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<KuraPayload>\n        PARSER = new com.google.protobuf.AbstractParser<KuraPayload>() {\n      @java.lang.Override\n      public KuraPayload parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        Builder builder = newBuilder();\n        try {\n          builder.mergeFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          throw e.setUnfinishedMessage(builder.buildPartial());\n        } catch (com.google.protobuf.UninitializedMessageException e) {\n          throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n        } catch (java.io.IOException e) {\n          throw new com.google.protobuf.InvalidProtocolBufferException(e)\n              .setUnfinishedMessage(builder.buildPartial());\n        }\n        return builder.buildPartial();\n      }\n    };\n\n    public static com.google.protobuf.Parser<KuraPayload> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<KuraPayload> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_kuradatatypes_KuraPayload_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_kuradatatypes_KuraPayload_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable;\n\n  public static com.google.protobuf.Descriptors.FileDescriptor\n      getDescriptor() {\n    return descriptor;\n  }\n  private static  com.google.protobuf.Descriptors.FileDescriptor\n      descriptor;\n  static {\n    java.lang.String[] descriptorData = {\n      \"\\n\\021kurapayload.proto\\022\\rkuradatatypes\\\"\\243\\005\\n\\013K\" +\n      \"uraPayload\\022\\021\\n\\ttimestamp\\030\\001 \\001(\\003\\0229\\n\\010positio\" +\n      \"n\\030\\002 \\001(\\0132\\'.kuradatatypes.KuraPayload.Kura\" +\n      \"Position\\0226\\n\\006metric\\030\\210\\' \\003(\\0132%.kuradatatype\" +\n      \"s.KuraPayload.KuraMetric\\022\\r\\n\\004body\\030\\211\\' \\001(\\014\\032\" +\n      \"\\305\\002\\n\\nKuraMetric\\022\\014\\n\\004name\\030\\001 \\002(\\t\\022=\\n\\004type\\030\\002 \\002\" +\n      \"(\\0162/.kuradatatypes.KuraPayload.KuraMetri\" +\n      \"c.ValueType\\022\\024\\n\\014double_value\\030\\003 \\001(\\001\\022\\023\\n\\013flo\" +\n      \"at_value\\030\\004 \\001(\\002\\022\\022\\n\\nlong_value\\030\\005 \\001(\\003\\022\\021\\n\\tin\" +\n      \"t_value\\030\\006 \\001(\\005\\022\\022\\n\\nbool_value\\030\\007 \\001(\\010\\022\\024\\n\\014str\" +\n      \"ing_value\\030\\010 \\001(\\t\\022\\023\\n\\013bytes_value\\030\\t \\001(\\014\\\"Y\\n\\t\" +\n      \"ValueType\\022\\n\\n\\006DOUBLE\\020\\000\\022\\t\\n\\005FLOAT\\020\\001\\022\\t\\n\\005INT6\" +\n      \"4\\020\\002\\022\\t\\n\\005INT32\\020\\003\\022\\010\\n\\004BOOL\\020\\004\\022\\n\\n\\006STRING\\020\\005\\022\\t\\n\\005\" +\n      \"BYTES\\020\\006\\032\\257\\001\\n\\014KuraPosition\\022\\020\\n\\010latitude\\030\\001 \\002\" +\n      \"(\\001\\022\\021\\n\\tlongitude\\030\\002 \\002(\\001\\022\\020\\n\\010altitude\\030\\003 \\001(\\001\\022\" +\n      \"\\021\\n\\tprecision\\030\\004 \\001(\\001\\022\\017\\n\\007heading\\030\\005 \\001(\\001\\022\\r\\n\\005s\" +\n      \"peed\\030\\006 \\001(\\001\\022\\021\\n\\ttimestamp\\030\\007 \\001(\\003\\022\\022\\n\\nsatelli\" +\n      \"tes\\030\\010 \\001(\\005\\022\\016\\n\\006status\\030\\t \\001(\\005*\\005\\010\\003\\020\\210\\'B^\\nJorg.\" +\n      \"eclipse.kura.internal.cloudconnection.ec\" +\n      \"lipseiot.mqtt.message.protobufB\\020KuraPayl\" +\n      \"oadProto\"\n    };\n    descriptor = com.google.protobuf.Descriptors.FileDescriptor\n      .internalBuildGeneratedFileFrom(descriptorData,\n        new com.google.protobuf.Descriptors.FileDescriptor[] {\n        });\n    internal_static_kuradatatypes_KuraPayload_descriptor =\n      getDescriptor().getMessageTypes().get(0);\n    internal_static_kuradatatypes_KuraPayload_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_kuradatatypes_KuraPayload_descriptor,\n        new java.lang.String[] { \"Timestamp\", \"Position\", \"Metric\", \"Body\", });\n    internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor =\n      internal_static_kuradatatypes_KuraPayload_descriptor.getNestedTypes().get(0);\n    internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor,\n        new java.lang.String[] { \"Name\", \"Type\", \"DoubleValue\", \"FloatValue\", \"LongValue\", \"IntValue\", \"BoolValue\", \"StringValue\", \"BytesValue\", });\n    internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor =\n      internal_static_kuradatatypes_KuraPayload_descriptor.getNestedTypes().get(1);\n    internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor,\n        new java.lang.String[] { \"Latitude\", \"Longitude\", \"Altitude\", \"Precision\", \"Heading\", \"Speed\", \"Timestamp\", \"Satellites\", \"Status\", });\n    descriptor.resolveAllFeaturesImmutable();\n  }\n\n  // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/protobuf/kurapayload.proto",
    "content": "//\n// To compile:\n// protoc --proto_path=src/main/protobuf --java_out=src/main/java src/main/protobuf/kurapayload.proto\n//\nsyntax = \"proto2\";\n\npackage kuradatatypes;\n\noption java_package         = \"org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf\";\noption java_outer_classname = \"KuraPayloadProto\";\n\nmessage KuraPayload {\n\n\tmessage KuraMetric {\n\t\tenum ValueType {  \n\t\t\tDOUBLE         = 0; \n\t\t\tFLOAT          = 1;\n\t\t\tINT64          = 2;\n\t\t\tINT32          = 3;\n\t\t\tBOOL           = 4;\n\t\t\tSTRING         = 5;\n\t\t\tBYTES          = 6;\n\t\t}\n\t\t  \n\t\trequired string    name            = 1;\n\t\trequired ValueType type            = 2;\n\n\t\toptional double double_value       = 3;\n\t\toptional float  float_value        = 4;\n\t\toptional int64  long_value         = 5;\n\t\toptional int32  int_value          = 6;\n\t\toptional bool   bool_value         = 7;\n\t\toptional string string_value       = 8;\n\t\toptional bytes  bytes_value        = 9;\n\t}\n\n    message KuraPosition {\n        required double latitude   = 1;\n        required double longitude  = 2;\n        optional double altitude   = 3;\n        optional double precision  = 4;  // dilution of precision of the current satellite fix. \n        optional double heading    = 5;  // heading in degrees\n        optional double speed      = 6;  // meters per second\n        optional int64  timestamp  = 7;\n        optional int32  satellites = 8;  // number satellites locked by the GPS device\n        optional int32  status     = 9;  // status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n    }\n\n    optional int64       timestamp = 1;\n    optional KuraPosition position  = 2;\n\t\n\textensions 3 to 4999;\n    repeated KuraMetric   metric    = 5000;  // can be zero, so optional\n \toptional bytes       body      = 5001;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/.gitignore",
    "content": "/target\n/bin\n/lib\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.cloudconnection.kapua.mqtt.provider\nBundle-SymbolicName: org.eclipse.kura.cloudconnection.kapua.mqtt.provider;singleton:=true\nBundle-Version: 1.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .,\n lib/protobuf-java.jar\nBundle-ActivationPolicy: lazy\nImport-Package: com.eclipsesource.json;version=\"0.9.5\",\n org.apache.commons.io;version=\"2.4.0\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.audit;version=\"[1.0,2.0)\",\n org.eclipse.kura.certificate;version=\"[2.0,3.0)\",\n org.eclipse.kura.cloud;version=\"[1.1,1.2)\",\n org.eclipse.kura.cloud.factory;version=\"[1.1,1.2)\",\n org.eclipse.kura.cloudconnection;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.factory;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.publisher;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.subscriber;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.subscriber.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.command;version=\"[1.2,1.3)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.data;version=\"[1.3,2.0)\",\n org.eclipse.kura.core.data.util;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.util;version=\"[2.0,3.0)\",\n org.eclipse.kura.crypto;version=\"[1.0,2.0)\",\n org.eclipse.kura.data;version=\"[1.0,2.0)\",\n org.eclipse.kura.data.listener;version=\"[1.0,1.1)\",\n org.eclipse.kura.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.marshalling;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.5,2.0)\",\n org.eclipse.kura.net;version=\"[2.0,3.0)\",\n org.eclipse.kura.net.modem;version=\"[2.0,3.0)\",\n org.eclipse.kura.net.status;version=\"[1.1,2.0)\",\n org.eclipse.kura.net.status.modem;version=\"[1.0,2.0)\",\n org.eclipse.kura.position;version=\"[1.0,2.0)\",\n org.eclipse.kura.security.tamper.detection;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.5,2.0)\",\n org.eclipse.kura.util.zip;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.3.0\",\n org.osgi.util.measurement;version=\"[1.0,2.0)\",\n org.osgi.util.position;version=\"[1.0,2.0)\",\n org.osgi.util.tracker;version=\"1.5.1\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/cloud.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"false\" modified=\"updated\" name=\"org.eclipse.kura.cloud.CloudService\">\n   <implementation class=\"org.eclipse.kura.core.cloud.CloudServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloud.CloudService\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.cloud.CloudPayloadProtoBufEncoder\"/>\n      <provide interface=\"org.eclipse.kura.cloud.CloudPayloadProtoBufDecoder\"/>\n      <provide interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\"/>\n      <provide interface=\"org.eclipse.kura.cloudconnection.CloudConnectionManager\"/>\n      <provide interface=\"org.eclipse.kura.cloudconnection.CloudEndpoint\"/>\n   </service>\n   <reference name=\"DataService\" \n              interface=\"org.eclipse.kura.data.DataService\" \n              policy=\"static\" \n              cardinality=\"1..1\" \n              bind=\"setDataService\" \n              unbind=\"unsetDataService\"/>\n   <reference name=\"SystemService\" \n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"setSystemService\"\n              unbind=\"unsetSystemService\"\n              interface=\"org.eclipse.kura.system.SystemService\"/>\n   <reference name=\"SystemAdminService\" \n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"setSystemAdminService\"\n              unbind=\"unsetSystemAdminService\"\n              interface=\"org.eclipse.kura.system.SystemAdminService\"/>\n   <reference name=\"NetworkService\" \n              policy=\"dynamic\" \n              cardinality=\"0..1\" \n              bind=\"setNetworkService\" \n              unbind=\"unsetNetworkService\"\n              interface=\"org.eclipse.kura.net.NetworkService\"/>\n   <reference name=\"PositionService\" \n              cardinality=\"0..1\" \n              bind=\"setPositionService\" \n              interface=\"org.eclipse.kura.position.PositionService\" \n              policy=\"dynamic\" \n              unbind=\"unsetPositionService\"/>\n   <reference name=\"EventAdmin\"              \n              cardinality=\"1..1\" \n              policy=\"static\" \n              bind=\"setEventAdmin\" \n              unbind=\"unsetEventAdmin\"\n              interface=\"org.osgi.service.event.EventAdmin\"/>\n   <reference bind=\"setJsonUnmarshaller\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.marshalling.Unmarshaller\"\n              name=\"Unmarshaller\"\n              policy=\"static\"\n              target=\"(kura.service.pid=org.eclipse.kura.json.marshaller.unmarshaller.provider)\"\n              unbind=\"unsetJsonUnmarshaller\"/>\n   <reference bind=\"setJsonMarshaller\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.marshalling.Marshaller\"\n              name=\"Marshaller\"\n              policy=\"static\"\n              target=\"(kura.service.pid=org.eclipse.kura.json.marshaller.unmarshaller.provider)\"\n              unbind=\"unsetJsonMarshaller\"/>\n   <reference bind=\"setTamperDetectionService\" \n              cardinality=\"0..n\" \n              interface=\"org.eclipse.kura.security.tamper.detection.TamperDetectionService\" \n              name=\"TamperDetectionService\" \n              policy=\"dynamic\" \n              unbind=\"unsetTamperDetectionService\"/>\n   <reference bind=\"setNetworkStatusService\" \n              cardinality=\"0..1\" \n              interface=\"org.eclipse.kura.net.status.NetworkStatusService\" \n              name=\"NetworkStatusService\" \n              policy=\"dynamic\" \n              unbind=\"unsetNetworkStatusService\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/cloudCall.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" \n               name=\"org.eclipse.kura.cloud.CloudCallService\"\n               activate=\"activate\" deactivate=\"deactivate\">\n   <implementation class=\"org.eclipse.kura.core.cloud.call.CloudCallServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloud.CloudCallService\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloud.CloudCallService\"/>\n   <reference name=\"DataService\"\n              policy=\"static\" \n              cardinality=\"1..1\" \n              bind=\"setDataService\" \n              unbind=\"unsetDataService\"\n              interface=\"org.eclipse.kura.data.DataService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/cloudPublisher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloud.publisher.CloudPublisher\">\n   <implementation class=\"org.eclipse.kura.core.cloud.publisher.CloudPublisherImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloud.publisher.CloudPublisher\"/>\n   <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloud.CloudService\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/cloudSubscriber.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloud.subscriber.CloudSubscriber\">\n   <implementation class=\"org.eclipse.kura.core.cloud.subscriber.CloudSubscriberImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloud.subscriber.CloudSubscriber\"/>\n   <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloud.CloudService\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloud.CloudService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n     Benjamin Cabé <benjamin@eclipse.org>\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.cloud.CloudService\" \n         name=\"CloudService\" \n         description=\"The CloudService allows for setting a user friendly name for the current device. It also provides the option to compress message payloads to reduce network traffic.\">\n\n        <Icon resource=\"CloudService\" size=\"32\"/>\n        \n        <AD id=\"device.display-name\"\n            name=\"Device Display-Name\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"device-name\"\n            description=\"Friendly name of the device. Device name is the common name of the device (eg: Reliagate 20-25, Raspberry Pi, etc.). Hostname will use the linux hostname utility. \n            \t\t\t\tCustom allows for defining a unique string. Server defined relies on the remote management server to define a name.\">\n        \t<Option label=\"Set display name as device name\" value=\"device-name\" />\n        \t<Option label=\"Set display name from hostname\" value=\"hostname\" />\n        \t<Option label=\"Custom\" value=\"custom\" />\n        \t<Option label=\"Server defined\" value=\"server\" />\n        </AD>\n        \n        <AD id=\"device.custom-name\"\n        \tname=\"Device Custom-Name\"\n        \ttype=\"String\"\n        \tcardinality=\"0\"\n        \trequired=\"false\"\n        \tdefault=\"\"\n        \tdescription='Custom name for the device. This value is applied ONLY if device.display-name is set to \"Custom\"'>\n        </AD>\n                    \n        <AD id=\"topic.control-prefix\"\n            name=\"Topic Control-Prefix\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"$EDC\"\n            description='Topic prefix for system and device management messages.'>\n        </AD>\n                    \n        <AD id=\"encode.gzip\"\n            name=\"Encode gzip\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"true\"\n            description=\"Compress message payloads before sending them to the remote server to reduce the network traffic.\">\n        </AD>\n        \n        <AD id=\"republish.mqtt.birth.cert.on.gps.lock\"\n            name=\"Republish Mqtt Birth Cert On Gps Lock\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Whether or not to republish the MQTT Birth Certificate on GPS lock event\"/>\n\n        <AD id=\"republish.mqtt.birth.cert.on.tamper.event\"\n            name=\"Republish Mqtt Birth Cert On Tamper Event\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"Whether or not to republish the MQTT Birth Certificate on a tamper event. This has effect only if a TamperDetectionService is available in the framework.\"/>\n            \n        <AD id=\"enable.default.subscriptions\"\n            name=\"Enable Default Subscriptions\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"Manages the default subscriptions to the gateway management MQTT topics. When disabled, the gateway will not be remotely manageable.\"/>\n\n        <AD id=\"payload.encoding\"\n            name=\"Payload Encoding\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"kura-protobuf\"\n            description=\"Specify the message payload encoding.\">\n            <Option label=\"Kura Protobuf\" value=\"kura-protobuf\" />\n            <Option label=\"Simple JSON\" value=\"simple-json\" />\n        </AD>\n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.cloud.CloudService\" factoryPid=\"org.eclipse.kura.cloud.CloudService\">\n        <Object ocdref=\"org.eclipse.kura.cloud.CloudService\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloud.publisher.CloudPublisher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2018, 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.cloud.publisher.CloudPublisher\" \n         name=\"CloudPublisher\" \n         description=\"The CloudPublisher allows to define publishing parameters and provide a simple endpoint where the applications can attach to publish their messages.\">\n\n        <AD id=\"appId\"\n            name=\"Application Id\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"W1\"\n            description='The application id used to publish messages.'>\n        </AD>\n        \n        <AD id=\"app.topic\"\n        \tname=\"Application Topic\"\n        \ttype=\"String\"\n        \tcardinality=\"0\"\n        \trequired=\"false\"\n        \tdefault=\"A1/$assetName\"\n        \tdescription='Follows the application Id and specifies the rest of the publishing topic. Wildcards can be defined in the topic by specifing a $value in the field. The publisher will try to match \"value\" with a corresponding property in the received KuraMessage. If possible, the $value placeholder will be substituted with the real value specified in the KuraMessage received from the user application.'>\n        </AD>\n                    \n        <AD id=\"qos\"\n            name=\"Qos\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            description='The desired quality of service for the messages that have to be published. If Qos is 0, the message is delivered at most once, or it is not delivered at all. If Qos is set to 1, the message is always delivered at least once.'>\n            <Option label=\"0\" value=\"0\" />\n            <Option label=\"1\" value=\"1\" />\n        </AD>\n                    \n        <AD id=\"retain\"\n            name=\"Retain\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Default retaing flag for the published messages.\">\n        </AD>\n        \n        <AD id=\"message.type\"\n            name=\"Kind of Message\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"data\"\n            description=\"Type of message to be published.\">\n            <Option label=\"Data\" value=\"data\" />\n            <Option label=\"Control\" value=\"control\" />\n        </AD>\n            \n        <AD id=\"priority\"\n            name=\"Priority\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            min=\"0\"\n            default=\"7\"\n            description='Message priority. Priority level 0 (highest) should be used sparingly and reserved for messages that should be sent with the minimum latency. Default is set to 7.'>\n        </AD>\n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.cloud.publisher.CloudPublisher\" factoryPid=\"org.eclipse.kura.cloud.publisher.CloudPublisher\">\n        <Object ocdref=\"org.eclipse.kura.cloud.publisher.CloudPublisher\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloud.subscriber.CloudSubscriber.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.cloud.subscriber.CloudSubscriber\" \n         name=\"CloudSubscriber\" \n         description=\"The CloudSubscriber allows to define the subscribe topic and notify the associated applications when a subscription event happens.\">\n        \n        <AD id=\"appId\"\n            name=\"Application Id\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"W1\"\n            description='The application id used to receive messages.'>\n        </AD>\n        \n        <AD id=\"app.topic\"\n        \tname=\"Application Topic\"\n        \ttype=\"String\"\n        \tcardinality=\"0\"\n        \trequired=\"false\"\n        \tdefault=\"A1/#\"\n        \tdescription='Follows the application Id and specifies the rest of the subscription topic.'>\n        </AD>\n                    \n        <AD id=\"qos\"\n            name=\"Qos\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            description='The desired quality of service for the subscription messages.'>\n            <Option label=\"0\" value=\"0\" />\n            <Option label=\"1\" value=\"1\" />\n        </AD>\n        \n        <AD id=\"message.type\"\n            name=\"Kind of Message\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"data\"\n            description=\"Type of message to be received.\">\n            <Option label=\"Data\" value=\"data\" />\n            <Option label=\"Control\" value=\"control\" />\n        </AD>\n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.cloud.subscriber.CloudSubscriber\" factoryPid=\"org.eclipse.kura.cloud.subscriber.CloudSubscriber\">\n        <Object ocdref=\"org.eclipse.kura.cloud.subscriber.CloudSubscriber\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/build.properties",
    "content": "bin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/,\\\n               lib/protobuf-java.jar\nsrc.includes = about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n     Red Hat Inc\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.cloudconnection.kapua.mqtt.provider</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.basedir}/../test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.google.protobuf</groupId>\n            <artifactId>protobuf-java</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>3.8.1</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <outputDirectory>${project.basedir}/lib</outputDirectory>\n                            <includeArtifactIds>\n                                protobuf-java\n                            </includeArtifactIds>\n                            <stripVersion>true</stripVersion>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <artifactId>maven-clean-plugin</artifactId>\n                <version>3.1.0</version>\n                <configuration>\n                    <filesets>\n                        <fileset>\n                            <directory>lib</directory>\n                        </fileset>\n                    </filesets>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/cloud/app/RequestIdGenerator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloud.app;\n\nimport java.util.Random;\n\npublic class RequestIdGenerator {\n\n    private static RequestIdGenerator s_instance = new RequestIdGenerator();\n\n    private final Random m_random;\n\n    private RequestIdGenerator() {\n        super();\n        this.m_random = new Random();\n    }\n\n    public static RequestIdGenerator getInstance() {\n        return s_instance;\n    }\n\n    public String next() {\n        long timestamp = System.currentTimeMillis();\n\n        long random;\n        synchronized (this.m_random) {\n            random = this.m_random.nextLong();\n        }\n\n        return timestamp + \"-\" + random;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudClientImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloud.CloudClientListener;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Implementation of the CloudClient interface.\n */\npublic class CloudClientImpl implements CloudClient, CloudClientListener {\n\n    @SuppressWarnings(\"unused\")\n    private static final Logger logger = LoggerFactory.getLogger(CloudClientImpl.class);\n\n    private final String applicationId;\n    private final DataService dataService;\n    private final CloudServiceImpl cloudServiceImpl;\n\n    private final List<CloudClientListenerAdapter> listeners;\n\n    protected CloudClientImpl(String applicationId, DataService dataService, CloudServiceImpl cloudServiceImpl) {\n        this.applicationId = applicationId;\n        this.dataService = dataService;\n        this.cloudServiceImpl = cloudServiceImpl;\n        this.listeners = new CopyOnWriteArrayList<>();\n    }\n\n    /**\n     * Returns the applicationId of this CloudApplicationClient\n     *\n     * @return applicationId\n     */\n    @Override\n    public String getApplicationId() {\n        return this.applicationId;\n    }\n\n    /**\n     * Releases this CloudClient handle. This instance should no longer be used.\n     * Note: CloudClient does not unsubscribes all subscriptions incurred by this client,\n     * this responsibility is left to the application developer\n     */\n    @Override\n    public void release() {\n        // remove this from being a callback handler\n        this.cloudServiceImpl.removeCloudClient(this);\n    }\n\n    // --------------------------------------------------------------------\n    //\n    // CloudCallbackHandler API\n    //\n    // --------------------------------------------------------------------\n\n    @Override\n    public void addCloudClientListener(CloudClientListener cloudClientListener) {\n        this.listeners.add(new CloudClientListenerAdapter(cloudClientListener));\n    }\n\n    @Override\n    public void removeCloudClientListener(CloudClientListener cloudClientListener) {\n        // create a copy to avoid concurrent modification exceptions\n        List<CloudClientListenerAdapter> adapters = new ArrayList<>(this.listeners);\n        for (CloudClientListenerAdapter adapter : adapters) {\n            if (adapter.getCloudClientListenerAdapted() == cloudClientListener) {\n                this.listeners.remove(adapter);\n                break;\n            }\n        }\n    }\n\n    // --------------------------------------------------------------------\n    //\n    // CloudClient API\n    //\n    // --------------------------------------------------------------------\n\n    @Override\n    public boolean isConnected() {\n        return this.dataService.isConnected();\n    }\n\n    @Override\n    public int publish(String appTopic, KuraPayload payload, int qos, boolean retain) throws KuraException {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        return publish(options.getTopicClientIdToken(), appTopic, payload, qos, retain);\n    }\n\n    @Override\n    public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain)\n            throws KuraException {\n        return publish(deviceId, appTopic, payload, qos, retain, 5);\n    }\n\n    @Override\n    public int publish(String appTopic, KuraPayload payload, int qos, boolean retain, int priority)\n            throws KuraException {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        return publish(options.getTopicClientIdToken(), appTopic, payload, qos, retain, priority);\n    }\n\n    @Override\n    public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain, int priority)\n            throws KuraException {\n        byte[] appPayload = this.cloudServiceImpl.encodePayload(payload);\n        return publish(deviceId, appTopic, appPayload, qos, retain, priority);\n    }\n\n    @Override\n    public int publish(String appTopic, byte[] payload, int qos, boolean retain, int priority) throws KuraException {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        return publish(options.getTopicClientIdToken(), appTopic, payload, qos, retain, priority);\n    }\n\n    @Override\n    public int publish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraException {\n        boolean isControl = false;\n        String fullTopic = encodeTopic(deviceId, appTopic, isControl);\n        return this.dataService.publish(fullTopic, payload, qos, retain, priority);\n    }\n\n    @Override\n    public int controlPublish(String appTopic, KuraPayload payload, int qos, boolean retain, int priority)\n            throws KuraException {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        return controlPublish(options.getTopicClientIdToken(), appTopic, payload, qos, retain, priority);\n    }\n\n    @Override\n    public int controlPublish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain,\n            int priority) throws KuraException {\n        byte[] appPayload = this.cloudServiceImpl.encodePayload(payload);\n        return controlPublish(deviceId, appTopic, appPayload, qos, retain, priority);\n    }\n\n    @Override\n    public int controlPublish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraException {\n        boolean isControl = true;\n        String fullTopic = encodeTopic(deviceId, appTopic, isControl);\n        return this.dataService.publish(fullTopic, payload, qos, retain, priority);\n    }\n\n    @Override\n    public void subscribe(String appTopic, int qos) throws KuraException {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        subscribe(options.getTopicClientIdToken(), appTopic, qos);\n    }\n\n    @Override\n    public void subscribe(String deviceId, String appTopic, int qos) throws KuraException {\n        boolean isControl = false;\n        String fullTopic = encodeTopic(deviceId, appTopic, isControl);\n        this.dataService.subscribe(fullTopic, qos);\n    }\n\n    @Override\n    public void controlSubscribe(String appTopic, int qos) throws KuraException {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        controlSubscribe(options.getTopicClientIdToken(), appTopic, qos);\n    }\n\n    @Override\n    public void controlSubscribe(String deviceId, String appTopic, int qos) throws KuraException {\n        boolean isControl = true;\n        String fullTopic = encodeTopic(deviceId, appTopic, isControl);\n        this.dataService.subscribe(fullTopic, qos);\n    }\n\n    @Override\n    public void unsubscribe(String appTopic) throws KuraException {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        unsubscribe(options.getTopicClientIdToken(), appTopic);\n    }\n\n    @Override\n    public void unsubscribe(String deviceId, String appTopic) throws KuraException {\n        boolean isControl = false;\n        String fullTopic = encodeTopic(deviceId, appTopic, isControl);\n        this.dataService.unsubscribe(fullTopic);\n    }\n\n    @Override\n    public void controlUnsubscribe(String appTopic) throws KuraException {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        controlUnsubscribe(options.getTopicClientIdToken(), appTopic);\n    }\n\n    @Override\n    public void controlUnsubscribe(String deviceId, String appTopic) throws KuraException {\n        boolean isControl = true;\n        String fullTopic = encodeTopic(deviceId, appTopic, isControl);\n        this.dataService.unsubscribe(fullTopic);\n    }\n\n    @Override\n    public List<Integer> getUnpublishedMessageIds() throws KuraException {\n        String topicRegex = getAppTopicRegex();\n        return this.dataService.getUnpublishedMessageIds(topicRegex);\n    }\n\n    @Override\n    public List<Integer> getInFlightMessageIds() throws KuraException {\n        String topicRegex = getAppTopicRegex();\n        return this.dataService.getInFlightMessageIds(topicRegex);\n    }\n\n    @Override\n    public List<Integer> getDroppedInFlightMessageIds() throws KuraException {\n        String topicRegex = getAppTopicRegex();\n        return this.dataService.getDroppedInFlightMessageIds(topicRegex);\n    }\n\n    // --------------------------------------------------------------------\n    //\n    // CloudCallbackHandler API\n    //\n    // --------------------------------------------------------------------\n\n    @Override\n    public void onMessageArrived(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain) {\n        for (CloudClientListener listener : this.listeners) {\n            listener.onMessageArrived(deviceId, appTopic, payload, qos, retain);\n        }\n    }\n\n    @Override\n    public void onControlMessageArrived(String deviceId, String appTopic, KuraPayload payload, int qos,\n            boolean retain) {\n        for (CloudClientListener listener : this.listeners) {\n            listener.onControlMessageArrived(deviceId, appTopic, payload, qos, retain);\n        }\n    }\n\n    @Override\n    public void onMessageConfirmed(int pubId, String appTopic) {\n        for (CloudClientListener listener : this.listeners) {\n            listener.onMessageConfirmed(pubId, appTopic);\n        }\n    }\n\n    @Override\n    public void onMessagePublished(int pubId, String appTopic) {\n        for (CloudClientListener listener : this.listeners) {\n            listener.onMessagePublished(pubId, appTopic);\n        }\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        for (CloudClientListener listener : this.listeners) {\n            listener.onConnectionEstablished();\n        }\n    }\n\n    @Override\n    public void onConnectionLost() {\n        for (CloudClientListener listener : this.listeners) {\n            listener.onConnectionLost();\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private methods\n    //\n    // ----------------------------------------------------------------\n\n    private String encodeTopic(String deviceId, String appTopic, boolean isControl) {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        StringBuilder sb = new StringBuilder();\n        if (isControl) {\n            sb.append(options.getTopicControlPrefix()).append(options.getTopicSeparator());\n        }\n\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator()).append(deviceId)\n                .append(options.getTopicSeparator()).append(this.applicationId);\n\n        if (appTopic != null && !appTopic.isEmpty()) {\n            sb.append(options.getTopicSeparator()).append(appTopic);\n        }\n\n        return sb.toString();\n    }\n\n    private String getAppTopicRegex() {\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        StringBuilder sb = new StringBuilder();\n\n        // String regexExample = \"^(\\\\$EDC/)?eurotech/.+/conf-v1(/.+)?\";\n\n        // Optional control prefix\n        sb.append(\"^(\")\n                // .append(options.getTopicControlPrefix())\n                .append(\"\\\\$EDC\").append(options.getTopicSeparator()).append(\")?\")\n\n                .append(options.getTopicAccountToken()).append(options.getTopicSeparator()).append(\".+\") // Any device\n                                                                                                         // ID\n                .append(options.getTopicSeparator()).append(this.applicationId).append(\"(/.+)?\");\n\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudClientListenerAdapter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport org.eclipse.kura.cloud.CloudClientListener;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Utility class to invoke CloudClientListeners catching and ignoring possible raised exceptions.\n */\npublic class CloudClientListenerAdapter implements CloudClientListener {\n\n    private static final String IGNORED_ERROR_NOTIFYING = \"IGNORED - Error notifying \";\n\n    private static final Logger s_logger = LoggerFactory.getLogger(CloudClientListenerAdapter.class);\n\n    private final CloudClientListener m_listener;\n\n    CloudClientListenerAdapter(CloudClientListener listener) {\n        this.m_listener = listener;\n    }\n\n    public CloudClientListener getCloudClientListenerAdapted() {\n        return this.m_listener;\n    }\n\n    @Override\n    public void onControlMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) {\n        try {\n            this.m_listener.onControlMessageArrived(deviceId, appTopic, msg, qos, retain);\n        } catch (Exception e) {\n            s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + \" for onControlMessageArrived\", e);\n        }\n    }\n\n    @Override\n    public void onMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) {\n        try {\n            this.m_listener.onMessageArrived(deviceId, appTopic, msg, qos, retain);\n        } catch (Exception e) {\n            s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + \" for onMessageArrived\", e);\n        }\n    }\n\n    @Override\n    public void onConnectionLost() {\n        try {\n            this.m_listener.onConnectionLost();\n        } catch (Exception e) {\n            s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + \" for onConnectionLost\", e);\n        }\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        try {\n            this.m_listener.onConnectionEstablished();\n        } catch (Exception e) {\n            s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + \" for onConnectionEstablished\", e);\n        }\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String appTopic) {\n        try {\n            this.m_listener.onMessageConfirmed(messageId, appTopic);\n        } catch (Exception e) {\n            s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + \" for onMessageConfirmed\", e);\n        }\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String appTopic) {\n        try {\n            this.m_listener.onMessagePublished(messageId, appTopic);\n        } catch (Exception e) {\n            s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + \" for onMessagePublished\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPayloadEncoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport java.io.IOException;\n\n/**\n * Common interface for the PayloadEncoders\n */\npublic interface CloudPayloadEncoder {\n\n    public byte[] getBytes() throws IOException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPayloadGZipEncoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport java.io.IOException;\n\nimport org.eclipse.kura.core.util.GZipUtil;\n\npublic class CloudPayloadGZipEncoder implements CloudPayloadEncoder {\n\n    private final CloudPayloadEncoder decorated;\n\n    public CloudPayloadGZipEncoder(CloudPayloadEncoder decorated) {\n        this.decorated = decorated;\n    }\n\n    @Override\n    public byte[] getBytes() throws IOException {\n        byte[] source = this.decorated.getBytes();\n        byte[] compressed = GZipUtil.compress(source);\n\n        // Return gzip compressed data only if shorter than uncompressed one\n        return compressed.length < source.length ? compressed : source;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPayloadProtoBufDecoderImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport java.io.IOException;\nimport java.util.Date;\n\nimport org.eclipse.kura.KuraInvalidMessageException;\nimport org.eclipse.kura.KuraInvalidMetricTypeException;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto;\nimport org.eclipse.kura.core.util.GZipUtil;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.protobuf.ByteString;\nimport com.google.protobuf.InvalidProtocolBufferException;\n\npublic class CloudPayloadProtoBufDecoderImpl {\n\n    private static final Logger s_logger = LoggerFactory.getLogger(CloudPayloadProtoBufDecoderImpl.class);\n\n    private byte[] m_bytes;\n\n    public CloudPayloadProtoBufDecoderImpl(byte[] bytes) {\n        this.m_bytes = bytes;\n    }\n\n    /**\n     * Factory method to build an KuraPayload instance from a byte array.\n     *\n     * @param bytes\n     * @return\n     * @throws InvalidProtocolBufferException\n     * @throws IOException\n     */\n    public KuraPayload buildFromByteArray() throws KuraInvalidMessageException, IOException {\n        // Check if a compressed payload and try to decompress it\n        if (GZipUtil.isCompressed(this.m_bytes)) {\n            try {\n                this.m_bytes = GZipUtil.decompress(this.m_bytes);\n            } catch (IOException e) {\n                s_logger.info(\"Decompression failed\");\n                // do not rethrow the exception here as isCompressed may return some false positives\n            }\n        }\n\n        // build the KuraPayloadProto.KuraPayload\n        KuraPayloadProto.KuraPayload protoMsg = null;\n        try {\n            protoMsg = KuraPayloadProto.KuraPayload.parseFrom(this.m_bytes);\n        } catch (InvalidProtocolBufferException ipbe) {\n            throw new KuraInvalidMessageException(ipbe);\n        }\n\n        // build the KuraPayload\n        KuraPayload kuraMsg = new KuraPayload();\n\n        // set the timestamp\n        if (protoMsg.hasTimestamp()) {\n            kuraMsg.setTimestamp(new Date(protoMsg.getTimestamp()));\n        }\n\n        // set the position\n        if (protoMsg.hasPosition()) {\n            kuraMsg.setPosition(buildFromProtoBuf(protoMsg.getPosition()));\n        }\n\n        // set the metrics\n        for (int i = 0; i < protoMsg.getMetricCount(); i++) {\n            String name = protoMsg.getMetric(i).getName();\n            try {\n                Object value = getProtoKuraMetricValue(protoMsg.getMetric(i), protoMsg.getMetric(i).getType());\n                kuraMsg.addMetric(name, value);\n            } catch (KuraInvalidMetricTypeException ihte) {\n                s_logger.warn(\"During deserialization, ignoring metric named: {}. Unrecognized value type: {}\", name,\n                        protoMsg.getMetric(i).getType(), ihte);\n            }\n        }\n\n        // set the body\n        if (protoMsg.hasBody()) {\n            kuraMsg.setBody(protoMsg.getBody().toByteArray());\n        }\n\n        return kuraMsg;\n    }\n\n    private KuraPosition buildFromProtoBuf(KuraPayloadProto.KuraPayload.KuraPosition protoPosition) {\n        KuraPosition position = new KuraPosition();\n\n        if (protoPosition.hasLatitude()) {\n            position.setLatitude(protoPosition.getLatitude());\n        }\n        if (protoPosition.hasLongitude()) {\n            position.setLongitude(protoPosition.getLongitude());\n        }\n        if (protoPosition.hasAltitude()) {\n            position.setAltitude(protoPosition.getAltitude());\n        }\n        if (protoPosition.hasPrecision()) {\n            position.setPrecision(protoPosition.getPrecision());\n        }\n        if (protoPosition.hasHeading()) {\n            position.setHeading(protoPosition.getHeading());\n        }\n        if (protoPosition.hasSpeed()) {\n            position.setSpeed(protoPosition.getSpeed());\n        }\n        if (protoPosition.hasSatellites()) {\n            position.setSatellites(protoPosition.getSatellites());\n        }\n        if (protoPosition.hasStatus()) {\n            position.setStatus(protoPosition.getStatus());\n        }\n        if (protoPosition.hasTimestamp()) {\n            position.setTimestamp(new Date(protoPosition.getTimestamp()));\n        }\n        return position;\n    }\n\n    private Object getProtoKuraMetricValue(KuraPayloadProto.KuraPayload.KuraMetric metric,\n            KuraPayloadProto.KuraPayload.KuraMetric.ValueType type) throws KuraInvalidMetricTypeException {\n        switch (type) {\n\n        case DOUBLE:\n            return metric.getDoubleValue();\n\n        case FLOAT:\n            return metric.getFloatValue();\n\n        case INT64:\n            return metric.getLongValue();\n\n        case INT32:\n            return metric.getIntValue();\n\n        case BOOL:\n            return metric.getBoolValue();\n\n        case STRING:\n            return metric.getStringValue();\n\n        case BYTES:\n            ByteString bs = metric.getBytesValue();\n            return bs.toByteArray();\n\n        default:\n            throw new KuraInvalidMetricTypeException(type);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPayloadProtoBufEncoderImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport java.io.IOException;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraInvalidMetricTypeException;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.protobuf.ByteString;\n\n/**\n * Encodes an KuraPayload class using the Google ProtoBuf binary format.\n */\npublic class CloudPayloadProtoBufEncoderImpl implements CloudPayloadEncoder {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudPayloadProtoBufEncoderImpl.class);\n\n    private final KuraPayload kuraPayload;\n\n    public CloudPayloadProtoBufEncoderImpl(KuraPayload kuraPayload) {\n        this.kuraPayload = kuraPayload;\n    }\n\n    /**\n     * Conversion method to serialize an KuraPayload instance into a byte array.\n     *\n     * @return\n     */\n    @Override\n    public byte[] getBytes() throws IOException {\n        // Build the message\n        KuraPayloadProto.KuraPayload.Builder protoMsg = KuraPayloadProto.KuraPayload.newBuilder();\n\n        // set the timestamp\n        if (this.kuraPayload.getTimestamp() != null) {\n            protoMsg.setTimestamp(this.kuraPayload.getTimestamp().getTime());\n        }\n\n        // set the position\n        if (this.kuraPayload.getPosition() != null) {\n            protoMsg.setPosition(buildPositionProtoBuf());\n        }\n\n        // set the metrics\n        for (final Map.Entry<String, Object> entry : this.kuraPayload.metrics().entrySet()) {\n            final String name = entry.getKey();\n            final Object value = entry.getValue();\n\n            // build a metric\n            try {\n                KuraMetric.Builder metricB = KuraMetric.newBuilder();\n                metricB.setName(name);\n\n                boolean result = setProtoKuraMetricValue(metricB, value);\n                if (result) {\n                    // add it to the message\n                    protoMsg.addMetric(metricB);\n                }\n            } catch (KuraInvalidMetricTypeException e) {\n                logger.error(\"During serialization, ignoring metric named: {}. Unrecognized value type: {}.\", name,\n                        value != null ? value.getClass().getName() : \"<null>\");\n                throw new RuntimeException(e);\n            }\n        }\n\n        // set the body\n        if (this.kuraPayload.getBody() != null) {\n            protoMsg.setBody(ByteString.copyFrom(this.kuraPayload.getBody()));\n        }\n\n        return protoMsg.build().toByteArray();\n    }\n\n    //\n    // Helper methods to convert the KuraMetrics\n    //\n    private KuraPayloadProto.KuraPayload.KuraPosition buildPositionProtoBuf() {\n        KuraPayloadProto.KuraPayload.KuraPosition.Builder protoPos = KuraPayloadProto.KuraPayload.KuraPosition\n                .newBuilder();\n\n        KuraPosition position = this.kuraPayload.getPosition();\n        if (position.getLatitude() != null) {\n            protoPos.setLatitude(position.getLatitude());\n        }\n        if (position.getLongitude() != null) {\n            protoPos.setLongitude(position.getLongitude());\n        }\n        if (position.getAltitude() != null) {\n            protoPos.setAltitude(position.getAltitude());\n        }\n        if (position.getPrecision() != null) {\n            protoPos.setPrecision(position.getPrecision());\n        }\n        if (position.getHeading() != null) {\n            protoPos.setHeading(position.getHeading());\n        }\n        if (position.getSpeed() != null) {\n            protoPos.setSpeed(position.getSpeed());\n        }\n        if (position.getTimestamp() != null) {\n            protoPos.setTimestamp(position.getTimestamp().getTime());\n        }\n        if (position.getSatellites() != null) {\n            protoPos.setSatellites(position.getSatellites());\n        }\n        if (position.getStatus() != null) {\n            protoPos.setStatus(position.getStatus());\n        }\n        return protoPos.build();\n    }\n\n    private static boolean setProtoKuraMetricValue(KuraPayloadProto.KuraPayload.KuraMetric.Builder metric, Object o)\n            throws KuraInvalidMetricTypeException {\n\n        if (o instanceof String) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.STRING);\n            metric.setStringValue((String) o);\n        } else if (o instanceof Double) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE);\n            metric.setDoubleValue((Double) o);\n        } else if (o instanceof Integer) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.INT32);\n            metric.setIntValue((Integer) o);\n        } else if (o instanceof Float) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.FLOAT);\n            metric.setFloatValue((Float) o);\n        } else if (o instanceof Long) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.INT64);\n            metric.setLongValue((Long) o);\n        } else if (o instanceof Boolean) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.BOOL);\n            metric.setBoolValue((Boolean) o);\n        } else if (o instanceof byte[]) {\n            metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.BYTES);\n            metric.setBytesValue(ByteString.copyFrom((byte[]) o));\n        } else if (o == null) {\n            logger.warn(\"Received a metric with a null value!\");\n            return false;\n        } else {\n            throw new KuraInvalidMetricTypeException(o.getClass().getName());\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPublisherDeliveryListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\n\npublic interface CloudPublisherDeliveryListener {\n    \n    public void onMessageConfirmed(String messageId, String topic);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport static java.util.Objects.isNull;\nimport static java.util.Objects.nonNull;\nimport static org.eclipse.kura.cloud.CloudPayloadEncoding.KURA_PROTOBUF;\nimport static org.eclipse.kura.cloud.CloudPayloadEncoding.SIMPLE_JSON;\nimport static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID;\nimport static org.eclipse.kura.core.message.MessageConstants.APP_ID;\nimport static org.eclipse.kura.core.message.MessageConstants.APP_TOPIC;\nimport static org.eclipse.kura.core.message.MessageConstants.CONTROL;\nimport static org.eclipse.kura.core.message.MessageConstants.FULL_TOPIC;\nimport static org.eclipse.kura.core.message.MessageConstants.PRIORITY;\nimport static org.eclipse.kura.core.message.MessageConstants.QOS;\nimport static org.eclipse.kura.core.message.MessageConstants.RETAIN;\nimport static org.osgi.framework.Constants.SERVICE_PID;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.Date;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraInvalidMessageException;\nimport org.eclipse.kura.certificate.CertificatesService;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloud.CloudConnectionEstablishedEvent;\nimport org.eclipse.kura.cloud.CloudConnectionLostEvent;\nimport org.eclipse.kura.cloud.CloudPayloadEncoding;\nimport org.eclipse.kura.cloud.CloudPayloadProtoBufDecoder;\nimport org.eclipse.kura.cloud.CloudPayloadProtoBufEncoder;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.cloud.publisher.NotificationPublisherImpl;\nimport org.eclipse.kura.core.cloud.subscriber.CloudSubscriptionRecord;\nimport org.eclipse.kura.core.data.DataServiceImpl;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.message.KuraApplicationTopic;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.net.NetworkService;\nimport org.eclipse.kura.net.status.NetworkInterfaceStatus;\nimport org.eclipse.kura.net.status.NetworkInterfaceType;\nimport org.eclipse.kura.net.status.NetworkStatusService;\nimport org.eclipse.kura.net.status.modem.ModemInterfaceStatus;\nimport org.eclipse.kura.net.status.modem.Sim;\nimport org.eclipse.kura.position.PositionLockedEvent;\nimport org.eclipse.kura.position.PositionService;\nimport org.eclipse.kura.security.tamper.detection.TamperDetectionService;\nimport org.eclipse.kura.security.tamper.detection.TamperEvent;\nimport org.eclipse.kura.system.SystemAdminService;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventAdmin;\nimport org.osgi.service.event.EventConstants;\nimport org.osgi.service.event.EventHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudServiceImpl\n        implements CloudService, DataServiceListener, ConfigurableComponent, EventHandler, CloudPayloadProtoBufEncoder,\n        CloudPayloadProtoBufDecoder, RequestHandlerRegistry, CloudConnectionManager, CloudEndpoint {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudServiceImpl.class);\n\n    private static final String TOPIC_BA_APP = \"BA\";\n    private static final String TOPIC_MQTT_APP = \"MQTT\";\n    private static final String CONNECTION_EVENT_PID_PROPERTY_KEY = \"cloud.service.pid\";\n    private static final String SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE = \"Cannot setup cloud service connection\";\n    private static final String NOTIFICATION_PUBLISHER_PID = \"org.eclipse.kura.cloud.publisher.CloudNotificationPublisher\";\n    private static final String KURA_PAYLOAD = \"KuraPayload\";\n    static final String EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL = \"org/osgi/service/deployment/INSTALL\";\n    static final String EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL = \"org/osgi/service/deployment/UNINSTALL\";\n\n    private static final int NUM_CONCURRENT_CALLBACKS = 2;\n\n    private static ExecutorService callbackExecutor = Executors.newFixedThreadPool(NUM_CONCURRENT_CALLBACKS);\n\n    private ComponentContext ctx;\n\n    private CloudServiceOptions options;\n\n    private DataService dataService;\n    private SystemService systemService;\n    private SystemAdminService systemAdminService;\n    private Optional<NetworkService> networkService = Optional.empty();\n    private Optional<PositionService> positionService = Optional.empty();\n    private EventAdmin eventAdmin;\n    private CertificatesService certificatesService;\n    private Unmarshaller jsonUnmarshaller;\n    private Marshaller jsonMarshaller;\n    private Optional<NetworkStatusService> networkStatusService = Optional.empty();\n\n    // use a synchronized implementation for the list\n    private final List<CloudClientImpl> cloudClients;\n    private final Set<CloudConnectionListener> registeredCloudConnectionListeners;\n    private final Set<CloudPublisherDeliveryListener> registeredCloudPublisherDeliveryListeners;\n    private final Set<CloudDeliveryListener> registeredCloudDeliveryListeners;\n    private final Map<CloudSubscriptionRecord, List<CloudSubscriberListener>> registeredSubscribers;\n\n    // package visibility for LyfeCyclePayloadBuilder\n    String imei;\n    String iccid;\n    String imsi;\n    String rssi;\n    String modemFwVer;\n\n    private boolean subscribed;\n\n    private final AtomicInteger messageId;\n\n    private ServiceRegistration<?> cloudServiceRegistration;\n\n    private final Map<String, RequestHandler> registeredRequestHandlers;\n\n    private ServiceRegistration<?> notificationPublisherRegistration;\n    private final CloudNotificationPublisher notificationPublisher;\n\n    private final Set<TamperDetectionService> tamperDetectionServices = new HashSet<>();\n\n    private String ownPid;\n\n    private ScheduledFuture<?> scheduledBirthPublisherFuture;\n    private final ScheduledExecutorService scheduledBirthPublisher = Executors.newSingleThreadScheduledExecutor();\n    private final AtomicBoolean shouldPublishDelayedBirth = new AtomicBoolean();\n\n    public CloudServiceImpl() {\n        this.cloudClients = new CopyOnWriteArrayList<>();\n        this.messageId = new AtomicInteger();\n        this.registeredRequestHandlers = new HashMap<>();\n        this.registeredSubscribers = new ConcurrentHashMap<>();\n        this.registeredCloudConnectionListeners = new CopyOnWriteArraySet<>();\n        this.registeredCloudPublisherDeliveryListeners = new CopyOnWriteArraySet<>();\n        this.registeredCloudDeliveryListeners = new CopyOnWriteArraySet<>();\n        this.notificationPublisher = new NotificationPublisherImpl(this);\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setDataService(DataService dataService) {\n        this.dataService = dataService;\n    }\n\n    public void unsetDataService(DataService dataService) {\n        if (this.dataService != null && this.dataService.equals(dataService)) {\n            this.dataService = null;\n        }\n    }\n\n    public DataService getDataService() {\n        return this.dataService;\n    }\n\n    public void setSystemAdminService(SystemAdminService systemAdminService) {\n        this.systemAdminService = systemAdminService;\n    }\n\n    public void unsetSystemAdminService(SystemAdminService systemAdminService) {\n        if (this.systemAdminService != null && this.systemAdminService.equals(systemAdminService)) {\n            this.systemAdminService = null;\n        }\n    }\n\n    public SystemAdminService getSystemAdminService() {\n        return this.systemAdminService;\n    }\n\n    public void setSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    public void unsetSystemService(SystemService systemService) {\n        if (this.systemService != null && this.systemService.equals(systemService)) {\n            this.systemService = null;\n        }\n    }\n\n    public SystemService getSystemService() {\n        return this.systemService;\n    }\n\n    public void setNetworkService(NetworkService networkService) {\n        this.networkService = Optional.of(networkService);\n    }\n\n    public void unsetNetworkService(NetworkService networkService) {\n        if (this.networkService.isPresent() && this.networkService.get().equals(networkService)) {\n            this.networkService = Optional.empty();\n        }\n    }\n\n    public Optional<NetworkService> getNetworkService() {\n        return this.networkService;\n    }\n\n    public void setPositionService(PositionService positionService) {\n        this.positionService = Optional.of(positionService);\n    }\n\n    public void unsetPositionService(PositionService positionService) {\n        if (this.positionService.isPresent() && this.positionService.get().equals(positionService)) {\n            this.positionService = Optional.empty();\n        }\n    }\n\n    public Optional<PositionService> getPositionService() {\n        return this.positionService;\n    }\n\n    public void setEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    public void unsetEventAdmin(EventAdmin eventAdmin) {\n        if (this.eventAdmin != null && this.eventAdmin.equals(eventAdmin)) {\n            this.eventAdmin = null;\n        }\n    }\n\n    public void setJsonUnmarshaller(Unmarshaller jsonUnmarshaller) {\n        this.jsonUnmarshaller = jsonUnmarshaller;\n    }\n\n    public void unsetJsonUnmarshaller(Unmarshaller jsonUnmarshaller) {\n        if (this.jsonUnmarshaller != null && this.jsonUnmarshaller.equals(jsonUnmarshaller)) {\n            this.jsonUnmarshaller = null;\n        }\n    }\n\n    public void setJsonMarshaller(Marshaller jsonMarshaller) {\n        this.jsonMarshaller = jsonMarshaller;\n    }\n\n    public void unsetJsonMarshaller(Marshaller jsonMarshaller) {\n        if (this.jsonMarshaller != null && this.jsonMarshaller.equals(jsonMarshaller)) {\n            this.jsonMarshaller = null;\n        }\n    }\n\n    public void setTamperDetectionService(final TamperDetectionService tamperDetectionService) {\n        synchronized (this.tamperDetectionServices) {\n            this.tamperDetectionServices.add(tamperDetectionService);\n        }\n    }\n\n    public void unsetTamperDetectionService(final TamperDetectionService tamperDetectionService) {\n        if (!this.tamperDetectionServices.isEmpty() && this.tamperDetectionServices.contains(tamperDetectionService)) {\n            synchronized (this.tamperDetectionServices) {\n                this.tamperDetectionServices.remove(tamperDetectionService);\n            }\n        }\n    }\n\n    public void setNetworkStatusService(NetworkStatusService networkStatusService) {\n        this.networkStatusService = Optional.of(networkStatusService);\n    }\n\n    public void unsetNetworkStatusService(NetworkStatusService networkStatusService) {\n        if (this.networkStatusService.isPresent() && this.networkStatusService.get().equals(networkStatusService)) {\n            this.networkStatusService = Optional.empty();\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        this.ownPid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n        logger.info(\"activate {}...\", this.ownPid);\n\n        //\n        // save the bundle context and the properties\n        this.ctx = componentContext;\n        this.options = new CloudServiceOptions(properties, this.systemService);\n        //\n        // install event listener for GPS locked event\n        Dictionary<String, Object> props = new Hashtable<>();\n        String[] eventTopics = { PositionLockedEvent.POSITION_LOCKED_EVENT_TOPIC, TamperEvent.TAMPER_EVENT_TOPIC,\n                EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL, EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL };\n        props.put(EventConstants.EVENT_TOPIC, eventTopics);\n        this.cloudServiceRegistration = this.ctx.getBundleContext().registerService(EventHandler.class.getName(), this,\n                props);\n\n        this.dataService.addDataServiceListener(this);\n\n        Dictionary<String, Object> notificationPublisherProps = new Hashtable<>();\n        notificationPublisherProps.put(KURA_SERVICE_PID, NOTIFICATION_PUBLISHER_PID);\n        notificationPublisherProps.put(SERVICE_PID, NOTIFICATION_PUBLISHER_PID);\n        this.notificationPublisherRegistration = this.ctx.getBundleContext().registerService(\n                CloudNotificationPublisher.class.getName(), this.notificationPublisher, notificationPublisherProps);\n\n        //\n        // Usually the cloud connection is setup in the\n        // onConnectionEstablished callback.\n        // Since the callback may be lost if we are activated\n        // too late (the DataService is already connected) we\n        // setup the cloud connection here.\n        if (isConnected()) {\n            logger.warn(\"DataService is already connected. Publish BIRTH certificate\");\n            try {\n                setupCloudConnection(true);\n            } catch (KuraException e) {\n                logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE, e);\n            }\n        }\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"updated {}...\", properties.get(ConfigurationService.KURA_SERVICE_PID));\n\n        // Update properties and re-publish Birth certificate\n        this.options = new CloudServiceOptions(properties, this.systemService);\n        if (isConnected()) {\n            try {\n                setupCloudConnection(false);\n            } catch (KuraException e) {\n                logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE);\n            }\n        }\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.info(\"deactivate {}...\", componentContext.getProperties().get(ConfigurationService.KURA_SERVICE_PID));\n\n        if (isConnected()) {\n            try {\n                publishDisconnectCertificate();\n            } catch (KuraException e) {\n                logger.warn(\"Cannot publish disconnect certificate\");\n            }\n        }\n\n        this.dataService.removeDataServiceListener(this);\n\n        // no need to release the cloud clients as the updated app\n        // certificate is already published due the missing dependency\n        // we only need to empty our CloudClient list\n        this.cloudClients.clear();\n\n        this.dataService = null;\n        this.systemService = null;\n        this.systemAdminService = null;\n        this.networkService = Optional.empty();\n        this.positionService = Optional.empty();\n        this.eventAdmin = null;\n        this.certificatesService = null;\n\n        this.cloudServiceRegistration.unregister();\n        this.notificationPublisherRegistration.unregister();\n    }\n\n    @Override\n    public void handleEvent(Event event) {\n        String topic = event.getTopic();\n\n        if (PositionLockedEvent.POSITION_LOCKED_EVENT_TOPIC.contains(topic)) {\n            handlePositionLockedEvent();\n            return;\n        }\n\n        if (TamperEvent.TAMPER_EVENT_TOPIC.equals(topic) && this.dataService.isConnected()\n                && this.options.getRepubBirthCertOnTamperEvent()) {\n            logger.debug(\"CloudServiceImpl: received tamper event, publishing BIRTH.\");\n            tryPublishBirthCertificate(false);\n            return;\n        }\n\n        if ((EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL.equals(topic) || EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL.equals(topic))\n                && this.dataService.isConnected()) {\n            logger.debug(\"CloudServiceImpl: received install/uninstall event, publishing BIRTH.\");\n            tryPublishBirthCertificate(false);\n        }\n    }\n\n    private void tryPublishBirthCertificate(boolean isNewConnection) {\n        try {\n            publishBirthCertificate(isNewConnection);\n        } catch (KuraException e) {\n            logger.warn(\"Cannot publish birth certificate\", e);\n        }\n    }\n\n    private void handlePositionLockedEvent() {\n        // if we get a position locked event,\n        // republish the birth certificate only if we are configured to\n        logger.info(\"Handling PositionLockedEvent\");\n        if (this.dataService.isConnected() && this.options.getRepubBirthCertOnGpsLock()) {\n            tryPublishBirthCertificate(false);\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public CloudClient newCloudClient(String applicationId) throws KuraException {\n        // create new instance\n        CloudClientImpl cloudClient = new CloudClientImpl(applicationId, this.dataService, this);\n        this.cloudClients.add(cloudClient);\n\n        // publish updated birth certificate with list of active apps\n        if (isConnected()) {\n            publishAppCertificate();\n        }\n\n        // return\n        return cloudClient;\n    }\n\n    @Override\n    public String[] getCloudApplicationIdentifiers() {\n        List<String> appIds = new ArrayList<>();\n        for (CloudClientImpl cloudClient : this.cloudClients) {\n            appIds.add(cloudClient.getApplicationId());\n        }\n\n        for (Entry<String, RequestHandler> entry : this.registeredRequestHandlers.entrySet()) {\n            appIds.add(entry.getKey());\n        }\n        return appIds.toArray(new String[0]);\n    }\n\n    @Override\n    public boolean isConnected() {\n        return this.dataService != null && this.dataService.isConnected();\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Package APIs\n    //\n    // ----------------------------------------------------------------\n\n    public CloudServiceOptions getCloudServiceOptions() {\n        return this.options;\n    }\n\n    public void removeCloudClient(CloudClientImpl cloudClient) {\n        // remove the client\n        this.cloudClients.remove(cloudClient);\n\n        // publish updated birth certificate with updated list of active apps\n        if (isConnected()) {\n            publishAppCertificate();\n        }\n    }\n\n    public byte[] encodePayload(KuraPayload payload) throws KuraException {\n        byte[] bytes;\n        CloudPayloadEncoding preferencesEncoding = this.options.getPayloadEncoding();\n\n        if (preferencesEncoding == KURA_PROTOBUF) {\n            bytes = encodeProtobufPayload(payload);\n        } else if (preferencesEncoding == SIMPLE_JSON) {\n            bytes = encodeJsonPayload(payload);\n        } else {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD);\n        }\n        return bytes;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // DataServiceListener API\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public void onConnectionEstablished() {\n        try {\n            setupCloudConnection(true);\n        } catch (KuraException e) {\n            logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE);\n        }\n\n        this.registeredSubscribers.keySet().forEach(this::subscribe);\n\n        postConnectionStateChangeEvent(true);\n\n        this.cloudClients.forEach(CloudClientImpl::onConnectionEstablished);\n\n        this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onConnectionEstablished);\n    }\n\n    private void setupDeviceSubscriptions(boolean subscribe) throws KuraException {\n        StringBuilder sbDeviceSubscription = new StringBuilder();\n        sbDeviceSubscription.append(this.options.getTopicControlPrefix())\n                .append(CloudServiceOptions.getTopicSeparator()).append(CloudServiceOptions.getTopicAccountToken())\n                .append(CloudServiceOptions.getTopicSeparator()).append(CloudServiceOptions.getTopicClientIdToken())\n                .append(CloudServiceOptions.getTopicSeparator()).append(CloudServiceOptions.getTopicWildCard());\n\n        // restore or remove default subscriptions\n        if (subscribe) {\n            this.dataService.subscribe(sbDeviceSubscription.toString(), 1);\n        } else {\n            this.dataService.unsubscribe(sbDeviceSubscription.toString());\n        }\n    }\n\n    @Override\n    public void onDisconnecting() {\n        // publish disconnect certificate\n        try {\n            publishDisconnectCertificate();\n        } catch (KuraException e) {\n            logger.warn(\"Cannot publish disconnect certificate\");\n        }\n    }\n\n    @Override\n    public void onDisconnected() {\n        // raise event\n        postConnectionStateChangeEvent(false);\n\n        this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onDisconnected);\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        // raise event\n        postConnectionStateChangeEvent(false);\n\n        this.cloudClients.forEach(CloudClientImpl::onConnectionLost);\n\n        this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onConnectionLost);\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n        logger.info(\"Message arrived on topic: {}\", topic);\n\n        // notify listeners\n        KuraTopicImpl kuraTopic = new KuraTopicImpl(topic, this.options.getTopicControlPrefix());\n        if (TOPIC_MQTT_APP.equals(kuraTopic.getApplicationId()) || TOPIC_BA_APP.equals(kuraTopic.getApplicationId())) {\n            logger.info(\"Ignoring feedback message from {}\", topic);\n        } else {\n            KuraPayload kuraPayload = encodeKuraPayload(topic, payload);\n\n            try {\n                if (this.options.getTopicControlPrefix().equals(kuraTopic.getPrefix())) {\n                    boolean validMessage = isValidMessage(kuraTopic, kuraPayload);\n\n                    if (validMessage) {\n                        dispatchControlMessage(qos, retained, kuraTopic, kuraPayload);\n                    } else {\n                        logger.warn(\"Message verification failed! Not valid signature or message not signed.\");\n                    }\n                } else {\n                    dispatchDataMessage(qos, retained, kuraTopic, kuraPayload);\n                }\n            } catch (Exception e) {\n                logger.error(\"Error during CloudClientListener notification.\", e);\n            }\n        }\n\n    }\n\n    private KuraPayload encodeKuraPayload(String topic, byte[] payload) {\n        KuraPayload kuraPayload = null;\n        if (this.options.getPayloadEncoding() == SIMPLE_JSON) {\n            try {\n                kuraPayload = createKuraPayloadFromJson(payload);\n            } catch (KuraException e) {\n                logger.warn(\"Error creating Kura Payload from Json\", e);\n            }\n        } else if (this.options.getPayloadEncoding() == KURA_PROTOBUF) {\n            kuraPayload = createKuraPayloadFromProtoBuf(topic, payload);\n        }\n        return kuraPayload;\n    }\n\n    private void dispatchControlMessage(int qos, boolean retained, KuraTopicImpl kuraTopic, KuraPayload kuraPayload) {\n        String applicationId = kuraTopic.getApplicationId();\n\n        RequestHandler cloudlet = this.registeredRequestHandlers.get(applicationId);\n        if (cloudlet != null) {\n            StringBuilder sb = new StringBuilder(applicationId).append(\"/\").append(\"REPLY\");\n\n            if (kuraTopic.getApplicationTopic().startsWith(sb.toString())) {\n                // Ignore replies\n                return;\n            }\n\n            callbackExecutor.submit(new MessageHandlerCallable(cloudlet, applicationId, kuraTopic.getApplicationTopic(),\n                    kuraPayload, this));\n        }\n        this.cloudClients.stream()\n                .filter(cloudClient -> cloudClient.getApplicationId().equals(kuraTopic.getApplicationId()))\n                .forEach(cloudClient -> cloudClient.onControlMessageArrived(kuraTopic.getDeviceId(),\n                        kuraTopic.getApplicationTopic(), kuraPayload, qos, retained));\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"deviceId\", kuraTopic.getDeviceId());\n        properties.put(\"appTopic\", kuraTopic.getApplicationTopic());\n\n        KuraMessage receivedMessage = new KuraMessage(kuraPayload, properties);\n\n        this.registeredSubscribers.entrySet().stream()\n                .filter(cloudSubscriberEntry -> cloudSubscriberEntry.getKey().matches(kuraTopic.getFullTopic()))\n                .forEach(e -> dispatchMessage(receivedMessage, e.getValue()));\n    }\n\n    private void dispatchDataMessage(int qos, boolean retained, KuraTopicImpl kuraTopic, KuraPayload kuraPayload) {\n        this.cloudClients.stream()\n                .filter(cloudClient -> cloudClient.getApplicationId().equals(kuraTopic.getApplicationId()))\n                .forEach(cloudClient -> cloudClient.onMessageArrived(kuraTopic.getDeviceId(),\n                        kuraTopic.getApplicationTopic(), kuraPayload, qos, retained));\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"deviceId\", kuraTopic.getDeviceId());\n        properties.put(\"appTopic\", kuraTopic.getApplicationTopic());\n\n        KuraMessage receivedMessage = new KuraMessage(kuraPayload, properties);\n\n        this.registeredSubscribers.entrySet().stream()\n                .filter(cloudSubscriberEntry -> cloudSubscriberEntry.getKey().matches(kuraTopic.getFullTopic()))\n                .forEach(e -> dispatchMessage(receivedMessage, e.getValue()));\n    }\n\n    private static void dispatchMessage(final KuraMessage message, final List<CloudSubscriberListener> listeners) {\n        for (final CloudSubscriberListener listener : listeners) {\n            try {\n                listener.onMessageArrived(message);\n            } catch (final Exception e) {\n                logger.warn(\"unhandled exception in CloudSubscriberListener\", e);\n            }\n        }\n    }\n\n    private boolean isValidMessage(KuraApplicationTopic kuraTopic, KuraPayload kuraPayload) {\n        if (this.certificatesService == null) {\n            ServiceReference<CertificatesService> sr = this.ctx.getBundleContext()\n                    .getServiceReference(CertificatesService.class);\n            if (sr != null) {\n                this.certificatesService = this.ctx.getBundleContext().getService(sr);\n            }\n        }\n        boolean validMessage = false;\n        if (this.certificatesService == null || this.certificatesService.verifySignature(kuraTopic, kuraPayload)) {\n            validMessage = true;\n        }\n        return validMessage;\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        synchronized (this.messageId) {\n            if (this.messageId.get() != -1 && this.messageId.get() == messageId) {\n                this.messageId.set(-1);\n                this.messageId.notifyAll();\n                return;\n            }\n        }\n\n        // notify listeners\n        KuraApplicationTopic kuraTopic = new KuraTopicImpl(topic, this.options.getTopicControlPrefix());\n        this.cloudClients.stream()\n                .filter(cloudClient -> cloudClient.getApplicationId().equals(kuraTopic.getApplicationId()))\n                .collect(Collectors.toList())\n                .forEach(cloudClient -> cloudClient.onMessagePublished(messageId, kuraTopic.getApplicationTopic()));\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        synchronized (this.messageId) {\n            if (this.messageId.get() != -1 && this.messageId.get() == messageId) {\n                this.messageId.set(-1);\n                this.messageId.notifyAll();\n                return;\n            }\n        }\n\n        // notify listeners\n        KuraApplicationTopic kuraTopic = new KuraTopicImpl(topic, this.options.getTopicControlPrefix());\n        this.cloudClients.stream()\n                .filter(cloudClient -> cloudClient.getApplicationId().equals(kuraTopic.getApplicationId()))\n                .collect(Collectors.toList())\n                .forEach(cloudClient -> cloudClient.onMessageConfirmed(messageId, kuraTopic.getApplicationTopic()));\n\n        this.registeredCloudPublisherDeliveryListeners\n                .forEach(deliveryListener -> deliveryListener.onMessageConfirmed(String.valueOf(messageId), topic));\n\n        this.registeredCloudDeliveryListeners\n                .forEach(deliveryListener -> deliveryListener.onMessageConfirmed(String.valueOf(messageId)));\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // CloudPayloadProtoBufEncoder API\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public byte[] getBytes(KuraPayload kuraPayload, boolean gzipped) throws KuraException {\n        CloudPayloadEncoder encoder = new CloudPayloadProtoBufEncoderImpl(kuraPayload);\n        if (gzipped) {\n            encoder = new CloudPayloadGZipEncoder(encoder);\n        }\n\n        byte[] bytes;\n        try {\n            bytes = encoder.getBytes();\n            return bytes;\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD, e);\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // CloudPayloadProtoBufDecoder API\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public KuraPayload buildFromByteArray(byte[] payload) throws KuraException {\n        CloudPayloadProtoBufDecoderImpl encoder = new CloudPayloadProtoBufDecoderImpl(payload);\n        KuraPayload kuraPayload;\n\n        try {\n            kuraPayload = encoder.buildFromByteArray();\n            return kuraPayload;\n        } catch (KuraInvalidMessageException | IOException e) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, KURA_PAYLOAD, e);\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Birth and Disconnect Certificates\n    //\n    // ----------------------------------------------------------------\n\n    private void setupCloudConnection(boolean isNewConnection) throws KuraException {\n        // assume we are not yet subscribed\n        if (isNewConnection) {\n            this.subscribed = false;\n        }\n\n        publishBirthCertificate(isNewConnection);\n\n        // restore or remove default subscriptions\n        if (this.options.getEnableDefaultSubscriptions()) {\n            if (!this.subscribed) {\n                setupDeviceSubscriptions(true);\n                this.subscribed = true;\n            }\n        } else {\n            logger.info(\"Default subscriptions are disabled in configuration\");\n            if (this.subscribed) {\n                setupDeviceSubscriptions(false);\n                this.subscribed = false;\n            }\n        }\n    }\n\n    private void publishBirthCertificate(boolean isNewConnection) throws KuraException {\n        if (isFrameworkStopping()) {\n            logger.info(\"framework is stopping.. not republishing birth certificate\");\n            return;\n        }\n\n        readModemProfile();\n\n        if (isNewConnection) {\n            publishLifeCycleMessage(new LifecycleMessage(this.options, this).asBirthCertificateMessage());\n        } else {\n            publishWithDelay(false);\n        }\n    }\n\n    private void publishDisconnectCertificate() throws KuraException {\n        publishLifeCycleMessage(new LifecycleMessage(this.options, this).asDisconnectCertificateMessage());\n    }\n\n    private void publishAppCertificate() {\n        if (isFrameworkStopping()) {\n            logger.info(\"framework is stopping.. not republishing app certificate\");\n            return;\n        }\n        publishWithDelay(true);\n    }\n\n    private void publishWithDelay(boolean isAppUpdate) {\n        synchronized (this.shouldPublishDelayedBirth) {\n            if (!isAppUpdate) {\n                this.shouldPublishDelayedBirth.set(true);\n            }\n\n            if (Objects.nonNull(this.scheduledBirthPublisherFuture)) {\n                this.scheduledBirthPublisherFuture.cancel(false);\n                logger.debug(\"CloudServiceImpl: BIRTH message cache timer restarted.\");\n            }\n\n            logger.debug(\"CloudServiceImpl: BIRTH message cached for 30s.\");\n\n            this.scheduledBirthPublisherFuture = this.scheduledBirthPublisher.schedule(this::publishDelayedMessage, 30L,\n                    TimeUnit.SECONDS);\n        }\n    }\n\n    private void publishLifeCycleMessage(LifecycleMessage message) throws KuraException {\n        // track the message ID and block until the message\n        // has been published (i.e. written to the socket).\n        synchronized (this.messageId) {\n            this.messageId.set(-1);\n            // add a timestamp to the message\n            KuraPayload payload = message.getPayload();\n            payload.setTimestamp(new Date());\n            byte[] encodedPayload = encodePayload(payload);\n            int id = this.dataService.publish(message.getTopic(), encodedPayload, message.getQos(),\n                    CloudServiceOptions.getLifeCycleMessageRetain(), CloudServiceOptions.getLifeCycleMessagePriority());\n            this.messageId.set(id);\n            try {\n                this.messageId.wait(1000);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                logger.info(\"Interrupted while waiting for the message to be published\", e);\n            }\n        }\n    }\n\n    private void publishDelayedMessage() {\n        synchronized (this.shouldPublishDelayedBirth) {\n            try {\n\n                if (this.shouldPublishDelayedBirth.get()) {\n                    publishLifeCycleMessage(new LifecycleMessage(this.options, this).asBirthCertificateMessage());\n                } else {\n                    publishLifeCycleMessage(new LifecycleMessage(this.options, this).asAppCertificateMessage());\n                }\n                this.shouldPublishDelayedBirth.set(false);\n\n            } catch (KuraException e) {\n                logger.error(\"Error sending cached BIRTH/APP certificate.\", e);\n            }\n        }\n    }\n\n    private byte[] encodeProtobufPayload(KuraPayload payload) throws KuraException {\n        byte[] bytes = new byte[0];\n        if (payload == null) {\n            return bytes;\n        }\n\n        CloudPayloadEncoder encoder = new CloudPayloadProtoBufEncoderImpl(payload);\n        if (this.options.getEncodeGzip()) {\n            encoder = new CloudPayloadGZipEncoder(encoder);\n        }\n\n        try {\n            bytes = encoder.getBytes();\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD, e);\n        }\n        return bytes;\n    }\n\n    private byte[] encodeJsonPayload(KuraPayload payload) throws KuraException {\n        return this.jsonMarshaller.marshal(payload).getBytes(StandardCharsets.UTF_8);\n    }\n\n    private KuraPayload createKuraPayloadFromJson(byte[] payload) throws KuraException {\n        return this.jsonUnmarshaller.unmarshal(new String(payload), KuraPayload.class);\n    }\n\n    private KuraPayload createKuraPayloadFromProtoBuf(String topic, byte[] payload) {\n        KuraPayload kuraPayload;\n        try {\n            // try to decode the message into an KuraPayload\n            kuraPayload = new CloudPayloadProtoBufDecoderImpl(payload).buildFromByteArray();\n        } catch (Exception e) {\n            // Wrap the received bytes payload into an KuraPayload\n            logger.debug(\"Received message on topic {} that could not be decoded. Wrapping it into an KuraPayload.\",\n                    topic);\n            kuraPayload = new KuraPayload();\n            kuraPayload.setBody(payload);\n        }\n        return kuraPayload;\n    }\n\n    private void postConnectionStateChangeEvent(final boolean isConnected) {\n\n        final Map<String, Object> eventProperties = Collections.singletonMap(CONNECTION_EVENT_PID_PROPERTY_KEY,\n                (String) this.ctx.getProperties().get(ConfigurationService.KURA_SERVICE_PID));\n\n        final Event event = isConnected ? new CloudConnectionEstablishedEvent(eventProperties)\n                : new CloudConnectionLostEvent(eventProperties);\n        this.eventAdmin.postEvent(event);\n    }\n\n    @Override\n    public void registerRequestHandler(String appId, RequestHandler requestHandler) {\n        this.registeredRequestHandlers.put(appId, requestHandler);\n\n        if (isConnected()) {\n            publishAppCertificate();\n        }\n    }\n\n    @Override\n    public void unregister(String appId) {\n        this.registeredRequestHandlers.remove(appId);\n\n        if (isConnected()) {\n            publishAppCertificate();\n        }\n    }\n\n    @Override\n    public void connect() throws KuraConnectException {\n        if (this.dataService != null) {\n            this.dataService.connect();\n        }\n    }\n\n    @Override\n    public void disconnect() {\n        if (this.dataService != null) {\n            this.dataService.disconnect(10);\n        }\n    }\n\n    @Override\n    public Map<String, String> getInfo() {\n        DataServiceImpl dataServiceImpl = (DataServiceImpl) this.dataService;\n        return dataServiceImpl.getConnectionInfo();\n    }\n\n    public String getNotificationPublisherPid() {\n        return NOTIFICATION_PUBLISHER_PID;\n    }\n\n    public CloudNotificationPublisher getNotificationPublisher() {\n        return this.notificationPublisher;\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.registeredCloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.registeredCloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    public void registerCloudPublisherDeliveryListener(CloudPublisherDeliveryListener cloudPublisherDeliveryListener) {\n        this.registeredCloudPublisherDeliveryListeners.add(cloudPublisherDeliveryListener);\n    }\n\n    public void unregisterCloudPublisherDeliveryListener(\n            CloudPublisherDeliveryListener cloudPublisherDeliveryListener) {\n        this.registeredCloudPublisherDeliveryListeners.remove(cloudPublisherDeliveryListener);\n    }\n\n    @Override\n    public String publish(KuraMessage message) throws KuraException {\n        Map<String, Object> messageProps = message.getProperties();\n        int qos = (Integer) messageProps.get(QOS.name());\n        boolean retain = (Boolean) messageProps.get(RETAIN.name());\n        int priority = (Integer) messageProps.get(PRIORITY.name());\n\n        String fullTopic = (String) messageProps.get(FULL_TOPIC.name());\n\n        if (isNull(fullTopic)) {\n            String appId = (String) messageProps.get(APP_ID.name());\n            String appTopic = (String) messageProps.get(APP_TOPIC.name());\n            boolean isControl = (Boolean) messageProps.get(CONTROL.name());\n\n            String deviceId = CloudServiceOptions.getTopicClientIdToken();\n\n            fullTopic = encodeTopic(appId, deviceId, appTopic, isControl);\n        }\n\n        byte[] appPayload = encodePayload(message.getPayload());\n\n        int id = this.dataService.publish(fullTopic, appPayload, qos, retain, priority);\n\n        if (qos == 0) {\n            return null;\n        }\n        return String.valueOf(id);\n    }\n\n    @Override\n    public void registerSubscriber(Map<String, Object> subscriptionProperties, CloudSubscriberListener subscriber) {\n        String appId = (String) subscriptionProperties.get(APP_ID.name());\n        String appTopic = (String) subscriptionProperties.get(APP_TOPIC.name());\n        int qos = (Integer) subscriptionProperties.get(QOS.name());\n        boolean isControl = (Boolean) subscriptionProperties.get(CONTROL.name());\n\n        if (isNull(appId) || isNull(appTopic)) {\n            return;\n        }\n\n        String fullTopic = encodeTopic(appId, CloudServiceOptions.getTopicClientIdToken(), appTopic, isControl);\n\n        CloudSubscriptionRecord subscriptionRecord = new CloudSubscriptionRecord(fullTopic, qos);\n\n        final List<CloudSubscriberListener> subscribers;\n\n        synchronized (this) {\n            subscribers = this.registeredSubscribers.compute(subscriptionRecord, (t, list) -> {\n                if (list == null) {\n                    return new CopyOnWriteArrayList<>(Collections.singletonList(subscriber));\n                }\n                list.add(subscriber);\n                return list;\n            });\n        }\n\n        if (subscribers.size() == 1) {\n            subscribe(subscriptionRecord);\n        }\n    }\n\n    @Override\n    public void unregisterSubscriber(CloudSubscriberListener subscriber) {\n\n        final List<CloudSubscriptionRecord> toUnsubscribe = new ArrayList<>();\n\n        synchronized (this) {\n            this.registeredSubscribers.entrySet().removeIf(e -> {\n                final List<CloudSubscriberListener> subscribers = e.getValue();\n\n                subscribers.removeIf(s -> s == subscriber);\n\n                if (subscribers.isEmpty()) {\n                    toUnsubscribe.add(e.getKey());\n                    return true;\n                } else {\n                    return false;\n                }\n            });\n        }\n\n        for (final CloudSubscriptionRecord subscription : toUnsubscribe) {\n            unsubscribe(subscription);\n        }\n    }\n\n    private synchronized void subscribe(CloudSubscriptionRecord subscriptionRecord) {\n        String fullTopic = subscriptionRecord.getTopic();\n\n        int qos = subscriptionRecord.getQos();\n\n        try {\n            this.dataService.subscribe(fullTopic, qos);\n        } catch (KuraException e) {\n            logger.info(\"Failed to subscribe\");\n        }\n    }\n\n    private synchronized void unsubscribe(CloudSubscriptionRecord subscriptionRecord) {\n        String fullTopic = subscriptionRecord.getTopic();\n\n        try {\n            this.dataService.unsubscribe(fullTopic);\n        } catch (KuraException e) {\n            logger.info(\"Failed to unsubscribe\");\n        }\n    }\n\n    private String encodeTopic(String appId, String deviceId, String appTopic, boolean isControl) {\n        StringBuilder sb = new StringBuilder();\n        if (isControl) {\n            sb.append(this.options.getTopicControlPrefix()).append(CloudServiceOptions.getTopicSeparator());\n        }\n\n        sb.append(CloudServiceOptions.getTopicAccountToken()).append(CloudServiceOptions.getTopicSeparator())\n                .append(deviceId).append(CloudServiceOptions.getTopicSeparator()).append(appId);\n\n        if (appTopic != null && !appTopic.isEmpty()) {\n            sb.append(CloudServiceOptions.getTopicSeparator()).append(appTopic);\n        }\n\n        return sb.toString();\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.registeredCloudDeliveryListeners.add(cloudDeliveryListener);\n\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.registeredCloudDeliveryListeners.remove(cloudDeliveryListener);\n    }\n\n    String getOwnPid() {\n        return this.ownPid;\n    }\n\n    void withTamperDetectionServices(final Consumer<Set<TamperDetectionService>> consumer) {\n        synchronized (this.tamperDetectionServices) {\n            consumer.accept(this.tamperDetectionServices);\n        }\n    }\n\n    private boolean isFrameworkStopping() {\n        try {\n            final Bundle ownBundle = FrameworkUtil.getBundle(CloudServiceImpl.class);\n\n            if (ownBundle == null) {\n                return false; // not running in an OSGi framework? e.g. unit test\n            }\n\n            return ownBundle.getBundleContext().getBundle(0).getState() == Bundle.STOPPING;\n        } catch (final Exception e) {\n            logger.warn(\"unexpected exception while checking if framework is shutting down\", e);\n            return false;\n        }\n    }\n\n    private void readModemProfile() {\n        this.networkStatusService.ifPresent(statusService -> {\n            List<ModemInterfaceStatus> modemStatuses = getModemsStatuses(statusService);\n            if (nonNull(modemStatuses) && !modemStatuses.isEmpty()) {\n                readModemInfos(modemStatuses);\n            } else {\n                this.imei = null;\n                this.iccid = null;\n                this.imsi = null;\n                this.rssi = null;\n                this.modemFwVer = null;\n            }\n        });\n    }\n\n    private List<ModemInterfaceStatus> getModemsStatuses(NetworkStatusService networkStatusService) {\n        List<ModemInterfaceStatus> modemStatuses = new ArrayList<>();\n        try {\n            List<String> interfaceIds = networkStatusService.getInterfaceIds();\n            for (String interfaceId : interfaceIds) {\n                Optional<NetworkInterfaceStatus> networkInterfaceStatus = networkStatusService\n                        .getNetworkStatus(interfaceId);\n                networkInterfaceStatus.ifPresent(state -> {\n                    NetworkInterfaceType type = state.getType();\n                    if (NetworkInterfaceType.MODEM.equals(type)) {\n                        modemStatuses.add((ModemInterfaceStatus) state);\n                    }\n                });\n            }\n        } catch (KuraException e) {\n            logger.error(\"Error reading modem profile\", e);\n        }\n        return modemStatuses;\n    }\n\n    private void readModemInfos(List<ModemInterfaceStatus> modemStatuses) {\n        Collections.sort(modemStatuses, Comparator.comparing(ModemInterfaceStatus::getConnectionStatus));\n        ModemInterfaceStatus modemStatus = modemStatuses.get(modemStatuses.size() - 1);\n        Optional<Sim> activeSim = Optional.empty();\n\n        List<Sim> availableSims = modemStatus.getAvailableSims();\n        for (Sim sim : availableSims) {\n            if (sim.isActive() && sim.isPrimary()) {\n                activeSim = Optional.of(sim);\n            }\n        }\n\n        this.iccid = null;\n        this.imsi = null;\n        activeSim.ifPresent(sim -> {\n            this.iccid = sim.getIccid();\n            this.imsi = sim.getImsi();\n        });\n        this.imei = modemStatus.getSerialNumber();\n        this.rssi = String.valueOf(modemStatus.getSignalStrength());\n        this.modemFwVer = modemStatus.getFirmwareVersion();\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.cloud.CloudPayloadEncoding;\nimport org.eclipse.kura.system.SystemService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudServiceOptions {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudServiceOptions.class);\n\n    private static final String TOPIC_SEPARATOR = \"/\";\n    private static final String TOPIC_ACCOUNT_TOKEN = \"#account-name\";\n    private static final String TOPIC_CLIENT_ID_TOKEN = \"#client-id\";\n    private static final String TOPIC_BIRTH_SUFFIX = \"MQTT/BIRTH\";\n    private static final String TOPIC_DISCONNECT_SUFFIX = \"MQTT/DC\";\n    private static final String TOPIC_APPS_SUFFIX = \"MQTT/APPS\";\n    private static final String TOPIC_CONTROL_PREFIX = \"topic.control-prefix\";\n    private static final String TOPIC_CONTROL_PREFIX_DEFAULT = \"$EDC\";\n    private static final String TOPIC_WILD_CARD = \"#\";\n\n    private static final String DEVICE_DISPLAY_NAME = \"device.display-name\";\n    private static final String DEVICE_CUSTOM_NAME = \"device.custom-name\";\n    private static final String ENCODE_GZIP = \"encode.gzip\";\n    private static final String REPUB_BIRTH_ON_GPS_LOCK = \"republish.mqtt.birth.cert.on.gps.lock\";\n    private static final String REPUB_BIRTH_ON_TAMPER_EVENT = \"republish.mqtt.birth.cert.on.tamper.event\";\n    private static final String ENABLE_DFLT_SUBSCRIPTIONS = \"enable.default.subscriptions\";\n    private static final String PAYLOAD_ENCODING = \"payload.encoding\";\n\n    private static final int LIFECYCLE_PRIORITY = 0;\n    private static final boolean LIFECYCLE_RETAIN = false;\n\n    private final Map<String, Object> properties;\n    private final SystemService systemService;\n\n    public CloudServiceOptions(Map<String, Object> properties, SystemService systemService) {\n        this.properties = properties;\n        this.systemService = systemService;\n    }\n\n    /**\n     * Returns the display name for the device.\n     *\n     * @return a String value.\n     */\n    public String getDeviceDisplayName() {\n        String displayName = \"\";\n        if (this.properties == null) {\n            return displayName;\n        }\n        String deviceDisplayNameOption = (String) this.properties.get(DEVICE_DISPLAY_NAME);\n\n        // Use the device name from SystemService. This should be kura.device.name from\n        // the properties file.\n        if (\"device-name\".equals(deviceDisplayNameOption)) {\n            displayName = this.systemService.getDeviceName();\n        }\n        // Try to get the device hostname\n        else if (\"hostname\".equals(deviceDisplayNameOption)) {\n            displayName = this.systemService.getHostname();\n        }\n        // Return the custom field defined by the user\n        else if (\"custom\".equals(deviceDisplayNameOption)\n                && this.properties.get(DEVICE_CUSTOM_NAME) instanceof String) {\n            displayName = (String) this.properties.get(DEVICE_CUSTOM_NAME);\n        }\n        // Return empty string to the server\n        else if (\"server\".equals(deviceDisplayNameOption)) {\n            displayName = \"\";\n        }\n\n        return displayName;\n    }\n\n    /**\n     * Returns true if the current CloudService configuration\n     * specifies Gzip compression enabled for outgoing payloads.\n     *\n     * @return a boolean value.\n     */\n    public boolean getEncodeGzip() {\n        boolean encodeGzip = false;\n        if (this.properties != null && this.properties.get(ENCODE_GZIP) instanceof Boolean) {\n            encodeGzip = (Boolean) this.properties.get(ENCODE_GZIP);\n        }\n        return encodeGzip;\n    }\n\n    /**\n     * Returns true if the current CloudService configuration\n     * specifies the cloud client should republish the MQTT birth\n     * certificate on GPS lock events.\n     *\n     * @return a boolean value.\n     */\n    public boolean getRepubBirthCertOnGpsLock() {\n        boolean repubBirth = false;\n        if (this.properties != null && this.properties.get(REPUB_BIRTH_ON_GPS_LOCK) instanceof Boolean) {\n            repubBirth = (Boolean) this.properties.get(REPUB_BIRTH_ON_GPS_LOCK);\n        }\n        return repubBirth;\n    }\n\n    public boolean getRepubBirthCertOnTamperEvent() {\n        boolean repubBirth = true;\n        if (this.properties != null && this.properties.get(REPUB_BIRTH_ON_TAMPER_EVENT) instanceof Boolean) {\n            repubBirth = (Boolean) this.properties.get(REPUB_BIRTH_ON_TAMPER_EVENT);\n        }\n        return repubBirth;\n    }\n\n    /**\n     * Returns the prefix to be used when publishing messages to control topics.\n     *\n     * @return a String value.\n     */\n    public String getTopicControlPrefix() {\n        String prefix = TOPIC_CONTROL_PREFIX_DEFAULT;\n        if (this.properties != null && this.properties.get(TOPIC_CONTROL_PREFIX) instanceof String) {\n            prefix = (String) this.properties.get(TOPIC_CONTROL_PREFIX);\n        }\n        return prefix;\n    }\n\n    /**\n     * Returns true if the current CloudService configuration\n     * specifies that the cloud client should perform default subscriptions.\n     *\n     * @return a boolean value.\n     */\n    public boolean getEnableDefaultSubscriptions() {\n        boolean enable = true;\n        if (this.properties != null && this.properties.get(ENABLE_DFLT_SUBSCRIPTIONS) instanceof Boolean) {\n            enable = (Boolean) this.properties.get(ENABLE_DFLT_SUBSCRIPTIONS);\n        }\n        return enable;\n    }\n\n    /**\n     * This method parses the Cloud Service configuration and returns the selected cloud payload encoding.\n     * By default, this method returns {@link CloudPayloadEncoding} {@code KURA_PROTOBUF}.\n     *\n     * @return a boolean value.\n     */\n    public CloudPayloadEncoding getPayloadEncoding() {\n        CloudPayloadEncoding result = CloudPayloadEncoding.KURA_PROTOBUF;\n        String encodingString = \"\";\n        if (this.properties != null && this.properties.get(PAYLOAD_ENCODING) != null\n                && this.properties.get(PAYLOAD_ENCODING) instanceof String) {\n            encodingString = (String) this.properties.get(PAYLOAD_ENCODING);\n        }\n        try {\n            result = CloudPayloadEncoding.getEncoding(encodingString);\n        } catch (IllegalArgumentException e) {\n            logger.warn(\"Cannot parse the provided payload encoding.\", e);\n        }\n\n        return result;\n    }\n\n    public static String getTopicSeparator() {\n        return TOPIC_SEPARATOR;\n    }\n\n    public static String getTopicAccountToken() {\n        return TOPIC_ACCOUNT_TOKEN;\n    }\n\n    public static String getTopicClientIdToken() {\n        return TOPIC_CLIENT_ID_TOKEN;\n    }\n\n    public static String getTopicBirthSuffix() {\n        return TOPIC_BIRTH_SUFFIX;\n    }\n\n    public static String getTopicDisconnectSuffix() {\n        return TOPIC_DISCONNECT_SUFFIX;\n    }\n\n    public static String getTopicAppsSuffix() {\n        return TOPIC_APPS_SUFFIX;\n    }\n\n    public static String getTopicWildCard() {\n        return TOPIC_WILD_CARD;\n    }\n\n    public static int getLifeCycleMessagePriority() {\n        return LIFECYCLE_PRIORITY;\n    }\n\n    public static boolean getLifeCycleMessageRetain() {\n        return LIFECYCLE_RETAIN;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/KuraTopicImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.message.KuraApplicationTopic;\n\n/**\n * Models a topic for messages posted to the Kura platform.\n * Topics are expected to be in the form of \"account/asset/&lt;application_specific&gt;\";\n * The system control topic prefix is defined in the {@link CloudService} and defaults\n * to $EDC.\n *\n */\npublic class KuraTopicImpl extends KuraApplicationTopic {\n\n    private String fullTopic;\n    private String[] topicParts;\n    private String prefix;\n    private String accountName;\n    private String deviceId;\n\n    public KuraTopicImpl(String fullTopic) {\n        this(fullTopic, \"$\");\n    }\n\n    public KuraTopicImpl(String fullTopic, String controlPrefix) {\n        this.fullTopic = fullTopic;\n        if (fullTopic.compareTo(\"#\") == 0) {\n            return;\n        }\n\n        this.topicParts = fullTopic.split(\"/\");\n        if (this.topicParts.length == 0) {\n            return;\n        }\n\n        // prefix\n        int index = 0;\n        int offset = 0; // skip a slash\n        if (this.topicParts[0].startsWith(controlPrefix)) {\n            this.prefix = this.topicParts[index];\n            offset += this.prefix.length() + 1;\n            index++;\n        }\n\n        // account name\n        if (index < this.topicParts.length) {\n            this.accountName = this.topicParts[index];\n            offset += this.accountName.length() + 1;\n            index++;\n        }\n\n        // deviceId\n        if (index < this.topicParts.length) {\n            this.deviceId = this.topicParts[index];\n            offset += this.deviceId.length() + 1;\n            index++;\n        }\n\n        // applicationId\n        if (index < this.topicParts.length) {\n            this.applicationId = this.topicParts[index];\n            offset += this.applicationId.length() + 1;\n            index++;\n        }\n\n        // applicationTopic\n        if (offset < this.fullTopic.length()) {\n            this.applicationTopic = this.fullTopic.substring(offset);\n        }\n    }\n\n    public String getFullTopic() {\n        return this.fullTopic;\n    }\n\n    public String[] getTopicParts() {\n        return this.topicParts;\n    }\n\n    public String getPrefix() {\n        return this.prefix;\n    }\n\n    public String getAccountName() {\n        return this.accountName;\n    }\n\n    public String getDeviceId() {\n        return this.deviceId;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/LifeCyclePayloadBuilder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport java.util.List;\nimport java.util.Map.Entry;\nimport java.util.Optional;\n\nimport org.eclipse.kura.core.util.NetUtil;\nimport org.eclipse.kura.message.KuraBirthPayload;\nimport org.eclipse.kura.message.KuraBirthPayload.KuraBirthPayloadBuilder;\nimport org.eclipse.kura.message.KuraBirthPayload.TamperStatus;\nimport org.eclipse.kura.message.KuraDeviceProfile;\nimport org.eclipse.kura.message.KuraDisconnectPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.eclipse.kura.net.NetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.eclipse.kura.net.NetworkService;\nimport org.eclipse.kura.position.PositionService;\nimport org.eclipse.kura.security.tamper.detection.TamperDetectionService;\nimport org.eclipse.kura.system.ExtendedProperties;\nimport org.eclipse.kura.system.ExtendedPropertyGroup;\nimport org.eclipse.kura.system.SystemAdminService;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.util.position.Position;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.eclipsesource.json.JsonObject;\n\n/**\n * Utility class to build lifecycle payload messages.\n */\npublic class LifeCyclePayloadBuilder {\n\n    private static final String EXTENDED_PROPERTIES_KEY = \"extended_properties\";\n\n    private static final String ERROR = \"ERROR\";\n\n    private static final Logger logger = LoggerFactory.getLogger(LifeCyclePayloadBuilder.class);\n\n    private static final String UNKNOWN = \"UNKNOWN\";\n\n    private final CloudServiceImpl cloudServiceImpl;\n\n    LifeCyclePayloadBuilder(CloudServiceImpl cloudServiceImpl) {\n        this.cloudServiceImpl = cloudServiceImpl;\n    }\n\n    public KuraBirthPayload buildBirthPayload() {\n        // build device profile\n        KuraDeviceProfile deviceProfile = buildDeviceProfile();\n\n        // build application IDs\n        String appIds = buildApplicationIDs();\n\n        // build accept encoding\n        String acceptEncoding = buildAcceptEncoding();\n\n        // build device name\n        CloudServiceOptions cso = this.cloudServiceImpl.getCloudServiceOptions();\n        String deviceName = cso.getDeviceDisplayName();\n        if (deviceName == null) {\n            deviceName = this.cloudServiceImpl.getSystemService().getDeviceName();\n        }\n\n        String payloadEncoding = this.cloudServiceImpl.getCloudServiceOptions().getPayloadEncoding().name();\n\n        // build birth certificate\n        KuraBirthPayloadBuilder birthPayloadBuilder = new KuraBirthPayloadBuilder();\n        birthPayloadBuilder.withUptime(deviceProfile.getUptime()).withDisplayName(deviceName)\n                .withModelName(deviceProfile.getModelName()).withModelId(deviceProfile.getModelId())\n                .withPartNumber(deviceProfile.getPartNumber()).withSerialNumber(deviceProfile.getSerialNumber())\n                .withFirmwareVersion(deviceProfile.getFirmwareVersion()).withBiosVersion(deviceProfile.getBiosVersion())\n                .withCpuVersion(deviceProfile.getCpuVersion()).withOs(deviceProfile.getOs())\n                .withOsVersion(deviceProfile.getOsVersion()).withJvmName(deviceProfile.getJvmName())\n                .withJvmVersion(deviceProfile.getJvmVersion()).withJvmProfile(deviceProfile.getJvmProfile())\n                .withKuraVersion(deviceProfile.getApplicationFrameworkVersion())\n                .withConnectionInterface(deviceProfile.getConnectionInterface())\n                .withConnectionIp(deviceProfile.getConnectionIp()).withAcceptEncoding(acceptEncoding)\n                .withApplicationIdentifiers(appIds).withAvailableProcessors(deviceProfile.getAvailableProcessors())\n                .withTotalMemory(deviceProfile.getTotalMemory()).withOsArch(deviceProfile.getOsArch())\n                .withOsgiFramework(deviceProfile.getOsgiFramework())\n                .withOsgiFrameworkVersion(deviceProfile.getOsgiFrameworkVersion()).withPayloadEncoding(payloadEncoding)\n                .withJvmVendor(deviceProfile.getJvmVendor()).withJdkVendorVersion(deviceProfile.getJdkVendorVersion());\n\n        tryAddTamperStatus(birthPayloadBuilder);\n\n        if (this.cloudServiceImpl.imei != null && this.cloudServiceImpl.imei.length() > 0\n                && !this.cloudServiceImpl.imei.equals(ERROR)) {\n            birthPayloadBuilder.withModemImei(this.cloudServiceImpl.imei);\n        }\n        if (this.cloudServiceImpl.iccid != null && this.cloudServiceImpl.iccid.length() > 0\n                && !this.cloudServiceImpl.iccid.equals(ERROR)) {\n            birthPayloadBuilder.withModemIccid(this.cloudServiceImpl.iccid);\n        }\n\n        if (this.cloudServiceImpl.imsi != null && this.cloudServiceImpl.imsi.length() > 0\n                && !this.cloudServiceImpl.imsi.equals(ERROR)) {\n            birthPayloadBuilder.withModemImsi(this.cloudServiceImpl.imsi);\n        }\n\n        if (this.cloudServiceImpl.rssi != null && this.cloudServiceImpl.rssi.length() > 0) {\n            birthPayloadBuilder.withModemRssi(this.cloudServiceImpl.rssi);\n        }\n\n        if (this.cloudServiceImpl.modemFwVer != null && this.cloudServiceImpl.modemFwVer.length() > 0\n                && !this.cloudServiceImpl.modemFwVer.equals(ERROR)) {\n            birthPayloadBuilder.withModemFirmwareVersion(this.cloudServiceImpl.modemFwVer);\n        }\n\n        if (deviceProfile.getLatitude() != null && deviceProfile.getLongitude() != null) {\n            KuraPosition kuraPosition = new KuraPosition();\n            kuraPosition.setLatitude(deviceProfile.getLatitude());\n            kuraPosition.setLongitude(deviceProfile.getLongitude());\n            kuraPosition.setAltitude(deviceProfile.getAltitude());\n            birthPayloadBuilder.withPosition(kuraPosition);\n        }\n\n        final KuraBirthPayload result = birthPayloadBuilder.build();\n\n        try {\n            final Optional<String> extendedProperties = serializeExtendedProperties();\n\n            if (extendedProperties.isPresent()) {\n                result.addMetric(EXTENDED_PROPERTIES_KEY, extendedProperties.get());\n            }\n        } catch (final Exception e) {\n            logger.warn(\"failed to get extended properties\", e);\n        }\n\n        return result;\n    }\n\n    private void tryAddTamperStatus(KuraBirthPayloadBuilder birthPayloadBuilder) {\n        this.cloudServiceImpl.withTamperDetectionServices(t -> {\n            if (t.isEmpty()) {\n                return;\n            }\n\n            boolean isDeviceTampered = false;\n\n            for (final TamperDetectionService tamperDetectionService : t) {\n                if (isDeviceTampered) {\n                    break;\n                }\n\n                try {\n                    isDeviceTampered = tamperDetectionService.getTamperStatus().isDeviceTampered();\n                } catch (final Exception e) {\n                    logger.warn(\"failed to obtain tamper status\", e);\n                }\n            }\n\n            birthPayloadBuilder.withTamperStatus(isDeviceTampered ? TamperStatus.TAMPERED : TamperStatus.NOT_TAMPERED);\n        });\n    }\n\n    public KuraDisconnectPayload buildDisconnectPayload() {\n        SystemService systemService = this.cloudServiceImpl.getSystemService();\n        SystemAdminService sysAdminService = this.cloudServiceImpl.getSystemAdminService();\n        CloudServiceOptions cloudOptions = this.cloudServiceImpl.getCloudServiceOptions();\n\n        // build device name\n        String deviceName = cloudOptions.getDeviceDisplayName();\n        if (deviceName == null) {\n            deviceName = systemService.getDeviceName();\n        }\n\n        return new KuraDisconnectPayload(sysAdminService.getUptime(), deviceName);\n    }\n\n    public KuraDeviceProfile buildDeviceProfile() {\n        SystemService systemService = this.cloudServiceImpl.getSystemService();\n        SystemAdminService sysAdminService = this.cloudServiceImpl.getSystemAdminService();\n        Optional<NetworkService> networkService = this.cloudServiceImpl.getNetworkService();\n        Optional<PositionService> positionService = this.cloudServiceImpl.getPositionService();\n\n        //\n        // get the network information if available\n        StringBuilder sbConnectionIp = new StringBuilder();\n        StringBuilder sbConnectionInterface = new StringBuilder();\n        networkService.ifPresent(ns -> {\n            try {\n                List<NetInterface<? extends NetInterfaceAddress>> nis = ns.getActiveNetworkInterfaces();\n                if (!nis.isEmpty()) {\n                    for (NetInterface<? extends NetInterfaceAddress> ni : nis) {\n                        List<? extends NetInterfaceAddress> nias = ni.getNetInterfaceAddresses();\n                        if (nias != null && !nias.isEmpty()) {\n                            sbConnectionInterface.append(buildConnectionInterface(ni)).append(\",\");\n                            sbConnectionIp.append(buildConnectionIp(ni)).append(\",\");\n                        }\n                    }\n\n                    // Remove trailing comma\n                    sbConnectionIp.deleteCharAt(sbConnectionIp.length() - 1);\n                    sbConnectionInterface.deleteCharAt(sbConnectionInterface.length() - 1);\n                }\n            } catch (Exception se) {\n                logger.warn(\"Error while getting ConnectionIP and ConnectionInterface\", se);\n            }\n        });\n\n        String connectionIp = !sbConnectionIp.isEmpty() ? sbConnectionIp.toString() : UNKNOWN;\n        String connectionInterface = !sbConnectionInterface.isEmpty() ? sbConnectionInterface.toString() : UNKNOWN;\n\n        //\n        // get the position information\n        double latitude = 0.0;\n        double longitude = 0.0;\n        double altitude = 0.0;\n        if (positionService.isPresent()) {\n            Position position = positionService.get().getPosition();\n            if (position != null) {\n                latitude = Math.toDegrees(position.getLatitude().getValue());\n                longitude = Math.toDegrees(position.getLongitude().getValue());\n                altitude = position.getAltitude().getValue();\n            } else {\n                logger.warn(\"Unresolved PositionService reference.\");\n            }\n        }\n\n        return buildKuraDeviceProfile(systemService, sysAdminService, connectionIp, connectionInterface, latitude,\n                longitude, altitude);\n    }\n\n    private KuraDeviceProfile buildKuraDeviceProfile(SystemService systemService, SystemAdminService sysAdminService,\n            String connectionIp, String connectionInterface, double latitude, double longitude, double altitude) {\n        KuraDeviceProfile kuraDeviceProfile = new KuraDeviceProfile();\n        kuraDeviceProfile.setUptime(sysAdminService.getUptime());\n        kuraDeviceProfile.setDisplayName(systemService.getDeviceName());\n        kuraDeviceProfile.setModelName(systemService.getModelName());\n        kuraDeviceProfile.setModelId(systemService.getModelId());\n        kuraDeviceProfile.setPartNumber(systemService.getPartNumber());\n        kuraDeviceProfile.setSerialNumber(systemService.getSerialNumber());\n        kuraDeviceProfile.setFirmwareVersion(systemService.getFirmwareVersion());\n        kuraDeviceProfile.setCpuVersion(systemService.getCpuVersion());\n        kuraDeviceProfile.setBiosVersion(systemService.getBiosVersion());\n        kuraDeviceProfile.setOs(systemService.getOsName());\n        kuraDeviceProfile.setOsVersion(systemService.getOsVersion());\n        kuraDeviceProfile.setJvmName(systemService.getJavaVmName());\n        kuraDeviceProfile.setJvmVersion(systemService.getJavaVmVersion() + \" \" + systemService.getJavaVmInfo());\n        kuraDeviceProfile.setJvmProfile(systemService.getJavaVendor() + \" \" + systemService.getJavaVersion());\n        kuraDeviceProfile.setApplicationFramework(KuraDeviceProfile.DEFAULT_APPLICATION_FRAMEWORK);\n        kuraDeviceProfile.setApplicationFrameworkVersion(systemService.getKuraVersion());\n        kuraDeviceProfile.setConnectionInterface(connectionInterface);\n        kuraDeviceProfile.setConnectionIp(connectionIp);\n        kuraDeviceProfile.setLatitude(latitude);\n        kuraDeviceProfile.setLongitude(longitude);\n        kuraDeviceProfile.setAltitude(altitude);\n        kuraDeviceProfile.setAvailableProcessors(String.valueOf(systemService.getNumberOfProcessors()));\n        kuraDeviceProfile.setTotalMemory(String.valueOf(systemService.getTotalMemory()));\n        kuraDeviceProfile.setOsArch(systemService.getOsArch());\n        kuraDeviceProfile.setOsgiFramework(systemService.getOsgiFwName());\n        kuraDeviceProfile.setOsgiFrameworkVersion(systemService.getOsgiFwVersion());\n        kuraDeviceProfile.setJvmVendor(systemService.getJavaVmVendor());\n        kuraDeviceProfile.setJdkVendorVersion(systemService.getJdkVendorVersion());\n        return kuraDeviceProfile;\n    }\n\n    private String buildConnectionIp(NetInterface<? extends NetInterfaceAddress> ni) {\n        String connectionIp = UNKNOWN;\n        List<? extends NetInterfaceAddress> nias = ni.getNetInterfaceAddresses();\n        if (nias != null && !nias.isEmpty() && nias.get(0).getAddress() != null) {\n            connectionIp = nias.get(0).getAddress().getHostAddress();\n        }\n        return connectionIp;\n    }\n\n    private String buildConnectionInterface(NetInterface<? extends NetInterfaceAddress> ni) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(ni.getName()).append(\" (\").append(NetUtil.hardwareAddressToString(ni.getHardwareAddress()))\n                .append(\")\");\n        return sb.toString();\n    }\n\n    private String buildApplicationIDs() {\n        String[] appIdArray = this.cloudServiceImpl.getCloudApplicationIdentifiers();\n        StringBuilder sbAppIDs = new StringBuilder();\n        for (int i = 0; i < appIdArray.length; i++) {\n            if (i != 0) {\n                sbAppIDs.append(\",\");\n            }\n            sbAppIDs.append(appIdArray[i]);\n        }\n        return sbAppIDs.toString();\n    }\n\n    private String buildAcceptEncoding() {\n        String acceptEncoding = \"\";\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        if (options.getEncodeGzip()) {\n            acceptEncoding = \"gzip\";\n        }\n        return acceptEncoding;\n    }\n\n    private Optional<String> serializeExtendedProperties() {\n        final Optional<ExtendedProperties> extendedProperties = this.cloudServiceImpl.getSystemService()\n                .getExtendedProperties();\n\n        if (!extendedProperties.isPresent()) {\n            return Optional.empty();\n        }\n\n        final JsonObject result = new JsonObject();\n\n        result.add(\"version\", extendedProperties.get().getVersion());\n\n        final JsonObject jsonProperties = new JsonObject();\n\n        final List<ExtendedPropertyGroup> groups = extendedProperties.get().getPropertyGroups();\n\n        for (final ExtendedPropertyGroup group : groups) {\n            final JsonObject properties = new JsonObject();\n\n            for (final Entry<String, String> entry : group.getProperties().entrySet()) {\n                final String value = entry.getValue();\n\n                if (value == null) {\n                    logger.warn(\"found null extended property: group {} property {}\", group.getName(), entry.getKey());\n                    continue;\n                }\n\n                properties.add(entry.getKey(), value);\n            }\n\n            jsonProperties.add(group.getName(), properties);\n        }\n\n        result.add(\"properties\", jsonProperties);\n\n        return Optional.of(result.toString());\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/LifecycleMessage.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport org.eclipse.kura.message.KuraPayload;\n\npublic class LifecycleMessage {\n    \n    private StringBuilder topicBuilder;\n    private LifeCyclePayloadBuilder payloadBuilder;\n    private KuraPayload payload;\n    private boolean isAppCertificateMessage = false;\n    private boolean isBirthCertificateMessage = false;\n    private int qos = 0;\n\n    public LifecycleMessage(CloudServiceOptions options, CloudServiceImpl cloudServiceImpl) {\n        this.topicBuilder = new StringBuilder(options.getTopicControlPrefix());\n        this.topicBuilder.append(CloudServiceOptions.getTopicSeparator())\n                .append(CloudServiceOptions.getTopicAccountToken())\n                .append(CloudServiceOptions.getTopicSeparator())\n                .append(CloudServiceOptions.getTopicClientIdToken())\n                .append(CloudServiceOptions.getTopicSeparator());\n\n        this.payloadBuilder = new LifeCyclePayloadBuilder(cloudServiceImpl);\n    }\n\n    public LifecycleMessage asBirthCertificateMessage() {\n        this.topicBuilder.append(CloudServiceOptions.getTopicBirthSuffix());\n        this.payload = this.payloadBuilder.buildBirthPayload();\n        this.isBirthCertificateMessage = true;\n        this.qos = 1;\n        return this;\n    }\n\n    public LifecycleMessage asAppCertificateMessage() {\n        this.topicBuilder.append(CloudServiceOptions.getTopicAppsSuffix());\n        this.payload = this.payloadBuilder.buildBirthPayload();\n        this.isAppCertificateMessage = true;\n        this.qos = 1;\n        return this;\n    }\n\n    public LifecycleMessage asDisconnectCertificateMessage() {\n        this.topicBuilder.append(CloudServiceOptions.getTopicDisconnectSuffix());\n        this.payload = this.payloadBuilder.buildDisconnectPayload();\n        return this;\n    }\n\n    public String getTopic() {\n        return this.topicBuilder.toString();\n    }\n\n    public KuraPayload getPayload() {\n        return this.payload;\n    }\n\n    public boolean isAppCertificateMessage() {\n        return this.isAppCertificateMessage;\n    }\n\n    public boolean isBirthCertificateMessage() {\n        return this.isBirthCertificateMessage;\n    }\n    \n    public int getQos() {\n        return this.qos;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/MessageHandlerCallable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerContextConstants.DEVICE_ID;\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerContextConstants.NOTIFICATION_PUBLISHER_PID;\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerContextConstants.TENANT_ID;\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Callable;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.audit.AuditConstants;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.audit.AuditContext.Scope;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerContext;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class MessageHandlerCallable implements Callable<Void> {\n\n    private static final Logger auditLogger = LoggerFactory.getLogger(\"AuditLogger\");\n    private static final Logger logger = LoggerFactory.getLogger(MessageHandlerCallable.class);\n\n    private static final Pattern RESOURCES_DELIM = Pattern.compile(\"/\");\n\n    public static final String METRIC_REQUEST_ID = \"request.id\";\n    public static final String REQUESTER_CLIENT_ID = \"requester.client.id\";\n\n    public static final String METRIC_RESPONSE_CODE = \"response.code\";\n    public static final String METRIC_EXCEPTION_MSG = \"response.exception.message\";\n    public static final String METRIC_EXCEPTION_STACK = \"response.exception.stack\";\n\n    public static final int RESPONSE_CODE_OK = 200;\n    public static final int RESPONSE_CODE_BAD_REQUEST = 400;\n    public static final int RESPONSE_CODE_NOTFOUND = 404;\n    public static final int RESPONSE_CODE_ERROR = 500;\n\n    protected static final int DFLT_PUB_QOS = 0;\n    protected static final boolean DFLT_RETAIN = false;\n    protected static final int DFLT_PRIORITY = 1;\n\n    private final RequestHandler cloudApp;\n    private final String appId;\n    private final String appTopic;\n    private final KuraPayload kuraMessage;\n    private final CloudServiceImpl cloudService;\n    private final RequestHandlerContext requestHandlerContext;\n\n    public MessageHandlerCallable(RequestHandler cloudApp, String appId, String appTopic, KuraPayload msg,\n            CloudServiceImpl cloudService) {\n        super();\n        this.cloudApp = cloudApp;\n        this.appId = appId;\n        this.appTopic = appTopic;\n        this.kuraMessage = msg;\n        this.cloudService = cloudService;\n\n        String notificationPublisherPid = this.cloudService.getNotificationPublisherPid();\n        CloudNotificationPublisher notificationPublisher = this.cloudService.getNotificationPublisher();\n        Map<String, String> connectionProperties = this.cloudService.getInfo();\n        Map<String, String> contextProperties = new HashMap<>();\n        contextProperties.put(NOTIFICATION_PUBLISHER_PID.name(), notificationPublisherPid);\n        contextProperties.put(TENANT_ID.name(), connectionProperties.get(\"Account\"));\n        contextProperties.put(DEVICE_ID.name(), connectionProperties.get(\"Client ID\"));\n\n        this.requestHandlerContext = new RequestHandlerContext(notificationPublisher, contextProperties);\n    }\n\n    @Override\n    public Void call() throws Exception {\n        logger.debug(\"Control Arrived on topic: {}\", this.appTopic);\n\n        String requestId = (String) this.kuraMessage.getMetric(METRIC_REQUEST_ID);\n        String requesterClientId = (String) this.kuraMessage.getMetric(REQUESTER_CLIENT_ID);\n        if ( requestId == null || requesterClientId == null ) {\n        if(logger.isDebugEnabled()) {\n            logger.debug(\"Request Id or Requester Cliend Id is null\"); \n        }\n            throw new ParseException(\"Not a valid request payload\", 0);\n        }\n\n        // Prepare the default response\n        KuraPayload reqPayload = this.kuraMessage;\n        KuraMessage response;\n\n        final Map<String, String> auditProperties = new HashMap<>();\n\n        auditProperties.put(AuditConstants.KEY_ENTRY_POINT.getValue(), \"DefaultCloudConnectionService\");\n        auditProperties.put(\"cloud.app.id\", this.appId);\n        auditProperties.put(\"cloud.app.topic\", this.appTopic);\n        auditProperties.put(\"cloud.connection.pid\", this.cloudService.getOwnPid());\n\n        try (final Scope scope = AuditContext.openScope(new AuditContext(auditProperties))) {\n            try {\n                Iterator<String> resources = RESOURCES_DELIM.splitAsStream(this.appTopic).iterator();\n\n                if (!resources.hasNext()) {\n                    throw new IllegalArgumentException();\n                }\n\n                String method = resources.next();\n\n                Map<String, Object> reqResources = getMessageResources(resources);\n\n                KuraMessage reqMessage = new KuraMessage(reqPayload, reqResources);\n\n                switch (method) {\n                case \"GET\":\n                    logger.debug(\"Handling GET request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doGet(this.requestHandlerContext, reqMessage);\n                    break;\n\n                case \"PUT\":\n                    logger.debug(\"Handling PUT request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doPut(this.requestHandlerContext, reqMessage);\n                    break;\n\n                case \"POST\":\n                    logger.debug(\"Handling POST request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doPost(this.requestHandlerContext, reqMessage);\n                    break;\n\n                case \"DEL\":\n                    logger.debug(\"Handling DEL request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doDel(this.requestHandlerContext, reqMessage);\n                    break;\n\n                case \"EXEC\":\n                    logger.debug(\"Handling EXEC request topic: {}\", this.appTopic);\n                    response = this.cloudApp.doExec(this.requestHandlerContext, reqMessage);\n                    break;\n\n                default:\n                    logger.error(\"Bad request topic: {}\", this.appTopic);\n                    KuraPayload payload = new KuraPayload();\n                    response = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST);\n                    break;\n                }\n            } catch (IllegalArgumentException e) {\n                logger.error(\"Bad request topic: {}\", this.appTopic);\n                KuraPayload payload = new KuraPayload();\n                response = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST);\n            } catch (KuraException e) {\n                logger.error(\"Error handling request topic: {}\", this.appTopic, e);\n                response = manageException(e);\n            } catch (Exception e) {\n                logger.error(\"Unexpected failure handling response\", e);\n                KuraPayload payload = new KuraPayload();\n                response = setResponseCode(payload, RESPONSE_CODE_ERROR);\n            }\n\n            final Object responseCode = response.getPayload().getMetric(METRIC_RESPONSE_CODE);\n            final boolean isSuccessful = responseCode instanceof Integer && (Integer) responseCode / 200 == 1;\n\n            if (isSuccessful) {\n                auditLogger.info(\"{} CloudCall - Success - Execute RequestHandler call\",\n                        AuditContext.currentOrInternal());\n            } else {\n                auditLogger.warn(\"{} CloudCall - Failure - Execute RequestHandler call\",\n                        AuditContext.currentOrInternal());\n            }\n\n            buildResponseMessage(requestId, requesterClientId, response);\n        }\n\n        return null;\n    }\n\n    private void buildResponseMessage(String requestId, String requesterClientId, KuraMessage response) {\n        try {\n            response.getPayload().setTimestamp(new Date());\n\n            StringBuilder sb = new StringBuilder(\"REPLY\").append(\"/\").append(requestId);\n            logger.debug(\"Publishing response topic: {}\", sb);\n\n            DataService dataService = this.cloudService.getDataService();\n            String fullTopic = encodeTopic(requesterClientId, sb.toString());\n            byte[] appPayload = this.cloudService.encodePayload(response.getPayload());\n            dataService.publish(fullTopic, appPayload, DFLT_PUB_QOS, DFLT_RETAIN, DFLT_PRIORITY);\n        } catch (KuraException e) {\n            logger.error(\"Error publishing response for topic: {}\\n{}\", this.appTopic, e);\n        }\n    }\n\n    private KuraMessage manageException(KuraException e) {\n        KuraMessage message;\n        KuraPayload payload = new KuraPayload();\n        setException(payload, e);\n        if (e.getCode().equals(KuraErrorCode.BAD_REQUEST)) {\n            message = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST);\n        } else if (e.getCode().equals(KuraErrorCode.NOT_FOUND)) {\n            message = setResponseCode(payload, RESPONSE_CODE_NOTFOUND);\n        } else {\n            message = setResponseCode(payload, RESPONSE_CODE_ERROR);\n        }\n        return message;\n    }\n\n    private Map<String, Object> getMessageResources(Iterator<String> iter) {\n        List<String> resourcesList = new ArrayList<>();\n        while (iter.hasNext()) {\n            resourcesList.add(iter.next());\n        }\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(ARGS_KEY.value(), resourcesList);\n        return properties;\n    }\n\n    public KuraMessage setResponseCode(KuraPayload payload, int responseCode) {\n        payload.addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode));\n        return new KuraMessage(payload);\n    }\n\n    public void setException(KuraPayload payload, Throwable t) {\n        if (t != null) {\n            payload.addMetric(METRIC_EXCEPTION_MSG, t.getMessage());\n        }\n    }\n\n    @SuppressWarnings(\"unused\")\n    private String stackTraceAsString(Throwable t) {\n        StringWriter sw = new StringWriter();\n        PrintWriter pw = new PrintWriter(sw);\n        t.printStackTrace(pw);\n        return sw.toString();\n    }\n\n    private String encodeTopic(String deviceId, String appTopic) {\n        CloudServiceOptions options = this.cloudService.getCloudServiceOptions();\n        StringBuilder sb = new StringBuilder();\n        sb.append(options.getTopicControlPrefix()).append(CloudServiceOptions.getTopicSeparator());\n\n        sb.append(CloudServiceOptions.getTopicAccountToken()).append(CloudServiceOptions.getTopicSeparator())\n                .append(deviceId).append(CloudServiceOptions.getTopicSeparator()).append(this.appId);\n\n        if (appTopic != null && !appTopic.isEmpty()) {\n            sb.append(CloudServiceOptions.getTopicSeparator()).append(appTopic);\n        }\n\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/call/CloudCallServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.call;\n\nimport java.io.IOException;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraInvalidMessageException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.KuraTimeoutException;\nimport org.eclipse.kura.cloud.CloudCallService;\nimport org.eclipse.kura.cloud.app.RequestIdGenerator;\nimport org.eclipse.kura.core.cloud.CloudPayloadProtoBufDecoderImpl;\nimport org.eclipse.kura.core.cloud.CloudPayloadProtoBufEncoderImpl;\nimport org.eclipse.kura.core.cloud.KuraTopicImpl;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.eclipse.kura.message.KuraApplicationTopic;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraRequestPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudCallServiceImpl implements CloudCallService, DataServiceListener {\n\n    private static final Logger s_logger = LoggerFactory.getLogger(CloudCallServiceImpl.class);\n\n    private static RequestIdGenerator s_generator = RequestIdGenerator.getInstance();\n\n    private static final int DFLT_PUB_QOS = 0;\n    private static final boolean DFLT_RETAIN = false;\n    private static final int DFLT_PRIORITY = 1;\n\n    private static final String ACCOUNT_NAME_VAR_NAME = \"#account-name\";\n    private static final String CLIENT_ID_VAR_NAME = \"#client-id\";\n\n    private DataService m_dataService;\n\n    private Object m_lock;\n    private String m_respTopic;\n    private KuraResponsePayload m_resp;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setDataService(DataService dataService) {\n        this.m_dataService = dataService;\n    }\n\n    public void unsetDataService(DataService dataService) {\n        this.m_dataService = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) {\n        s_logger.info(\"Activating...\");\n        this.m_lock = new Object();\n        this.m_dataService.addDataServiceListener(this);\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        s_logger.info(\"Deactivating...\");\n        this.m_dataService.removeDataServiceListener(this);\n        synchronized (this.m_lock) {\n            this.m_lock.notifyAll();\n        }\n    }\n\n    @Override\n    public synchronized KuraResponsePayload call(String appId, String appTopic, KuraPayload appPayload, int timeout)\n            throws KuraException {\n        return call(CLIENT_ID_VAR_NAME, appId, appTopic, appPayload, timeout);\n    }\n\n    @Override\n    public synchronized KuraResponsePayload call(String deviceId, String appId, String appTopic, KuraPayload appPayload,\n            int timeout) throws KuraException {\n        // Generate the request ID\n        String requestId = s_generator.next();\n\n        StringBuilder sbReqTopic = new StringBuilder(\"$EDC\").append(\"/\").append(ACCOUNT_NAME_VAR_NAME).append(\"/\")\n                .append(deviceId).append(\"/\").append(appId).append(\"/\").append(appTopic);\n\n        StringBuilder sbRespTopic = new StringBuilder(\"$EDC\").append(\"/\").append(ACCOUNT_NAME_VAR_NAME).append(\"/\")\n                .append(CLIENT_ID_VAR_NAME).append(\"/\").append(appId).append(\"/\").append(\"REPLY\").append(\"/\")\n                .append(requestId);\n\n        KuraRequestPayload req = null;\n        if (appPayload != null) {\n            // Construct a request payload\n            req = new KuraRequestPayload(appPayload);\n        } else {\n            req = new KuraRequestPayload();\n        }\n\n        req.setRequestId(requestId);\n        req.setRequesterClientId(CLIENT_ID_VAR_NAME);\n\n        CloudPayloadProtoBufEncoderImpl encoder = new CloudPayloadProtoBufEncoderImpl(req);\n        byte[] rawPayload;\n        try {\n            rawPayload = encoder.getBytes();\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e, \"Cannot encode request\");\n        }\n\n        this.m_respTopic = sbRespTopic.toString();\n        this.m_resp = null;\n\n        this.m_dataService.subscribe(this.m_respTopic, 0);\n\n        synchronized (this.m_lock) {\n            try {\n                this.m_dataService.publish(sbReqTopic.toString(), rawPayload, DFLT_PUB_QOS, DFLT_RETAIN, DFLT_PRIORITY);\n                this.m_lock.wait(timeout);\n            } catch (KuraStoreException e) {\n                throw e;\n            } catch (InterruptedException e) {\n                // Avoid re-throwing this exception which should not normally happen\n                s_logger.warn(\"Interrupted while waiting for the response\");\n                Thread.currentThread().interrupt();\n            } finally {\n                try {\n                    this.m_dataService.unsubscribe(this.m_respTopic);\n                } catch (KuraException e) {\n                    s_logger.error(\"Cannot unsubscribe\");\n                }\n                this.m_respTopic = null;\n            }\n        }\n\n        if (this.m_resp == null) {\n            throw new KuraTimeoutException(\"Timed out while waiting for the response\");\n        }\n\n        return this.m_resp;\n    }\n\n    public void cancel() {\n        synchronized (this.m_lock) {\n            notifyAll();\n        }\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        // Ignore\n    }\n\n    @Override\n    public void onDisconnecting() {\n        // Ignore\n    }\n\n    @Override\n    public void onDisconnected() {\n        // Ignore\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        // Ignore\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n\n        s_logger.debug(\"Message arrived on topic: '{}'\", topic);\n\n        if (this.m_respTopic != null) {\n            // Filter on application ID and topic\n            KuraApplicationTopic kuraTopic = new KuraTopicImpl(topic);\n            KuraApplicationTopic kuraRespTopic = new KuraTopicImpl(this.m_respTopic);\n\n            if (kuraTopic.getApplicationId().equals(kuraRespTopic.getApplicationId())\n                    && kuraTopic.getApplicationTopic().equals(kuraRespTopic.getApplicationTopic())) {\n\n                s_logger.debug(\"Got response\");\n\n                CloudPayloadProtoBufDecoderImpl decoder = new CloudPayloadProtoBufDecoderImpl(payload);\n\n                KuraResponsePayload resp = null;\n                try {\n                    KuraPayload kuraPayload = decoder.buildFromByteArray();\n                    resp = new KuraResponsePayload(kuraPayload);\n                } catch (KuraInvalidMessageException e) {\n                    s_logger.error(\"Cannot decode protobuf\", e);\n                } catch (IOException e) {\n                    s_logger.error(\"Cannot decode protobuf\", e);\n                }\n\n                synchronized (this.m_lock) {\n                    this.m_resp = resp; // Can be null\n                    this.m_lock.notifyAll();\n                }\n            }\n        }\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        // Ignore\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        // Ignore\n    }\n\n    @Override\n    public boolean isConnected() {\n        return this.m_dataService.isConnected();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/publisher/CloudPublisherImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.publisher;\n\nimport static java.util.Objects.nonNull;\nimport static org.eclipse.kura.core.message.MessageConstants.APP_ID;\nimport static org.eclipse.kura.core.message.MessageConstants.APP_TOPIC;\nimport static org.eclipse.kura.core.message.MessageConstants.CONTROL;\nimport static org.eclipse.kura.core.message.MessageConstants.PRIORITY;\nimport static org.eclipse.kura.core.message.MessageConstants.QOS;\nimport static org.eclipse.kura.core.message.MessageConstants.RETAIN;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.core.cloud.CloudPublisherDeliveryListener;\nimport org.eclipse.kura.core.cloud.CloudServiceImpl;\nimport org.eclipse.kura.core.message.MessageType;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudPublisherImpl\n        implements CloudPublisher, ConfigurableComponent, CloudConnectionListener, CloudPublisherDeliveryListener {\n\n    private final class CloudConnectionManagerTrackerCustomizer\n            implements ServiceTrackerCustomizer<CloudConnectionManager, CloudConnectionManager> {\n\n        @Override\n        public CloudConnectionManager addingService(final ServiceReference<CloudConnectionManager> reference) {\n            CloudConnectionManager tempCloudService = CloudPublisherImpl.this.bundleContext.getService(reference);\n\n            if (tempCloudService instanceof CloudServiceImpl) {\n                CloudPublisherImpl.this.cloudServiceImpl = (CloudServiceImpl) tempCloudService;\n                CloudPublisherImpl.this.cloudServiceImpl.registerCloudConnectionListener(CloudPublisherImpl.this);\n                CloudPublisherImpl.this.cloudServiceImpl\n                        .registerCloudPublisherDeliveryListener(CloudPublisherImpl.this);\n                return tempCloudService;\n            } else {\n                CloudPublisherImpl.this.bundleContext.ungetService(reference);\n            }\n\n            return null;\n        }\n\n        @Override\n        public void removedService(final ServiceReference<CloudConnectionManager> reference,\n                final CloudConnectionManager service) {\n            CloudPublisherImpl.this.cloudServiceImpl.unregisterCloudConnectionListener(CloudPublisherImpl.this);\n            CloudPublisherImpl.this.cloudServiceImpl.unregisterCloudPublisherDeliveryListener(CloudPublisherImpl.this);\n            CloudPublisherImpl.this.cloudServiceImpl = null;\n        }\n\n        @Override\n        public void modifiedService(ServiceReference<CloudConnectionManager> reference,\n                CloudConnectionManager service) {\n            // Not needed\n        }\n    }\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudPublisherImpl.class);\n\n    private static final String TOPIC_PATTERN_STRING = \"\\\\$([^\\\\s/]+)\";\n    private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING);\n\n    private final Set<CloudConnectionListener> cloudConnectionListeners = new CopyOnWriteArraySet<>();\n    private final Set<CloudDeliveryListener> cloudDeliveryListeners = new CopyOnWriteArraySet<>();\n\n    private ServiceTrackerCustomizer<CloudConnectionManager, CloudConnectionManager> cloudConnectionManagerTrackerCustomizer;\n    private ServiceTracker<CloudConnectionManager, CloudConnectionManager> cloudConnectionManagerTracker;\n\n    private CloudPublisherOptions cloudPublisherOptions;\n    private CloudServiceImpl cloudServiceImpl;\n    private BundleContext bundleContext;\n\n    private final ExecutorService worker = Executors.newCachedThreadPool();\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        logger.debug(\"Activating Cloud Publisher...\");\n        this.bundleContext = componentContext.getBundleContext();\n\n        this.cloudPublisherOptions = new CloudPublisherOptions(properties);\n\n        this.cloudConnectionManagerTrackerCustomizer = new CloudConnectionManagerTrackerCustomizer();\n        initCloudConnectionManagerTracking();\n\n        logger.debug(\"Activating Cloud Publisher... Done\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.debug(\"Updating Cloud Publisher...\");\n\n        this.cloudPublisherOptions = new CloudPublisherOptions(properties);\n\n        if (nonNull(this.cloudConnectionManagerTracker)) {\n            this.cloudConnectionManagerTracker.close();\n        }\n        initCloudConnectionManagerTracking();\n\n        logger.debug(\"Updating Cloud Publisher... Done\");\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.debug(\"Deactivating Cloud Publisher...\");\n\n        if (nonNull(this.cloudConnectionManagerTracker)) {\n            this.cloudConnectionManagerTracker.close();\n        }\n\n        this.worker.shutdown();\n        logger.debug(\"Deactivating Cloud Publisher... Done\");\n    }\n\n    @Override\n    public String publish(KuraMessage message) throws KuraException {\n        if (this.cloudServiceImpl == null) {\n            logger.info(\"Null cloud service\");\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, \"The Cloud Service is null.\");\n        }\n\n        if (message == null) {\n            logger.warn(\"Received null message!\");\n            throw new IllegalArgumentException();\n        }\n\n        String appTopic = fillAppTopicPlaceholders(this.cloudPublisherOptions.getAppTopic(), message);\n\n        int qos = this.cloudPublisherOptions.getQos();\n        boolean retain = this.cloudPublisherOptions.isRetain();\n        int priority = this.cloudPublisherOptions.getPriority();\n        boolean isControl = MessageType.CONTROL.equals(this.cloudPublisherOptions.getMessageType());\n\n        Map<String, Object> publishMessageProps = new HashMap<>();\n        publishMessageProps.put(APP_TOPIC.name(), appTopic);\n        publishMessageProps.put(APP_ID.name(), this.cloudPublisherOptions.getAppId());\n        publishMessageProps.put(QOS.name(), qos);\n        publishMessageProps.put(RETAIN.name(), retain);\n        publishMessageProps.put(PRIORITY.name(), priority);\n        publishMessageProps.put(CONTROL.name(), isControl);\n\n        KuraMessage publishMessage = new KuraMessage(message.getPayload(), publishMessageProps);\n\n        return this.cloudServiceImpl.publish(publishMessage);\n    }\n\n    private String fillAppTopicPlaceholders(String appTopic, KuraMessage message) {\n        Matcher matcher = TOPIC_PATTERN.matcher(appTopic);\n        StringBuffer buffer = new StringBuffer();\n\n        while (matcher.find()) {\n            Map<String, Object> properties = message.getProperties();\n            if (properties.containsKey(matcher.group(1))) {\n                String replacement = matcher.group(0);\n\n                Object value = properties.get(matcher.group(1));\n                if (replacement != null) {\n                    matcher.appendReplacement(buffer, value.toString());\n                }\n            }\n        }\n        matcher.appendTail(buffer);\n        return buffer.toString();\n    }\n\n    private void initCloudConnectionManagerTracking() {\n        String selectedCloudServicePid = this.cloudPublisherOptions.getCloudServicePid();\n        String filterString = String.format(\"(&(%s=%s)(kura.service.pid=%s))\", Constants.OBJECTCLASS,\n                CloudConnectionManager.class.getName(), selectedCloudServicePid);\n        Filter filter = null;\n        try {\n            filter = this.bundleContext.createFilter(filterString);\n        } catch (InvalidSyntaxException e) {\n            logger.error(\"Filter setup exception \", e);\n        }\n        this.cloudConnectionManagerTracker = new ServiceTracker<>(this.bundleContext, filter,\n                this.cloudConnectionManagerTrackerCustomizer);\n        this.cloudConnectionManagerTracker.open();\n    }\n\n    @Override\n    public void onDisconnected() {\n        this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onDisconnected));\n    }\n\n    @Override\n    public void onConnectionLost() {\n        this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionLost));\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionEstablished));\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.add(cloudDeliveryListener);\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.remove(cloudDeliveryListener);\n    }\n\n    @Override\n    public void onMessageConfirmed(String messageId, String topic) {\n        if (topic.contains(this.cloudPublisherOptions.getAppId())) {\n            this.cloudDeliveryListeners.forEach(listener -> this.worker.execute(() -> listener.onMessageConfirmed(messageId)));\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/publisher/CloudPublisherOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.publisher;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.core.message.MessageType;\n\npublic class CloudPublisherOptions {\n\n    private static final Property<String> PROPERTY_CLOUD_SERVICE_PID = new Property<>(\n            CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), \"org.eclipse.kura.cloud.CloudService\");\n    private static final Property<String> PROPERTY_APP_ID = new Property<>(\"appId\", \"W1\");\n    private static final Property<String> PROPERTY_APP_TOPIC = new Property<>(\"app.topic\", \"A1/$assetName\");\n    private static final Property<Integer> PROPERTY_QOS = new Property<>(\"qos\", 0);\n    private static final Property<Boolean> PROPERTY_RETAIN = new Property<>(\"retain\", false);\n    private static final Property<String> PROPERTY_MESSAGE_TYPE = new Property<>(\"message.type\", \"data\");\n    private static final Property<Integer> PROPERTY_PRIORITY = new Property<>(\"priority\", 7);\n\n    private final String cloudServicePid;\n    private final String appId;\n    private final String appTopic;\n    private final int qos;\n    private final boolean retain;\n    private final String messageType;\n    private final int priority;\n\n    public CloudPublisherOptions(final Map<String, Object> properties) {\n        this.cloudServicePid = PROPERTY_CLOUD_SERVICE_PID.get(properties);\n        this.appId = PROPERTY_APP_ID.get(properties);\n        this.appTopic = PROPERTY_APP_TOPIC.get(properties);\n        this.qos = PROPERTY_QOS.get(properties);\n        this.retain = PROPERTY_RETAIN.get(properties);\n        this.messageType = PROPERTY_MESSAGE_TYPE.get(properties);\n        this.priority = PROPERTY_PRIORITY.get(properties);\n    }\n\n    public String getCloudServicePid() {\n        return this.cloudServicePid;\n    }\n\n    public String getAppId() {\n        return this.appId;\n    }\n\n    public String getAppTopic() {\n        return this.appTopic;\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    public boolean isRetain() {\n        return this.retain;\n    }\n\n    public MessageType getMessageType() {\n        return MessageType.fromValue(this.messageType);\n    }\n\n    public int getPriority() {\n        return this.priority;\n    }\n\n    private static final class Property<T> {\n\n        private final String key;\n        private final T defaultValue;\n\n        public Property(final String key, final T defaultValue) {\n            this.key = key;\n            this.defaultValue = defaultValue;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public T get(final Map<String, Object> properties) {\n            final Object value = properties.get(this.key);\n\n            if (this.defaultValue.getClass().isInstance(value)) {\n                return (T) value;\n            }\n            return this.defaultValue;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/publisher/NotificationPublisherImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.publisher;\n\nimport static java.util.Objects.isNull;\nimport static org.eclipse.kura.core.message.MessageConstants.CONTROL;\nimport static org.eclipse.kura.core.message.MessageConstants.PRIORITY;\nimport static org.eclipse.kura.core.message.MessageConstants.QOS;\nimport static org.eclipse.kura.core.message.MessageConstants.RETAIN;\nimport static org.eclipse.kura.core.message.MessageConstants.FULL_TOPIC;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher;\nimport org.eclipse.kura.core.cloud.CloudServiceImpl;\nimport org.eclipse.kura.core.cloud.CloudServiceOptions;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class NotificationPublisherImpl implements CloudNotificationPublisher {\n\n    private static final Logger logger = LoggerFactory.getLogger(NotificationPublisherImpl.class);\n\n    private static final String TOPIC_PATTERN_STRING = \"\\\\$([^\\\\s/]+)\";\n    private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING);\n\n    private static final int DFLT_PUB_QOS = 0;\n    private static final boolean DFLT_RETAIN = false;\n    private static final int DFLT_PRIORITY = 1;\n\n    private static final String MESSAGE_TYPE_KEY = \"messageType\";\n\n    private static final String REQUESTOR_CLIENT_ID_KEY = \"requestorClientId\";\n\n    private static final String APP_ID_KEY = \"appId\";\n\n    private final CloudServiceImpl cloudServiceImpl;\n\n    public NotificationPublisherImpl(CloudServiceImpl cloudServiceImpl) {\n        this.cloudServiceImpl = cloudServiceImpl;\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        // Not needed\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        // Not needed\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        // Not needed\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        // Not needed\n    }\n\n    @Override\n    public String publish(KuraMessage message) throws KuraException {\n        if (this.cloudServiceImpl == null) {\n            logger.warn(\"Null cloud connection\");\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, \"The Cloud Service is null.\");\n        }\n\n        if (message == null) {\n            logger.warn(\"Received null message!\");\n            throw new IllegalArgumentException();\n        }\n\n        String fullTopic = encodeFullTopic(message);\n\n        Map<String, Object> publishMessageProps = new HashMap<>();\n        publishMessageProps.put(FULL_TOPIC.name(), fullTopic);\n        publishMessageProps.put(QOS.name(), DFLT_PUB_QOS);\n        publishMessageProps.put(RETAIN.name(), DFLT_RETAIN);\n        publishMessageProps.put(PRIORITY.name(), DFLT_PRIORITY);\n        publishMessageProps.put(CONTROL.name(), true);\n\n        KuraMessage publishMessage = new KuraMessage(message.getPayload(), publishMessageProps);\n\n        return this.cloudServiceImpl.publish(publishMessage);\n    }\n\n    private String encodeFullTopic(KuraMessage message) {\n        String appId = (String) message.getProperties().get(APP_ID_KEY);\n        String messageType = (String) message.getProperties().get(MESSAGE_TYPE_KEY);\n        String requestorClientId = (String) message.getProperties().get(REQUESTOR_CLIENT_ID_KEY);\n\n        if (isNull(appId) || isNull(messageType) || isNull(requestorClientId)) {\n            throw new IllegalArgumentException(\"Incomplete properties in received message.\");\n        }\n\n        String fullTopic = encodeTopic(appId, messageType, requestorClientId);\n        return fillAppTopicPlaceholders(fullTopic, message);\n    }\n\n    private String encodeTopic(String appId, String messageType, String requestorClientId) {\n\n        CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions();\n        String deviceId = options.getTopicClientIdToken();\n        String topicSeparator = options.getTopicSeparator();\n\n        StringBuilder sb = new StringBuilder();\n\n        sb.append(options.getTopicControlPrefix()).append(topicSeparator);\n\n        sb.append(options.getTopicAccountToken()).append(topicSeparator).append(requestorClientId)\n                .append(topicSeparator).append(appId);\n\n        sb.append(topicSeparator).append(\"NOTIFY\").append(topicSeparator).append(deviceId).append(topicSeparator)\n                .append(messageType);\n\n        return sb.toString();\n    }\n\n    private String fillAppTopicPlaceholders(String fullTopic, KuraMessage message) {\n\n        Matcher matcher = TOPIC_PATTERN.matcher(fullTopic);\n        StringBuffer buffer = new StringBuffer();\n\n        while (matcher.find()) {\n            Map<String, Object> properties = message.getProperties();\n            if (properties.containsKey(matcher.group(1))) {\n                String replacement = matcher.group(0);\n\n                Object value = properties.get(matcher.group(1));\n                if (replacement != null) {\n                    matcher.appendReplacement(buffer, value.toString());\n                }\n            }\n        }\n        matcher.appendTail(buffer);\n        return buffer.toString();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/subscriber/CloudSubscriberImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.subscriber;\n\nimport static java.util.Objects.nonNull;\nimport static org.eclipse.kura.core.message.MessageConstants.APP_ID;\nimport static org.eclipse.kura.core.message.MessageConstants.APP_TOPIC;\nimport static org.eclipse.kura.core.message.MessageConstants.CONTROL;\nimport static org.eclipse.kura.core.message.MessageConstants.QOS;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.core.cloud.CloudServiceImpl;\nimport org.eclipse.kura.core.message.MessageType;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudSubscriberImpl\n        implements CloudSubscriber, ConfigurableComponent, CloudConnectionListener, CloudSubscriberListener {\n\n    private final class CloudServiceTrackerCustomizer\n            implements ServiceTrackerCustomizer<CloudConnectionManager, CloudConnectionManager> {\n\n        @Override\n        public CloudConnectionManager addingService(final ServiceReference<CloudConnectionManager> reference) {\n            CloudConnectionManager tempCloudService = CloudSubscriberImpl.this.bundleContext.getService(reference);\n\n            if (tempCloudService instanceof CloudServiceImpl) {\n                CloudSubscriberImpl.this.cloudService = (CloudServiceImpl) tempCloudService;\n\n                Map<String, Object> subscriptionProps = new HashMap<>();\n                subscriptionProps.put(APP_ID.name(), CloudSubscriberImpl.this.cloudSubscriberOptions.getAppId());\n                subscriptionProps.put(APP_TOPIC.name(), CloudSubscriberImpl.this.cloudSubscriberOptions.getAppTopic());\n                subscriptionProps.put(QOS.name(), CloudSubscriberImpl.this.cloudSubscriberOptions.getQos());\n                subscriptionProps.put(CONTROL.name(),\n                        MessageType.CONTROL.equals(CloudSubscriberImpl.this.cloudSubscriberOptions.getMessageType()));\n\n                CloudSubscriberImpl.this.cloudService.registerSubscriber(subscriptionProps, CloudSubscriberImpl.this);\n                CloudSubscriberImpl.this.cloudService.registerCloudConnectionListener(CloudSubscriberImpl.this);\n                return tempCloudService;\n            } else {\n                CloudSubscriberImpl.this.bundleContext.ungetService(reference);\n            }\n\n            return null;\n        }\n\n        @Override\n        public void removedService(final ServiceReference<CloudConnectionManager> reference,\n                final CloudConnectionManager service) {\n\n            CloudSubscriberImpl.this.cloudService.unregisterSubscriber(CloudSubscriberImpl.this);\n            CloudSubscriberImpl.this.cloudService.unregisterCloudConnectionListener(CloudSubscriberImpl.this);\n            CloudSubscriberImpl.this.cloudService = null;\n        }\n\n        @Override\n        public void modifiedService(ServiceReference<CloudConnectionManager> reference,\n                CloudConnectionManager service) {\n            // Not needed\n        }\n    }\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudSubscriberImpl.class);\n\n    private ServiceTrackerCustomizer<CloudConnectionManager, CloudConnectionManager> cloudServiceTrackerCustomizer;\n    private ServiceTracker<CloudConnectionManager, CloudConnectionManager> cloudServiceTracker;\n\n    private CloudSubscriberOptions cloudSubscriberOptions;\n    private CloudServiceImpl cloudService;\n    private BundleContext bundleContext;\n\n    private final Set<CloudSubscriberListener> subscribers = new CopyOnWriteArraySet<>();\n    private final Set<CloudConnectionListener> cloudConnectionListeners = new CopyOnWriteArraySet<>();\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        logger.debug(\"Activating Cloud Publisher...\");\n        this.bundleContext = componentContext.getBundleContext();\n\n        this.cloudServiceTrackerCustomizer = new CloudServiceTrackerCustomizer();\n\n        doUpdate(properties);\n\n        logger.debug(\"Activating Cloud Publisher... Done\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.debug(\"Updating Cloud Publisher...\");\n\n        doUpdate(properties);\n\n        logger.debug(\"Updating Cloud Publisher... Done\");\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.debug(\"Deactivating Cloud Publisher...\");\n\n        if (nonNull(this.cloudServiceTracker)) {\n            this.cloudServiceTracker.close();\n        }\n        logger.debug(\"Deactivating Cloud Publisher... Done\");\n    }\n\n    private void doUpdate(Map<String, Object> properties) {\n        this.cloudSubscriberOptions = new CloudSubscriberOptions(properties);\n\n        if (nonNull(this.cloudServiceTracker)) {\n            this.cloudServiceTracker.close();\n        }\n        initCloudServiceTracking();\n    }\n\n    private void initCloudServiceTracking() {\n        String selectedCloudServicePid = this.cloudSubscriberOptions.getCloudServicePid();\n        String filterString = String.format(\"(&(%s=%s)(kura.service.pid=%s))\", Constants.OBJECTCLASS,\n                CloudConnectionManager.class.getName(), selectedCloudServicePid);\n        Filter filter = null;\n        try {\n            filter = this.bundleContext.createFilter(filterString);\n        } catch (InvalidSyntaxException e) {\n            logger.error(\"Filter setup exception \", e);\n        }\n        this.cloudServiceTracker = new ServiceTracker<>(this.bundleContext, filter, this.cloudServiceTrackerCustomizer);\n        this.cloudServiceTracker.open();\n    }\n\n    @Override\n    public void registerCloudSubscriberListener(CloudSubscriberListener listener) {\n        this.subscribers.add(listener);\n    }\n\n    @Override\n    public void unregisterCloudSubscriberListener(CloudSubscriberListener listener) {\n        this.subscribers.remove(listener);\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        this.cloudConnectionListeners.forEach(CloudConnectionListener::onConnectionEstablished);\n    }\n\n    @Override\n    public void onConnectionLost() {\n        this.cloudConnectionListeners.forEach(CloudConnectionListener::onConnectionLost);\n    }\n\n    @Override\n    public void onDisconnected() {\n        this.cloudConnectionListeners.forEach(CloudConnectionListener::onDisconnected);\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    @Override\n    public void onMessageArrived(KuraMessage message) {\n        this.subscribers.forEach(subscriber -> subscriber.onMessageArrived(message));\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/subscriber/CloudSubscriberOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.subscriber;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.core.message.MessageType;\n\npublic class CloudSubscriberOptions {\n\n    private static final Property<String> PROPERTY_CLOUD_SERVICE_PID = new Property<>(\n            CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), \"org.eclipse.kura.cloud.CloudService\");\n    private static final Property<String> PROPERTY_APP_ID = new Property<>(\"appId\", \"appId\");\n    private static final Property<String> PROPERTY_APP_TOPIC = new Property<>(\"app.topic\", \"#\");\n    private static final Property<Integer> PROPERTY_QOS = new Property<>(\"qos\", 0);\n    private static final Property<String> PROPERTY_MESSAGE_TYPE = new Property<>(\"message.type\", \"data\");\n\n    private final String cloudServicePid;\n    private final String appId;\n    private final String appTopic;\n    private final int qos;\n    private final String messageType;\n\n    public CloudSubscriberOptions(final Map<String, Object> properties) {\n        this.cloudServicePid = PROPERTY_CLOUD_SERVICE_PID.get(properties);\n        this.appId = PROPERTY_APP_ID.get(properties);\n        this.appTopic = PROPERTY_APP_TOPIC.get(properties);\n        this.qos = PROPERTY_QOS.get(properties);\n        this.messageType = PROPERTY_MESSAGE_TYPE.get(properties);\n    }\n\n    public String getCloudServicePid() {\n        return this.cloudServicePid;\n    }\n\n    public String getAppId() {\n        return this.appId;\n    }\n\n    public String getAppTopic() {\n        return this.appTopic;\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    public MessageType getMessageType() {\n        return MessageType.fromValue(this.messageType);\n    }\n\n    private static final class Property<T> {\n\n        private final String key;\n        private final T defaultValue;\n\n        public Property(final String key, final T defaultValue) {\n            this.key = key;\n            this.defaultValue = defaultValue;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public T get(final Map<String, Object> properties) {\n            final Object value = properties.get(this.key);\n\n            if (this.defaultValue.getClass().isInstance(value)) {\n                return (T) value;\n            }\n            return this.defaultValue;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/subscriber/CloudSubscriptionRecord.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.subscriber;\n\nimport org.eclipse.kura.core.cloud.CloudServiceOptions;\nimport org.eclipse.kura.core.data.util.MqttTopicUtil;\n\npublic class CloudSubscriptionRecord {\n\n    private final String topic;\n    private final int qos;\n\n    private String topicFilter;\n\n    public CloudSubscriptionRecord(final String topic, final int qos) {\n        this.topic = topic;\n        this.qos = qos;\n    }\n\n    public String getTopic() {\n        return this.topic;\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    public boolean matches(final String topic) {\n        if (topicFilter == null) {\n            topicFilter = this.topic.replaceAll(CloudServiceOptions.getTopicAccountToken(), \"+\")\n                    .replaceAll(CloudServiceOptions.getTopicClientIdToken(), \"+\");\n        }\n        return MqttTopicUtil.isMatched(this.topicFilter, topic);\n    }\n\n    @Override\n    public int hashCode() {\n        return topic.hashCode();\n    }\n\n    @Override\n    public boolean equals(final Object obj) {\n        if (!(obj instanceof CloudSubscriptionRecord)) {\n            return false;\n        }\n        return ((CloudSubscriptionRecord) obj).topic.equals(topic);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/message/MessageConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.message;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber;\n\n/**\n * Internal enum providing constants for property sharing between {@link CloudPublisher}s or {@link CloudSubscriber}s\n * and {@link CloudConnectionManager} implementations.\n *\n * These constants are used as keys to identify the different properties shared in a {@link KuraMessage} to provide\n * context associated to a corresponding {@link KuraPayload}\n *\n */\npublic enum MessageConstants {\n\n    FULL_TOPIC,\n    APP_ID,\n    APP_TOPIC,\n    QOS,\n    RETAIN,\n    PRIORITY,\n    CONTROL;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/message/MessageType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.message;\n\npublic enum MessageType {\n\n    DATA(\"data\"),\n    CONTROL(\"control\");\n\n    private String type;\n\n    private MessageType(String type) {\n        this.type = type;\n    }\n\n    public String value() {\n        return this.type;\n    }\n\n    public static MessageType fromValue(String v) {\n        for (MessageType mt : MessageType.values()) {\n            if (mt.type.equals(v)) {\n                return mt;\n            }\n        }\n        throw new IllegalArgumentException(v);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/message/protobuf/KuraPayloadProto.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// NO CHECKED-IN PROTOBUF GENCODE\n// source: kurapayload.proto\n// Protobuf Java Version: 4.29.3\n\npackage org.eclipse.kura.core.message.protobuf;\n\npublic final class KuraPayloadProto {\n  private KuraPayloadProto() {}\n  static {\n    com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n      com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n      /* major= */ 4,\n      /* minor= */ 29,\n      /* patch= */ 3,\n      /* suffix= */ \"\",\n      KuraPayloadProto.class.getName());\n  }\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistryLite registry) {\n  }\n\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistry registry) {\n    registerAllExtensions(\n        (com.google.protobuf.ExtensionRegistryLite) registry);\n  }\n  public interface KuraPayloadOrBuilder extends\n      // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload)\n      com.google.protobuf.GeneratedMessage.\n          ExtendableMessageOrBuilder<KuraPayload> {\n\n    /**\n     * <code>optional int64 timestamp = 1;</code>\n     * @return Whether the timestamp field is set.\n     */\n    boolean hasTimestamp();\n    /**\n     * <code>optional int64 timestamp = 1;</code>\n     * @return The timestamp.\n     */\n    long getTimestamp();\n\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     * @return Whether the position field is set.\n     */\n    boolean hasPosition();\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     * @return The position.\n     */\n    org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition();\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     */\n    org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder();\n\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    java.util.List<org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> \n        getMetricList();\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index);\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    int getMetricCount();\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    java.util.List<? extends org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> \n        getMetricOrBuilderList();\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder(\n        int index);\n\n    /**\n     * <code>optional bytes body = 5001;</code>\n     * @return Whether the body field is set.\n     */\n    boolean hasBody();\n    /**\n     * <code>optional bytes body = 5001;</code>\n     * @return The body.\n     */\n    com.google.protobuf.ByteString getBody();\n  }\n  /**\n   * Protobuf type {@code kuradatatypes.KuraPayload}\n   */\n  public static final class KuraPayload extends\n      com.google.protobuf.GeneratedMessage.ExtendableMessage<\n        KuraPayload> implements\n      // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload)\n      KuraPayloadOrBuilder {\n  private static final long serialVersionUID = 0L;\n    static {\n      com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n        com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n        /* major= */ 4,\n        /* minor= */ 29,\n        /* patch= */ 3,\n        /* suffix= */ \"\",\n        KuraPayload.class.getName());\n    }\n    // Use KuraPayload.newBuilder() to construct.\n    private KuraPayload(com.google.protobuf.GeneratedMessage.ExtendableBuilder<org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload, ?> builder) {\n      super(builder);\n    }\n    private KuraPayload() {\n      metric_ = java.util.Collections.emptyList();\n      body_ = com.google.protobuf.ByteString.EMPTY;\n    }\n\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor;\n    }\n\n    @java.lang.Override\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.Builder.class);\n    }\n\n    public interface KuraMetricOrBuilder extends\n        // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload.KuraMetric)\n        com.google.protobuf.MessageOrBuilder {\n\n      /**\n       * <code>required string name = 1;</code>\n       * @return Whether the name field is set.\n       */\n      boolean hasName();\n      /**\n       * <code>required string name = 1;</code>\n       * @return The name.\n       */\n      java.lang.String getName();\n      /**\n       * <code>required string name = 1;</code>\n       * @return The bytes for name.\n       */\n      com.google.protobuf.ByteString\n          getNameBytes();\n\n      /**\n       * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n       * @return Whether the type field is set.\n       */\n      boolean hasType();\n      /**\n       * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n       * @return The type.\n       */\n      org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType();\n\n      /**\n       * <code>optional double double_value = 3;</code>\n       * @return Whether the doubleValue field is set.\n       */\n      boolean hasDoubleValue();\n      /**\n       * <code>optional double double_value = 3;</code>\n       * @return The doubleValue.\n       */\n      double getDoubleValue();\n\n      /**\n       * <code>optional float float_value = 4;</code>\n       * @return Whether the floatValue field is set.\n       */\n      boolean hasFloatValue();\n      /**\n       * <code>optional float float_value = 4;</code>\n       * @return The floatValue.\n       */\n      float getFloatValue();\n\n      /**\n       * <code>optional int64 long_value = 5;</code>\n       * @return Whether the longValue field is set.\n       */\n      boolean hasLongValue();\n      /**\n       * <code>optional int64 long_value = 5;</code>\n       * @return The longValue.\n       */\n      long getLongValue();\n\n      /**\n       * <code>optional int32 int_value = 6;</code>\n       * @return Whether the intValue field is set.\n       */\n      boolean hasIntValue();\n      /**\n       * <code>optional int32 int_value = 6;</code>\n       * @return The intValue.\n       */\n      int getIntValue();\n\n      /**\n       * <code>optional bool bool_value = 7;</code>\n       * @return Whether the boolValue field is set.\n       */\n      boolean hasBoolValue();\n      /**\n       * <code>optional bool bool_value = 7;</code>\n       * @return The boolValue.\n       */\n      boolean getBoolValue();\n\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return Whether the stringValue field is set.\n       */\n      boolean hasStringValue();\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return The stringValue.\n       */\n      java.lang.String getStringValue();\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return The bytes for stringValue.\n       */\n      com.google.protobuf.ByteString\n          getStringValueBytes();\n\n      /**\n       * <code>optional bytes bytes_value = 9;</code>\n       * @return Whether the bytesValue field is set.\n       */\n      boolean hasBytesValue();\n      /**\n       * <code>optional bytes bytes_value = 9;</code>\n       * @return The bytesValue.\n       */\n      com.google.protobuf.ByteString getBytesValue();\n    }\n    /**\n     * Protobuf type {@code kuradatatypes.KuraPayload.KuraMetric}\n     */\n    public static final class KuraMetric extends\n        com.google.protobuf.GeneratedMessage implements\n        // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload.KuraMetric)\n        KuraMetricOrBuilder {\n    private static final long serialVersionUID = 0L;\n      static {\n        com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n          com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n          /* major= */ 4,\n          /* minor= */ 29,\n          /* patch= */ 3,\n          /* suffix= */ \"\",\n          KuraMetric.class.getName());\n      }\n      // Use KuraMetric.newBuilder() to construct.\n      private KuraMetric(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n        super(builder);\n      }\n      private KuraMetric() {\n        name_ = \"\";\n        type_ = 0;\n        stringValue_ = \"\";\n        bytesValue_ = com.google.protobuf.ByteString.EMPTY;\n      }\n\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder.class);\n      }\n\n      /**\n       * Protobuf enum {@code kuradatatypes.KuraPayload.KuraMetric.ValueType}\n       */\n      public enum ValueType\n          implements com.google.protobuf.ProtocolMessageEnum {\n        /**\n         * <code>DOUBLE = 0;</code>\n         */\n        DOUBLE(0),\n        /**\n         * <code>FLOAT = 1;</code>\n         */\n        FLOAT(1),\n        /**\n         * <code>INT64 = 2;</code>\n         */\n        INT64(2),\n        /**\n         * <code>INT32 = 3;</code>\n         */\n        INT32(3),\n        /**\n         * <code>BOOL = 4;</code>\n         */\n        BOOL(4),\n        /**\n         * <code>STRING = 5;</code>\n         */\n        STRING(5),\n        /**\n         * <code>BYTES = 6;</code>\n         */\n        BYTES(6),\n        ;\n\n        static {\n          com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n            com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n            /* major= */ 4,\n            /* minor= */ 29,\n            /* patch= */ 3,\n            /* suffix= */ \"\",\n            ValueType.class.getName());\n        }\n        /**\n         * <code>DOUBLE = 0;</code>\n         */\n        public static final int DOUBLE_VALUE = 0;\n        /**\n         * <code>FLOAT = 1;</code>\n         */\n        public static final int FLOAT_VALUE = 1;\n        /**\n         * <code>INT64 = 2;</code>\n         */\n        public static final int INT64_VALUE = 2;\n        /**\n         * <code>INT32 = 3;</code>\n         */\n        public static final int INT32_VALUE = 3;\n        /**\n         * <code>BOOL = 4;</code>\n         */\n        public static final int BOOL_VALUE = 4;\n        /**\n         * <code>STRING = 5;</code>\n         */\n        public static final int STRING_VALUE = 5;\n        /**\n         * <code>BYTES = 6;</code>\n         */\n        public static final int BYTES_VALUE = 6;\n\n\n        public final int getNumber() {\n          return value;\n        }\n\n        /**\n         * @param value The numeric wire value of the corresponding enum entry.\n         * @return The enum associated with the given numeric wire value.\n         * @deprecated Use {@link #forNumber(int)} instead.\n         */\n        @java.lang.Deprecated\n        public static ValueType valueOf(int value) {\n          return forNumber(value);\n        }\n\n        /**\n         * @param value The numeric wire value of the corresponding enum entry.\n         * @return The enum associated with the given numeric wire value.\n         */\n        public static ValueType forNumber(int value) {\n          switch (value) {\n            case 0: return DOUBLE;\n            case 1: return FLOAT;\n            case 2: return INT64;\n            case 3: return INT32;\n            case 4: return BOOL;\n            case 5: return STRING;\n            case 6: return BYTES;\n            default: return null;\n          }\n        }\n\n        public static com.google.protobuf.Internal.EnumLiteMap<ValueType>\n            internalGetValueMap() {\n          return internalValueMap;\n        }\n        private static final com.google.protobuf.Internal.EnumLiteMap<\n            ValueType> internalValueMap =\n              new com.google.protobuf.Internal.EnumLiteMap<ValueType>() {\n                public ValueType findValueByNumber(int number) {\n                  return ValueType.forNumber(number);\n                }\n              };\n\n        public final com.google.protobuf.Descriptors.EnumValueDescriptor\n            getValueDescriptor() {\n          return getDescriptor().getValues().get(ordinal());\n        }\n        public final com.google.protobuf.Descriptors.EnumDescriptor\n            getDescriptorForType() {\n          return getDescriptor();\n        }\n        public static final com.google.protobuf.Descriptors.EnumDescriptor\n            getDescriptor() {\n          return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDescriptor().getEnumTypes().get(0);\n        }\n\n        private static final ValueType[] VALUES = values();\n\n        public static ValueType valueOf(\n            com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n          if (desc.getType() != getDescriptor()) {\n            throw new java.lang.IllegalArgumentException(\n              \"EnumValueDescriptor is not for this type.\");\n          }\n          return VALUES[desc.getIndex()];\n        }\n\n        private final int value;\n\n        private ValueType(int value) {\n          this.value = value;\n        }\n\n        // @@protoc_insertion_point(enum_scope:kuradatatypes.KuraPayload.KuraMetric.ValueType)\n      }\n\n      private int bitField0_;\n      public static final int NAME_FIELD_NUMBER = 1;\n      @SuppressWarnings(\"serial\")\n      private volatile java.lang.Object name_ = \"\";\n      /**\n       * <code>required string name = 1;</code>\n       * @return Whether the name field is set.\n       */\n      @java.lang.Override\n      public boolean hasName() {\n        return ((bitField0_ & 0x00000001) != 0);\n      }\n      /**\n       * <code>required string name = 1;</code>\n       * @return The name.\n       */\n      @java.lang.Override\n      public java.lang.String getName() {\n        java.lang.Object ref = name_;\n        if (ref instanceof java.lang.String) {\n          return (java.lang.String) ref;\n        } else {\n          com.google.protobuf.ByteString bs = \n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            name_ = s;\n          }\n          return s;\n        }\n      }\n      /**\n       * <code>required string name = 1;</code>\n       * @return The bytes for name.\n       */\n      @java.lang.Override\n      public com.google.protobuf.ByteString\n          getNameBytes() {\n        java.lang.Object ref = name_;\n        if (ref instanceof java.lang.String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          name_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n\n      public static final int TYPE_FIELD_NUMBER = 2;\n      private int type_ = 0;\n      /**\n       * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n       * @return Whether the type field is set.\n       */\n      @java.lang.Override public boolean hasType() {\n        return ((bitField0_ & 0x00000002) != 0);\n      }\n      /**\n       * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n       * @return The type.\n       */\n      @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType() {\n        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType result = org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(type_);\n        return result == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE : result;\n      }\n\n      public static final int DOUBLE_VALUE_FIELD_NUMBER = 3;\n      private double doubleValue_ = 0D;\n      /**\n       * <code>optional double double_value = 3;</code>\n       * @return Whether the doubleValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasDoubleValue() {\n        return ((bitField0_ & 0x00000004) != 0);\n      }\n      /**\n       * <code>optional double double_value = 3;</code>\n       * @return The doubleValue.\n       */\n      @java.lang.Override\n      public double getDoubleValue() {\n        return doubleValue_;\n      }\n\n      public static final int FLOAT_VALUE_FIELD_NUMBER = 4;\n      private float floatValue_ = 0F;\n      /**\n       * <code>optional float float_value = 4;</code>\n       * @return Whether the floatValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasFloatValue() {\n        return ((bitField0_ & 0x00000008) != 0);\n      }\n      /**\n       * <code>optional float float_value = 4;</code>\n       * @return The floatValue.\n       */\n      @java.lang.Override\n      public float getFloatValue() {\n        return floatValue_;\n      }\n\n      public static final int LONG_VALUE_FIELD_NUMBER = 5;\n      private long longValue_ = 0L;\n      /**\n       * <code>optional int64 long_value = 5;</code>\n       * @return Whether the longValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasLongValue() {\n        return ((bitField0_ & 0x00000010) != 0);\n      }\n      /**\n       * <code>optional int64 long_value = 5;</code>\n       * @return The longValue.\n       */\n      @java.lang.Override\n      public long getLongValue() {\n        return longValue_;\n      }\n\n      public static final int INT_VALUE_FIELD_NUMBER = 6;\n      private int intValue_ = 0;\n      /**\n       * <code>optional int32 int_value = 6;</code>\n       * @return Whether the intValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasIntValue() {\n        return ((bitField0_ & 0x00000020) != 0);\n      }\n      /**\n       * <code>optional int32 int_value = 6;</code>\n       * @return The intValue.\n       */\n      @java.lang.Override\n      public int getIntValue() {\n        return intValue_;\n      }\n\n      public static final int BOOL_VALUE_FIELD_NUMBER = 7;\n      private boolean boolValue_ = false;\n      /**\n       * <code>optional bool bool_value = 7;</code>\n       * @return Whether the boolValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasBoolValue() {\n        return ((bitField0_ & 0x00000040) != 0);\n      }\n      /**\n       * <code>optional bool bool_value = 7;</code>\n       * @return The boolValue.\n       */\n      @java.lang.Override\n      public boolean getBoolValue() {\n        return boolValue_;\n      }\n\n      public static final int STRING_VALUE_FIELD_NUMBER = 8;\n      @SuppressWarnings(\"serial\")\n      private volatile java.lang.Object stringValue_ = \"\";\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return Whether the stringValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasStringValue() {\n        return ((bitField0_ & 0x00000080) != 0);\n      }\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return The stringValue.\n       */\n      @java.lang.Override\n      public java.lang.String getStringValue() {\n        java.lang.Object ref = stringValue_;\n        if (ref instanceof java.lang.String) {\n          return (java.lang.String) ref;\n        } else {\n          com.google.protobuf.ByteString bs = \n              (com.google.protobuf.ByteString) ref;\n          java.lang.String s = bs.toStringUtf8();\n          if (bs.isValidUtf8()) {\n            stringValue_ = s;\n          }\n          return s;\n        }\n      }\n      /**\n       * <code>optional string string_value = 8;</code>\n       * @return The bytes for stringValue.\n       */\n      @java.lang.Override\n      public com.google.protobuf.ByteString\n          getStringValueBytes() {\n        java.lang.Object ref = stringValue_;\n        if (ref instanceof java.lang.String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          stringValue_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n\n      public static final int BYTES_VALUE_FIELD_NUMBER = 9;\n      private com.google.protobuf.ByteString bytesValue_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>optional bytes bytes_value = 9;</code>\n       * @return Whether the bytesValue field is set.\n       */\n      @java.lang.Override\n      public boolean hasBytesValue() {\n        return ((bitField0_ & 0x00000100) != 0);\n      }\n      /**\n       * <code>optional bytes bytes_value = 9;</code>\n       * @return The bytesValue.\n       */\n      @java.lang.Override\n      public com.google.protobuf.ByteString getBytesValue() {\n        return bytesValue_;\n      }\n\n      private byte memoizedIsInitialized = -1;\n      @java.lang.Override\n      public final boolean isInitialized() {\n        byte isInitialized = memoizedIsInitialized;\n        if (isInitialized == 1) return true;\n        if (isInitialized == 0) return false;\n\n        if (!hasName()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n        if (!hasType()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n        memoizedIsInitialized = 1;\n        return true;\n      }\n\n      @java.lang.Override\n      public void writeTo(com.google.protobuf.CodedOutputStream output)\n                          throws java.io.IOException {\n        if (((bitField0_ & 0x00000001) != 0)) {\n          com.google.protobuf.GeneratedMessage.writeString(output, 1, name_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n          output.writeEnum(2, type_);\n        }\n        if (((bitField0_ & 0x00000004) != 0)) {\n          output.writeDouble(3, doubleValue_);\n        }\n        if (((bitField0_ & 0x00000008) != 0)) {\n          output.writeFloat(4, floatValue_);\n        }\n        if (((bitField0_ & 0x00000010) != 0)) {\n          output.writeInt64(5, longValue_);\n        }\n        if (((bitField0_ & 0x00000020) != 0)) {\n          output.writeInt32(6, intValue_);\n        }\n        if (((bitField0_ & 0x00000040) != 0)) {\n          output.writeBool(7, boolValue_);\n        }\n        if (((bitField0_ & 0x00000080) != 0)) {\n          com.google.protobuf.GeneratedMessage.writeString(output, 8, stringValue_);\n        }\n        if (((bitField0_ & 0x00000100) != 0)) {\n          output.writeBytes(9, bytesValue_);\n        }\n        getUnknownFields().writeTo(output);\n      }\n\n      @java.lang.Override\n      public int getSerializedSize() {\n        int size = memoizedSize;\n        if (size != -1) return size;\n\n        size = 0;\n        if (((bitField0_ & 0x00000001) != 0)) {\n          size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeEnumSize(2, type_);\n        }\n        if (((bitField0_ & 0x00000004) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(3, doubleValue_);\n        }\n        if (((bitField0_ & 0x00000008) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeFloatSize(4, floatValue_);\n        }\n        if (((bitField0_ & 0x00000010) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt64Size(5, longValue_);\n        }\n        if (((bitField0_ & 0x00000020) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt32Size(6, intValue_);\n        }\n        if (((bitField0_ & 0x00000040) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeBoolSize(7, boolValue_);\n        }\n        if (((bitField0_ & 0x00000080) != 0)) {\n          size += com.google.protobuf.GeneratedMessage.computeStringSize(8, stringValue_);\n        }\n        if (((bitField0_ & 0x00000100) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeBytesSize(9, bytesValue_);\n        }\n        size += getUnknownFields().getSerializedSize();\n        memoizedSize = size;\n        return size;\n      }\n\n      @java.lang.Override\n      public boolean equals(final java.lang.Object obj) {\n        if (obj == this) {\n         return true;\n        }\n        if (!(obj instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric)) {\n          return super.equals(obj);\n        }\n        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric other = (org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric) obj;\n\n        if (hasName() != other.hasName()) return false;\n        if (hasName()) {\n          if (!getName()\n              .equals(other.getName())) return false;\n        }\n        if (hasType() != other.hasType()) return false;\n        if (hasType()) {\n          if (type_ != other.type_) return false;\n        }\n        if (hasDoubleValue() != other.hasDoubleValue()) return false;\n        if (hasDoubleValue()) {\n          if (java.lang.Double.doubleToLongBits(getDoubleValue())\n              != java.lang.Double.doubleToLongBits(\n                  other.getDoubleValue())) return false;\n        }\n        if (hasFloatValue() != other.hasFloatValue()) return false;\n        if (hasFloatValue()) {\n          if (java.lang.Float.floatToIntBits(getFloatValue())\n              != java.lang.Float.floatToIntBits(\n                  other.getFloatValue())) return false;\n        }\n        if (hasLongValue() != other.hasLongValue()) return false;\n        if (hasLongValue()) {\n          if (getLongValue()\n              != other.getLongValue()) return false;\n        }\n        if (hasIntValue() != other.hasIntValue()) return false;\n        if (hasIntValue()) {\n          if (getIntValue()\n              != other.getIntValue()) return false;\n        }\n        if (hasBoolValue() != other.hasBoolValue()) return false;\n        if (hasBoolValue()) {\n          if (getBoolValue()\n              != other.getBoolValue()) return false;\n        }\n        if (hasStringValue() != other.hasStringValue()) return false;\n        if (hasStringValue()) {\n          if (!getStringValue()\n              .equals(other.getStringValue())) return false;\n        }\n        if (hasBytesValue() != other.hasBytesValue()) return false;\n        if (hasBytesValue()) {\n          if (!getBytesValue()\n              .equals(other.getBytesValue())) return false;\n        }\n        if (!getUnknownFields().equals(other.getUnknownFields())) return false;\n        return true;\n      }\n\n      @java.lang.Override\n      public int hashCode() {\n        if (memoizedHashCode != 0) {\n          return memoizedHashCode;\n        }\n        int hash = 41;\n        hash = (19 * hash) + getDescriptor().hashCode();\n        if (hasName()) {\n          hash = (37 * hash) + NAME_FIELD_NUMBER;\n          hash = (53 * hash) + getName().hashCode();\n        }\n        if (hasType()) {\n          hash = (37 * hash) + TYPE_FIELD_NUMBER;\n          hash = (53 * hash) + type_;\n        }\n        if (hasDoubleValue()) {\n          hash = (37 * hash) + DOUBLE_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getDoubleValue()));\n        }\n        if (hasFloatValue()) {\n          hash = (37 * hash) + FLOAT_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + java.lang.Float.floatToIntBits(\n              getFloatValue());\n        }\n        if (hasLongValue()) {\n          hash = (37 * hash) + LONG_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              getLongValue());\n        }\n        if (hasIntValue()) {\n          hash = (37 * hash) + INT_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + getIntValue();\n        }\n        if (hasBoolValue()) {\n          hash = (37 * hash) + BOOL_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean(\n              getBoolValue());\n        }\n        if (hasStringValue()) {\n          hash = (37 * hash) + STRING_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + getStringValue().hashCode();\n        }\n        if (hasBytesValue()) {\n          hash = (37 * hash) + BYTES_VALUE_FIELD_NUMBER;\n          hash = (53 * hash) + getBytesValue().hashCode();\n        }\n        hash = (29 * hash) + getUnknownFields().hashCode();\n        memoizedHashCode = hash;\n        return hash;\n      }\n\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          java.nio.ByteBuffer data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          java.nio.ByteBuffer data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          com.google.protobuf.ByteString data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          com.google.protobuf.ByteString data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(byte[] data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          byte[] data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(java.io.InputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          java.io.InputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input, extensionRegistry);\n      }\n\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseDelimitedFrom(java.io.InputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseDelimitedWithIOException(PARSER, input);\n      }\n\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseDelimitedFrom(\n          java.io.InputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          com.google.protobuf.CodedInputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input, extensionRegistry);\n      }\n\n      @java.lang.Override\n      public Builder newBuilderForType() { return newBuilder(); }\n      public static Builder newBuilder() {\n        return DEFAULT_INSTANCE.toBuilder();\n      }\n      public static Builder newBuilder(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric prototype) {\n        return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n      }\n      @java.lang.Override\n      public Builder toBuilder() {\n        return this == DEFAULT_INSTANCE\n            ? new Builder() : new Builder().mergeFrom(this);\n      }\n\n      @java.lang.Override\n      protected Builder newBuilderForType(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        Builder builder = new Builder(parent);\n        return builder;\n      }\n      /**\n       * Protobuf type {@code kuradatatypes.KuraPayload.KuraMetric}\n       */\n      public static final class Builder extends\n          com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n          // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload.KuraMetric)\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder {\n        public static final com.google.protobuf.Descriptors.Descriptor\n            getDescriptor() {\n          return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor;\n        }\n\n        @java.lang.Override\n        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n            internalGetFieldAccessorTable() {\n          return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable\n              .ensureFieldAccessorsInitialized(\n                  org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder.class);\n        }\n\n        // Construct using org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.newBuilder()\n        private Builder() {\n\n        }\n\n        private Builder(\n            com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n          super(parent);\n\n        }\n        @java.lang.Override\n        public Builder clear() {\n          super.clear();\n          bitField0_ = 0;\n          name_ = \"\";\n          type_ = 0;\n          doubleValue_ = 0D;\n          floatValue_ = 0F;\n          longValue_ = 0L;\n          intValue_ = 0;\n          boolValue_ = false;\n          stringValue_ = \"\";\n          bytesValue_ = com.google.protobuf.ByteString.EMPTY;\n          return this;\n        }\n\n        @java.lang.Override\n        public com.google.protobuf.Descriptors.Descriptor\n            getDescriptorForType() {\n          return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor;\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstanceForType() {\n          return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance();\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric build() {\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result = buildPartial();\n          if (!result.isInitialized()) {\n            throw newUninitializedMessageException(result);\n          }\n          return result;\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric buildPartial() {\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric(this);\n          if (bitField0_ != 0) { buildPartial0(result); }\n          onBuilt();\n          return result;\n        }\n\n        private void buildPartial0(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result) {\n          int from_bitField0_ = bitField0_;\n          int to_bitField0_ = 0;\n          if (((from_bitField0_ & 0x00000001) != 0)) {\n            result.name_ = name_;\n            to_bitField0_ |= 0x00000001;\n          }\n          if (((from_bitField0_ & 0x00000002) != 0)) {\n            result.type_ = type_;\n            to_bitField0_ |= 0x00000002;\n          }\n          if (((from_bitField0_ & 0x00000004) != 0)) {\n            result.doubleValue_ = doubleValue_;\n            to_bitField0_ |= 0x00000004;\n          }\n          if (((from_bitField0_ & 0x00000008) != 0)) {\n            result.floatValue_ = floatValue_;\n            to_bitField0_ |= 0x00000008;\n          }\n          if (((from_bitField0_ & 0x00000010) != 0)) {\n            result.longValue_ = longValue_;\n            to_bitField0_ |= 0x00000010;\n          }\n          if (((from_bitField0_ & 0x00000020) != 0)) {\n            result.intValue_ = intValue_;\n            to_bitField0_ |= 0x00000020;\n          }\n          if (((from_bitField0_ & 0x00000040) != 0)) {\n            result.boolValue_ = boolValue_;\n            to_bitField0_ |= 0x00000040;\n          }\n          if (((from_bitField0_ & 0x00000080) != 0)) {\n            result.stringValue_ = stringValue_;\n            to_bitField0_ |= 0x00000080;\n          }\n          if (((from_bitField0_ & 0x00000100) != 0)) {\n            result.bytesValue_ = bytesValue_;\n            to_bitField0_ |= 0x00000100;\n          }\n          result.bitField0_ |= to_bitField0_;\n        }\n\n        @java.lang.Override\n        public Builder mergeFrom(com.google.protobuf.Message other) {\n          if (other instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric) {\n            return mergeFrom((org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric)other);\n          } else {\n            super.mergeFrom(other);\n            return this;\n          }\n        }\n\n        public Builder mergeFrom(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric other) {\n          if (other == org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance()) return this;\n          if (other.hasName()) {\n            name_ = other.name_;\n            bitField0_ |= 0x00000001;\n            onChanged();\n          }\n          if (other.hasType()) {\n            setType(other.getType());\n          }\n          if (other.hasDoubleValue()) {\n            setDoubleValue(other.getDoubleValue());\n          }\n          if (other.hasFloatValue()) {\n            setFloatValue(other.getFloatValue());\n          }\n          if (other.hasLongValue()) {\n            setLongValue(other.getLongValue());\n          }\n          if (other.hasIntValue()) {\n            setIntValue(other.getIntValue());\n          }\n          if (other.hasBoolValue()) {\n            setBoolValue(other.getBoolValue());\n          }\n          if (other.hasStringValue()) {\n            stringValue_ = other.stringValue_;\n            bitField0_ |= 0x00000080;\n            onChanged();\n          }\n          if (other.hasBytesValue()) {\n            setBytesValue(other.getBytesValue());\n          }\n          this.mergeUnknownFields(other.getUnknownFields());\n          onChanged();\n          return this;\n        }\n\n        @java.lang.Override\n        public final boolean isInitialized() {\n          if (!hasName()) {\n            return false;\n          }\n          if (!hasType()) {\n            return false;\n          }\n          return true;\n        }\n\n        @java.lang.Override\n        public Builder mergeFrom(\n            com.google.protobuf.CodedInputStream input,\n            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n          if (extensionRegistry == null) {\n            throw new java.lang.NullPointerException();\n          }\n          try {\n            boolean done = false;\n            while (!done) {\n              int tag = input.readTag();\n              switch (tag) {\n                case 0:\n                  done = true;\n                  break;\n                case 10: {\n                  name_ = input.readBytes();\n                  bitField0_ |= 0x00000001;\n                  break;\n                } // case 10\n                case 16: {\n                  int tmpRaw = input.readEnum();\n                  org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType tmpValue =\n                      org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(tmpRaw);\n                  if (tmpValue == null) {\n                    mergeUnknownVarintField(2, tmpRaw);\n                  } else {\n                    type_ = tmpRaw;\n                    bitField0_ |= 0x00000002;\n                  }\n                  break;\n                } // case 16\n                case 25: {\n                  doubleValue_ = input.readDouble();\n                  bitField0_ |= 0x00000004;\n                  break;\n                } // case 25\n                case 37: {\n                  floatValue_ = input.readFloat();\n                  bitField0_ |= 0x00000008;\n                  break;\n                } // case 37\n                case 40: {\n                  longValue_ = input.readInt64();\n                  bitField0_ |= 0x00000010;\n                  break;\n                } // case 40\n                case 48: {\n                  intValue_ = input.readInt32();\n                  bitField0_ |= 0x00000020;\n                  break;\n                } // case 48\n                case 56: {\n                  boolValue_ = input.readBool();\n                  bitField0_ |= 0x00000040;\n                  break;\n                } // case 56\n                case 66: {\n                  stringValue_ = input.readBytes();\n                  bitField0_ |= 0x00000080;\n                  break;\n                } // case 66\n                case 74: {\n                  bytesValue_ = input.readBytes();\n                  bitField0_ |= 0x00000100;\n                  break;\n                } // case 74\n                default: {\n                  if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                    done = true; // was an endgroup tag\n                  }\n                  break;\n                } // default:\n              } // switch (tag)\n            } // while (!done)\n          } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n            throw e.unwrapIOException();\n          } finally {\n            onChanged();\n          } // finally\n          return this;\n        }\n        private int bitField0_;\n\n        private java.lang.Object name_ = \"\";\n        /**\n         * <code>required string name = 1;</code>\n         * @return Whether the name field is set.\n         */\n        public boolean hasName() {\n          return ((bitField0_ & 0x00000001) != 0);\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @return The name.\n         */\n        public java.lang.String getName() {\n          java.lang.Object ref = name_;\n          if (!(ref instanceof java.lang.String)) {\n            com.google.protobuf.ByteString bs =\n                (com.google.protobuf.ByteString) ref;\n            java.lang.String s = bs.toStringUtf8();\n            if (bs.isValidUtf8()) {\n              name_ = s;\n            }\n            return s;\n          } else {\n            return (java.lang.String) ref;\n          }\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @return The bytes for name.\n         */\n        public com.google.protobuf.ByteString\n            getNameBytes() {\n          java.lang.Object ref = name_;\n          if (ref instanceof String) {\n            com.google.protobuf.ByteString b = \n                com.google.protobuf.ByteString.copyFromUtf8(\n                    (java.lang.String) ref);\n            name_ = b;\n            return b;\n          } else {\n            return (com.google.protobuf.ByteString) ref;\n          }\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @param value The name to set.\n         * @return This builder for chaining.\n         */\n        public Builder setName(\n            java.lang.String value) {\n          if (value == null) { throw new NullPointerException(); }\n          name_ = value;\n          bitField0_ |= 0x00000001;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearName() {\n          name_ = getDefaultInstance().getName();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required string name = 1;</code>\n         * @param value The bytes for name to set.\n         * @return This builder for chaining.\n         */\n        public Builder setNameBytes(\n            com.google.protobuf.ByteString value) {\n          if (value == null) { throw new NullPointerException(); }\n          name_ = value;\n          bitField0_ |= 0x00000001;\n          onChanged();\n          return this;\n        }\n\n        private int type_ = 0;\n        /**\n         * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n         * @return Whether the type field is set.\n         */\n        @java.lang.Override public boolean hasType() {\n          return ((bitField0_ & 0x00000002) != 0);\n        }\n        /**\n         * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n         * @return The type.\n         */\n        @java.lang.Override\n        public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType() {\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType result = org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(type_);\n          return result == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE : result;\n        }\n        /**\n         * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n         * @param value The type to set.\n         * @return This builder for chaining.\n         */\n        public Builder setType(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType value) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          bitField0_ |= 0x00000002;\n          type_ = value.getNumber();\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearType() {\n          bitField0_ = (bitField0_ & ~0x00000002);\n          type_ = 0;\n          onChanged();\n          return this;\n        }\n\n        private double doubleValue_ ;\n        /**\n         * <code>optional double double_value = 3;</code>\n         * @return Whether the doubleValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasDoubleValue() {\n          return ((bitField0_ & 0x00000004) != 0);\n        }\n        /**\n         * <code>optional double double_value = 3;</code>\n         * @return The doubleValue.\n         */\n        @java.lang.Override\n        public double getDoubleValue() {\n          return doubleValue_;\n        }\n        /**\n         * <code>optional double double_value = 3;</code>\n         * @param value The doubleValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setDoubleValue(double value) {\n\n          doubleValue_ = value;\n          bitField0_ |= 0x00000004;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional double double_value = 3;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearDoubleValue() {\n          bitField0_ = (bitField0_ & ~0x00000004);\n          doubleValue_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private float floatValue_ ;\n        /**\n         * <code>optional float float_value = 4;</code>\n         * @return Whether the floatValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasFloatValue() {\n          return ((bitField0_ & 0x00000008) != 0);\n        }\n        /**\n         * <code>optional float float_value = 4;</code>\n         * @return The floatValue.\n         */\n        @java.lang.Override\n        public float getFloatValue() {\n          return floatValue_;\n        }\n        /**\n         * <code>optional float float_value = 4;</code>\n         * @param value The floatValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setFloatValue(float value) {\n\n          floatValue_ = value;\n          bitField0_ |= 0x00000008;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional float float_value = 4;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearFloatValue() {\n          bitField0_ = (bitField0_ & ~0x00000008);\n          floatValue_ = 0F;\n          onChanged();\n          return this;\n        }\n\n        private long longValue_ ;\n        /**\n         * <code>optional int64 long_value = 5;</code>\n         * @return Whether the longValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasLongValue() {\n          return ((bitField0_ & 0x00000010) != 0);\n        }\n        /**\n         * <code>optional int64 long_value = 5;</code>\n         * @return The longValue.\n         */\n        @java.lang.Override\n        public long getLongValue() {\n          return longValue_;\n        }\n        /**\n         * <code>optional int64 long_value = 5;</code>\n         * @param value The longValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setLongValue(long value) {\n\n          longValue_ = value;\n          bitField0_ |= 0x00000010;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional int64 long_value = 5;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearLongValue() {\n          bitField0_ = (bitField0_ & ~0x00000010);\n          longValue_ = 0L;\n          onChanged();\n          return this;\n        }\n\n        private int intValue_ ;\n        /**\n         * <code>optional int32 int_value = 6;</code>\n         * @return Whether the intValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasIntValue() {\n          return ((bitField0_ & 0x00000020) != 0);\n        }\n        /**\n         * <code>optional int32 int_value = 6;</code>\n         * @return The intValue.\n         */\n        @java.lang.Override\n        public int getIntValue() {\n          return intValue_;\n        }\n        /**\n         * <code>optional int32 int_value = 6;</code>\n         * @param value The intValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setIntValue(int value) {\n\n          intValue_ = value;\n          bitField0_ |= 0x00000020;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional int32 int_value = 6;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearIntValue() {\n          bitField0_ = (bitField0_ & ~0x00000020);\n          intValue_ = 0;\n          onChanged();\n          return this;\n        }\n\n        private boolean boolValue_ ;\n        /**\n         * <code>optional bool bool_value = 7;</code>\n         * @return Whether the boolValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasBoolValue() {\n          return ((bitField0_ & 0x00000040) != 0);\n        }\n        /**\n         * <code>optional bool bool_value = 7;</code>\n         * @return The boolValue.\n         */\n        @java.lang.Override\n        public boolean getBoolValue() {\n          return boolValue_;\n        }\n        /**\n         * <code>optional bool bool_value = 7;</code>\n         * @param value The boolValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setBoolValue(boolean value) {\n\n          boolValue_ = value;\n          bitField0_ |= 0x00000040;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional bool bool_value = 7;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearBoolValue() {\n          bitField0_ = (bitField0_ & ~0x00000040);\n          boolValue_ = false;\n          onChanged();\n          return this;\n        }\n\n        private java.lang.Object stringValue_ = \"\";\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @return Whether the stringValue field is set.\n         */\n        public boolean hasStringValue() {\n          return ((bitField0_ & 0x00000080) != 0);\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @return The stringValue.\n         */\n        public java.lang.String getStringValue() {\n          java.lang.Object ref = stringValue_;\n          if (!(ref instanceof java.lang.String)) {\n            com.google.protobuf.ByteString bs =\n                (com.google.protobuf.ByteString) ref;\n            java.lang.String s = bs.toStringUtf8();\n            if (bs.isValidUtf8()) {\n              stringValue_ = s;\n            }\n            return s;\n          } else {\n            return (java.lang.String) ref;\n          }\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @return The bytes for stringValue.\n         */\n        public com.google.protobuf.ByteString\n            getStringValueBytes() {\n          java.lang.Object ref = stringValue_;\n          if (ref instanceof String) {\n            com.google.protobuf.ByteString b = \n                com.google.protobuf.ByteString.copyFromUtf8(\n                    (java.lang.String) ref);\n            stringValue_ = b;\n            return b;\n          } else {\n            return (com.google.protobuf.ByteString) ref;\n          }\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @param value The stringValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setStringValue(\n            java.lang.String value) {\n          if (value == null) { throw new NullPointerException(); }\n          stringValue_ = value;\n          bitField0_ |= 0x00000080;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearStringValue() {\n          stringValue_ = getDefaultInstance().getStringValue();\n          bitField0_ = (bitField0_ & ~0x00000080);\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional string string_value = 8;</code>\n         * @param value The bytes for stringValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setStringValueBytes(\n            com.google.protobuf.ByteString value) {\n          if (value == null) { throw new NullPointerException(); }\n          stringValue_ = value;\n          bitField0_ |= 0x00000080;\n          onChanged();\n          return this;\n        }\n\n        private com.google.protobuf.ByteString bytesValue_ = com.google.protobuf.ByteString.EMPTY;\n        /**\n         * <code>optional bytes bytes_value = 9;</code>\n         * @return Whether the bytesValue field is set.\n         */\n        @java.lang.Override\n        public boolean hasBytesValue() {\n          return ((bitField0_ & 0x00000100) != 0);\n        }\n        /**\n         * <code>optional bytes bytes_value = 9;</code>\n         * @return The bytesValue.\n         */\n        @java.lang.Override\n        public com.google.protobuf.ByteString getBytesValue() {\n          return bytesValue_;\n        }\n        /**\n         * <code>optional bytes bytes_value = 9;</code>\n         * @param value The bytesValue to set.\n         * @return This builder for chaining.\n         */\n        public Builder setBytesValue(com.google.protobuf.ByteString value) {\n          if (value == null) { throw new NullPointerException(); }\n          bytesValue_ = value;\n          bitField0_ |= 0x00000100;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional bytes bytes_value = 9;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearBytesValue() {\n          bitField0_ = (bitField0_ & ~0x00000100);\n          bytesValue_ = getDefaultInstance().getBytesValue();\n          onChanged();\n          return this;\n        }\n\n        // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload.KuraMetric)\n      }\n\n      // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload.KuraMetric)\n      private static final org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric DEFAULT_INSTANCE;\n      static {\n        DEFAULT_INSTANCE = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric();\n      }\n\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstance() {\n        return DEFAULT_INSTANCE;\n      }\n\n      private static final com.google.protobuf.Parser<KuraMetric>\n          PARSER = new com.google.protobuf.AbstractParser<KuraMetric>() {\n        @java.lang.Override\n        public KuraMetric parsePartialFrom(\n            com.google.protobuf.CodedInputStream input,\n            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n          Builder builder = newBuilder();\n          try {\n            builder.mergeFrom(input, extensionRegistry);\n          } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n            throw e.setUnfinishedMessage(builder.buildPartial());\n          } catch (com.google.protobuf.UninitializedMessageException e) {\n            throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n          } catch (java.io.IOException e) {\n            throw new com.google.protobuf.InvalidProtocolBufferException(e)\n                .setUnfinishedMessage(builder.buildPartial());\n          }\n          return builder.buildPartial();\n        }\n      };\n\n      public static com.google.protobuf.Parser<KuraMetric> parser() {\n        return PARSER;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Parser<KuraMetric> getParserForType() {\n        return PARSER;\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstanceForType() {\n        return DEFAULT_INSTANCE;\n      }\n\n    }\n\n    public interface KuraPositionOrBuilder extends\n        // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload.KuraPosition)\n        com.google.protobuf.MessageOrBuilder {\n\n      /**\n       * <code>required double latitude = 1;</code>\n       * @return Whether the latitude field is set.\n       */\n      boolean hasLatitude();\n      /**\n       * <code>required double latitude = 1;</code>\n       * @return The latitude.\n       */\n      double getLatitude();\n\n      /**\n       * <code>required double longitude = 2;</code>\n       * @return Whether the longitude field is set.\n       */\n      boolean hasLongitude();\n      /**\n       * <code>required double longitude = 2;</code>\n       * @return The longitude.\n       */\n      double getLongitude();\n\n      /**\n       * <code>optional double altitude = 3;</code>\n       * @return Whether the altitude field is set.\n       */\n      boolean hasAltitude();\n      /**\n       * <code>optional double altitude = 3;</code>\n       * @return The altitude.\n       */\n      double getAltitude();\n\n      /**\n       * <pre>\n       * dilution of precision of the current satellite fix. \n       * </pre>\n       *\n       * <code>optional double precision = 4;</code>\n       * @return Whether the precision field is set.\n       */\n      boolean hasPrecision();\n      /**\n       * <pre>\n       * dilution of precision of the current satellite fix. \n       * </pre>\n       *\n       * <code>optional double precision = 4;</code>\n       * @return The precision.\n       */\n      double getPrecision();\n\n      /**\n       * <pre>\n       * heading in degrees\n       * </pre>\n       *\n       * <code>optional double heading = 5;</code>\n       * @return Whether the heading field is set.\n       */\n      boolean hasHeading();\n      /**\n       * <pre>\n       * heading in degrees\n       * </pre>\n       *\n       * <code>optional double heading = 5;</code>\n       * @return The heading.\n       */\n      double getHeading();\n\n      /**\n       * <pre>\n       * meters per second\n       * </pre>\n       *\n       * <code>optional double speed = 6;</code>\n       * @return Whether the speed field is set.\n       */\n      boolean hasSpeed();\n      /**\n       * <pre>\n       * meters per second\n       * </pre>\n       *\n       * <code>optional double speed = 6;</code>\n       * @return The speed.\n       */\n      double getSpeed();\n\n      /**\n       * <code>optional int64 timestamp = 7;</code>\n       * @return Whether the timestamp field is set.\n       */\n      boolean hasTimestamp();\n      /**\n       * <code>optional int64 timestamp = 7;</code>\n       * @return The timestamp.\n       */\n      long getTimestamp();\n\n      /**\n       * <pre>\n       * number satellites locked by the GPS device\n       * </pre>\n       *\n       * <code>optional int32 satellites = 8;</code>\n       * @return Whether the satellites field is set.\n       */\n      boolean hasSatellites();\n      /**\n       * <pre>\n       * number satellites locked by the GPS device\n       * </pre>\n       *\n       * <code>optional int32 satellites = 8;</code>\n       * @return The satellites.\n       */\n      int getSatellites();\n\n      /**\n       * <pre>\n       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n       * </pre>\n       *\n       * <code>optional int32 status = 9;</code>\n       * @return Whether the status field is set.\n       */\n      boolean hasStatus();\n      /**\n       * <pre>\n       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n       * </pre>\n       *\n       * <code>optional int32 status = 9;</code>\n       * @return The status.\n       */\n      int getStatus();\n    }\n    /**\n     * Protobuf type {@code kuradatatypes.KuraPayload.KuraPosition}\n     */\n    public static final class KuraPosition extends\n        com.google.protobuf.GeneratedMessage implements\n        // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload.KuraPosition)\n        KuraPositionOrBuilder {\n    private static final long serialVersionUID = 0L;\n      static {\n        com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(\n          com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,\n          /* major= */ 4,\n          /* minor= */ 29,\n          /* patch= */ 3,\n          /* suffix= */ \"\",\n          KuraPosition.class.getName());\n      }\n      // Use KuraPosition.newBuilder() to construct.\n      private KuraPosition(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n        super(builder);\n      }\n      private KuraPosition() {\n      }\n\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder.class);\n      }\n\n      private int bitField0_;\n      public static final int LATITUDE_FIELD_NUMBER = 1;\n      private double latitude_ = 0D;\n      /**\n       * <code>required double latitude = 1;</code>\n       * @return Whether the latitude field is set.\n       */\n      @java.lang.Override\n      public boolean hasLatitude() {\n        return ((bitField0_ & 0x00000001) != 0);\n      }\n      /**\n       * <code>required double latitude = 1;</code>\n       * @return The latitude.\n       */\n      @java.lang.Override\n      public double getLatitude() {\n        return latitude_;\n      }\n\n      public static final int LONGITUDE_FIELD_NUMBER = 2;\n      private double longitude_ = 0D;\n      /**\n       * <code>required double longitude = 2;</code>\n       * @return Whether the longitude field is set.\n       */\n      @java.lang.Override\n      public boolean hasLongitude() {\n        return ((bitField0_ & 0x00000002) != 0);\n      }\n      /**\n       * <code>required double longitude = 2;</code>\n       * @return The longitude.\n       */\n      @java.lang.Override\n      public double getLongitude() {\n        return longitude_;\n      }\n\n      public static final int ALTITUDE_FIELD_NUMBER = 3;\n      private double altitude_ = 0D;\n      /**\n       * <code>optional double altitude = 3;</code>\n       * @return Whether the altitude field is set.\n       */\n      @java.lang.Override\n      public boolean hasAltitude() {\n        return ((bitField0_ & 0x00000004) != 0);\n      }\n      /**\n       * <code>optional double altitude = 3;</code>\n       * @return The altitude.\n       */\n      @java.lang.Override\n      public double getAltitude() {\n        return altitude_;\n      }\n\n      public static final int PRECISION_FIELD_NUMBER = 4;\n      private double precision_ = 0D;\n      /**\n       * <pre>\n       * dilution of precision of the current satellite fix. \n       * </pre>\n       *\n       * <code>optional double precision = 4;</code>\n       * @return Whether the precision field is set.\n       */\n      @java.lang.Override\n      public boolean hasPrecision() {\n        return ((bitField0_ & 0x00000008) != 0);\n      }\n      /**\n       * <pre>\n       * dilution of precision of the current satellite fix. \n       * </pre>\n       *\n       * <code>optional double precision = 4;</code>\n       * @return The precision.\n       */\n      @java.lang.Override\n      public double getPrecision() {\n        return precision_;\n      }\n\n      public static final int HEADING_FIELD_NUMBER = 5;\n      private double heading_ = 0D;\n      /**\n       * <pre>\n       * heading in degrees\n       * </pre>\n       *\n       * <code>optional double heading = 5;</code>\n       * @return Whether the heading field is set.\n       */\n      @java.lang.Override\n      public boolean hasHeading() {\n        return ((bitField0_ & 0x00000010) != 0);\n      }\n      /**\n       * <pre>\n       * heading in degrees\n       * </pre>\n       *\n       * <code>optional double heading = 5;</code>\n       * @return The heading.\n       */\n      @java.lang.Override\n      public double getHeading() {\n        return heading_;\n      }\n\n      public static final int SPEED_FIELD_NUMBER = 6;\n      private double speed_ = 0D;\n      /**\n       * <pre>\n       * meters per second\n       * </pre>\n       *\n       * <code>optional double speed = 6;</code>\n       * @return Whether the speed field is set.\n       */\n      @java.lang.Override\n      public boolean hasSpeed() {\n        return ((bitField0_ & 0x00000020) != 0);\n      }\n      /**\n       * <pre>\n       * meters per second\n       * </pre>\n       *\n       * <code>optional double speed = 6;</code>\n       * @return The speed.\n       */\n      @java.lang.Override\n      public double getSpeed() {\n        return speed_;\n      }\n\n      public static final int TIMESTAMP_FIELD_NUMBER = 7;\n      private long timestamp_ = 0L;\n      /**\n       * <code>optional int64 timestamp = 7;</code>\n       * @return Whether the timestamp field is set.\n       */\n      @java.lang.Override\n      public boolean hasTimestamp() {\n        return ((bitField0_ & 0x00000040) != 0);\n      }\n      /**\n       * <code>optional int64 timestamp = 7;</code>\n       * @return The timestamp.\n       */\n      @java.lang.Override\n      public long getTimestamp() {\n        return timestamp_;\n      }\n\n      public static final int SATELLITES_FIELD_NUMBER = 8;\n      private int satellites_ = 0;\n      /**\n       * <pre>\n       * number satellites locked by the GPS device\n       * </pre>\n       *\n       * <code>optional int32 satellites = 8;</code>\n       * @return Whether the satellites field is set.\n       */\n      @java.lang.Override\n      public boolean hasSatellites() {\n        return ((bitField0_ & 0x00000080) != 0);\n      }\n      /**\n       * <pre>\n       * number satellites locked by the GPS device\n       * </pre>\n       *\n       * <code>optional int32 satellites = 8;</code>\n       * @return The satellites.\n       */\n      @java.lang.Override\n      public int getSatellites() {\n        return satellites_;\n      }\n\n      public static final int STATUS_FIELD_NUMBER = 9;\n      private int status_ = 0;\n      /**\n       * <pre>\n       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n       * </pre>\n       *\n       * <code>optional int32 status = 9;</code>\n       * @return Whether the status field is set.\n       */\n      @java.lang.Override\n      public boolean hasStatus() {\n        return ((bitField0_ & 0x00000100) != 0);\n      }\n      /**\n       * <pre>\n       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n       * </pre>\n       *\n       * <code>optional int32 status = 9;</code>\n       * @return The status.\n       */\n      @java.lang.Override\n      public int getStatus() {\n        return status_;\n      }\n\n      private byte memoizedIsInitialized = -1;\n      @java.lang.Override\n      public final boolean isInitialized() {\n        byte isInitialized = memoizedIsInitialized;\n        if (isInitialized == 1) return true;\n        if (isInitialized == 0) return false;\n\n        if (!hasLatitude()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n        if (!hasLongitude()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n        memoizedIsInitialized = 1;\n        return true;\n      }\n\n      @java.lang.Override\n      public void writeTo(com.google.protobuf.CodedOutputStream output)\n                          throws java.io.IOException {\n        if (((bitField0_ & 0x00000001) != 0)) {\n          output.writeDouble(1, latitude_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n          output.writeDouble(2, longitude_);\n        }\n        if (((bitField0_ & 0x00000004) != 0)) {\n          output.writeDouble(3, altitude_);\n        }\n        if (((bitField0_ & 0x00000008) != 0)) {\n          output.writeDouble(4, precision_);\n        }\n        if (((bitField0_ & 0x00000010) != 0)) {\n          output.writeDouble(5, heading_);\n        }\n        if (((bitField0_ & 0x00000020) != 0)) {\n          output.writeDouble(6, speed_);\n        }\n        if (((bitField0_ & 0x00000040) != 0)) {\n          output.writeInt64(7, timestamp_);\n        }\n        if (((bitField0_ & 0x00000080) != 0)) {\n          output.writeInt32(8, satellites_);\n        }\n        if (((bitField0_ & 0x00000100) != 0)) {\n          output.writeInt32(9, status_);\n        }\n        getUnknownFields().writeTo(output);\n      }\n\n      @java.lang.Override\n      public int getSerializedSize() {\n        int size = memoizedSize;\n        if (size != -1) return size;\n\n        size = 0;\n        if (((bitField0_ & 0x00000001) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(1, latitude_);\n        }\n        if (((bitField0_ & 0x00000002) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(2, longitude_);\n        }\n        if (((bitField0_ & 0x00000004) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(3, altitude_);\n        }\n        if (((bitField0_ & 0x00000008) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(4, precision_);\n        }\n        if (((bitField0_ & 0x00000010) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(5, heading_);\n        }\n        if (((bitField0_ & 0x00000020) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeDoubleSize(6, speed_);\n        }\n        if (((bitField0_ & 0x00000040) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt64Size(7, timestamp_);\n        }\n        if (((bitField0_ & 0x00000080) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt32Size(8, satellites_);\n        }\n        if (((bitField0_ & 0x00000100) != 0)) {\n          size += com.google.protobuf.CodedOutputStream\n            .computeInt32Size(9, status_);\n        }\n        size += getUnknownFields().getSerializedSize();\n        memoizedSize = size;\n        return size;\n      }\n\n      @java.lang.Override\n      public boolean equals(final java.lang.Object obj) {\n        if (obj == this) {\n         return true;\n        }\n        if (!(obj instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition)) {\n          return super.equals(obj);\n        }\n        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition other = (org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition) obj;\n\n        if (hasLatitude() != other.hasLatitude()) return false;\n        if (hasLatitude()) {\n          if (java.lang.Double.doubleToLongBits(getLatitude())\n              != java.lang.Double.doubleToLongBits(\n                  other.getLatitude())) return false;\n        }\n        if (hasLongitude() != other.hasLongitude()) return false;\n        if (hasLongitude()) {\n          if (java.lang.Double.doubleToLongBits(getLongitude())\n              != java.lang.Double.doubleToLongBits(\n                  other.getLongitude())) return false;\n        }\n        if (hasAltitude() != other.hasAltitude()) return false;\n        if (hasAltitude()) {\n          if (java.lang.Double.doubleToLongBits(getAltitude())\n              != java.lang.Double.doubleToLongBits(\n                  other.getAltitude())) return false;\n        }\n        if (hasPrecision() != other.hasPrecision()) return false;\n        if (hasPrecision()) {\n          if (java.lang.Double.doubleToLongBits(getPrecision())\n              != java.lang.Double.doubleToLongBits(\n                  other.getPrecision())) return false;\n        }\n        if (hasHeading() != other.hasHeading()) return false;\n        if (hasHeading()) {\n          if (java.lang.Double.doubleToLongBits(getHeading())\n              != java.lang.Double.doubleToLongBits(\n                  other.getHeading())) return false;\n        }\n        if (hasSpeed() != other.hasSpeed()) return false;\n        if (hasSpeed()) {\n          if (java.lang.Double.doubleToLongBits(getSpeed())\n              != java.lang.Double.doubleToLongBits(\n                  other.getSpeed())) return false;\n        }\n        if (hasTimestamp() != other.hasTimestamp()) return false;\n        if (hasTimestamp()) {\n          if (getTimestamp()\n              != other.getTimestamp()) return false;\n        }\n        if (hasSatellites() != other.hasSatellites()) return false;\n        if (hasSatellites()) {\n          if (getSatellites()\n              != other.getSatellites()) return false;\n        }\n        if (hasStatus() != other.hasStatus()) return false;\n        if (hasStatus()) {\n          if (getStatus()\n              != other.getStatus()) return false;\n        }\n        if (!getUnknownFields().equals(other.getUnknownFields())) return false;\n        return true;\n      }\n\n      @java.lang.Override\n      public int hashCode() {\n        if (memoizedHashCode != 0) {\n          return memoizedHashCode;\n        }\n        int hash = 41;\n        hash = (19 * hash) + getDescriptor().hashCode();\n        if (hasLatitude()) {\n          hash = (37 * hash) + LATITUDE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getLatitude()));\n        }\n        if (hasLongitude()) {\n          hash = (37 * hash) + LONGITUDE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getLongitude()));\n        }\n        if (hasAltitude()) {\n          hash = (37 * hash) + ALTITUDE_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getAltitude()));\n        }\n        if (hasPrecision()) {\n          hash = (37 * hash) + PRECISION_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getPrecision()));\n        }\n        if (hasHeading()) {\n          hash = (37 * hash) + HEADING_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getHeading()));\n        }\n        if (hasSpeed()) {\n          hash = (37 * hash) + SPEED_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              java.lang.Double.doubleToLongBits(getSpeed()));\n        }\n        if (hasTimestamp()) {\n          hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER;\n          hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n              getTimestamp());\n        }\n        if (hasSatellites()) {\n          hash = (37 * hash) + SATELLITES_FIELD_NUMBER;\n          hash = (53 * hash) + getSatellites();\n        }\n        if (hasStatus()) {\n          hash = (37 * hash) + STATUS_FIELD_NUMBER;\n          hash = (53 * hash) + getStatus();\n        }\n        hash = (29 * hash) + getUnknownFields().hashCode();\n        memoizedHashCode = hash;\n        return hash;\n      }\n\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          java.nio.ByteBuffer data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          java.nio.ByteBuffer data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          com.google.protobuf.ByteString data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          com.google.protobuf.ByteString data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(byte[] data)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          byte[] data,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return PARSER.parseFrom(data, extensionRegistry);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(java.io.InputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          java.io.InputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input, extensionRegistry);\n      }\n\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseDelimitedFrom(java.io.InputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseDelimitedWithIOException(PARSER, input);\n      }\n\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseDelimitedFrom(\n          java.io.InputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          com.google.protobuf.CodedInputStream input)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input);\n      }\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        return com.google.protobuf.GeneratedMessage\n            .parseWithIOException(PARSER, input, extensionRegistry);\n      }\n\n      @java.lang.Override\n      public Builder newBuilderForType() { return newBuilder(); }\n      public static Builder newBuilder() {\n        return DEFAULT_INSTANCE.toBuilder();\n      }\n      public static Builder newBuilder(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition prototype) {\n        return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n      }\n      @java.lang.Override\n      public Builder toBuilder() {\n        return this == DEFAULT_INSTANCE\n            ? new Builder() : new Builder().mergeFrom(this);\n      }\n\n      @java.lang.Override\n      protected Builder newBuilderForType(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        Builder builder = new Builder(parent);\n        return builder;\n      }\n      /**\n       * Protobuf type {@code kuradatatypes.KuraPayload.KuraPosition}\n       */\n      public static final class Builder extends\n          com.google.protobuf.GeneratedMessage.Builder<Builder> implements\n          // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload.KuraPosition)\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder {\n        public static final com.google.protobuf.Descriptors.Descriptor\n            getDescriptor() {\n          return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor;\n        }\n\n        @java.lang.Override\n        protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n            internalGetFieldAccessorTable() {\n          return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable\n              .ensureFieldAccessorsInitialized(\n                  org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder.class);\n        }\n\n        // Construct using org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.newBuilder()\n        private Builder() {\n\n        }\n\n        private Builder(\n            com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n          super(parent);\n\n        }\n        @java.lang.Override\n        public Builder clear() {\n          super.clear();\n          bitField0_ = 0;\n          latitude_ = 0D;\n          longitude_ = 0D;\n          altitude_ = 0D;\n          precision_ = 0D;\n          heading_ = 0D;\n          speed_ = 0D;\n          timestamp_ = 0L;\n          satellites_ = 0;\n          status_ = 0;\n          return this;\n        }\n\n        @java.lang.Override\n        public com.google.protobuf.Descriptors.Descriptor\n            getDescriptorForType() {\n          return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor;\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstanceForType() {\n          return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance();\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition build() {\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result = buildPartial();\n          if (!result.isInitialized()) {\n            throw newUninitializedMessageException(result);\n          }\n          return result;\n        }\n\n        @java.lang.Override\n        public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition buildPartial() {\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition(this);\n          if (bitField0_ != 0) { buildPartial0(result); }\n          onBuilt();\n          return result;\n        }\n\n        private void buildPartial0(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result) {\n          int from_bitField0_ = bitField0_;\n          int to_bitField0_ = 0;\n          if (((from_bitField0_ & 0x00000001) != 0)) {\n            result.latitude_ = latitude_;\n            to_bitField0_ |= 0x00000001;\n          }\n          if (((from_bitField0_ & 0x00000002) != 0)) {\n            result.longitude_ = longitude_;\n            to_bitField0_ |= 0x00000002;\n          }\n          if (((from_bitField0_ & 0x00000004) != 0)) {\n            result.altitude_ = altitude_;\n            to_bitField0_ |= 0x00000004;\n          }\n          if (((from_bitField0_ & 0x00000008) != 0)) {\n            result.precision_ = precision_;\n            to_bitField0_ |= 0x00000008;\n          }\n          if (((from_bitField0_ & 0x00000010) != 0)) {\n            result.heading_ = heading_;\n            to_bitField0_ |= 0x00000010;\n          }\n          if (((from_bitField0_ & 0x00000020) != 0)) {\n            result.speed_ = speed_;\n            to_bitField0_ |= 0x00000020;\n          }\n          if (((from_bitField0_ & 0x00000040) != 0)) {\n            result.timestamp_ = timestamp_;\n            to_bitField0_ |= 0x00000040;\n          }\n          if (((from_bitField0_ & 0x00000080) != 0)) {\n            result.satellites_ = satellites_;\n            to_bitField0_ |= 0x00000080;\n          }\n          if (((from_bitField0_ & 0x00000100) != 0)) {\n            result.status_ = status_;\n            to_bitField0_ |= 0x00000100;\n          }\n          result.bitField0_ |= to_bitField0_;\n        }\n\n        @java.lang.Override\n        public Builder mergeFrom(com.google.protobuf.Message other) {\n          if (other instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition) {\n            return mergeFrom((org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition)other);\n          } else {\n            super.mergeFrom(other);\n            return this;\n          }\n        }\n\n        public Builder mergeFrom(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition other) {\n          if (other == org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance()) return this;\n          if (other.hasLatitude()) {\n            setLatitude(other.getLatitude());\n          }\n          if (other.hasLongitude()) {\n            setLongitude(other.getLongitude());\n          }\n          if (other.hasAltitude()) {\n            setAltitude(other.getAltitude());\n          }\n          if (other.hasPrecision()) {\n            setPrecision(other.getPrecision());\n          }\n          if (other.hasHeading()) {\n            setHeading(other.getHeading());\n          }\n          if (other.hasSpeed()) {\n            setSpeed(other.getSpeed());\n          }\n          if (other.hasTimestamp()) {\n            setTimestamp(other.getTimestamp());\n          }\n          if (other.hasSatellites()) {\n            setSatellites(other.getSatellites());\n          }\n          if (other.hasStatus()) {\n            setStatus(other.getStatus());\n          }\n          this.mergeUnknownFields(other.getUnknownFields());\n          onChanged();\n          return this;\n        }\n\n        @java.lang.Override\n        public final boolean isInitialized() {\n          if (!hasLatitude()) {\n            return false;\n          }\n          if (!hasLongitude()) {\n            return false;\n          }\n          return true;\n        }\n\n        @java.lang.Override\n        public Builder mergeFrom(\n            com.google.protobuf.CodedInputStream input,\n            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws java.io.IOException {\n          if (extensionRegistry == null) {\n            throw new java.lang.NullPointerException();\n          }\n          try {\n            boolean done = false;\n            while (!done) {\n              int tag = input.readTag();\n              switch (tag) {\n                case 0:\n                  done = true;\n                  break;\n                case 9: {\n                  latitude_ = input.readDouble();\n                  bitField0_ |= 0x00000001;\n                  break;\n                } // case 9\n                case 17: {\n                  longitude_ = input.readDouble();\n                  bitField0_ |= 0x00000002;\n                  break;\n                } // case 17\n                case 25: {\n                  altitude_ = input.readDouble();\n                  bitField0_ |= 0x00000004;\n                  break;\n                } // case 25\n                case 33: {\n                  precision_ = input.readDouble();\n                  bitField0_ |= 0x00000008;\n                  break;\n                } // case 33\n                case 41: {\n                  heading_ = input.readDouble();\n                  bitField0_ |= 0x00000010;\n                  break;\n                } // case 41\n                case 49: {\n                  speed_ = input.readDouble();\n                  bitField0_ |= 0x00000020;\n                  break;\n                } // case 49\n                case 56: {\n                  timestamp_ = input.readInt64();\n                  bitField0_ |= 0x00000040;\n                  break;\n                } // case 56\n                case 64: {\n                  satellites_ = input.readInt32();\n                  bitField0_ |= 0x00000080;\n                  break;\n                } // case 64\n                case 72: {\n                  status_ = input.readInt32();\n                  bitField0_ |= 0x00000100;\n                  break;\n                } // case 72\n                default: {\n                  if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                    done = true; // was an endgroup tag\n                  }\n                  break;\n                } // default:\n              } // switch (tag)\n            } // while (!done)\n          } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n            throw e.unwrapIOException();\n          } finally {\n            onChanged();\n          } // finally\n          return this;\n        }\n        private int bitField0_;\n\n        private double latitude_ ;\n        /**\n         * <code>required double latitude = 1;</code>\n         * @return Whether the latitude field is set.\n         */\n        @java.lang.Override\n        public boolean hasLatitude() {\n          return ((bitField0_ & 0x00000001) != 0);\n        }\n        /**\n         * <code>required double latitude = 1;</code>\n         * @return The latitude.\n         */\n        @java.lang.Override\n        public double getLatitude() {\n          return latitude_;\n        }\n        /**\n         * <code>required double latitude = 1;</code>\n         * @param value The latitude to set.\n         * @return This builder for chaining.\n         */\n        public Builder setLatitude(double value) {\n\n          latitude_ = value;\n          bitField0_ |= 0x00000001;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required double latitude = 1;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearLatitude() {\n          bitField0_ = (bitField0_ & ~0x00000001);\n          latitude_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double longitude_ ;\n        /**\n         * <code>required double longitude = 2;</code>\n         * @return Whether the longitude field is set.\n         */\n        @java.lang.Override\n        public boolean hasLongitude() {\n          return ((bitField0_ & 0x00000002) != 0);\n        }\n        /**\n         * <code>required double longitude = 2;</code>\n         * @return The longitude.\n         */\n        @java.lang.Override\n        public double getLongitude() {\n          return longitude_;\n        }\n        /**\n         * <code>required double longitude = 2;</code>\n         * @param value The longitude to set.\n         * @return This builder for chaining.\n         */\n        public Builder setLongitude(double value) {\n\n          longitude_ = value;\n          bitField0_ |= 0x00000002;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>required double longitude = 2;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearLongitude() {\n          bitField0_ = (bitField0_ & ~0x00000002);\n          longitude_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double altitude_ ;\n        /**\n         * <code>optional double altitude = 3;</code>\n         * @return Whether the altitude field is set.\n         */\n        @java.lang.Override\n        public boolean hasAltitude() {\n          return ((bitField0_ & 0x00000004) != 0);\n        }\n        /**\n         * <code>optional double altitude = 3;</code>\n         * @return The altitude.\n         */\n        @java.lang.Override\n        public double getAltitude() {\n          return altitude_;\n        }\n        /**\n         * <code>optional double altitude = 3;</code>\n         * @param value The altitude to set.\n         * @return This builder for chaining.\n         */\n        public Builder setAltitude(double value) {\n\n          altitude_ = value;\n          bitField0_ |= 0x00000004;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional double altitude = 3;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearAltitude() {\n          bitField0_ = (bitField0_ & ~0x00000004);\n          altitude_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double precision_ ;\n        /**\n         * <pre>\n         * dilution of precision of the current satellite fix. \n         * </pre>\n         *\n         * <code>optional double precision = 4;</code>\n         * @return Whether the precision field is set.\n         */\n        @java.lang.Override\n        public boolean hasPrecision() {\n          return ((bitField0_ & 0x00000008) != 0);\n        }\n        /**\n         * <pre>\n         * dilution of precision of the current satellite fix. \n         * </pre>\n         *\n         * <code>optional double precision = 4;</code>\n         * @return The precision.\n         */\n        @java.lang.Override\n        public double getPrecision() {\n          return precision_;\n        }\n        /**\n         * <pre>\n         * dilution of precision of the current satellite fix. \n         * </pre>\n         *\n         * <code>optional double precision = 4;</code>\n         * @param value The precision to set.\n         * @return This builder for chaining.\n         */\n        public Builder setPrecision(double value) {\n\n          precision_ = value;\n          bitField0_ |= 0x00000008;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * dilution of precision of the current satellite fix. \n         * </pre>\n         *\n         * <code>optional double precision = 4;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearPrecision() {\n          bitField0_ = (bitField0_ & ~0x00000008);\n          precision_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double heading_ ;\n        /**\n         * <pre>\n         * heading in degrees\n         * </pre>\n         *\n         * <code>optional double heading = 5;</code>\n         * @return Whether the heading field is set.\n         */\n        @java.lang.Override\n        public boolean hasHeading() {\n          return ((bitField0_ & 0x00000010) != 0);\n        }\n        /**\n         * <pre>\n         * heading in degrees\n         * </pre>\n         *\n         * <code>optional double heading = 5;</code>\n         * @return The heading.\n         */\n        @java.lang.Override\n        public double getHeading() {\n          return heading_;\n        }\n        /**\n         * <pre>\n         * heading in degrees\n         * </pre>\n         *\n         * <code>optional double heading = 5;</code>\n         * @param value The heading to set.\n         * @return This builder for chaining.\n         */\n        public Builder setHeading(double value) {\n\n          heading_ = value;\n          bitField0_ |= 0x00000010;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * heading in degrees\n         * </pre>\n         *\n         * <code>optional double heading = 5;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearHeading() {\n          bitField0_ = (bitField0_ & ~0x00000010);\n          heading_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private double speed_ ;\n        /**\n         * <pre>\n         * meters per second\n         * </pre>\n         *\n         * <code>optional double speed = 6;</code>\n         * @return Whether the speed field is set.\n         */\n        @java.lang.Override\n        public boolean hasSpeed() {\n          return ((bitField0_ & 0x00000020) != 0);\n        }\n        /**\n         * <pre>\n         * meters per second\n         * </pre>\n         *\n         * <code>optional double speed = 6;</code>\n         * @return The speed.\n         */\n        @java.lang.Override\n        public double getSpeed() {\n          return speed_;\n        }\n        /**\n         * <pre>\n         * meters per second\n         * </pre>\n         *\n         * <code>optional double speed = 6;</code>\n         * @param value The speed to set.\n         * @return This builder for chaining.\n         */\n        public Builder setSpeed(double value) {\n\n          speed_ = value;\n          bitField0_ |= 0x00000020;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * meters per second\n         * </pre>\n         *\n         * <code>optional double speed = 6;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearSpeed() {\n          bitField0_ = (bitField0_ & ~0x00000020);\n          speed_ = 0D;\n          onChanged();\n          return this;\n        }\n\n        private long timestamp_ ;\n        /**\n         * <code>optional int64 timestamp = 7;</code>\n         * @return Whether the timestamp field is set.\n         */\n        @java.lang.Override\n        public boolean hasTimestamp() {\n          return ((bitField0_ & 0x00000040) != 0);\n        }\n        /**\n         * <code>optional int64 timestamp = 7;</code>\n         * @return The timestamp.\n         */\n        @java.lang.Override\n        public long getTimestamp() {\n          return timestamp_;\n        }\n        /**\n         * <code>optional int64 timestamp = 7;</code>\n         * @param value The timestamp to set.\n         * @return This builder for chaining.\n         */\n        public Builder setTimestamp(long value) {\n\n          timestamp_ = value;\n          bitField0_ |= 0x00000040;\n          onChanged();\n          return this;\n        }\n        /**\n         * <code>optional int64 timestamp = 7;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearTimestamp() {\n          bitField0_ = (bitField0_ & ~0x00000040);\n          timestamp_ = 0L;\n          onChanged();\n          return this;\n        }\n\n        private int satellites_ ;\n        /**\n         * <pre>\n         * number satellites locked by the GPS device\n         * </pre>\n         *\n         * <code>optional int32 satellites = 8;</code>\n         * @return Whether the satellites field is set.\n         */\n        @java.lang.Override\n        public boolean hasSatellites() {\n          return ((bitField0_ & 0x00000080) != 0);\n        }\n        /**\n         * <pre>\n         * number satellites locked by the GPS device\n         * </pre>\n         *\n         * <code>optional int32 satellites = 8;</code>\n         * @return The satellites.\n         */\n        @java.lang.Override\n        public int getSatellites() {\n          return satellites_;\n        }\n        /**\n         * <pre>\n         * number satellites locked by the GPS device\n         * </pre>\n         *\n         * <code>optional int32 satellites = 8;</code>\n         * @param value The satellites to set.\n         * @return This builder for chaining.\n         */\n        public Builder setSatellites(int value) {\n\n          satellites_ = value;\n          bitField0_ |= 0x00000080;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * number satellites locked by the GPS device\n         * </pre>\n         *\n         * <code>optional int32 satellites = 8;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearSatellites() {\n          bitField0_ = (bitField0_ & ~0x00000080);\n          satellites_ = 0;\n          onChanged();\n          return this;\n        }\n\n        private int status_ ;\n        /**\n         * <pre>\n         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n         * </pre>\n         *\n         * <code>optional int32 status = 9;</code>\n         * @return Whether the status field is set.\n         */\n        @java.lang.Override\n        public boolean hasStatus() {\n          return ((bitField0_ & 0x00000100) != 0);\n        }\n        /**\n         * <pre>\n         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n         * </pre>\n         *\n         * <code>optional int32 status = 9;</code>\n         * @return The status.\n         */\n        @java.lang.Override\n        public int getStatus() {\n          return status_;\n        }\n        /**\n         * <pre>\n         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n         * </pre>\n         *\n         * <code>optional int32 status = 9;</code>\n         * @param value The status to set.\n         * @return This builder for chaining.\n         */\n        public Builder setStatus(int value) {\n\n          status_ = value;\n          bitField0_ |= 0x00000100;\n          onChanged();\n          return this;\n        }\n        /**\n         * <pre>\n         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n         * </pre>\n         *\n         * <code>optional int32 status = 9;</code>\n         * @return This builder for chaining.\n         */\n        public Builder clearStatus() {\n          bitField0_ = (bitField0_ & ~0x00000100);\n          status_ = 0;\n          onChanged();\n          return this;\n        }\n\n        // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload.KuraPosition)\n      }\n\n      // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload.KuraPosition)\n      private static final org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition DEFAULT_INSTANCE;\n      static {\n        DEFAULT_INSTANCE = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition();\n      }\n\n      public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstance() {\n        return DEFAULT_INSTANCE;\n      }\n\n      private static final com.google.protobuf.Parser<KuraPosition>\n          PARSER = new com.google.protobuf.AbstractParser<KuraPosition>() {\n        @java.lang.Override\n        public KuraPosition parsePartialFrom(\n            com.google.protobuf.CodedInputStream input,\n            com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n            throws com.google.protobuf.InvalidProtocolBufferException {\n          Builder builder = newBuilder();\n          try {\n            builder.mergeFrom(input, extensionRegistry);\n          } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n            throw e.setUnfinishedMessage(builder.buildPartial());\n          } catch (com.google.protobuf.UninitializedMessageException e) {\n            throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n          } catch (java.io.IOException e) {\n            throw new com.google.protobuf.InvalidProtocolBufferException(e)\n                .setUnfinishedMessage(builder.buildPartial());\n          }\n          return builder.buildPartial();\n        }\n      };\n\n      public static com.google.protobuf.Parser<KuraPosition> parser() {\n        return PARSER;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Parser<KuraPosition> getParserForType() {\n        return PARSER;\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstanceForType() {\n        return DEFAULT_INSTANCE;\n      }\n\n    }\n\n    private int bitField0_;\n    public static final int TIMESTAMP_FIELD_NUMBER = 1;\n    private long timestamp_ = 0L;\n    /**\n     * <code>optional int64 timestamp = 1;</code>\n     * @return Whether the timestamp field is set.\n     */\n    @java.lang.Override\n    public boolean hasTimestamp() {\n      return ((bitField0_ & 0x00000001) != 0);\n    }\n    /**\n     * <code>optional int64 timestamp = 1;</code>\n     * @return The timestamp.\n     */\n    @java.lang.Override\n    public long getTimestamp() {\n      return timestamp_;\n    }\n\n    public static final int POSITION_FIELD_NUMBER = 2;\n    private org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition position_;\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     * @return Whether the position field is set.\n     */\n    @java.lang.Override\n    public boolean hasPosition() {\n      return ((bitField0_ & 0x00000002) != 0);\n    }\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     * @return The position.\n     */\n    @java.lang.Override\n    public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition() {\n      return position_ == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_;\n    }\n    /**\n     * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n     */\n    @java.lang.Override\n    public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder() {\n      return position_ == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_;\n    }\n\n    public static final int METRIC_FIELD_NUMBER = 5000;\n    @SuppressWarnings(\"serial\")\n    private java.util.List<org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> metric_;\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public java.util.List<org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> getMetricList() {\n      return metric_;\n    }\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public java.util.List<? extends org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> \n        getMetricOrBuilderList() {\n      return metric_;\n    }\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public int getMetricCount() {\n      return metric_.size();\n    }\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index) {\n      return metric_.get(index);\n    }\n    /**\n     * <pre>\n     * can be zero, so optional\n     * </pre>\n     *\n     * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n     */\n    @java.lang.Override\n    public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder(\n        int index) {\n      return metric_.get(index);\n    }\n\n    public static final int BODY_FIELD_NUMBER = 5001;\n    private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY;\n    /**\n     * <code>optional bytes body = 5001;</code>\n     * @return Whether the body field is set.\n     */\n    @java.lang.Override\n    public boolean hasBody() {\n      return ((bitField0_ & 0x00000004) != 0);\n    }\n    /**\n     * <code>optional bytes body = 5001;</code>\n     * @return The body.\n     */\n    @java.lang.Override\n    public com.google.protobuf.ByteString getBody() {\n      return body_;\n    }\n\n    private byte memoizedIsInitialized = -1;\n    @java.lang.Override\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized == 1) return true;\n      if (isInitialized == 0) return false;\n\n      if (hasPosition()) {\n        if (!getPosition().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      for (int i = 0; i < getMetricCount(); i++) {\n        if (!getMetric(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      if (!extensionsAreInitialized()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    @java.lang.Override\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      com.google.protobuf.GeneratedMessage\n        .ExtendableMessage.ExtensionSerializer\n          extensionWriter = newExtensionSerializer();\n      if (((bitField0_ & 0x00000001) != 0)) {\n        output.writeInt64(1, timestamp_);\n      }\n      if (((bitField0_ & 0x00000002) != 0)) {\n        output.writeMessage(2, getPosition());\n      }\n      extensionWriter.writeUntil(5000, output);\n      for (int i = 0; i < metric_.size(); i++) {\n        output.writeMessage(5000, metric_.get(i));\n      }\n      if (((bitField0_ & 0x00000004) != 0)) {\n        output.writeBytes(5001, body_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    @java.lang.Override\n    public int getSerializedSize() {\n      int size = memoizedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) != 0)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, timestamp_);\n      }\n      if (((bitField0_ & 0x00000002) != 0)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(2, getPosition());\n      }\n      for (int i = 0; i < metric_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(5000, metric_.get(i));\n      }\n      if (((bitField0_ & 0x00000004) != 0)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5001, body_);\n      }\n      size += extensionsSerializedSize();\n      size += getUnknownFields().getSerializedSize();\n      memoizedSize = size;\n      return size;\n    }\n\n    @java.lang.Override\n    public boolean equals(final java.lang.Object obj) {\n      if (obj == this) {\n       return true;\n      }\n      if (!(obj instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload)) {\n        return super.equals(obj);\n      }\n      org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload other = (org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload) obj;\n\n      if (hasTimestamp() != other.hasTimestamp()) return false;\n      if (hasTimestamp()) {\n        if (getTimestamp()\n            != other.getTimestamp()) return false;\n      }\n      if (hasPosition() != other.hasPosition()) return false;\n      if (hasPosition()) {\n        if (!getPosition()\n            .equals(other.getPosition())) return false;\n      }\n      if (!getMetricList()\n          .equals(other.getMetricList())) return false;\n      if (hasBody() != other.hasBody()) return false;\n      if (hasBody()) {\n        if (!getBody()\n            .equals(other.getBody())) return false;\n      }\n      if (!getUnknownFields().equals(other.getUnknownFields())) return false;\n      if (!getExtensionFields().equals(other.getExtensionFields()))\n        return false;\n      return true;\n    }\n\n    @java.lang.Override\n    public int hashCode() {\n      if (memoizedHashCode != 0) {\n        return memoizedHashCode;\n      }\n      int hash = 41;\n      hash = (19 * hash) + getDescriptor().hashCode();\n      if (hasTimestamp()) {\n        hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER;\n        hash = (53 * hash) + com.google.protobuf.Internal.hashLong(\n            getTimestamp());\n      }\n      if (hasPosition()) {\n        hash = (37 * hash) + POSITION_FIELD_NUMBER;\n        hash = (53 * hash) + getPosition().hashCode();\n      }\n      if (getMetricCount() > 0) {\n        hash = (37 * hash) + METRIC_FIELD_NUMBER;\n        hash = (53 * hash) + getMetricList().hashCode();\n      }\n      if (hasBody()) {\n        hash = (37 * hash) + BODY_FIELD_NUMBER;\n        hash = (53 * hash) + getBody().hashCode();\n      }\n      hash = hashFields(hash, getExtensionFields());\n      hash = (29 * hash) + getUnknownFields().hashCode();\n      memoizedHashCode = hash;\n      return hash;\n    }\n\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        java.nio.ByteBuffer data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        java.nio.ByteBuffer data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseWithIOException(PARSER, input);\n    }\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseDelimitedWithIOException(PARSER, input);\n    }\n\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n    }\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseWithIOException(PARSER, input);\n    }\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return com.google.protobuf.GeneratedMessage\n          .parseWithIOException(PARSER, input, extensionRegistry);\n    }\n\n    @java.lang.Override\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder() {\n      return DEFAULT_INSTANCE.toBuilder();\n    }\n    public static Builder newBuilder(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload prototype) {\n      return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);\n    }\n    @java.lang.Override\n    public Builder toBuilder() {\n      return this == DEFAULT_INSTANCE\n          ? new Builder() : new Builder().mergeFrom(this);\n    }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code kuradatatypes.KuraPayload}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.ExtendableBuilder<\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload, Builder> implements\n        // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload)\n        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayloadOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor;\n      }\n\n      @java.lang.Override\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.Builder.class);\n      }\n\n      // Construct using org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage\n                .alwaysUseFieldBuilders) {\n          getPositionFieldBuilder();\n          getMetricFieldBuilder();\n        }\n      }\n      @java.lang.Override\n      public Builder clear() {\n        super.clear();\n        bitField0_ = 0;\n        timestamp_ = 0L;\n        position_ = null;\n        if (positionBuilder_ != null) {\n          positionBuilder_.dispose();\n          positionBuilder_ = null;\n        }\n        if (metricBuilder_ == null) {\n          metric_ = java.util.Collections.emptyList();\n        } else {\n          metric_ = null;\n          metricBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        body_ = com.google.protobuf.ByteString.EMPTY;\n        return this;\n      }\n\n      @java.lang.Override\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor;\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstanceForType() {\n        return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.getDefaultInstance();\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload build() {\n        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      @java.lang.Override\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload buildPartial() {\n        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload result = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload(this);\n        buildPartialRepeatedFields(result);\n        if (bitField0_ != 0) { buildPartial0(result); }\n        onBuilt();\n        return result;\n      }\n\n      private void buildPartialRepeatedFields(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload result) {\n        if (metricBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) != 0)) {\n            metric_ = java.util.Collections.unmodifiableList(metric_);\n            bitField0_ = (bitField0_ & ~0x00000004);\n          }\n          result.metric_ = metric_;\n        } else {\n          result.metric_ = metricBuilder_.build();\n        }\n      }\n\n      private void buildPartial0(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload result) {\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) != 0)) {\n          result.timestamp_ = timestamp_;\n          to_bitField0_ |= 0x00000001;\n        }\n        if (((from_bitField0_ & 0x00000002) != 0)) {\n          result.position_ = positionBuilder_ == null\n              ? position_\n              : positionBuilder_.build();\n          to_bitField0_ |= 0x00000002;\n        }\n        if (((from_bitField0_ & 0x00000008) != 0)) {\n          result.body_ = body_;\n          to_bitField0_ |= 0x00000004;\n        }\n        result.bitField0_ |= to_bitField0_;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload) {\n          return mergeFrom((org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload other) {\n        if (other == org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.getDefaultInstance()) return this;\n        if (other.hasTimestamp()) {\n          setTimestamp(other.getTimestamp());\n        }\n        if (other.hasPosition()) {\n          mergePosition(other.getPosition());\n        }\n        if (metricBuilder_ == null) {\n          if (!other.metric_.isEmpty()) {\n            if (metric_.isEmpty()) {\n              metric_ = other.metric_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n            } else {\n              ensureMetricIsMutable();\n              metric_.addAll(other.metric_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.metric_.isEmpty()) {\n            if (metricBuilder_.isEmpty()) {\n              metricBuilder_.dispose();\n              metricBuilder_ = null;\n              metric_ = other.metric_;\n              bitField0_ = (bitField0_ & ~0x00000004);\n              metricBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getMetricFieldBuilder() : null;\n            } else {\n              metricBuilder_.addAllMessages(other.metric_);\n            }\n          }\n        }\n        if (other.hasBody()) {\n          setBody(other.getBody());\n        }\n        this.mergeExtensionFields(other);\n        this.mergeUnknownFields(other.getUnknownFields());\n        onChanged();\n        return this;\n      }\n\n      @java.lang.Override\n      public final boolean isInitialized() {\n        if (hasPosition()) {\n          if (!getPosition().isInitialized()) {\n            return false;\n          }\n        }\n        for (int i = 0; i < getMetricCount(); i++) {\n          if (!getMetric(i).isInitialized()) {\n            return false;\n          }\n        }\n        if (!extensionsAreInitialized()) {\n          return false;\n        }\n        return true;\n      }\n\n      @java.lang.Override\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        if (extensionRegistry == null) {\n          throw new java.lang.NullPointerException();\n        }\n        try {\n          boolean done = false;\n          while (!done) {\n            int tag = input.readTag();\n            switch (tag) {\n              case 0:\n                done = true;\n                break;\n              case 8: {\n                timestamp_ = input.readInt64();\n                bitField0_ |= 0x00000001;\n                break;\n              } // case 8\n              case 18: {\n                input.readMessage(\n                    getPositionFieldBuilder().getBuilder(),\n                    extensionRegistry);\n                bitField0_ |= 0x00000002;\n                break;\n              } // case 18\n              case 40002: {\n                org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric m =\n                    input.readMessage(\n                        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.parser(),\n                        extensionRegistry);\n                if (metricBuilder_ == null) {\n                  ensureMetricIsMutable();\n                  metric_.add(m);\n                } else {\n                  metricBuilder_.addMessage(m);\n                }\n                break;\n              } // case 40002\n              case 40010: {\n                body_ = input.readBytes();\n                bitField0_ |= 0x00000008;\n                break;\n              } // case 40010\n              default: {\n                if (!super.parseUnknownField(input, extensionRegistry, tag)) {\n                  done = true; // was an endgroup tag\n                }\n                break;\n              } // default:\n            } // switch (tag)\n          } // while (!done)\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          throw e.unwrapIOException();\n        } finally {\n          onChanged();\n        } // finally\n        return this;\n      }\n      private int bitField0_;\n\n      private long timestamp_ ;\n      /**\n       * <code>optional int64 timestamp = 1;</code>\n       * @return Whether the timestamp field is set.\n       */\n      @java.lang.Override\n      public boolean hasTimestamp() {\n        return ((bitField0_ & 0x00000001) != 0);\n      }\n      /**\n       * <code>optional int64 timestamp = 1;</code>\n       * @return The timestamp.\n       */\n      @java.lang.Override\n      public long getTimestamp() {\n        return timestamp_;\n      }\n      /**\n       * <code>optional int64 timestamp = 1;</code>\n       * @param value The timestamp to set.\n       * @return This builder for chaining.\n       */\n      public Builder setTimestamp(long value) {\n\n        timestamp_ = value;\n        bitField0_ |= 0x00000001;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 timestamp = 1;</code>\n       * @return This builder for chaining.\n       */\n      public Builder clearTimestamp() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        timestamp_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      private org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition position_;\n      private com.google.protobuf.SingleFieldBuilder<\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder> positionBuilder_;\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       * @return Whether the position field is set.\n       */\n      public boolean hasPosition() {\n        return ((bitField0_ & 0x00000002) != 0);\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       * @return The position.\n       */\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition() {\n        if (positionBuilder_ == null) {\n          return position_ == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_;\n        } else {\n          return positionBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public Builder setPosition(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition value) {\n        if (positionBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          position_ = value;\n        } else {\n          positionBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000002;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public Builder setPosition(\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder builderForValue) {\n        if (positionBuilder_ == null) {\n          position_ = builderForValue.build();\n        } else {\n          positionBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000002;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public Builder mergePosition(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition value) {\n        if (positionBuilder_ == null) {\n          if (((bitField0_ & 0x00000002) != 0) &&\n            position_ != null &&\n            position_ != org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance()) {\n            getPositionBuilder().mergeFrom(value);\n          } else {\n            position_ = value;\n          }\n        } else {\n          positionBuilder_.mergeFrom(value);\n        }\n        if (position_ != null) {\n          bitField0_ |= 0x00000002;\n          onChanged();\n        }\n        return this;\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public Builder clearPosition() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        position_ = null;\n        if (positionBuilder_ != null) {\n          positionBuilder_.dispose();\n          positionBuilder_ = null;\n        }\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder getPositionBuilder() {\n        bitField0_ |= 0x00000002;\n        onChanged();\n        return getPositionFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder() {\n        if (positionBuilder_ != null) {\n          return positionBuilder_.getMessageOrBuilder();\n        } else {\n          return position_ == null ?\n              org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_;\n        }\n      }\n      /**\n       * <code>optional .kuradatatypes.KuraPayload.KuraPosition position = 2;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder> \n          getPositionFieldBuilder() {\n        if (positionBuilder_ == null) {\n          positionBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder>(\n                  getPosition(),\n                  getParentForChildren(),\n                  isClean());\n          position_ = null;\n        }\n        return positionBuilder_;\n      }\n\n      private java.util.List<org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> metric_ =\n        java.util.Collections.emptyList();\n      private void ensureMetricIsMutable() {\n        if (!((bitField0_ & 0x00000004) != 0)) {\n          metric_ = new java.util.ArrayList<org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric>(metric_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> metricBuilder_;\n\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public java.util.List<org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> getMetricList() {\n        if (metricBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(metric_);\n        } else {\n          return metricBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public int getMetricCount() {\n        if (metricBuilder_ == null) {\n          return metric_.size();\n        } else {\n          return metricBuilder_.getCount();\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index) {\n        if (metricBuilder_ == null) {\n          return metric_.get(index);\n        } else {\n          return metricBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder setMetric(\n          int index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) {\n        if (metricBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMetricIsMutable();\n          metric_.set(index, value);\n          onChanged();\n        } else {\n          metricBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder setMetric(\n          int index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          metric_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          metricBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addMetric(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) {\n        if (metricBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMetricIsMutable();\n          metric_.add(value);\n          onChanged();\n        } else {\n          metricBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addMetric(\n          int index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) {\n        if (metricBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMetricIsMutable();\n          metric_.add(index, value);\n          onChanged();\n        } else {\n          metricBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addMetric(\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          metric_.add(builderForValue.build());\n          onChanged();\n        } else {\n          metricBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addMetric(\n          int index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          metric_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          metricBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder addAllMetric(\n          java.lang.Iterable<? extends org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric> values) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          com.google.protobuf.AbstractMessageLite.Builder.addAll(\n              values, metric_);\n          onChanged();\n        } else {\n          metricBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder clearMetric() {\n        if (metricBuilder_ == null) {\n          metric_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000004);\n          onChanged();\n        } else {\n          metricBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public Builder removeMetric(int index) {\n        if (metricBuilder_ == null) {\n          ensureMetricIsMutable();\n          metric_.remove(index);\n          onChanged();\n        } else {\n          metricBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder getMetricBuilder(\n          int index) {\n        return getMetricFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder(\n          int index) {\n        if (metricBuilder_ == null) {\n          return metric_.get(index);  } else {\n          return metricBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public java.util.List<? extends org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> \n           getMetricOrBuilderList() {\n        if (metricBuilder_ != null) {\n          return metricBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(metric_);\n        }\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder addMetricBuilder() {\n        return getMetricFieldBuilder().addBuilder(\n            org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance());\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder addMetricBuilder(\n          int index) {\n        return getMetricFieldBuilder().addBuilder(\n            index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance());\n      }\n      /**\n       * <pre>\n       * can be zero, so optional\n       * </pre>\n       *\n       * <code>repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000;</code>\n       */\n      public java.util.List<org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder> \n           getMetricBuilderList() {\n        return getMetricFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> \n          getMetricFieldBuilder() {\n        if (metricBuilder_ == null) {\n          metricBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder>(\n                  metric_,\n                  ((bitField0_ & 0x00000004) != 0),\n                  getParentForChildren(),\n                  isClean());\n          metric_ = null;\n        }\n        return metricBuilder_;\n      }\n\n      private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>optional bytes body = 5001;</code>\n       * @return Whether the body field is set.\n       */\n      @java.lang.Override\n      public boolean hasBody() {\n        return ((bitField0_ & 0x00000008) != 0);\n      }\n      /**\n       * <code>optional bytes body = 5001;</code>\n       * @return The body.\n       */\n      @java.lang.Override\n      public com.google.protobuf.ByteString getBody() {\n        return body_;\n      }\n      /**\n       * <code>optional bytes body = 5001;</code>\n       * @param value The body to set.\n       * @return This builder for chaining.\n       */\n      public Builder setBody(com.google.protobuf.ByteString value) {\n        if (value == null) { throw new NullPointerException(); }\n        body_ = value;\n        bitField0_ |= 0x00000008;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bytes body = 5001;</code>\n       * @return This builder for chaining.\n       */\n      public Builder clearBody() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        body_ = getDefaultInstance().getBody();\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload)\n    }\n\n    // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload)\n    private static final org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload DEFAULT_INSTANCE;\n    static {\n      DEFAULT_INSTANCE = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload();\n    }\n\n    public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstance() {\n      return DEFAULT_INSTANCE;\n    }\n\n    private static final com.google.protobuf.Parser<KuraPayload>\n        PARSER = new com.google.protobuf.AbstractParser<KuraPayload>() {\n      @java.lang.Override\n      public KuraPayload parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        Builder builder = newBuilder();\n        try {\n          builder.mergeFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          throw e.setUnfinishedMessage(builder.buildPartial());\n        } catch (com.google.protobuf.UninitializedMessageException e) {\n          throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());\n        } catch (java.io.IOException e) {\n          throw new com.google.protobuf.InvalidProtocolBufferException(e)\n              .setUnfinishedMessage(builder.buildPartial());\n        }\n        return builder.buildPartial();\n      }\n    };\n\n    public static com.google.protobuf.Parser<KuraPayload> parser() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<KuraPayload> getParserForType() {\n      return PARSER;\n    }\n\n    @java.lang.Override\n    public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstanceForType() {\n      return DEFAULT_INSTANCE;\n    }\n\n  }\n\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_kuradatatypes_KuraPayload_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_kuradatatypes_KuraPayload_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable;\n  private static final com.google.protobuf.Descriptors.Descriptor\n    internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor;\n  private static final \n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable;\n\n  public static com.google.protobuf.Descriptors.FileDescriptor\n      getDescriptor() {\n    return descriptor;\n  }\n  private static  com.google.protobuf.Descriptors.FileDescriptor\n      descriptor;\n  static {\n    java.lang.String[] descriptorData = {\n      \"\\n\\021kurapayload.proto\\022\\rkuradatatypes\\\"\\243\\005\\n\\013K\" +\n      \"uraPayload\\022\\021\\n\\ttimestamp\\030\\001 \\001(\\003\\0229\\n\\010positio\" +\n      \"n\\030\\002 \\001(\\0132\\'.kuradatatypes.KuraPayload.Kura\" +\n      \"Position\\0226\\n\\006metric\\030\\210\\' \\003(\\0132%.kuradatatype\" +\n      \"s.KuraPayload.KuraMetric\\022\\r\\n\\004body\\030\\211\\' \\001(\\014\\032\" +\n      \"\\305\\002\\n\\nKuraMetric\\022\\014\\n\\004name\\030\\001 \\002(\\t\\022=\\n\\004type\\030\\002 \\002\" +\n      \"(\\0162/.kuradatatypes.KuraPayload.KuraMetri\" +\n      \"c.ValueType\\022\\024\\n\\014double_value\\030\\003 \\001(\\001\\022\\023\\n\\013flo\" +\n      \"at_value\\030\\004 \\001(\\002\\022\\022\\n\\nlong_value\\030\\005 \\001(\\003\\022\\021\\n\\tin\" +\n      \"t_value\\030\\006 \\001(\\005\\022\\022\\n\\nbool_value\\030\\007 \\001(\\010\\022\\024\\n\\014str\" +\n      \"ing_value\\030\\010 \\001(\\t\\022\\023\\n\\013bytes_value\\030\\t \\001(\\014\\\"Y\\n\\t\" +\n      \"ValueType\\022\\n\\n\\006DOUBLE\\020\\000\\022\\t\\n\\005FLOAT\\020\\001\\022\\t\\n\\005INT6\" +\n      \"4\\020\\002\\022\\t\\n\\005INT32\\020\\003\\022\\010\\n\\004BOOL\\020\\004\\022\\n\\n\\006STRING\\020\\005\\022\\t\\n\\005\" +\n      \"BYTES\\020\\006\\032\\257\\001\\n\\014KuraPosition\\022\\020\\n\\010latitude\\030\\001 \\002\" +\n      \"(\\001\\022\\021\\n\\tlongitude\\030\\002 \\002(\\001\\022\\020\\n\\010altitude\\030\\003 \\001(\\001\\022\" +\n      \"\\021\\n\\tprecision\\030\\004 \\001(\\001\\022\\017\\n\\007heading\\030\\005 \\001(\\001\\022\\r\\n\\005s\" +\n      \"peed\\030\\006 \\001(\\001\\022\\021\\n\\ttimestamp\\030\\007 \\001(\\003\\022\\022\\n\\nsatelli\" +\n      \"tes\\030\\010 \\001(\\005\\022\\016\\n\\006status\\030\\t \\001(\\005*\\005\\010\\003\\020\\210\\'B:\\n&org.\" +\n      \"eclipse.kura.core.message.protobufB\\020Kura\" +\n      \"PayloadProto\"\n    };\n    descriptor = com.google.protobuf.Descriptors.FileDescriptor\n      .internalBuildGeneratedFileFrom(descriptorData,\n        new com.google.protobuf.Descriptors.FileDescriptor[] {\n        });\n    internal_static_kuradatatypes_KuraPayload_descriptor =\n      getDescriptor().getMessageTypes().get(0);\n    internal_static_kuradatatypes_KuraPayload_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_kuradatatypes_KuraPayload_descriptor,\n        new java.lang.String[] { \"Timestamp\", \"Position\", \"Metric\", \"Body\", });\n    internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor =\n      internal_static_kuradatatypes_KuraPayload_descriptor.getNestedTypes().get(0);\n    internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor,\n        new java.lang.String[] { \"Name\", \"Type\", \"DoubleValue\", \"FloatValue\", \"LongValue\", \"IntValue\", \"BoolValue\", \"StringValue\", \"BytesValue\", });\n    internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor =\n      internal_static_kuradatatypes_KuraPayload_descriptor.getNestedTypes().get(1);\n    internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable = new\n      com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n        internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor,\n        new java.lang.String[] { \"Latitude\", \"Longitude\", \"Altitude\", \"Precision\", \"Heading\", \"Speed\", \"Timestamp\", \"Satellites\", \"Status\", });\n    descriptor.resolveAllFeaturesImmutable();\n  }\n\n  // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/protobuf/kurapayload.proto",
    "content": "//\n// To compile:\n// protoc --proto_path=src/main/protobuf --java_out=src/main/java src/main/protobuf/kurapayload.proto\n//\nsyntax = \"proto2\";\n\npackage kuradatatypes;\n\noption java_package         = \"org.eclipse.kura.core.message.protobuf\";\noption java_outer_classname = \"KuraPayloadProto\";\n\nmessage KuraPayload {\n\n\tmessage KuraMetric {\n\t\tenum ValueType {  \n\t\t\tDOUBLE         = 0; \n\t\t\tFLOAT          = 1;\n\t\t\tINT64          = 2;\n\t\t\tINT32          = 3;\n\t\t\tBOOL           = 4;\n\t\t\tSTRING         = 5;\n\t\t\tBYTES          = 6;\n\t\t}\n\t\t  \n\t\trequired string    name            = 1;\n\t\trequired ValueType type            = 2;\n\n\t\toptional double double_value       = 3;\n\t\toptional float  float_value        = 4;\n\t\toptional int64  long_value         = 5;\n\t\toptional int32  int_value          = 6;\n\t\toptional bool   bool_value         = 7;\n\t\toptional string string_value       = 8;\n\t\toptional bytes  bytes_value        = 9;\n\t}\n\n    message KuraPosition {\n        required double latitude   = 1;\n        required double longitude  = 2;\n        optional double altitude   = 3;\n        optional double precision  = 4;  // dilution of precision of the current satellite fix. \n        optional double heading    = 5;  // heading in degrees\n        optional double speed      = 6;  // meters per second\n        optional int64  timestamp  = 7;\n        optional int32  satellites = 8;  // number satellites locked by the GPS device\n        optional int32  status     = 9;  // status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.\n    }\n\n    optional int64       timestamp = 1;\n    optional KuraPosition position  = 2;\n\t\n\textensions 3 to 4999;\n    repeated KuraMetric   metric    = 5000;  // can be zero, so optional\n \toptional bytes       body      = 5001;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Raw MQTT Cloud Connection Provider\nBundle-SymbolicName: org.eclipse.kura.cloudconnection.raw.mqtt.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloud;version=\"[1.1,2.0)\",\n org.eclipse.kura.cloudconnection;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.factory;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.publisher;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.subscriber;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.subscriber.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.data.util;version=\"[1.0,2.0)\",\n org.eclipse.kura.data;version=\"[1.0,2.0)\",\n org.eclipse.kura.data.listener;version=\"[1.0,1.1)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.3.1\",\n org.osgi.util.tracker;version=\"1.5.1\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/cloud.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activated\" configuration-policy=\"require\" deactivate=\"deactivated\" enabled=\"true\" immediate=\"false\" modified=\"updated\" name=\"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\">\n   <implementation class=\"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.cloudconnection.CloudConnectionManager\"/>\n      <provide interface=\"org.eclipse.kura.cloudconnection.CloudEndpoint\"/>\n   </service>\n   <reference name=\"DataService\" \n              interface=\"org.eclipse.kura.data.DataService\" \n              policy=\"static\" \n              cardinality=\"1..1\" \n              bind=\"setDataService\" \n              unbind=\"unsetDataService\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   <property name=\"kura.ui.factory.hide\" type=\"Boolean\" value=\"true\"/>\n   <reference bind=\"setEventAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.event.EventAdmin\" name=\"EventAdmin\" policy=\"static\" unbind=\"unsetEventAdmin\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/cloudPublisher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n \n   Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activated\" configuration-policy=\"require\" deactivate=\"deactivated\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\">\n   <implementation class=\"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\"/>\n   <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/cloudServiceFactory.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.cloudconnection.raw.mqtt.factory.RawMqttCloudConnectionFactory\"> \n   <implementation class=\"org.eclipse.kura.cloudconnection.raw.mqtt.factory.RawMqttCloudConnectionFactory\"/>\n   <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\" unbind=\"unsetConfigurationService\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n   </service>\n   <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.raw.mqtt.CloudEndpoint\"/>\n   <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.raw.mqtt.CloudEndpoint(\\-[a-zA-Z0-9]+)?$\"/>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.raw.mqtt.factory.RawMqttCloudConnectionFactory\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/cloudSubscriber.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activated\" configuration-policy=\"require\" deactivate=\"deactivated\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\">\n   <implementation class=\"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\"/>\n   <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\" \n         name=\"RawMqttCloudEndpoint\" \n         description=\"A CloudEndpoint that allows to publish MQTT messages without restrictions or assumptions on payload format.\">\n\n        <Icon resource=\"CloudService\" size=\"32\"/>\n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\" factoryPid=\"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\">\n        <Object ocdref=\"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2019, 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\" \n         name=\"CloudPublisher\" \n         description=\"The CloudPublisher allows to define publishing parameters and provide a simple endpoint where the applications can attach to publish their messages.\">\n        \n        <AD id=\"topic\"\n        \tname=\"Topic\"\n        \ttype=\"String\"\n        \tcardinality=\"0\"\n        \trequired=\"true\"\n        \tdefault=\"\"\n        \tdescription='The MQTT topic to publish messages on.'>\n        </AD>\n                    \n        <AD id=\"qos\"\n            name=\"Qos\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            description='The desired quality of service for the messages that have to be published. If Qos is 0, the message is delivered at most once, or it is not delivered at all. If Qos is set to 1, the message is always delivered at least once. If set to 2, the message will be delivered exactly once.'>\n            <Option label=\"0\" value=\"0\" />\n            <Option label=\"1\" value=\"1\" />\n            <Option label=\"2\" value=\"2\" />\n        </AD>\n                    \n        <AD id=\"retain\"\n            name=\"Retain\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Retain flag for the published messages.\">\n        </AD>\n            \n        <AD id=\"priority\"\n            name=\"Priority\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"7\"\n            min=\"0\"\n            description='The priority of the messages. 0 is highest priority. This parameter is related to the DataService component of the cloud stack.'>\n        </AD>\n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\" factoryPid=\"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\">\n        <Object ocdref=\"org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\" \n         name=\"RawMqttSubscriber\" \n         description=\"The RawMqttSubscriber allows to define the subscribtion topic and notify the associated applications when a subscription event happens.\">\n        \n        <AD id=\"topic.filter\"\n        \tname=\"Topic Filter\"\n        \ttype=\"String\"\n        \tcardinality=\"0\"\n        \trequired=\"true\"\n        \tdefault=\"\"\n        \tdescription='The MQTT subscription topic filter. For example foo/bar/baz, foo/+/bar, #, foo/#'>\n        </AD>\n                    \n        <AD id=\"qos\"\n            name=\"Qos\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            description='The desired quality of service for the subscription messages.'>\n            <Option label=\"0\" value=\"0\" />\n            <Option label=\"1\" value=\"1\" />\n            <Option label=\"2\" value=\"2\" />\n        </AD>\n        \n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\" factoryPid=\"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\">\n        <Object ocdref=\"org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/build.properties",
    "content": "#\n#  Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html,\\\n               OSGI-INF/,\\\n               about_files/\n\nsrc.includes = about.html,\\\n\t\t\t   about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2019, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.cloudconnection.raw.mqtt.provider</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/cloud/Constants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.raw.mqtt.cloud;\n\npublic final class Constants {\n\n    public static final String TOPIC_PROP_NAME = \"topic\";\n\n    private Constants() {\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/cloud/Qos.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.raw.mqtt.cloud;\n\npublic enum Qos {\n\n    QOS0(0),\n    QOS1(1),\n    QOS2(2);\n\n    private final int value;\n\n    private Qos(final int value) {\n        this.value = value;\n    }\n\n    public int getValue() {\n        return this.value;\n    }\n\n    public static Qos valueOf(final int i) {\n        if (i == 0) {\n            return QOS0;\n        } else if (i == 1) {\n            return QOS1;\n        } else if (i == 2) {\n            return QOS2;\n        }\n\n        throw new IllegalArgumentException();\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/cloud/RawMqttCloudEndpoint.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.raw.mqtt.cloud;\n\nimport static org.eclipse.kura.cloudconnecton.raw.mqtt.util.Utils.catchAll;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraDisconnectException;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraNotConnectedException;\nimport org.eclipse.kura.cloud.CloudConnectionEstablishedEvent;\nimport org.eclipse.kura.cloud.CloudConnectionLostEvent;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.raw.mqtt.publisher.PublishOptions;\nimport org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.SubscribeOptions;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.data.util.MqttTopicUtil;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class RawMqttCloudEndpoint\n        implements CloudEndpoint, CloudConnectionManager, DataServiceListener, ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(RawMqttCloudEndpoint.class);\n\n    private DataService dataService;\n    private EventAdmin eventAdmin;\n    private ComponentContext componentContext;\n\n    private final Set<CloudDeliveryListener> cloudDeliveryListeners = new CopyOnWriteArraySet<>();\n    private final Set<CloudConnectionListener> cloudConnectionListeners = new CopyOnWriteArraySet<>();\n    private final Map<SubscribeOptions, Set<CloudSubscriberListener>> subscribers = new ConcurrentHashMap<>();\n\n    public void setDataService(final DataService dataService) {\n        this.dataService = dataService;\n    }\n\n    public void unsetDataService(final DataService dataService) {\n        this.dataService = null;\n    }\n\n    public void setEventAdmin(final EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    public void unsetEventAdmin(final EventAdmin eventAdmin) {\n        this.eventAdmin = null;\n    }\n\n    public void activated(final ComponentContext componentContext) {\n        logger.info(\"activating...\");\n\n        this.componentContext = componentContext;\n        this.dataService.addDataServiceListener(this);\n\n        if (this.dataService.isConnected()) {\n            onConnectionEstablished();\n        }\n\n        logger.info(\"activating...done\");\n    }\n\n    public void updated() {\n        logger.info(\"updating...\");\n        logger.info(\"updating...done\");\n    }\n\n    public void deactivated() {\n        logger.info(\"deactivating...\");\n\n        this.dataService.removeDataServiceListener(this);\n\n        synchronized (this) {\n            this.subscribers.keySet().forEach(this::unsubscribe);\n        }\n\n        logger.info(\"deactivating...done\");\n    }\n\n    @Override\n    public void connect() throws KuraConnectException {\n        this.dataService.connect();\n    }\n\n    @Override\n    public void disconnect() throws KuraDisconnectException {\n        this.dataService.disconnect(10);\n    }\n\n    @Override\n    public boolean isConnected() {\n        return this.dataService.isConnected();\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    @Override\n    public String publish(final KuraMessage message) throws KuraException {\n\n        return publish(new PublishOptions(message.getProperties()), message.getPayload());\n    }\n\n    public String publish(final PublishOptions options, final KuraPayload kuraPayload) throws KuraException {\n\n        final byte[] body = kuraPayload.getBody();\n\n        if (body == null) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Missing message body in received payload.\");\n        }\n\n        final int qos = options.getQos().getValue();\n\n        final int id = this.dataService.publish(options.getTopic(), body, qos, options.getRetain(),\n                options.getPriority());\n\n        if (qos == 0) {\n            return null;\n        } else {\n            return Integer.toString(id);\n        }\n    }\n\n    @Override\n    public synchronized void registerSubscriber(final Map<String, Object> subscriptionProperties,\n            final CloudSubscriberListener cloudSubscriberListener) {\n\n        final SubscribeOptions subscribeOptions;\n\n        try {\n            subscribeOptions = new SubscribeOptions(subscriptionProperties);\n        } catch (final Exception e) {\n            throw new IllegalArgumentException(e);\n        }\n\n        registerSubscriber(subscribeOptions, cloudSubscriberListener);\n    }\n\n    public synchronized void registerSubscriber(final SubscribeOptions subscribeOptions,\n            final CloudSubscriberListener cloudSubscriberListener) {\n\n        final Set<CloudSubscriberListener> listeners = this.subscribers.computeIfAbsent(subscribeOptions,\n                e -> new CopyOnWriteArraySet<>());\n\n        listeners.add(cloudSubscriberListener);\n\n        subscribe(subscribeOptions);\n    }\n\n    @Override\n    public synchronized void unregisterSubscriber(CloudSubscriberListener cloudSubscriberListener) {\n        final Set<SubscribeOptions> toUnsubscribe = new HashSet<>();\n\n        this.subscribers.entrySet().removeIf(e -> {\n\n            final Set<CloudSubscriberListener> listeners = e.getValue();\n\n            listeners.remove(cloudSubscriberListener);\n\n            if (listeners.isEmpty()) {\n                toUnsubscribe.add(e.getKey());\n                return true;\n            } else {\n                return false;\n            }\n        });\n\n        toUnsubscribe.forEach(this::unsubscribe);\n\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.add(cloudDeliveryListener);\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.remove(cloudDeliveryListener);\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        this.cloudConnectionListeners.forEach(catchAll(CloudConnectionListener::onConnectionEstablished));\n\n        synchronized (this) {\n            this.subscribers.keySet().forEach(this::subscribe);\n        }\n\n        postConnectionStateChangeEvent(true);\n    }\n\n    @Override\n    public void onDisconnecting() {\n        // do nothing\n    }\n\n    @Override\n    public void onDisconnected() {\n        this.cloudConnectionListeners.forEach(catchAll(CloudConnectionListener::onDisconnected));\n\n        postConnectionStateChangeEvent(false);\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        this.cloudConnectionListeners.forEach(catchAll(CloudConnectionListener::onConnectionLost));\n\n        postConnectionStateChangeEvent(false);\n    }\n\n    @Override\n    public void onMessageArrived(final String topic, final byte[] payload, final int qos, final boolean retained) {\n        logger.info(\"message arrived on topic {}\", topic);\n\n        final KuraPayload kuraPayload = new KuraPayload();\n        kuraPayload.setBody(payload);\n\n        final Map<String, Object> messagePropertes = Collections.singletonMap(Constants.TOPIC_PROP_NAME, topic);\n\n        final KuraMessage message = new KuraMessage(kuraPayload, messagePropertes);\n\n        for (final Entry<SubscribeOptions, Set<CloudSubscriberListener>> e : this.subscribers.entrySet()) {\n            if (MqttTopicUtil.isMatched(e.getKey().getTopicFilter(), topic)) {\n                e.getValue().forEach(catchAll(l -> l.onMessageArrived(message)));\n            }\n        }\n    }\n\n    @Override\n    public void onMessagePublished(final int messageId, final String topic) {\n        // do nothing\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        this.cloudDeliveryListeners.forEach(catchAll(l -> l.onMessageConfirmed(Integer.toString(messageId))));\n    }\n\n    private void postConnectionStateChangeEvent(final boolean isConnected) {\n\n        final Map<String, Object> eventProperties = Collections.singletonMap(\"cloud.service.pid\",\n                (String) this.componentContext.getProperties().get(ConfigurationService.KURA_SERVICE_PID));\n\n        final Event event = isConnected ? new CloudConnectionEstablishedEvent(eventProperties)\n                : new CloudConnectionLostEvent(eventProperties);\n        this.eventAdmin.postEvent(event);\n    }\n\n    private void subscribe(final SubscribeOptions options) {\n        try {\n            final String topicFilter = options.getTopicFilter();\n            final int qos = options.getQos().getValue();\n\n            logger.info(\"subscribing to {} with qos {}\", topicFilter, qos);\n            this.dataService.subscribe(topicFilter, qos);\n        } catch (final KuraNotConnectedException e) {\n            logger.debug(\"failed to subscribe, DataService not connected\");\n        } catch (final Exception e) {\n            logger.warn(\"failed to subscribe\", e);\n        }\n    }\n\n    private void unsubscribe(final SubscribeOptions options) {\n        try {\n            final String topicFilter = options.getTopicFilter();\n\n            logger.info(\"unsubscribing from {}\", topicFilter);\n            this.dataService.unsubscribe(topicFilter);\n        } catch (final KuraNotConnectedException e) {\n            logger.debug(\"failed to unsubscribe, DataService not connected\");\n        } catch (final Exception e) {\n            logger.warn(\"failed to unsubscribe\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/factory/RawMqttCloudConnectionFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.raw.mqtt.factory;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.component.ComponentConstants;\n\npublic class RawMqttCloudConnectionFactory implements CloudConnectionFactory {\n\n    private static final String FACTORY_PID = \"org.eclipse.kura.cloudconnection.raw.mqtt.factory.RawMqttCloudConnectionFactory\";\n\n    // The following constants must match the factory component definitions\n    private static final String CLOUD_ENDPOINT_FACTORY_PID = \"org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint\";\n    private static final String DATA_SERVICE_FACTORY_PID = \"org.eclipse.kura.data.DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    private static final String CLOUD_SERVICE_PID = \"org.eclipse.kura.cloudconnection.raw.mqtt.CloudEndpoint\";\n    private static final String DATA_SERVICE_PID = \"org.eclipse.kura.cloudconnection.raw.mqtt.DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_PID = \"org.eclipse.kura.cloudconnection.raw.mqtt.MqttDataTransport\";\n\n    private static final String DATA_SERVICE_REFERENCE_NAME = \"DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = \"DataTransportService\";\n\n    private static final String REFERENCE_TARGET_VALUE_FORMAT = \"(\" + ConfigurationService.KURA_SERVICE_PID + \"=%s)\";\n\n    private static final Pattern MANAGED_CLOUD_SERVICE_PID_PATTERN = Pattern\n            .compile(\"^org\\\\.eclipse\\\\.kura\\\\.cloudconnection\\\\.raw\\\\.mqtt\\\\.CloudEndpoint(-[a-zA-Z0-9]+)?$\");\n\n    private ConfigurationService configurationService;\n\n    protected void setConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    protected void unsetConfigurationService(ConfigurationService configurationService) {\n        if (configurationService == this.configurationService) {\n            this.configurationService = null;\n        }\n    }\n\n    @Override\n    public String getFactoryPid() {\n        return CLOUD_ENDPOINT_FACTORY_PID;\n    }\n\n    @Override\n    public void createConfiguration(String pid) throws KuraException {\n        String[] parts = pid.split(\"-\");\n        if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) {\n            String suffix = null;\n            if (parts.length > 1) {\n                suffix = parts[1];\n            }\n\n            String dataServicePid = DATA_SERVICE_PID;\n            String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID;\n            if (suffix != null) {\n                dataServicePid += \"-\" + suffix;\n                dataTransportServicePid += \"-\" + suffix;\n            }\n\n            // create the CloudService layer and set the selective dependency on the DataService PID\n            Map<String, Object> cloudServiceProperties = new HashMap<>();\n            String name = DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n            cloudServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataServicePid));\n            cloudServiceProperties.put(KURA_CLOUD_CONNECTION_FACTORY_PID, FACTORY_PID);\n\n            this.configurationService.createFactoryConfiguration(CLOUD_ENDPOINT_FACTORY_PID, pid,\n                    cloudServiceProperties, false);\n\n            // create the DataService layer and set the selective dependency on the DataTransportService PID\n            Map<String, Object> dataServiceProperties = new HashMap<>();\n            name = DATA_TRANSPORT_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n            dataServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid));\n\n            this.configurationService.createFactoryConfiguration(DATA_SERVICE_FACTORY_PID, dataServicePid,\n                    dataServiceProperties, false);\n\n            // create the DataTransportService layer and take a snapshot\n            this.configurationService.createFactoryConfiguration(DATA_TRANSPORT_SERVICE_FACTORY_PID,\n                    dataTransportServicePid, null, true);\n        } else {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Invalid PID '{}'\", pid);\n        }\n    }\n\n    @Override\n    public void deleteConfiguration(String pid) throws KuraException {\n        String[] parts = pid.split(\"-\");\n        if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) {\n            String suffix = null;\n            if (parts.length > 1) {\n                suffix = parts[1];\n            }\n\n            String dataServicePid = DATA_SERVICE_PID;\n            String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID;\n            if (suffix != null) {\n                dataServicePid += \"-\" + suffix;\n                dataTransportServicePid += \"-\" + suffix;\n            }\n\n            this.configurationService.deleteFactoryConfiguration(pid, false);\n            this.configurationService.deleteFactoryConfiguration(dataServicePid, false);\n            this.configurationService.deleteFactoryConfiguration(dataTransportServicePid, true);\n        }\n    }\n\n    @Override\n    public List<String> getStackComponentsPids(String pid) throws KuraException {\n        List<String> componentPids = new ArrayList<>();\n        String[] parts = pid.split(\"-\");\n        if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) {\n            String suffix = null;\n            if (parts.length > 1) {\n                suffix = parts[1];\n            }\n\n            String dataServicePid = DATA_SERVICE_PID;\n            String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID;\n            if (suffix != null) {\n                dataServicePid += \"-\" + suffix;\n                dataTransportServicePid += \"-\" + suffix;\n            }\n\n            componentPids.add(pid);\n            componentPids.add(dataServicePid);\n            componentPids.add(dataTransportServicePid);\n            return componentPids;\n        } else {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Invalid PID '{}'\", pid);\n        }\n    }\n\n    @Override\n    public Set<String> getManagedCloudConnectionPids() throws KuraException {\n\n        final BundleContext context = FrameworkUtil.getBundle(RawMqttCloudConnectionFactory.class).getBundleContext();\n\n        try {\n            return context.getServiceReferences(CloudEndpoint.class, null).stream().filter(ref -> {\n                final Object kuraServicePid = ref.getProperty(ConfigurationService.KURA_SERVICE_PID);\n\n                if (!(kuraServicePid instanceof String)) {\n                    return false;\n                }\n\n                return MANAGED_CLOUD_SERVICE_PID_PATTERN.matcher((String) kuraServicePid).matches()\n                        && FACTORY_PID.equals(ref.getProperty(KURA_CLOUD_CONNECTION_FACTORY_PID));\n            }).map(ref -> (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID)).collect(Collectors.toSet());\n        } catch (InvalidSyntaxException e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, e);\n        }\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/publisher/PublishOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.raw.mqtt.publisher;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.raw.mqtt.cloud.Qos;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.Property;\n\npublic class PublishOptions {\n\n    public static final Property<String> TOPIC_PROP = new Property<>(\"topic\", String.class);\n    public static final Property<Qos> QOS_PROP = new Property<>(\"qos\", 0).map(Qos.class, Qos::valueOf);\n    public static final Property<Boolean> RETAIN_PROP = new Property<>(\"retain\", false);\n    public static final Property<Integer> PRIORITY_PROP = new Property<>(\"priority\", 4);\n\n    private final String topic;\n    private final Qos qos;\n    private final boolean retain;\n    private final int priority;\n\n    public PublishOptions(final Map<String, Object> properties) throws KuraException {\n        this.topic = TOPIC_PROP.get(properties);\n        this.qos = QOS_PROP.getOrDefault(properties);\n        this.retain = RETAIN_PROP.getOrDefault(properties);\n        this.priority = PRIORITY_PROP.getOrDefault(properties);\n    }\n\n    public String getTopic() {\n        return this.topic;\n    }\n\n    public Qos getQos() {\n        return this.qos;\n    }\n\n    public boolean getRetain() {\n        return this.retain;\n    }\n\n    public int getPriority() {\n        return this.priority;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/publisher/RawMqttPublisher.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.raw.mqtt.publisher;\n\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.AbstractStackComponent;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions.OptionsFactory;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.Utils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class RawMqttPublisher extends AbstractStackComponent<PublishOptions>\n        implements CloudPublisher, CloudDeliveryListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(RawMqttPublisher.class);\n\n    private final Set<CloudDeliveryListener> cloudDeliveryListeners = new CopyOnWriteArraySet<>();\n\n    @Override\n    protected void setCloudEndpoint(final RawMqttCloudEndpoint endpoint) {\n        super.setCloudEndpoint(endpoint);\n        endpoint.registerCloudDeliveryListener(this);\n    }\n\n    @Override\n    protected void unsetCloudEndpoint(final RawMqttCloudEndpoint endpoint) {\n        endpoint.unregisterCloudConnectionListener(this);\n        super.unsetCloudEndpoint(endpoint);\n    }\n\n    @Override\n    public String publish(final KuraMessage message) throws KuraException {\n        final StackComponentOptions<PublishOptions> currentOptions = getOptions();\n\n        final Optional<PublishOptions> publishOptions = currentOptions.getComponentOptions();\n\n        if (!publishOptions.isPresent()) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, null, null, \"invalid publish configuration\");\n        }\n\n        final Optional<RawMqttCloudEndpoint> currentEndpoint = getEndpoint();\n\n        if (!currentEndpoint.isPresent()) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND, null, null, \"cloud endpoint not bound\");\n        }\n\n        return currentEndpoint.get().publish(publishOptions.get(), message.getPayload());\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.add(cloudDeliveryListener);\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.remove(cloudDeliveryListener);\n    }\n\n    @Override\n    public void onMessageConfirmed(String messageId) {\n        this.cloudDeliveryListeners.forEach(Utils.catchAll(l -> l.onMessageConfirmed(messageId)));\n    }\n\n    @Override\n    protected Logger getLogger() {\n        return logger;\n    }\n\n    @Override\n    protected OptionsFactory<PublishOptions> getOptionsFactory() {\n        return PublishOptions::new;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/subscriber/RawMqttSubscriber.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.raw.mqtt.subscriber;\n\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint;\nimport org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.AbstractStackComponent;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions.OptionsFactory;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.Utils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class RawMqttSubscriber extends AbstractStackComponent<SubscribeOptions>\n        implements CloudSubscriber, CloudSubscriberListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(RawMqttSubscriber.class);\n\n    private final Set<CloudSubscriberListener> cloudSubscriberListeners = new CopyOnWriteArraySet<>();\n\n    @Override\n    protected void setCloudEndpoint(final RawMqttCloudEndpoint endpoint) {\n        super.setCloudEndpoint(endpoint);\n        trySubscribe();\n    }\n\n    @Override\n    protected void unsetCloudEndpoint(final RawMqttCloudEndpoint endpoint) {\n        tryUnsubscribe();\n        super.unsetCloudEndpoint(endpoint);\n    }\n\n    @Override\n    public void registerCloudSubscriberListener(final CloudSubscriberListener listener) {\n        this.cloudSubscriberListeners.add(listener);\n    }\n\n    @Override\n    public void unregisterCloudSubscriberListener(final CloudSubscriberListener listener) {\n        this.cloudSubscriberListeners.remove(listener);\n    }\n\n    @Override\n    public void onMessageArrived(final KuraMessage message) {\n        this.cloudSubscriberListeners.forEach(Utils.catchAll(l -> l.onMessageArrived(message)));\n    }\n\n    private void trySubscribe() {\n\n        final Optional<RawMqttCloudEndpoint> endpoint = getEndpoint();\n\n        if (!endpoint.isPresent()) {\n            return;\n        }\n\n        final RawMqttCloudEndpoint currentEndpoint = endpoint.get();\n\n        currentEndpoint.unregisterSubscriber(this);\n\n        final StackComponentOptions<SubscribeOptions> options = getOptions();\n\n        final Optional<SubscribeOptions> subscribeOptions = options.getComponentOptions();\n\n        if (subscribeOptions.isPresent()) {\n            currentEndpoint.registerSubscriber(subscribeOptions.get(), this);\n        }\n\n    }\n\n    private void tryUnsubscribe() {\n\n        final Optional<RawMqttCloudEndpoint> endpoint = getEndpoint();\n\n        if (endpoint.isPresent()) {\n            endpoint.get().unregisterSubscriber(this);\n        }\n\n    }\n\n    @Override\n    protected Logger getLogger() {\n        return logger;\n    }\n\n    @Override\n    protected OptionsFactory<SubscribeOptions> getOptionsFactory() {\n        return SubscribeOptions::new;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/subscriber/SubscribeOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.raw.mqtt.subscriber;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.raw.mqtt.cloud.Qos;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.Property;\nimport org.eclipse.kura.core.data.util.MqttTopicUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SubscribeOptions {\n\n    private static final Logger logger = LoggerFactory.getLogger(SubscribeOptions.class);\n\n    public static final Property<String> TOPIC_FILTER_PROP = new Property<>(\"topic.filter\", String.class)\n            .validate(SubscribeOptions::validateTopicFilter);\n    public static final Property<Qos> QOS_PROP = new Property<>(\"qos\", 0).map(Qos.class, Qos::valueOf);\n\n    private final String topicFilter;\n    private final Qos qos;\n\n    public SubscribeOptions(final Map<String, Object> properties) throws KuraException {\n        this.topicFilter = TOPIC_FILTER_PROP.get(properties);\n        this.qos = QOS_PROP.get(properties);\n    }\n\n    public String getTopicFilter() {\n        return this.topicFilter;\n    }\n\n    public Qos getQos() {\n        return this.qos;\n    }\n\n    private static boolean validateTopicFilter(final String filter) {\n        try {\n            MqttTopicUtil.validate(filter, true);\n            return true;\n        } catch (final Exception e) {\n            logger.warn(\"invalid topic filter\", e);\n            return false;\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.qos == null ? 0 : this.qos.hashCode());\n        result = prime * result + (this.topicFilter == null ? 0 : this.topicFilter.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        SubscribeOptions other = (SubscribeOptions) obj;\n        if (this.qos != other.qos) {\n            return false;\n        }\n        if (this.topicFilter == null) {\n            if (other.topicFilter != null) {\n                return false;\n            }\n        } else if (!this.topicFilter.equals(other.topicFilter)) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnecton/raw/mqtt/util/AbstractStackComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnecton.raw.mqtt.util;\n\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint;\nimport org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions.OptionsFactory;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.slf4j.Logger;\n\npublic abstract class AbstractStackComponent<T> implements ConfigurableComponent, CloudConnectionListener {\n\n    private final Set<CloudConnectionListener> cloudConnectionListeners = new CopyOnWriteArraySet<>();\n    private final AtomicReference<StackComponentOptions<T>> options = new AtomicReference<>();\n    private final AtomicReference<Optional<RawMqttCloudEndpoint>> endpoint = new AtomicReference<>(Optional.empty());\n\n    private ServiceTracker<CloudEndpoint, RawMqttCloudEndpoint> tracker;\n    private final BundleContext context = FrameworkUtil.getBundle(AbstractStackComponent.class).getBundleContext();\n\n    protected abstract Logger getLogger();\n\n    protected abstract OptionsFactory<T> getOptionsFactory();\n\n    protected void setCloudEndpoint(final RawMqttCloudEndpoint endpoint) {\n        this.endpoint.set(Optional.of(endpoint));\n        endpoint.registerCloudConnectionListener(this);\n    }\n\n    protected void unsetCloudEndpoint(final RawMqttCloudEndpoint endpoint) {\n        endpoint.unregisterCloudConnectionListener(this);\n        this.endpoint.set(Optional.empty());\n    }\n\n    public void activated(final Map<String, Object> properties) {\n        getLogger().info(\"activating...\");\n\n        updated(properties);\n\n        getLogger().info(\"activating...done\");\n    }\n\n    public void updated(final Map<String, Object> properties) {\n        getLogger().info(\"updating...\");\n\n        this.options.set(new StackComponentOptions<>(properties, getOptionsFactory()));\n        reopenTracker();\n\n        getLogger().info(\"updating...done\");\n    }\n\n    public void deactivated() {\n        getLogger().info(\"deactivating...\");\n\n        shutdownTracker();\n\n        getLogger().info(\"deactivating...done\");\n    }\n\n    protected StackComponentOptions<T> getOptions() {\n        return this.options.get();\n    }\n\n    protected Optional<RawMqttCloudEndpoint> getEndpoint() {\n        return this.endpoint.get();\n    }\n\n    private void shutdownTracker() {\n        if (this.tracker != null) {\n            this.tracker.close();\n            this.tracker = null;\n        }\n    }\n\n    private void reopenTracker() {\n        shutdownTracker();\n\n        final StackComponentOptions<?> currentOptions = this.options.get();\n\n        final Optional<String> endpointPid = currentOptions.getCloudEndpointPid();\n\n        if (!endpointPid.isPresent()) {\n            return;\n        }\n\n        final Filter filter;\n        try {\n            filter = Utils.createFilter(CloudEndpoint.class, endpointPid.get());\n        } catch (final Exception e) {\n            getLogger().warn(\"invalid cloud endpoint pid\", e);\n            return;\n        }\n\n        this.tracker = new ServiceTracker<>(this.context, filter, new Customizer());\n        this.tracker.open();\n    }\n\n    private class Customizer implements ServiceTrackerCustomizer<CloudEndpoint, RawMqttCloudEndpoint> {\n\n        @Override\n        public RawMqttCloudEndpoint addingService(final ServiceReference<CloudEndpoint> reference) {\n            final CloudEndpoint service = AbstractStackComponent.this.context.getService(reference);\n\n            if (service == null) {\n                return null;\n            }\n\n            if (!(service instanceof RawMqttCloudEndpoint)) {\n                AbstractStackComponent.this.context.ungetService(reference);\n                return null;\n            }\n\n            final RawMqttCloudEndpoint trackedService = (RawMqttCloudEndpoint) service;\n\n            setCloudEndpoint(trackedService);\n\n            return trackedService;\n        }\n\n        @Override\n        public void modifiedService(final ServiceReference<CloudEndpoint> reference,\n                final RawMqttCloudEndpoint service) {\n            // do nothing\n        }\n\n        @Override\n        public void removedService(final ServiceReference<CloudEndpoint> reference,\n                final RawMqttCloudEndpoint service) {\n\n            unsetCloudEndpoint(service);\n            AbstractStackComponent.this.context.ungetService(reference);\n        }\n\n    }\n\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    @Override\n    public void onDisconnected() {\n        this.cloudConnectionListeners.forEach(Utils.catchAll(CloudConnectionListener::onDisconnected));\n    }\n\n    @Override\n    public void onConnectionLost() {\n        this.cloudConnectionListeners.forEach(Utils.catchAll(CloudConnectionListener::onConnectionLost));\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        this.cloudConnectionListeners.forEach(Utils.catchAll(CloudConnectionListener::onConnectionEstablished));\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnecton/raw/mqtt/util/Property.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnecton.raw.mqtt.util;\n\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\n\npublic class Property<T> {\n\n    protected final String key;\n    protected final T defaultValue;\n    protected final Class<?> valueType;\n\n    public Property(final String key, final T defaultValue) {\n        this(key, defaultValue, defaultValue.getClass());\n    }\n\n    public Property(final String key, final Class<T> valueType) {\n        this(key, null, valueType);\n    }\n\n    private Property(final String key, final T defaultValue, final Class<?> valueType) {\n        this.key = key;\n        this.defaultValue = defaultValue;\n        this.valueType = valueType;\n    }\n\n    public String getKey() {\n        return this.key;\n    }\n\n    public T getDefaultValue() {\n        return this.defaultValue;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T get(final Map<String, Object> properties) throws KuraException {\n        try {\n            return (T) properties.get(this.key);\n        } catch (final Exception e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, null, null,\n                    \"invalid property value for \" + this.key, e);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T getOrDefault(final Map<String, Object> properties) throws KuraException {\n        final Object value = properties.get(this.key);\n\n        if (this.valueType.isInstance(value)) {\n            return (T) value;\n        }\n        return this.defaultValue;\n    }\n\n    public <U> Property<U> map(final Class<U> valueType, final Function<T, U> mapper) {\n\n        final Property<T> orig = this;\n\n        return new Property<U>(this.key, this.defaultValue != null ? mapper.apply(this.defaultValue) : null,\n                valueType) {\n\n            @Override\n            public U get(final Map<String, Object> properties) throws KuraException {\n                return mapper.apply(orig.get(properties));\n            }\n\n            @Override\n            public U getOrDefault(final Map<String, Object> properties) {\n                try {\n                    return mapper.apply(orig.getOrDefault(properties));\n                } catch (final Exception e) {\n                    return this.defaultValue;\n                }\n            }\n        };\n    }\n\n    public Property<T> validate(final Predicate<T> validator) {\n\n        final Property<T> orig = this;\n\n        return new Property<T>(this.key, this.defaultValue, this.valueType) {\n\n            @Override\n            public T get(final Map<String, Object> properties) throws KuraException {\n                final T value = orig.get(properties);\n\n                if (!validator.test(value)) {\n                    throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, null, null,\n                            \"Validation failed for property \" + this.key);\n                }\n\n                return value;\n            }\n\n            @Override\n            public T getOrDefault(final Map<String, Object> properties) throws KuraException {\n                final T value = orig.getOrDefault(properties);\n\n                if (!validator.test(value)) {\n                    return this.defaultValue;\n                }\n\n                return value;\n            }\n        };\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnecton/raw/mqtt/util/StackComponentOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnecton.raw.mqtt.util;\n\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class StackComponentOptions<T> {\n\n    private static final Logger logger = LoggerFactory.getLogger(StackComponentOptions.class);\n\n    private static final Property<String> CLOUD_ENDPOINT_SERVICE_PID = new Property<>(\n            CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), String.class);\n\n    private final Optional<String> cloudEndpointPid;\n    private final Optional<T> componentOptions;\n\n    public StackComponentOptions(final Map<String, Object> properties, final OptionsFactory<T> factory) {\n        this.cloudEndpointPid = extractCloudEndpointPid(properties);\n        this.componentOptions = factory.tryBuild(properties);\n    }\n\n    private static Optional<String> extractCloudEndpointPid(final Map<String, Object> properties) {\n        try {\n            return Optional.of(CLOUD_ENDPOINT_SERVICE_PID.get(properties));\n        } catch (final Exception e) {\n            logger.warn(\"cloud endpoint pid not set\");\n            return Optional.empty();\n        }\n    }\n\n    public Optional<String> getCloudEndpointPid() {\n        return this.cloudEndpointPid;\n    }\n\n    public Optional<T> getComponentOptions() {\n        return this.componentOptions;\n    }\n\n    public interface OptionsFactory<T> {\n\n        public T build(final Map<String, Object> properties) throws KuraException;\n\n        public default Optional<T> tryBuild(final Map<String, Object> properties) {\n            try {\n                return Optional.of(this.build(properties));\n            } catch (final Exception e) {\n                logger.warn(\"invalid publishing properties\", e);\n                return Optional.empty();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnecton/raw/mqtt/util/Utils.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnecton.raw.mqtt.util;\n\nimport java.util.function.Consumer;\n\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic final class Utils {\n\n    private static final Logger logger = LoggerFactory.getLogger(Utils.class);\n\n    private Utils() {\n    }\n\n    public static <T> Consumer<T> catchAll(final Consumer<T> consumer) {\n        return item -> {\n            try {\n                consumer.accept(item);\n            } catch (final Exception e) {\n                logger.warn(\"unexpected exception\", e);\n            }\n        };\n    }\n\n    public static Filter createFilter(final Class<?> type, final String kuraServicePid) throws InvalidSyntaxException {\n        final StringBuilder builder = new StringBuilder();\n\n        builder.append(\"(&(\") //\n                .append(Constants.OBJECTCLASS) //\n                .append('=') //\n                .append(type.getName()) //\n                .append(\")(\") //\n                .append(ConfigurationService.KURA_SERVICE_PID) //\n                .append('=') //\n                .append(kuraServicePid) //\n                .append(\"))\");\n\n        return FrameworkUtil.createFilter(builder.toString());\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/.gitignore",
    "content": "/target\n/bin\n.vscode\ngenerated-sources/\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Sparkplug MQTT Cloud Connection Provider\nBundle-SymbolicName: org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: com.google.gson;version=\"[2.7,3.0)\",\n com.google.protobuf;version=\"4.30.2\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloud;version=\"[1.1,2.0)\",\n org.eclipse.kura.cloudconnection;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.factory;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.publisher;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.subscriber;version=\"[1.0,1.1)\",\n org.eclipse.kura.cloudconnection.subscriber.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.data;version=\"[1.0,2.0)\",\n org.eclipse.kura.data.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.data.transport.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.4,2.0)\",\n org.eclipse.kura.ssl;version=\"[2.1,3.0)\",\n org.eclipse.kura.type;version=\"[1.1,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.3.1\",\n org.osgi.util.tracker;version=\"[1.5,2.0)\",\n org.slf4j;version=\"1.7.36\"\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nBundle-ClassPath: .,\n lib/org.eclipse.paho.client.mqttv3-1.2.1.k2.jar\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugCloudConnectionFactory.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n               name=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.SparkplugCloudConnectionFactory\">\n\n    <implementation class=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.SparkplugCloudConnectionFactory\"/>\n\n    <reference interface=\"org.eclipse.kura.configuration.ConfigurationService\"\n               bind=\"setConfigurationService\"\n               cardinality=\"1..1\"\n               name=\"ConfigurationService\"\n               policy=\"static\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n    </service>\n\n    <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint[-optionalSuffix]\"/>\n    <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint(\\-[a-zA-Z0-9]+)?$\"/>\n    <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.SparkplugCloudConnectionFactory\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugCloudEndpoint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n               activate=\"activate\"\n               deactivate=\"deactivate\"\n               modified=\"update\"\n               configuration-policy=\"require\"\n               enabled=\"true\"\n               immediate=\"false\"\n               name=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\">\n\n    <implementation class=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n        <provide interface=\"org.eclipse.kura.cloudconnection.CloudConnectionManager\"/>\n        <provide interface=\"org.eclipse.kura.cloudconnection.CloudEndpoint\"/>\n    </service>\n\n    <reference interface=\"org.eclipse.kura.data.DataService\"\n               name=\"DataService\" \n               policy=\"static\" \n               cardinality=\"1..1\" \n               bind=\"setDataService\"/>\n\n    <reference interface=\"org.osgi.service.event.EventAdmin\"\n               name=\"EventAdmin\"\n               policy=\"static\"\n               cardinality=\"1..1\"\n               bind=\"setEventAdmin\"/>\n\n    <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n    <property name=\"kura.ui.factory.hide\" type=\"Boolean\" value=\"true\"/>\n\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugDataTransport.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.2.0\"\n               configuration-policy=\"require\"\n               activate=\"activate\"\n               deactivate=\"deactivate\"\n               modified=\"update\"\n               enabled=\"true\"\n               immediate=\"true\"\n               name=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\">\n\n    <implementation class=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.data.DataTransportService\"/>\n        <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n    </service>\n    \n    <reference name=\"DataTransportListener\"\n               policy=\"dynamic\"\n               cardinality=\"0..n\"\n               interface=\"org.eclipse.kura.data.DataTransportListener\"/>\n\n    <reference name=\"SslManagerService\"\n               interface=\"org.eclipse.kura.ssl.SslManagerService\"\n               policy=\"dynamic\"\n               cardinality=\"0..1\"\n               bind=\"setSslManagerService\"\n               unbind=\"unsetSslManagerService\"/>\n\n    <reference name=\"CryptoService\" \n               interface=\"org.eclipse.kura.crypto.CryptoService\"\n               policy=\"static\"\n               cardinality=\"1..1\"\n               bind=\"setCryptoService\"/>\n\n    <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n    <property name=\"kura.ui.factory.hide\" type=\"Boolean\" value=\"true\"/>\n\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugDevice.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n    name=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice\"\n    activate=\"activate\"\n    modified=\"update\"\n    deactivate=\"deactivate\"\n    configuration-policy=\"require\"\n    enabled=\"true\"\n    immediate=\"true\">\n\n    <implementation class=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n        <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n    </service>\n\n    <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice\"/>\n    <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\"/>\n    <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n    <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugSubscriber.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<scr:component  xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n                configuration-policy=\"require\"\n                activate=\"activate\"\n                deactivate=\"deactivate\"\n                modified=\"update\"\n                enabled=\"true\"\n                immediate=\"true\"\n                name=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber\">\n\n    <implementation class=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber\"/>\n        <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n    </service>\n\n    <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber\"/>\n    <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\"/>\n    <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n    <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n\n    <OCD id=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice\"\n         name=\"SparkplugDevice\"\n         description=\"Sparkplug Device configuration. This Cloud Publisher sends a device birth message (DBIRTH message type)\n                      when the first publish occurs or when the set of published metrics is changed.\n                      After a DBIRTH message, this Cloud Publisher will send device data messages (DDATA message type).\">\n\n         <AD id=\"device.id\"\n             name=\"Sparkplug Device ID\"\n             type=\"String\"\n             cardinality=\"0\"\n             required=\"true\"\n             default=\"device\"\n             description=\"Sparkplug Device identifier, needs to be unique under the same Sparkplug Edge Node ID.\"/>\n\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice\"\n               factoryPid=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice\">\n        <Object ocdref=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice\"/>\n    </Designate>\n</MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n\n    <OCD id=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\"\n         name=\"SparkplugCloudEndpoint\"\n         description=\"Cloud Endpoint layer configuration.\">\n\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\"\n               factoryPid=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\">\n        <Object ocdref=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\"/>\n    </Designate>\n</MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n\n    <OCD id=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber\"\n         name=\"SparkplugSubscriber\"\n         description=\"Component that serves as a CloudSubscriber for this Sparkplug Cloud Connection.\">\n\n         <AD id=\"topic.filter\"\n             name=\"Topic Filter\"\n             type=\"String\"\n             cardinality=\"0\"\n             required=\"true\"\n             default=\"A/B/C\"\n             description=\"The MQTT subscription topic filter. For example foo/bar/baz, foo/+/bar, #, foo/#.\"/>\n\n         <AD id=\"qos\"\n             name=\"QoS\"\n             type=\"Integer\"\n             cardinality=\"0\"\n             required=\"true\"\n             default=\"0\"\n             description=\"The maximum desired quality of service for the subscription messages.\">\n\n             <Option label=\"QoS 0 - at most once\" value=\"0\" />\n             <Option label=\"QoS 1 - at least once\" value=\"1\" />\n             <Option label=\"QoS 2 - exactly once\" value=\"2\" />\n         </AD>\n\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber\"\n               factoryPid=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber\">\n        <Object ocdref=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber\"/>\n    </Designate>\n</MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n\n    <OCD id=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\"\n         name=\"SparkplugDataTransport\"\n         description=\"Data Transport layer configuration.\">\n\n         <Icon resource=\"MqttDataTransport\" size=\"32\"/>\n         \n         <AD id=\"group.id\"\n            name=\"Sparkplug Group ID\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"group\"\n            description=\"Sparkplug Group identifier to which this Sparkplug Edge Node belongs.\"/>\n\n        <AD id=\"node.id\"\n            name=\"Sparkplug Edge Node ID\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"node\"\n            description=\"Sparkplug Edge Node identifier to use for this Cloud Connection.\"/>\n\n        <AD id=\"primary.host.application.id\"\n            name=\"Sparkplug Primary Host Application ID\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"\"\n            description=\"Sparkplug Primary Host Application to associate with this Sparkplug Edge Node.\"/>\n\n         <AD id=\"server.uris\"\n             name=\"Server URIs\"\n             type=\"String\"\n             cardinality=\"0\"\n             required=\"true\"\n             default=\"tcp://broker1-url:1883\"\n             description=\"List of space-separated URIs of the MQTT brokers to connect to.\n                          Supported types of connection are tcp: and ssl:. URIs must not end with /.\n                          If a primary.host.application.id has been set, the client will cycle\n                          over the list until a Primary Host Application becomes online.\"/>\n\n         <AD id=\"client.id\"\n             name=\"Client ID\"\n             type=\"String\"\n             cardinality=\"0\" \n             required=\"true\"\n             default=\"client\" \n             description=\"Client identifier to be used when connecting to the MQTT broker.\"/>\n\n         <AD id=\"username\"\n             name=\"Username\"\n             type=\"String\"\n             cardinality=\"0\"\n             required=\"false\"\n             default=\"\" \n             description=\"Username to be used when connecting to the MQTT broker.\"/>\n\n         <AD id=\"password\"\n             name=\"Password\"\n             type=\"Password\"\n             cardinality=\"0\" \n             required=\"false\"\n             default=\"\"\n             description=\"Password to be used when connecting to the MQTT broker.\"/>\n\n         <AD id=\"keep.alive\"\n             name=\"Keep Alive Interval\"\n             type=\"Integer\"\n             cardinality=\"0\"\n             required=\"true\"\n             default=\"60\"\n             description=\"Frequency in seconds for the periodic MQTT PING message.\"/>\n\n         <AD id=\"connection.timeout\"\n             name=\"Connection Timeout\"\n             type=\"Integer\"\n             cardinality=\"0\"\n             required=\"true\"\n             default=\"30\"\n             description=\"Timeout used for all interactions with the MQTT broker.\"/>\n\n         <AD id=\"SslManagerService.target\"\n            name=\"SslManagerService Target Filter\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)\"\n            description=\"Specifies, as an OSGi target filter, the pid of the SslManagerService used to create SSL connections.\"/>\n\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\"\n               factoryPid=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\">\n        <Object ocdref=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\"/>\n    </Designate>\n</MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/build.properties",
    "content": "source.. = src/main/java/,\\\n           generated-sources/src/main/java/\noutput.. = target/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               lib/\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.basedir}/../test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/target/site/jacoco-aggregate/jacoco.xml\n        </sonar.coverage.jacoco.xmlReportPaths>\n        <sonar.coverage.exclusions>${project.basedir}/generated-sources/**/*</sonar.coverage.exclusions>\n        <sonar.exclusions>${project.basedir}/generated-sources/**/*</sonar.exclusions>\n        <protoc.version>4.30.2</protoc.version>\n    </properties>\n\n    <artifactId>org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n\n    <!--\n    The dependency is committed in lib/.\n    Adding to the dependencies section for tracking it and make it parsable from BOM tools\n    -->\n    <dependencies>\n        <dependency>\n            <groupId>org.eclipse.paho</groupId>\n            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n\n            <plugin>\n                <groupId>kr.motd.maven</groupId>\n                <artifactId>os-maven-plugin</artifactId>\n                <version>1.7.1</version>\n                <executions>\n                    <execution>\n                        <phase>initialize</phase>\n                        <goals>\n                            <goal>detect</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <groupId>org.xolstice.maven.plugins</groupId>\n                <artifactId>protobuf-maven-plugin</artifactId>\n                <version>0.6.1</version>\n                <configuration>\n                    <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>\n                </configuration>\n                <executions>\n                    <execution>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>compile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>build-helper-maven-plugin</artifactId>\n                <version>3.3.0</version>\n                <executions>\n                    <execution>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>add-source</goal>\n                        </goals>\n                        <configuration>\n                            <sources>\n                                <source>${project.basedir}/generated-sources/src/main/java</source>\n                            </sources>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-resources-plugin</artifactId>\n                <version>3.0.2</version>\n                <executions>\n                    <execution>\n                        <id>copy-protobuf-resource</id>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>copy-resources</goal>\n                        </goals>\n                        <configuration>\n                            <outputDirectory>${project.basedir}/generated-sources/src/main</outputDirectory>\n                            <resources>\n                                <resource>\n                                    <directory>${project.build.directory}/generated-sources/protobuf/</directory>\n                                </resource>\n                            </resources>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <configuration>\n                    <excludes>${project.basedir}/generated-sources/**/*</excludes>\n                </configuration>\n            </plugin>\n\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/device/SparkplugDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.device;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugMessageType;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.SparkplugCloudEndpointTracker;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SparkplugDevice\n        implements CloudPublisher, ConfigurableComponent, CloudConnectionListener, CloudDeliveryListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(SparkplugDevice.class);\n\n    public static final String KEY_MESSAGE_TYPE = \"message.type\";\n    public static final String KEY_DEVICE_ID = \"device.id\";\n\n    private String deviceId;\n    private SparkplugCloudEndpointTracker endpointTracker;\n    private Optional<SparkplugCloudEndpoint> sparkplugCloudEndpoint = Optional.empty();\n    private final Set<CloudConnectionListener> cloudConnectionListeners = new CopyOnWriteArraySet<>();\n    private final Set<CloudDeliveryListener> cloudDeliveryListeners = new CopyOnWriteArraySet<>();\n    private final ExecutorService executorService = Executors.newCachedThreadPool();\n    private Set<String> deviceMetrics = new HashSet<>();\n\n    /*\n     * ConfigurableComponent APIs\n     */\n\n    public void activate(final ComponentContext componentContext, final Map<String, Object> properties)\n            throws InvalidSyntaxException {\n        String endpointPid = (String) properties\n                .get(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value());\n\n        this.endpointTracker = new SparkplugCloudEndpointTracker(componentContext.getBundleContext(),\n                this::setSparkplugCloudEndpoint, this::unsetSparkplugCloudEndpoint, endpointPid);\n        this.endpointTracker.startEndpointTracker();\n\n        update(properties);\n    }\n\n    public void update(final Map<String, Object> properties) {\n        this.deviceId = (String) properties.get(KEY_DEVICE_ID);\n        if (Objects.isNull(this.deviceId) || this.deviceId.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"Property '\" + KEY_DEVICE_ID + \"' cannot be null or empty\");\n        }\n\n        this.deviceMetrics.clear();\n\n        logger.info(\"Sparkplug Device {} - Updated device ID\", this.deviceId);\n    }\n\n    public void deactivate() {\n        logger.info(\"Sparkplug Device {} - Deactivating\", this.deviceId);\n\n        this.endpointTracker.stopEndpointTracker();\n\n        logger.debug(\"Sparkplug Device {} - Shutting down executor service\", this.deviceId);\n        this.executorService.shutdownNow();\n\n        logger.info(\"Sparkplug Device {} - Deactivated\", this.deviceId);\n    }\n\n    /*\n     * CloudConnectionListener APIs\n     */\n\n    @Override\n    public void onDisconnected() {\n        this.deviceMetrics.clear();\n        this.cloudConnectionListeners.forEach(listener -> this.executorService.execute(listener::onDisconnected));\n    }\n\n    @Override\n    public void onConnectionLost() {\n        this.deviceMetrics.clear();\n        this.cloudConnectionListeners.forEach(listener -> this.executorService.execute(listener::onConnectionLost));\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        this.deviceMetrics.clear();\n        this.cloudConnectionListeners\n                .forEach(listener -> this.executorService.execute(listener::onConnectionEstablished));\n    }\n\n    /*\n     * CloudPublisher APIs\n     */\n\n    @Override\n    public synchronized String publish(final KuraMessage message) throws KuraException {\n        if (!this.sparkplugCloudEndpoint.isPresent()) {\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, \"Missing SparkplugCloudEndpoint reference\");\n        }\n\n        final Map<String, Object> newMessageProperties = new HashMap<>();\n        newMessageProperties.put(KEY_DEVICE_ID, this.deviceId);\n\n        if (this.deviceMetrics.isEmpty() || !this.deviceMetrics.equals(message.getPayload().metricNames())) {\n            this.deviceMetrics.clear();\n            this.deviceMetrics.addAll(message.getPayload().metricNames());\n            newMessageProperties.put(KEY_MESSAGE_TYPE, SparkplugMessageType.DBIRTH);\n            logger.info(\"Sparkplug Device {} - Metrics set changed, publishing DBIRTH\", this.deviceId);\n        } else {\n            newMessageProperties.put(KEY_MESSAGE_TYPE, SparkplugMessageType.DDATA);\n        }\n\n        return this.sparkplugCloudEndpoint.get().publish(new KuraMessage(message.getPayload(), newMessageProperties));\n    }\n\n    @Override\n    public void registerCloudConnectionListener(final CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(final CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(final CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.add(cloudDeliveryListener);\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(final CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.remove(cloudDeliveryListener);\n    }\n\n    /*\n     * CloudDeliveryListener APIs\n     */\n\n    @Override\n    public void onMessageConfirmed(final String messageId) {\n        this.cloudDeliveryListeners.forEach(listener -> this.executorService\n                .execute(() -> InvocationUtils.callSafely(listener::onMessageConfirmed, messageId)));\n    }\n\n    /*\n     * Utils\n     */\n\n    private synchronized void setSparkplugCloudEndpoint(SparkplugCloudEndpoint endpoint) {\n        this.sparkplugCloudEndpoint = Optional.of(endpoint);\n        this.sparkplugCloudEndpoint.get().registerCloudConnectionListener(this);\n        this.sparkplugCloudEndpoint.get().registerCloudDeliveryListener(this);\n    }\n\n    private synchronized void unsetSparkplugCloudEndpoint(SparkplugCloudEndpoint endpoint) {\n        if (this.sparkplugCloudEndpoint.isPresent() && this.sparkplugCloudEndpoint.get() == endpoint) {\n            this.sparkplugCloudEndpoint.get().unregisterCloudConnectionListener(this);\n            this.sparkplugCloudEndpoint.get().unregisterCloudDeliveryListener(this);\n            this.sparkplugCloudEndpoint = Optional.empty();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/SeqCounter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint;\n\n\npublic class SeqCounter {\n\n    private int seq = 1; // start from 1 since 0 is reserved for BIRTH messages\n\n    public synchronized void next() {\n        if (this.seq == 255) {\n            this.seq = 1;\n        } else {\n            this.seq = this.seq + 1;\n        }\n    }\n\n    public synchronized int getCurrent() {\n        return this.seq;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/SparkplugCloudEndpoint.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraDisconnectException;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.cloud.CloudConnectionEstablishedEvent;\nimport org.eclipse.kura.cloud.CloudConnectionLostEvent;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugMessageType;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugPayloads;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugTopics;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.protobuf.InvalidProtocolBufferException;\n\npublic class SparkplugCloudEndpoint\n        implements ConfigurableComponent, CloudEndpoint, CloudConnectionManager, DataServiceListener {\n\n    public static final String PLACEHOLDER_GROUP_ID = \"placeholder.group.id\";\n    public static final String PLACEHOLDER_NODE_ID = \"placeholder.node.id\";\n\n    private static final Logger logger = LoggerFactory.getLogger(SparkplugCloudEndpoint.class);\n\n    private Set<CloudConnectionListener> cloudConnectionListeners = new HashSet<>();\n    private Set<CloudDeliveryListener> cloudDeliveryListeners = new HashSet<>();\n    private String kuraServicePid;\n    private SeqCounter seqCounter = new SeqCounter();\n    private SubscriptionsMap subscriptions = new SubscriptionsMap();\n    private ExecutorService executorService = Executors.newCachedThreadPool();\n\n    /*\n     * Activation APIs\n     */\n\n    private DataService dataService;\n    private EventAdmin eventAdmin;\n\n    public void setDataService(final DataService dataService) {\n        this.dataService = dataService;\n    }\n\n    public void setEventAdmin(final EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    public void activate(final Map<String, Object> properties) {\n        this.kuraServicePid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n        logger.info(\"{} - Activating\", this.kuraServicePid);\n\n        this.dataService.addDataServiceListener(this);\n        update();\n\n        logger.info(\"{} - Activated\", this.kuraServicePid);\n    }\n\n    public void update() {\n        logger.info(\"{} - Updating\", this.kuraServicePid);\n\n        this.seqCounter = new SeqCounter();\n        logger.debug(\"{} - seq number reset to {}\", this.kuraServicePid, this.seqCounter.getCurrent());\n\n        logger.info(\"{} - Updated\", this.kuraServicePid);\n    }\n\n    public void deactivate() {\n        logger.info(\"{} - Deactivating\", this.kuraServicePid);\n\n        try {\n            disconnect();\n        } catch (KuraDisconnectException e) {\n            logger.info(\"{} - Error disconnecting\", this.kuraServicePid, e);\n        }\n\n        this.executorService.shutdownNow();\n\n        logger.info(\"{} - Deactivated\", this.kuraServicePid);\n    }\n\n    /*\n     * CloudEndpoint APIs\n     */\n\n    @Override\n    public String publish(final KuraMessage message) throws KuraException {\n        Map<String, Object> messageProperties = message.getProperties();\n        if (!messageProperties.containsKey(SparkplugDevice.KEY_MESSAGE_TYPE)\n                || !messageProperties.containsKey(SparkplugDevice.KEY_DEVICE_ID)) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                    \"KuraMessage has a missing property between message.type and device.id\");\n        }\n\n        SparkplugMessageType type = (SparkplugMessageType) messageProperties.get(SparkplugDevice.KEY_MESSAGE_TYPE);\n        String deviceId = (String) messageProperties.get(SparkplugDevice.KEY_DEVICE_ID);\n\n        logger.debug(\"{} - Sending message with seq: {}\", this.kuraServicePid, this.seqCounter.getCurrent());\n\n        byte[] sparkplugPayload = SparkplugPayloads.getSparkplugDevicePayload(this.seqCounter.getCurrent(),\n                message.getPayload());\n\n        this.seqCounter.next();\n\n        if (type == SparkplugMessageType.DBIRTH) {\n            return publishInternal(\n                    SparkplugTopics.getDeviceBirthTopic(PLACEHOLDER_GROUP_ID, PLACEHOLDER_NODE_ID, deviceId),\n                    sparkplugPayload, 0, false, 0);\n        }\n\n        if (type == SparkplugMessageType.DDATA) {\n            return publishInternal(\n                    SparkplugTopics.getDeviceDataTopic(PLACEHOLDER_GROUP_ID, PLACEHOLDER_NODE_ID, deviceId),\n                    sparkplugPayload, 0, false, 7);\n        }\n\n        return null;\n    }\n\n    private String publishInternal(String topic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraStoreException {\n        int id = this.dataService.publish(topic, payload, qos, retain, priority);\n\n        if (qos == 0) {\n            return null;\n        }\n\n        return String.valueOf(id);\n    }\n\n    @Override\n    public void registerSubscriber(Map<String, Object> subscriptionProperties,\n            CloudSubscriberListener cloudSubscriberListener) {\n        String topicFilter = (String) subscriptionProperties.get(SparkplugSubscriber.KEY_TOPIC_FILTER);\n        int qos = (int) subscriptionProperties.get(SparkplugSubscriber.KEY_QOS);\n\n        this.subscriptions.add(topicFilter, qos, cloudSubscriberListener);\n        subscribeIfConnected(topicFilter, qos);\n\n        logger.info(\"{} - Added subscription for {}\", this.kuraServicePid,\n                cloudSubscriberListener.getClass().getSimpleName());\n    }\n\n    @Override\n    public void unregisterSubscriber(CloudSubscriberListener cloudSubscriberListener) {\n        this.subscriptions.remove(cloudSubscriberListener).forEach(this::unsubscribeIfConnected);\n\n        logger.info(\"{} - Removed subscription for {}\", this.kuraServicePid,\n                cloudSubscriberListener.getClass().getSimpleName());\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        logger.debug(\"{} - Adding CloudDeliveryListener {}\", this.kuraServicePid,\n                cloudDeliveryListener.getClass().getName());\n        this.cloudDeliveryListeners.add(cloudDeliveryListener);\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        logger.debug(\"{} - Removing CloudDeliveryListener {}\", this.kuraServicePid,\n                cloudDeliveryListener.getClass().getName());\n        this.cloudDeliveryListeners.remove(cloudDeliveryListener);\n    }\n\n    /*\n     * CloudConnectionManager APIs\n     */\n\n    @Override\n    public void connect() throws KuraConnectException {\n        this.dataService.connect();\n    }\n\n    @Override\n    public void disconnect() throws KuraDisconnectException {\n        this.dataService.disconnect(0);\n    }\n\n    @Override\n    public boolean isConnected() {\n        return this.dataService.isConnected();\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        logger.debug(\"{} - Adding CloudConnectionListener {}\", this.kuraServicePid,\n                cloudConnectionListener.getClass().getName());\n        this.cloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        logger.debug(\"{} - Removing CloudConnectionListener {}\", this.kuraServicePid,\n                cloudConnectionListener.getClass().getName());\n        this.cloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    /*\n     * DataServiceListener APIs\n     */\n\n    @Override\n    public void onConnectionEstablished() {\n        logger.debug(\"{} - Connection estabilished\", this.kuraServicePid);\n\n        this.cloudConnectionListeners\n                .forEach(listener -> InvocationUtils.callSafely(listener::onConnectionEstablished));\n        postConnectionChangeEvent(true);\n\n        this.seqCounter = new SeqCounter();\n\n        this.subscriptions.getSubscriptionRecords()\n                .forEach(subscription -> subscribeIfConnected(subscription.getTopicFilter(), subscription.getQos()));\n    }\n\n    @Override\n    public void onDisconnecting() {\n        // nothing to do\n    }\n\n    @Override\n    public void onDisconnected() {\n        logger.debug(\"{} - Disconnected\", this.kuraServicePid);\n        this.cloudConnectionListeners.forEach(listener -> InvocationUtils.callSafely(listener::onDisconnected));\n        postConnectionChangeEvent(false);\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        logger.debug(\"{} - Connection lost\", this.kuraServicePid);\n        this.cloudConnectionListeners.forEach(listener -> InvocationUtils.callSafely(listener::onConnectionLost));\n        postConnectionChangeEvent(false);\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n        logger.debug(\"{} - Message arrived on topic {}, forwarding to registered subscribers\", this.kuraServicePid,\n                topic);\n\n        for (CloudSubscriberListener listener : this.subscriptions.getMatchingListeners(topic, qos)) {\n            try {\n                KuraMessage message = new KuraMessage(SparkplugPayloads.getKuraPayload(payload));\n\n                this.executorService.execute(() -> InvocationUtils.callSafely(listener::onMessageArrived, message));\n            } catch (InvalidProtocolBufferException e) {\n                logger.error(\"{} - Error parsing received SparkplugPayload to KuraPayload\", this.kuraServicePid, e);\n            }\n        }\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        // nothing to do\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        logger.debug(\"{} - Message with ID {} confirmed\", this.kuraServicePid, messageId);\n        this.cloudDeliveryListeners.forEach(\n                listener -> InvocationUtils.callSafely(listener::onMessageConfirmed, String.valueOf(messageId)));\n    }\n\n    /*\n     * Utilities\n     */\n\n    private void postConnectionChangeEvent(final boolean isConnected) {\n        logger.debug(\"{} - Posting connection changed event\", this.kuraServicePid);\n\n        Map<String, Object> eventProperties = new HashMap<>();\n        eventProperties.put(\"cloud.service.pid\", this.kuraServicePid);\n\n        Event event = isConnected ? new CloudConnectionEstablishedEvent(eventProperties)\n                : new CloudConnectionLostEvent(eventProperties);\n\n        this.eventAdmin.postEvent(event);\n    }\n\n    private synchronized void subscribeIfConnected(String topicFilter, int qos) {\n        try {\n            if (isConnected()) {\n                this.dataService.subscribe(topicFilter, qos);\n            }\n        } catch (KuraException e) {\n            logger.error(\"{} - Error subscribing to topic \" + topicFilter + \" with QoS \" + qos, this.kuraServicePid, e);\n        }\n    }\n\n    private synchronized void unsubscribeIfConnected(String topic) {\n        try {\n            if (isConnected()) {\n                this.dataService.unsubscribe(topic);\n            }\n        } catch (KuraException e) {\n            logger.error(\"{} - Error unsubscribing from topic {}\", this.kuraServicePid, topic);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/SubscriptionRecord.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint;\n\nimport org.eclipse.paho.client.mqttv3.MqttTopic;\n\npublic class SubscriptionRecord {\n\n    private final String topicFilter;\n    private final Integer qos;\n\n    public SubscriptionRecord(String topicFilter, int qos) {\n        this.topicFilter = topicFilter;\n        this.qos = qos;\n    }\n\n    public String getTopicFilter() {\n        return this.topicFilter;\n    }\n\n    public Integer getQos() {\n        return this.qos;\n    }\n\n    public boolean matches(String topic, int qos) {\n        return this.qos <= qos && MqttTopic.isMatched(this.topicFilter, topic);\n    }\n\n    @Override\n    public boolean equals(Object other) {\n        if (other == this) {\n            return true;\n        }\n\n        if (!(other instanceof SubscriptionRecord)) {\n            return false;\n        }\n\n        SubscriptionRecord otherRecord = (SubscriptionRecord) other;\n\n        return otherRecord.getTopicFilter().equals(this.topicFilter) && otherRecord.getQos().equals(this.qos);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 7;\n        int result = 1;\n        result = prime * result + this.topicFilter.hashCode();\n        result = prime * result + this.qos.hashCode();\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/SubscriptionsMap.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\n\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\n\npublic class SubscriptionsMap {\n\n    private Map<SubscriptionRecord, Set<CloudSubscriberListener>> subscriptions = new HashMap<>();\n\n    public void add(String topicFilter, int qos, CloudSubscriberListener listener) {\n        SubscriptionRecord subscription = new SubscriptionRecord(topicFilter, qos);\n\n        Set<CloudSubscriberListener> listeners = this.subscriptions.computeIfAbsent(subscription,\n                key -> new CopyOnWriteArraySet<CloudSubscriberListener>());\n\n        listeners.add(listener);\n    }\n\n    public List<String> remove(CloudSubscriberListener listener) {\n        List<String> topicsToUnsubscribe = new ArrayList<>();\n\n        this.subscriptions.entrySet().removeIf(entry -> {\n            entry.getValue().remove(listener);\n\n            if (entry.getValue().isEmpty()) {\n                topicsToUnsubscribe.add(entry.getKey().getTopicFilter());\n                return true;\n            }\n\n            return false;\n        });\n\n        return topicsToUnsubscribe;\n    }\n\n    public List<CloudSubscriberListener> getMatchingListeners(String topic, int qos) {\n        List<CloudSubscriberListener> result = new ArrayList<>();\n\n        this.subscriptions.forEach((subscription, listeners) -> {\n            if (subscription.matches(topic, qos)) {\n                result.addAll(listeners);\n            }\n        });\n\n        return result;\n    }\n\n    public Set<SubscriptionRecord> getSubscriptionRecords() {\n        return this.subscriptions.keySet();\n    }\n\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/factory/SparkplugCloudConnectionFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.component.ComponentConstants;\n\npublic class SparkplugCloudConnectionFactory implements CloudConnectionFactory {\n\n    private static final String FACTORY_PID = \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.SparkplugCloudConnectionFactory\";\n\n    private static final String CLOUD_ENDPOINT_FACTORY_PID = \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\";\n    private static final String DATA_SERVICE_FACTORY_PID = \"org.eclipse.kura.data.DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID =\n            \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\";\n\n    private static final String CLOUD_ENDPOINT_PID = \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\";\n    private static final String DATA_SERVICE_PID = \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.data.SparkplugDataService\";\n    private static final String DATA_TRANSPORT_SERVICE_PID = \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\";\n\n    private static final String DATA_SERVICE_REFERENCE_NAME = \"DataService\"\n            + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n    private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = \"DataTransportService\"\n            + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n\n    private static final String REFERENCE_TARGET_VALUE_FORMAT = \"(\" + ConfigurationService.KURA_SERVICE_PID + \"=%s)\";\n\n    private ConfigurationService configurationService;\n\n    public void setConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    @Override\n    public String getFactoryPid() {\n        return CLOUD_ENDPOINT_FACTORY_PID;\n    }\n\n    @Override\n    public void createConfiguration(String pid) throws KuraException {\n        String dataServicePid = getStackPidWithSuffix(pid, DATA_SERVICE_PID);\n        String dataTransportServicePid = getStackPidWithSuffix(pid, DATA_TRANSPORT_SERVICE_PID);\n\n        // CloudEndpoint\n        Map<String, Object> cloudEndpointProperties = new HashMap<>();\n        cloudEndpointProperties.put(DATA_SERVICE_REFERENCE_NAME,\n                String.format(REFERENCE_TARGET_VALUE_FORMAT, dataServicePid));\n        cloudEndpointProperties.put(KURA_CLOUD_CONNECTION_FACTORY_PID, FACTORY_PID);\n        cloudEndpointProperties.put(DATA_TRANSPORT_SERVICE_REFERENCE_NAME,\n                String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid));\n\n        this.configurationService.createFactoryConfiguration(CLOUD_ENDPOINT_FACTORY_PID, pid, cloudEndpointProperties,\n                false);\n\n        // DataService\n        Map<String, Object> dataServiceProperties = new HashMap<>();\n        dataServiceProperties.put(DATA_TRANSPORT_SERVICE_REFERENCE_NAME,\n                String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid));\n\n        this.configurationService.createFactoryConfiguration(DATA_SERVICE_FACTORY_PID, dataServicePid,\n                dataServiceProperties, false);\n\n        // DataTransportService\n        this.configurationService.createFactoryConfiguration(DATA_TRANSPORT_SERVICE_FACTORY_PID,\n                dataTransportServicePid, null, true);\n    }\n\n    @Override\n    public List<String> getStackComponentsPids(String pid) throws KuraException {\n        String dataServicePid = getStackPidWithSuffix(pid, DATA_SERVICE_PID);\n        String dataTransportServicePid = getStackPidWithSuffix(pid, DATA_TRANSPORT_SERVICE_PID);\n\n        List<String> stackComponentPids = new LinkedList<>();\n        stackComponentPids.add(pid);\n        stackComponentPids.add(dataServicePid);\n        stackComponentPids.add(dataTransportServicePid);\n\n        return stackComponentPids;\n    }\n\n    @Override\n    public void deleteConfiguration(String pid) throws KuraException {\n        String dataServicePid = getStackPidWithSuffix(pid, DATA_SERVICE_PID);\n        String dataTransportServicePid = getStackPidWithSuffix(pid, DATA_TRANSPORT_SERVICE_PID);\n\n        this.configurationService.deleteFactoryConfiguration(pid, false);\n        this.configurationService.deleteFactoryConfiguration(dataServicePid, false);\n        this.configurationService.deleteFactoryConfiguration(dataTransportServicePid, true);\n    }\n\n    @Override\n    public Set<String> getManagedCloudConnectionPids() throws KuraException {\n        final BundleContext context = FrameworkUtil.getBundle(SparkplugCloudConnectionFactory.class).getBundleContext();\n\n        try {\n            return context\n                    .getServiceReferences(CloudEndpoint.class,\n                            \"(service.factoryPid=\" + CLOUD_ENDPOINT_FACTORY_PID + \")\")\n                    .stream().map(ref -> (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID))\n                    .collect(Collectors.toSet());\n        } catch (InvalidSyntaxException e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, e);\n        }\n    }\n\n    private String getStackPidWithSuffix(String userPid, String componentPid) throws KuraException {\n        if (!userPid.startsWith(CLOUD_ENDPOINT_PID)) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Invalid PID '{}'\", userPid);\n        }\n\n        String[] parts = userPid.split(\"-\");\n\n        if (parts.length > 1) {\n            return componentPid + \"-\" + parts[1];\n        } else {\n            return componentPid;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/SparkplugBProtobufPayloadBuilder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.message;\n\nimport java.math.BigInteger;\nimport java.util.Date;\n\nimport org.eclipse.tahu.protobuf.SparkplugBProto.DataType;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.protobuf.ByteString;\n\npublic class SparkplugBProtobufPayloadBuilder {\n\n    private static final Logger logger = LoggerFactory.getLogger(SparkplugBProtobufPayloadBuilder.class);\n\n    public static final String BDSEQ_METRIC_NAME = \"bdSeq\";\n\n    private Payload.Builder payloadBuilder = Payload.newBuilder();\n\n    public SparkplugBProtobufPayloadBuilder withMetric(String name, Object value, long timestamp) {\n        DataType sparkplugDataType = DataType.Unknown;\n\n        if (value instanceof Boolean) {\n            sparkplugDataType = DataType.Boolean;\n        }\n\n        if (value instanceof byte[]) {\n            sparkplugDataType = DataType.Bytes;\n        }\n\n        if (value instanceof Double) {\n            sparkplugDataType = DataType.Double;\n        }\n\n        if (value instanceof Float) {\n            sparkplugDataType = DataType.Float;\n        }\n\n        if (value instanceof Byte) {\n            sparkplugDataType = DataType.Int8;\n        }\n\n        if (value instanceof Short) {\n            sparkplugDataType = DataType.Int16;\n        }\n\n        if (value instanceof Integer) {\n            sparkplugDataType = DataType.Int32;\n        }\n\n        if (value instanceof Long) {\n            sparkplugDataType = DataType.Int64;\n        }\n\n        if (value instanceof String) {\n            sparkplugDataType = DataType.String;\n        }\n\n        if (value instanceof Date) {\n            sparkplugDataType = DataType.DateTime;\n        }\n\n        if (value instanceof BigInteger) {\n            sparkplugDataType = DataType.UInt64;\n        }\n\n        logger.debug(\"Converting Java Type: {} to Sparkplug.DataType: {}\", value.getClass().getName(),\n                sparkplugDataType);\n\n        return this.withMetric(name, value, sparkplugDataType, timestamp);\n    }\n\n    public SparkplugBProtobufPayloadBuilder withMetric(String name, Object value, DataType dataType, long timestamp) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setDatatype(dataType.getNumber());\n        metricBuilder.setTimestamp(timestamp);\n\n        switch (dataType) {\n        case Boolean:\n            metricBuilder.setBooleanValue((Boolean) value);\n            break;\n        case Bytes:\n            metricBuilder.setBytesValue(ByteString.copyFrom((byte[]) value));\n            break;\n        case Double:\n            metricBuilder.setDoubleValue((Double) value);\n            break;\n        case Float:\n            metricBuilder.setFloatValue((Float) value);\n            break;\n        case Int8:\n            metricBuilder.setIntValue((Byte) value);\n            break;\n        case Int16:\n            metricBuilder.setIntValue((Short) value);\n            break;\n        case Int32:\n            metricBuilder.setIntValue((Integer) value);\n            break;\n        case Int64:\n            metricBuilder.setLongValue((Long) value);\n            break;\n        case String:\n        case Text:\n        case UUID:\n            metricBuilder.setStringValue((String) value);\n            break;\n        case DateTime:\n            metricBuilder.setLongValue(((Date) value).getTime());\n            break;\n        case UInt8:\n            metricBuilder.setIntValue(Short.toUnsignedInt((Short) value));\n            break;\n        case UInt16:\n            metricBuilder.setIntValue((int) Integer.toUnsignedLong((Integer) value));\n            break;\n        case UInt32:\n            metricBuilder.setLongValue(Long.parseUnsignedLong(Long.toUnsignedString((Long) value)));\n            break;\n        case UInt64:\n            metricBuilder.setLongValue(((BigInteger) value).longValue());\n            break;\n        case DataSet:\n        case Template:\n        case PropertySet:\n        case PropertySetList:\n        case File:\n        case BooleanArray:\n        case DateTimeArray:\n        case UInt8Array:\n        case UInt64Array:\n        case UInt32Array:\n        case UInt16Array:\n        case StringArray:\n        case Int8Array:\n        case Int64Array:\n        case Int32Array:\n        case Int16Array:\n        case FloatArray:\n        case DoubleArray:\n        case Unknown:\n        default:\n            throw new UnsupportedOperationException(\"DataType \" + dataType.toString() + \" not implemented\");\n        }\n\n        this.payloadBuilder.addMetrics(metricBuilder.build());\n\n        return this;\n    }\n\n    public SparkplugBProtobufPayloadBuilder withBdSeq(long bdSeq, long timestamp) {\n        Payload.Metric.Builder bdSeqMetric = Payload.Metric.newBuilder();\n        bdSeqMetric.setName(BDSEQ_METRIC_NAME);\n        bdSeqMetric.setLongValue(bdSeq);\n        bdSeqMetric.setDatatype(DataType.Int64.getNumber());\n        bdSeqMetric.setTimestamp(timestamp);\n\n        this.payloadBuilder.addMetrics(bdSeqMetric.build());\n        return this;\n    }\n\n    public SparkplugBProtobufPayloadBuilder withSeq(long seq) {\n        this.payloadBuilder.setSeq(seq);\n        return this;\n    }\n\n    public SparkplugBProtobufPayloadBuilder withTimestamp(long timestamp) {\n        this.payloadBuilder.setTimestamp(timestamp);\n        return this;\n    }\n\n    public SparkplugBProtobufPayloadBuilder withBody(byte[] body) {\n        this.payloadBuilder.setBody(ByteString.copyFrom(body));\n        return this;\n    }\n\n    public Payload buildPayload() {\n        return this.payloadBuilder.build();\n    }\n\n    public byte[] build() {\n        return this.buildPayload().toByteArray();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/SparkplugMessageType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.message;\n\n\npublic enum SparkplugMessageType {\n    NBIRTH,\n    NDEATH,\n    NCMD,\n    DBIRTH,\n    DDEATH,\n    DDATA,\n    DCMD,\n    STATE\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/SparkplugPayloads.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.message;\n\nimport java.util.Date;\nimport java.util.Map.Entry;\nimport java.util.Objects;\n\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.DataType;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload.Metric;\n\nimport com.google.protobuf.InvalidProtocolBufferException;\n\npublic class SparkplugPayloads {\n\n    public static final String NODE_CONTROL_REBIRTH_METRIC_NAME = \"Node Control/Rebirth\";\n\n    private SparkplugPayloads() {\n    }\n\n    public static byte[] getNodeDeathPayload(long bdSeq) {\n        return new SparkplugBProtobufPayloadBuilder().withBdSeq(bdSeq, new Date().getTime()).build();\n    }\n\n    public static byte[] getNodeBirthPayload(long bdSeq, long seq) {\n        long timestamp = new Date().getTime();\n\n        SparkplugBProtobufPayloadBuilder payloadBuilder = new SparkplugBProtobufPayloadBuilder();\n        payloadBuilder.withBdSeq(bdSeq, timestamp);\n        payloadBuilder.withMetric(NODE_CONTROL_REBIRTH_METRIC_NAME, false, DataType.Boolean, timestamp);\n        payloadBuilder.withSeq(seq);\n        payloadBuilder.withTimestamp(timestamp);\n\n        return payloadBuilder.build();\n    }\n\n    public static boolean getBooleanMetric(String metricName, byte[] rawSparkplugPayload)\n            throws InvalidProtocolBufferException, NoSuchFieldException {\n        Payload payload = Payload.parseFrom(rawSparkplugPayload);\n\n        for (Metric metric : payload.getMetricsList()) {\n            if (metric.getName().equals(metricName)) {\n                return metric.getBooleanValue();\n            }\n        }\n        \n        throw new NoSuchFieldException(\"Metric \" + metricName + \" not found in payload\");\n    }\n\n    public static byte[] getSparkplugDevicePayload(final long seq, final KuraPayload kuraPayload) {\n        SparkplugBProtobufPayloadBuilder payloadBuilder = new SparkplugBProtobufPayloadBuilder();\n\n        byte[] payloadBody = kuraPayload.getBody();\n        if (Objects.nonNull(payloadBody)) {\n            payloadBuilder.withBody(payloadBody);\n        }\n\n        Date kuraTimestamp = kuraPayload.getTimestamp();\n        long timestamp = Objects.nonNull(kuraTimestamp) ? kuraTimestamp.getTime() : new Date().getTime();\n        payloadBuilder.withTimestamp(timestamp);\n\n        for (Entry<String, Object> metric : kuraPayload.metrics().entrySet()) {\n            payloadBuilder.withMetric(metric.getKey(), metric.getValue(), timestamp);\n        }\n\n        KuraPosition position = kuraPayload.getPosition();\n        if (Objects.nonNull(position)) {\n            addMetricIfNonNull(payloadBuilder, \"kura.position.altitude\", position.getAltitude(), timestamp);\n            addMetricIfNonNull(payloadBuilder, \"kura.position.latitude\", position.getLatitude(), timestamp);\n            addMetricIfNonNull(payloadBuilder, \"kura.position.longitude\", position.getLongitude(), timestamp);\n            addMetricIfNonNull(payloadBuilder, \"kura.position.heading\", position.getHeading(), timestamp);\n            addMetricIfNonNull(payloadBuilder, \"kura.position.precision\", position.getPrecision(), timestamp);\n            addMetricIfNonNull(payloadBuilder, \"kura.position.satellites\", position.getSatellites(), timestamp);\n            addMetricIfNonNull(payloadBuilder, \"kura.position.speed\", position.getSpeed(), timestamp);\n            addMetricIfNonNull(payloadBuilder, \"kura.position.status\", position.getStatus(), timestamp);\n            addMetricIfNonNull(payloadBuilder, \"kura.position.timestamp\", position.getTimestamp(), timestamp);\n        }\n\n        payloadBuilder.withSeq(seq);\n        payloadBuilder.withTimestamp(timestamp);\n\n        return payloadBuilder.build();\n    }\n\n    public static KuraPayload getKuraPayload(byte[] rawSparkplugPayload) throws InvalidProtocolBufferException {\n        KuraPayload kuraPayload = new KuraPayload();\n        Payload sparkplugPayload = Payload.parseFrom(rawSparkplugPayload);\n        \n        for (Metric metric : sparkplugPayload.getMetricsList()) {\n            kuraPayload.addMetric(metric.getName(), getMetricValue(metric));\n        }\n\n        if (sparkplugPayload.hasBody()) {\n            kuraPayload.setBody(sparkplugPayload.getBody().toByteArray());\n        }\n\n        if (Objects.nonNull(sparkplugPayload.getSeq())) {\n            kuraPayload.addMetric(\"seq\", sparkplugPayload.getSeq());\n        }\n\n        if (Objects.nonNull(sparkplugPayload.getTimestamp())) {\n            kuraPayload.setTimestamp(new Date(sparkplugPayload.getTimestamp()));\n        }\n\n        return kuraPayload;\n    }\n\n    private static void addMetricIfNonNull(SparkplugBProtobufPayloadBuilder payloadBuilder, String name, Object value,\n            long timestamp) {\n        if (Objects.nonNull(value)) {\n            payloadBuilder.withMetric(name, value, timestamp);\n        }\n    }\n\n    private static Object getMetricValue(Metric metric) {\n        switch (metric.getValueCase()) {\n        case BOOLEAN_VALUE:\n            return metric.getBooleanValue();\n        case BYTES_VALUE:\n            return metric.getBytesValue().toByteArray();\n        case DATASET_VALUE:\n            return metric.getDatasetValue().toByteArray();\n        case DOUBLE_VALUE:\n            return metric.getDoubleValue();\n        case EXTENSION_VALUE:\n            return metric.getExtensionValue().toByteArray();\n        case FLOAT_VALUE:\n            return metric.getFloatValue();\n        case INT_VALUE:\n            return metric.getIntValue();\n        case LONG_VALUE:\n            return metric.getLongValue();\n        case STRING_VALUE:\n            return metric.getStringValue();\n        case TEMPLATE_VALUE:\n            return metric.getTemplateValue().toByteArray();\n        case VALUE_NOT_SET:\n        default:\n            return null;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/SparkplugTopics.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.message;\n\n\npublic class SparkplugTopics {\n\n    private SparkplugTopics() {\n    }\n\n    private static final String NAMESPACE = \"spBv1.0\";\n\n    // Edge Node topics\n\n    public static String getNodeBirthTopic(String groupId, String nodeId) {\n        return getTopic(groupId, SparkplugMessageType.NBIRTH.toString(), nodeId);\n    }\n\n    public static String getNodeDeathTopic(String groupId, String nodeId) {\n        return getTopic(groupId, SparkplugMessageType.NDEATH.toString(), nodeId);\n    }\n\n    public static String getNodeCommandTopic(String groupId, String nodeId) {\n        return getTopic(groupId, SparkplugMessageType.NCMD.toString(), nodeId);\n    }\n\n    // Device topics\n\n    public static String getDeviceBirthTopic(String groupId, String nodeId, String deviceId) {\n        return getTopic(groupId, SparkplugMessageType.DBIRTH.toString(), nodeId, deviceId);\n    }\n\n    public static String getDeviceDeathTopic(String groupId, String nodeId, String deviceId) {\n        return getTopic(groupId, SparkplugMessageType.DDEATH.toString(), nodeId, deviceId);\n    }\n\n    public static String getDeviceDataTopic(String groupId, String nodeId, String deviceId) {\n        return getTopic(groupId, SparkplugMessageType.DDATA.toString(), nodeId, deviceId);\n    }\n\n    public static String getDeviceCommandTopic(String groupId, String nodeId, String deviceId) {\n        return getTopic(groupId, SparkplugMessageType.DCMD.toString(), nodeId, deviceId);\n    }\n\n    // Host Application topics\n\n    public static String getStateTopic(String hostId) {\n        return getTopic(SparkplugMessageType.STATE.toString(), hostId);\n    }\n\n    private static String getTopic(String... args) {\n        StringBuilder topicBuilder = new StringBuilder(NAMESPACE);\n\n        for (String arg : args) {\n            topicBuilder.append(\"/\");\n            topicBuilder.append(arg);\n        }\n\n        return topicBuilder.toString();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/subscriber/SparkplugSubscriber.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.SparkplugCloudEndpointTracker;\nimport org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.paho.client.mqttv3.MqttTopic;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SparkplugSubscriber\n        implements ConfigurableComponent, CloudSubscriber, CloudSubscriberListener, CloudConnectionListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(SparkplugSubscriber.class);\n\n    public static final String KEY_TOPIC_FILTER = \"topic.filter\";\n    public static final String KEY_QOS = \"qos\";\n\n    private Optional<SparkplugCloudEndpoint> sparkplugCloudEndpoint = Optional.empty();\n    private SparkplugCloudEndpointTracker endpointTracker;\n    private final ExecutorService executorService = Executors.newCachedThreadPool();\n    private Set<CloudSubscriberListener> cloudSubscriberListeners = new CopyOnWriteArraySet<>();\n    private Set<CloudConnectionListener> cloudConnectionListeners = new CopyOnWriteArraySet<>();\n\n    private String kuraServicePid;\n    private String topicFilter;\n    private int qos;\n\n    /*\n     * Activation APIs\n     */\n\n    public void activate(final ComponentContext componentContext, final Map<String, Object> properties)\n            throws InvalidSyntaxException {\n        this.kuraServicePid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n\n        logger.info(\"{} - Activating\", this.kuraServicePid);\n\n        String endpointPid = (String) properties\n                .get(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value());\n\n        this.endpointTracker = new SparkplugCloudEndpointTracker(componentContext.getBundleContext(),\n                this::setSparkplugCloudEndpoint, this::unsetSparkplugCloudEndpoint, endpointPid);\n        update(properties);\n\n        logger.info(\"{} - Activated\", this.kuraServicePid);\n    }\n\n    public void update(final Map<String, Object> properties) throws InvalidSyntaxException {\n        logger.info(\"{} - Updating\", this.kuraServicePid);\n\n        this.topicFilter = (String) properties.get(KEY_TOPIC_FILTER);\n        this.qos = (int) properties.get(KEY_QOS);\n        MqttTopic.validate(this.topicFilter, true);\n\n        this.endpointTracker.stopEndpointTracker();\n        this.endpointTracker.startEndpointTracker();\n\n        logger.info(\"{} - Updated\", this.kuraServicePid);\n    }\n\n    public void deactivate() {\n        logger.info(\"{} - Deactivating\", this.kuraServicePid);\n\n        this.endpointTracker.stopEndpointTracker();\n\n        logger.debug(\"{} - Shutting down executor service\", this.kuraServicePid);\n        this.executorService.shutdownNow();\n\n        logger.info(\"{} - Deactivated\", this.kuraServicePid);\n    }\n\n    /*\n     * CloudSubscriber APIs\n     */\n\n    @Override\n    public void registerCloudSubscriberListener(CloudSubscriberListener listener) {\n        this.cloudSubscriberListeners.add(listener);\n    }\n\n    @Override\n    public void unregisterCloudSubscriberListener(CloudSubscriberListener listener) {\n        this.cloudSubscriberListeners.remove(listener);\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    /*\n     * CloudSubscriberListener APIs\n     */\n\n    @Override\n    public void onMessageArrived(KuraMessage message) {\n        this.cloudSubscriberListeners.forEach(listener -> this.executorService\n                .execute(() -> InvocationUtils.callSafely(listener::onMessageArrived, message)));\n    }\n\n    /*\n     * CloudConnectionListener APIs\n     */\n\n    @Override\n    public void onDisconnected() {\n        this.cloudConnectionListeners.forEach(\n                listener -> this.executorService.execute(() -> InvocationUtils.callSafely(listener::onDisconnected)));\n    }\n\n    @Override\n    public void onConnectionLost() {\n        this.cloudConnectionListeners.forEach(\n                listener -> this.executorService.execute(() -> InvocationUtils.callSafely(listener::onConnectionLost)));\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        this.cloudConnectionListeners.forEach(listener -> this.executorService\n                .execute(() -> InvocationUtils.callSafely(listener::onConnectionEstablished)));\n    }\n\n    /*\n     * Utils\n     */\n\n    private synchronized void setSparkplugCloudEndpoint(SparkplugCloudEndpoint endpoint) {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_TOPIC_FILTER, this.topicFilter);\n        properties.put(KEY_QOS, this.qos);\n\n        this.sparkplugCloudEndpoint = Optional.of(endpoint);\n        this.sparkplugCloudEndpoint.get().registerSubscriber(properties, this);\n    }\n\n    private synchronized void unsetSparkplugCloudEndpoint(SparkplugCloudEndpoint endpoint) {\n        if (this.sparkplugCloudEndpoint.isPresent() && this.sparkplugCloudEndpoint.get() == endpoint) {\n            this.sparkplugCloudEndpoint.get().unregisterSubscriber(this);\n            this.sparkplugCloudEndpoint = Optional.empty();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/BdSeqCounter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport;\n\npublic class BdSeqCounter {\n\n    private int bdSeq = -1; // first invocation of next should return 0\n\n    public synchronized void next() {\n        if (this.bdSeq == 255) {\n            this.bdSeq = 0;\n        } else {\n            this.bdSeq = this.bdSeq + 1;\n        }\n    }\n\n    public synchronized int getCurrent() {\n        return this.bdSeq;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/SparkplugDataTransport.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport;\n\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraNotConnectedException;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.eclipse.kura.ssl.SslManagerService;\nimport org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;\nimport org.eclipse.paho.client.mqttv3.MqttCallback;\nimport org.eclipse.paho.client.mqttv3.MqttException;\nimport org.eclipse.paho.client.mqttv3.MqttMessage;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SparkplugDataTransport implements ConfigurableComponent, DataTransportService, MqttCallback {\n\n    private static final Logger logger = LoggerFactory.getLogger(SparkplugDataTransport.class);\n\n    private String kuraServicePid;\n    private String sessionId;\n    private SparkplugMqttClient client;\n    private SparkplugDataTransportOptions options;\n    private Set<DataTransportListener> dataTransportListeners = new HashSet<>();\n    private ExecutorService executorService;\n    private SslManagerService sslManagerService;\n    private CryptoService cryptoService;\n\n    /*\n     * Activation APIs\n     */\n\n    public synchronized void setSslManagerService(SslManagerService sslManagerService) {\n        this.sslManagerService = sslManagerService;\n        update();\n    }\n\n    public synchronized void unsetSslManagerService(SslManagerService sslManagerService) {\n        if (this.sslManagerService == sslManagerService) {\n            this.sslManagerService = null;\n            update();\n        }\n    }\n\n    public synchronized void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public synchronized void activate(Map<String, Object> properties) {\n        this.kuraServicePid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n        logger.info(\"{} - Activating\", this.kuraServicePid);\n\n        update(properties);\n\n        logger.info(\"{} - Activated\", this.kuraServicePid);\n    }\n\n    public synchronized void update(Map<String, Object> properties) {\n        try {\n            this.options = new SparkplugDataTransportOptions(properties, this.cryptoService);\n            update();\n        } catch (KuraException ke) {\n            logger.error(\"{} - Error in configuration properties\", this.kuraServicePid, ke);\n        }\n    }\n\n    public synchronized void deactivate() {\n        logger.info(\"{} - Deactivating\", this.kuraServicePid);\n\n        disconnect(0);\n\n        logger.info(\"{} - Deactivated\", this.kuraServicePid);\n    }\n\n    private void update() {\n        if (Objects.nonNull(this.options)) {\n            logger.info(\"{} - Updating\", this.kuraServicePid);\n\n            boolean wasConnected = isConnected();\n\n            this.dataTransportListeners\n                    .forEach(listener -> InvocationUtils.callSafely(listener::onConfigurationUpdating, wasConnected));\n\n            try {\n                applyConfiguration(wasConnected);\n            } catch (KuraConnectException ke) {\n                logger.error(\"{} - Error reconnecting after configuration update\", this.kuraServicePid, ke);\n            }\n        }\n    }\n\n    private void applyConfiguration(boolean wasConnected) throws KuraConnectException {\n        if (wasConnected) {\n            disconnect(0);\n        }\n\n        this.sessionId = getBrokerUrl() + \"-\" + getClientId();\n        this.client = new SparkplugMqttClient(this.options, this, this.dataTransportListeners, this.sslManagerService);\n\n        if (wasConnected) {\n            connect();\n        }\n\n        this.dataTransportListeners\n                .forEach(listener -> InvocationUtils.callSafely(listener::onConfigurationUpdated, wasConnected));\n        logger.info(\"{} - Updated\", this.kuraServicePid);\n    }\n\n    /*\n     * DataTransportService APIs\n     */\n\n    @Override\n    public void connect() throws KuraConnectException {\n        if (isConnected()) {\n            throw new IllegalStateException(\"MQTT client is already connected\");\n        }\n\n        this.client.establishSession(true);\n\n        stopExecutorService();\n        this.executorService = Executors.newSingleThreadExecutor();\n        logger.debug(\"{} - Initialized message dispatcher executor\", this.kuraServicePid);\n    }\n\n    @Override\n    public boolean isConnected() {\n        return Objects.nonNull(this.client) && this.client.isSessionEstablished();\n    }\n\n    @Override\n    public String getBrokerUrl() {\n        return Objects.nonNull(this.client) ? this.client.getConnectedServer() : \"\";\n    }\n\n    @Override\n    public synchronized String getAccountName() {\n        return \"\";\n    }\n\n    @Override\n    public String getUsername() {\n        return this.options.getUsername();\n    }\n\n    @Override\n    public String getClientId() {\n        return this.options.getClientId();\n    }\n\n    @Override\n    public void disconnect(long quiesceTimeout) {\n        stopExecutorService();\n        if (Objects.nonNull(this.client)) {\n            this.client.terminateSession(true, quiesceTimeout);\n        }\n    }\n\n    @Override\n    public void subscribe(String topic, int qos) throws KuraException {\n        checkConnected();\n\n        this.client.subscribe(topic, qos);\n    }\n\n    @Override\n    public void unsubscribe(String topic) throws KuraException {\n        checkConnected();\n\n        this.client.unsubscribe(topic);\n    }\n\n    @Override\n    public DataTransportToken publish(String completeTopic, byte[] payload, int qos, boolean retain)\n            throws KuraException {\n        checkConnected();\n\n        String topic = completeTopic.replace(SparkplugCloudEndpoint.PLACEHOLDER_GROUP_ID, this.options.getGroupId())\n                .replace(SparkplugCloudEndpoint.PLACEHOLDER_NODE_ID, this.options.getNodeId());\n\n        IMqttDeliveryToken deliveryToken = this.client.publish(topic, payload, qos, retain);\n\n        if (qos > 0) {\n            return new DataTransportToken(deliveryToken.getMessageId(), this.sessionId);\n        }\n\n        return null;\n    }\n\n    @Override\n    public void addDataTransportListener(DataTransportListener listener) {\n        logger.debug(\"{} - Adding DataTransportListener {}\", this.kuraServicePid, listener.getClass().getName());\n        this.dataTransportListeners.add(listener);\n    }\n\n    @Override\n    public void removeDataTransportListener(DataTransportListener listener) {\n        logger.debug(\"{} - Removing DataTransportListener {}\", this.kuraServicePid, listener.getClass().getName());\n        this.dataTransportListeners.remove(listener);\n    }\n\n    /*\n     * MqttCallback APIs\n     */\n\n    @Override\n    public void connectionLost(Throwable arg0) {\n        logger.info(\"{} - Connection lost\", this.kuraServicePid);\n        this.client.handleConnectionLost();\n        this.dataTransportListeners.forEach(listener -> InvocationUtils.callSafely(listener::onConnectionLost, arg0));\n    }\n\n    @Override\n    public void deliveryComplete(IMqttDeliveryToken deliveryToken) {\n        try {\n            if (deliveryToken.getMessage().getQos() > 0) {\n                DataTransportToken dataTransportToken = new DataTransportToken(deliveryToken.getMessageId(),\n                        this.sessionId);\n\n                this.dataTransportListeners\n                        .forEach(listener -> InvocationUtils.callSafely(listener::onMessageConfirmed,\n                                dataTransportToken));\n            }\n        } catch (MqttException e) {\n            logger.error(\"{} - Error processing MQTTDeliveryToken\", this.kuraServicePid, e);\n        }\n    }\n\n    @Override\n    public void messageArrived(String topic, MqttMessage message) {\n        logger.debug(\"{} - Message arrived on topic {} with QoS {}\", this.kuraServicePid, topic, message.getQos());\n\n        this.executorService.submit(() -> this.dataTransportListeners.forEach(listener -> listener\n                .onMessageArrived(topic, message.getPayload(), message.getQos(), message.isRetained())));\n        this.executorService.submit(this.client.getMessageDispatcher(topic, message));\n    }\n\n    /*\n     * Utils\n     */\n\n    private void checkConnected() throws KuraNotConnectedException {\n        if (!isConnected()) {\n            throw new KuraNotConnectedException(\"MQTT client is not connected\");\n        }\n    }\n\n    private void stopExecutorService() {\n        if (Objects.nonNull(this.executorService)) {\n            logger.debug(\"{} - Shutting down message dispatcher executor\", this.kuraServicePid);\n            this.executorService.shutdownNow();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/SparkplugDataTransportOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.paho.client.mqttv3.MqttConnectOptions;\n\npublic class SparkplugDataTransportOptions {\n\n    public static final String KEY_GROUP_ID = \"group.id\";\n    public static final String KEY_NODE_ID = \"node.id\";\n    public static final String KEY_PRIMARY_HOST_APPLICATION_ID = \"primary.host.application.id\";\n    public static final String KEY_SERVER_URIS = \"server.uris\";\n    public static final String KEY_CLIENT_ID = \"client.id\";\n    public static final String KEY_USERNAME = \"username\";\n    public static final String KEY_PASSWORD = \"password\";\n    public static final String KEY_KEEP_ALIVE = \"keep.alive\";\n    public static final String KEY_CONNECTION_TIMEOUT = \"connection.timeout\";\n\n    private final String groupId;\n    private final String nodeId;\n    private final Optional<String> primaryHostApplicationId;\n    private final List<String> servers;\n    private final MqttConnectOptions connectionOptions = new MqttConnectOptions();\n    private final String clientId;\n\n    public SparkplugDataTransportOptions(final Map<String, Object> properties, final CryptoService cryptoService)\n            throws KuraException {        \n        this.groupId = getMandatoryString(KEY_GROUP_ID, properties);\n        this.nodeId = getMandatoryString(KEY_NODE_ID, properties);\n        this.primaryHostApplicationId = getOptionalString(KEY_PRIMARY_HOST_APPLICATION_ID, properties);\n        this.servers = getServersList(KEY_SERVER_URIS, properties);\n        this.clientId = getMandatoryString(KEY_CLIENT_ID, properties);\n\n        Optional<String> username = getOptionalString(KEY_USERNAME, properties);\n        Optional<Password> password = getOptionalPassword(KEY_PASSWORD, properties);\n        if (username.isPresent()) {\n            this.connectionOptions.setUserName(username.get());\n        }\n        if (password.isPresent()) {\n            this.connectionOptions.setPassword(cryptoService.decryptAes(password.get().getPassword()));\n        }\n\n        this.connectionOptions.setKeepAliveInterval(getMandatoryInt(KEY_KEEP_ALIVE, properties));\n        this.connectionOptions.setConnectionTimeout(getMandatoryInt(KEY_CONNECTION_TIMEOUT, properties));\n\n        this.connectionOptions.setCleanSession(true);\n        this.connectionOptions.setAutomaticReconnect(false);\n    }\n\n    public String getGroupId() {\n        return this.groupId;\n    }\n\n    public String getNodeId() {\n        return this.nodeId;\n    }\n\n    public Optional<String> getPrimaryHostApplicationId() {\n        return this.primaryHostApplicationId;\n    }\n\n    public List<String> getServers() {\n        return this.servers;\n    }\n\n    public MqttConnectOptions getMqttConnectOptions() {\n        return this.connectionOptions;\n    }\n\n    public String getClientId() {\n        return this.clientId;\n    }\n\n    public String getUsername() {\n        return this.connectionOptions.getUserName();\n    }\n\n    public long getConnectionTimeoutMs() {\n        return this.connectionOptions.getConnectionTimeout() * 1000L;\n    }\n\n    private String getMandatoryString(String key, Map<String, Object> map) throws KuraException {\n        String value = (String) map.get(key);\n\n        if (Objects.isNull(value) || value.isEmpty()) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, key + \" cannot be empty or null\");\n        }\n\n        return value;\n    }\n\n    private int getMandatoryInt(String key, Map<String, Object> map) throws KuraException {\n        Integer value = (Integer) map.get(key);\n\n        if (Objects.isNull(value)) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, key + \" cannot be null\");\n        }\n        \n        return value;\n    }\n\n    private Optional<String> getOptionalString(String key, Map<String, Object> map) {\n        String value = (String) map.get(key);\n\n        if (Objects.isNull(value) || value.isEmpty()) {\n            return Optional.empty();\n        } else {\n            return Optional.of(value);\n        }\n    }\n\n    private Optional<Password> getOptionalPassword(String key, Map<String, Object> map) {\n        String value = (String) map.get(key);\n\n        if (Objects.isNull(value) || value.isEmpty()) {\n            return Optional.empty();\n        } else {\n            return Optional.of(new Password(value));\n        }\n    }\n\n    private List<String> getServersList(String key, Map<String, Object> map) throws KuraException {\n        String spaceSeparatedList = (String) map.get(key);\n\n        if (Objects.isNull(spaceSeparatedList) || spaceSeparatedList.isEmpty()) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, key + \" cannot be empty or null\");\n        }\n\n        List<String> result = new ArrayList<>();\n\n        String[] uris = spaceSeparatedList.split(\" \");\n        for (String server : uris) {\n            if (server.endsWith(\"/\") || server.isEmpty()) {\n                throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                        key + \" items cannot be empty, or end with '/', or contain a path\");\n            }\n\n            result.add(server);\n        }\n\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/SparkplugMqttClient.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.security.GeneralSecurityException;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Random;\nimport java.util.Set;\n\nimport javax.net.SocketFactory;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugPayloads;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugTopics;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.eclipse.kura.ssl.SslManagerService;\nimport org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;\nimport org.eclipse.paho.client.mqttv3.IMqttToken;\nimport org.eclipse.paho.client.mqttv3.MqttAsyncClient;\nimport org.eclipse.paho.client.mqttv3.MqttCallback;\nimport org.eclipse.paho.client.mqttv3.MqttConnectOptions;\nimport org.eclipse.paho.client.mqttv3.MqttException;\nimport org.eclipse.paho.client.mqttv3.MqttMessage;\nimport org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonParser;\nimport com.google.protobuf.InvalidProtocolBufferException;\n\npublic class SparkplugMqttClient {\n\n    private static final Logger logger = LoggerFactory.getLogger(SparkplugMqttClient.class);\n\n    private List<String> servers;\n    private Iterator<String> serversIterator;\n    private String clientId;\n    private MqttConnectOptions options;\n    private MqttCallback callback;\n    private Set<DataTransportListener> listeners;\n\n    private String groupId;\n    private String nodeId;\n    private Optional<String> primaryHostId;\n    private long connectionTimeoutMs;\n\n    private MqttAsyncClient client;\n    private BdSeqCounter bdSeqCounter = new BdSeqCounter();\n    private long lastStateTimestamp = 0;\n    private Random randomDelayGenerator = new Random();\n\n    private SslManagerService sslManagerService;\n\n    private SessionStatus sessionStatus = new Terminated();\n\n    /*\n     * State management\n     */\n\n    private abstract class SessionStatus {\n\n        public abstract SessionStatus establishSession(boolean shouldConnectClient) throws KuraConnectException;\n\n        public abstract SessionStatus terminateSession(boolean shouldDisconnectClient, long quiesceTimeout);\n\n        public abstract SessionStatus confirmSession();\n\n        SessionStatus toEstablishing(boolean shouldConnectClient) throws KuraConnectException {\n            try {\n                if (shouldConnectClient) {\n                    newClientConnection();\n                }\n\n                subscribe(SparkplugTopics.getNodeCommandTopic(SparkplugMqttClient.this.groupId,\n                        SparkplugMqttClient.this.nodeId), 1);\n\n                if (SparkplugMqttClient.this.primaryHostId.isPresent()) {\n                    subscribe(SparkplugTopics.getStateTopic(SparkplugMqttClient.this.primaryHostId.get()), 1);\n                } else {\n                    return toEstablished();\n                }\n            } catch (MqttException | GeneralSecurityException | IOException e) {\n                SparkplugMqttClient.this.bdSeqCounter = new BdSeqCounter();\n                throw new KuraConnectException(e);\n            }\n\n            return new Establishing();\n        }\n\n        SessionStatus toTerminated(boolean shouldDisconnectClient, long quiesceTimeout) {\n            try {\n                SparkplugMqttClient.this.listeners\n                        .forEach(listener -> InvocationUtils.callSafely(listener::onDisconnecting));\n\n                if (SparkplugMqttClient.this.sessionStatus instanceof Established) {\n                    sendEdgeNodeDeath();\n                }\n\n                if (shouldDisconnectClient) {\n                    disconnectClient(quiesceTimeout);\n                }\n\n                SparkplugMqttClient.this.listeners\n                        .forEach(listener -> InvocationUtils.callSafely(listener::onDisconnected));\n            } catch (MqttException e) {\n                logger.error(\"Error terminating Sparkplug Edge Node session\", e);\n                return SparkplugMqttClient.this.sessionStatus;\n            }\n\n            return new Terminated();\n        }\n\n        SessionStatus toEstablished() {\n            sendEdgeNodeBirth();\n            SparkplugMqttClient.this.listeners\n                    .forEach(listener -> InvocationUtils.callSafely(listener::onConnectionEstablished, true));\n            return new Established();\n        }\n\n        private void newClientConnection() throws MqttException, GeneralSecurityException, IOException {\n            SparkplugMqttClient.this.bdSeqCounter.next();\n            setWillMessage();\n            logger.debug(\"bdSeq: {}\", SparkplugMqttClient.this.bdSeqCounter.getCurrent());\n\n            try {\n                long randomDelay = SparkplugMqttClient.this.randomDelayGenerator.nextInt(5000);\n                logger.info(\"Randomly delaying connect by {} ms\", randomDelay);\n                Thread.sleep(randomDelay);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n\n            SparkplugMqttClient.this.client = new MqttAsyncClient(getNextServer(), SparkplugMqttClient.this.clientId,\n                    new MemoryPersistence());\n            SparkplugMqttClient.this.client.setCallback(SparkplugMqttClient.this.callback);\n\n            IMqttToken token = SparkplugMqttClient.this.client.connect(SparkplugMqttClient.this.options);\n            token.waitForCompletion(SparkplugMqttClient.this.connectionTimeoutMs);\n\n            logger.debug(\"Client connected\");\n        }\n\n        private void disconnectClient(long quiesceTimeout) throws MqttException {\n            if (SparkplugMqttClient.this.client.isConnected()) {\n                IMqttToken token = SparkplugMqttClient.this.client.disconnect(quiesceTimeout);\n                token.waitForCompletion(SparkplugMqttClient.this.connectionTimeoutMs);\n            }\n\n            logger.debug(\"Client disconnected\");\n        }\n\n        private void setWillMessage() {\n            String topic = SparkplugTopics.getNodeDeathTopic(SparkplugMqttClient.this.groupId,\n                    SparkplugMqttClient.this.nodeId);\n            byte[] payload = SparkplugPayloads.getNodeDeathPayload(SparkplugMqttClient.this.bdSeqCounter.getCurrent());\n            SparkplugMqttClient.this.options.setWill(topic, payload, 1, false);\n        }\n\n        private void sendEdgeNodeBirth() {\n            String topic = SparkplugTopics.getNodeBirthTopic(SparkplugMqttClient.this.groupId,\n                    SparkplugMqttClient.this.nodeId);\n            byte[] payload = SparkplugPayloads.getNodeBirthPayload(SparkplugMqttClient.this.bdSeqCounter.getCurrent(),\n                    0);\n            publish(topic, payload, 0, false);\n            logger.debug(\"Published Edge Node BIRTH with bdSeq {}\", SparkplugMqttClient.this.bdSeqCounter.getCurrent());\n        }\n\n        private void sendEdgeNodeDeath() {\n            String topic = SparkplugTopics.getNodeDeathTopic(SparkplugMqttClient.this.groupId,\n                    SparkplugMqttClient.this.nodeId);\n            byte[] payload = SparkplugPayloads.getNodeDeathPayload(SparkplugMqttClient.this.bdSeqCounter.getCurrent());\n            publish(topic, payload, 0, false);\n            logger.debug(\"Published Edge Node DEATH with bdSeq {}\", SparkplugMqttClient.this.bdSeqCounter.getCurrent());\n        }\n\n        private String getNextServer() throws GeneralSecurityException, IOException {\n            String server;\n            if (SparkplugMqttClient.this.serversIterator.hasNext()) {\n                server = SparkplugMqttClient.this.serversIterator.next();\n            } else {\n                SparkplugMqttClient.this.serversIterator = SparkplugMqttClient.this.servers.iterator();\n                server = SparkplugMqttClient.this.serversIterator.next();\n            }\n\n            setSocketFactory(server);\n\n            logger.info(\"Selecting next server {} from {}\", server, SparkplugMqttClient.this.servers);\n            return server;\n        }\n\n        private void setSocketFactory(String server) throws GeneralSecurityException, IOException {\n            if (server.startsWith(\"ssl\")) {\n                SparkplugMqttClient.this.options\n                        .setSocketFactory(SparkplugMqttClient.this.sslManagerService.getSSLSocketFactory());\n            } else {\n                SparkplugMqttClient.this.options.setSocketFactory(SocketFactory.getDefault());\n            }\n        }\n\n    }\n\n    private class Terminated extends SessionStatus {\n\n        @Override\n        public SessionStatus establishSession(boolean shouldConnectClient) throws KuraConnectException {\n            return toEstablishing(shouldConnectClient);\n        }\n\n        @Override\n        public SessionStatus terminateSession(boolean shouldDisconnectClient, long quiesceTimeout) {\n            return this;\n        }\n\n        @Override\n        public SessionStatus confirmSession() {\n            return this;\n        }\n\n    }\n\n    private class Establishing extends SessionStatus {\n\n        @Override\n        public SessionStatus establishSession(boolean shouldConnectClient) throws KuraConnectException {\n            return this;\n        }\n\n        @Override\n        public SessionStatus terminateSession(boolean shouldDisconnectClient, long quiesceTimeout) {\n            return toTerminated(shouldDisconnectClient, quiesceTimeout);\n        }\n\n        @Override\n        public SessionStatus confirmSession() {\n            return toEstablished();\n        }\n\n    }\n\n    private class Established extends SessionStatus {\n\n        @Override\n        public SessionStatus establishSession(boolean shouldConnectClient) throws KuraConnectException {\n            return this;\n        }\n\n        @Override\n        public SessionStatus terminateSession(boolean shouldDisconnectClient, long quiesceTimeout) {\n            return toTerminated(shouldDisconnectClient, quiesceTimeout);\n        }\n\n        @Override\n        public SessionStatus confirmSession() {\n            return toEstablished();\n        }\n\n    }\n\n    /*\n     * Public methods\n     */\n\n    public SparkplugMqttClient(SparkplugDataTransportOptions options, MqttCallback callback,\n            Set<DataTransportListener> listeners, SslManagerService sslManagerService) {\n        this.servers = options.getServers();\n        this.serversIterator = this.servers.iterator();\n        this.clientId = options.getClientId();\n        this.options = options.getMqttConnectOptions();\n        this.callback = callback;\n        this.listeners = listeners;\n\n        this.groupId = options.getGroupId();\n        this.nodeId = options.getNodeId();\n        this.primaryHostId = options.getPrimaryHostApplicationId();\n        this.connectionTimeoutMs = options.getConnectionTimeoutMs();\n\n        this.sslManagerService = sslManagerService;\n\n        logger.info(\n                \"Sparkplug MQTT client updated\" + \"\\n\\tServers: {}\" + \"\\n\\tClient ID: {}\" + \"\\n\\tGroup ID: {}\"\n                        + \"\\n\\tNode ID: {}\" + \"\\n\\tPrimary Host Application ID: {}\" + \"\\n\\tConnection Timeout (ms): {}\",\n                this.servers, this.clientId, this.groupId, this.nodeId, this.primaryHostId, this.connectionTimeoutMs);\n    }\n\n    public synchronized boolean isSessionEstablished() {\n        return this.sessionStatus instanceof Established && Objects.nonNull(this.client)\n                && this.client.isConnected();\n    }\n\n    public synchronized void handleConnectionLost() {\n        doSessionTransition(new Terminated());\n    }\n\n    public synchronized void establishSession(boolean shouldConnectClient) throws KuraConnectException {\n        logger.debug(\"Requested session establishment\");\n        doSessionTransition(this.sessionStatus.establishSession(shouldConnectClient));\n    }\n    \n    public synchronized void terminateSession(boolean shouldDisconnectClient, long quiesceTimeout) {\n        logger.debug(\"Requested session termination\");\n        doSessionTransition(this.sessionStatus.terminateSession(shouldDisconnectClient, quiesceTimeout));\n    }\n\n    public synchronized void confirmSession() {\n        logger.debug(\"Requested session confirmation\");\n        doSessionTransition(this.sessionStatus.confirmSession());\n    }\n\n    public synchronized IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean isRetained) {\n        try {\n            logger.info(\"Publishing message on topic {} with QoS {} and retain {}\", topic, qos, isRetained);\n            return this.client.publish(topic, payload, qos, isRetained);\n        } catch (MqttException e) {\n            logger.error(\"Error publishing to topic {} with QoS {}\", topic, qos, e);\n        }\n\n        return null;\n    }\n\n    public synchronized void subscribe(String topic, int qos) {\n        try {\n            IMqttToken token = this.client.subscribe(topic, qos);\n            token.waitForCompletion(this.connectionTimeoutMs);\n            logger.info(\"Subscribed to topic {} with QoS {}\", topic, qos);\n        } catch (MqttException e) {\n            logger.error(\"Error subscribing to topic {} with QoS {}\", topic, qos, e);\n        }\n    }\n    \n    public synchronized void unsubscribe(String topic) {\n        try {\n            IMqttToken token = this.client.unsubscribe(topic);\n            token.waitForCompletion(this.connectionTimeoutMs);\n            logger.info(\"Unsubscribed from topic {}\", topic);\n        } catch (MqttException e) {\n            logger.error(\"Error unsubscribing from topic {}\", topic, e);\n        }\n    }\n\n    public synchronized String getConnectedServer() {\n        return isSessionEstablished() ? this.client.getCurrentServerURI() : this.servers.toString();\n    }\n\n    public synchronized Runnable getMessageDispatcher(String topic, MqttMessage message) {\n        return () -> dispatchMessage(topic, message);\n    }\n\n    /*\n     * Private methods\n     */\n\n    private void doSessionTransition(SessionStatus newStatus) {\n        String from = this.sessionStatus.getClass().getSimpleName();\n        String to = newStatus.getClass().getSimpleName();\n\n        if (!from.equals(to)) {\n            logger.info(\"Sparkplug session: {} -> {}\", from, to);\n            this.sessionStatus = newStatus;\n        }\n    }\n\n    private synchronized void dispatchMessage(String topic, MqttMessage message) {\n        boolean isValidStateMessage = this.primaryHostId.isPresent()\n                && topic.equals(SparkplugTopics.getStateTopic(this.primaryHostId.get()));\n        boolean isValidNcmdMessage = topic.equals(SparkplugTopics.getNodeCommandTopic(this.groupId, this.nodeId));\n\n        try {\n            if (isValidStateMessage) {\n                dispatchStateMessage(message.getPayload());\n            } else if (isValidNcmdMessage) {\n                dispatchNcmdMessage(message.getPayload());\n            }\n        } catch (Exception e) {\n            logger.error(\"Error dispatching arrived message\", e);\n        }\n    }\n\n    private void dispatchStateMessage(byte[] payload) throws KuraConnectException {\n        logger.debug(\"Handling STATE message\");\n\n        JsonElement json = JsonParser.parseString(new String(payload, StandardCharsets.UTF_8));\n        boolean isOnline = json.getAsJsonObject().get(\"online\").getAsBoolean();\n        long timestamp = json.getAsJsonObject().get(\"timestamp\").getAsLong();\n\n        if (this.lastStateTimestamp <= timestamp) {\n            this.lastStateTimestamp = timestamp;\n\n            if (isOnline) {\n                logger.info(\"Primary Host Application is online\");\n                confirmSession();\n            } else {\n                logger.info(\"Primary Host Application is offline\");\n                terminateSession(true, 0);\n                establishSession(true);\n            }\n        }\n    }\n\n    private void dispatchNcmdMessage(byte[] payload) throws KuraConnectException {\n        logger.debug(\"Handling NCMD message\");\n\n        try {\n            boolean nodeRebirth = SparkplugPayloads.getBooleanMetric(SparkplugPayloads.NODE_CONTROL_REBIRTH_METRIC_NAME,\n                    payload);\n\n            if (nodeRebirth) {\n                logger.debug(\"{} requested\", SparkplugPayloads.NODE_CONTROL_REBIRTH_METRIC_NAME);\n\n                terminateSession(false, 0);\n                establishSession(false);\n            }\n        } catch (InvalidProtocolBufferException e) {\n            logger.error(\"Error processing payload for NCMD message\", e);\n        } catch (NoSuchFieldException e) {\n            logger.debug(\"NMCD message ignored, it does not contain any Node Control/Rebirth metric\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/utils/InvocationUtils.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils;\n\nimport java.util.function.Consumer;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class InvocationUtils {\n    \n    private static final String ERROR_MESSAGE_FORMAT = \"An error occurred in listener '%s'\";\n\n    private InvocationUtils() {\n    }\n\n    private static final Logger logger = LoggerFactory.getLogger(InvocationUtils.class);\n\n    public static void callSafely(Runnable f) {\n        try {\n            f.run();\n        } catch (Exception e) {\n            logger.error(String.format(ERROR_MESSAGE_FORMAT, f.getClass().getName()), e);\n        }\n    }\n\n    public static <T> void callSafely(Consumer<T> f, T argument) {\n        try {\n            f.accept(argument);\n        } catch (Exception e) {\n            logger.error(String.format(ERROR_MESSAGE_FORMAT, f.getClass().getName()), e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/utils/SparkplugCloudEndpointTracker.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils;\n\nimport java.util.Objects;\nimport java.util.function.Consumer;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\n\npublic class SparkplugCloudEndpointTracker {\n\n    private final BundleContext bundleContext;\n    private ServiceTracker<CloudConnectionManager, CloudConnectionManager> cloudConnectionManagerTracker;\n    private final Consumer<SparkplugCloudEndpoint> serviceAddedConsumer;\n    private final Consumer<SparkplugCloudEndpoint> serviceRemovedConsumer;\n    private final String endpointPid;\n\n    public SparkplugCloudEndpointTracker(BundleContext bundleContext,\n            Consumer<SparkplugCloudEndpoint> serviceAddedConsumer,\n            Consumer<SparkplugCloudEndpoint> serviceRemovedConsumer, String endpointPid) {\n        this.bundleContext = bundleContext;\n        this.serviceAddedConsumer = serviceAddedConsumer;\n        this.serviceRemovedConsumer = serviceRemovedConsumer;\n        this.endpointPid = endpointPid;\n    }\n\n    public void startEndpointTracker() throws InvalidSyntaxException {\n        String filterString = String.format(\"(&(%s=%s)(kura.service.pid=%s))\", Constants.OBJECTCLASS,\n                CloudConnectionManager.class.getName(), this.endpointPid);\n\n        final Filter filter = this.bundleContext.createFilter(filterString);\n        this.cloudConnectionManagerTracker = new ServiceTracker<>(this.bundleContext, filter,\n                new SparkplugCloudEndpointTrackerCustomizer());\n\n        this.cloudConnectionManagerTracker.open();\n    }\n\n    public void stopEndpointTracker() {\n        if (Objects.nonNull(this.cloudConnectionManagerTracker)) {\n            this.cloudConnectionManagerTracker.close();\n        }\n    }\n\n    private class SparkplugCloudEndpointTrackerCustomizer\n            implements ServiceTrackerCustomizer<CloudConnectionManager, CloudConnectionManager> {\n\n        @Override\n        public synchronized CloudConnectionManager addingService(\n                final ServiceReference<CloudConnectionManager> reference) {\n            CloudConnectionManager cloudConnectionManager = SparkplugCloudEndpointTracker.this.bundleContext\n                    .getService(reference);\n\n            if (cloudConnectionManager instanceof SparkplugCloudEndpoint) {\n                SparkplugCloudEndpointTracker.this.serviceAddedConsumer\n                        .accept((SparkplugCloudEndpoint) cloudConnectionManager);\n                return cloudConnectionManager;\n            } else {\n                SparkplugCloudEndpointTracker.this.bundleContext.ungetService(reference);\n            }\n\n            return null;\n        }\n\n        @Override\n        public synchronized void removedService(final ServiceReference<CloudConnectionManager> reference,\n                final CloudConnectionManager service) {\n            if (service instanceof SparkplugCloudEndpoint) {\n                SparkplugCloudEndpointTracker.this.serviceRemovedConsumer.accept((SparkplugCloudEndpoint) service);\n            }\n        }\n\n        @Override\n        public synchronized void modifiedService(final ServiceReference<CloudConnectionManager> reference,\n                final CloudConnectionManager service) {\n            // Not needed\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/proto/sparkplug_b.proto",
    "content": "// * Copyright (c) 2015, 2018 Cirrus Link Solutions and others\n// *\n// * This program and the accompanying materials are made available under the\n// * terms of the Eclipse Public License 2.0 which is available at\n// * http://www.eclipse.org/legal/epl-2.0.\n// *\n// * SPDX-License-Identifier: EPL-2.0\n// *\n// * Contributors:\n// *   Cirrus Link Solutions - initial implementation\n\n//\n// To compile:\n// cd client_libraries/java\n// protoc --proto_path=../../ --java_out=src/main/java ../../sparkplug_b.proto\n//\n\nsyntax = \"proto2\";\n\npackage org.eclipse.tahu.protobuf;\n\noption java_package         = \"org.eclipse.tahu.protobuf\";\noption java_outer_classname = \"SparkplugBProto\";\n\nenum DataType {\n    // Indexes of Data Types\n\n    // Unknown placeholder for future expansion.\n    Unknown         = 0;\n\n    // Basic Types\n    Int8            = 1;\n    Int16           = 2;\n    Int32           = 3;\n    Int64           = 4;\n    UInt8           = 5;\n    UInt16          = 6;\n    UInt32          = 7;\n    UInt64          = 8;\n    Float           = 9;\n    Double          = 10;\n    Boolean         = 11;\n    String          = 12;\n    DateTime        = 13;\n    Text            = 14;\n\n    // Additional Metric Types\n    UUID            = 15;\n    DataSet         = 16;\n    Bytes           = 17;\n    File            = 18;\n    Template        = 19;\n\n    // Additional PropertyValue Types\n    PropertySet     = 20;\n    PropertySetList = 21;\n\n    // Array Types\n    Int8Array = 22;\n    Int16Array = 23;\n    Int32Array = 24;\n    Int64Array = 25;\n    UInt8Array = 26;\n    UInt16Array = 27;\n    UInt32Array = 28;\n    UInt64Array = 29;\n    FloatArray = 30;\n    DoubleArray = 31;\n    BooleanArray = 32;\n    StringArray = 33;\n    DateTimeArray = 34;\n}\n\nmessage Payload {\n\n    message Template {\n\n        message Parameter {\n            optional string name        = 1;\n            optional uint32 type        = 2;\n\n            oneof value {\n                uint32 int_value        = 3;\n                uint64 long_value       = 4;\n                float  float_value      = 5;\n                double double_value     = 6;\n                bool   boolean_value    = 7;\n                string string_value     = 8;\n                ParameterValueExtension extension_value = 9;\n            }\n\n            message ParameterValueExtension {\n                extensions              1 to max;\n            }\n        }\n\n        optional string version         = 1;          // The version of the Template to prevent mismatches\n        repeated Metric metrics         = 2;          // Each metric includes a name, datatype, and optionally a value\n        repeated Parameter parameters   = 3;\n        optional string template_ref    = 4;          // MUST be a reference to a template definition if this is an instance (i.e. the name of the template definition) - MUST be omitted for template definitions\n        optional bool is_definition     = 5;\n        extensions                      6 to max;\n    }\n\n    message DataSet {\n\n        message DataSetValue {\n\n            oneof value {\n                uint32 int_value                        = 1;\n                uint64 long_value                       = 2;\n                float  float_value                      = 3;\n                double double_value                     = 4;\n                bool   boolean_value                    = 5;\n                string string_value                     = 6;\n                DataSetValueExtension extension_value   = 7;\n            }\n\n            message DataSetValueExtension {\n                extensions  1 to max;\n            }\n        }\n\n        message Row {\n            repeated DataSetValue elements  = 1;\n            extensions                      2 to max;   // For third party extensions\n        }\n\n        optional uint64   num_of_columns    = 1;\n        repeated string   columns           = 2;\n        repeated uint32   types             = 3;\n        repeated Row      rows              = 4;\n        extensions                          5 to max;   // For third party extensions\n    }\n\n    message PropertyValue {\n\n        optional uint32     type                    = 1;\n        optional bool       is_null                 = 2;\n\n        oneof value {\n            uint32          int_value               = 3;\n            uint64          long_value              = 4;\n            float           float_value             = 5;\n            double          double_value            = 6;\n            bool            boolean_value           = 7;\n            string          string_value            = 8;\n            PropertySet     propertyset_value       = 9;\n            PropertySetList propertysets_value      = 10;      // List of Property Values\n            PropertyValueExtension extension_value  = 11;\n        }\n\n        message PropertyValueExtension {\n            extensions                             1 to max;\n        }\n    }\n\n    message PropertySet {\n        repeated string        keys     = 1;         // Names of the properties\n        repeated PropertyValue values   = 2;\n        extensions                      3 to max;\n    }\n\n    message PropertySetList {\n        repeated PropertySet propertyset = 1;\n        extensions                       2 to max;\n    }\n\n    message MetaData {\n        // Bytes specific metadata\n        optional bool   is_multi_part   = 1;\n\n        // General metadata\n        optional string content_type    = 2;        // Content/Media type\n        optional uint64 size            = 3;        // File size, String size, Multi-part size, etc\n        optional uint64 seq             = 4;        // Sequence number for multi-part messages\n\n        // File metadata\n        optional string file_name       = 5;        // File name\n        optional string file_type       = 6;        // File type (i.e. xml, json, txt, cpp, etc)\n        optional string md5             = 7;        // md5 of data\n\n        // Catchalls and future expansion\n        optional string description     = 8;        // Could be anything such as json or xml of custom properties\n        extensions                      9 to max;\n    }\n\n    message Metric {\n\n        optional string   name          = 1;        // Metric name - should only be included on birth\n        optional uint64   alias         = 2;        // Metric alias - tied to name on birth and included in all later DATA messages\n        optional uint64   timestamp     = 3;        // Timestamp associated with data acquisition time\n        optional uint32   datatype      = 4;        // DataType of the metric/tag value\n        optional bool     is_historical = 5;        // If this is historical data and should not update real time tag\n        optional bool     is_transient  = 6;        // Tells consuming clients such as MQTT Engine to not store this as a tag\n        optional bool     is_null       = 7;        // If this is null - explicitly say so rather than using -1, false, etc for some datatypes.\n        optional MetaData metadata      = 8;        // Metadata for the payload\n        optional PropertySet properties = 9;\n\n        oneof value {\n            uint32   int_value                      = 10;\n            uint64   long_value                     = 11;\n            float    float_value                    = 12;\n            double   double_value                   = 13;\n            bool     boolean_value                  = 14;\n            string   string_value                   = 15;\n            bytes    bytes_value                    = 16;       // Bytes, File\n            DataSet  dataset_value                  = 17;\n            Template template_value                 = 18;\n            MetricValueExtension extension_value    = 19;\n        }\n\n        message MetricValueExtension {\n            extensions  1 to max;\n        }\n    }\n\n    optional uint64   timestamp     = 1;        // Timestamp at message sending time\n    repeated Metric   metrics       = 2;        // Repeated forever - no limit in Google Protobufs\n    optional uint64   seq           = 3;        // Sequence number\n    optional string   uuid          = 4;        // UUID to track message type in terms of schema definitions\n    optional bytes    body          = 5;        // To optionally bypass the whole definition above\n    extensions                      6 to max;   // For third party extensions\n}"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/.gitignore",
    "content": "/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.configuration.change.manager\nBundle-SymbolicName: org.eclipse.kura.configuration.change.manager;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: com.google.gson;version=\"2.7.0\",\n org.eclipse.kura;version=\"[1.7,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.publisher;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,1.3)\",\n org.eclipse.kura.message;version=\"[1.4,2.0)\",\n org.osgi.framework;version=\"1.7.0\",\n org.osgi.service.cm;version=\"1.4.0\",\n org.osgi.util.tracker;version=\"[1.5,2.0)\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/OSGI-INF/metatype/org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n    Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager\"\n        name=\"Configuration Change Manager\"\n        description=\"Detect changes to the configuration service and publish them to the cloud as a KuraMessage.\">\n\n        <Icon resource=\"OSGI-INF/configurationChangeManagerLogo.png\" size=\"32\" />\n\n        <AD id=\"enabled\" \n            name=\"Enable\" \n            type=\"Boolean\" \n            cardinality=\"0\" \n            required=\"true\" \n            default=\"false\"\n            description=\"Set to true to enable this component.\">\n        </AD>\n\n        <AD id=\"CloudPublisher.target\" \n            name=\"CloudPublisher Target Filter\" \n            type=\"String\" \n            cardinality=\"0\"\n            required=\"true\" \n            default=\"(kura.service.pid=changeme)\"\n            description=\"Specifies, as an OSGi target filter, the pid of the Cloud Publisher used to publish messages\n            to the cloud platform.\">\n        </AD>\n\n        <AD id=\"send.delay\" \n            name=\"Notification send delay (sec)\" \n            type=\"Long\" \n            cardinality=\"0\" \n            required=\"true\"\n            default=\"10\" \n            min=\"0\"\n            description=\"Delay before notifications are sent. A large delay accumulates notifications into a single message.\n\t\t\tA delay of 0 will send the notifications as soon as they arrive, without accumulation.\">\n        </AD>\n\n    </OCD>\n    <Designate factoryPid=\"org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager\">\n        <Object ocdref=\"org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager\" />\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/OSGI-INF/org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2022 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n        Eurotech\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n\tconfiguration-policy=\"require\"\n\tenabled=\"true\"\n\timmediate=\"true\"\n\tname=\"org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager\"\n\tactivate=\"activate\" modified=\"updated\" deactivate=\"deactivate\">\n    \n    <implementation class=\"org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager\"/>\n    <property name=\"service.pid\" value=\"org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager\"/>\n    <property name=\"kura.service.pid\" type=\"String\" value=\"org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n    </service>\n\t\t\n\t<reference name=\"CloudPublisher\"\n\t\tpolicy=\"dynamic\"\n\t\tbind=\"setCloudPublisher\"\n\t\tunbind=\"unsetCloudPublisher\"\n\t\tcardinality=\"0..1\"\n\t\tinterface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n  \n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/build.properties",
    "content": "bin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/,\\\n               OSGI-INF/org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager.xml\nsrc.includes = about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n        Eurotech\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.configuration.change.manager</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.configuration.change.manager.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\t\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/src/main/java/org/eclipse/kura/configuration/change/manager/ComponentsServiceTracker.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.configuration.change.manager;\n\nimport java.util.HashSet;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.util.tracker.ServiceTracker;\n\n@SuppressWarnings(\"rawtypes\")\npublic class ComponentsServiceTracker extends ServiceTracker {\n\n    private final Set<ServiceTrackerListener> listeners;\n    private static final String FILTER_EXCLUDE_CONF_CHANGE_MANAGER_FACTORY = \"(!(service.factoryPid=org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager))\";\n\n    @SuppressWarnings(\"unchecked\")\n    public ComponentsServiceTracker(BundleContext context) throws InvalidSyntaxException {\n        super(context, context.createFilter(FILTER_EXCLUDE_CONF_CHANGE_MANAGER_FACTORY), null);\n        this.listeners = new HashSet<>();\n    }\n\n    @SuppressWarnings({ \"unchecked\" })\n    @Override\n    public Object addingService(ServiceReference ref) {\n        Object service = super.addingService(ref);\n\n        notifyListeners(ref);\n\n        return service;\n    }\n\n    @Override\n    public void modifiedService(ServiceReference reference, Object service) {\n        notifyListeners(reference);\n    }\n\n    @SuppressWarnings({ \"unchecked\" })\n    @Override\n    public void removedService(ServiceReference reference, Object service) {\n        super.removedService(reference, service);\n\n        notifyListeners(reference);\n    }\n\n    public void addServiceTrackerListener(ServiceTrackerListener listener) {\n        this.listeners.add(listener);\n    }\n\n    public void removeServiceTrackerListener(ServiceTrackerListener listener) {\n        this.listeners.remove(listener);\n    }\n\n    private void notifyListeners(ServiceReference ref) {\n        Optional<String> pid = getPidFromServiceReference(ref);\n\n        if (pid.isPresent()) {\n            for (ServiceTrackerListener listener : this.listeners) {\n                listener.onConfigurationChanged(pid.get());\n            }\n        }\n    }\n\n    private Optional<String> getPidFromServiceReference(ServiceReference ref) {\n        Optional<String> pid = Optional.empty();\n\n        if (ref.getProperty(ConfigurationService.KURA_SERVICE_PID) != null) {\n            pid = Optional.of((String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID));\n        } else if (ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID) != null) {\n            pid = Optional.of((String) ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID));\n        } else if (ref.getProperty(Constants.SERVICE_PID) != null) {\n            pid = Optional.of((String) ref.getProperty(Constants.SERVICE_PID));\n        }\n\n        return pid;\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/src/main/java/org/eclipse/kura/configuration/change/manager/ConfigurationChangeManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.configuration.change.manager;\n\nimport java.util.Date;\nimport java.util.LinkedList;\nimport java.util.Map;\nimport java.util.Queue;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.gson.ExclusionStrategy;\nimport com.google.gson.FieldAttributes;\nimport com.google.gson.GsonBuilder;\n\npublic class ConfigurationChangeManager implements ConfigurableComponent, ServiceTrackerListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(ConfigurationChangeManager.class);\n\n    private class ChangedConfiguration {\n\n        protected long timestamp;\n        protected String pid;\n\n        public ChangedConfiguration(String pid) {\n            this.timestamp = new Date().getTime();\n            this.pid = pid;\n        }\n\n        @Override\n        public boolean equals(Object other) {\n            if (!(other instanceof ChangedConfiguration)) {\n                return false;\n            }\n\n            return ((ChangedConfiguration) other).pid.equals(this.pid);\n        }\n\n        @Override\n        public int hashCode() {\n            return this.pid.hashCode();\n        }\n\n    }\n\n    private ConfigurationChangeManagerOptions options;\n    private CloudPublisher cloudPublisher;\n\n    private final ScheduledExecutorService scheduledSendQueueExecutor = Executors.newScheduledThreadPool(1);\n    private ScheduledFuture<?> futureSendQueue;\n    private volatile boolean acceptNotifications = false;\n    private final Queue<ChangedConfiguration> notificationsQueue = new LinkedList<>();\n    private ComponentsServiceTracker serviceTracker;\n\n    /*\n     * Dependencies\n     */\n\n    public void setCloudPublisher(CloudPublisher cloudPublisher) {\n        this.cloudPublisher = cloudPublisher;\n    }\n\n    public void unsetCloudPublisher(CloudPublisher cloudPublisher) {\n        if (this.cloudPublisher == cloudPublisher) {\n            this.cloudPublisher = null;\n        }\n    }\n\n    /*\n     * Activation APIs\n     */\n\n    public void activate(final Map<String, Object> properties) throws InvalidSyntaxException {\n        logger.info(\"Activating ConfigurationChangeManager...\");\n\n        this.acceptNotifications = false;\n\n        BundleContext bundleContext = FrameworkUtil.getBundle(ConfigurationChangeManager.class).getBundleContext();\n        this.serviceTracker = new ComponentsServiceTracker(bundleContext);\n\n        updated(properties);\n\n        logger.info(\"Activating ConfigurationChangeManager... Done.\");\n    }\n\n    public void updated(final Map<String, Object> properties) {\n        logger.info(\"Updating ConfigurationChangeManager...\");\n\n        this.options = new ConfigurationChangeManagerOptions(properties);\n\n        if (this.options.isEnabled()) {\n            this.acceptNotifications = true;\n            this.serviceTracker.open(true);\n            this.serviceTracker.addServiceTrackerListener(this);\n        } else {\n            this.acceptNotifications = false;\n            this.serviceTracker.removeServiceTrackerListener(this);\n            this.serviceTracker.close();\n        }\n\n        logger.info(\"Updating ConfigurationChangeManager... Done.\");\n    }\n\n    public void deactivate() {\n        logger.info(\"Deactivating ConfigurationChangeManager...\");\n        this.acceptNotifications = false;\n        this.serviceTracker.removeServiceTrackerListener(this);\n        this.serviceTracker.close();\n        logger.info(\"Deactivating ConfigurationChangeManager... Done.\");\n    }\n\n    @Override\n    public void onConfigurationChanged(String pid) {\n        if (this.acceptNotifications) {\n            ChangedConfiguration conf = new ChangedConfiguration(pid);\n            if (this.notificationsQueue.contains(conf)) {\n                this.notificationsQueue.remove(conf);\n            }\n            this.notificationsQueue.add(conf);\n\n            if (this.futureSendQueue != null) {\n                this.futureSendQueue.cancel(false);\n            }\n            this.futureSendQueue = this.scheduledSendQueueExecutor.schedule(this::sendQueue,\n                    this.options.getSendDelay(), TimeUnit.SECONDS);\n        }\n    }\n\n    private byte[] createJsonFromNotificationsQueue() {\n        GsonBuilder builder = new GsonBuilder();\n        builder.setExclusionStrategies(new ExclusionStrategy() {\n\n            @Override\n            public boolean shouldSkipClass(Class<?> arg0) {\n                return false;\n            }\n\n            @Override\n            public boolean shouldSkipField(FieldAttributes arg0) {\n                return arg0.getName().equals(\"timestamp\");\n            }\n\n        });\n        return builder.create().toJson(this.notificationsQueue).getBytes();\n    }\n\n    private void sendQueue() {\n        KuraPayload payload = new KuraPayload();\n        payload.setTimestamp(new Date(this.notificationsQueue.peek().timestamp));\n        payload.setBody(createJsonFromNotificationsQueue());\n\n        this.notificationsQueue.clear();\n\n        if (this.cloudPublisher != null) {\n            try {\n                this.cloudPublisher.publish(new KuraMessage(payload));\n            } catch (KuraException e) {\n                logger.error(\"Error publishing configuration change event.\", e);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/src/main/java/org/eclipse/kura/configuration/change/manager/ConfigurationChangeManagerOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.configuration.change.manager;\n\nimport java.util.Map;\n\npublic class ConfigurationChangeManagerOptions {\n\n    public static final String KEY_ENABLED = \"enabled\";\n    public static final String KEY_SEND_DELAY = \"send.delay\";\n    public static final boolean DEFAULT_ENABLED = false;\n    public static final long DEFAULT_SEND_DELAY = 10;\n\n    private final boolean enabled;\n    private final long sendDelay;\n\n    public ConfigurationChangeManagerOptions(Map<String, Object> properties) {\n        this.enabled = (boolean) properties.getOrDefault(KEY_ENABLED, DEFAULT_ENABLED);\n        this.sendDelay = (long) properties.getOrDefault(KEY_SEND_DELAY, DEFAULT_SEND_DELAY);\n    }\n\n    public boolean isEnabled() {\n        return this.enabled;\n    }\n\n    public long getSendDelay() {\n        return this.sendDelay;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.configuration.change.manager/src/main/java/org/eclipse/kura/configuration/change/manager/ServiceTrackerListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.configuration.change.manager;\n\npublic interface ServiceTrackerListener {\n\n    public void onConfigurationChanged(String pid);\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/.gitignore",
    "content": "/target/\nlib/*\n/lib/\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Configurable container management component\nBundle-SymbolicName: org.eclipse.kura.container.orchestration.provider\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nAutomatic-Module-Name: org.eclipse.kura.container.orchestration.provider\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: com.google.common.base;version=\"32.1.1\",\n com.google.common.collect;version=\"32.1.1\",\n com.google.common.escape;version=\"32.1.1\",\n com.google.common.io;version=\"32.1.1\",\n com.google.common.net;version=\"32.1.1\",\n org.apache.commons.io;version=\"1.4.9999\",\n org.apache.commons.lang3;version=\"3.17.0\",\n org.eclipse.kura;version=\"[1.6,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.container.orchestration;version=\"[1.3,2.0)\",\n org.eclipse.kura.container.orchestration.listener;version=\"[1.0,1.1)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0]\",\n org.eclipse.kura.util.configuration;version=\"[1.0,2.0)\",\n com.fasterxml.jackson.annotation;version=\"2.19.2\",\n com.fasterxml.jackson.core;version=\"2.19.2\",\n com.fasterxml.jackson.core.type;version=\"2.19.2\",\n com.fasterxml.jackson.databind;version=\"2.19.2\",\n com.fasterxml.jackson.databind.node;version=\"2.19.2\",\n com.fasterxml.jackson.databind.module;version=\"2.19.2\",\n com.fasterxml.jackson.databind.deser;version=\"2.19.2\",\n com.fasterxml.jackson.databind.deser.std;version=\"2.19.2\",\n com.fasterxml.jackson.databind.type;version=\"2.19.2\",\n org.bouncycastle.cert;version=\"1.78.1\",\n org.bouncycastle.cert.jcajce;version=\"1.78.1\",\n org.bouncycastle.jce.provider;version=\"1.78.1\",\n org.bouncycastle.asn1;version=\"1.78.1\",\n org.osgi.service.component;version=\"1.4.0\",\n org.slf4j;version=\"1.7.25\"\nService-Component: OSGI-INF/component.xml\nBundle-ClassPath: .,\n lib/commons-codec.jar,\n lib/commons-compress.jar,\n lib/docker-java-api.jar,\n lib/docker-java-core.jar,\n lib/docker-java-transport.jar,\n lib/docker-java-transport-httpclient5.jar,\n lib/httpclient5.jar,\n lib/httpcore5.jar,\n lib/httpcore5-h2.jar,\n lib/jna.jar\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/OSGI-INF/component.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService\">\n   <implementation class=\"org.eclipse.kura.container.orchestration.provider.impl.ContainerOrchestrationServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.container.orchestration.ContainerOrchestrationService\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService\"/>\n   <reference name=\"CryptoService\" \n              interface=\"org.eclipse.kura.crypto.CryptoService\" \n              bind=\"setCryptoService\" \n              cardinality=\"1..1\" \n              policy=\"static\"/> \n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/OSGI-INF/metatype/org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService\" name=\"Container Orchestration Service\"\n        description=\"The ContainerOrchestrationService connects to locally running Docker/Podman instances, and allows for container management.\">\n        \n\n        <AD id=\"enabled\" name=\"Enabled\" type=\"Boolean\" cardinality=\"0\" required=\"true\" default=\"false\"\n            description=\"Enables the service to connect to the container engine host. Please make sure that the Docker/Podman service is running in the host environment prior to enable this functionality.\">\n        </AD>\n\n        <AD id=\"container.engine.host\" name=\"Container Engine Host URL\"\n            description=\"Host URL: tcp://localhost:2376 or unix:///var/run/docker.sock\" type=\"String\"\n            cardinality=\"0\" required=\"true\" default=\"unix:///var/run/docker.sock\" />\n            \n        <AD id=\"enforcement.enabled\" name=\"Allowlist Enforcement Enabled\" type=\"Boolean\" cardinality=\"0\" required=\"true\" default=\"false\"\n            description=\"Enable/Disable the Allowlist enforcement. If enabled, only containers images whose digest can be found in the allowlist will be allowed to be run/loaded/created.\">\n        </AD>\n        \n        <AD\n            id=\"enforcement.allowlist\"\n            name=\"Container Image Allowlist \"\n            description=\"List of container image digests. Each entry must be separated by a new line of the text box|TextArea\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"false\"\n            default=\"\" />\n        \n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService\">\n        <Object ocdref=\"org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService\" />\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/build.properties",
    "content": "#\n#  Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes\n\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               lib/commons-codec.jar,\\\n               lib/commons-compress.jar,\\\n               lib/docker-java-api.jar,\\\n               lib/docker-java-core.jar,\\\n               lib/docker-java-transport.jar,\\\n               lib/docker-java-transport-httpclient5.jar,\\\n               lib/httpclient5.jar,\\\n               lib/httpcore5.jar,\\\n               lib/httpcore5-h2.jar,\\\n               lib/jna.jar,\\\n               about.html,\\\n               about_files/\n\nsrc.includes = about.html,\\\n\t\t\t   about_files/"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.container.orchestration.provider</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n    <description>Management of docker container orchestration engine</description>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml\n        </sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.github.docker-java</groupId>\n            <artifactId>docker-java</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.github.docker-java</groupId>\n            <artifactId>docker-java-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.github.docker-java</groupId>\n            <artifactId>docker-java-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.github.docker-java</groupId>\n            <artifactId>docker-java-transport</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.github.docker-java</groupId>\n            <artifactId>docker-java-transport-httpclient5</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents.client5</groupId>\n            <artifactId>httpclient5</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents.core5</groupId>\n            <artifactId>httpcore5</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.httpcomponents.core5</groupId>\n            <artifactId>httpcore5-h2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.java.dev.jna</groupId>\n            <artifactId>jna</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-compress</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-clean-plugin</artifactId>\n                <configuration>\n                    <verbose>true</verbose>\n                    <filesets>\n                        <fileset>\n                            <directory>lib/</directory>\n                            <followSymlinks>false</followSymlinks>\n                        </fileset>\n                    </filesets>\n                </configuration>\n            </plugin>\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>3.8.1</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <outputDirectory>${project.basedir}/lib</outputDirectory>\n                            <includeArtifactIds>\n                                docker-java, docker-java-core, docker-java-api,\n                                docker-java-transport, docker-java-transport-httpclient5,\n                                httpclient5, httpcore5, httpcore5-h2, jna,\n                                commons-codec, commons-compress\n                            </includeArtifactIds>\n                            <stripVersion>true</stripVersion>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <pluginManagement>\n            <plugins>\n                <!--This\n                plugin's configuration is used to store Eclipse m2e settings\n                    only. It has no influence on the Maven build itself. -->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>1.0.0</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.codehaus.mojo\n                                        </groupId>\n                                        <artifactId>\n                                            properties-maven-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [1.2.1,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>read-project-properties</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore />\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.codehaus.mojo\n                                        </groupId>\n                                        <artifactId>\n                                            build-helper-maven-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [1.9,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>regex-property</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/src/main/java/org/eclipse/kura/container/orchestration/provider/impl/ContainerOrchestrationServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.container.orchestration.provider.impl;\n\nimport static java.util.Objects.isNull;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ContainerOrchestrationService;\nimport org.eclipse.kura.container.orchestration.ContainerState;\nimport org.eclipse.kura.container.orchestration.ImageConfiguration;\nimport org.eclipse.kura.container.orchestration.ImageInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ImageInstanceDescriptor.ImageInstanceDescriptorBuilder;\nimport org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;\nimport org.eclipse.kura.container.orchestration.PortInternetProtocol;\nimport org.eclipse.kura.container.orchestration.RegistryCredentials;\nimport org.eclipse.kura.container.orchestration.listener.ContainerOrchestrationServiceListener;\nimport org.eclipse.kura.container.orchestration.provider.impl.enforcement.AllowlistEnforcementMonitor;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.github.dockerjava.api.DockerClient;\nimport com.github.dockerjava.api.command.CreateContainerCmd;\nimport com.github.dockerjava.api.command.InspectImageResponse;\nimport com.github.dockerjava.api.command.PullImageCmd;\nimport com.github.dockerjava.api.command.PullImageResultCallback;\nimport com.github.dockerjava.api.exception.NotModifiedException;\nimport com.github.dockerjava.api.model.AuthConfig;\nimport com.github.dockerjava.api.model.Bind;\nimport com.github.dockerjava.api.model.Container;\nimport com.github.dockerjava.api.model.ContainerPort;\nimport com.github.dockerjava.api.model.Device;\nimport com.github.dockerjava.api.model.DeviceRequest;\nimport com.github.dockerjava.api.model.ExposedPort;\nimport com.github.dockerjava.api.model.HostConfig;\nimport com.github.dockerjava.api.model.Image;\nimport com.github.dockerjava.api.model.InternetProtocol;\nimport com.github.dockerjava.api.model.LogConfig;\nimport com.github.dockerjava.api.model.LogConfig.LoggingType;\nimport com.github.dockerjava.api.model.Ports;\nimport com.github.dockerjava.api.model.Ports.Binding;\nimport com.github.dockerjava.api.model.PullResponseItem;\nimport com.github.dockerjava.api.model.RestartPolicy;\nimport com.github.dockerjava.api.model.Volume;\nimport com.github.dockerjava.core.DefaultDockerClientConfig;\nimport com.github.dockerjava.core.DockerClientConfig;\nimport com.github.dockerjava.core.DockerClientImpl;\nimport com.github.dockerjava.httpclient5.ApacheDockerHttpClient;\nimport com.github.dockerjava.transport.DockerHttpClient;\nimport com.google.common.collect.ImmutableList;\n\npublic class ContainerOrchestrationServiceImpl implements ConfigurableComponent, ContainerOrchestrationService {\n\n    private static final String PARAMETER_CANNOT_BE_NULL = \"The provided parameter cannot be null\";\n    private static final String UNABLE_TO_CONNECT_TO_DOCKER_CLI = \"Unable to connect to docker cli\";\n    private static final Logger logger = LoggerFactory.getLogger(ContainerOrchestrationServiceImpl.class);\n    private static final String APP_ID = \"org.eclipse.kura.container.orchestration.provider.ConfigurableDocker\";\n\n    private ContainerOrchestrationServiceOptions currentConfig;\n\n    private final Set<ContainerOrchestrationServiceListener> dockerServiceListeners = new CopyOnWriteArraySet<>();\n    private final Set<FrameworkManagedContainer> frameworkManagedContainers = new CopyOnWriteArraySet<>();\n\n    private DockerClient dockerClient;\n    private CryptoService cryptoService;\n\n    private AllowlistEnforcementMonitor allowlistEnforcementMonitor;\n\n    private Map<String, String> containerInstancesDigests = new HashMap<>();\n\n    public void setDockerClient(DockerClient dockerClient) {\n        this.dockerClient = dockerClient;\n    }\n\n    public void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void activate(Map<String, Object> properties) {\n        logger.info(\"Bundle {} is starting with config!\", APP_ID);\n        if (!isNull(properties)) {\n            updated(properties);\n        }\n        logger.info(\"Bundle {} has started with config!\", APP_ID);\n    }\n\n    public void deactivate() {\n        logger.info(\"Bundle {} is stopping!\", APP_ID);\n        if (testConnection()) {\n            disconnect();\n        }\n        logger.info(\"Bundle {} has stopped!\", APP_ID);\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"Bundle {} is updating with config!\", APP_ID);\n        ContainerOrchestrationServiceOptions newProps = new ContainerOrchestrationServiceOptions(properties);\n        if (!newProps.equals(this.currentConfig)) {\n\n            this.currentConfig = newProps;\n\n            logger.info(\"Connecting to docker \");\n\n            if (!this.currentConfig.isEnabled()) {\n                cleanUpDocker();\n                return;\n            }\n\n            if (this.allowlistEnforcementMonitor != null) {\n                closeEnforcementMonitor();\n            }\n\n            connect();\n\n            if (!testConnection()) {\n                logger.error(\"Could not connect to docker CLI.\");\n                return;\n            }\n            logger.info(\"Connection Successful\");\n\n            if (currentConfig.isEnforcementEnabled()) {\n                try {\n                    startEnforcementMonitor();\n                } catch (Exception ex) {\n                    logger.error(\"Error starting enforcement monitor. Due to {}\", ex.getMessage());\n                    closeEnforcementMonitor();\n                    logger.warn(\"Enforcement won't be active.\");\n                }\n                enforceAlreadyRunningContainer();\n            }\n        }\n\n        logger.info(\"Bundle {} has updated with config!\", APP_ID);\n    }\n\n    private void startEnforcementMonitor() {\n        logger.info(\"Enforcement monitor starting...\");\n        this.allowlistEnforcementMonitor = this.dockerClient.eventsCmd().withEventFilter(\"start\")\n                .exec(new AllowlistEnforcementMonitor(currentConfig.getEnforcementAllowlist(), this));\n        logger.info(\"Enforcement monitor starting...done.\");\n    }\n\n    private void closeEnforcementMonitor() {\n\n        if (this.allowlistEnforcementMonitor == null) {\n            return;\n        }\n\n        try {\n            logger.info(\"Enforcement monitor closing...\");\n            this.allowlistEnforcementMonitor.close();\n            this.allowlistEnforcementMonitor.awaitCompletion(5, TimeUnit.SECONDS);\n            this.allowlistEnforcementMonitor = null;\n            logger.info(\"Enforcement monitor closing...done.\");\n        } catch (InterruptedException ex) {\n            logger.error(\"Waited too long to close enforcement monitor, stopping it...\", ex);\n            Thread.currentThread().interrupt();\n        } catch (IOException ex) {\n            logger.error(\"Failed to close enforcement monitor, stopping it...\", ex);\n        }\n    }\n\n    private void enforceAlreadyRunningContainer() {\n        if (this.allowlistEnforcementMonitor == null) {\n            logger.warn(\"Enforcement wasn't started. Check on running containers will not be performed.\");\n            return;\n        }\n        logger.info(\"Enforcement check on already running containers...\");\n        this.allowlistEnforcementMonitor.enforceAllowlistFor(listContainerDescriptors());\n        logger.info(\"Enforcement check on already running containers...done\");\n    }\n\n    @Override\n    public List<String> listContainersIds() {\n        if (!testConnection()) {\n            throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI);\n        }\n\n        List<Container> containers = this.dockerClient.listContainersCmd().withShowAll(true).exec();\n\n        List<String> result = new ArrayList<>();\n\n        for (Container cont : containers) {\n            result.add(cont.getId());\n        }\n\n        return result;\n\n    }\n\n    @Override\n    public List<ContainerInstanceDescriptor> listContainerDescriptors() {\n        if (!testConnection()) {\n            throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI);\n        }\n\n        List<Container> containers = this.dockerClient.listContainersCmd().withShowAll(true).exec();\n\n        List<ContainerInstanceDescriptor> result = new ArrayList<>();\n        containers.forEach(container -> result.add(ContainerInstanceDescriptor.builder()\n                .setContainerName(getContainerName(container)).setContainerImage(getContainerTag(container))\n                .setContainerImageTag(getContainerVersion(container)).setContainerID(container.getId())\n                .setContainerPorts(parseContainerPortsList(container.getPorts()))\n                .setContainerState(convertDockerStateToFrameworkState(container.getState()))\n                .setFrameworkManaged(isFrameworkManaged(container)).build()));\n\n        return result;\n\n    }\n\n    private Boolean isFrameworkManaged(Container container) {\n        String containerName = getContainerName(container);\n        return this.frameworkManagedContainers.stream().anyMatch(c -> c.name.equals(containerName));\n    }\n\n    private String getContainerName(Container container) {\n        return container.getNames()[0].replace(\"/\", \"\");\n    }\n\n    private String getContainerVersion(Container container) {\n        String version = \"\";\n        String[] image = container.getImage().split(\":\");\n        if (image.length > 1 && !image[0].startsWith(\"sha256\")) {\n            version = image[1];\n        }\n        return version;\n    }\n\n    private String getContainerTag(Container container) {\n        String[] image = container.getImage().split(\":\");\n        if (image[0].startsWith(\"sha256\")) {\n            return \"none\";\n        } else {\n            return image[0];\n        }\n    }\n\n    private List<org.eclipse.kura.container.orchestration.ContainerPort> parseContainerPortsList(\n            ContainerPort[] ports) {\n\n        List<org.eclipse.kura.container.orchestration.ContainerPort> kuraContainerPorts = new ArrayList<>();\n\n        Arrays.asList(ports).stream().forEach(containerPort -> {\n            String ipTest = containerPort.getIp();\n            if (ipTest != null && (ipTest.equals(\"::\") || ipTest.equals(\"0.0.0.0\"))) {\n                kuraContainerPorts\n                        .add(new org.eclipse.kura.container.orchestration.ContainerPort(containerPort.getPrivatePort(),\n                                containerPort.getPublicPort(), parsePortInternetProtocol(containerPort.getType())));\n            }\n        });\n\n        return kuraContainerPorts;\n    }\n\n    private PortInternetProtocol parsePortInternetProtocol(String dockerPortProtocol) {\n\n        switch (dockerPortProtocol) {\n\n        case \"tcp\":\n            return PortInternetProtocol.TCP;\n\n        case \"udp\":\n            return PortInternetProtocol.UDP;\n\n        case \"sctp\":\n            return PortInternetProtocol.SCTP;\n\n        default:\n            throw new IllegalStateException();\n\n        }\n\n    }\n\n    private ContainerState convertDockerStateToFrameworkState(String dockerState) {\n\n        switch (dockerState.trim()) {\n        case \"created\":\n            return ContainerState.INSTALLED;\n        case \"restarting\":\n            return ContainerState.INSTALLED;\n        case \"running\":\n            return ContainerState.ACTIVE;\n        case \"paused\":\n            return ContainerState.STOPPING;\n        case \"exited\":\n            return ContainerState.STOPPING;\n        case \"dead\":\n            return ContainerState.FAILED;\n        default:\n            return ContainerState.INSTALLED;\n        }\n    }\n\n    @Override\n    public Optional<String> getContainerIdByName(String name) {\n        checkRequestEnv(name);\n\n        List<Container> containers = this.dockerClient.listContainersCmd().withShowAll(true).exec();\n\n        for (Container cont : containers) {\n            String[] containerNames = cont.getNames();\n            for (String containerName : containerNames) {\n                if (containerName.equals(\"/\" + name)) { // docker API seems to put a '/' in front of the names\n                    return Optional.of(cont.getId());\n                }\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    @Override\n    public void startContainer(String id) throws KuraException {\n        checkRequestEnv(id);\n        try {\n            this.dockerClient.startContainerCmd(id).exec();\n        } catch (Exception e) {\n            logger.error(\"Could not start container {}. It could be already running or not exist at all. Caused by {}\",\n                    id, e);\n            throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR);\n        }\n    }\n\n    @Override\n    public String startContainer(ContainerConfiguration container) throws KuraException, InterruptedException {\n        checkRequestEnv(container);\n\n        logger.info(\"Starting {} Microservice\", container.getContainerName());\n\n        final Optional<ContainerInstanceDescriptor> existingInstance = listContainerDescriptors().stream()\n                .filter(c -> c.getContainerName().equals(container.getContainerName())).findAny();\n\n        String containerId;\n\n        if (existingInstance.isPresent()) {\n\n            if (existingInstance.get().getContainerState() == ContainerState.ACTIVE) {\n                logger.info(\"Found already existing running container\");\n                containerId = existingInstance.get().getContainerId();\n            } else {\n                logger.info(\"Found already exisiting not running container, recreating it..\");\n                containerId = existingInstance.get().getContainerId();\n                deleteContainer(containerId);\n                pullImage(container.getImageConfiguration());\n                containerId = createContainer(container);\n                startContainer(containerId);\n\n            }\n        } else {\n            logger.info(\"Creating new container instance\");\n            pullImage(container.getImageConfiguration());\n            containerId = createContainer(container);\n            addContainerInstanceDigest(containerId, container.getEnforcementDigest());\n            startContainer(containerId);\n        }\n\n        logger.info(\"Container Started Successfully\");\n\n        if (container.isFrameworkManaged()) {\n            this.frameworkManagedContainers\n                    .add(new FrameworkManagedContainer(container.getContainerName(), containerId));\n        }\n\n        return containerId;\n    }\n\n    @Override\n    public void stopContainer(String id) throws KuraException {\n        checkRequestEnv(id);\n        try {\n\n            if (listContainersIds().contains(id)) {\n                this.dockerClient.stopContainerCmd(id).exec();\n            }\n\n        } catch (NotModifiedException e) {\n            logger.debug(\"Container {} already stopped\", id);\n        } catch (Exception e) {\n            logger.error(\"Could not stop container {}. Caused by {}\", id, e);\n            throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR);\n        }\n    }\n\n    @Override\n    public void deleteContainer(String id) throws KuraException {\n        checkRequestEnv(id);\n        try {\n\n            if (listContainersIds().contains(id)) {\n                this.dockerClient.removeContainerCmd(id).exec();\n            }\n\n            this.frameworkManagedContainers.removeIf(c -> id.equals(c.id));\n\n            removeContainerInstanceDigest(id);\n\n        } catch (Exception e) {\n            logger.error(\"Could not remove container {}. Caused by {}\", id, e);\n            throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR);\n        }\n    }\n\n    private void checkRequestEnv(Object parameter) {\n        if (isNull(parameter)) {\n            throw new IllegalArgumentException(PARAMETER_CANNOT_BE_NULL);\n        }\n        if (!testConnection()) {\n            throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI);\n        }\n    }\n\n    @Override\n    public void registerListener(ContainerOrchestrationServiceListener dockerListener) {\n        this.dockerServiceListeners.add(dockerListener);\n\n    }\n\n    @Override\n    public void unregisterListener(ContainerOrchestrationServiceListener dockerListener) {\n        this.dockerServiceListeners.remove(dockerListener);\n\n    }\n\n    private void imagePullHelper(String imageName, String imageTag, int timeOutSeconds,\n            Optional<RegistryCredentials> repositoryCredentials) throws InterruptedException, KuraException {\n\n        logger.info(\"Attempting to pull image: {}.\", imageName);\n        PullImageCmd pullRequest = this.dockerClient.pullImageCmd(imageName).withTag(imageTag);\n\n        if (repositoryCredentials.isPresent()) {\n            doAuthenticate(repositoryCredentials.get(), pullRequest);\n        }\n\n        pullRequest.exec(new PullImageResultCallback() {\n\n            @Override\n            public void onNext(PullResponseItem item) {\n                super.onNext(item);\n                createLoggerMessageForContainerPull(item, imageName, imageTag);\n\n            }\n\n        }).awaitCompletion(timeOutSeconds, TimeUnit.SECONDS);\n\n    }\n\n    private void doAuthenticate(RegistryCredentials repositoryCredentials, PullImageCmd pullRequest)\n            throws KuraException {\n        if (!(repositoryCredentials instanceof PasswordRegistryCredentials)) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        PasswordRegistryCredentials repositoryPasswordCredentials = (PasswordRegistryCredentials) repositoryCredentials;\n\n        AuthConfig authConfig = new AuthConfig().withUsername(repositoryPasswordCredentials.getUsername()).withPassword(\n                new String(this.cryptoService.decryptAes(repositoryPasswordCredentials.getPassword().getPassword())));\n        Optional<String> url = repositoryPasswordCredentials.getUrl();\n        if (url.isPresent()) {\n            logger.info(\"Attempting to sign into repo: {}\", url.get());\n            authConfig = authConfig.withRegistryAddress(url.get());\n        }\n        pullRequest.withAuthConfig(authConfig);\n    }\n\n    private void createLoggerMessageForContainerPull(PullResponseItem item, String imageName, String imageTag) {\n\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"Pulling {}:{} Layer {}, State: {}\", imageName, imageTag, item.getId(), item.getStatus());\n        }\n\n        if (item.isErrorIndicated()) {\n            logger.error(\"Unable To Pull image {}:{} because : {}\", item.getErrorDetail(), imageName, imageTag);\n        }\n\n        if (item.isPullSuccessIndicated()) {\n            logger.info(\"Image pull of {}:{}, Layer: {}, was successful\", imageName, imageTag, item.getId());\n        }\n    }\n\n    private String createContainer(ContainerConfiguration containerDescription) throws KuraException {\n        if (!testConnection()) {\n            throw new IllegalStateException(\"failed to reach docker engine\");\n        }\n\n        if (containerDescription == null) {\n            throw new IllegalStateException(\"failed to create container, null containerImage passed\");\n        }\n\n        String containerImageFullString = String.format(\"%s:%s\",\n                containerDescription.getImageConfiguration().getImageName(),\n                containerDescription.getImageConfiguration().getImageTag());\n\n        CreateContainerCmd commandBuilder = null;\n        try {\n            commandBuilder = this.dockerClient.createContainerCmd(containerImageFullString);\n\n            if (containerDescription.getContainerName() != null) {\n                commandBuilder = commandBuilder.withName(containerDescription.getContainerName());\n            }\n\n            HostConfig configuration = new HostConfig();\n\n            commandBuilder = containerEnviromentVariablesHandler(containerDescription, commandBuilder);\n\n            commandBuilder = containerEntrypointHandler(containerDescription, commandBuilder);\n\n            // Host Configuration Related\n            configuration = containerVolumeMangamentHandler(containerDescription, configuration);\n\n            configuration = containerDevicesHandler(containerDescription, configuration);\n\n            if (containerDescription.getRestartOnFailure()) {\n                configuration = configuration.withRestartPolicy(RestartPolicy.unlessStoppedRestart());\n            }\n\n            configuration = containerPortManagementHandler(containerDescription, configuration, commandBuilder);\n\n            configuration = containerLogConfigurationHandler(containerDescription, configuration);\n\n            configuration = containerNetworkConfigurationHandler(containerDescription, configuration);\n\n            configuration = containerMemoryConfigurationHandler(containerDescription, configuration);\n\n            configuration = containerCpusConfigurationHandler(containerDescription, configuration);\n\n            configuration = containerGpusConfigurationHandler(containerDescription, configuration);\n\n            configuration = containerRuntimeConfigurationHandler(containerDescription, configuration);\n\n            if (containerDescription.isContainerPrivileged()) {\n                configuration = configuration.withPrivileged(containerDescription.isContainerPrivileged());\n            }\n\n            return commandBuilder.withHostConfig(configuration).exec().getId();\n\n        } catch (Exception e) {\n            logger.error(\"Failed to create container\", e);\n            throw new KuraException(KuraErrorCode.PROCESS_EXECUTION_ERROR);\n        } finally {\n            if (!isNull(commandBuilder)) {\n                commandBuilder.close();\n            }\n        }\n    }\n\n    private HostConfig containerLogConfigurationHandler(ContainerConfiguration containerDescription,\n            HostConfig configuration) {\n        LoggingType lt;\n        switch (containerDescription.getContainerLoggingType().toUpperCase().trim()) {\n        case \"NONE\":\n            lt = LoggingType.NONE;\n            break;\n        case \"LOCAL\":\n            lt = LoggingType.LOCAL;\n            break;\n        case \"ETWLOGS\":\n            lt = LoggingType.ETWLOGS;\n            break;\n        case \"JSON_FILE\":\n            lt = LoggingType.JSON_FILE;\n            break;\n        case \"SYSLOG\":\n            lt = LoggingType.SYSLOG;\n            break;\n        case \"JOURNALD\":\n            lt = LoggingType.JOURNALD;\n            break;\n        case \"GELF\":\n            lt = LoggingType.GELF;\n            break;\n        case \"FLUENTD\":\n            lt = LoggingType.FLUENTD;\n            break;\n        case \"AWSLOGS\":\n            lt = LoggingType.AWSLOGS;\n            break;\n        case \"DB\":\n            lt = LoggingType.DB;\n            break;\n        case \"SPLUNK\":\n            lt = LoggingType.SPLUNK;\n            break;\n        case \"GCPLOGS\":\n            lt = LoggingType.GCPLOGS;\n            break;\n        case \"LOKI\":\n            lt = LoggingType.LOKI;\n            break;\n        default:\n            lt = LoggingType.DEFAULT;\n            break;\n        }\n\n        LogConfig lc = new LogConfig(lt, containerDescription.getLoggerParameters());\n\n        configuration.withLogConfig(lc);\n\n        return configuration;\n    }\n\n    private HostConfig containerNetworkConfigurationHandler(ContainerConfiguration containerDescription,\n            HostConfig configuration) {\n\n        Optional<String> networkMode = containerDescription.getContainerNetworkConfiguration().getNetworkMode();\n        if (networkMode.isPresent() && !networkMode.get().trim().isEmpty()) {\n            configuration.withNetworkMode(networkMode.get().trim());\n        }\n\n        return configuration;\n    }\n\n    private HostConfig containerMemoryConfigurationHandler(ContainerConfiguration containerDescription,\n            HostConfig configuration) {\n\n        Optional<Long> memory = containerDescription.getMemory();\n        if (memory.isPresent()) {\n            try {\n                configuration.withMemory(memory.get());\n            } catch (NumberFormatException e) {\n                logger.warn(\"Memory value {} not valid. Caused by {}\", memory.get(), e);\n            }\n        }\n\n        return configuration;\n    }\n\n    private HostConfig containerCpusConfigurationHandler(ContainerConfiguration containerDescription,\n            HostConfig configuration) {\n\n        Optional<Float> cpus = containerDescription.getCpus();\n        cpus.ifPresent(cpu -> {\n            configuration.withCpuPeriod(100000L);\n            configuration.withCpuQuota((long) (100000L * cpus.get()));\n        });\n\n        return configuration;\n    }\n\n    private HostConfig containerGpusConfigurationHandler(ContainerConfiguration containerDescription,\n            HostConfig configuration) {\n\n        Optional<String> gpus = containerDescription.getGpus();\n        gpus.ifPresent(gpu -> configuration.withDeviceRequests(ImmutableList\n                .of(new DeviceRequest().withDriver(\"nvidia\").withCount(gpu.equals(\"all\") ? -1 : Integer.parseInt(gpu))\n                        .withCapabilities(ImmutableList.of(ImmutableList.of(\"gpu\"))))));\n\n        return configuration;\n    }\n\n    private HostConfig containerRuntimeConfigurationHandler(ContainerConfiguration containerDescription,\n            HostConfig configuration) {\n\n        Optional<String> runtime = containerDescription.getRuntime();\n        runtime.ifPresent(configuration::withRuntime);\n\n        return configuration;\n    }\n\n    private HostConfig containerPortManagementHandler(ContainerConfiguration containerConfiguration,\n            HostConfig hostConfig, CreateContainerCmd commandBuilder) {\n\n        List<ExposedPort> exposedPorts = new LinkedList<>();\n        Ports portbindings = new Ports();\n\n        if (containerConfiguration.getContainerPorts() != null\n                && !containerConfiguration.getContainerPorts().isEmpty()) {\n\n            List<org.eclipse.kura.container.orchestration.ContainerPort> containerPorts = containerConfiguration\n                    .getContainerPorts();\n\n            for (org.eclipse.kura.container.orchestration.ContainerPort port : containerPorts) {\n\n                InternetProtocol ipProtocol = InternetProtocol.TCP;\n\n                if (port.getInternetProtocol() != null) {\n                    try {\n                        ipProtocol = InternetProtocol.parse(port.getInternetProtocol().toString());\n                    } catch (IllegalArgumentException e) {\n                        logger.warn(\"Invalid internet protocol: {}. Using TCP.\", port.getInternetProtocol());\n                    }\n                }\n\n                ExposedPort exposedPort = new ExposedPort(port.getInternalPort(), ipProtocol);\n                exposedPorts.add(exposedPort);\n                portbindings.bind(exposedPort, Binding.bindPort(port.getExternalPort()));\n            }\n\n            if (exposedPorts.size() != portbindings.getBindings().size()) {\n                logger.error(\"portsExternal and portsInternal must have the same size: {}\",\n                        containerConfiguration.getContainerName());\n            }\n        }\n\n        hostConfig.withPortBindings(portbindings);\n        commandBuilder.withExposedPorts(exposedPorts);\n\n        return hostConfig;\n    }\n\n    private CreateContainerCmd containerEnviromentVariablesHandler(ContainerConfiguration containerDescription,\n            CreateContainerCmd commandBuilder) {\n\n        if (containerDescription.getContainerEnvVars().isEmpty()) {\n            return commandBuilder;\n        }\n\n        if (containerDescription.getContainerEnvVars() != null\n                && !containerDescription.getContainerEnvVars().isEmpty()) {\n            List<String> formattedEnvVars = new LinkedList<>();\n            for (String env : containerDescription.getContainerEnvVars()) {\n                if (!env.trim().isEmpty()) {\n                    formattedEnvVars.add(env.trim());\n                }\n            }\n            commandBuilder = commandBuilder.withEnv(formattedEnvVars);\n        }\n\n        return commandBuilder;\n\n    }\n\n    private CreateContainerCmd containerEntrypointHandler(ContainerConfiguration containerDescription,\n            CreateContainerCmd commandBuilder) {\n\n        if (containerDescription.getEntryPoint().isEmpty() || containerDescription.getEntryPoint() == null) {\n            return commandBuilder;\n        }\n\n        return commandBuilder.withEntrypoint(containerDescription.getEntryPoint());\n\n    }\n\n    private HostConfig containerVolumeMangamentHandler(ContainerConfiguration containerDescription,\n            HostConfig hostConfiguration) {\n\n        if (containerDescription.getContainerVolumes().isEmpty()) {\n            return hostConfiguration;\n        }\n\n        List<Bind> bindsToAdd = new LinkedList<>();\n\n        if (containerDescription.getContainerVolumes() != null\n                && !containerDescription.getContainerVolumes().isEmpty()) {\n\n            for (Map.Entry<String, String> element : containerDescription.getContainerVolumes().entrySet()) {\n                // source: path on host (key)\n                // destination: path in container (value)\n                if (!element.getKey().isEmpty() && !element.getValue().isEmpty()) {\n                    Volume tempVolume = new Volume(element.getValue());\n                    Bind tempBind = new Bind(element.getKey(), tempVolume);\n                    bindsToAdd.add(tempBind);\n                }\n            }\n            hostConfiguration = hostConfiguration.withBinds(bindsToAdd);\n\n        }\n\n        return hostConfiguration;\n\n    }\n\n    private HostConfig containerDevicesHandler(ContainerConfiguration containerDescription,\n            HostConfig hostConfiguration) {\n\n        if (containerDescription.getContainerDevices().isEmpty()) {\n            return hostConfiguration;\n        }\n\n        if (containerDescription.getContainerDevices() != null\n                && !containerDescription.getContainerDevices().isEmpty()) {\n\n            List<Device> deviceList = new LinkedList<>();\n            for (String deviceString : containerDescription.getContainerDevices()) {\n                deviceList.add(Device.parse(deviceString));\n            }\n            if (!deviceList.isEmpty()) {\n                hostConfiguration = hostConfiguration.withDevices(deviceList);\n\n            }\n        }\n\n        return hostConfiguration;\n\n    }\n\n    private boolean doesImageExist(String imageName, String imageTag) {\n\n        if (!testConnection()) {\n            throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI);\n        }\n\n        List<Image> images = this.dockerClient.listImagesCmd().exec();\n\n        String requiredImage = imageName + \":\" + imageTag;\n\n        for (Image image : images) {\n            if (isNull(image.getRepoTags())) {\n                continue;\n            }\n            for (String tag : image.getRepoTags()) {\n                if (tag.equals(requiredImage)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    private void cleanUpDocker() {\n\n        if (this.allowlistEnforcementMonitor != null) {\n            closeEnforcementMonitor();\n        }\n\n        if (testConnection()) {\n            this.dockerServiceListeners.forEach(ContainerOrchestrationServiceListener::onDisabled);\n            disconnect();\n        }\n    }\n\n    private boolean connect() {\n        if (this.currentConfig.getHostUrl() == null) {\n            return false;\n        }\n        DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder()\n                .withDockerHost(this.currentConfig.getHostUrl()).build();\n\n        DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder().dockerHost(config.getDockerHost()).build();\n\n        this.dockerClient = DockerClientImpl.getInstance(config, httpClient);\n\n        final boolean connected = testConnection();\n\n        if (connected) {\n            this.dockerServiceListeners.forEach(ContainerOrchestrationServiceListener::onConnect);\n        }\n        return connected;\n    }\n\n    private void disconnect() {\n        if (testConnection()) {\n            try {\n                this.dockerServiceListeners.forEach(ContainerOrchestrationServiceListener::onDisconnect);\n                this.dockerClient.close();\n            } catch (IOException e) {\n                logger.error(\"Error disconnecting\", e);\n            }\n        }\n    }\n\n    private boolean testConnection() {\n        boolean canConnect = false;\n        try {\n            this.dockerClient.pingCmd().exec();\n            canConnect = true;\n        } catch (Exception ex) {\n            canConnect = false;\n        }\n        return canConnect;\n    }\n\n    private static class FrameworkManagedContainer {\n\n        private final String name;\n        private final String id;\n\n        public FrameworkManagedContainer(String name, String id) {\n            this.name = name;\n            this.id = id;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(this.id, this.name);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (obj == null || getClass() != obj.getClass()) {\n                return false;\n            }\n            FrameworkManagedContainer other = (FrameworkManagedContainer) obj;\n            return Objects.equals(this.id, other.id) && Objects.equals(this.name, other.name);\n        }\n\n    }\n\n    @Override\n    public void pullImage(ImageConfiguration imageConfig) throws KuraException, InterruptedException {\n        if (isNull(imageConfig.getImageName()) || isNull(imageConfig.getImageTag())\n                || imageConfig.getimageDownloadTimeoutSeconds() < 0 || isNull(imageConfig.getRegistryCredentials())) {\n            throw new IllegalArgumentException(\"Parameters cannot be null or negative\");\n        }\n\n        boolean imageAvailableLocally = doesImageExist(imageConfig.getImageName(), imageConfig.getImageTag());\n\n        if (!imageAvailableLocally) {\n            try {\n                imagePullHelper(imageConfig.getImageName(), imageConfig.getImageTag(),\n                        imageConfig.getimageDownloadTimeoutSeconds(), imageConfig.getRegistryCredentials());\n            } catch (InterruptedException e) {\n                throw e;\n            } catch (Exception e) {\n                logger.error(\"Cannot pull container. Caused by \", e);\n                throw new KuraException(KuraErrorCode.IO_ERROR, \"Unable to pull container\");\n            }\n        }\n    }\n\n    @Override\n    public void pullImage(String imageName, String imageTag, int timeOutSeconds,\n            Optional<RegistryCredentials> registryCredentials) throws KuraException, InterruptedException {\n        pullImage(new ImageConfiguration.ImageConfigurationBuilder().setImageName(imageName).setImageTag(imageTag)\n                .setImageDownloadTimeoutSeconds(timeOutSeconds).setRegistryCredentials(registryCredentials).build());\n    }\n\n    @Override\n    public List<ImageInstanceDescriptor> listImageInstanceDescriptors() {\n        if (!testConnection()) {\n            throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI);\n        }\n        List<Image> images = this.dockerClient.listImagesCmd().withShowAll(true).exec();\n        List<ImageInstanceDescriptor> result = new ArrayList<>();\n        images.forEach(image -> {\n            InspectImageResponse iir = this.dockerClient.inspectImageCmd(image.getId()).exec();\n\n            ImageInstanceDescriptorBuilder imageBuilder = ImageInstanceDescriptor.builder()\n                    .setImageName(getImageName(image)).setImageTag(getImageTag(image)).setImageId(image.getId())\n                    .setImageAuthor(iir.getAuthor()).setImageArch(iir.getArch())\n                    .setimageSize(iir.getSize().longValue());\n\n            if (image.getLabels() != null) {\n                imageBuilder.setImageLabels(image.getLabels());\n            }\n\n            result.add(imageBuilder.build());\n        });\n        return result;\n    }\n\n    private String getImageName(Image image) {\n        if (image.getRepoTags() == null || image.getRepoTags().length < 1) {\n            return \"\";\n        }\n\n        return image.getRepoTags()[0].split(\":\")[0];\n    }\n\n    private String getImageTag(Image image) {\n        if (image.getRepoTags() == null || image.getRepoTags().length < 1\n                || image.getRepoTags()[0].split(\":\").length < 2) {\n            return \"\";\n        }\n\n        return image.getRepoTags()[0].split(\":\")[1];\n    }\n\n    @Override\n    public void deleteImage(String imageId) throws KuraException {\n        checkRequestEnv(imageId);\n        try {\n            this.dockerClient.removeImageCmd(imageId).exec();\n        } catch (Exception e) {\n            logger.error(\"Could not remove image {}. Caused by {}\", imageId, e);\n            throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR, \"Delete Container Image\",\n                    \"500 (server error). Image is most likely in use by a container.\");\n        }\n    }\n\n    public Set<String> getImageDigestsByContainerId(String containerId) {\n\n        Set<String> imageDigests = new HashSet<>();\n\n        String containerName = listContainerDescriptors().stream()\n                .filter(container -> container.getContainerId().equals(containerId)).findFirst()\n                .map(container -> container.getContainerName()).orElse(null);\n\n        if (containerName == null) {\n            return imageDigests;\n        }\n\n        dockerClient.listImagesCmd().withImageNameFilter(containerName).exec().stream().forEach(image -> {\n            List<String> digests = Arrays.asList(image.getRepoDigests());\n            digests.stream().forEach(digest -> imageDigests.add(digest.split(\"@\")[1]));\n        });\n\n        return imageDigests;\n    }\n\n    private void addContainerInstanceDigest(String containerId, Optional<String> containerInstanceDigest) {\n\n        if (containerInstanceDigest.isPresent()) {\n            logger.info(\n                    \"Container {} presented enforcement digest. Adding it to the digests allowlist: it will be used if the enforcement is enabled.\",\n                    containerId);\n            this.containerInstancesDigests.put(containerId, containerInstanceDigest.get());\n        } else {\n            logger.info(\"Container {} doesn't contain the enforcement digest. \"\n                    + \"If enforcement is enabled, be sure that the digest is included in the Orchestration Service allowlist\",\n                    containerId);\n        }\n\n    }\n\n    private void removeContainerInstanceDigest(String containerId) {\n        if (this.containerInstancesDigests.containsKey(containerId)) {\n            this.containerInstancesDigests.remove(containerId);\n            logger.info(\"Removed digest of container with ID {} from Container Instances Allowlist\", containerId);\n            enforceAlreadyRunningContainer();\n        }\n    }\n\n    public Set<String> getContainerInstancesAllowlist() {\n        return new HashSet<>(this.containerInstancesDigests.values());\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/src/main/java/org/eclipse/kura/container/orchestration/provider/impl/ContainerOrchestrationServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.container.orchestration.provider.impl;\n\nimport static java.util.Objects.isNull;\n\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class ContainerOrchestrationServiceOptions {\n\n    private static final Property<Boolean> IS_ENABLED = new Property<>(\"enabled\", false);\n    private static final Property<String> DOCKER_HOST_URL = new Property<>(\"container.engine.host\",\n            \"unix:///var/run/docker.sock\");\n    private static final Property<Boolean> ENFORCEMENT_ENABLED = new Property<>(\"enforcement.enabled\", false);\n    private static final Property<String> ENFORCEMENT_ALLOWLIST = new Property<>(\"enforcement.allowlist\", \"\");\n\n    private final boolean enabled;\n    private final String hostUrl;\n    private final boolean enforcementEnabled;\n    private final String enforcementAllowlist;\n\n    public ContainerOrchestrationServiceOptions(final Map<String, Object> properties) {\n\n        if (isNull(properties)) {\n            throw new IllegalArgumentException(\"Properties cannot be null!\");\n        }\n\n        this.enabled = IS_ENABLED.get(properties);\n        this.hostUrl = DOCKER_HOST_URL.get(properties);\n        this.enforcementEnabled = ENFORCEMENT_ENABLED.get(properties);\n        this.enforcementAllowlist = ENFORCEMENT_ALLOWLIST.get(properties);\n\n    }\n\n    public boolean isEnabled() {\n        return this.enabled;\n    }\n\n    public String getHostUrl() {\n        return this.hostUrl;\n    }\n\n    public boolean isEnforcementEnabled() {\n        return this.enforcementEnabled;\n    }\n\n    public String getEnforcementAllowlist() {\n        return this.enforcementAllowlist;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(enforcementAllowlist, enforcementEnabled, enabled, hostUrl);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        ContainerOrchestrationServiceOptions other = (ContainerOrchestrationServiceOptions) obj;\n        return Objects.equals(enforcementAllowlist, other.enforcementAllowlist)\n                && enforcementEnabled == other.enforcementEnabled && enabled == other.enabled\n                && Objects.equals(hostUrl, other.hostUrl);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.orchestration.provider/src/main/java/org/eclipse/kura/container/orchestration/provider/impl/enforcement/AllowlistEnforcementMonitor.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration.provider.impl.enforcement;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ContainerState;\nimport org.eclipse.kura.container.orchestration.provider.impl.ContainerOrchestrationServiceImpl;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.github.dockerjava.api.async.ResultCallbackTemplate;\nimport com.github.dockerjava.api.model.Event;\n\npublic class AllowlistEnforcementMonitor extends ResultCallbackTemplate<AllowlistEnforcementMonitor, Event> {\n\n    private static final Logger logger = LoggerFactory.getLogger(AllowlistEnforcementMonitor.class);\n    private static final String ENFORCEMENT_CHECK_SUCCESS = \"Enforcement allowlist contains image digests {}...container {} is starting\";\n    private static final String ENFORCEMENT_CHECK_FAILURE = \"Enforcement allowlist doesn't contain image digests...container {} will be stopped\";\n    private final Set<String> enforcementAllowlistContent;\n    private final ContainerOrchestrationServiceImpl orchestrationServiceImpl;\n\n    public AllowlistEnforcementMonitor(String allowlistContent,\n            ContainerOrchestrationServiceImpl containerOrchestrationService) {\n\n        this.enforcementAllowlistContent = Arrays.asList(allowlistContent.replace(\" \", \"\").split(\"\\\\r?\\\\n|\\\\r\"))\n                .stream().filter(line -> !line.isEmpty()).collect(Collectors.toSet());\n        this.orchestrationServiceImpl = containerOrchestrationService;\n    }\n\n    @Override\n    public void onNext(Event item) {\n        enforceAllowlistFor(item.getId());\n    }\n\n    private void enforceAllowlistFor(String containerId) {\n\n        Set<String> digestsList = this.orchestrationServiceImpl.getImageDigestsByContainerId(containerId);\n\n        Set<String> digestIntersection = this.enforcementAllowlistContent.stream().distinct()\n                .filter(digestsList::contains).collect(Collectors.toSet());\n      \n        if (digestIntersection.isEmpty()) {\n            digestIntersection = this.orchestrationServiceImpl.getContainerInstancesAllowlist().stream().distinct()\n                    .filter(digestsList::contains).collect(Collectors.toSet());\n        }\n\n\n        if (!digestIntersection.isEmpty()) {\n            logger.info(ENFORCEMENT_CHECK_SUCCESS, digestIntersection, containerId);\n        } else {\n            logger.info(ENFORCEMENT_CHECK_FAILURE, containerId);\n            stopContainer(containerId);\n            deleteContainer(containerId);\n        }\n    }\n\n    public void enforceAllowlistFor(List<ContainerInstanceDescriptor> containerDescriptors) {\n\n        for (ContainerInstanceDescriptor descriptor : containerDescriptors) {\n            enforceAllowlistFor(descriptor.getContainerId());\n        }\n    }\n\n    private void stopContainer(String containerId) {\n\n        this.orchestrationServiceImpl.listContainerDescriptors().stream()\n                .filter(descriptor -> descriptor.getContainerId().equals(containerId)).findFirst()\n                .ifPresent(descriptor -> {\n                    if (descriptor.getContainerState().equals(ContainerState.ACTIVE)\n                            || descriptor.getContainerState().equals(ContainerState.STARTING)) {\n                        try {\n                            this.orchestrationServiceImpl.stopContainer(descriptor.getContainerId());\n                        } catch (KuraException ex) {\n                            logger.error(\"Error during container stopping process of {}:\", descriptor.getContainerId(),\n                                    ex);\n                        }\n                    }\n\n                });\n    }\n\n    private void deleteContainer(String containerId) {\n        try {\n            this.orchestrationServiceImpl.deleteContainer(containerId);\n        } catch (KuraException ex) {\n            logger.error(\"Error during container deleting process of {}:\", containerId, ex);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Configurable custom container service\nBundle-SymbolicName: org.eclipse.kura.container.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: EUROTECH\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,1.3)\",\n org.eclipse.kura.container.orchestration;version=\"[1.2,2.0)\",\n org.eclipse.kura.container.orchestration.listener;version=\"[1.0,1.1)\",\n org.eclipse.kura.container.signature;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.identity;version=\"[1.2,2.0)\",\n org.eclipse.kura.net;version=\"[2.0,3.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0,2.0)\",\n org.osgi.service.component;version=\"1.4.0\",\n org.slf4j;version=\"1.7.25\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/OSGI-INF/containerinstance.xml",
    "content": "<!--\n     Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n\n     This program and the accompanying materials are made\n     available under the terms of the Eclipse Public License 2.0\n     which is available at https://www.eclipse.org/legal/epl-2.0/\n\n \tSPDX-License-Identifier: EPL-2.0\n\n\tContributors:\n\t Eurotech\n -->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" enabled=\"true\" immediate=\"true\" activate=\"activate\"\n    configuration-policy=\"require\" deactivate=\"deactivate\" modified=\"updated\" name=\"org.eclipse.kura.container.provider.ContainerInstance\">\n   <implementation class=\"org.eclipse.kura.container.provider.ContainerInstance\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.container.provider.ContainerInstance\"/>\n   <reference bind=\"setContainerOrchestrationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.container.orchestration.ContainerOrchestrationService\" name=\"ContainerOrchestrationService\" policy=\"static\"/>\n   <reference bind=\"setContainerSignatureValidationService\" cardinality=\"0..n\" interface=\"org.eclipse.kura.container.signature.ContainerSignatureValidationService\" name=\"ContainerSignatureValidationService\" policy=\"dynamic\" unbind=\"unsetContainerSignatureValidationService\"/>\n   <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\"/>\n   <reference bind=\"setIdentityService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.identity.IdentityService\" name=\"IdentityService\" policy=\"static\"/>\n   <reference bind=\"setPasswordStrengthVerificationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.identity.PasswordStrengthVerificationService\" name=\"PasswordStrengthVerificationService\" policy=\"static\"/>\n   <reference name=\"NetworkService\" \n              policy=\"static\" \n              cardinality=\"0..1\" \n              bind=\"setNetworkService\"\n              interface=\"org.eclipse.kura.net.NetworkService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/OSGI-INF/metatype/org.eclipse.kura.container.provider.ContainerInstance.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.container.provider.ContainerInstance\" name=\"Container Instance\"\n        description=\"Allows for the creation of containers.\">\n\n        <AD id=\"container.enabled\" name=\"Enabled\" type=\"Boolean\" cardinality=\"1\" required=\"true\" default=\"false\"\n            description=\"Enables this container\">\n        </AD>\n        \n        <AD id=\"container.image\" \n            name=\"Image name\" \n            description=\"Specifies the image reference that will be used to create this container instance. \n            The value has to be expressed in the form registryURL/imagename. If no registryURL is provided, the official Docker Hub registry will be used as default. \n            When pulling the testing/test-image image from a local registry listening on port 5000 (e.g. myregistry.local:5000), the registryURL/imagename field has\n            to be specified as follows: myregistry.local:5000/testing/test-image\n            Default: nginx (the image will be pulled from the Docker Hub registry)\"\n            type=\"String\" cardinality=\"1\" required=\"true\" default=\"nginx\" />\n\n        <AD id=\"container.image.tag\" name=\"Image tag\"\n            description=\"Describes which image version should be pulled from the container registry. Default: latest\" type=\"String\"\n            cardinality=\"1\" required=\"true\" default=\"latest\" />\n        \n        <AD id=\"registry.hostname\" name=\"Authentication Registry URL\"\n            description=\"Url for docker registry. Required only for authenticated registries\" \n            type=\"String\"\n            cardinality=\"0\" required=\"false\" default=\"\" />\n            \n        <AD id=\"registry.username\" name=\"Authentication Username\"\n            description=\"Username for container registry. Required only for authenticated registries\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"false\" \n            default=\"\" />\n            \n        <AD id=\"registry.password\" name=\"Password\"\n            description=\"Password for container registry. Required only for authenticated registries\" \n            type=\"Password\"\n            cardinality=\"0\" required=\"false\" default=\"\" />\n\n        <AD id=\"container.signature.trust.anchor\" name=\"Trust anchor\"\n            description=\"Trust anchor used to verify the container image signature.|TextArea\" type=\"String\"\n            cardinality=\"1\" required=\"false\" default=\"\" />\n\n        <AD id=\"container.signature.verify.transparency.log\" name=\"Verify in transparency log\"\n            description=\"Sets the transparency log verification, to be used when a container image signature has been uploaded to the transparency log.\" type=\"Boolean\"\n            cardinality=\"1\" required=\"false\" default=\"true\" />\n        \n        <AD id=\"container.signature.enforcement.digest\"\n            name=\"Container Image Enforcement Digest\"\n            description=\"Digest of the container image allowed to run on the device, if the Container Enforcement Monitor is enabled. If not provided, it will be computed by the Container Signature Verification service.\"\n            type=\"String\" cardinality=\"1\" required=\"false\"\n            default=\"\" />\n        \n        <AD id=\"container.image.download.retries\" \n            name=\"Image Download Retries\" \n            description=\"Specifies the number of retries the framework performs when attempting to pull the container image. Set to 0 for unlimited retries. Default: 5\"\n            type=\"Integer\" \n            cardinality=\"1\" \n            min=\"0\"\n            required=\"true\" \n            default=\"5\" />\n            \n        <AD id=\"container.image.download.interval\" \n            name=\"Image Download Retry Interval\" \n            description=\"The interval (in milliseconds) between retries to pull the container image. Default: 30000\"\n            type=\"Integer\" \n            cardinality=\"1\" \n            min=\"0\"\n            required=\"true\" \n            default=\"30000\" />\n        \n        <AD id=\"container.image.download.timeout\" \n            name=\"Image Download Timeout\"\n            description=\"Image download timeout. Value specified in seconds. Default: 500\" \n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\" \n            min=\"1\"\n            default=\"500\" />\n\n        <AD id=\"container.ports.internal\" name=\"Internal Ports\"\n            description=\"A comma-separated list of ports. If no protocol is specified tcp will be used. Note, the number of internal ports must be equal to the number of external ports. A port internet protocol can also be specified with a colon and text after the port number. Example: 80, 443:udp, 8080:tcp.\" \n            type=\"String\" cardinality=\"1\" required=\"false\"\n            default=\"80:tcp\" />\n\n        <AD id=\"container.ports.external\" name=\"External Ports\"\n            description=\"A comma separated list of ports. Note, the number of external ports must be equal to the number of internal ports. Example: 8080, 443.\" \n            type=\"String\" cardinality=\"1\" required=\"false\"\n            default=\"8080\" />\n\n        <AD id=\"container.privileged\" name=\"Privileged Mode\" type=\"Boolean\" cardinality=\"1\" required=\"true\" default=\"false\"\n            description=\"Give the container privileged access. (Warning: use this option at your own risk as privileged containers can be dangerous)\">\n        </AD>\n        \n        <AD id=\"container.env\" name=\"Environment Variables\"\n            description=\"Additional container enviroment variables. Example: example_var_1=123, example_var_2=123.\" \n            type=\"String\" cardinality=\"1\"\n            required=\"false\" default=\"\" />\n            \n        <AD id=\"container.entrypoint\" name=\"Entrypoint Override\"\n            description=\"Comma separated list which is used to override the command used to start a container. Example: ./test.sh,-v,-d,--human-readable\"\n            type=\"String\" cardinality=\"1\"\n            required=\"false\" default=\"\" />\n            \n        <AD id=\"container.memory\" name=\"Memory\"\n            description=\"The maximum amount of memory the container can use in bytes. Set it as a positive integer, optionally followed by a suffix of b, k, m, g, to indicate bytes, kilobytes, megabytes, or gigabytes. \n            The minimum allowed value is platform dependent (i.e. 6m). If left empty, the memory assigned to the container will be set to a default value by the native container orchestrator.\n            This parameter only takes effect if the host system’s kernel has the corresponding cgroup v2 features enabled.\n            Please refer to the Kura documentation for more information.\"\n            type=\"String\" cardinality=\"0\"\n            required=\"false\" default=\"\" />\n            \n        <AD id=\"container.cpus\" name=\"CPUs\"\n            description=\"Specify how many CPUs a container can use. Decimal values are allowed, so if set to 1.5, the container will use at most one and a half cpu resource.\n            This parameter only takes effect if the host system’s kernel has the corresponding cgroup v2 features enabled.\n            Please refer to the Kura documentation for more information.\"\n            type=\"Float\" cardinality=\"0\"\n            required=\"false\" default=\"\" />\n\n        <AD id=\"container.gpus\" name=\"GPUs\"\n            description=\"Specify how many Nvidia GPUs a container can use. Allowed values are 'all' or an integer number. If there's no Nvidia GPU installed, leave the field empty.\"\n            type=\"String\" cardinality=\"1\"\n            required=\"false\" default=\"\" />\n                        \n        <AD id=\"container.volume\" name=\"Volume Mount\"\n            description=\"The path on the container at which you would like to mount a file or folder. Example: /path/on/host1:/path/on/container1, /path/on/host2:/path/on/container2.\" \n            type=\"String\" cardinality=\"1\"\n            required=\"false\" default=\"\" />\n            \n        <AD id=\"container.device\" name=\"Peripheral Device\"\n            description=\"Used to pass physical devices to a container. Example: /dev/gpiomem, /dev/ttyUSB0. (Generally Requires privileged mode to be enabled)\" \n            type=\"String\" cardinality=\"1\"\n            required=\"false\" default=\"\" />\n            \n        <AD id=\"container.runtime\"\n            name=\"Runtime\"\n            description=\"Specifies the fully qualified name of an alternate OCI-compatible runtime, which is used to run commands specified by the 'run' instruction. Example: 'nvidia' corresponds to '--runtime=nvidia'.\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"false\"\n            default=\"\">\n        </AD>\n            \n        <AD id=\"container.networkMode\" \n            name=\"Networking Mode\"\n            description=\"Used to specify what networking mode the container will use. Possible Drivers: bridge, none, container:{container id}, host. Note: This field is case-sensitive.\" type=\"String\" cardinality=\"0\"\n            required=\"false\" \n            default=\"\">\n         </AD>\n         \n        <AD id=\"container.loggingType\" \n            name=\"Logger Type\"\n            description=\"Used to specify what logging driver the container will use. By default, containers will log to a JSON-FILE on the gateway.\" type=\"String\" cardinality=\"0\"\n            required=\"true\" \n            default=\"DEFAULT\">\n            <Option label=\"NONE\" value=\"NONE\" />\n            <Option label=\"DEFAULT\" value=\"DEFAULT\" />\n            <Option label=\"LOCAL\" value=\"LOCAL\" />\n            <Option label=\"ETWLOGS\" value=\"ETWLOGS\" />\n            <Option label=\"JSON_FILE\" value=\"JSON_FILE\" />\n            <Option label=\"SYSLOG\" value=\"SYSLOG\" />\n            <Option label=\"JOURNALD\" value=\"JOURNALD\" />\n            <Option label=\"GELF\" value=\"GELF\" />\n            <Option label=\"FLUENTD\" value=\"FLUENTD\" />\n            <Option label=\"AWSLOGS\" value=\"AWSLOGS\" />\n            <Option label=\"DB\" value=\"DB\" />\n            <Option label=\"SPLUNK\" value=\"SPLUNK\" />\n            <Option label=\"GCPLOGS\" value=\"GCPLOGS\" />\n            <Option label=\"LOKI\" value=\"LOKI\" />\n         </AD>\n            \n       <AD id=\"container.loggerParameters\" name=\"Logger Parameters\"\n            description=\"Used to pass logger parameters to a container's logging driver. Example: max-size=10m, max-file=2. Default: max-size=10m\" type=\"String\" cardinality=\"1\"\n            required=\"false\" default=\"max-size=10m\" />\n\n        <AD id=\"container.restart.onfailure\" name=\"Restart Container On Failure\" type=\"Boolean\" cardinality=\"1\" required=\"true\" default=\"false\"\n            description=\"Automatically restart the container when it has failed. Default: false\">\n        </AD>\n\n        <AD id=\"container.identity.enabled\" name=\"Enable Identity Integration\" type=\"Boolean\" cardinality=\"1\" required=\"true\" default=\"false\"\n            description=\"Enable integration with Kura Identity Service to provide temporary credentials to the container. Default: false\">\n        </AD>\n        \n        <AD id=\"container.permissions\" name=\"Container Permissions\"\n            description=\"Comma-separated list of permissions to grant to the container when identity integration is enabled. Example: rest.assets,rest.configuration\" \n            type=\"String\" cardinality=\"1\" required=\"false\" default=\"\" />\n            \n    </OCD>\n    <Designate pid=\"org.eclipse.kura.container.provider.ContainerInstance\"\n        factoryPid=\"org.eclipse.kura.container.provider.ContainerInstance\">\n        <Object ocdref=\"org.eclipse.kura.container.provider.ContainerInstance\" />\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/build.properties",
    "content": "bin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n     Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n   \n     This program and the accompanying materials are made\n     available under the terms of the Eclipse Public License 2.0\n     which is available at https://www.eclipse.org/legal/epl-2.0/\n  \n \tSPDX-License-Identifier: EPL-2.0\n \t\n \tContributors:\n \t Eurotech\n -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n      <groupId>org.eclipse.kura</groupId>\n      <artifactId>kura</artifactId>\n      <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n  <artifactId>org.eclipse.kura.container.provider</artifactId>\n  <version>2.0.0-SNAPSHOT</version>\n  <packaging>eclipse-plugin</packaging>\n\n\n  <properties>\n    <kura.basedir>${project.basedir}/..</kura.basedir>\n    <sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n</properties>\n\n<build>\n  <plugins>\n    <plugin>\n      <groupId>org.eclipse.tycho</groupId>\n      <artifactId>tycho-packaging-plugin</artifactId>\n      <version>${tycho-version}</version>\n    </plugin>\n    <plugin>\n      <groupId>org.apache.maven.plugins</groupId>\n      <artifactId>maven-jarsigner-plugin</artifactId>\n      <version>1.4</version>\n    </plugin>\n    <plugin>\n\t  <groupId>de.dentrassi.maven</groupId>\n\t  <artifactId>osgi-dp</artifactId>\n\t  <version>0.4.1</version>\n\t\t<executions>\n\t\t\t<execution>\n\t\t\t\t<goals>\n\t\t\t\t\t<goal>build</goal>\n\t\t\t\t</goals>\n\t\t\t</execution>\n\t\t</executions>\n\t</plugin>\n  </plugins>\n  <pluginManagement>\n    <plugins>\n      <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->\n      <plugin>\n        <groupId>org.eclipse.m2e</groupId>\n        <artifactId>lifecycle-mapping</artifactId>\n        <version>1.0.0</version>\n        <configuration>\n          <lifecycleMappingMetadata>\n            <pluginExecutions>\n              <pluginExecution>\n                <pluginExecutionFilter>\n                  <groupId>\n                    org.codehaus.mojo\n                  </groupId>\n                  <artifactId>\n                    properties-maven-plugin\n                  </artifactId>\n                  <versionRange>\n                    [1.0-alpha-1,)\n                  </versionRange>\n                  <goals>\n                    <goal>read-project-properties</goal>\n                  </goals>\n                </pluginExecutionFilter>\n                <action>\n                  <ignore />\n                </action>\n              </pluginExecution>\n              <pluginExecution>\n                <pluginExecutionFilter>\n                  <groupId>\n                    org.codehaus.mojo\n                  </groupId>\n                  <artifactId>\n                    build-helper-maven-plugin\n                  </artifactId>\n                  <versionRange>\n                    [1.9,)\n                  </versionRange>\n                  <goals>\n                    <goal>\n                      regex-property\n                    </goal>\n                  </goals>\n                </pluginExecutionFilter>\n                <action>\n                  <ignore></ignore>\n                </action>\n              </pluginExecution>\n            </pluginExecutions>\n          </lifecycleMappingMetadata>\n        </configuration>\n      </plugin>\n    </plugins>\n  </pluginManagement>\n</build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/src/main/java/org/eclipse/kura/container/provider/ContainerInstance.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.container.provider;\n\nimport static java.util.Objects.isNull;\n\nimport java.net.Inet4Address;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.UnaryOperator;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ContainerOrchestrationService;\nimport org.eclipse.kura.container.orchestration.RegistryCredentials;\nimport org.eclipse.kura.container.orchestration.listener.ContainerOrchestrationServiceListener;\nimport org.eclipse.kura.container.signature.ContainerSignatureValidationService;\nimport org.eclipse.kura.container.signature.ValidationResult;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.identity.Permission;\nimport org.eclipse.kura.net.IP4Address;\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.eclipse.kura.net.NetworkService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ContainerInstance implements ConfigurableComponent, ContainerOrchestrationServiceListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(ContainerInstance.class);\n\n    private static final ValidationResult FAILED_VALIDATION = new ValidationResult();\n    private static final String CONTAINER_IDENTITY_PREFIX = \"container_\";\n    private static final int MAX_IDENTITY_NAME_LENGTH = 255;\n    private static final int MAX_IDENTITY_NAME_GENERATION_ATTEMPTS = 10;\n\n    private final ExecutorService executor = Executors.newSingleThreadExecutor();\n\n    private ContainerOrchestrationService containerOrchestrationService;\n    private Set<ContainerSignatureValidationService> availableContainerSignatureValidationService = new HashSet<>();\n    private ConfigurationService configurationService;\n    private IdentityService identityService;\n    private NetworkService networkService;\n    private PasswordStrengthVerificationService passwordStrengthVerificationService;\n    private State state = new Disabled(new ContainerInstanceOptions(Collections.emptyMap()));\n    private ContainerInstanceOptions currentOptions = null;\n    private final AtomicReference<String> currentTemporaryIdentityName = new AtomicReference<>();\n    private final AtomicReference<char[]> currentTemporaryPassword = new AtomicReference<>();\n\n    public void setContainerOrchestrationService(final ContainerOrchestrationService containerOrchestrationService) {\n        this.containerOrchestrationService = containerOrchestrationService;\n    }\n\n    public void setPasswordStrengthVerificationService(\n            final PasswordStrengthVerificationService passwordStrengthVerificationService) {\n        this.passwordStrengthVerificationService = passwordStrengthVerificationService;\n    }\n\n    public synchronized void setContainerSignatureValidationService(\n            final ContainerSignatureValidationService containerSignatureValidationService) {\n\n        logger.info(\"Container signature validation service {} added.\", containerSignatureValidationService.getClass());\n        this.availableContainerSignatureValidationService.add(containerSignatureValidationService);\n    }\n\n    public synchronized void unsetContainerSignatureValidationService(\n            final ContainerSignatureValidationService containerSignatureValidationService) {\n        logger.info(\"Container signature validation service {} removed.\",\n                containerSignatureValidationService.getClass());\n        this.availableContainerSignatureValidationService.remove(containerSignatureValidationService);\n    }\n\n    public synchronized void setConfigurationService(final ConfigurationService confService) {\n        this.configurationService = confService;\n    }\n\n    public synchronized void setIdentityService(final IdentityService identityService) {\n        this.identityService = identityService;\n    }\n\n    public synchronized void setNetworkService(final NetworkService networkService) {\n        this.networkService = networkService;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    public void activate(final Map<String, Object> properties) {\n        logger.info(\"activating...\");\n        updated(properties);\n\n        logger.info(\"activating...done\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n\n        if (isNull(properties)) {\n            throw new IllegalArgumentException(\"Properties cannot be null!\");\n        }\n\n        try {\n            ContainerInstanceOptions newOptions = new ContainerInstanceOptions(properties);\n\n            if (this.currentOptions != null && this.currentOptions.equals(newOptions)) {\n                return;\n            }\n\n            this.currentOptions = newOptions;\n\n            if (!this.currentOptions.getEnforcementDigest().isPresent()) {\n\n                logger.info(\n                        \"Container configuration doesn't include enforcement digest. Validating with Container Signature Validation service\");\n\n                if (this.currentOptions.getSignatureTrustAnchor().isPresent()) {\n\n                    ValidationResult containerSignatureValidated = validateContainerImageSignature(this.currentOptions);\n\n                    logger.info(\"Container signature validation result for {}@{}({}) - {}\",\n                            this.currentOptions.getContainerImage(),\n                            containerSignatureValidated.imageDigest().orElse(\"?\"),\n                            this.currentOptions.getContainerImageTag(),\n                            containerSignatureValidated.isSignatureValid() ? \"OK\" : \"FAIL\");\n\n                    containerSignatureValidated.imageDigest().ifPresent(digest -> {\n\n                        Map<String, Object> updatedProperties = updatePropertiesWithSignatureDigest(properties, digest);\n                        this.currentOptions = new ContainerInstanceOptions(updatedProperties);\n                        updateSnapshotWithSignatureDigest(updatedProperties);\n\n                    });\n\n                } else {\n                    logger.info(\"No trust anchor available. Signature validation skipped.\");\n                }\n\n            }\n\n            if (this.currentOptions.isEnabled()) {\n                this.containerOrchestrationService.registerListener(this);\n            } else {\n                this.containerOrchestrationService.unregisterListener(this);\n            }\n\n            updateState(s -> s.onConfigurationUpdated(this.currentOptions));\n\n        } catch (Exception e) {\n            logger.error(\"Failed to create container instance. Please check configuration of container: {}. Caused by:\",\n                    properties.get(ConfigurationService.KURA_SERVICE_PID), e);\n            updateState(State::onDisabled);\n        }\n\n    }\n\n    public void deactivate() {\n        logger.info(\"deactivate...\");\n\n        updateState(State::onDisabled);\n        cleanupTemporaryIdentity();\n\n        this.executor.shutdown();\n        this.containerOrchestrationService.unregisterListener(this);\n\n        logger.info(\"deactivate...done\");\n    }\n\n    public synchronized String getState() {\n        return this.state.getClass().getSimpleName();\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private methods\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public void onConnect() {\n        updateState(State::onConnect);\n    }\n\n    @Override\n    public void onDisconnect() {\n        //\n    }\n\n    @Override\n    public void onDisabled() {\n        updateState(State::onDisabled);\n    }\n\n    private ValidationResult validateContainerImageSignature(ContainerInstanceOptions configuration) {\n\n        if (Objects.isNull(this.availableContainerSignatureValidationService)\n                || this.availableContainerSignatureValidationService.isEmpty()) {\n            logger.warn(\"No container signature validation service available. Signature validation failed.\");\n            return FAILED_VALIDATION;\n        }\n\n        Optional<String> optTrustAnchor = configuration.getSignatureTrustAnchor();\n        if (!optTrustAnchor.isPresent() || optTrustAnchor.get().isEmpty()) {\n            logger.warn(\"No trust anchor available. Signature validation failed.\");\n            return FAILED_VALIDATION;\n        }\n\n        String trustAnchor = optTrustAnchor.get();\n        boolean verifyInTransparencyLog = configuration.getSignatureVerifyTransparencyLog();\n        Optional<RegistryCredentials> registryCredentials = configuration.getRegistryCredentials();\n\n        for (ContainerSignatureValidationService validationService : this.availableContainerSignatureValidationService) {\n            ValidationResult results = FAILED_VALIDATION;\n\n            try {\n                if (registryCredentials.isPresent()) {\n                    results = validationService.verify(configuration.getContainerImage(),\n                            configuration.getContainerImageTag(), trustAnchor, verifyInTransparencyLog,\n                            registryCredentials.get());\n                } else {\n                    results = validationService.verify(configuration.getContainerImage(),\n                            configuration.getContainerImageTag(), trustAnchor, verifyInTransparencyLog);\n                }\n            } catch (KuraException e) {\n                logger.warn(\n                        \"Error validating container signature with {}. Setting validation results as FAILED. Caused by: \",\n                        validationService.getClass(), e);\n            }\n\n            if (results.isSignatureValid()) {\n                return results;\n            }\n        }\n\n        return FAILED_VALIDATION;\n    }\n\n    private synchronized void updateState(final UnaryOperator<State> update) {\n        final State previous = this.state;\n        final State newState = update.apply(previous);\n        logger.info(\"State update: {} -> {}\", previous.getClass().getSimpleName(), newState.getClass().getSimpleName());\n\n        this.state = newState;\n    }\n\n    private Optional<ContainerInstanceDescriptor> getExistingContainerByName(final String containerName) {\n        return containerOrchestrationService.listContainerDescriptors().stream()\n                .filter(c -> c.getContainerName().equals(containerName)).findAny();\n    }\n\n    private interface State {\n\n        public default State onConnect() {\n            return this;\n        }\n\n        public default State onConfigurationUpdated(final ContainerInstanceOptions options) {\n            return this;\n        }\n\n        public default State onContainerReady(final String containerId) {\n            return this;\n        }\n\n        public default State onStartupFailure() {\n            return this;\n        }\n\n        public default State onDisabled() {\n            return this;\n        }\n\n    }\n\n    private class Disabled implements State {\n\n        private final ContainerInstanceOptions options;\n\n        public Disabled(ContainerInstanceOptions options) {\n            this.options = options;\n        }\n\n        @Override\n        public State onConfigurationUpdated(ContainerInstanceOptions options) {\n            return updateStateInternal(options);\n        }\n\n        @Override\n        public State onConnect() {\n            return updateStateInternal(this.options);\n        }\n\n        private State updateStateInternal(ContainerInstanceOptions newOptions) {\n\n            final Optional<ContainerInstanceDescriptor> existingContainer;\n            final boolean isInstanceEnabled = newOptions.isEnabled();\n\n            try {\n                existingContainer = getExistingContainerByName(\n                        newOptions.getContainerConfiguration().getContainerName());\n            } catch (final Exception e) {\n                logger.warn(\"failed to get existing container state\", e);\n                return new Disabled(newOptions);\n            }\n\n            if (existingContainer.isPresent()) {\n\n                logger.info(\"found existing container with name {}\",\n                        newOptions.getContainerConfiguration().getContainerName());\n                if (isInstanceEnabled) {\n                    return new Starting(newOptions);\n                } else {\n                    return new Created(newOptions, existingContainer.get().getContainerId()).onDisabled();\n                }\n\n            } else {\n\n                if (isInstanceEnabled) {\n                    return new Starting(newOptions);\n                } else {\n                    return new Disabled(newOptions);\n                }\n\n            }\n        }\n    }\n\n    private class Starting implements State {\n\n        private final ContainerInstanceOptions options;\n        private final Future<?> startupFuture;\n\n        public Starting(final ContainerInstanceOptions options) {\n            this.options = options;\n            this.startupFuture = ContainerInstance.this.executor.submit(() -> startMicroservice(options));\n        }\n\n        private ContainerConfiguration getContainerConfigurationWithCredentials(\n                final ContainerInstanceOptions options) {\n            ContainerConfiguration baseConfig = options.getContainerConfiguration();\n\n            final String identityName = ContainerInstance.this.currentTemporaryIdentityName.get();\n            final char[] password = ContainerInstance.this.currentTemporaryPassword.get();\n\n            if (options.isIdentityIntegrationEnabled() && password != null && identityName != null) {\n                final List<String> envVars = new ArrayList<>(baseConfig.getContainerEnvVars());\n                envVars.add(\"KURA_IDENTITY_NAME=\" + identityName);\n                envVars.add(\"KURA_IDENTITY_PASSWORD=\" + new String(password));\n\n                String restBaseUrl = buildRestBaseUrl(options);\n                envVars.add(\"KURA_REST_BASE_URL=\" + restBaseUrl);\n                logger.info(\"Setting container REST base URL to: {}\", restBaseUrl);\n\n                return ContainerConfiguration.builder().setContainerName(baseConfig.getContainerName())\n                        .setImageConfiguration(baseConfig.getImageConfiguration())\n                        .setContainerPorts(baseConfig.getContainerPorts()).setEnvVars(envVars)\n                        .setVolumes(baseConfig.getContainerVolumes())\n                        .setPrivilegedMode(baseConfig.isContainerPrivileged())\n                        .setDeviceList(baseConfig.getContainerDevices())\n                        .setFrameworkManaged(baseConfig.isFrameworkManaged())\n                        .setLoggingType(baseConfig.getContainerLoggingType())\n                        .setContainerNetowrkConfiguration(baseConfig.getContainerNetworkConfiguration())\n                        .setLoggerParameters(baseConfig.getLoggerParameters()).setEntryPoint(baseConfig.getEntryPoint())\n                        .setRestartOnFailure(baseConfig.getRestartOnFailure()).setMemory(baseConfig.getMemory())\n                        .setCpus(baseConfig.getCpus()).setGpus(baseConfig.getGpus()).setRuntime(baseConfig.getRuntime())\n                        .setEnforcementDigest(baseConfig.getEnforcementDigest()).build();\n            }\n\n            return baseConfig;\n        }\n\n        private void createTemporaryIdentityIfEnabled(final ContainerInstanceOptions options) {\n            if (options.isIdentityIntegrationEnabled() && ContainerInstance.this.identityService != null) {\n                try {\n                    cleanupTemporaryIdentity();\n\n                    final Set<Permission> permissions = options.getContainerPermissions().stream().map(Permission::new)\n                            .collect(Collectors.toSet());\n\n                    // Generate password as char[] to minimize exposure\n                    final char[] password = PasswordGenerator\n                            .generatePassword(passwordStrengthVerificationService.getPasswordStrengthRequirements());\n\n                    final String identityName = createTemporaryIdentityWithValidName(options, permissions,\n                            new String(password));\n\n                    // Store identity name and a copy of the password for env injection\n                    ContainerInstance.this.currentTemporaryIdentityName.set(identityName);\n                    ContainerInstance.this.currentTemporaryPassword.set(Arrays.copyOf(password, password.length));\n                    Arrays.fill(password, '\\0');\n\n                    logger.info(\"Created temporary identity {} for container {} with {} permissions\", identityName,\n                            options.getContainerName(), permissions.size());\n\n                } catch (KuraException e) {\n                    logger.error(\"Failed to create temporary identity for container {}\", options.getContainerName(), e);\n                    ContainerInstance.this.currentTemporaryIdentityName.set(null);\n                    clearTemporaryPassword();\n                }\n            }\n        }\n\n        private String createTemporaryIdentityWithValidName(final ContainerInstanceOptions options,\n                final Set<Permission> permissions, final String password) throws KuraException {\n\n            final String baseIdentityName = sanitizeContainerIdentityName(options.getContainerName());\n\n            for (int attempt = 0; attempt < MAX_IDENTITY_NAME_GENERATION_ATTEMPTS; attempt++) {\n                final String candidateName = buildIdentityNameCandidate(baseIdentityName, attempt);\n\n                try {\n                    final PasswordConfiguration passwordConfiguration = new PasswordConfiguration(false, true,\n                            Optional.of(password.toCharArray()), Optional.empty());\n                    final AssignedPermissions assignedPermissions = new AssignedPermissions(permissions);\n                    final IdentityConfiguration configuration = new IdentityConfiguration(candidateName,\n                            Arrays.asList(passwordConfiguration, assignedPermissions));\n\n                    ContainerInstance.this.identityService.createTemporaryIdentity(candidateName, Duration.ofDays(365));\n                    ContainerInstance.this.identityService.updateIdentityConfiguration(configuration);\n                    return candidateName;\n\n                } catch (final KuraException e) {\n                    if (!shouldRetryIdentityNameGeneration(e, attempt)) {\n                        throw e;\n                    }\n                }\n            }\n\n            throw new KuraException(KuraErrorCode.INTERNAL_ERROR,\n                    \"Unable to generate a valid temporary identity name for container \" + options.getContainerName());\n        }\n\n        private String sanitizeContainerIdentityName(final String containerName) {\n            String safeName = containerName.replaceAll(\"[^a-zA-Z0-9._]\", \"_\");\n            safeName = safeName.replaceAll(\"[._]{2,}\", \"_\");\n            safeName = trimIdentityDelimiters(safeName);\n\n            if (safeName.isEmpty()) {\n                safeName = \"auto\";\n            }\n\n            return CONTAINER_IDENTITY_PREFIX + safeName;\n        }\n\n        private String trimIdentityDelimiters(final String value) {\n            int start = 0;\n            int end = value.length();\n\n            while (start < end && isIdentityDelimiter(value.charAt(start))) {\n                start++;\n            }\n\n            while (end > start && isIdentityDelimiter(value.charAt(end - 1))) {\n                end--;\n            }\n\n            return value.substring(start, end);\n        }\n\n        private boolean isIdentityDelimiter(final char value) {\n            return value == '.' || value == '_';\n        }\n\n        private String buildIdentityNameCandidate(final String baseIdentityName, final int attempt) {\n            final String candidate = attempt == 0 ? baseIdentityName : baseIdentityName + \"_\" + attempt;\n\n            if (candidate.length() <= MAX_IDENTITY_NAME_LENGTH) {\n                return candidate;\n            }\n\n            if (attempt == 0) {\n                return candidate.substring(0, MAX_IDENTITY_NAME_LENGTH);\n            }\n\n            final String suffix = \"_\" + attempt;\n            return candidate.substring(0, MAX_IDENTITY_NAME_LENGTH - suffix.length()) + suffix;\n        }\n\n        private boolean shouldRetryIdentityNameGeneration(final KuraException e, final int attempt) {\n            if (attempt == MAX_IDENTITY_NAME_GENERATION_ATTEMPTS - 1) {\n                return false;\n            }\n\n            if (!KuraErrorCode.INVALID_PARAMETER.equals(e.getCode())) {\n                return false;\n            }\n\n            final String message = e.getMessage();\n            return message != null && (message.contains(\"Identity name\") || message.contains(\"identity with name\")\n                    || message.contains(\"already exists\"));\n        }\n\n        @Override\n        public State onConfigurationUpdated(ContainerInstanceOptions newOptions) {\n            if (newOptions.equals(this.options)) {\n                return this;\n            }\n\n            cleanupTemporaryIdentity();\n            this.startupFuture.cancel(true);\n\n            if (newOptions.isEnabled()) {\n                return new Starting(newOptions);\n            } else {\n                return new Disabled(newOptions);\n            }\n        }\n\n        @Override\n        public State onContainerReady(final String containerId) {\n            clearTemporaryPassword();\n            return new Created(this.options, containerId);\n        }\n\n        @Override\n        public State onStartupFailure() {\n            clearTemporaryPassword();\n            cleanupTemporaryIdentity();\n            return new Disabled(this.options);\n        }\n\n        @Override\n        public State onDisabled() {\n            this.startupFuture.cancel(true);\n\n            try {\n                final Optional<ContainerInstanceDescriptor> existingInstance = getExistingContainerByName(\n                        this.options.getContainerName());\n\n                if (existingInstance.isPresent()) {\n                    return new Created(this.options, existingInstance.get().getContainerId()).onDisabled();\n                }\n            } catch (final Exception e) {\n                logger.warn(\"failed to check container state\", e);\n            }\n\n            return new Disabled(this.options);\n        }\n\n        private void startMicroservice(final ContainerInstanceOptions options) {\n            boolean unlimitedRetries = options.isUnlimitedRetries();\n            int maxRetries = options.getMaxDownloadRetries();\n            int retryInterval = options.getRetryInterval();\n\n            createTemporaryIdentityIfEnabled(options);\n            final ContainerConfiguration containerConfiguration = getContainerConfigurationWithCredentials(options);\n\n            int retries = 0;\n            while ((unlimitedRetries || retries < maxRetries) && !Thread.currentThread().isInterrupted()) {\n                try {\n                    logger.info(\"Tentative number: {}\", retries);\n\n                    if (retries > 0) {\n                        Thread.sleep(retryInterval);\n                    }\n\n                    final String containerId = ContainerInstance.this.containerOrchestrationService\n                            .startContainer(containerConfiguration);\n                    updateState(s -> s.onContainerReady(containerId));\n\n                    return;\n\n                } catch (InterruptedException e) {\n                    logger.info(\"interrupted exiting\");\n                    Thread.currentThread().interrupt();\n                    return;\n                } catch (KuraException e) {\n                    logger.error(\"Error managing microservice state\", e);\n                    if (!unlimitedRetries) {\n                        retries++;\n                    }\n                }\n            }\n\n            updateState(State::onStartupFailure);\n\n            logger.warn(\"Unable to start microservice...giving up\");\n        }\n\n        private String buildRestBaseUrl(ContainerInstanceOptions options) {\n            boolean useHttps = isHttpsEnabled();\n            String protocol = useHttps ? \"https\" : \"http\";\n            String host = getHostAddressForNetworkMode(options.getContainerNetworkingMode().orElse(\"bridge\"));\n            String formattedHost = formatHostForUrl(host);\n            int port = getRestServicePort(useHttps);\n\n            return String.format(\"%s://%s:%d/services\", protocol, formattedHost, port);\n        }\n\n        private String formatHostForUrl(String host) {\n            if (host == null || host.isEmpty()) {\n                return host;\n            }\n\n            if (host.startsWith(\"[\") && host.endsWith(\"]\")) {\n                return host;\n            }\n\n            if (!host.contains(\":\")) {\n                return host;\n            }\n\n            String encodedHost = host.contains(\"%25\") ? host : host.replace(\"%\", \"%25\");\n            return \"[\" + encodedHost + \"]\";\n        }\n\n        private int getRestServicePort(boolean useHttps) {\n            int defaultPort = useHttps ? 443 : 8080;\n\n            if (ContainerInstance.this.configurationService == null) {\n                logger.debug(\"ConfigurationService not available, using default port\");\n                return defaultPort;\n            }\n\n            try {\n                ComponentConfiguration config = ContainerInstance.this.configurationService\n                        .getComponentConfiguration(\"org.eclipse.kura.http.server.manager.HttpService\");\n\n                return extractPortFromConfig(config, useHttps).orElse(defaultPort);\n            } catch (KuraException e) {\n                logger.warn(\"Failed to get REST service port configuration\", e);\n            }\n\n            return defaultPort;\n        }\n\n        private Optional<Integer> extractPortFromConfig(ComponentConfiguration config, boolean useHttps) {\n            if (config == null || config.getConfigurationProperties() == null) {\n                return Optional.empty();\n            }\n\n            Map<String, Object> properties = config.getConfigurationProperties();\n            String portKey = useHttps ? \"https.ports\" : \"http.ports\";\n            Integer[] ports = (Integer[]) properties.get(portKey);\n\n            if (ports != null && ports.length > 0) {\n                return Optional.of(ports[0]);\n            }\n\n            return Optional.empty();\n        }\n\n        private boolean isHttpsEnabled() {\n            if (ContainerInstance.this.configurationService == null) {\n                logger.debug(\"ConfigurationService not available, defaulting to HTTP\");\n                return false;\n            }\n\n            try {\n                ComponentConfiguration config = ContainerInstance.this.configurationService\n                        .getComponentConfiguration(\"org.eclipse.kura.http.server.manager.HttpService\");\n\n                if (config != null && config.getConfigurationProperties() != null) {\n                    Map<String, Object> properties = config.getConfigurationProperties();\n                    Integer[] httpsPorts = (Integer[]) properties.get(\"https.ports\");\n                    return httpsPorts != null && httpsPorts.length > 0;\n                }\n            } catch (KuraException e) {\n                logger.warn(\"Failed to check HTTPS configuration\", e);\n            }\n            return false;\n        }\n\n        private String getHostAddressForNetworkMode(String networkMode) {\n            if (\"host\".equalsIgnoreCase(networkMode)) {\n                logger.debug(\"Container using host network mode, using localhost\");\n                return \"localhost\";\n            }\n\n            return getAddressForBridgeMode();\n        }\n\n        private String getAddressForBridgeMode() {\n            String dockerGateway = getDockerBridgeGateway();\n            if (dockerGateway != null) {\n                return dockerGateway;\n            }\n\n            String hostPrimaryIp = getHostPrimaryIpAddress();\n            if (hostPrimaryIp != null) {\n                return hostPrimaryIp;\n            }\n\n            logger.warn(\"Could not determine host address, using host.docker.internal as fallback\");\n            return \"host.docker.internal\";\n        }\n\n        private String getDockerBridgeGateway() {\n            String address = getDockerBridgeViaNetworkService();\n            if (address != null) {\n                return address;\n            }\n\n            return getDockerBridgeViaJavaApi();\n        }\n\n        private String getDockerBridgeViaNetworkService() {\n            if (ContainerInstance.this.networkService == null) {\n                return null;\n            }\n\n            try {\n                for (NetInterface<?> netInterface : ContainerInstance.this.networkService.getNetworkInterfaces()) {\n                    String address = extractDockerInterfaceAddress(netInterface);\n                    if (address != null) {\n                        return address;\n                    }\n                }\n            } catch (Exception e) {\n                logger.debug(\"Failed to detect docker0 interface using NetworkService\", e);\n            }\n            return null;\n        }\n\n        private String extractDockerInterfaceAddress(NetInterface<?> netInterface) {\n            if (!\"docker0\".equals(netInterface.getName())) {\n                return null;\n            }\n\n            return getAddressNetworkService(netInterface.getNetInterfaceAddresses());\n        }\n\n        private String getAddressNetworkService(List<? extends NetInterfaceAddress> addresses) {\n            if (addresses == null) {\n                return null;\n            }\n\n            IPAddress candidate = null;\n\n            for (final NetInterfaceAddress address : addresses) {\n                candidate = address.getAddress();\n\n                if (candidate instanceof IP4Address) {\n                    break;\n                }\n            }\n\n            return candidate != null ? candidate.getHostAddress() : null;\n        }\n\n        private String getDockerBridgeViaJavaApi() {\n            try {\n                NetworkInterface dockerInterface = NetworkInterface.getByName(\"docker0\");\n                if (dockerInterface != null) {\n                    return getAddressJavaAPI(dockerInterface);\n                }\n            } catch (Exception e) {\n                logger.debug(\"Failed to detect docker0 interface using Java NetworkInterface API\", e);\n            }\n            return null;\n        }\n\n        private String getAddressJavaAPI(NetworkInterface nif) throws SocketException {\n            final Enumeration<? extends InetAddress> addresses = nif.getInetAddresses();\n\n            InetAddress candidate = null;\n\n            while (addresses.hasMoreElements()) {\n                final InetAddress addr = addresses.nextElement();\n\n                if (!isValidAddress(addr, nif)) {\n                    continue;\n                }\n\n                candidate = addr;\n\n                if (candidate instanceof Inet4Address) {\n                    break;\n                }\n            }\n\n            return candidate != null ? candidate.getHostAddress() : null;\n\n        }\n\n        private String getHostPrimaryIpAddress() {\n            try {\n                Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces();\n                if (nifs != null) {\n                    return findSuitableNetworkAddress(nifs);\n                }\n            } catch (Exception e) {\n                logger.warn(\"Failed to determine host IP address\", e);\n            }\n            return null;\n        }\n\n        private String findSuitableNetworkAddress(Enumeration<NetworkInterface> nifs) throws SocketException {\n            while (nifs.hasMoreElements()) {\n                NetworkInterface nif = nifs.nextElement();\n                String address = getAddressFromInterface(nif);\n                if (address != null) {\n                    return address;\n                }\n            }\n            return null;\n        }\n\n        private String getAddressFromInterface(NetworkInterface nif) throws SocketException {\n            if (!isValidNetworkInterface(nif)) {\n                return null;\n            }\n\n            final String result = getAddressJavaAPI(nif);\n\n            if (result != null) {\n                logger.debug(\"Using host primary IP address: {}\", result);\n            }\n\n            return result;\n\n        }\n\n        private boolean isValidNetworkInterface(NetworkInterface nif) throws SocketException {\n            return !nif.isLoopback() && nif.isUp() && !nif.isVirtual() && nif.getHardwareAddress() != null;\n        }\n\n        private boolean isValidAddress(InetAddress adr, NetworkInterface nif) throws SocketException {\n            return adr != null && !adr.isLoopbackAddress() && (nif.isPointToPoint() || !adr.isLinkLocalAddress());\n        }\n\n    }\n\n    private class Created implements State {\n\n        private final ContainerInstanceOptions options;\n        private final String containerId;\n\n        public Created(ContainerInstanceOptions options, String containerId) {\n            this.options = options;\n            this.containerId = containerId;\n        }\n\n        private void deleteContainer() {\n            try {\n                ContainerInstance.this.containerOrchestrationService.stopContainer(this.containerId);\n            } catch (Exception e) {\n                logger.error(\"Error stopping microservice {}\", this.options.getContainerName(), e);\n            }\n\n            try {\n                ContainerInstance.this.containerOrchestrationService.deleteContainer(this.containerId);\n            } catch (Exception e) {\n                logger.error(\"Error deleting microservice {}\", this.options.getContainerName(), e);\n            }\n\n            cleanupTemporaryIdentity();\n        }\n\n        @Override\n        public State onConfigurationUpdated(ContainerInstanceOptions options) {\n            if (options.equals(this.options)) {\n                return this;\n            }\n\n            deleteContainer();\n\n            if (options.isEnabled()) {\n                return new Starting(options);\n            } else {\n                return new Disabled(options);\n            }\n        }\n\n        @Override\n        public State onDisabled() {\n            deleteContainer();\n            return new Disabled(this.options);\n        }\n\n    }\n\n    private Map<String, Object> updatePropertiesWithSignatureDigest(Map<String, Object> oldProperties,\n            String enforcementDigest) {\n\n        Map<String, Object> updatedProperties = new HashMap<>(oldProperties);\n        updatedProperties.put(\"container.signature.enforcement.digest\", enforcementDigest);\n        return updatedProperties;\n\n    }\n\n    private void updateSnapshotWithSignatureDigest(Map<String, Object> properties) {\n\n        try {\n            this.configurationService.updateConfiguration(\n                    (String) properties.get(ConfigurationService.KURA_SERVICE_PID), properties, true);\n        } catch (KuraException ex) {\n            logger.error(\"Impossible to update snapshot for pid {} due to {}\",\n                    properties.get(ConfigurationService.KURA_SERVICE_PID), ex.getMessage());\n        }\n    }\n\n    private void cleanupTemporaryIdentity() {\n        final String identityName = this.currentTemporaryIdentityName.getAndSet(null);\n        clearTemporaryPassword();\n\n        if (identityName != null && this.identityService != null) {\n            try {\n                this.identityService.deleteIdentity(identityName);\n                logger.info(\"Cleaned up temporary identity: {}\", identityName);\n            } catch (KuraException e) {\n                logger.warn(\"Failed to cleanup temporary identity: {}\", identityName, e);\n            }\n        }\n    }\n\n    private void clearTemporaryPassword() {\n        final char[] password = this.currentTemporaryPassword.getAndSet(null);\n        if (password != null) {\n            Arrays.fill(password, '\\0');\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/src/main/java/org/eclipse/kura/container/provider/ContainerInstanceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.container.provider;\n\nimport static java.util.Objects.isNull;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration.ContainerConfigurationBuilder;\nimport org.eclipse.kura.container.orchestration.ContainerNetworkConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerPort;\nimport org.eclipse.kura.container.orchestration.ImageConfiguration;\nimport org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;\nimport org.eclipse.kura.container.orchestration.PortInternetProtocol;\nimport org.eclipse.kura.container.orchestration.RegistryCredentials;\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class ContainerInstanceOptions {\n\n    private static final Property<Boolean> IS_ENABLED = new Property<>(\"container.enabled\", false);\n    private static final Property<String> CONTAINER_IMAGE = new Property<>(\"container.image\", \"nginx\");\n    private static final Property<String> CONTAINER_IMAGE_TAG = new Property<>(\"container.image.tag\", \"latest\");\n    private static final Property<String> CONTAINER_NAME = new Property<>(\"kura.service.pid\", \"kura_test_container\");\n    private static final String ALT_CONTAINER_NAME_PROPERTY = \"container.name\";\n    private static final Property<String> CONTAINER_PORTS_EXTERNAL = new Property<>(\"container.ports.external\", \"\");\n    private static final Property<String> CONTAINER_PORTS_INTERNAL = new Property<>(\"container.ports.internal\", \"\");\n    private static final Property<String> CONTAINER_ENV = new Property<>(\"container.env\", \"\");\n    private static final Property<String> CONTAINER_VOLUME = new Property<>(\"container.volume\", \"\");\n    private static final Property<String> CONTAINER_DEVICE = new Property<>(\"container.device\", \"\");\n    private static final Property<Boolean> CONTAINER_PRIVILEGED = new Property<>(\"container.privileged\", false);\n    private static final Property<Integer> CONTAINER_IMAGE_DOWNLOAD_RETRIES = new Property<>(\n            \"container.image.download.retries\", 5);\n    private static final Property<Integer> CONTAINER_IMAGE_DOWNLOAD_RETRY_INTERVAL = new Property<>(\n            \"container.image.download.interval\", 30000);\n    private static final Property<String> CONTAINER_LOGGER_PARAMETERS = new Property<>(\"container.loggerParameters\",\n            \"\");\n    private static final Property<String> CONTAINER_LOGGING_TYPE = new Property<>(\"container.loggingType\", \"default\");\n    private static final Property<String> REGISTRY_URL = new Property<>(\"registry.hostname\", \"\");\n    private static final Property<String> REGISTRY_USERNAME = new Property<>(\"registry.username\", \"\");\n    private static final Property<String> REGISTRY_PASSWORD = new Property<>(\"registry.password\", \"\");\n    private static final Property<Integer> IMAGES_DOWNLOAD_TIMEOUT = new Property<>(\"container.image.download.timeout\",\n            500);\n    private static final Property<String> CONTAINER_NETWORKING_MODE = new Property<>(\"container.networkMode\", \"\");\n    private static final Property<String> CONTAINER_ENTRY_POINT = new Property<>(\"container.entrypoint\", \"\");\n    private static final Property<Boolean> CONTAINER_RESTART_FAILURE = new Property<>(\"container.restart.onfailure\",\n            false);\n    private static final Property<String> CONTAINER_MEMORY = new Property<>(\"container.memory\", \"\");\n    private static final Property<Float> CONTAINER_CPUS = new Property<>(\"container.cpus\", 1F);\n    private static final Property<String> CONTAINER_GPUS = new Property<>(\"container.gpus\", \"all\");\n    private static final Property<String> CONTAINER_RUNTIME = new Property<>(\"container.runtime\", \"\");\n\n    private static final Property<String> SIGNATURE_TRUST_ANCHOR = new Property<>(\"container.signature.trust.anchor\",\n            \"\");\n    private static final Property<Boolean> SIGNATURE_VERIFY_TLOG = new Property<>(\n            \"container.signature.verify.transparency.log\", true);\n    private static final Property<String> ENFORCEMENT_DIGEST = new Property<>(\"container.signature.enforcement.digest\",\n            \"\");\n    \n    private static final Property<Boolean> IDENTITY_INTEGRATION_ENABLED = new Property<>(\"container.identity.enabled\", false);\n    private static final Property<String> CONTAINER_PERMISSIONS = new Property<>(\"container.permissions\", \"\");\n\n    private boolean enabled;\n    private final String image;\n    private final String imageTag;\n    private final String containerName;\n    private final List<Integer> internalPorts;\n    private final List<Integer> externalPorts;\n    private final List<PortInternetProtocol> containerPortProtocol;\n    private final String containerEnv;\n    private final String containerVolumeString;\n    private final String containerDevice;\n    private final boolean privilegedMode;\n    private final Map<String, String> containerVolumes;\n    private final int maxDownloadRetries;\n    private final int retryInterval;\n    private final Map<String, String> containerLoggingParameters;\n    private final String containerLoggerType;\n    private final Optional<String> registryURL;\n    private final Optional<String> registryUsername;\n    private final Optional<String> registryPassword;\n    private final int imageDownloadTimeout;\n    private final Optional<String> containerNetworkingMode;\n    private final List<String> containerEntryPoint;\n    private final boolean restartOnFailure;\n    private final Optional<Long> containerMemory;\n    private final Optional<Float> containerCpus;\n    private final Optional<String> containerGpus;\n    private final Optional<String> containerRuntime;\n\n    private final Optional<String> signatureTrustAnchor;\n    private final Boolean signatureVerifyTransparencyLog;\n\n    private final Optional<String> enforcementDigest;\n    \n    private final boolean identityIntegrationEnabled;\n    private final List<String> containerPermissions;\n\n    public ContainerInstanceOptions(final Map<String, Object> properties) {\n        if (isNull(properties)) {\n            throw new IllegalArgumentException(\"Properties cannot be null!\");\n        }\n\n        this.enabled = IS_ENABLED.get(properties);\n        this.image = CONTAINER_IMAGE.get(properties);\n        this.imageTag = CONTAINER_IMAGE_TAG.get(properties);\n        this.containerName = resolveContainerName(properties);\n        this.internalPorts = parsePortString(CONTAINER_PORTS_INTERNAL.get(properties));\n        this.containerPortProtocol = parsePortStringProtocol(CONTAINER_PORTS_INTERNAL.get(properties));\n        this.externalPorts = parsePortString(CONTAINER_PORTS_EXTERNAL.get(properties));\n        this.containerEnv = CONTAINER_ENV.get(properties);\n        this.containerVolumeString = CONTAINER_VOLUME.get(properties);\n        this.containerVolumes = parseVolume(this.containerVolumeString);\n        this.containerDevice = CONTAINER_DEVICE.get(properties);\n        this.privilegedMode = CONTAINER_PRIVILEGED.get(properties);\n        this.maxDownloadRetries = CONTAINER_IMAGE_DOWNLOAD_RETRIES.get(properties);\n        this.retryInterval = CONTAINER_IMAGE_DOWNLOAD_RETRY_INTERVAL.get(properties);\n        this.containerLoggerType = CONTAINER_LOGGING_TYPE.get(properties);\n        this.containerLoggingParameters = parseLoggingParams(CONTAINER_LOGGER_PARAMETERS.get(properties));\n        this.registryURL = REGISTRY_URL.getOptional(properties);\n        this.registryUsername = REGISTRY_USERNAME.getOptional(properties);\n        this.registryPassword = REGISTRY_PASSWORD.getOptional(properties);\n        this.imageDownloadTimeout = IMAGES_DOWNLOAD_TIMEOUT.get(properties);\n        this.containerNetworkingMode = CONTAINER_NETWORKING_MODE.getOptional(properties);\n        this.containerEntryPoint = parseStringListSplitByComma(CONTAINER_ENTRY_POINT.get(properties));\n        this.restartOnFailure = CONTAINER_RESTART_FAILURE.get(properties);\n        this.containerMemory = parseMemoryString(CONTAINER_MEMORY.getOptional(properties));\n        this.containerCpus = CONTAINER_CPUS.getOptional(properties);\n        this.containerGpus = parseOptionalString(CONTAINER_GPUS.getOptional(properties));\n        this.containerRuntime = parseOptionalString(CONTAINER_RUNTIME.getOptional(properties));\n        this.signatureTrustAnchor = parseOptionalString(SIGNATURE_TRUST_ANCHOR.getOptional(properties));\n        this.signatureVerifyTransparencyLog = SIGNATURE_VERIFY_TLOG.get(properties);\n        this.enforcementDigest = parseOptionalString(ENFORCEMENT_DIGEST.getOptional(properties));\n        this.identityIntegrationEnabled = IDENTITY_INTEGRATION_ENABLED.get(properties);\n        this.containerPermissions = parseStringListSplitByComma(CONTAINER_PERMISSIONS.get(properties));\n    }\n\n    private String resolveContainerName(final Map<String, Object> properties) {\n        final Object altName = properties.get(ALT_CONTAINER_NAME_PROPERTY);\n        if (altName instanceof String && !((String) altName).isEmpty()) {\n            return (String) altName;\n        }\n\n        return CONTAINER_NAME.get(properties);\n    }\n\n    private Map<String, String> parseVolume(String volumeString) {\n        Map<String, String> map = new HashMap<>();\n\n        if (this.containerVolumeString.isEmpty()) {\n            return map;\n        }\n\n        for (String entry : volumeString.trim().split(\",\")) {\n            String[] tempEntry = entry.split(\":\");\n            if (tempEntry.length == 2) {\n                map.put(tempEntry[0].trim(), tempEntry[1].trim());\n            }\n        }\n\n        return map;\n    }\n\n    private Map<String, String> parseLoggingParams(String loggingString) {\n        Map<String, String> map = new HashMap<>();\n\n        if (loggingString.isEmpty()) {\n            return map;\n        }\n\n        for (String entry : loggingString.trim().split(\",\")) {\n            String[] tempEntry = entry.split(\"=\");\n            if (tempEntry.length == 2) {\n                map.put(tempEntry[0].trim(), tempEntry[1].trim());\n            }\n        }\n\n        return map;\n    }\n\n    private List<String> parseEnvVars(String containerVolumeString) {\n        List<String> envList = new LinkedList<>();\n\n        if (containerVolumeString.isEmpty()) {\n            return envList;\n        }\n\n        for (String entry : containerVolumeString.trim().split(\",\")) {\n            envList.add(entry.trim());\n        }\n\n        return envList;\n    }\n\n    private List<String> parseStringListSplitByComma(String stringToSplit) {\n\n        List<String> stringList = new LinkedList<>();\n\n        if (stringToSplit.isEmpty()) {\n            return stringList;\n        }\n\n        for (String entry : stringToSplit.trim().split(\",\")) {\n            if (entry.trim().length() > 0) {\n                stringList.add(entry.trim());\n            }\n        }\n\n        return stringList;\n    }\n\n    private Optional<Long> parseMemoryString(Optional<String> value) {\n        if (value.isPresent() && !value.get().trim().isEmpty()) {\n            String stringValue = value.get().trim();\n            long result = 0;\n            switch (stringValue.charAt(stringValue.length() - 1)) {\n            case 'b':\n                result = Long.parseLong(stringValue.substring(0, stringValue.length() - 1));\n                break;\n            case 'k':\n                result = Long.parseLong(stringValue.substring(0, stringValue.length() - 1)) * 1024L;\n                break;\n            case 'm':\n                result = Long.parseLong(stringValue.substring(0, stringValue.length() - 1)) * 1048576L;\n                break;\n            case 'g':\n                result = Long.parseLong(stringValue.substring(0, stringValue.length() - 1)) * 1073741824L;\n                break;\n            default:\n                result = Long.parseLong(stringValue);\n            }\n            return Optional.of(result);\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    private Optional<String> parseOptionalString(Optional<String> optionalString) {\n        if (optionalString.isPresent() && optionalString.get().isEmpty()) {\n            return Optional.empty();\n        } else {\n            return optionalString;\n        }\n    }\n\n    public boolean isEnabled() {\n        return this.enabled;\n    }\n\n    public String getContainerImage() {\n        return this.image;\n    }\n\n    public String getContainerImageTag() {\n        return this.imageTag;\n    }\n\n    public String getContainerName() {\n        return this.containerName;\n    }\n\n    public List<Integer> getContainerPortsInternal() {\n        return this.internalPorts;\n    }\n\n    public List<Integer> getContainerPortsExternal() {\n        return this.externalPorts;\n    }\n\n    public Map<String, String> getContainerVolumeList() {\n        return parseVolume(this.containerVolumeString);\n    }\n\n    public List<String> getContainerEnvList() {\n        return parseEnvVars(this.containerEnv);\n    }\n\n    public List<String> getContainerDeviceList() {\n        return parseStringListSplitByComma(this.containerDevice);\n    }\n\n    public boolean getPrivilegedMode() {\n        return this.privilegedMode;\n    }\n\n    public boolean isUnlimitedRetries() {\n        return this.maxDownloadRetries == 0;\n    }\n\n    public int getMaxDownloadRetries() {\n        return this.maxDownloadRetries;\n    }\n\n    public int getRetryInterval() {\n        return this.retryInterval;\n    }\n\n    public String getLoggingType() {\n        return this.containerLoggerType;\n    }\n\n    public boolean getRestartOnFailure() {\n        return this.restartOnFailure;\n    }\n\n    public Map<String, String> getLoggerParameters() {\n        return this.containerLoggingParameters;\n    }\n\n    public Optional<String> getContainerNetworkingMode() {\n        return this.containerNetworkingMode;\n    }\n\n    public Optional<RegistryCredentials> getRegistryCredentials() {\n        if (this.registryUsername.isPresent() && this.registryPassword.isPresent()) {\n            return Optional.of(new PasswordRegistryCredentials(this.registryURL, this.registryUsername.get(),\n                    new Password(this.registryPassword.get())));\n        }\n\n        return Optional.empty();\n    }\n\n    public int getImageDownloadTimeout() {\n        return this.imageDownloadTimeout;\n    }\n\n    private ContainerNetworkConfiguration buildContainerNetworkConfig() {\n        return new ContainerNetworkConfiguration.ContainerNetworkConfigurationBuilder()\n                .setNetworkMode(getContainerNetworkingMode()).build();\n    }\n\n    public List<String> getEntryPoint() {\n        return this.containerEntryPoint;\n    }\n\n    public Optional<Long> getMemory() {\n        return this.containerMemory;\n    }\n\n    public Optional<Float> getCpus() {\n        return this.containerCpus;\n    }\n\n    public Optional<String> getGpus() {\n        return this.containerGpus;\n    }\n\n    public Optional<String> getRuntime() {\n        return this.containerRuntime;\n    }\n\n    public Optional<String> getSignatureTrustAnchor() {\n        return this.signatureTrustAnchor;\n    }\n\n    public Boolean getSignatureVerifyTransparencyLog() {\n        return this.signatureVerifyTransparencyLog;\n    }\n\n    public Optional<String> getEnforcementDigest() {\n        return this.enforcementDigest;\n    }\n\n    public boolean isIdentityIntegrationEnabled() {\n        return this.identityIntegrationEnabled;\n    }\n\n    public List<String> getContainerPermissions() {\n        return this.containerPermissions;\n    }\n\n    private ImageConfiguration buildImageConfig() {\n        return new ImageConfiguration.ImageConfigurationBuilder().setImageName(this.image).setImageTag(this.imageTag)\n                .setImageDownloadTimeoutSeconds(this.imageDownloadTimeout)\n                .setRegistryCredentials(getRegistryCredentials()).build();\n    }\n\n    private ContainerConfigurationBuilder buildPortConfig(ContainerConfigurationBuilder cc) {\n        List<ContainerPort> containerPorts = new LinkedList<>();\n\n        Iterator<Integer> internalIt = this.internalPorts.iterator();\n        Iterator<Integer> externalIt = this.externalPorts.iterator();\n        Iterator<PortInternetProtocol> ipIt = this.containerPortProtocol.iterator();\n\n        while (externalIt.hasNext() && internalIt.hasNext() && ipIt.hasNext()) {\n            containerPorts.add(new ContainerPort(internalIt.next(), externalIt.next(), ipIt.next()));\n        }\n\n        cc.setContainerPorts(containerPorts);\n\n        return cc;\n    }\n\n    public ContainerConfiguration getContainerConfiguration() {\n        return buildPortConfig(ContainerConfiguration.builder()).setContainerName(getContainerName())\n                .setImageConfiguration(buildImageConfig()).setEnvVars(getContainerEnvList())\n                .setVolumes(getContainerVolumeList()).setPrivilegedMode(this.privilegedMode)\n                .setDeviceList(getContainerDeviceList()).setFrameworkManaged(true).setLoggingType(getLoggingType())\n                .setContainerNetowrkConfiguration(buildContainerNetworkConfig())\n                .setLoggerParameters(getLoggerParameters()).setEntryPoint(getEntryPoint())\n                .setRestartOnFailure(getRestartOnFailure()).setMemory(getMemory()).setCpus(getCpus()).setGpus(getGpus())\n                .setRuntime(getRuntime()).setEnforcementDigest(getEnforcementDigest()).build();\n    }\n\n    private List<Integer> parsePortString(String ports) {\n        List<Integer> tempArray = new ArrayList<>();\n        if (!ports.isEmpty()) {\n            String[] tempString = ports.trim().replace(\" \", \"\").split(\",\");\n\n            for (String element : tempString) {\n                tempArray.add(Integer.parseInt(element.trim().replace(\"-\", \"\").split(\":\")[0]));\n            }\n        }\n\n        return tempArray;\n    }\n\n    private List<PortInternetProtocol> parsePortStringProtocol(String ports) {\n        List<PortInternetProtocol> tempArray = new ArrayList<>();\n        if (!ports.isEmpty()) {\n            for (String portToken : ports.trim().replace(\" \", \"\").split(\",\")) {\n                if (portToken.split(\":\").length > 1) {\n                    switch (portToken.split(\":\")[1].toUpperCase().trim()) {\n                    case \"UDP\":\n                        tempArray.add(PortInternetProtocol.UDP);\n                        break;\n                    case \"SCTP\":\n                        tempArray.add(PortInternetProtocol.SCTP);\n                        break;\n                    default:\n                        tempArray.add(PortInternetProtocol.TCP);\n                        break;\n                    }\n                } else {\n                    // if setting is not used add TCP by default.\n                    tempArray.add(PortInternetProtocol.TCP);\n                }\n            }\n        }\n\n        return tempArray;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(containerCpus, containerDevice, containerEntryPoint, containerEnv, containerGpus,\n                containerLoggerType, containerLoggingParameters, containerMemory, containerName,\n                containerNetworkingMode, containerPermissions, containerPortProtocol, containerRuntime, containerVolumeString,\n                containerVolumes, enabled, enforcementDigest, externalPorts, identityIntegrationEnabled, image, imageDownloadTimeout, imageTag,\n                internalPorts, maxDownloadRetries, privilegedMode, registryPassword, registryURL, registryUsername,\n                restartOnFailure, retryInterval, signatureTrustAnchor, signatureVerifyTransparencyLog);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        ContainerInstanceOptions other = (ContainerInstanceOptions) obj;\n        return Objects.equals(containerCpus, other.containerCpus)\n                && Objects.equals(containerDevice, other.containerDevice)\n                && Objects.equals(containerEntryPoint, other.containerEntryPoint)\n                && Objects.equals(containerEnv, other.containerEnv)\n                && Objects.equals(containerGpus, other.containerGpus)\n                && Objects.equals(containerLoggerType, other.containerLoggerType)\n                && Objects.equals(containerLoggingParameters, other.containerLoggingParameters)\n                && Objects.equals(containerMemory, other.containerMemory)\n                && Objects.equals(containerName, other.containerName)\n                && Objects.equals(containerNetworkingMode, other.containerNetworkingMode)\n                && Objects.equals(containerPermissions, other.containerPermissions)\n                && Objects.equals(containerPortProtocol, other.containerPortProtocol)\n                && Objects.equals(containerVolumeString, other.containerVolumeString)\n                && Objects.equals(containerVolumes, other.containerVolumes) && enabled == other.enabled\n                && Objects.equals(enforcementDigest, other.enforcementDigest)\n                && Objects.equals(externalPorts, other.externalPorts) \n                && identityIntegrationEnabled == other.identityIntegrationEnabled\n                && Objects.equals(image, other.image)\n                && imageDownloadTimeout == other.imageDownloadTimeout && Objects.equals(imageTag, other.imageTag)\n                && Objects.equals(internalPorts, other.internalPorts) && maxDownloadRetries == other.maxDownloadRetries\n                && privilegedMode == other.privilegedMode && Objects.equals(registryPassword, other.registryPassword)\n                && Objects.equals(registryURL, other.registryURL)\n                && Objects.equals(registryUsername, other.registryUsername)\n                && restartOnFailure == other.restartOnFailure && retryInterval == other.retryInterval\n                && Objects.equals(containerRuntime, other.containerRuntime)\n                && Objects.equals(signatureTrustAnchor, other.signatureTrustAnchor)\n                && Objects.equals(signatureVerifyTransparencyLog, other.signatureVerifyTransparencyLog);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.container.provider/src/main/java/org/eclipse/kura/container/provider/PasswordGenerator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.container.provider;\n\nimport java.security.SecureRandom;\nimport java.util.Random;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.identity.PasswordStrengthRequirements;\n\npublic class PasswordGenerator {\n\n    private static final char[] SPECIAL_CHARS = { '!', '#', '$', '%', '&', '\\'', '(', ')', '*', '+', ',', '-', '.', '/',\n            ':', ';', '?', '@', '[', ']', '^', '_', '{', '|', '~' };\n    private static final int SPECIAL_CHARS_BOUND = SPECIAL_CHARS.length;\n    private static final int DIGITS_BOUND = SPECIAL_CHARS_BOUND + ((int) '9' - (int) '0' + 1);\n    private static final int LOWERCASE_BOUND = DIGITS_BOUND + ((int) 'z' - (int) 'a' + 1);\n    private static final int UPPERCASE_BOUND = LOWERCASE_BOUND + ((int) 'Z' - (int) 'A' + 1);\n    private static final Random RANDOM = new SecureRandom();\n\n    private PasswordGenerator() {\n    }\n\n    private static char charInRange(final Random random, final char lower, final char upper) {\n        return (char) random.nextInt((int) lower, ((int) upper) + 1);\n    }\n\n    private static int freeIndex(final Random random, final char[] values) {\n        int result;\n\n        do {\n            result = random.nextInt(values.length);\n        } while (values[result] != '\\u0000');\n\n        return result;\n    }\n\n    public static char[] generatePassword(final PasswordStrengthRequirements requirements) throws KuraException {\n        final char[] pwd = new char[Math.max(32, requirements.getPasswordMinimumLength())];\n\n        if (requirements.digitsRequired()) {\n            pwd[freeIndex(RANDOM, pwd)] = charInRange(RANDOM, '0', '9');\n        }\n\n        if (requirements.specialCharactersRequired()) {\n            pwd[freeIndex(RANDOM, pwd)] = SPECIAL_CHARS[RANDOM.nextInt(SPECIAL_CHARS.length)];\n        }\n\n        if (requirements.bothCasesRequired()) {\n            pwd[freeIndex(RANDOM, pwd)] = charInRange(RANDOM, 'A', 'Z');\n            pwd[freeIndex(RANDOM, pwd)] = charInRange(RANDOM, 'a', 'z');\n        }\n\n        for (int i = 0; i < pwd.length; i++) {\n            if (pwd[i] != '\\u0000') {\n                continue;\n            }\n\n            final int index = RANDOM.nextInt(UPPERCASE_BOUND);\n\n            char result;\n\n            if (index < SPECIAL_CHARS_BOUND) {\n                result = SPECIAL_CHARS[index];\n            } else if (index < DIGITS_BOUND) {\n                result = (char) ((int) '0' + (index - SPECIAL_CHARS_BOUND));\n            } else if (index < LOWERCASE_BOUND) {\n                result = (char) ((int) 'a' + (index - DIGITS_BOUND));\n            } else {\n                result = (char) ((int) 'A' + (index - LOWERCASE_BOUND));\n            }\n\n            pwd[i] = result;\n        }\n\n        return pwd;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core\nBundle-SymbolicName: org.eclipse.kura.core;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nExport-Package: org.eclipse.kura.core.linux.executor;version=\"1.0.0\",\n org.eclipse.kura.core.linux.util;version=\"1.2.0\",\n org.eclipse.kura.core.ssl;version=\"1.0.0\",\n org.eclipse.kura.core.util;version=\"2.0.0\";x-internal:=true\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: javax.crypto,\n javax.naming,\n javax.net,\n javax.net.ssl,\n javax.sql,\n org.apache.commons.exec;version=\"1.3.0\",\n org.apache.commons.exec.environment;version=\"1.3.0\",\n org.apache.commons.exec.util;version=\"1.3.0\",\n org.apache.commons.io;version=\"[2.4,3.0)\",\n org.apache.commons.io.output;version=\"2.4.0\",\n org.bouncycastle.asn1.x500;version=\"1.78.1\",\n org.bouncycastle.openssl.jcajce;version=\"1.78.1\",\n org.bouncycastle.operator;version=\"1.78.1\",\n org.bouncycastle.operator.jcajce;version=\"1.78.1\",\n org.bouncycastle.pkcs;version=\"1.78.1\",\n org.bouncycastle.pkcs.jcajce;version=\"1.78.1\",\n org.bouncycastle.util.io.pem;version=\"1.78.1\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.certificate;version=\"[2.0,3.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.connection.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.ssl;version=\"1.0.0\",\n org.eclipse.kura.crypto;version=\"[1.0,2.0)\",\n org.eclipse.kura.db;version=\"[2.0,2.1)\",\n org.eclipse.kura.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.message.store;version=\"[1.0,2.0)\",\n org.eclipse.kura.message.store.provider;version=\"[1.0,1.1)\",\n org.eclipse.kura.net;version=\"[2.0,3.0)\",\n org.eclipse.kura.security.keystore;version=\"[1.0,2.0)\",\n org.eclipse.kura.ssl;version=\"[2.1,2.2)\",\n org.eclipse.kura.system;version=\"[1.4,2.0)\",\n org.eclipse.kura.type;version=\"[1.1,2.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.jdbc;version=\"[1.0,2.0)\",\n org.eclipse.kura.watchdog;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.4.0\",\n org.osgi.util.tracker;version=\"1.5.0\",\n org.quartz;version=\"2.3.2\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html\nsrc.includes = about.html,\\\n               about_files/\nadditional.bundles = org.osgi.service.component.annotations,\\\n                     org.osgi.service.metatype.annotations\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<artifactId>org.eclipse.kura.core</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>biz.aQute.bnd</groupId>\n\t\t\t\t<artifactId>bnd-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/internal/linux/executor/ExecutorUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.internal.linux.executor;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.StringTokenizer;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.exec.CommandLine;\nimport org.apache.commons.exec.DefaultExecutor;\nimport org.apache.commons.exec.ExecuteException;\nimport org.apache.commons.exec.ExecuteWatchdog;\nimport org.apache.commons.exec.Executor;\nimport org.apache.commons.exec.PumpStreamHandler;\nimport org.apache.commons.exec.environment.EnvironmentUtils;\nimport org.apache.commons.io.output.NullOutputStream;\nimport org.eclipse.kura.core.linux.executor.LinuxExitStatus;\nimport org.eclipse.kura.core.linux.executor.LinuxPid;\nimport org.eclipse.kura.core.linux.executor.LinuxResultHandler;\nimport org.eclipse.kura.core.linux.executor.LinuxSignal;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.eclipse.kura.executor.Pid;\nimport org.eclipse.kura.executor.Signal;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ExecutorUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(ExecutorUtil.class);\n    private static final String COMMAND_MESSAGE = \"Command \";\n    private static final String FAILED_TO_GET_PID_MESSAGE = \"Failed to get pid for command '{}'\";\n    private static final File TEMP_DIR = new File(System.getProperty(\"java.io.tmpdir\"));\n    private static final String DEFAULT_COMMAND_USERNAME = \"kura\";\n\n    private String commandUsername;\n\n    public ExecutorUtil() {\n        this.commandUsername = DEFAULT_COMMAND_USERNAME;\n    }\n\n    public ExecutorUtil(String commandUsername) {\n        this.commandUsername = commandUsername;\n    }\n\n    public String getCommandUsername() {\n        return commandUsername;\n    }\n\n    public void setCommandUsername(String commandUsername) {\n        this.commandUsername = commandUsername;\n    }\n\n    public CommandStatus executeUnprivileged(Command command) {\n        CommandLine commandLine = buildUnprivilegedCommand(command);\n        return executeSync(command, commandLine);\n    }\n\n    public void executeUnprivileged(Command command, Consumer<CommandStatus> callback) {\n        CommandLine commandLine = buildUnprivilegedCommand(command);\n        executeAsync(command, commandLine, callback);\n    }\n\n    public CommandStatus executePrivileged(Command command) {\n        CommandLine commandLine = buildPrivilegedCommand(command);\n        return executeSync(command, commandLine);\n    }\n\n    public void executePrivileged(Command command, Consumer<CommandStatus> callback) {\n        CommandLine commandLine = buildPrivilegedCommand(command);\n        executeAsync(command, commandLine, callback);\n    }\n\n    public boolean stopUnprivileged(Pid pid, Signal signal) {\n        boolean isStopped = true;\n        if (isRunning(pid)) {\n            Command killCommand = new Command(buildKillCommand(pid, signal));\n            killCommand.setTimeout(60);\n            killCommand.setSignal(signal);\n            CommandStatus commandStatus = executeUnprivileged(killCommand);\n            isStopped = commandStatus.getExitStatus().isSuccessful();\n        }\n        return isStopped;\n    }\n\n    public boolean killUnprivileged(String[] commandLine, Signal signal) {\n        boolean isKilled = true;\n        Map<String, Pid> pids = getPids(commandLine);\n        for (Pid pid : pids.values()) {\n            isKilled &= stopUnprivileged(pid, signal);\n        }\n        return isKilled;\n    }\n\n    public boolean stopPrivileged(Pid pid, Signal signal) {\n        boolean isStopped = true;\n        if (isRunning(pid)) {\n            Command killCommand = new Command(buildKillCommand(pid, signal));\n            killCommand.setTimeout(60);\n            killCommand.setSignal(signal);\n            CommandStatus commandStatus = executePrivileged(killCommand);\n            isStopped = commandStatus.getExitStatus().isSuccessful();\n        }\n        return isStopped;\n    }\n\n    public boolean killPrivileged(String[] commandLine, Signal signal) {\n        boolean isKilled = true;\n        Map<String, Pid> pids = getPids(commandLine);\n        for (Pid pid : pids.values()) {\n            isKilled &= stopPrivileged(pid, signal);\n        }\n        return isKilled;\n    }\n\n    public boolean isRunning(Pid pid) {\n        boolean isRunning = false;\n        String pidString = ((Integer) pid.getPid()).toString();\n        String psCommand = \"ps -p \" + pidString;\n        CommandLine commandLine = CommandLine.parse(psCommand);\n        Executor executor = getExecutor();\n\n        final ByteArrayOutputStream out = createStream();\n        final ByteArrayOutputStream err = createStream();\n        final PumpStreamHandler handler = new PumpStreamHandler(out, err);\n\n        executor.setStreamHandler(handler);\n        executor.setWorkingDirectory(TEMP_DIR);\n        executor.setExitValue(0);\n        int exitValue;\n        try {\n            exitValue = executor.execute(commandLine);\n            if (exitValue == 0 && new String(out.toByteArray(), UTF_8).contains(pidString)) {\n                isRunning = true;\n            }\n        } catch (IOException e) {\n            logger.warn(\"Failed to check if process with pid {} is running\", pidString);\n        }\n        return isRunning;\n    }\n\n    public boolean isRunning(String[] commandLine) {\n        return !getPids(commandLine).isEmpty();\n    }\n\n    public Map<String, Pid> getPids(String[] commandLine) {\n        Map<String, Pid> pids = new HashMap<>();\n        CommandLine psCommandLine = new CommandLine(\"ps\");\n        psCommandLine.addArgument(\"-ax\");\n        Executor executor = getExecutor();\n\n        final ByteArrayOutputStream out = createStream();\n        final ByteArrayOutputStream err = createStream();\n        final PumpStreamHandler handler = new PumpStreamHandler(out, err);\n\n        executor.setStreamHandler(handler);\n        executor.setWorkingDirectory(TEMP_DIR);\n        executor.setExitValue(0);\n        int exitValue = 1;\n        try {\n            exitValue = executor.execute(psCommandLine);\n        } catch (IOException e) {\n            logger.debug(FAILED_TO_GET_PID_MESSAGE, commandLine, e);\n        }\n        if (exitValue == 0) {\n            pids = parsePids(out, commandLine);\n        }\n        return pids;\n    }\n\n    public static void stopStreamHandler(Executor executor) {\n        try {\n            if (executor.getStreamHandler() != null) {\n                executor.getStreamHandler().stop();\n            }\n        } catch (IOException e) {\n            logger.warn(\"Failed to stop stream handlers\", e);\n        }\n    }\n\n    private Map<String, Pid> parsePids(ByteArrayOutputStream out, String[] commandLine) {\n        Map<String, Integer> pids = new HashMap<>();\n        String pid;\n        String[] output = new String(out.toByteArray(), UTF_8).split(\"\\n\");\n        for (String line : output) {\n            StringTokenizer st = new StringTokenizer(line);\n            pid = st.nextToken();\n            st.nextElement();\n            st.nextElement();\n            st.nextElement();\n\n            // get the remainder of the line showing the command that was issued\n            line = line.substring(line.indexOf(st.nextToken()));\n            if (checkLine(line, commandLine)) {\n                pids.put(line, Integer.parseInt(pid));\n            }\n        }\n        // Sort pids in reverse order (useful when stop processes...)\n        return pids.entrySet().stream().sorted(Map.Entry.<String, Integer>comparingByValue().reversed())\n                .collect(Collectors.toMap(Map.Entry::getKey, e -> new LinuxPid(e.getValue()), (e1, e2) -> e1,\n                        LinkedHashMap::new));\n    }\n\n    private boolean checkLine(String line, String[] tokens) {\n        return Arrays.stream(tokens).parallel().allMatch(line::contains);\n    }\n\n    private CommandStatus executeSync(Command command, CommandLine commandLine) {\n        CommandStatus commandStatus = new CommandStatus(command, new LinuxExitStatus(0));\n        commandStatus.setOutputStream(command.getOutputStream());\n        commandStatus.setErrorStream(command.getErrorStream());\n        commandStatus.setInputStream(command.getInputStream());\n\n        Executor executor = configureExecutor(command);\n\n        int exitStatus = 0;\n        logger.debug(\"Executing: {}\", commandLine);\n        try {\n            Map<String, String> environment = command.getEnvironment();\n            if (environment != null && !environment.isEmpty()) {\n                Map<String, String> currentEnv = EnvironmentUtils.getProcEnvironment();\n                currentEnv.putAll(environment);\n                exitStatus = executor.execute(commandLine, currentEnv);\n            } else {\n                exitStatus = executor.execute(commandLine);\n            }\n        } catch (ExecuteException e) {\n            exitStatus = e.getExitValue();\n            logger.debug(COMMAND_MESSAGE + \" {} returned error code {}\", commandLine, exitStatus, e);\n        } catch (IOException e) {\n            exitStatus = 1;\n            logger.debug(COMMAND_MESSAGE + \" {} failed\", commandLine, e);\n        } finally {\n            stopStreamHandler(executor);\n            commandStatus.setExitStatus(new LinuxExitStatus(exitStatus));\n            commandStatus.setTimedout(executor.getWatchdog().killedProcess());\n        }\n\n        return commandStatus;\n    }\n\n    private Executor configureExecutor(Command command) {\n        Executor executor = getExecutor();\n        int timeout = command.getTimeout();\n        ExecuteWatchdog watchdog = timeout <= 0 ? new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT)\n                : new ExecuteWatchdog(timeout * 1000L);\n        executor.setWatchdog(watchdog);\n\n        OutputStream out = command.getOutputStream();\n        OutputStream err = command.getErrorStream();\n        InputStream in = command.getInputStream();\n        FlushPumpStreamHandler handler;\n        if (out != null && err != null) {\n            handler = new FlushPumpStreamHandler(out, err, in);\n        } else if (out != null) {\n            handler = new FlushPumpStreamHandler(out, new NullOutputStream(), in);\n        } else if (err != null) {\n            handler = new FlushPumpStreamHandler(new NullOutputStream(), err, in);\n        } else {\n            handler = new FlushPumpStreamHandler(new NullOutputStream(), new NullOutputStream(), in);\n        }\n        executor.setStreamHandler(handler);\n\n        String directory = command.getDirectory();\n\n        File workingDir = directory == null || directory.isEmpty() || !Files.isDirectory(Paths.get(directory))\n                ? TEMP_DIR\n                : new File(directory);\n        executor.setWorkingDirectory(workingDir);\n        return executor;\n    }\n\n    protected Executor getExecutor() {\n        return new DefaultExecutor();\n    }\n\n    private void executeAsync(Command command, CommandLine commandLine, Consumer<CommandStatus> callback) {\n        CommandStatus commandStatus = new CommandStatus(command, new LinuxExitStatus(0));\n        commandStatus.setOutputStream(command.getOutputStream());\n        commandStatus.setErrorStream(command.getErrorStream());\n        commandStatus.setInputStream(command.getInputStream());\n\n        Executor executor = configureExecutor(command);\n\n        LinuxResultHandler resultHandler = new LinuxResultHandler(callback, executor);\n        resultHandler.setStatus(commandStatus);\n\n        logger.debug(\"Executing: {}\", commandLine);\n        try {\n            Map<String, String> environment = command.getEnvironment();\n            if (environment != null && !environment.isEmpty()) {\n                Map<String, String> currentEnv = EnvironmentUtils.getProcEnvironment();\n                currentEnv.putAll(environment);\n                executor.execute(commandLine, currentEnv, resultHandler);\n            } else {\n                executor.execute(commandLine, resultHandler);\n            }\n        } catch (IOException e) {\n            stopStreamHandler(executor);\n            commandStatus.setExitStatus(new LinuxExitStatus(1));\n            logger.error(COMMAND_MESSAGE + commandLine + \" failed\", e);\n        }\n    }\n\n    private String[] buildKillCommand(Pid pid, Signal signal) {\n        Integer pidNumber = pid.getPid();\n        if (logger.isInfoEnabled()) {\n            logger.info(\"Attempting to send {} to process with pid {}\", ((LinuxSignal) signal).name(), pidNumber);\n        }\n        return new String[] { \"kill\", \"-\" + signal.getSignalNumber(), String.valueOf(pidNumber) };\n    }\n\n    private CommandLine buildUnprivilegedCommand(Command command) {\n        // Build the command as follows:\n        // su <command_user> -c \"VARS... timeout -s <signal> <timeout> <command>\"\n        // or su <command_user> c \"VARS... sh -c <command>\"\n        // The timeout command is added because the commons-exec doesn't allow to set the signal to send for killing a\n        // process after a timeout\n        CommandLine commandLine = new CommandLine(\"su\");\n        commandLine.addArgument(this.commandUsername);\n        commandLine.addArgument(\"-c\");\n\n        List<String> c = new ArrayList<>();\n        Map<String, String> env = command.getEnvironment();\n        if (env != null && !env.isEmpty()) {\n            env.entrySet().stream().forEach(entry -> c.add(entry.getKey() + \"=\" + entry.getValue()));\n        }\n\n        int timeout = command.getTimeout();\n        if (timeout != -1) {\n            c.add(\"timeout\");\n            c.add(\"-s\");\n            c.add(((LinuxSignal) command.getSignal()).name());\n            c.add(Integer.toString(timeout));\n        }\n\n        Arrays.asList(command.getCommandLine()).stream().forEach(c::add);\n        commandLine.addArgument(String.join(\" \", c), false);\n\n        return commandLine;\n    }\n\n    private CommandLine buildPrivilegedCommand(Command command) {\n        CommandLine commandLine;\n        if (command.isExecutedInAShell()) {\n            commandLine = new CommandLine(\"/bin/sh\");\n            commandLine.addArgument(\"-c\");\n            commandLine.addArgument(command.toString(), false);\n        } else {\n            String[] tokens = command.getCommandLine();\n            commandLine = new CommandLine(tokens[0]);\n            for (int i = 1; i < tokens.length; i++) {\n                commandLine.addArgument(tokens[i], false);\n            }\n        }\n        return commandLine;\n    }\n\n    protected ByteArrayOutputStream createStream() {\n        return new ByteArrayOutputStream();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/internal/linux/executor/FlushPumpStreamHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.internal.linux.executor;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.apache.commons.exec.PumpStreamHandler;\n\npublic class FlushPumpStreamHandler extends PumpStreamHandler {\n\n    public FlushPumpStreamHandler(final OutputStream out, final OutputStream err, final InputStream input) {\n        super(out, err, input);\n    }\n\n    @Override\n    protected Thread createPump(final InputStream is, final OutputStream os, final boolean closeWhenExhausted) {\n        final Thread result = new Thread(new FlushStreamPumper(is, os, closeWhenExhausted), \"Exec Stream Pumper\");\n        result.setDaemon(true);\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/internal/linux/executor/FlushStreamPumper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.internal.linux.executor;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.apache.commons.exec.StreamPumper;\nimport org.apache.commons.exec.util.DebugUtils;\n\npublic class FlushStreamPumper extends StreamPumper {\n\n    private static final int DEFAULT_SIZE = 1024;\n    private final InputStream is;\n    private final OutputStream os;\n    private final int size;\n    private boolean finished;\n    private final boolean closeWhenExhausted;\n\n    public FlushStreamPumper(InputStream is, OutputStream os, boolean closeWhenExhausted) {\n        super(is, os, closeWhenExhausted);\n        this.is = is;\n        this.os = os;\n        this.size = DEFAULT_SIZE;\n        this.closeWhenExhausted = closeWhenExhausted;\n    }\n\n    @Override\n    public void run() {\n        synchronized (this) {\n            // Just in case this object is reused in the future\n            this.finished = false;\n        }\n\n        final byte[] buf = new byte[this.size];\n\n        int length;\n        try {\n            while ((length = this.is.read(buf)) > 0) {\n                this.os.write(buf, 0, length);\n                this.os.flush();\n            }\n        } catch (final Exception e) {\n            // nothing to do\n        } finally {\n            if (this.closeWhenExhausted) {\n                try {\n                    this.os.close();\n                } catch (final IOException e) {\n                    final String msg = \"Got exception while closing exhausted output stream\";\n                    DebugUtils.handleException(msg, e);\n                }\n            }\n            synchronized (this) {\n                this.finished = true;\n                notifyAll();\n            }\n        }\n    }\n\n    @Override\n    public synchronized boolean isFinished() {\n        return this.finished;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/LinuxExitStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.linux.executor;\n\nimport org.eclipse.kura.executor.ExitStatus;\n\npublic class LinuxExitStatus implements ExitStatus {\n\n    private final int exitValue;\n\n    public LinuxExitStatus(int exitStatus) {\n        this.exitValue = exitStatus;\n    }\n\n    @Override\n    public int getExitCode() {\n        return this.exitValue;\n    }\n\n    @Override\n    public boolean isSuccessful() {\n        return this.exitValue == 0;\n    }\n\n    @Override\n    public String toString() {\n        return String.valueOf(this.exitValue);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + this.exitValue;\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        LinuxExitStatus other = (LinuxExitStatus) obj;\n        return this.exitValue == other.exitValue;\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/LinuxPid.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.linux.executor;\n\nimport org.eclipse.kura.executor.Pid;\n\npublic class LinuxPid implements Pid {\n\n    private final int pid;\n\n    public LinuxPid(int pid) {\n        this.pid = pid;\n    }\n\n    @Override\n    public int getPid() {\n        return this.pid;\n    }\n\n    @Override\n    public String toString() {\n        return String.valueOf(this.pid);\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + this.pid;\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        LinuxPid other = (LinuxPid) obj;\n        return this.pid == other.pid;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/LinuxResultHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.linux.executor;\n\nimport java.util.function.Consumer;\n\nimport org.apache.commons.exec.ExecuteException;\nimport org.apache.commons.exec.ExecuteResultHandler;\nimport org.apache.commons.exec.Executor;\nimport org.eclipse.kura.core.internal.linux.executor.ExecutorUtil;\nimport org.eclipse.kura.executor.CommandStatus;\n\npublic class LinuxResultHandler implements ExecuteResultHandler {\n\n    private static final int TIMEOUT_EXIT_VALUE = 124;\n    private static final int SIGTERM_EXIT_VALUE = 143;\n    private final Consumer<CommandStatus> callback;\n    private CommandStatus commandStatus;\n    private Executor executor;\n\n    public LinuxResultHandler(Consumer<CommandStatus> callback, Executor executor) {\n        this.callback = callback;\n        this.executor = executor;\n    }\n\n    public CommandStatus getStatus() {\n        return this.commandStatus;\n    }\n\n    public void setStatus(CommandStatus status) {\n        this.commandStatus = status;\n    }\n\n    @Override\n    public void onProcessComplete(int exitValue) {\n        ExecutorUtil.stopStreamHandler(this.executor);\n        this.commandStatus.setExitStatus(new LinuxExitStatus(exitValue));\n        this.callback.accept(this.commandStatus);\n    }\n\n    @Override\n    public void onProcessFailed(ExecuteException e) {\n        ExecutorUtil.stopStreamHandler(this.executor);\n        this.commandStatus.setExitStatus(new LinuxExitStatus(e.getExitValue()));\n        // The PrivilegedExecutorService kills a command with SIGTERM and exits with 143 when timedout; the\n        // UnprivilegedExecutorService uses timeout command that exits with 124.\n        if (e.getExitValue() == TIMEOUT_EXIT_VALUE || e.getExitValue() == SIGTERM_EXIT_VALUE) {\n            this.commandStatus.setTimedout(true);\n        }\n        this.callback.accept(this.commandStatus);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/LinuxSignal.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.linux.executor;\n\nimport org.eclipse.kura.executor.Signal;\n\npublic enum LinuxSignal implements Signal {\n\n    SIGHUP {\n\n        @Override\n        public int getSignalNumber() {\n            return 1;\n        }\n    },\n    SIGINT {\n\n        @Override\n        public int getSignalNumber() {\n            return 2;\n        }\n    },\n    SIGQUIT {\n\n        @Override\n        public int getSignalNumber() {\n            return 3;\n        }\n    },\n    SIGILL {\n\n        @Override\n        public int getSignalNumber() {\n            return 4;\n        }\n    },\n    SIGTRAP {\n\n        @Override\n        public int getSignalNumber() {\n            return 5;\n        }\n    },\n    SIGABRT {\n\n        @Override\n        public int getSignalNumber() {\n            return 6;\n        }\n    },\n    SIGBUS {\n\n        @Override\n        public int getSignalNumber() {\n            return 7;\n        }\n    },\n    SIGFPE {\n\n        @Override\n        public int getSignalNumber() {\n            return 8;\n        }\n    },\n    SIGKILL {\n\n        @Override\n        public int getSignalNumber() {\n            return 9;\n        }\n    },\n    SIGUSR1 {\n\n        @Override\n        public int getSignalNumber() {\n            return 10;\n        }\n    },\n    SIGSEGV {\n\n        @Override\n        public int getSignalNumber() {\n            return 11;\n        }\n    },\n    SIGUSR2 {\n\n        @Override\n        public int getSignalNumber() {\n            return 12;\n        }\n    },\n    SIGPIPE {\n\n        @Override\n        public int getSignalNumber() {\n            return 13;\n        }\n    },\n    SIGALRM {\n\n        @Override\n        public int getSignalNumber() {\n            return 14;\n        }\n    },\n    SIGTERM {\n\n        @Override\n        public int getSignalNumber() {\n            return 15;\n        }\n    },\n    SIGSTKFLT {\n\n        @Override\n        public int getSignalNumber() {\n            return 16;\n        }\n    },\n    SIGCHLD {\n\n        @Override\n        public int getSignalNumber() {\n            return 17;\n        }\n    },\n    SIGCONT {\n\n        @Override\n        public int getSignalNumber() {\n            return 18;\n        }\n    },\n    SIGSTOP {\n\n        @Override\n        public int getSignalNumber() {\n            return 19;\n        }\n    },\n    SIGTSTP {\n\n        @Override\n        public int getSignalNumber() {\n            return 20;\n        }\n    },\n    SIGTTIN {\n\n        @Override\n        public int getSignalNumber() {\n            return 21;\n        }\n    },\n    SIGTTOU {\n\n        @Override\n        public int getSignalNumber() {\n            return 22;\n        }\n    },\n    SIGURG {\n\n        @Override\n        public int getSignalNumber() {\n            return 23;\n        }\n    },\n    SIGXCPU {\n\n        @Override\n        public int getSignalNumber() {\n            return 24;\n        }\n    },\n    SIGXFSZ {\n\n        @Override\n        public int getSignalNumber() {\n            return 25;\n        }\n    },\n    SIGVTALRM {\n\n        @Override\n        public int getSignalNumber() {\n            return 26;\n        }\n    },\n    SIGPROF {\n\n        @Override\n        public int getSignalNumber() {\n            return 27;\n        }\n    },\n    SIGWINCH {\n\n        @Override\n        public int getSignalNumber() {\n            return 28;\n        }\n    },\n    SIGIO {\n\n        @Override\n        public int getSignalNumber() {\n            return 29;\n        }\n    },\n    SIGPWR {\n\n        @Override\n        public int getSignalNumber() {\n            return 30;\n        }\n    },\n    SIGSYS {\n\n        @Override\n        public int getSignalNumber() {\n            return 31;\n        }\n    },\n    SIGRTMIN {\n\n        @Override\n        public int getSignalNumber() {\n            return 34;\n        }\n    },\n    SIGRTMIN_PLUS_1 {\n\n        @Override\n        public int getSignalNumber() {\n            return 35;\n        }\n    },\n    SIGRTMIN_PLUS_2 {\n\n        @Override\n        public int getSignalNumber() {\n            return 36;\n        }\n    },\n    SIGRTMIN_PLUS_3 {\n\n        @Override\n        public int getSignalNumber() {\n            return 37;\n        }\n    },\n    SIGRTMIN_PLUS_4 {\n\n        @Override\n        public int getSignalNumber() {\n            return 38;\n        }\n    },\n    SIGRTMIN_PLUS_5 {\n\n        @Override\n        public int getSignalNumber() {\n            return 39;\n        }\n    },\n    SIGRTMIN_PLUS_6 {\n\n        @Override\n        public int getSignalNumber() {\n            return 40;\n        }\n    },\n    SIGRTMIN_PLUS_7 {\n\n        @Override\n        public int getSignalNumber() {\n            return 41;\n        }\n    },\n    SIGRTMIN_PLUS_8 {\n\n        @Override\n        public int getSignalNumber() {\n            return 42;\n        }\n    },\n    SIGRTMIN_PLUS_9 {\n\n        @Override\n        public int getSignalNumber() {\n            return 43;\n        }\n    },\n    SIGRTMIN_PLUS_10 {\n\n        @Override\n        public int getSignalNumber() {\n            return 44;\n        }\n    },\n    SIGRTMIN_PLUS_11 {\n\n        @Override\n        public int getSignalNumber() {\n            return 45;\n        }\n    },\n    SIGRTMIN_PLUS_12 {\n\n        @Override\n        public int getSignalNumber() {\n            return 46;\n        }\n    },\n    SIGRTMIN_PLUS_13 {\n\n        @Override\n        public int getSignalNumber() {\n            return 47;\n        }\n    },\n    SIGRTMIN_PLUS_14 {\n\n        @Override\n        public int getSignalNumber() {\n            return 48;\n        }\n    },\n    SIGRTMIN_PLUS_15 {\n\n        @Override\n        public int getSignalNumber() {\n            return 49;\n        }\n    },\n    SIGRTMAX_MINUS_14 {\n\n        @Override\n        public int getSignalNumber() {\n            return 50;\n        }\n    },\n    SIGRTMAX_MINUS_13 {\n\n        @Override\n        public int getSignalNumber() {\n            return 51;\n        }\n    },\n    SIGRTMAX_MINUS_12 {\n\n        @Override\n        public int getSignalNumber() {\n            return 52;\n        }\n    },\n    SIGRTMAX_MINUS_11 {\n\n        @Override\n        public int getSignalNumber() {\n            return 53;\n        }\n    },\n    SIGRTMAX_MINUS_10 {\n\n        @Override\n        public int getSignalNumber() {\n            return 54;\n        }\n    },\n    SIGRTMAX_MINUS_9 {\n\n        @Override\n        public int getSignalNumber() {\n            return 55;\n        }\n    },\n    SIGRTMAX_MINUS_8 {\n\n        @Override\n        public int getSignalNumber() {\n            return 56;\n        }\n    },\n    SIGRTMAX_MINUS_7 {\n\n        @Override\n        public int getSignalNumber() {\n            return 57;\n        }\n    },\n    SIGRTMAX_MINUS_6 {\n\n        @Override\n        public int getSignalNumber() {\n            return 58;\n        }\n    },\n    SIGRTMAX_MINUS_5 {\n\n        @Override\n        public int getSignalNumber() {\n            return 59;\n        }\n    },\n    SIGRTMAX_MINUS_4 {\n\n        @Override\n        public int getSignalNumber() {\n            return 60;\n        }\n    },\n    SIGRTMAX_MINUS_3 {\n\n        @Override\n        public int getSignalNumber() {\n            return 61;\n        }\n    },\n    SIGRTMAX_MINUS_2 {\n\n        @Override\n        public int getSignalNumber() {\n            return 62;\n        }\n    },\n    SIGRTMAX_MINUS_1 {\n\n        @Override\n        public int getSignalNumber() {\n            return 63;\n        }\n    },\n    SIGRTMAX {\n\n        @Override\n        public int getSignalNumber() {\n            return 64;\n        }\n    };\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/privileged/PrivilegedExecutorServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.linux.executor.privileged;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.io.Charsets;\nimport org.eclipse.kura.core.internal.linux.executor.ExecutorUtil;\nimport org.eclipse.kura.core.linux.executor.LinuxExitStatus;\nimport org.eclipse.kura.core.linux.executor.LinuxSignal;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.eclipse.kura.executor.Pid;\nimport org.eclipse.kura.executor.PrivilegedExecutorService;\nimport org.eclipse.kura.executor.Signal;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.Deactivate;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Component(immediate = true, //\n        name = \"org.eclipse.kura.executor.PrivilegedExecutorService\", //\n        property = \"service.pid=org.eclipse.kura.executor.PrivilegedExecutorService\")\npublic class PrivilegedExecutorServiceImpl implements PrivilegedExecutorService {\n\n    private static final Logger logger = LoggerFactory.getLogger(PrivilegedExecutorServiceImpl.class);\n    private static final LinuxSignal DEFAULT_SIGNAL = LinuxSignal.SIGTERM;\n\n    private ExecutorUtil executorUtil;\n\n    @SuppressWarnings(\"unused\")\n    private ComponentContext ctx;\n\n    @Activate\n    public void activate(ComponentContext componentContext) {\n        logger.info(\"activate...\");\n        this.ctx = componentContext;\n        this.executorUtil = new ExecutorUtil();\n    }\n\n    @Deactivate\n    public void deactivate(ComponentContext componentContext) {\n        logger.info(\"deactivate...\");\n        this.ctx = null;\n    }\n\n    @Override\n    public CommandStatus execute(Command command) {\n        if (command.getCommandLine() == null || command.getCommandLine().length == 0) {\n            return buildErrorStatus(command);\n        }\n        if (command.getSignal() == null) {\n            command.setSignal(DEFAULT_SIGNAL);\n        }\n        return this.executorUtil.executePrivileged(command);\n    }\n\n    @Override\n    public void execute(Command command, Consumer<CommandStatus> callback) {\n        if (command.getCommandLine() == null || command.getCommandLine().length == 0) {\n            callback.accept(buildErrorStatus(command));\n            return;\n        }\n        if (command.getSignal() == null) {\n            command.setSignal(DEFAULT_SIGNAL);\n        }\n        this.executorUtil.executePrivileged(command, callback);\n    }\n\n    @Override\n    public boolean stop(Pid pid, Signal signal) {\n        boolean isStopped = false;\n        if (signal == null) {\n            isStopped = this.executorUtil.stopPrivileged(pid, DEFAULT_SIGNAL);\n        } else {\n            isStopped = this.executorUtil.stopPrivileged(pid, signal);\n        }\n        return isStopped;\n    }\n\n    @Override\n    public boolean kill(String[] commandLine, Signal signal) {\n        boolean isKilled = false;\n        if (signal == null) {\n            isKilled = this.executorUtil.killPrivileged(commandLine, DEFAULT_SIGNAL);\n        } else {\n            isKilled = this.executorUtil.killPrivileged(commandLine, signal);\n        }\n        return isKilled;\n    }\n\n    @Override\n    public boolean isRunning(Pid pid) {\n        return this.executorUtil.isRunning(pid);\n    }\n\n    @Override\n    public boolean isRunning(String[] commandLine) {\n        return this.executorUtil.isRunning(commandLine);\n    }\n\n    @Override\n    public Map<String, Pid> getPids(String[] commandLine) {\n        return this.executorUtil.getPids(commandLine);\n    }\n\n    private CommandStatus buildErrorStatus(Command command) {\n        CommandStatus status = new CommandStatus(command, new LinuxExitStatus(1));\n        ByteArrayOutputStream err = new ByteArrayOutputStream();\n        try {\n            err.write(\"The commandLine cannot be empty or not defined\".getBytes(Charsets.UTF_8));\n        } catch (IOException e) {\n            logger.error(\"Cannot write to error stream\", e);\n        }\n        status.setErrorStream(err);\n        return status;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/unprivileged/UnprivilegedExecutorServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.linux.executor.unprivileged;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.io.Charsets;\nimport org.eclipse.kura.core.internal.linux.executor.ExecutorUtil;\nimport org.eclipse.kura.core.linux.executor.LinuxExitStatus;\nimport org.eclipse.kura.core.linux.executor.LinuxSignal;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.eclipse.kura.executor.Pid;\nimport org.eclipse.kura.executor.Signal;\nimport org.eclipse.kura.executor.UnprivilegedExecutorService;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.Deactivate;\nimport org.osgi.service.component.annotations.Reference;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Component(name = \"org.eclipse.kura.executor.UnprivilegedExecutorService\", //\n        property = \"service.pid=org.eclipse.kura.executor.UnprivilegedExecutorService\" //\n)\npublic class UnprivilegedExecutorServiceImpl implements UnprivilegedExecutorService {\n\n    private static final Logger logger = LoggerFactory.getLogger(UnprivilegedExecutorServiceImpl.class);\n    private static final LinuxSignal DEFAULT_SIGNAL = LinuxSignal.SIGTERM;\n\n    private final ExecutorUtil executorUtil;\n\n    @Activate\n    public UnprivilegedExecutorServiceImpl(final @Reference SystemService systemService) {\n        logger.info(\"activate...\");\n\n        String user = systemService.getCommandUser();\n        if (user == null || user.equals(\"unknown\")) {\n            this.executorUtil = new ExecutorUtil();\n        } else {\n            this.executorUtil = new ExecutorUtil(user);\n        }\n    }\n\n    @Deactivate\n    protected void deactivate() {\n        logger.info(\"deactivate...\");\n    }\n\n    @Override\n    public CommandStatus execute(Command command) {\n        if (command.getCommandLine() == null || command.getCommandLine().length == 0) {\n            return buildErrorStatus(command);\n        }\n        if (command.getSignal() == null) {\n            command.setSignal(DEFAULT_SIGNAL);\n        }\n        return this.executorUtil.executeUnprivileged(command);\n    }\n\n    @Override\n    public void execute(Command command, Consumer<CommandStatus> callback) {\n        if (command.getCommandLine() == null || command.getCommandLine().length == 0) {\n            callback.accept(buildErrorStatus(command));\n            return;\n        }\n        if (command.getSignal() == null) {\n            command.setSignal(DEFAULT_SIGNAL);\n        }\n        this.executorUtil.executeUnprivileged(command, callback);\n    }\n\n    @Override\n    public boolean stop(Pid pid, Signal signal) {\n        boolean isStopped = false;\n        if (signal == null) {\n            isStopped = this.executorUtil.stopUnprivileged(pid, DEFAULT_SIGNAL);\n        } else {\n            isStopped = this.executorUtil.stopUnprivileged(pid, signal);\n        }\n        return isStopped;\n    }\n\n    @Override\n    public boolean kill(String[] commandLine, Signal signal) {\n        boolean isKilled = false;\n        if (signal == null) {\n            isKilled = this.executorUtil.killUnprivileged(commandLine, DEFAULT_SIGNAL);\n        } else {\n            isKilled = this.executorUtil.killUnprivileged(commandLine, signal);\n        }\n        return isKilled;\n    }\n\n    @Override\n    public boolean isRunning(Pid pid) {\n        return this.executorUtil.isRunning(pid);\n    }\n\n    @Override\n    public boolean isRunning(String[] commandLine) {\n        return this.executorUtil.isRunning(commandLine);\n    }\n\n    @Override\n    public Map<String, Pid> getPids(String[] commandLine) {\n        return this.executorUtil.getPids(commandLine);\n    }\n\n    private CommandStatus buildErrorStatus(Command command) {\n        CommandStatus status = new CommandStatus(command, new LinuxExitStatus(1));\n        ByteArrayOutputStream err = new ByteArrayOutputStream();\n        try {\n            err.write(\"The commandLine cannot be empty or not defined\".getBytes(Charsets.UTF_8));\n        } catch (IOException e) {\n            logger.error(\"Cannot write to error stream\", e);\n        }\n        status.setErrorStream(err);\n        return status;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/util/LinuxProcessUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.linux.util;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.Arrays;\nimport java.util.StringTokenizer;\n\nimport javax.naming.OperationNotSupportedException;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.util.ProcessUtil;\nimport org.eclipse.kura.core.util.SafeProcess;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceReference;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @deprecated since {@link org.eclipse.kura.core.util} version 1.3 in favor of\n *             {@link org.eclipse.kura.executor.CommandExecutorService}\n */\n@Deprecated\npublic class LinuxProcessUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(LinuxProcessUtil.class);\n\n    public static final String RETURNED_WITH_EXIT_VALUE = \"{} returned with exit value: {}\";\n    public static final String EXECUTING = \"executing: {}\";\n    public static final String PRIVILEGED_OPERATIONS_NOT_ALLOWED = \"Privileged operations not allowed\";\n    private static final String PS_COMMAND = \"ps -ax\";\n\n    private static final String PLATFORM_INTEL_EDISON = \"intel-edison\";\n    private static Boolean usingBusybox;\n\n    protected LinuxProcessUtil() {\n        // Empty private constructor\n    }\n\n    public static int start(String command, boolean wait, boolean background)\n            throws OperationNotSupportedException, IOException {\n        if (command.contains(\"sudo\")) {\n            throw new OperationNotSupportedException(PRIVILEGED_OPERATIONS_NOT_ALLOWED);\n        }\n        SafeProcess proc = null;\n        try {\n            logger.info(EXECUTING, command);\n            proc = ProcessUtil.exec(command);\n            if (wait) {\n                waitFor(proc);\n\n                logger.info(RETURNED_WITH_EXIT_VALUE, command, proc.exitValue());\n                if (proc.exitValue() > 0) {\n                    String stdout = getInputStreamAsString(proc.getInputStream());\n                    String stderr = getInputStreamAsString(proc.getErrorStream());\n                    logger.debug(\"stdout: {}\", stdout);\n                    logger.debug(\"stderr: {}\", stderr);\n                }\n                return proc.exitValue();\n            } else {\n                return 0;\n            }\n        } finally {\n            if (!background && proc != null) {\n                ProcessUtil.destroy(proc);\n            }\n        }\n    }\n\n    public static int start(String command) throws OperationNotSupportedException, IOException {\n        return start(command, true, false);\n    }\n\n    public static int start(String command, boolean wait) throws OperationNotSupportedException, IOException {\n        return start(command, wait, false);\n    }\n\n    public static int start(String[] command, boolean wait) throws OperationNotSupportedException, IOException {\n        StringBuilder cmdBuilder = new StringBuilder();\n        for (String cmd : command) {\n            cmdBuilder.append(cmd).append(' ');\n        }\n        return start(cmdBuilder.toString(), wait);\n    }\n\n    public static int startBackground(String command, boolean wait) throws OperationNotSupportedException, IOException {\n        return start(command, wait, true);\n    }\n\n    public static ProcessStats startWithStats(String command) throws OperationNotSupportedException, IOException {\n        if (command.contains(\"sudo\")) {\n            throw new OperationNotSupportedException(PRIVILEGED_OPERATIONS_NOT_ALLOWED);\n        }\n        SafeProcess proc = null;\n        logger.info(EXECUTING, command);\n        proc = ProcessUtil.exec(command);\n\n        try {\n            int exitVal = proc.waitFor();\n            logger.debug(RETURNED_WITH_EXIT_VALUE, command, exitVal);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            logger.error(\"error executing {} command\", command, e);\n        }\n\n        return new ProcessStats(proc);\n    }\n\n    public static ProcessStats startWithStats(String[] command) throws OperationNotSupportedException, IOException {\n        if (Arrays.asList(command).stream().anyMatch(s -> s.contains(\"sudo\"))) {\n            throw new OperationNotSupportedException(PRIVILEGED_OPERATIONS_NOT_ALLOWED);\n        }\n        SafeProcess proc = null;\n        StringBuilder cmdBuilder = new StringBuilder();\n        for (String cmd : command) {\n            cmdBuilder.append(cmd).append(' ');\n        }\n        logger.debug(EXECUTING, cmdBuilder);\n        proc = ProcessUtil.exec(command);\n\n        wairFor(proc, cmdBuilder);\n\n        return new ProcessStats(proc);\n    }\n\n    public static int getPid(String command) throws IOException, InterruptedException {\n        StringTokenizer st = null;\n        String line = null;\n        String pid = null;\n        SafeProcess proc = null;\n        BufferedReader br = null;\n        try {\n\n            if (command != null && !command.isEmpty()) {\n                logger.trace(\"searching process list for {}\", command);\n\n                if (isUsingBusyBox()) {\n                    proc = ProcessUtil.exec(\"ps\");\n                } else {\n                    proc = ProcessUtil.exec(PS_COMMAND);\n                }\n                proc.waitFor();\n\n                // get the output\n                br = new BufferedReader(new InputStreamReader(proc.getInputStream()));\n                while ((line = br.readLine()) != null) {\n                    st = new StringTokenizer(line);\n                    pid = st.nextToken();\n                    st.nextElement();\n                    st.nextElement();\n                    st.nextElement();\n\n                    // get the remainder of the line showing the command that\n                    // was issued\n                    line = line.substring(line.indexOf(st.nextToken()));\n\n                    // see if the line has our command\n                    if (line.indexOf(command) >= 0) {\n                        logger.trace(\"found pid {} for command: {}\", pid, command);\n                        return Integer.parseInt(pid);\n                    }\n                }\n            }\n\n            // return failure\n            return -1;\n        } finally {\n            if (br != null) {\n                br.close();\n            }\n            if (proc != null) {\n                ProcessUtil.destroy(proc);\n            }\n        }\n    }\n\n    public static int getPid(String command, String[] tokens) throws IOException, InterruptedException {\n        StringTokenizer st = null;\n        String line = null;\n        String pid = null;\n        SafeProcess proc = null;\n        BufferedReader br = null;\n        try {\n            if (command != null && !command.isEmpty()) {\n                logger.trace(\"searching process list for {}\", command);\n                if (isUsingBusyBox()) {\n                    proc = ProcessUtil.exec(\"ps\");\n                } else {\n                    proc = ProcessUtil.exec(PS_COMMAND);\n                }\n                proc.waitFor();\n\n                // get the output\n                br = new BufferedReader(new InputStreamReader(proc.getInputStream()));\n                while ((line = br.readLine()) != null) {\n                    st = new StringTokenizer(line);\n                    pid = st.nextToken();\n                    st.nextElement();\n                    st.nextElement();\n                    st.nextElement();\n\n                    // get the remainder of the line showing the command that was issued\n                    line = line.substring(line.indexOf(st.nextToken()));\n\n                    // see if the line has our command\n                    if (line.indexOf(command) >= 0 && checkLine(line, tokens)) {\n                        logger.trace(\"found pid {} for command: {}\", pid, command);\n                        return Integer.parseInt(pid);\n                    }\n                }\n            }\n\n            return -1;\n        } finally {\n            if (br != null) {\n                br.close();\n            }\n            if (proc != null) {\n                ProcessUtil.destroy(proc);\n            }\n        }\n    }\n\n    public static int getKuraPid() throws IOException {\n\n        int pid = -1;\n        File kuraPidFile = new File(\"/var/run/kura.pid\");\n        if (kuraPidFile.exists()) {\n            try (BufferedReader br = new BufferedReader(new FileReader(kuraPidFile))) {\n                pid = Integer.parseInt(br.readLine());\n            }\n        }\n        return pid;\n    }\n\n    public static boolean stop(int pid) {\n        return stop(pid, false);\n    }\n\n    public static boolean kill(int pid) {\n        return stop(pid, true);\n    }\n\n    public static boolean killAll(String command) {\n        boolean result = false;\n        try {\n            logger.info(\"attempting to kill process {}\", command);\n            result = (start(\"killall \" + command) == 0);\n            if (result) {\n                logger.info(\"successfully killed process {}\", command);\n            } else {\n                logger.warn(\"failed to kill process {}\", command);\n            }\n        } catch (Exception e) {\n            logger.warn(\"failed to kill process {}\", command);\n        }\n        return result;\n    }\n\n    public static String getInputStreamAsString(InputStream stream) throws IOException {\n        StringBuilder sb = new StringBuilder();\n        try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {\n            char[] cbuf = new char[1024];\n            int len;\n            while ((len = br.read(cbuf)) > 0) {\n                sb.append(cbuf, 0, len);\n            }\n        }\n        return sb.toString();\n    }\n\n    /**\n     * This method takes a pid and returns a boolean that defines if the corresponding process is running or not in the\n     * host system.\n     *\n     * @param pid\n     *            integer representing the process id that has to be verified.\n     * @return true if the process in running in the system, false otherwise.\n     * @throws IOException\n     *             if an I/O or execution error occurs\n     */\n    public static boolean isProcessRunning(int pid) throws IOException {\n        boolean isRunning = false;\n\n        SafeProcess proc = null;\n        BufferedReader br = null;\n        try {\n            logger.trace(\"searching process list for pid{}\", pid);\n            if (isUsingBusyBox()) {\n                proc = ProcessUtil.exec(\"ps\");\n            } else {\n                proc = ProcessUtil.exec(PS_COMMAND);\n            }\n            proc.waitFor();\n\n            // get the output\n            br = new BufferedReader(new InputStreamReader(proc.getInputStream()));\n            String line = br.readLine(); // skip first line: PID TTY STAT TIME COMMAND\n            while ((line = br.readLine()) != null) {\n                if (parsePid(line) == pid) {\n                    isRunning = true;\n                    break;\n                }\n            }\n            return isRunning;\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new IOException(e);\n        } finally {\n            if (br != null) {\n                br.close();\n            }\n            if (proc != null) {\n                ProcessUtil.destroy(proc);\n            }\n        }\n    }\n\n    /**\n     * This method tries first to stop a process specified by the passed PID. If, aster this first step, the process is\n     * still alive, the code invokes a kill operation.\n     *\n     * @param pid\n     *            An int representing the linux pid.\n     * @throws KuraException\n     *             Thrown if one of the executed operations generate an exception.\n     * @since {@link org.eclipse.kura.core.linux.util} 1.1.0\n     */\n    public static boolean stopAndKill(int pid) throws KuraException {\n        try {\n            if (pid >= 0) {\n                logger.info(\"stopping pid={}\", pid);\n\n                boolean exists = stop(pid);\n                if (!exists) {\n                    logger.warn(\"stopping pid={} has failed\", pid);\n                } else {\n                    exists = waitProcess(pid, 500, 5000);\n                }\n\n                if (exists) {\n                    logger.info(\"killing pid={}\", pid);\n                    exists = kill(pid);\n                    if (!exists) {\n                        logger.warn(\"killing pid={} has failed\", pid);\n                    } else {\n                        exists = waitProcess(pid, 500, 5000);\n                    }\n                }\n\n                if (exists) {\n                    logger.warn(\"Failed to stop process with pid {}\", pid);\n                    return false;\n                }\n            }\n            return true;\n        } catch (Exception e) {\n            throw KuraException.internalError(e);\n        }\n    }\n\n    //\n    // Private Methods\n    //\n    private static boolean isUsingBusyBox() {\n        if (usingBusybox != null) {\n            return usingBusybox;\n        }\n\n        final BundleContext ctx = FrameworkUtil.getBundle(LinuxProcessUtil.class).getBundleContext();\n\n        final ServiceReference<SystemService> systemServiceRef = ctx.getServiceReference(SystemService.class);\n        if (systemServiceRef == null) {\n            throw new IllegalStateException(\"Unable to find instance of: \" + SystemService.class.getName());\n        }\n\n        final SystemService service = ctx.getService(systemServiceRef);\n        if (service == null) {\n            throw new IllegalStateException(\"Unable to get instance of: \" + SystemService.class.getName());\n        }\n\n        try {\n            usingBusybox = PLATFORM_INTEL_EDISON.equals(service.getPlatform());\n        } finally {\n            ctx.ungetService(systemServiceRef);\n        }\n\n        return usingBusybox;\n    }\n\n    private static boolean stop(int pid, boolean kill) {\n        boolean result = false;\n        try {\n            if (isProcessRunning(pid)) {\n                StringBuilder cmd = new StringBuilder();\n                cmd.append(\"kill \");\n                if (kill) {\n                    cmd.append(\"-9 \");\n                }\n                cmd.append(pid);\n\n                if (kill) {\n                    logger.info(\"attempting to kill -9 pid {}\", pid);\n                } else {\n                    logger.info(\"attempting to kill pid {}\", pid);\n                }\n\n                if (start(cmd.toString()) == 0) {\n                    logger.info(\"successfully killed pid {}\", pid);\n                    result = true;\n                } else {\n                    logger.warn(\"failed to kill pid {}\", pid);\n                }\n            }\n        } catch (Exception e) {\n            logger.warn(\"failed to kill pid {}\", pid);\n        }\n        return result;\n    }\n\n    private static boolean waitProcess(int pid, long poll, long timeout) {\n        boolean exists = false;\n        try {\n            final long startTime = System.currentTimeMillis();\n            long now;\n            do {\n                Thread.sleep(poll);\n                exists = isProcessRunning(pid);\n                now = System.currentTimeMillis();\n            } while (exists && now - startTime < timeout);\n        } catch (Exception e) {\n            Thread.currentThread().interrupt();\n            logger.warn(\"Failed waiting for pid {} to exit - {}\", pid, e);\n        }\n\n        return exists;\n    }\n\n    private static int parsePid(String line) {\n        StringTokenizer st = new StringTokenizer(line);\n        int processID = -1;\n        try {\n            processID = Integer.parseInt(st.nextToken());\n        } catch (NumberFormatException e) {\n            logger.warn(\"getPid() :: NumberFormatException reading PID - {}\", e);\n        }\n        return processID;\n    }\n\n    private static void waitFor(SafeProcess proc) {\n        try {\n            proc.waitFor();\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            logger.warn(\"Interrupted exception - \", e);\n        }\n    }\n\n    private static void wairFor(SafeProcess proc, StringBuilder cmdBuilder) {\n        try {\n            int exitVal = proc.waitFor();\n            logger.debug(RETURNED_WITH_EXIT_VALUE, cmdBuilder, exitVal);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            logger.error(\"error executing {} command\", cmdBuilder, e);\n        }\n    }\n\n    private static boolean checkLine(String line, String[] tokens) {\n        boolean allTokensPresent = true;\n        for (String token : tokens) {\n            if (!line.contains(token)) {\n                allTokensPresent = false;\n                break;\n            }\n        }\n        return allTokensPresent;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/util/ProcessStats.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.linux.util;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport org.eclipse.kura.core.util.SafeProcess;\n\n/**\n * @deprecated since {@link org.eclipse.kura.core.util} version 1.3\n */\n@Deprecated\npublic class ProcessStats {\n\n    private final SafeProcess process;\n\n    public ProcessStats(SafeProcess proc) {\n        this.process = proc;\n    }\n\n    public SafeProcess getProcess() {\n        return this.process;\n    }\n\n    public OutputStream getOutputStream() {\n        return this.process.getOutputStream();\n    }\n\n    public InputStream getInputStream() {\n        return this.process.getInputStream();\n    }\n\n    public InputStream getErrorStream() {\n        return this.process.getErrorStream();\n    }\n\n    public int getReturnValue() {\n        return this.process.exitValue();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/ConnectionSslOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport java.util.Arrays;\n\npublic class ConnectionSslOptions {\n\n    private final SslManagerServiceOptions sslManagerOpts;\n    private String protocol;\n    private String ciphers;\n    private String trustStore;\n    private String keyStore;\n    private char[] keyStorePassword;\n    private String alias;\n    private boolean hostnameVerification;\n\n    public ConnectionSslOptions(SslManagerServiceOptions sslManagerOpts) {\n        this.sslManagerOpts = sslManagerOpts;\n    }\n\n    public SslManagerServiceOptions getSslManagerOpts() {\n        return this.sslManagerOpts;\n    }\n\n    public String getProtocol() {\n        return this.protocol;\n    }\n\n    public void setProtocol(String protocol) {\n        if (protocol == null || \"\".equals(protocol.trim())) {\n            this.protocol = this.sslManagerOpts.getSslProtocol();\n        } else {\n            this.protocol = protocol;\n        }\n    }\n\n    public String getCiphers() {\n        return this.ciphers;\n    }\n\n    public void setCiphers(String ciphers) {\n        if (ciphers == null || \"\".equals(ciphers.trim())) {\n            this.ciphers = this.sslManagerOpts.getSslCiphers();\n        } else {\n            this.ciphers = ciphers;\n        }\n    }\n\n    public String getTrustStore() {\n        return this.trustStore;\n    }\n\n    public void setTrustStore(String trustStore) {\n\n            this.trustStore = trustStore;\n    }\n\n    public String getKeyStore() {\n        return this.keyStore;\n    }\n\n    public void setKeyStore(String keyStore) {\n            this.keyStore = keyStore;\n    }\n\n    public char[] getKeyStorePassword() {\n        return this.keyStorePassword;\n    }\n\n    public void setKeyStorePassword(char[] keyStorePassword) {\n        this.keyStorePassword = keyStorePassword;\n    }\n\n    public String getAlias() {\n        return this.alias;\n    }\n\n    public void setAlias(String alias) {\n        this.alias = alias;\n    }\n\n    public boolean getHostnameVerification() {\n        return this.hostnameVerification;\n    }\n\n    public void setHostnameVerification(boolean hostnameVerification) {\n        this.hostnameVerification = hostnameVerification;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.alias == null ? 0 : this.alias.hashCode());\n        result = prime * result + (this.ciphers == null ? 0 : this.ciphers.hashCode());\n        result = prime * result + (this.hostnameVerification ? 1231 : 1237);\n        result = prime * result + (this.keyStore == null ? 0 : this.keyStore.hashCode());\n        result = prime * result + Arrays.hashCode(this.keyStorePassword);\n        result = prime * result + (this.protocol == null ? 0 : this.protocol.hashCode());\n        result = prime * result + (this.sslManagerOpts == null ? 0 : this.sslManagerOpts.hashCode());\n        result = prime * result + (this.trustStore == null ? 0 : this.trustStore.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof ConnectionSslOptions)) {\n            return false;\n        }\n        ConnectionSslOptions other = (ConnectionSslOptions) obj;\n        if (this.alias == null) {\n            if (other.alias != null) {\n                return false;\n            }\n        } else if (!this.alias.equals(other.alias)) {\n            return false;\n        }\n        if (this.ciphers == null) {\n            if (other.ciphers != null) {\n                return false;\n            }\n        } else if (!this.ciphers.equals(other.ciphers)) {\n            return false;\n        }\n        if (this.hostnameVerification != other.hostnameVerification) {\n            return false;\n        }\n        if (this.keyStore == null) {\n            if (other.keyStore != null) {\n                return false;\n            }\n        } else if (!this.keyStore.equals(other.keyStore)) {\n            return false;\n        }\n        if (!Arrays.equals(this.keyStorePassword, other.keyStorePassword)) {\n            return false;\n        }\n        if (this.protocol == null) {\n            if (other.protocol != null) {\n                return false;\n            }\n        } else if (!this.protocol.equals(other.protocol)) {\n            return false;\n        }\n        if (this.sslManagerOpts == null) {\n            if (other.sslManagerOpts != null) {\n                return false;\n            }\n        } else if (!this.sslManagerOpts.equals(other.sslManagerOpts)) {\n            return false;\n        }\n        if (this.trustStore == null) {\n            if (other.trustStore != null) {\n                return false;\n            }\n        } else if (!this.trustStore.equals(other.trustStore)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SSLContextSPIWrapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport java.security.KeyManagementException;\nimport java.security.SecureRandom;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLContextSpi;\nimport javax.net.ssl.SSLEngine;\nimport javax.net.ssl.SSLServerSocketFactory;\nimport javax.net.ssl.SSLSessionContext;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\n\npublic class SSLContextSPIWrapper extends SSLContextSpi {\n\n    private final SSLContext wrapped;\n    private final SSLSocketFactory factory;\n\n    public SSLContextSPIWrapper(final SSLContext wrapped, final SSLSocketFactory factory) {\n        this.wrapped = wrapped;\n        this.factory = factory;\n    }\n\n    @Override\n    protected SSLEngine engineCreateSSLEngine() {\n        return this.wrapped.createSSLEngine();\n    }\n\n    @Override\n    protected SSLEngine engineCreateSSLEngine(final String arg0, final int arg1) {\n        return this.wrapped.createSSLEngine(arg0, arg1);\n    }\n\n    @Override\n    protected SSLSessionContext engineGetClientSessionContext() {\n        return this.wrapped.getClientSessionContext();\n    }\n\n    @Override\n    protected SSLSessionContext engineGetServerSessionContext() {\n        return this.wrapped.getServerSessionContext();\n    }\n\n    @Override\n    protected SSLServerSocketFactory engineGetServerSocketFactory() {\n        return this.wrapped.getServerSocketFactory();\n    }\n\n    @Override\n    protected SSLSocketFactory engineGetSocketFactory() {\n        return this.factory;\n    }\n\n    @Override\n    protected void engineInit(KeyManager[] arg0, TrustManager[] arg1, SecureRandom arg2) throws KeyManagementException {\n        this.wrapped.init(arg0, arg1, arg2);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SSLSocketFactoryWrapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.Socket;\nimport java.net.SocketException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\nimport javax.net.ssl.SSLParameters;\nimport javax.net.ssl.SSLSocket;\nimport javax.net.ssl.SSLSocketFactory;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Wrapper over the SSLSocketFactory which enforces HTTPS style hostname validation on the returned sockets.\n * http://stackoverflow.com/questions/18139448/how-should-i-do-hostname-validation-when-using-jsse\n */\npublic class SSLSocketFactoryWrapper extends SSLSocketFactory {\n\n    private static final Logger logger = LoggerFactory.getLogger(SSLSocketFactoryWrapper.class);\n\n    private final String ciphers;\n    private final Boolean hostnameVerification;\n    private final SSLSocketFactory sslsf;\n\n    public SSLSocketFactoryWrapper(SSLSocketFactory sslsf, String ciphers, Boolean hnVerify) {\n        this.sslsf = sslsf;\n        this.ciphers = ciphers;\n        this.hostnameVerification = hnVerify;\n    }\n\n    @Override\n    public String[] getDefaultCipherSuites() {\n        return this.sslsf.getDefaultCipherSuites();\n    }\n\n    @Override\n    public String[] getSupportedCipherSuites() {\n        return this.sslsf.getSupportedCipherSuites();\n    }\n\n    @Override\n    public Socket createSocket() throws IOException {\n        Socket socket = this.sslsf.createSocket();\n        updateSSLParameters(socket);\n        return socket;\n    }\n\n    @Override\n    public Socket createSocket(InetAddress host, int port) throws IOException {\n        Socket socket = this.sslsf.createSocket(host, port);\n        updateSSLParameters(socket);\n        return socket;\n    }\n\n    @Override\n    public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {\n        Socket socket = this.sslsf.createSocket(host, port, localHost, localPort);\n        updateSSLParameters(socket);\n        return socket;\n    }\n\n    @Override\n    public Socket createSocket(String host, int port) throws IOException {\n        Socket socket = this.sslsf.createSocket(host, port);\n        updateSSLParameters(socket);\n        return socket;\n    }\n\n    @Override\n    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)\n            throws IOException {\n        Socket socket = this.sslsf.createSocket(address, port, address, localPort);\n        updateSSLParameters(socket);\n        return socket;\n    }\n\n    @Override\n    public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {\n        Socket socket = this.sslsf.createSocket(s, host, port, autoClose);\n        updateSSLParameters(socket);\n        return socket;\n    }\n\n    private void updateSSLParameters(Socket socket) throws SocketException {\n        if (socket instanceof SSLSocket) {\n            SSLSocket sslSocket = (SSLSocket) socket;\n\n            SSLParameters sslParams = sslSocket.getSSLParameters();\n\n            // Do not send an SSL-2.0-compatible Client Hello.\n            ArrayList<String> protocols = new ArrayList<>(Arrays.asList(sslParams.getProtocols()));\n            protocols.remove(\"SSLv2Hello\");\n            sslParams.setProtocols(protocols.toArray(new String[protocols.size()]));\n\n            // enable server verification\n            if (this.hostnameVerification) {\n                sslParams.setEndpointIdentificationAlgorithm(\"HTTPS\");\n                logger.info(\"SSL Endpoint Identification enabled.\");\n            }\n\n            // Adjust the supported ciphers.\n            if (this.ciphers != null && !this.ciphers.isEmpty()) {\n                String[] arrCiphers = this.ciphers.split(\",\");\n                ArrayList<String> lsCiphers = new ArrayList<>();\n                for (String cipher : arrCiphers) {\n                    lsCiphers.add(cipher.trim());\n                }\n                sslParams.setCipherSuites(lsCiphers.toArray(new String[lsCiphers.size()]));\n            }\n\n            // update the socket parameters\n            sslSocket.setSSLParameters(sslParams);\n\n            // Disable the Nagle algorithm.\n            socket.setTcpNoDelay(true);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SslManagerServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport static java.util.Objects.isNull;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.Socket;\nimport java.security.GeneralSecurityException;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.KeyManagementException;\nimport java.security.KeyStore;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.Principal;\nimport java.security.PrivateKey;\nimport java.security.UnrecoverableEntryException;\nimport java.security.cert.CertPathBuilder;\nimport java.security.cert.CertStore;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.PKIXBuilderParameters;\nimport java.security.cert.PKIXParameters;\nimport java.security.cert.PKIXRevocationChecker;\nimport java.security.cert.X509CertSelector;\nimport java.security.cert.X509Certificate;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.EnumSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\nimport javax.net.ssl.CertPathTrustManagerParameters;\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\nimport javax.net.ssl.X509KeyManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraRuntimeException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.ssl.SslManagerServiceOptions.RevocationCheckMode;\nimport org.eclipse.kura.security.keystore.KeystoreChangedEvent;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.eclipse.kura.ssl.SslManagerService;\nimport org.eclipse.kura.ssl.SslServiceListener;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.ConfigurationPolicy;\nimport org.osgi.service.component.annotations.Deactivate;\nimport org.osgi.service.component.annotations.Modified;\nimport org.osgi.service.component.annotations.Reference;\nimport org.osgi.service.component.annotations.ReferenceCardinality;\nimport org.osgi.service.component.annotations.ReferencePolicy;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventConstants;\nimport org.osgi.service.event.EventHandler;\nimport org.osgi.service.metatype.annotations.Designate;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Component(name = \"org.eclipse.kura.ssl.SslManagerService\", //\n        configurationPolicy = ConfigurationPolicy.REQUIRE, //\n        immediate = true, //\n        property = { //\n                \"kura.ui.factory.hide=true\", //\n                \"kura.ui.service.hide=true\", //\n                EventConstants.EVENT_TOPIC + \"=\" + KeystoreChangedEvent.EVENT_TOPIC })\n@Designate(ocd = SslManagerServiceOCD.class, factory = true)\npublic class SslManagerServiceImpl implements SslManagerService, ConfigurableComponent, EventHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(SslManagerServiceImpl.class);\n\n    private final SslServiceListeners sslServiceListeners;\n\n    private SslManagerServiceOptions options;\n\n    private KeystoreService keystoreService;\n    private KeystoreService truststoreKeystoreService;\n\n    private Map<ConnectionSslOptions, SSLContext> sslContexts;\n\n    private Optional<String> keystoreServicePid = Optional.empty();\n    private Optional<String> truststoreKeystoreServicePid = Optional.empty();\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL)\n    public void setKeystoreService(KeystoreService keystoreService, final Map<String, Object> properties) {\n        this.keystoreService = keystoreService;\n        this.keystoreServicePid = Optional.of((String) properties.get(ConfigurationService.KURA_SERVICE_PID));\n\n        this.clearSslContexCache();\n\n        if (this.sslServiceListeners != null) {\n            // Notify listeners that service has been updated\n            this.sslServiceListeners.onConfigurationUpdated();\n        }\n    }\n\n    public void unsetKeystoreService(KeystoreService keystoreService) {\n        if (this.keystoreService == keystoreService) {\n\n            this.keystoreService = null;\n            this.keystoreServicePid = Optional.empty();\n\n            this.clearSslContexCache();\n\n            if (this.sslServiceListeners != null) {\n                // Notify listeners that service has been updated\n                this.sslServiceListeners.onConfigurationUpdated();\n            }\n        }\n    }\n\n    @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL)\n    public void setTruststoreKeystoreService(KeystoreService keystoreService, final Map<String, Object> properties) {\n        this.truststoreKeystoreService = keystoreService;\n        this.truststoreKeystoreServicePid = Optional.of((String) properties.get(ConfigurationService.KURA_SERVICE_PID));\n\n        this.clearSslContexCache();\n\n        if (this.sslServiceListeners != null) {\n            // Notify listeners that service has been updated\n            this.sslServiceListeners.onConfigurationUpdated();\n        }\n    }\n\n    public void unsetTruststoreKeystoreService(KeystoreService keystoreService) {\n        if (this.truststoreKeystoreService == keystoreService) {\n\n            this.truststoreKeystoreService = null;\n            this.truststoreKeystoreServicePid = Optional.empty();\n\n            this.clearSslContexCache();\n\n            if (this.sslServiceListeners != null) {\n                // Notify listeners that service has been updated\n                this.sslServiceListeners.onConfigurationUpdated();\n            }\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Activate\n    public SslManagerServiceImpl(ComponentContext componentContext, Map<String, Object> properties) {\n        logger.info(\"activate...\");\n\n        this.options = new SslManagerServiceOptions(properties);\n        this.sslContexts = new ConcurrentHashMap<>();\n\n        ServiceTracker<SslServiceListener, SslServiceListener> listenersTracker = new ServiceTracker<>(\n                componentContext.getBundleContext(), SslServiceListener.class, null);\n\n        // Deferred open of tracker to prevent\n        // java.lang.Exception: Recursive invocation of\n        // ServiceFactory.getService\n        // on ProSyst\n        this.sslServiceListeners = new SslServiceListeners(listenersTracker);\n    }\n\n    @Modified\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"updated...\");\n\n        this.options = new SslManagerServiceOptions(properties);\n        this.sslContexts = new ConcurrentHashMap<>();\n\n        // Notify listeners that service has been updated\n        this.sslServiceListeners.onConfigurationUpdated();\n    }\n\n    @Deactivate\n    protected void deactivate(ComponentContext componentContext) {\n        logger.info(\"deactivate...\");\n        this.sslServiceListeners.close();\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public SSLContext getSSLContext() throws GeneralSecurityException, IOException {\n        return getSSLContext(\"\");\n    }\n\n    @Override\n    public SSLContext getSSLContext(String keyAlias) throws GeneralSecurityException, IOException {\n        String protocol = this.options.getSslProtocol();\n        String ciphers = this.options.getSslCiphers();\n        boolean hostnameVerifcation = this.options.isSslHostnameVerification();\n\n        return getSSLContext(protocol, ciphers, null, null, null, keyAlias, hostnameVerifcation);\n    }\n\n    private SSLContext getSSLContext(String protocol, String ciphers, String trustStore, String keyStore,\n            char[] keyStorePassword, String keyAlias) throws GeneralSecurityException, IOException {\n        return getSSLContext(protocol, ciphers, trustStore, keyStore, keyStorePassword, keyAlias,\n                this.options.isSslHostnameVerification());\n    }\n\n    private SSLContext getSSLContext(String protocol, String ciphers, String trustStore, String keyStore,\n            char[] keyStorePassword, String keyAlias, boolean hostnameVerification)\n            throws GeneralSecurityException, IOException {\n        ConnectionSslOptions connSslOpts = new ConnectionSslOptions(this.options);\n        connSslOpts.setProtocol(protocol);\n        connSslOpts.setCiphers(ciphers);\n        connSslOpts.setTrustStore(trustStore);\n        connSslOpts.setKeyStore(keyStore);\n        connSslOpts.setKeyStorePassword(keyStorePassword);\n        connSslOpts.setAlias(keyAlias);\n        connSslOpts.setHostnameVerification(hostnameVerification);\n\n        return getSSLContextInternal(connSslOpts);\n    }\n\n    @Override\n    public SSLSocketFactory getSSLSocketFactory() throws GeneralSecurityException, IOException {\n        return getSSLContext().getSocketFactory();\n    }\n\n    @Override\n    public SSLSocketFactory getSSLSocketFactory(String keyAlias) throws GeneralSecurityException, IOException {\n        return getSSLContext(keyAlias).getSocketFactory();\n    }\n\n    @Override\n    public SSLSocketFactory getSSLSocketFactory(String protocol, String ciphers, String trustStore, String keyStore,\n            char[] keyStorePassword, String keyAlias) throws GeneralSecurityException, IOException {\n        return getSSLContext(protocol, ciphers, trustStore, keyStore, keyStorePassword, keyAlias).getSocketFactory();\n    }\n\n    @Override\n    public SSLSocketFactory getSSLSocketFactory(String protocol, String ciphers, String trustStore, String keyStore,\n            char[] keyStorePassword, String keyAlias, boolean hostnameVerification)\n            throws GeneralSecurityException, IOException {\n        return getSSLContext(protocol, ciphers, trustStore, keyStore, keyStorePassword, keyAlias, hostnameVerification)\n                .getSocketFactory();\n    }\n\n    @Override\n    public X509Certificate[] getTrustCertificates() throws GeneralSecurityException, IOException {\n        X509Certificate[] cacerts = null;\n        TrustManager[] tms = getTrustManagers();\n        for (TrustManager tm : tms) {\n            if (tm instanceof X509TrustManager) {\n                X509TrustManager x509tm = (X509TrustManager) tm;\n                cacerts = x509tm.getAcceptedIssuers();\n                break;\n            }\n        }\n        return cacerts;\n    }\n\n    @Override\n    public void installTrustCertificate(String alias, X509Certificate x509crt)\n            throws GeneralSecurityException, IOException {\n\n        if (isNull(this.keystoreService)) {\n            throw new KuraRuntimeException(KuraErrorCode.INTERNAL_ERROR); // TO DO:review\n        }\n\n        TrustedCertificateEntry trustedCertificateEntry = new TrustedCertificateEntry(x509crt);\n        try {\n            this.keystoreService.setEntry(alias, trustedCertificateEntry);\n        } catch (KuraException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public void deleteTrustCertificate(String alias) throws GeneralSecurityException, IOException {\n        try {\n            this.keystoreService.deleteEntry(alias);\n        } catch (KuraException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public void installPrivateKey(String alias, PrivateKey privateKey, char[] password, Certificate[] publicCerts)\n            throws GeneralSecurityException, IOException {\n        if (isNull(this.keystoreService)) {\n            throw new KuraRuntimeException(KuraErrorCode.INTERNAL_ERROR); // TO DO:review\n        }\n\n        PrivateKeyEntry privateKeyEntry = new PrivateKeyEntry(privateKey, publicCerts);\n\n        try {\n            this.keystoreService.setEntry(alias, privateKeyEntry);\n        } catch (KuraException e) {\n            throw new IOException(e);\n        }\n    }\n\n    private KeyStore loadKeystore(String keyStore, char[] keyStorePassword)\n            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n\n        try (InputStream tsReadStream = new FileInputStream(keyStore);) {\n            ks.load(tsReadStream, keyStorePassword);\n        }\n\n        return ks;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private methods\n    //\n    // ----------------------------------------------------------------\n\n    private SSLContext getSSLContextInternal(ConnectionSslOptions options)\n            throws GeneralSecurityException, IOException {\n        // Only create a new SSLSocketFactory instance if the configuration has\n        // changed or\n        // for a new alias.\n        // This allows for SSL Context Resumption and abbreviated SSL handshake\n        // in case of reconnects to the same host.\n        SSLContext context = this.sslContexts.get(options);\n        if (context == null) {\n            logger.info(\"Creating a new SSLSocketFactory instance\");\n\n            TrustManager[] tms = null;\n            KeyManager[] kms = null;\n            if (isNull(options.getTrustStore()) && isNull(options.getKeyStorePassword())) {\n                tms = getTrustManagers();\n                kms = getKeyManagers();\n            } else {\n                tms = getTrustManagers(options.getTrustStore(), options.getKeyStorePassword());\n                kms = getKeyManagers(options.getKeyStore(), options.getKeyStorePassword(), options.getAlias());\n            }\n\n            context = createSSLContext(options.getProtocol(), options.getCiphers(), kms, tms,\n                    options.getHostnameVerification());\n            this.sslContexts.put(options, context);\n        }\n\n        return context;\n    }\n\n    private static SSLContext createSSLContext(String protocol, String ciphers, KeyManager[] kms, TrustManager[] tms,\n            boolean hostnameVerification) throws NoSuchAlgorithmException, KeyManagementException {\n        // inits the SSL context\n        SSLContext sslCtx;\n        if (protocol == null || protocol.isEmpty()) {\n            sslCtx = SSLContext.getDefault();\n        } else {\n            sslCtx = SSLContext.getInstance(protocol);\n            sslCtx.init(kms, tms, null);\n        }\n\n        // get the SSLSocketFactory\n        final SSLSocketFactory sslSocketFactory = sslCtx.getSocketFactory();\n        final SSLSocketFactoryWrapper socketFactoryWrapper = new SSLSocketFactoryWrapper(sslSocketFactory, ciphers,\n                hostnameVerification);\n\n        // wrap it\n        return new SSLContext(new SSLContextSPIWrapper(sslCtx, socketFactoryWrapper), sslCtx.getProvider(),\n                sslCtx.getProtocol()) {\n        };\n    }\n\n    private TrustManager[] getTrustManagers() throws GeneralSecurityException, IOException {\n        TrustManager[] result = new TrustManager[0];\n        TrustManagerFactory tmf = null;\n\n        final KeystoreService ks;\n\n        if (this.truststoreKeystoreService != null) {\n            ks = truststoreKeystoreService;\n        } else if (this.keystoreService != null) {\n            ks = keystoreService;\n        } else {\n            return result;\n        }\n\n        try {\n            KeyStore ts = ks.getKeyStore();\n            tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n            initTrustManagerFactory(tmf, ts);\n            result = tmf.getTrustManagers();\n        } catch (KuraException e) {\n            throw new IOException(e);\n        }\n\n        return result;\n    }\n\n    private TrustManager[] getTrustManagers(String trustStore, char[] keyStorePassword)\n            throws IOException, GeneralSecurityException {\n        TrustManager[] result = new TrustManager[0];\n        TrustManagerFactory tmf = null;\n        if (trustStore != null) {\n\n            // Load the configured the Trust Store\n            File fTrustStore = new File(trustStore);\n            if (fTrustStore.exists()) {\n\n                KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());\n                InputStream tsReadStream = new FileInputStream(trustStore);\n                ts.load(tsReadStream, keyStorePassword);\n                tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n                initTrustManagerFactory(tmf, ts);\n                result = tmf.getTrustManagers();\n                tsReadStream.close();\n            }\n        }\n        return result;\n    }\n\n    private void initTrustManagerFactory(final TrustManagerFactory trustManagerFactory, final KeyStore keyStore)\n            throws KeyStoreException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {\n\n        if (!this.options.isSslRevocationCheckEnabled()) {\n            trustManagerFactory.init(keyStore);\n            return;\n        }\n\n        List<CertStore> certStores;\n\n        try {\n            certStores = Collections.singletonList(keystoreService.getCRLStore());\n        } catch (final Exception e) {\n            logger.warn(\"Failed to get CRL store\", e);\n            certStores = Collections.emptyList();\n        }\n\n        final EnumSet<PKIXRevocationChecker.Option> checkerOptions;\n\n        final RevocationCheckMode revocationCheckMode = options.getRevocationCheckMode();\n\n        if (revocationCheckMode == RevocationCheckMode.CRL_ONLY) {\n            checkerOptions = EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,\n                    PKIXRevocationChecker.Option.NO_FALLBACK);\n        } else if (revocationCheckMode == RevocationCheckMode.PREFER_CRL) {\n            checkerOptions = EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS);\n        } else {\n            checkerOptions = EnumSet.noneOf(PKIXRevocationChecker.Option.class);\n        }\n\n        if (this.options.isSslRevocationSoftFail()) {\n            checkerOptions.add(PKIXRevocationChecker.Option.SOFT_FAIL);\n        }\n\n        final CertPathBuilder certPathBuilder = CertPathBuilder.getInstance(\"PKIX\");\n        final PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();\n        revocationChecker.setOptions(checkerOptions);\n\n        PKIXParameters pkixParams = new PKIXBuilderParameters(keyStore, new X509CertSelector());\n        pkixParams.setRevocationEnabled(true);\n        pkixParams.setCertStores(certStores);\n        pkixParams.addCertPathChecker(revocationChecker);\n\n        trustManagerFactory.init(new CertPathTrustManagerParameters(pkixParams));\n    }\n\n    private KeyManager[] getKeyManagers() throws IOException {\n        if (isNull(this.keystoreService)) {\n            throw new KuraRuntimeException(KuraErrorCode.INTERNAL_ERROR); // TO DO:review\n        }\n        try {\n            return this.keystoreService.getKeyManagers(KeyManagerFactory.getDefaultAlgorithm())\n                    .toArray(new KeyManager[0]);\n            // TO DO: it was possible to load a keystore based on Alias. Now it is not possible.\n        } catch (KuraException e) {\n            throw new IOException(e);\n        }\n    }\n\n    private KeyManager[] getKeyManagers(String keyStore, char[] keyStorePassword, String keyAlias)\n            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,\n            UnrecoverableEntryException {\n        KeyStore ks = getKeyStore(keyStore, keyStorePassword, keyAlias);\n\n        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n        kmf.init(ks, keyStorePassword);\n\n        final List<KeyManager> matching = Arrays.stream(kmf.getKeyManagers())\n                .filter(m -> m instanceof X509KeyManager && ((X509KeyManager) m).getCertificateChain(keyAlias) != null)\n                .map(k -> new SingleAliasX509KeyManager(keyAlias, (X509KeyManager) k)).collect(Collectors.toList());\n\n        return matching.toArray(new KeyManager[matching.size()]);\n    }\n\n    private KeyStore getKeyStore(String keyStore, char[] keyStorePassword, String keyAlias)\n            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {\n\n        // Load the configured the Key Store\n        File fKeyStore = new File(keyStore);\n        if (!fKeyStore.exists() || !isKeyStoreAccessible(keyStore, keyStorePassword)) {\n            logger.warn(\"The referenced keystore does not exist or is not accessible\");\n            throw new KeyStoreException(\"The referenced keystore does not exist or is not accessible\");\n        }\n\n        try (InputStream ksReadStream = new FileInputStream(keyStore);) {\n            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n            ks.load(ksReadStream, keyStorePassword);\n\n            // if we have an alias, then build KeyStore with such key\n            if (ks.containsAlias(keyAlias) && ks.isKeyEntry(keyAlias)) {\n                return ks;\n            }\n\n            return ks;\n        }\n    }\n\n    private boolean isKeyStoreAccessible(String location, char[] password) {\n        try {\n            loadKeystore(location, password);\n            return true;\n        } catch (Exception e) {\n            return false;\n        }\n    }\n\n    private class SingleAliasX509KeyManager implements X509KeyManager {\n\n        private final String alias;\n        private final X509KeyManager wrapped;\n\n        public SingleAliasX509KeyManager(final String alias, final X509KeyManager wrapped) {\n            this.alias = alias;\n            this.wrapped = wrapped;\n        }\n\n        @Override\n        public String[] getClientAliases(String keyType, Principal[] issuers) {\n            return new String[] { this.alias };\n        }\n\n        @Override\n        public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {\n            return this.alias;\n        }\n\n        @Override\n        public String[] getServerAliases(String keyType, Principal[] issuers) {\n            return new String[] { this.alias };\n        }\n\n        @Override\n        public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {\n            return this.alias;\n        }\n\n        @Override\n        public X509Certificate[] getCertificateChain(String alias) {\n            if (this.alias.equals(alias)) {\n                return this.wrapped.getCertificateChain(alias);\n            }\n            return new X509Certificate[0];\n        }\n\n        @Override\n        public PrivateKey getPrivateKey(String alias) {\n            if (this.alias.equals(alias)) {\n                return this.wrapped.getPrivateKey(alias);\n            }\n            return null;\n        }\n    }\n\n    @Override\n    public void handleEvent(final Event event) {\n        if (!(event instanceof KeystoreChangedEvent)) {\n            return;\n        }\n\n        final KeystoreChangedEvent keystoreChangedEvent = (KeystoreChangedEvent) event;\n\n        final Optional<String> eventPid = Optional.of(keystoreChangedEvent.getSenderPid());\n\n        if (this.keystoreServicePid.equals(eventPid) || this.truststoreKeystoreServicePid.equals(eventPid)) {\n            this.clearSslContexCache();\n            this.sslServiceListeners.onConfigurationUpdated();\n        }\n    }\n\n    private void clearSslContexCache() {\n        if (sslContexts != null) {\n            this.sslContexts.clear();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SslManagerServiceOCD.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport org.osgi.service.metatype.annotations.AttributeDefinition;\nimport org.osgi.service.metatype.annotations.Icon;\nimport org.osgi.service.metatype.annotations.ObjectClassDefinition;\nimport org.osgi.service.metatype.annotations.Option;\n\n@SuppressWarnings(\"checkstyle:MethodName\")\n@ObjectClassDefinition(id = \"org.eclipse.kura.ssl.SslManagerService\", //\n        name = \"SslManagerService\", //\n        description = \"The SslManagerService is responsible to manage the configuration of the SSL connections.\", //\n        icon = @Icon(resource = \"SslManagerService\", size = 32) //\n)\npublic interface SslManagerServiceOCD {\n\n    @AttributeDefinition(name = \"ssl.default.protocol\", //\n            required = false, //\n            defaultValue = \"TLSv1.2\", //\n            description = \"The protocol to use to initialize the SSLContext. \"\n                    + \"If not specified, the default JVM SSL Context will be used.\")\n    String ssl_default_protocol();\n\n    @AttributeDefinition(name = \"ssl.hostname.verification\", //\n            required = false, //\n            defaultValue = \"true\", //\n            description = \"Enable or disable hostname verification.\")\n    Boolean ssl_hostname_verification();\n\n    @AttributeDefinition(name = \"Keystore Target Filter\", //\n            defaultValue = \"(kura.service.pid=changeme)\", //\n            description = \"Specifies, as an OSGi target filter, \"\n                    + \"the pid of the KeystoreService used to manage the SSL key store.\")\n    String KeystoreService_target();\n\n    @AttributeDefinition(name = \"Truststore Target Filter\", //\n            defaultValue = \"(kura.service.pid=changeme)\", //\n            description = \"Specifies, as an OSGi target filter, \"\n                    + \"the pid of the KeystoreService used to manage the SSL trust Store.\"\n                    + \" If the target service cannot be found, \"\n                    + \"the service configured with the Keystore Target Filter parameter will be used as truststore.\")\n    String TruststoreKeystoreService_target();\n\n    @AttributeDefinition(name = \"ssl.default.cipherSuites\", //\n            required = false, //\n            description = \"Comma-separated list of allowed ciphers.\"\n                    + \" If not specifed, all Java VM ciphers will be allowed.\")\n    String ssl_default_cipherSuites();\n\n    @AttributeDefinition(name = \"Revocation Check Enabled\", //\n            required = false, //\n            defaultValue = \"false\", //\n            description = \"If enabled, \"\n                    + \"the revocation status of server certificates will be ckeched during TLS handshake. \"\n                    + \"If a revoked certificate is detected, handshake will fail. \"\n                    + \"The revocation status will be checked using OCSP, CRLDP or the CRLs cached by the attached KeystoreService instance, \"\n                    + \"depending on the value of the Revocation Check Mode parameter. \"\n                    + \"If not enabled, revocation ckeck will not be performed.\")\n    Boolean ssl_revocation_check_enabled();\n\n    @AttributeDefinition(name = \"Revocation Check Mode\", //\n            defaultValue = \"PREFER_OCSP\", //\n            description = \"Specifies the mode for performing revocation check. \"\n                    + \"This parameter is ignored if Revocation Check Enabled is set to false.\", //\n            options = {\n                    @Option(label = \"Use OCSP first and then KeystoreService CRLs and CRLDP\", value = \"PREFER_OCSP\"), //\n                    @Option(label = \"Use KeystoreService CRLs and CRLDP first and then OCSP\", value = \"PREFER_CRL\"), //\n                    @Option(label = \"Use only KeystoreService CRLs and CRLDP\", value = \"CRL_ONLY\") //\n            })\n    String ssl_revocation_mode();\n\n    @AttributeDefinition(name = \"Revocation Soft-fail Enabled\", //\n            defaultValue = \"false\", //\n            description = \"Specifies whether the revocation soft fail is enabled or not.\" //\n                    + \" If it is not enabled and the gateway is not able to determine the revocation status of a server certificate,\"\n                    + \" for example due to a network error, the certificate will be rejected.\"\n                    + \" This parameter is ignored if Revocation Check Enabled is set to false.\")\n    Boolean ssl_revocation_soft_fail();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SslManagerServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport static java.util.Objects.isNull;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class SslManagerServiceOptions {\n\n    public enum RevocationCheckMode {\n        PREFER_OCSP,\n        PREFER_CRL,\n        CRL_ONLY\n    }\n\n    public static final String PROP_PROTOCOL = \"ssl.default.protocol\";\n    public static final String PROP_CIPHERS = \"ssl.default.cipherSuites\";\n    public static final String PROP_HN_VERIFY = \"ssl.hostname.verification\";\n\n    public static final Boolean PROP_DEFAULT_HN_VERIFY = true;\n    public static final String PROP_DEFAULT_TRUST_PASSWORD = \"changeit\";\n\n    private static final Property<String> SELECTED_SSL_PROTOCOL = new Property<>(PROP_PROTOCOL, \"\");\n    private static final Property<String> SELECTED_SSL_CIPHERS = new Property<>(PROP_CIPHERS, \"\");\n    private static final Property<Boolean> SELECTED_SSL_HN_VERIFICATION = new Property<>(PROP_HN_VERIFY,\n            PROP_DEFAULT_HN_VERIFY);\n    private static final Property<Boolean> SSL_REVOCATION_CHECK_ENABLED = new Property<>(\"ssl.revocation.check.enabled\",\n            false);\n    private static final Property<Boolean> SSL_REVOCATION_SOFT_FAIL = new Property<>(\"ssl.revocation.soft.fail\", false);\n    private static final Property<String> SSL_REVOCATION_MODE = new Property<>(\"ssl.revocation.mode\",\n            RevocationCheckMode.PREFER_OCSP.name());\n\n    private final Map<String, Object> properties;\n\n    private final String sslProtocol;\n    private final String sslCiphers;\n    private final boolean sslHNVerification;\n    private final boolean sslRevocationCheckEnabled;\n    private final RevocationCheckMode sslRevocationMode;\n    private final boolean sslRevocationSoftFail;\n\n    public SslManagerServiceOptions(Map<String, Object> properties) {\n        if (isNull(properties)) {\n            throw new IllegalArgumentException(\"SSL Options cannot be null!\");\n        }\n        this.properties = properties;\n        this.sslProtocol = SELECTED_SSL_PROTOCOL.get(properties).trim();\n        this.sslCiphers = SELECTED_SSL_CIPHERS.get(properties).trim();\n        this.sslHNVerification = SELECTED_SSL_HN_VERIFICATION.get(properties);\n        this.sslRevocationCheckEnabled = SSL_REVOCATION_CHECK_ENABLED.get(properties);\n        this.sslRevocationMode = RevocationCheckMode.valueOf(SSL_REVOCATION_MODE.get(properties));\n        this.sslRevocationSoftFail = SSL_REVOCATION_SOFT_FAIL.get(properties);\n    }\n\n    public Map<String, Object> getConfigurationProperties() {\n        return this.properties;\n    }\n\n    /**\n     * Returns the ssl.default.protocol.\n     *\n     * @return\n     */\n    public String getSslProtocol() {\n        return this.sslProtocol;\n    }\n\n    /**\n     * Returns the ssl.default.trustStore.\n     *\n     * @return\n     */\n    public String getSslCiphers() {\n        return this.sslCiphers;\n    }\n\n    /**\n     * Returns the ssl.hostname.verification\n     *\n     * @return\n     */\n    public Boolean isSslHostnameVerification() {\n        return this.sslHNVerification;\n    }\n\n    public boolean isSslRevocationCheckEnabled() {\n        return sslRevocationCheckEnabled;\n    }\n\n    public RevocationCheckMode getRevocationCheckMode() {\n        return sslRevocationMode;\n    }\n\n    public boolean isSslRevocationSoftFail() {\n        return sslRevocationSoftFail;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.properties == null ? 0 : this.properties.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (!(obj instanceof SslManagerServiceOptions)) {\n            return false;\n        }\n        SslManagerServiceOptions other = (SslManagerServiceOptions) obj;\n        if (this.properties == null) {\n            if (other.properties != null) {\n                return false;\n            }\n        } else if (!this.properties.equals(other.properties)) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SslServiceListeners.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport org.eclipse.kura.ssl.SslServiceListener;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nclass SslServiceListeners implements SslServiceListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(SslServiceListeners.class);\n\n    private final ServiceTracker<SslServiceListener, SslServiceListener> listenersTracker;\n\n    public SslServiceListeners(ServiceTracker<SslServiceListener, SslServiceListener> listenersTracker) {\n        super();\n        this.listenersTracker = listenersTracker;\n    }\n\n    @Override\n    public void onConfigurationUpdated() {\n        openOnce();\n\n        Object[] listeners = this.listenersTracker.getServices();\n        if (listeners != null && listeners.length != 0) {\n            for (Object listener : listeners) {\n                try {\n                    ((SslServiceListener) listener).onConfigurationUpdated();\n                } catch (Throwable t) {\n                    logger.error(\"Unexpected Throwable\", t);\n                }\n            }\n        }\n    }\n\n    public synchronized void close() {\n        if (this.listenersTracker.getTrackingCount() != -1) {\n            this.listenersTracker.close();\n        }\n    }\n\n    private synchronized void openOnce() {\n        if (this.listenersTracker.getTrackingCount() == -1) {\n            this.listenersTracker.open();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/GZipUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.zip.GZIPInputStream;\nimport java.util.zip.GZIPOutputStream;\n\npublic class GZipUtil {\n\n    private GZipUtil() {\n\n    }\n\n    public static boolean isCompressed(byte[] bytes) {\n        if (bytes == null || bytes.length < 2) {\n            return false;\n        } else {\n            return bytes[0] == (byte) GZIPInputStream.GZIP_MAGIC\n                    && bytes[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8);\n        }\n    }\n\n    public static byte[] compress(byte[] source) throws IOException {\n\n        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {\n            GZIPOutputStream gzipos = new GZIPOutputStream(baos);\n            gzipos.write(source);\n            gzipos.close();\n            return baos.toByteArray();\n        }\n    }\n\n    public static byte[] decompress(byte[] source) throws IOException {\n        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();\n                ByteArrayInputStream bais = new ByteArrayInputStream(source);\n                GZIPInputStream gzipis = new GZIPInputStream(bais);) {\n            int n;\n            final int maxBuf = 1024;\n            byte[] buf = new byte[maxBuf];\n            while ((n = gzipis.read(buf, 0, maxBuf)) != -1) {\n                baos.write(buf, 0, n);\n            }\n            return baos.toByteArray();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/IOUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport static java.lang.Thread.currentThread;\n\nimport java.io.IOException;\nimport java.net.URL;\n\nimport org.apache.commons.io.IOUtils;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\n\n/**\n * A few basic IO helper methods\n */\npublic final class IOUtil {\n\n    private IOUtil() {\n    }\n\n    /**\n     * Reads a resource fully and returns it as a string.\n     *\n     * @param resourceName\n     *            the name of the resource\n     * @return the content as string, or {@code null if the resource could not be found}\n     * @throws IOException\n     *             in case there is a resource but it cannot be read\n     */\n    public static String readResource(final String resourceName) throws IOException {\n        return readResource(currentThread().getContextClassLoader().getResource(resourceName));\n    }\n\n    /**\n     * Reads a resource fully and returns it as a string.\n     *\n     * @param ctx\n     *            the bundle context to use for locating the resource\n     * @param resourceName\n     *            the name of the resource\n     * @return the content as string, or {@code null if the resource could not be found}\n     * @throws IOException\n     *             in case there is a resource but it cannot be read\n     */\n    public static String readResource(BundleContext ctx, String resourceName) throws IOException {\n        return readResource(ctx.getBundle().getResource(resourceName));\n    }\n\n    /**\n     * Reads a resource fully and returns it as a string.\n     *\n     * @param bundle\n     *            the bundle to use for getting the bundle context\n     * @param resourceName\n     *            the name of the resource\n     * @return the content as string, or {@code null if the resource could not be found}\n     * @throws IOException\n     *             in case there is a resource but it cannot be read\n     */\n    public static String readResource(Bundle bundle, String resourceName) throws IOException {\n        return readResource(bundle.getResource(resourceName));\n    }\n\n    /**\n     * Reads a resource fully and returns it as a string.\n     *\n     * @param resourceUrl\n     *            the URL to read the resource from, may be {@code null}\n     * @return the content as string, or {@code null if the resource could not be found}\n     * @throws IOException\n     *             in case there is a resource but it cannot be read\n     */\n    public static String readResource(URL resourceUrl) throws IOException {\n        if (resourceUrl == null) {\n            return null;\n        }\n\n        return IOUtils.toString(resourceUrl);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/NamedThreadFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadFactory;\n\npublic class NamedThreadFactory implements ThreadFactory {\n\n    public NamedThreadFactory() {\n    }\n\n    @Override\n    public Thread newThread(Runnable r) {\n        Thread t = Executors.defaultThreadFactory().newThread(r);\n        String className = r.getClass().getSimpleName();\n        t.setName(className);\n        return t;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/NetUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.util.Enumeration;\nimport java.util.StringJoiner;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class NetUtil {\n\n    private static final String MAC_IS_INVALID_MESSAGE = \"mac is invalid: \";\n    private static final Logger logger = LoggerFactory.getLogger(NetUtil.class);\n\n    private NetUtil() {\n\n    }\n\n    public static String hardwareAddressToString(byte[] macAddress) {\n        if (macAddress == null) {\n            return \"N/A\";\n        }\n\n        if (macAddress.length != 6) {\n            throw new IllegalArgumentException(\"macAddress is invalid\");\n        }\n\n        StringJoiner sj = new StringJoiner(\":\");\n        for (byte item : macAddress) {\n            sj.add(String.format(\"%02X\", item));\n        }\n\n        return sj.toString();\n    }\n\n    public static byte[] hardwareAddressToBytes(String macAddress) {\n        if (macAddress == null || macAddress.isEmpty()) {\n            return new byte[] { 0, 0, 0, 0, 0, 0 };\n        }\n\n        String[] items = macAddress.split(\"\\\\:\");\n\n        if (items.length != 6) {\n            throw new IllegalArgumentException(MAC_IS_INVALID_MESSAGE + macAddress);\n        }\n\n        byte[] bytes = new byte[6];\n        for (int i = 0; i < 6; i++) {\n            String item = items[i];\n            if (item.isEmpty() || item.length() > 2) {\n                throw new IllegalArgumentException(MAC_IS_INVALID_MESSAGE + macAddress);\n            }\n\n            try {\n                bytes[i] = (byte) Integer.parseInt(items[i], 16);\n            } catch (NumberFormatException e) {\n                throw new IllegalArgumentException(MAC_IS_INVALID_MESSAGE + macAddress, e);\n            }\n        }\n\n        return bytes;\n    }\n\n    public static String getPrimaryMacAddress() {\n        NetworkInterface firstInterface = null;\n        Enumeration<NetworkInterface> nifs = null;\n        try {\n\n            // look for eth0 or en0 first\n            nifs = NetworkInterface.getNetworkInterfaces();\n            if (nifs != null) {\n                while (nifs.hasMoreElements()) {\n                    NetworkInterface nif = nifs.nextElement();\n                    if (\"eth0\".equals(nif.getName()) || \"en0\".equals(nif.getName())) {\n                        return hardwareAddressToString(nif.getHardwareAddress());\n                    }\n                }\n            }\n\n            // if not found yet, look for the first active ethernet interface\n            nifs = NetworkInterface.getNetworkInterfaces();\n            if (nifs != null) {\n                while (nifs.hasMoreElements()) {\n                    NetworkInterface nif = nifs.nextElement();\n                    if (!nif.isVirtual() && nif.getHardwareAddress() != null) {\n                        firstInterface = nif;\n                        if (nif.getName().startsWith(\"eth\") || nif.getName().startsWith(\"en\")) {\n                            return hardwareAddressToString(nif.getHardwareAddress());\n                        }\n                    }\n                }\n            }\n\n            if (firstInterface != null) {\n                return hardwareAddressToString(firstInterface.getHardwareAddress());\n            }\n        } catch (Exception e) {\n            logger.warn(\"Exception while getting current IP\", e);\n        }\n\n        return null;\n    }\n\n    public static InetAddress getCurrentInetAddress() {\n        try {\n\n            Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces();\n            if (nifs != null) {\n\n                while (nifs.hasMoreElements()) {\n\n                    NetworkInterface nif = nifs.nextElement();\n                    if (!nif.isLoopback() && nif.isUp() && !nif.isVirtual() && nif.getHardwareAddress() != null) {\n\n                        Enumeration<InetAddress> nadrs = nif.getInetAddresses();\n                        while (nadrs.hasMoreElements()) {\n\n                            InetAddress adr = nadrs.nextElement();\n                            if (adr != null && !adr.isLoopbackAddress()\n                                    && (nif.isPointToPoint() || !adr.isLinkLocalAddress())) {\n                                return adr;\n                            }\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            logger.warn(\"Exception while getting current IP\", e);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/ProcessUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport java.io.IOException;\nimport java.util.StringTokenizer;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @deprecated since {@link org.eclipse.kura.core.util} version 1.3 in favor of\n *             {@link org.eclipse.kura.executor.CommandExecutorService}\n */\n@Deprecated\npublic class ProcessUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(ProcessUtil.class);\n\n    private static ExecutorService processExecutor = Executors.newSingleThreadExecutor();\n\n    private ProcessUtil() {\n\n    }\n\n    public static SafeProcess exec(String command) throws IOException {\n        // Use StringTokenizer since this is the method documented by Runtime\n        StringTokenizer st = new StringTokenizer(command);\n        int count = st.countTokens();\n        String[] cmdArray = new String[count];\n\n        for (int i = 0; i < count; i++) {\n            cmdArray[i] = st.nextToken();\n        }\n\n        return exec(cmdArray);\n    }\n\n    public static SafeProcess exec(final String[] cmdarray) throws IOException {\n        // Serialize process executions. One at a time so we can consume all streams.\n        Future<SafeProcess> futureSafeProcess = processExecutor.submit(() -> {\n            Thread.currentThread().setName(\"SafeProcessExecutor\");\n            SafeProcess safeProcess = new SafeProcess();\n            safeProcess.exec(cmdarray);\n            return safeProcess;\n        });\n\n        try {\n            return futureSafeProcess.get();\n        } catch (Exception e) {\n            logger.error(\"Error waiting from SafeProcess output\");\n            throw new IOException(e);\n        }\n    }\n\n    /**\n     * @deprecated The method does nothing\n     */\n    @Deprecated\n    public static void close(SafeProcess proc) {\n    }\n\n    public static void destroy(SafeProcess proc) {\n        proc.destroy();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/QuickSort.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport java.util.Arrays;\n\n/**\n * Utilities to quickly sort an array of values\n *\n * @deprecated Use sort methods from {@link Arrays} instead\n */\n@Deprecated\npublic final class QuickSort {\n\n    private QuickSort() {\n    }\n\n    /**\n     * @deprecated Use {@link Arrays#sort(int[])} instead\n     */\n    @Deprecated\n    public static void sort(int[] array) {\n        Arrays.sort(array);\n    }\n\n    /**\n     * @deprecated Use {@link Arrays#sort(long[])} instead\n     */\n    @Deprecated\n    public static void sort(long[] array) {\n        Arrays.sort(array);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/SafeProcess.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Arrays;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @deprecated since {@link org.eclipse.kura.core.util} version 1.3 in favor of\n *             {@link org.eclipse.kura.executor.CommandExecutorService}\n */\n@Deprecated\npublic class SafeProcess {\n\n    private static final Logger logger = LoggerFactory.getLogger(SafeProcess.class);\n\n    private static ExecutorService streamGobblers = Executors.newFixedThreadPool(2);\n\n    private Process process;\n    private byte[] inBytes;\n    private byte[] errBytes;\n    private boolean waited;\n    private int exitValue;\n\n    SafeProcess() {\n        super();\n    }\n\n    public OutputStream getOutputStream() {\n        logger.warn(\"getOutputStream() is unsupported\");\n        return null;\n    }\n\n    public InputStream getInputStream() {\n        if (!this.waited) {\n            logger.warn(\"getInputStream() must be called after waitFor()\");\n        }\n        return new ByteArrayInputStream(this.inBytes);\n    }\n\n    public InputStream getErrorStream() {\n        if (!this.waited) {\n            logger.warn(\"getErrorStream() must be called after waitFor()\");\n        }\n        return new ByteArrayInputStream(this.errBytes);\n    }\n\n    void exec(String[] cmdarray) throws IOException {\n        logger.debug(\"Executing: {}\", Arrays.toString(cmdarray));\n        ProcessBuilder pb = new ProcessBuilder(cmdarray);\n        this.process = pb.start();\n\n        // process the input stream\n        Future<byte[]> futureInputGobbler = streamGobblers.submit(() -> {\n            Thread.currentThread().setName(\"SafeProcess InputStream Gobbler\");\n            return readStreamFully(SafeProcess.this.process.getInputStream());\n        });\n\n        // process the error stream\n        Future<byte[]> futureErrorGobbler = streamGobblers.submit(() -> {\n            Thread.currentThread().setName(\"SafeProcess ErrorStream Gobbler\");\n            return readStreamFully(SafeProcess.this.process.getErrorStream());\n        });\n\n        // wait for the process execution\n        try {\n            this.inBytes = futureInputGobbler.get();\n            this.errBytes = futureErrorGobbler.get();\n            this.exitValue = this.process.waitFor();\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new IOException(e);\n        } catch (ExecutionException e) {\n            throw new IOException(e);\n        } finally {\n            closeQuietly(this.process.getInputStream());\n            closeQuietly(this.process.getErrorStream());\n            closeQuietly(this.process.getOutputStream());\n            this.process.destroy();\n            this.process = null;\n            this.waited = true;\n        }\n    }\n\n    public int waitFor() throws InterruptedException {\n        return this.exitValue;\n    }\n\n    public int exitValue() {\n        return this.exitValue;\n    }\n\n    public void destroy() {\n        if (!this.waited) {\n            logger.warn(\"Calling destroy() before waitFor() might lead to resource leaks\");\n            Thread.dumpStack();\n            if (this.process != null) {\n                this.process.destroy();\n            }\n        }\n        this.inBytes = null; // just in case...\n        this.errBytes = null;\n        this.process = null;\n    }\n\n    private byte[] readStreamFully(InputStream is) throws IOException {\n        int len;\n        byte[] buf = new byte[1024];\n        ByteArrayOutputStream inBaos = new ByteArrayOutputStream(1024);\n        while ((len = is.read(buf)) != -1) {\n            inBaos.write(buf, 0, len);\n        }\n        return inBaos.toByteArray();\n    }\n\n    private void closeQuietly(InputStream is) {\n        if (is != null) {\n            try {\n                is.close();\n                is = null;\n            } catch (IOException e) {\n                logger.warn(\"Failed to close process input stream\", e);\n            }\n        }\n    }\n\n    private void closeQuietly(OutputStream os) {\n        if (os != null) {\n            try {\n                os.close();\n                os = null;\n            } catch (IOException e) {\n                logger.warn(\"Failed to close process output stream\", e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/ThrowableUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\npublic class ThrowableUtil {\n\n    private ThrowableUtil() {\n\n    }\n\n    public static String stackTraceAsString(Throwable t) {\n        StringWriter sw = new StringWriter();\n        PrintWriter pw = new PrintWriter(sw);\n        t.printStackTrace(pw);\n        return sw.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/ValidationUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\n\npublic class ValidationUtil {\n\n    private ValidationUtil() {\n\n    }\n\n    public static void notNull(Object value, String argumentName) throws KuraException {\n        if (value == null) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName);\n        }\n    }\n\n    /**\n     * Throws an KuraException if the string value for the specified argument is empty, null, or whitespace.\n     *\n     * @param obj\n     * @param argumentName\n     * @throws KuraException\n     */\n    public static void notEmptyOrNull(String value, String argumentName) throws KuraException {\n        if (value == null || value.trim().length() == 0) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName);\n        }\n    }\n\n    /**\n     * Throws an KuraException if the value for the specified argument is null.\n     *\n     * @param obj\n     * @param argumentName\n     * @throws KuraException\n     */\n    public static void notNegative(int value, String argumentName) throws KuraException {\n        if (value < 0) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName);\n        }\n    }\n\n    /**\n     * Throws an KuraException if the value for the specified argument is null.\n     *\n     * @param obj\n     * @param argumentName\n     * @throws KuraException\n     */\n    public static void notNegative(short value, String argumentName) throws KuraException {\n        if (value < 0) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName);\n        }\n    }\n\n    /**\n     * Throws an KuraException if the value for the specified argument is null.\n     *\n     * @param obj\n     * @param argumentName\n     * @throws KuraException\n     */\n    public static void notNegative(long value, String argumentName) throws KuraException {\n        if (value < 0) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/watchdog/CriticalServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.watchdog;\n\npublic class CriticalServiceImpl {\n\n    private final String name;\n    private final long timeout;\n    private long updated;\n\n    /**\n     *\n     * @param name\n     * @param timeout\n     *            timeout for reporting interval in seconds\n     */\n    public CriticalServiceImpl(String name, long timeout) {\n        this.name = name;\n        this.timeout = timeout;\n        this.updated = System.currentTimeMillis();\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public long getTimeout() {\n        return this.timeout;\n    }\n\n    public boolean isTimedOut() {\n        long current = System.currentTimeMillis();\n        return this.timeout < current - this.updated;\n    }\n\n    public void update() {\n        this.updated = System.currentTimeMillis();\n    }\n\n    @Override\n    public String toString() {\n        return \"Service Name:  \" + this.name + \", Timeout(ms):  \" + this.timeout;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.certificates/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.certificates\nBundle-SymbolicName: org.eclipse.kura.core.certificates;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: com.google.gson;version=\"2.7.0\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.certificate;version=\"[2.1,2.2)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.1,2.0)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.rest.utils;version=\"1.0.0\",\n org.eclipse.kura.security.keystore;version=\"[1.0,2.0)\",\n org.eclipse.osgi.util;version=\"1.1.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.6.4\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.certificates/OSGI-INF/CertificatesService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" configuration-policy=\"optional\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.certificate.CertificatesService\">\n   <implementation class=\"org.eclipse.kura.core.certificates.CertificatesManager\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.certificate.CertificatesService\"/>\n   </service>\n\n\t<property name=\"service.pid\" value=\"org.eclipse.kura.certificate.CertificatesService\"/>\n\t<reference name=\"CryptoService\"\n              interface=\"org.eclipse.kura.crypto.CryptoService\"\n              bind=\"setCryptoService\"\n              unbind=\"unsetCryptoService\"\n              cardinality=\"1..1\"\n              policy=\"static\"/>\n  <reference name=\"ConfigurationService\"\n              bind=\"setConfigurationService\"\n              unbind=\"unsetConfigurationService\"\n              policy=\"static\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.configuration.ConfigurationService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.certificates/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.certificates/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.certificates/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about_files/,\\\n               about.html\nadditional.bundles = org.eclipse.osgi,\\\n                     org.eclipse.osgi.util,\\\n                     org.eclipse.kura.api\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.certificates/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.certificates</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.core.certificates.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.certificates/src/main/java/org/eclipse/kura/core/certificates/CertificatesManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.certificates;\n\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.cert.Certificate;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraIOException;\nimport org.eclipse.kura.certificate.CertificatesService;\nimport org.eclipse.kura.certificate.KuraCertificateEntry;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.message.KuraApplicationTopic;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/*\n *\n */\npublic class CertificatesManager implements CertificatesService {\n\n    private static final Logger logger = LoggerFactory.getLogger(CertificatesManager.class);\n\n    public static final String APP_ID = \"org.eclipse.kura.core.certificates.CertificatesManager\";\n\n    private static final String RESOURCE_CERTIFICATE_DM = \"dm\";\n    private static final String RESOURCE_CERTIFICATE_LOGIN = \"login\";\n    private static final String RESOURCE_CERTIFICATE_BUNDLE = \"bundle\";\n    private static final String RESOURCE_CERTIFICATE_SSL = \"ssl\";\n\n    private static final String LOGIN_KEYSTORE_SERVICE_PID = \"HttpsKeystore\";\n    private static final String SSL_KEYSTORE_SERVICE_PID = \"SSLKeystore\";\n    private static final String DEFAULT_KEYSTORE_SERVICE_PID = \"org.eclipse.kura.crypto.CryptoService\";\n\n    private CryptoService cryptoService;\n    private ConfigurationService configurationService;\n    private Map<String, KeystoreService> keystoreServices = new HashMap<>();\n    private BundleContext bundleContext;\n    private ServiceTrackerCustomizer<KeystoreService, KeystoreService> keystoreServiceTrackerCustomizer;\n    private ServiceTracker<KeystoreService, KeystoreService> keystoreServiceTracker;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void unsetCryptoService(CryptoService cryptoService) {\n        if (this.cryptoService == cryptoService) {\n            this.cryptoService = null;\n        }\n    }\n\n    public void setConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    public void unsetConfigurationService(ConfigurationService configurationService) {\n        if (this.configurationService == configurationService) {\n            this.configurationService = null;\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) {\n        this.bundleContext = componentContext.getBundleContext();\n        this.keystoreServiceTrackerCustomizer = new KeystoreServiceTrackerCustomizer();\n        initKeystoreServiceTracking();\n        logger.info(\"Bundle {} has started!\", APP_ID);\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        if (this.keystoreServiceTracker != null) {\n            this.keystoreServiceTracker.close();\n        }\n        logger.info(\"Bundle {} is deactivating!\", APP_ID);\n    }\n\n    @Override\n    public Certificate returnCertificate(String alias) throws KuraException {\n        TrustedCertificateEntry cert;\n        try {\n            cert = getCertificateEntry(DEFAULT_KEYSTORE_SERVICE_PID + \":\" + alias).getCertificateEntry();\n        } catch (KuraException e) {\n            return null;\n        }\n        return cert.getTrustedCertificate();\n    }\n\n    @Override\n    public void storeCertificate(Certificate cert, String alias) throws KuraException {\n        if (alias.startsWith(RESOURCE_CERTIFICATE_DM)) {\n            storeDmCertificate(cert, alias);\n        } else if (alias.startsWith(RESOURCE_CERTIFICATE_BUNDLE)) {\n            storeTrustRepoCertificate(cert, alias);\n        } else if (alias.startsWith(RESOURCE_CERTIFICATE_LOGIN)) {\n            storeLoginCertificate(cert, alias);\n        } else if (alias.startsWith(RESOURCE_CERTIFICATE_SSL)) {\n            storeSSLCertificate(cert, alias);\n        }\n    }\n\n    protected void storeLoginCertificate(Certificate cert, String alias) throws KuraException {\n        KuraCertificateEntry kuraCertificate = new KuraCertificateEntry(LOGIN_KEYSTORE_SERVICE_PID, alias, cert);\n        addCertificate(kuraCertificate);\n    }\n\n    protected void storeSSLCertificate(Certificate cert, String alias) throws KuraException {\n        KuraCertificateEntry kuraCertificate = new KuraCertificateEntry(SSL_KEYSTORE_SERVICE_PID, alias, cert);\n        addCertificate(kuraCertificate);\n    }\n\n    protected void storeTrustRepoCertificate(Certificate cert, String alias) throws KuraException {\n        KuraCertificateEntry kuraCertificate = new KuraCertificateEntry(DEFAULT_KEYSTORE_SERVICE_PID, alias, cert);\n        addCertificate(kuraCertificate);\n    }\n\n    protected void storeDmCertificate(Certificate cert, String alias) throws KuraException {\n        storeTrustRepoCertificate(cert, alias);\n    }\n\n    @Override\n    public Enumeration<String> listBundleCertificatesAliases() {\n        return listCertificatesAliases(DEFAULT_KEYSTORE_SERVICE_PID);\n    }\n\n    @Override\n    public Enumeration<String> listDMCertificatesAliases() {\n        return listCertificatesAliases(DEFAULT_KEYSTORE_SERVICE_PID);\n    }\n\n    @Override\n    public Enumeration<String> listSSLCertificatesAliases() {\n        return listCertificatesAliases(SSL_KEYSTORE_SERVICE_PID);\n    }\n\n    @Override\n    public Enumeration<String> listCACertificatesAliases() {\n        return listCertificatesAliases(DEFAULT_KEYSTORE_SERVICE_PID);\n    }\n\n    @Override\n    public void removeCertificate(String alias) throws KuraException {\n        for (Entry<String, KeystoreService> keystoreServiceEntry : this.keystoreServices.entrySet()) {\n            keystoreServiceEntry.getValue().deleteEntry(alias);\n        }\n    }\n\n    @Override\n    public boolean verifySignature(KuraApplicationTopic kuraTopic, KuraPayload kuraPayload) {\n        return true;\n    }\n\n    protected Enumeration<String> listCertificatesAliases(String keystoreId) {\n        try {\n            return Collections.enumeration(getKeystore(keystoreId).getAliases());\n        } catch (IllegalArgumentException | KuraException e) {\n            return Collections.emptyEnumeration();\n        }\n    }\n\n    @Override\n    public List<KuraCertificateEntry> getCertificates() throws KuraException {\n        List<KuraCertificateEntry> certificates = new ArrayList<>();\n        for (Entry<String, KeystoreService> keystoreServiceEntry : this.keystoreServices.entrySet()) {\n            String keystoreId = keystoreServiceEntry.getKey();\n            Map<String, java.security.KeyStore.Entry> keystoreEntries = keystoreServiceEntry.getValue().getEntries();\n            keystoreEntries.entrySet().stream().filter(entry -> entry.getValue() instanceof TrustedCertificateEntry)\n                    .forEach(entry -> {\n                        String alias = entry.getKey();\n                        certificates.add(new KuraCertificateEntry(keystoreId, alias,\n                                (TrustedCertificateEntry) entry.getValue()));\n                    });\n        }\n        return certificates;\n    }\n\n    @Override\n    public KuraCertificateEntry getCertificateEntry(String id) throws KuraException {\n        String keystoreId = KuraCertificateEntry.getKeystoreId(id);\n        String alias = KuraCertificateEntry.getAlias(id);\n        java.security.KeyStore.Entry keystoreEntry = getKeystore(keystoreId).getEntry(alias);\n        if (keystoreEntry instanceof TrustedCertificateEntry) {\n            return new KuraCertificateEntry(keystoreId, alias, (TrustedCertificateEntry) keystoreEntry);\n        } else {\n            throw new KuraIOException(\"Failed to retrieve certificate \" + id);\n        }\n    }\n\n    @Override\n    public void updateCertificate(KuraCertificateEntry certificate) throws KuraException {\n        addCertificate(certificate);\n    }\n\n    @Override\n    public void addCertificate(KuraCertificateEntry certificate) throws KuraException {\n        getKeystore(certificate.getKeystoreId()).setEntry(certificate.getAlias(), certificate.getCertificateEntry());\n    }\n\n    @Override\n    public void deleteCertificate(String id) throws KuraException {\n        String keystoreId = KuraCertificateEntry.getKeystoreId(id);\n        String alias = KuraCertificateEntry.getAlias(id);\n        getKeystore(keystoreId).deleteEntry(alias);\n    }\n\n    private void initKeystoreServiceTracking() {\n        String filterString = String.format(\"(&(%s=%s))\", Constants.OBJECTCLASS, KeystoreService.class.getName());\n        Filter filter = null;\n        try {\n            filter = this.bundleContext.createFilter(filterString);\n        } catch (InvalidSyntaxException e) {\n            logger.error(\"Filter setup exception \", e);\n        }\n        this.keystoreServiceTracker = new ServiceTracker<>(this.bundleContext, filter,\n                this.keystoreServiceTrackerCustomizer);\n        this.keystoreServiceTracker.open();\n    }\n\n    private KeystoreService getKeystore(String keystoreId) throws KuraException {\n        KeystoreService service = this.keystoreServices.get(keystoreId);\n        if (service == null) {\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, \"KeystoreService \" + keystoreId + \" not found\");\n        }\n        return service;\n    }\n\n    private final class KeystoreServiceTrackerCustomizer\n            implements ServiceTrackerCustomizer<KeystoreService, KeystoreService> {\n\n        private static final String KURA_SERVICE_PID = \"kura.service.pid\";\n\n        @Override\n        public KeystoreService addingService(final ServiceReference<KeystoreService> reference) {\n            String kuraServicePid = (String) reference.getProperty(KURA_SERVICE_PID);\n            CertificatesManager.this.keystoreServices.put(kuraServicePid,\n                    CertificatesManager.this.bundleContext.getService(reference));\n            return CertificatesManager.this.keystoreServices.get(kuraServicePid);\n        }\n\n        @Override\n        public void modifiedService(final ServiceReference<KeystoreService> reference, final KeystoreService service) {\n            String kuraServicePid = (String) reference.getProperty(KURA_SERVICE_PID);\n            CertificatesManager.this.keystoreServices.put(kuraServicePid,\n                    CertificatesManager.this.bundleContext.getService(reference));\n        }\n\n        @Override\n        public void removedService(final ServiceReference<KeystoreService> reference, final KeystoreService service) {\n            String kuraServicePid = (String) reference.getProperty(KURA_SERVICE_PID);\n            CertificatesManager.this.keystoreServices.remove(kuraServicePid);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.certificates/src/main/java/org/eclipse/kura/core/certificates/KeyStoreManagement.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.certificates;\n\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertificateException;\n\nfinal class KeyStoreManagement {\n\n    private static final String ENV_JAVA_KEYSTORE = System.getenv(\"JAVA_HOME\") + \"/jre/lib/security/cacerts\";\n\n    private KeyStoreManagement() {\n\n    }\n\n    static KeyStore loadKeyStore(byte[] password)\n            throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {\n        return loadKeyStore(new String(password).toCharArray());\n    }\n\n    static void saveKeyStore(KeyStore keystore, byte[] password)\n            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n        saveKeyStore(keystore, new String(password).toCharArray());\n    }\n\n    static KeyStore loadKeyStore(char[] password)\n            throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {\n        return loadKeyStore(ENV_JAVA_KEYSTORE, new String(password).toCharArray());\n    }\n\n    static void saveKeyStore(KeyStore keystore, char[] password)\n            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n        saveKeyStore(keystore, ENV_JAVA_KEYSTORE, new String(password).toCharArray());\n    }\n\n    static void saveKeyStore(String keystorePath, KeyStore keystore, char[] password)\n            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n        saveKeyStore(keystore, keystorePath, new String(password).toCharArray());\n    }\n\n    static KeyStore loadKeyStore(String location, char[] password)\n            throws IOException, NoSuchAlgorithmException, CertificateException, KeyStoreException {\n        FileInputStream is = null;\n        try {\n            is = new FileInputStream(location);\n            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());\n            keystore.load(is, password);\n            is.close();\n            return keystore;\n        } finally {\n            if (is != null) {\n                is.close();\n            }\n        }\n    }\n\n    static void saveKeyStore(KeyStore keystore, String location, char[] password)\n            throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException {\n        FileOutputStream fos = null;\n        try {\n            fos = new FileOutputStream(location);\n            keystore.store(fos, password);\n            fos.flush();\n            fos.close();\n        } finally {\n            if (fos != null) {\n                fos.close();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.cloud.factory/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.cloud.factory\nBundle-SymbolicName: org.eclipse.kura.core.cloud.factory;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"1.6.0\",\n org.eclipse.kura.cloud;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloud.factory;version=\"[1.1,1.2)\",\n org.eclipse.kura.cloudconnection;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.factory;version=\"[1.0,1.1)\",\n org.eclipse.kura.configuration;version=\"[1.0,2.0)\",\n org.eclipse.kura.data;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.component\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.cloud.factory/OSGI-INF/cloudServiceFactory.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" name=\"org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory\"> \n   <implementation class=\"org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory\"/>\n   <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\" unbind=\"unsetConfigurationService\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.cloud.factory.CloudServiceFactory\"/>\n      <provide interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n   </service>\n   <property name=\"osgi.command.scope\" type=\"String\" value=\"kura.cloud\"/>\n   <property name=\"osgi.command.function\" type=\"String\">\n      createConfiguration\n   </property>\n   <property name=\"kura.ui.csf.pid.default\" type=\"String\" value=\"org.eclipse.kura.cloud.CloudService-2\"/>\n   <property name=\"kura.ui.csf.pid.regex\" type=\"String\" value=\"^org.eclipse.kura.cloud.CloudService\\-[a-zA-Z0-9]+$\"/>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.cloud.factory/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.cloud.factory/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.cloud.factory/build.properties",
    "content": "bin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files\nsrc.includes = about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.cloud.factory/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n\tSPDX-License-Identifier: EPL-2.0\n\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.cloud.factory</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<build>\n\t\t<plugins>\n        \t<plugin>\n        \t\t<groupId>org.apache.maven.plugins</groupId>\n        \t\t<artifactId>maven-checkstyle-plugin</artifactId>\n        \t\t<configuration>\n        \t\t\t<skip>true</skip>\n        \t\t</configuration>\n        \t</plugin>\n        </plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.cloud.factory/src/main/java/org/eclipse/kura/core/cloud/factory/DefaultCloudServiceFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.factory;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.cloud.factory.CloudServiceFactory;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.component.ComponentConstants;\nimport org.osgi.service.component.ComponentContext;\n\n/**\n * The Kura default {@link CloudServiceFactory} implements a three layer stack architecture.\n * Each layer is an OSGi Declarative Services Factory Component and provides a service as follows:\n *\n * <table>\n * <thead>\n * <tr>\n * <th>Factory PID</th>\n * <th>Service interface</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr>\n * <td>org.eclipse.kura.cloud.CloudService</td>\n * <td>{@link CloudService}</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.data.DataService</td>\n * <td>{@link CloudService}</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</td>\n * <td>{@link DataTransportService}</td>\n * </tr>\n * </tbody>\n * </table>\n * <br>\n * When a new CloudService is created the factory creates also a DataService and a DataTransportService.\n * Since the <i>pid</i> parameter of {@link #createConfiguration(String)} only specifies the PID of\n * the CloudService layer, a convention is needed to derive the PIDs of the lower layers.\n * <br>\n * <br>\n * The default stack instance is special.\n * For backward compatibility the PIDs of the default stack must be as follows:\n *\n * <table>\n * <thead>\n * <tr>\n * <th>PID (kura.service.pid)</th>\n * <th>Factory PID</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr>\n * <td>org.eclipse.kura.cloud.CloudService</td>\n * <td>org.eclipse.kura.cloud.CloudService</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.data.DataService</td>\n * <td>org.eclipse.kura.data.DataService</td>\n * </tr>\n * <tr>\n * <td></td>\n * <td>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</td>\n * </tr>\n * </tbody>\n * </table>\n * <br>\n *\n * For other stack instances the convention used to generate the PIDs for the lower layers is\n * to use the sub string in the CloudService PID starting after the first occurrence of the '-' character and append\n * the sub string to the PIDs of the default stack above, for example:\n *\n * <table>\n * <thead>\n * <tr>\n * <th>PID (kura.service.pid)</th>\n * <th>Factory PID</th>\n * </tr>\n * </thead>\n * <tbody>\n * <tr>\n * <td>org.eclipse.kura.cloud.CloudService-2</td>\n * <td>org.eclipse.kura.cloud.CloudService</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.data.DataService-2</td>\n * <td>org.eclipse.kura.data.DataService</td>\n * </tr>\n * <tr>\n * <td>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-2</td>\n * <td>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</td>\n * </tr>\n * </tbody>\n * </table>\n * <br>\n * The (configuration of) layer instances of each stack are persisted to Kura snapshot and\n * recreated at every Kura start.\n * On startup every stack must be properly reassembled with the right layer instances.\n * <br>\n * This can be achieved using a standard OSGi Declarative Services magic property set in a layer configuration\n * specifying the layer dependency on a specific PID of its next lower layer.\n * The following example shows this selective dependency mechanism for the DataService and MqttDataTransport services.\n * <br>\n * The DataService component definition specifies a dependency on a DataTransportService as follows:\n *\n * <pre>\n * &ltreference name=\"DataTransportService\"\n *              bind=\"setDataTransportService\"\n *              unbind=\"unsetDataTransportService\"\n *              cardinality=\"1..1\"\n *              policy=\"static\"\n *              interface=\"org.eclipse.kura.data.DataTransportService\"/&gt\n * </pre>\n *\n * <br>\n * The DataService with PID <i>org.eclipse.kura.data.DataService-2</i> needs to be activated\n * only when its dependency on a specific DataTransportService with\n * PID <i>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-2</i> is satisfied.\n * <br>\n * The OSGi Declarative Services specification provides a magic <i>&ltreference name&gt.target</i>\n * property that can be set at runtime to specify a selective dependency.\n * <br>\n * In the above example the <i>org.eclipse.kura.data.DataService-2</i> component instance will have a\n * <i>DataTransportService.target</i> property set to the value:\n *\n * <pre>\n * (kura.service.pid = org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport - 2)\n * </pre>\n *\n * Since {@link org.eclipse.kura.cloud.factory} 1.1.0, the CloudService instance contains a property that maps the\n * instance with the {@link org.eclipse.kura.cloud.factory.CloudServiceFactory} implementation that generated it.\n *\n * <br>\n */\npublic class DefaultCloudServiceFactory implements CloudServiceFactory, CloudConnectionFactory {\n\n    private static final String FACTORY_PID = \"org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory\";\n\n    // The following constants must match the factory component definitions\n    private static final String CLOUD_SERVICE_FACTORY_PID = \"org.eclipse.kura.cloud.CloudService\";\n    private static final String DATA_SERVICE_FACTORY_PID = \"org.eclipse.kura.data.DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    private static final String CLOUD_SERVICE_PID = \"org.eclipse.kura.cloud.CloudService\";\n    private static final String DATA_SERVICE_PID = \"org.eclipse.kura.data.DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    private static final String DATA_SERVICE_REFERENCE_NAME = \"DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = \"DataTransportService\";\n\n    private static final String REFERENCE_TARGET_VALUE_FORMAT = \"(\" + ConfigurationService.KURA_SERVICE_PID + \"=%s)\";\n\n    private static final Pattern MANAGED_CLOUD_SERVICE_PID_PATTERN = Pattern\n            .compile(\"^org\\\\.eclipse\\\\.kura\\\\.cloud\\\\.CloudService(-[a-zA-Z0-9]+)?$\");\n\n    private ConfigurationService configurationService;\n    private BundleContext bundleContext;\n\n    protected void setConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    protected void unsetConfigurationService(ConfigurationService configurationService) {\n        if (configurationService == this.configurationService) {\n            this.configurationService = null;\n        }\n    }\n\n    public void activate(final ComponentContext context) {\n        this.bundleContext = context.getBundleContext();\n    }\n\n    @Override\n    public String getFactoryPid() {\n        return CLOUD_SERVICE_FACTORY_PID;\n    }\n\n    @Override\n    public void createConfiguration(String pid) throws KuraException {\n        String[] parts = pid.split(\"-\");\n        if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) {\n            String suffix = null;\n            if (parts.length > 1) {\n                suffix = parts[1];\n            }\n\n            String dataServicePid = DATA_SERVICE_PID;\n            String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID;\n            if (suffix != null) {\n                dataServicePid += \"-\" + suffix;\n                dataTransportServicePid += \"-\" + suffix;\n            }\n\n            // create the CloudService layer and set the selective dependency on the DataService PID\n            Map<String, Object> cloudServiceProperties = new HashMap<>();\n            String name = DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n            cloudServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataServicePid));\n            cloudServiceProperties.put(KURA_CLOUD_SERVICE_FACTORY_PID, FACTORY_PID);\n            cloudServiceProperties.put(KURA_CLOUD_CONNECTION_FACTORY_PID, FACTORY_PID);\n\n            this.configurationService.createFactoryConfiguration(CLOUD_SERVICE_FACTORY_PID, pid, cloudServiceProperties,\n                    false);\n\n            // create the DataService layer and set the selective dependency on the DataTransportService PID\n            Map<String, Object> dataServiceProperties = new HashMap<String, Object>();\n            name = DATA_TRANSPORT_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n            dataServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid));\n\n            this.configurationService.createFactoryConfiguration(DATA_SERVICE_FACTORY_PID, dataServicePid,\n                    dataServiceProperties, false);\n\n            // create the DataTransportService layer and take a snapshot\n            this.configurationService.createFactoryConfiguration(DATA_TRANSPORT_SERVICE_FACTORY_PID,\n                    dataTransportServicePid, null, true);\n        } else {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Invalid PID '{}'\", pid);\n        }\n    }\n\n    @Override\n    public void deleteConfiguration(String pid) throws KuraException {\n        String[] parts = pid.split(\"-\");\n        if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) {\n            String suffix = null;\n            if (parts.length > 1) {\n                suffix = parts[1];\n            }\n\n            String dataServicePid = DATA_SERVICE_PID;\n            String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID;\n            if (suffix != null) {\n                dataServicePid += \"-\" + suffix;\n                dataTransportServicePid += \"-\" + suffix;\n            }\n\n            this.configurationService.deleteFactoryConfiguration(pid, false);\n            this.configurationService.deleteFactoryConfiguration(dataServicePid, false);\n            this.configurationService.deleteFactoryConfiguration(dataTransportServicePid, true);\n        }\n    }\n\n    @Override\n    public List<String> getStackComponentsPids(String pid) throws KuraException {\n        List<String> componentPids = new ArrayList<String>();\n        String[] parts = pid.split(\"-\");\n        if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) {\n            String suffix = null;\n            if (parts.length > 1) {\n                suffix = parts[1];\n            }\n\n            String dataServicePid = DATA_SERVICE_PID;\n            String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID;\n            if (suffix != null) {\n                dataServicePid += \"-\" + suffix;\n                dataTransportServicePid += \"-\" + suffix;\n            }\n\n            componentPids.add(pid);\n            componentPids.add(dataServicePid);\n            componentPids.add(dataTransportServicePid);\n            return componentPids;\n        } else {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Invalid PID '{}'\", pid);\n        }\n    }\n\n    @Override\n    public Set<String> getManagedCloudConnectionPids() throws KuraException {\n\n        try {\n            return this.bundleContext.getServiceReferences(CloudConnectionManager.class, null).stream().filter(ref -> {\n                final Object kuraServicePid = ref.getProperty(ConfigurationService.KURA_SERVICE_PID);\n\n                if (!(kuraServicePid instanceof String)) {\n                    return false;\n                }\n\n                return MANAGED_CLOUD_SERVICE_PID_PATTERN.matcher((String) kuraServicePid).matches()\n                        && (FACTORY_PID.equals(ref.getProperty(KURA_CLOUD_SERVICE_FACTORY_PID))\n                                || FACTORY_PID.equals(ref.getProperty(KURA_CLOUD_CONNECTION_FACTORY_PID)));\n            }).map(ref -> (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID)).collect(Collectors.toSet());\n        } catch (InvalidSyntaxException e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, e);\n        }\n    }\n\n    @Override\n    public Set<String> getManagedCloudServicePids() throws KuraException {\n        return getManagedCloudConnectionPids();\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.comm/.gitignore",
    "content": "/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.comm/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.comm\nBundle-SymbolicName: org.eclipse.kura.core.comm;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: javax.comm;version=\"1.2.0\",\n javax.microedition.io,\n org.apache.logging.log4j;version=\"2.8.2\",\n org.apache.logging.log4j.util;version=\"2.8.2\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.comm;version=\"[1.1,1.2)\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.io;version=\"1.0.0\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.comm/OSGI-INF/comm.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n    Red Hat Inc\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.core.comm.CommConnectionFactory\">\n   <implementation class=\"org.eclipse.kura.core.comm.CommConnectionFactory\"/>\n   <service>\n      <provide interface=\"org.osgi.service.io.ConnectionFactory\"/>\n   </service>\n   <property name=\"io.scheme\">comm</property>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.core.comm.CommConnectionFactory\"/>   \n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.comm/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.comm/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.comm/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech \n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.eclipse.osgi,\\\n                     org.eclipse.equinox.io\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.comm/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n     Red Hat Inc\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.comm</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.core.comm.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.comm/src/main/java/org/eclipse/kura/core/comm/CommConnectionFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.comm;\n\nimport static org.eclipse.kura.comm.CommURI.parseString;\n\nimport java.io.IOException;\n\nimport javax.microedition.io.Connection;\n\nimport org.osgi.service.io.ConnectionFactory;\n\npublic class CommConnectionFactory implements ConnectionFactory {\n\n    @Override\n    public Connection createConnection(String name, int mode, boolean timeouts) throws IOException {\n        try {\n            return new CommConnectionImpl(parseString(name), mode, timeouts);\n        } catch (IOException e) {\n            throw e; // re-throw\n        } catch (Throwable t) {\n            throw new IOException(t);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.comm/src/main/java/org/eclipse/kura/core/comm/CommConnectionImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.comm;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.io.Closeable;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.Buffer;\nimport java.nio.ByteBuffer;\nimport java.util.StringJoiner;\n\nimport javax.comm.CommPort;\nimport javax.comm.CommPortIdentifier;\nimport javax.comm.NoSuchPortException;\nimport javax.comm.PortInUseException;\nimport javax.comm.SerialPort;\n\nimport org.apache.logging.log4j.LogManager;\nimport org.apache.logging.log4j.Logger;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.comm.CommConnection;\nimport org.eclipse.kura.comm.CommURI;\n\npublic class CommConnectionImpl implements CommConnection, Closeable {\n\n    private static final String SEND_MESSAGE = \"sendMessage() - {}\";\n    private static final String JAVA_EXT_DIRS = \"java.ext.dirs\";\n    private static final String KURA_EXT_DIR = \"kura.ext.dir\";\n\n    private static final Logger logger = LogManager.getLogger(CommConnectionImpl.class);\n\n    // set up the appropriate ext dir for RXTX extra device nodes\n    static {\n        String kuraExtDir = System.getProperty(KURA_EXT_DIR);\n        if (kuraExtDir != null) {\n            StringBuffer sb = new StringBuffer();\n            String existingDirs = System.getProperty(JAVA_EXT_DIRS);\n            if (existingDirs != null) {\n                if (!existingDirs.contains(kuraExtDir)) {\n                    sb.append(existingDirs).append(File.pathSeparator).append(kuraExtDir);\n                    System.setProperty(JAVA_EXT_DIRS, sb.toString());\n                }\n            } else {\n                sb.append(kuraExtDir);\n                System.setProperty(JAVA_EXT_DIRS, sb.toString());\n            }\n        }\n    }\n\n    private final CommURI commUri;\n    private SerialPort serialPort;\n    private InputStream inputStream;\n    private OutputStream outputStream;\n\n    public CommConnectionImpl(CommURI commUri, int mode, boolean timeouts)\n            throws IOException, NoSuchPortException, PortInUseException {\n\n        requireNonNull(commUri);\n\n        this.commUri = commUri;\n\n        final String port = this.commUri.getPort();\n        final int baudRate = this.commUri.getBaudRate();\n        final int dataBits = this.commUri.getDataBits();\n        final int stopBits = this.commUri.getStopBits();\n        final int parity = this.commUri.getParity();\n        final int flowControl = this.commUri.getFlowControl();\n        final int openTimeout = this.commUri.getOpenTimeout();\n        final int receiveTimeout = this.commUri.getReceiveTimeout();\n\n        final CommPortIdentifier commPortIdentifier = CommPortIdentifier.getPortIdentifier(port);\n\n        final CommPort commPort = commPortIdentifier.open(this.getClass().getName(), openTimeout);\n\n        if (commPort == null) {\n            throw new NoSuchPortException(\"CommPortIdentifier.open() returned a null port\");\n        }\n\n        try {\n            if (commPort instanceof SerialPort) {\n                this.serialPort = (SerialPort) commPort;\n\n                this.serialPort.setSerialPortParams(baudRate, dataBits, stopBits, parity);\n                this.serialPort.setFlowControlMode(flowControl);\n                if (receiveTimeout > 0) {\n                    this.serialPort.enableReceiveTimeout(receiveTimeout);\n                    if (!this.serialPort.isReceiveTimeoutEnabled()) {\n                        throw new IOException(\"Serial receive timeout not supported by driver\");\n                    }\n                }\n            } else {\n                throw new IOException(\"Unsupported Port Type\");\n            }\n        } catch (final Exception e) {\n            logger.error(\"Failed to configure COM port\", e);\n            commPort.close();\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public CommURI getURI() {\n        return this.commUri;\n    }\n\n    @Override\n    public DataInputStream openDataInputStream() throws IOException {\n        return new DataInputStream(openInputStream());\n    }\n\n    @Override\n    public synchronized InputStream openInputStream() throws IOException {\n        checkIfClosed();\n\n        if (this.inputStream == null) {\n            this.inputStream = this.serialPort.getInputStream();\n        }\n        return this.inputStream;\n    }\n\n    @Override\n    public DataOutputStream openDataOutputStream() throws IOException {\n        return new DataOutputStream(openOutputStream());\n    }\n\n    @Override\n    public synchronized OutputStream openOutputStream() throws IOException {\n        checkIfClosed();\n\n        if (this.outputStream == null) {\n            this.outputStream = this.serialPort.getOutputStream();\n        }\n        return this.outputStream;\n    }\n\n    @Override\n    public synchronized void close() throws IOException {\n        if (this.serialPort != null) {\n            this.serialPort.notifyOnDataAvailable(false);\n            this.serialPort.removeEventListener();\n            if (this.inputStream != null) {\n                this.inputStream.close();\n                this.inputStream = null;\n            }\n            if (this.outputStream != null) {\n                this.outputStream.close();\n                this.outputStream = null;\n            }\n\n            this.serialPort.close();\n            this.serialPort = null;\n        }\n    }\n\n    private void checkIfClosed() throws IOException {\n        if (this.serialPort == null) {\n            throw new IOException(\"Connection is already closed\");\n        }\n    }\n\n    @Override\n    public synchronized void sendMessage(byte[] message) throws KuraException, IOException {\n        checkIfClosed();\n\n        if (message == null) {\n            throw new NullPointerException(\"Message must not be null\");\n        }\n\n        logger.debug(SEND_MESSAGE, () -> getBytesAsString(message));\n\n        if (this.outputStream == null) {\n            openOutputStream();\n        }\n\n        this.outputStream.write(message, 0, message.length);\n        this.outputStream.flush();\n    }\n\n    @Override\n    public synchronized byte[] sendCommand(byte[] command, int timeout) throws KuraException, IOException {\n        checkIfClosed();\n\n        if (command == null) {\n            throw new NullPointerException(\"Serial command must not be null\");\n        }\n\n        logger.debug(SEND_MESSAGE, () -> getBytesAsString(command));\n\n        if (this.outputStream == null) {\n            openOutputStream();\n        }\n        if (this.inputStream == null) {\n            openInputStream();\n        }\n\n        byte[] dataInBuffer = flushSerialBuffer();\n        if (dataInBuffer != null && dataInBuffer.length > 0) {\n            logger.warn(\"eating bytes in the serial buffer input stream before sending command: {}\",\n                    getBytesAsString(dataInBuffer));\n        }\n        this.outputStream.write(command, 0, command.length);\n        this.outputStream.flush();\n\n        ByteBuffer buffer = getResponse(timeout);\n        if (buffer != null) {\n            byte[] response = new byte[buffer.limit()];\n            buffer.get(response, 0, response.length);\n            return response;\n        } else {\n            return null;\n        }\n    }\n\n    @Override\n    public synchronized byte[] sendCommand(byte[] command, int timeout, int demark) throws KuraException, IOException {\n        checkIfClosed();\n\n        if (command == null) {\n            throw new NullPointerException(\"Serial command must not be null\");\n        }\n\n        logger.debug(SEND_MESSAGE, getBytesAsString(command));\n\n        if (this.outputStream == null) {\n            openOutputStream();\n        }\n        if (this.inputStream == null) {\n            openInputStream();\n        }\n\n        byte[] dataInBuffer = flushSerialBuffer();\n        if (dataInBuffer != null && dataInBuffer.length > 0) {\n            logger.warn(\"eating bytes in the serial buffer input stream before sending command: {}\",\n                    getBytesAsString(dataInBuffer));\n        }\n        this.outputStream.write(command, 0, command.length);\n        this.outputStream.flush();\n\n        ByteBuffer buffer = getResponse(timeout, demark);\n        if (buffer != null) {\n            byte[] response = new byte[buffer.limit()];\n            buffer.get(response, 0, response.length);\n            return response;\n        } else {\n            return null;\n        }\n    }\n\n    @Override\n    public synchronized byte[] flushSerialBuffer() throws KuraException, IOException {\n        checkIfClosed();\n\n        ByteBuffer buffer = getResponse(50);\n        if (buffer != null) {\n            byte[] response = new byte[buffer.limit()];\n            buffer.get(response, 0, response.length);\n            return response;\n        } else {\n            return null;\n        }\n    }\n\n    private synchronized ByteBuffer getResponse(int timeout) throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate(4096);\n        long start = System.currentTimeMillis();\n\n        while (this.inputStream.available() < 1 && System.currentTimeMillis() - start < timeout) {\n            try {\n                Thread.sleep(10);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        }\n\n        while (this.inputStream.available() >= 1) {\n            int c = this.inputStream.read();\n            buffer.put((byte) c);\n        }\n\n        // The buffer is casted to Buffer for Java8 compatibility\n        ((Buffer) buffer).flip();\n\n        return buffer.limit() > 0 ? buffer : null;\n    }\n\n    private synchronized ByteBuffer getResponse(int timeout, int demark) throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate(4096);\n        long start = System.currentTimeMillis();\n\n        while (this.inputStream.available() < 1 && System.currentTimeMillis() - start < timeout) {\n            try {\n                Thread.sleep(10);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        }\n\n        start = System.currentTimeMillis();\n        do {\n            if (this.inputStream.available() > 0) {\n                start = System.currentTimeMillis();\n                int c = this.inputStream.read();\n                buffer.put((byte) c);\n            }\n        } while (System.currentTimeMillis() - start < demark);\n\n        // The buffer is casted to Buffer for Java8 compatibility\n        ((Buffer) buffer).flip();\n\n        return buffer.limit() > 0 ? buffer : null;\n    }\n\n    /* default */ static String getBytesAsString(byte[] bytes) {\n        if (bytes == null) {\n            return null;\n        }\n\n        StringJoiner sj = new StringJoiner(\" \");\n\n        for (byte b : bytes) {\n            sj.add(String.format(\"%02X\", b));\n        }\n\n        return sj.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/.gitignore",
    "content": "/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.configuration\nBundle-SymbolicName: org.eclipse.kura.core.configuration;singleton:=true\nBundle-Version: 3.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: javax.crypto,\n javax.xml.namespace,\n javax.xml.parsers,\n javax.xml.stream,\n javax.xml.transform,\n javax.xml.transform.dom,\n javax.xml.transform.stream,\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.audit;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloud;version=\"[1.1,1.2)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,1.3)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.util;version=\"[2.0,3.0)\",\n org.eclipse.kura.crypto;version=\"[1.4,2.0)\",\n org.eclipse.kura.marshalling;version=\"[1.1,2.0)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.service;version=\"[1.0,2.0)\",\n org.eclipse.kura.wire;version=\"[2.0,3.0)\",\n org.eclipse.kura.wire.graph;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.cm;version=\"1.4.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.component.runtime;version=\"1.3.0\",\n org.osgi.service.component.runtime.dto;version=\"1.3.0\",\n org.osgi.service.event;version=\"1.3.0\",\n org.osgi.service.metatype;version=\"1.2.0\",\n org.osgi.util.tracker;version=\"[1.5.0,2.0.0)\",\n org.slf4j;version=\"1.6.4\",\n org.w3c.dom,\n org.xml.sax\nExport-Package: org.eclipse.kura.core.configuration;version=\"2.0.0\",\n org.eclipse.kura.core.configuration.metatype;version=\"1.0.0\",\n org.eclipse.kura.core.configuration.util;version=\"2.0.0\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/OSGI-INF/cloudConfigurationHandler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.core.configuration.CloudConfigurationHandler\">\n   <implementation class=\"org.eclipse.kura.core.configuration.CloudConfigurationHandler\"/>\n   <reference name=\"ConfigurationService\"\n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"setConfigurationService\"\n              unbind=\"unsetConfigurationService\"\n              interface=\"org.eclipse.kura.configuration.ConfigurationService\"/>\n   <reference name=\"SystemService\"\n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"setSystemService\"\n              unbind=\"unsetSystemService\"\n              interface=\"org.eclipse.kura.system.SystemService\"/>\n   <reference name=\"RequestHandlerRegistry\"\n              policy=\"dynamic\"\n              cardinality=\"0..n\" \n              bind=\"setRequestHandlerRegistry\"\n              unbind=\"unsetRequestHandlerRegistry\"\n              interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/OSGI-INF/configuration.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.4.0\" \n    activate=\"activate\" \n    deactivate=\"deactivate\" \n    enabled=\"true\" \n    immediate=\"true\" \n    name=\"org.eclipse.kura.configuration.ConfigurationService\">\n\n    <implementation class=\"org.eclipse.kura.core.configuration.ConfigurationServiceAuditFacade\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.configuration.ConfigurationService\"/>\n        <provide interface=\"org.eclipse.kura.configuration.metatype.OCDService\"/>\n    </service>\n\n    <property name=\"service.pid\" value=\"org.eclipse.kura.configuration.ConfigurationService\"/>\n\n    <reference  name=\"EventAdmin\" \n                bind=\"setEventAdmin\" \n                cardinality=\"1..1\" \n                interface=\"org.osgi.service.event.EventAdmin\"\n                policy=\"static\" />\n\n   <reference name=\"ConfigurationAdmin\"\n              bind=\"setConfigurationAdmin\"\n              cardinality=\"1..1\"\n              policy=\"static\"\n              interface=\"org.osgi.service.cm.ConfigurationAdmin\" />\n\n   <reference name=\"MetaTypeService\"\n              bind=\"setMetaTypeService\"\n              cardinality=\"1..1\"\n              policy=\"static\"\n              interface=\"org.osgi.service.metatype.MetaTypeService\" />\n\n   <reference name=\"SystemService\"\n              bind=\"setSystemService\"\n              cardinality=\"1..1\"\n              policy=\"static\"\n              interface=\"org.eclipse.kura.system.SystemService\" />\n\n   <reference name=\"CryptoService\"\n              interface=\"org.eclipse.kura.crypto.CryptoService\"\n              bind=\"setCryptoService\"\n              cardinality=\"1..1\"\n              policy=\"static\" />\n\n   <reference bind=\"setScrService\"\n              cardinality=\"1..1\"\n              interface=\"org.osgi.service.component.runtime.ServiceComponentRuntime\"\n              name=\"ScrService\"\n              policy=\"static\" />\n\n   <reference name=\"ConfigurableComponent\"\n              bind=\"addConfigurableComponent\"\n              cardinality=\"0..n\"\n              interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"\n              policy=\"dynamic\"\n              unbind=\"removeConfigurableComponent\" />\n\n   <reference bind=\"addSelfConfiguringComponent\"\n              cardinality=\"0..n\"\n              interface=\"org.eclipse.kura.configuration.SelfConfiguringComponent\"\n              name=\"SelfConfiguringComponent\"\n              policy=\"dynamic\"\n              unbind=\"removeSelfConfiguringComponent\" />\n\n   <reference bind=\"setXmlUnmarshaller\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.marshalling.Unmarshaller\"\n              name=\"Unmarshaller\"\n              policy=\"static\"\n              target=\"(kura.service.pid=org.eclipse.kura.xml.marshaller.unmarshaller.provider)\" />\n\n   <reference bind=\"setXmlMarshaller\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.marshalling.Marshaller\"\n              name=\"Marshaller\"\n              policy=\"static\"\n              target=\"(kura.service.pid=org.eclipse.kura.xml.marshaller.unmarshaller.provider)\" />\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/build.properties",
    "content": "bin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/,\\\n               OSGI-INF/cloudConfigurationHandler.xml\nsrc.includes = about.html,\\\n               about_files/\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.eclipse.osgi\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n     Red Hat Inc\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.configuration</artifactId>\n\t<version>3.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.core.configuration.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\t\n\t<build>\n\t\t<plugins>\n        \t<plugin>\n        \t\t<groupId>org.apache.maven.plugins</groupId>\n        \t\t<artifactId>maven-checkstyle-plugin</artifactId>\n        \t\t<configuration>\n        \t\t\t<skip>true</skip>\n        \t\t</configuration>\n        \t</plugin>\n        </plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/CloudConfigurationHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\n\nimport java.io.UnsupportedEncodingException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.audit.AuditContext.Scope;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerContext;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.eclipse.kura.system.SystemService;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @deprecated Please switch to CONF-V2 and corresponding REST APIs\n *             (https://eclipse-kura.github.io/kura/docs-release-5.6/references/rest-apis/rest-configuration-service-v2/)\n */\n@Deprecated\npublic class CloudConfigurationHandler implements RequestHandler {\n\n    private static final String EXPECTED_ONE_RESOURCE_BUT_FOUND_NONE_MESSAGE = \"Expected one resource but found none\";\n\n    private static final String EXPECTED_AT_MOST_TWO_RESOURCES_BUT_FOUND_MESSAGE = \"Expected at most two resource(s) but found {}\";\n\n    private static final String CANNOT_FIND_RESOURCE_WITH_NAME_MESSAGE = \"Cannot find resource with name: {}\";\n\n    private static final String BAD_REQUEST_TOPIC_MESSAGE = \"Bad request topic: {}\";\n\n    private static Logger logger = LoggerFactory.getLogger(CloudConfigurationHandler.class);\n\n    public static final String APP_ID = \"CONF-V1\";\n\n    /* GET or PUT */\n    public static final String RESOURCE_CONFIGURATIONS = \"configurations\";\n    /* GET */\n    public static final String RESOURCE_SNAPSHOTS = \"snapshots\";\n    /* EXEC */\n    public static final String RESOURCE_SNAPSHOT = \"snapshot\";\n    public static final String RESOURCE_ROLLBACK = \"rollback\";\n\n    private SystemService systemService;\n    private ConfigurationService configurationService;\n\n    private BundleContext bundleContext;\n\n    private ScheduledExecutorService executor;\n\n    protected void setConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    protected void unsetConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = null;\n    }\n\n    protected void setSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    protected void unsetSystemService(SystemService systemService) {\n        this.systemService = null;\n    }\n\n    public void setRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) {\n        try {\n            requestHandlerRegistry.registerRequestHandler(APP_ID, this);\n        } catch (KuraException e) {\n            logger.info(\"Unable to register cloudlet {} in {}\", APP_ID, requestHandlerRegistry.getClass().getName());\n        }\n    }\n\n    public void unsetRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) {\n        try {\n            requestHandlerRegistry.unregister(APP_ID);\n        } catch (KuraException e) {\n            logger.info(\"Unable to register cloudlet {} in {}\", APP_ID, requestHandlerRegistry.getClass().getName());\n        }\n    }\n\n    protected void activate(ComponentContext componentContext) {\n        this.bundleContext = componentContext.getBundleContext();\n        this.executor = Executors.newSingleThreadScheduledExecutor();\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        this.executor.shutdownNow();\n    }\n\n    @Override\n    public KuraMessage doGet(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException {\n\n        List<String> resources = getRequestResources(reqMessage);\n\n        if (resources.isEmpty()) {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(EXPECTED_ONE_RESOURCE_BUT_FOUND_NONE_MESSAGE);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        KuraPayload payload;\n        if (resources.get(0).equals(RESOURCE_CONFIGURATIONS)) {\n            payload = doGetConfigurations(resources);\n        } else if (resources.get(0).equals(RESOURCE_SNAPSHOTS)) {\n            payload = doGetSnapshots(resources);\n        } else {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(CANNOT_FIND_RESOURCE_WITH_NAME_MESSAGE, resources.get(0));\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n\n        return new KuraMessage(payload);\n    }\n\n    @Override\n    public KuraMessage doPut(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException {\n\n        List<String> resources = getRequestResources(reqMessage);\n\n        if (resources.isEmpty()) {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(EXPECTED_ONE_RESOURCE_BUT_FOUND_NONE_MESSAGE);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        KuraPayload payload;\n        if (resources.get(0).equals(RESOURCE_CONFIGURATIONS)) {\n            payload = doPutConfigurations(resources, reqMessage.getPayload());\n        } else {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(CANNOT_FIND_RESOURCE_WITH_NAME_MESSAGE, resources.get(0));\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n\n        return new KuraMessage(payload);\n    }\n\n    @Override\n    public KuraMessage doExec(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException {\n\n        List<String> resources = getRequestResources(reqMessage);\n\n        if (resources.isEmpty()) {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(EXPECTED_ONE_RESOURCE_BUT_FOUND_NONE_MESSAGE);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        KuraPayload payload;\n        if (resources.get(0).equals(RESOURCE_SNAPSHOT)) {\n            payload = doExecSnapshot(resources);\n        } else if (resources.get(0).equals(RESOURCE_ROLLBACK)) {\n            payload = doExecRollback(resources);\n        } else {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(CANNOT_FIND_RESOURCE_WITH_NAME_MESSAGE, resources.get(0));\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n\n        return new KuraMessage(payload);\n    }\n\n    private KuraPayload doGetSnapshots(List<String> resources) throws KuraException {\n\n        KuraResponsePayload responsePayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n\n        if (resources.size() > 2) {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(\"Expected one or two resource(s) but found {}\", resources.size());\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        String snapshotId = resources.size() == 2 ? resources.get(1) : null;\n\n        if (snapshotId != null) {\n            long sid = Long.parseLong(snapshotId);\n            XmlComponentConfigurations xmlConfigs = ((ConfigurationServiceImpl) this.configurationService)\n                    .loadEncryptedSnapshotFileContent(sid);\n            //\n            // marshall the response\n\n            List<ComponentConfiguration> configs = xmlConfigs.getConfigurations();\n            configs.forEach(config -> ((ConfigurationServiceImpl) this.configurationService)\n                    .decryptConfigurationProperties(config.getConfigurationProperties()));\n\n            byte[] body = toResponseBody(xmlConfigs);\n\n            //\n            // Build payload\n            responsePayload.setBody(body);\n        } else {\n            // get the list of snapshot IDs and put them into a response object\n            Set<Long> sids = null;\n            try {\n                sids = this.configurationService.getSnapshots();\n            } catch (KuraException e) {\n                logger.error(\"Error listing snapshots: {}\", e);\n                throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_LISTING, e);\n            }\n            List<Long> snapshotIds = new ArrayList<>(sids);\n            XmlSnapshotIdResult xmlResult = new XmlSnapshotIdResult();\n            xmlResult.setSnapshotIds(snapshotIds);\n\n            //\n            // marshall the response\n            byte[] body = toResponseBody(xmlResult);\n\n            //\n            // Build payload\n            responsePayload.setBody(body);\n        }\n        return responsePayload;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private List<String> getRequestResources(KuraMessage reqMessage) throws KuraException {\n        Object requestObject = reqMessage.getProperties().get(ARGS_KEY.value());\n        List<String> resources;\n        if (requestObject instanceof List) {\n            resources = (List<String>) requestObject;\n        } else {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n        return resources;\n    }\n\n    private KuraPayload doGetConfigurations(List<String> resources) throws KuraException {\n        if (resources.size() > 2) {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(EXPECTED_AT_MOST_TWO_RESOURCES_BUT_FOUND_MESSAGE, resources.size());\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n        String pid = resources.size() == 2 ? resources.get(1) : null;\n\n        //\n        // get current configuration with descriptors\n        List<ComponentConfiguration> configs = new ArrayList<>();\n        try {\n            if (pid == null) {\n                configs = getAllConfigurations();\n            } else {\n                configs = getConfiguration(pid);\n            }\n        } catch (KuraException e) {\n            logger.error(\"Error getting component configurations: {}\", e);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        XmlComponentConfigurations xmlConfigs = new XmlComponentConfigurations();\n        xmlConfigs.setConfigurations(configs);\n\n        //\n        // marshall\n        byte[] body = toResponseBody(xmlConfigs);\n\n        //\n        // Build response payload\n        KuraResponsePayload response = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        response.setBody(body);\n        return response;\n    }\n\n    private List<ComponentConfiguration> getConfiguration(String pid) throws KuraException {\n        List<ComponentConfiguration> configs = new ArrayList<>();\n        ComponentConfiguration cc = this.configurationService.getComponentConfiguration(pid);\n        if (cc != null) {\n            configs.add(cc);\n        }\n        return configs;\n    }\n\n    private List<ComponentConfiguration> getAllConfigurations() {\n\n        List<ComponentConfiguration> configs = new ArrayList<>();\n        List<String> pidsToIgnore = this.systemService.getDeviceManagementServiceIgnore();\n\n        // the configuration for all components has been requested\n        Set<String> componentPids = this.configurationService.getConfigurableComponentPids();\n        if (pidsToIgnore != null) {\n            Set<String> filteredComponentPids = componentPids.stream()\n                    .filter(((Predicate<String>) pidsToIgnore::contains).negate()).collect(Collectors.toSet());\n            filteredComponentPids.forEach(componentPid -> {\n                ComponentConfiguration cc;\n                try {\n                    cc = this.configurationService.getComponentConfiguration(componentPid);\n\n                    // TODO: define a validate method for ComponentConfiguration\n                    if (cc == null) {\n                        logger.error(\"null ComponentConfiguration\");\n                        return;\n                    }\n                    if (cc.getPid() == null || cc.getPid().isEmpty()) {\n                        logger.error(\"null or empty ComponentConfiguration PID\");\n                        return;\n                    }\n                    if (cc.getDefinition() == null) {\n                        logger.error(\"null OCD for ComponentConfiguration PID {}\", cc.getPid());\n                        return;\n                    }\n                    if (cc.getDefinition().getId() == null || cc.getDefinition().getId().isEmpty()) {\n\n                        logger.error(\"null or empty OCD ID for ComponentConfiguration PID {}. OCD ID: {}\", cc.getPid(),\n                                cc.getDefinition().getId());\n                        return;\n                    }\n                    configs.add(cc);\n                } catch (KuraException e) {\n                    // Nothing needed here\n                }\n\n            });\n        }\n        return configs;\n    }\n\n    private KuraPayload doPutConfigurations(List<String> resources, KuraPayload reqPayload) throws KuraException {\n\n        if (resources.size() > 2) {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(EXPECTED_AT_MOST_TWO_RESOURCES_BUT_FOUND_MESSAGE, resources.size());\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        String pid = resources.size() == 2 ? resources.get(1) : null;\n\n        XmlComponentConfigurations xmlConfigs = null;\n        try {\n\n            // unmarshall the response\n            if (reqPayload.getBody() == null || reqPayload.getBody().length == 0) {\n                throw new IllegalArgumentException(\"body\");\n            }\n\n            String s = new String(reqPayload.getBody(), \"UTF-8\");\n            logger.info(\"Received new Configuration\");\n\n            xmlConfigs = unmarshal(s, XmlComponentConfigurations.class);\n        } catch (Exception e) {\n            logger.error(\"Error unmarshalling the request body: {}\", e);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        this.executor.schedule(new UpdateConfigurationsCallable(pid, xmlConfigs, this.configurationService), 1000,\n                TimeUnit.MILLISECONDS);\n\n        return new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n    }\n\n    private KuraPayload doExecRollback(List<String> resources) throws KuraException {\n        if (resources.size() > 2) {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(EXPECTED_AT_MOST_TWO_RESOURCES_BUT_FOUND_MESSAGE, resources.size());\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        String snapshotId = resources.size() == 2 ? resources.get(1) : null;\n        Long sid;\n        try {\n            sid = snapshotId != null ? Long.parseLong(snapshotId) : null;\n        } catch (NumberFormatException e) {\n            logger.error(\"Bad numeric numeric format for snapshot ID: {}\", snapshotId);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        this.executor.schedule(new RollbackCallable(sid, this.configurationService), 1000, TimeUnit.MILLISECONDS);\n\n        return new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n    }\n\n    private KuraPayload doExecSnapshot(List<String> resources) throws KuraException {\n\n        if (resources.size() > 1) {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(\"Expected one resource(s) but found {}\", resources.size());\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        // take a new snapshot and get the id\n        long snapshotId;\n        try {\n            snapshotId = this.configurationService.snapshot();\n        } catch (KuraException e) {\n            logger.error(\"Error taking snapshot: {}\", e);\n            throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_TAKING, e);\n        }\n        List<Long> snapshotIds = new ArrayList<>();\n        snapshotIds.add(snapshotId);\n        XmlSnapshotIdResult xmlResult = new XmlSnapshotIdResult();\n        xmlResult.setSnapshotIds(snapshotIds);\n\n        byte[] body = toResponseBody(xmlResult);\n\n        KuraResponsePayload responsePayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        responsePayload.setBody(body);\n        return responsePayload;\n    }\n\n    private byte[] toResponseBody(Object o) throws KuraException {\n        //\n        // marshall the response\n        String result = null;\n        try {\n            result = marshal(o);\n        } catch (Exception e) {\n            logger.error(\"Error marshalling snapshots: {}\", e);\n            throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_LOADING, e);\n        }\n\n        byte[] body = null;\n        try {\n            body = result.getBytes(\"UTF-8\");\n        } catch (UnsupportedEncodingException e) {\n            logger.error(\"Error encoding response body: {}\", e);\n            throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_LOADING, e);\n        }\n\n        return body;\n    }\n\n    private ServiceReference<Marshaller>[] getXmlMarshallers() {\n        String filterString = String.format(\"(&(kura.service.pid=%s))\",\n                \"org.eclipse.kura.xml.marshaller.unmarshaller.provider\");\n        return ServiceUtil.getServiceReferences(this.bundleContext, Marshaller.class, filterString);\n    }\n\n    private ServiceReference<Unmarshaller>[] getXmlUnmarshallers() {\n        String filterString = String.format(\"(&(kura.service.pid=%s))\",\n                \"org.eclipse.kura.xml.marshaller.unmarshaller.provider\");\n        return ServiceUtil.getServiceReferences(this.bundleContext, Unmarshaller.class, filterString);\n    }\n\n    private void ungetServiceReferences(final ServiceReference<?>[] refs) {\n        ServiceUtil.ungetServiceReferences(this.bundleContext, refs);\n    }\n\n    protected <T> T unmarshal(String xmlString, Class<T> clazz) throws KuraException {\n        T result = null;\n        ServiceReference<Unmarshaller>[] unmarshallerSRs = getXmlUnmarshallers();\n        try {\n            for (final ServiceReference<Unmarshaller> unmarshallerSR : unmarshallerSRs) {\n                Unmarshaller unmarshaller = this.bundleContext.getService(unmarshallerSR);\n                result = unmarshaller.unmarshal(xmlString, clazz);\n                if (result != null) {\n                    break;\n                }\n            }\n        } catch (Exception e) {\n            logger.warn(\"Failed to extract persisted configuration.\");\n        } finally {\n            ungetServiceReferences(unmarshallerSRs);\n        }\n        if (result == null) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, \"value\");\n        }\n        return result;\n    }\n\n    protected String marshal(Object object) {\n        String result = null;\n        ServiceReference<Marshaller>[] marshallerSRs = getXmlMarshallers();\n        try {\n            for (final ServiceReference<Marshaller> marshallerSR : marshallerSRs) {\n                Marshaller marshaller = this.bundleContext.getService(marshallerSR);\n                result = marshaller.marshal(object);\n                if (result != null) {\n                    break;\n                }\n            }\n        } catch (Exception e) {\n            logger.warn(\"Failed to marshal configuration.\");\n        } finally {\n            ungetServiceReferences(marshallerSRs);\n        }\n        return result;\n    }\n}\n\nclass UpdateConfigurationsCallable implements Callable<Void> {\n\n    private static Logger logger = LoggerFactory.getLogger(UpdateConfigurationsCallable.class);\n\n    private final String pid;\n    private final XmlComponentConfigurations xmlConfigurations;\n    private final ConfigurationService configurationService;\n    private final AuditContext auditContext;\n\n    public UpdateConfigurationsCallable(String pid, XmlComponentConfigurations xmlConfigurations,\n            ConfigurationService configurationService) {\n        this.pid = pid;\n        this.xmlConfigurations = xmlConfigurations;\n        this.configurationService = configurationService;\n        this.auditContext = AuditContext.currentOrInternal();\n    }\n\n    @Override\n    public Void call() throws Exception {\n\n        logger.info(\"Updating configurations\");\n        Thread.currentThread().setName(getClass().getSimpleName());\n        //\n        // update the configuration\n        try (final Scope scope = AuditContext.openScope(this.auditContext)) {\n            List<ComponentConfiguration> configImpls = this.xmlConfigurations != null\n                    ? this.xmlConfigurations.getConfigurations()\n                    : null;\n            if (configImpls == null) {\n                return null;\n            }\n\n            List<ComponentConfiguration> configs = new ArrayList<>();\n            configs.addAll(configImpls);\n\n            if (this.pid == null) {\n                // update all the configurations provided\n                this.configurationService.updateConfigurations(configs);\n            } else {\n                // update only the configuration with the provided id\n                for (ComponentConfiguration config : configs) {\n                    if (this.pid.equals(config.getPid())) {\n                        this.configurationService.updateConfiguration(this.pid, config.getConfigurationProperties());\n                    }\n                }\n            }\n        } catch (KuraException e) {\n            logger.error(\"Error updating configurations: {}\", e);\n            throw new KuraException(KuraErrorCode.CONFIGURATION_UPDATE, e);\n        }\n\n        return null;\n    }\n}\n\nclass RollbackCallable implements Callable<Void> {\n\n    private static Logger logger = LoggerFactory.getLogger(RollbackCallable.class);\n\n    private final Long snapshotId;\n    private final ConfigurationService configurationService;\n    private final AuditContext auditContext;\n\n    public RollbackCallable(Long snapshotId, ConfigurationService configurationService) {\n        super();\n        this.snapshotId = snapshotId;\n        this.configurationService = configurationService;\n        this.auditContext = AuditContext.currentOrInternal();\n    }\n\n    @Override\n    public Void call() throws Exception {\n        Thread.currentThread().setName(getClass().getSimpleName());\n        // rollback to the specified snapshot if any\n        try (final Scope scope = AuditContext.openScope(this.auditContext)) {\n            if (this.snapshotId == null) {\n                this.configurationService.rollback();\n            } else {\n                this.configurationService.rollback(this.snapshotId);\n            }\n        } catch (KuraException e) {\n            logger.error(\"Error rolling back to snapshot: {}\", e);\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ROLLBACK, e);\n        }\n\n        return null;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ComponentConfigurationImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.core.configuration.metatype.Tocd;\n\npublic class ComponentConfigurationImpl implements ComponentConfiguration {\n\n    protected String pid;\n\n    protected Tocd definition;\n\n    protected Map<String, Object> properties;\n\n    /**\n     * Default constructor. Does not initialize any of the fields.\n     */\n    // Required by JAXB\n    public ComponentConfigurationImpl() {\n    }\n\n    public ComponentConfigurationImpl(String pid, Tocd definition, Map<String, Object> properties) {\n        super();\n        this.pid = pid;\n        this.definition = definition;\n        this.properties = properties;\n    }\n\n    @Override\n    public String getPid() {\n        return this.pid;\n    }\n\n    @Override\n    public Tocd getDefinition() {\n        return this.definition;\n    }\n\n    @Override\n    public Map<String, Object> getConfigurationProperties() {\n        return this.properties;\n    }\n\n    public void setPid(String pid) {\n        this.pid = pid;\n    }\n\n    public void setDefinition(Tocd definition) {\n        this.definition = definition;\n    }\n\n    public void setProperties(Map<String, Object> properties) {\n        this.properties = properties;\n    }\n\n    @Override\n    public String toString() {\n        return \"ComponentConfigurationImpl [pid=\" + this.pid + \", definition=\" + this.definition + \", properties=\"\n                + this.properties + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ComponentMetaTypeBundleTracker.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.metatype.Designate;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.core.configuration.metatype.Tmetadata;\nimport org.eclipse.kura.core.configuration.metatype.Tocd;\nimport org.eclipse.kura.core.configuration.util.ComponentUtil;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.BundleEvent;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.util.tracker.BundleTracker;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * BundleTracker to track all the Service which have defaults in MetaType.\n * When the ConfigurableComponet is found it is then registered to the ConfigurationService.\n */\npublic class ComponentMetaTypeBundleTracker extends BundleTracker<Bundle> {\n\n    private static final Logger s_logger = LoggerFactory.getLogger(ComponentMetaTypeBundleTracker.class);\n\n    private final BundleContext m_context;\n    private final ConfigurationServiceImpl m_configurationService;\n\n    public ComponentMetaTypeBundleTracker(BundleContext context, ConfigurationServiceImpl configurationService)\n            throws InvalidSyntaxException {\n        super(context, Bundle.ACTIVE, null);\n        this.m_context = context;\n        this.m_configurationService = configurationService;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Override APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public Bundle addingBundle(Bundle bundle, BundleEvent event) {\n        Bundle bnd = super.addingBundle(bundle, event);\n        s_logger.debug(\"addingBundle(): processing MetaType for bundle: {}...\", bundle.getSymbolicName());\n        processBundleMetaType(bundle);\n        s_logger.debug(\"addingBundle(): processed MetaType for bundle: {}\", bundle.getSymbolicName());\n        return bnd;\n    }\n\n    @Override\n    public void removedBundle(Bundle bundle, BundleEvent event, Bundle object) {\n        super.removedBundle(bundle, event, object);\n        this.m_configurationService.onBundleRemoved(bundle);\n    }\n    // ----------------------------------------------------------------\n    //\n    // Private APIs\n    //\n    // ----------------------------------------------------------------\n\n    private void processBundleMetaType(Bundle bundle) {\n        // Push the latest configuration merging the properties in ConfigAdmin\n        // with the default properties read from the component's meta-type.\n        // This allows components to incrementally add new configuration\n        // properties in the meta-type.\n        // Only the new default properties are merged with the configuration\n        // properties in ConfigurationAdmin.\n        // Note: configuration properties in snapshots no longer present in\n        // the meta-type are not purged.\n\n        Map<String, Tmetadata> metas = ComponentUtil.getMetadata(this.m_context, bundle);\n        for (String metatypePid : metas.keySet()) {\n            try {\n\n                // register the OCD for all the contained services\n                Tmetadata metadata = metas.get(metatypePid);\n                if (metadata != null) {\n\n                    // check if this component is a factory\n                    boolean isFactory = false;\n                    Designate designate = ComponentUtil.getDesignate(metadata, metatypePid);\n                    if (designate.getFactoryPid() != null && !designate.getFactoryPid().isEmpty()) {\n                        isFactory = true;\n                        metatypePid = designate.getFactoryPid();\n                    }\n\n                    // register the pid with the OCD and whether it is a factory\n                    OCD ocd = ComponentUtil.getOCD(metadata, metatypePid);\n                    this.m_configurationService.registerComponentOCD(metatypePid, (Tocd) ocd, isFactory, bundle);\n                }\n            } catch (Exception e) {\n                s_logger.error(\"Error seeding configuration for pid: \" + metatypePid, e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurableComponentTracker.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.SelfConfiguringComponent;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * ServiceTracker to track all the ConfigurabaleComponents.\n * When the ConfigurableComponet is found it is then registered to the ConfigurationService.\n */\n\n@SuppressWarnings(\"rawtypes\")\npublic class ConfigurableComponentTracker extends ServiceTracker {\n\n    private static final Logger s_logger = LoggerFactory.getLogger(ConfigurableComponentTracker.class);\n\n    private final ConfigurationServiceImpl m_confService;\n\n    @SuppressWarnings(\"unchecked\")\n    public ConfigurableComponentTracker(BundleContext context, ConfigurationServiceImpl confService)\n            throws InvalidSyntaxException {\n        // super(context, (String) null, null); // Wrong: throws an exception\n        // super(context, \"\", null); // Wrong: does not track anything\n        // super(context, \"org.eclipse.kura..example.publisher.ExamplePublisher\", null); // tracks the specified class\n        // but of course we cannot use this\n        // super(context, (ServiceReference) null, null); // Wrong: throws an exception\n        // super(context, SelfConfiguringComponent.class, null); // Wrong: does not track anything\n        // super(context, context.createFilter(\"(\" + Constants.OBJECTCLASS +\n        // \"=\"+SelfConfiguringComponent.class.getName()+\")\"), null); // No\n        // super(context, context.createFilter(\"(\" + Constants.SERVICE_EXPORTED_INTERFACES +\n        // \"=\"+SelfConfiguringComponent.class.getName()+\")\"), null); // Track nothing. Export the interface?\n\n        // TODO: find a better filter\n        // This works but we track everything\n        super(context, context.createFilter(\"(\" + Constants.OBJECTCLASS + \"=*)\"), null);\n\n        this.m_confService = confService;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Override APIs\n    //\n    // ----------------------------------------------------------------\n\n    @SuppressWarnings({ \"unchecked\" })\n    @Override\n    public void open(boolean trackAllServices) {\n        s_logger.info(\"Opening ServiceTracker\");\n        super.open(trackAllServices);\n        try {\n            s_logger.info(\"Getting ServiceReferences\");\n            ServiceReference[] refs = this.context.getServiceReferences((String) null, null);\n            if (refs != null) {\n                for (ServiceReference ref : refs) {\n                    String servicePid = (String) ref.getProperty(Constants.SERVICE_PID);\n                    String pid = (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID);\n                    String factoryPid = (String) ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID);\n\n                    if (servicePid != null) {\n                        Object obj = this.context.getService(ref);\n                        try {\n                            if (obj == null) {\n                                s_logger.info(\"Could not find service for: {}\", ref);\n                            } else if (obj instanceof ConfigurableComponent) {\n                                s_logger.info(\n                                        \"Adding ConfigurableComponent with pid {}, service pid {} and factory pid \"\n                                                + factoryPid,\n                                        pid, servicePid);\n                                this.m_confService.registerComponentConfiguration(pid, servicePid, factoryPid);\n                            } else if (obj instanceof SelfConfiguringComponent) {\n                                s_logger.info(\"Adding SelfConfiguringComponent with pid {} and service pid {}\", pid,\n                                        servicePid);\n                                this.m_confService.registerSelfConfiguringComponent(pid, servicePid);\n                            }\n                        } finally {\n                            this.context.ungetService(ref);\n                        }\n                    }\n                }\n            }\n        } catch (InvalidSyntaxException ise) {\n            s_logger.error(\"Error in addingBundle\", ise);\n        }\n    }\n\n    @SuppressWarnings({ \"unchecked\" })\n    @Override\n    public Object addingService(ServiceReference ref) {\n        Object service = super.addingService(ref);\n\n        String servicePid = (String) ref.getProperty(Constants.SERVICE_PID);\n        String pid = (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID);\n        String factoryPid = (String) ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID);\n\n        if (servicePid != null) {\n            if (service instanceof ConfigurableComponent) {\n                s_logger.info(\"Adding ConfigurableComponent with pid {}, service pid {} and factory pid \" + factoryPid,\n                        pid, servicePid);\n                this.m_confService.registerComponentConfiguration(pid, servicePid, factoryPid);\n            } else if (service instanceof SelfConfiguringComponent) {\n                s_logger.info(\"Adding SelfConfiguringComponent with pid {} and service pid {}\", pid, servicePid);\n                this.m_confService.registerSelfConfiguringComponent(pid, servicePid);\n            }\n        }\n\n        return service;\n    }\n\n    @SuppressWarnings({ \"unchecked\" })\n    @Override\n    public void removedService(ServiceReference reference, Object service) {\n        super.removedService(reference, service);\n\n        String servicePid = (String) reference.getProperty(Constants.SERVICE_PID);\n        String pid = (String) reference.getProperty(ConfigurationService.KURA_SERVICE_PID);\n\n        if (service instanceof ConfigurableComponent) {\n            s_logger.info(\"Removed ConfigurableComponent with pid {} and service pid {}\", pid, servicePid);\n            this.m_confService.unregisterComponentConfiguration(pid);\n        } else if (service instanceof SelfConfiguringComponent) {\n            s_logger.info(\"Removed SelfConfiguringComponent with pid {} and service pid {}\", pid, servicePid);\n            this.m_confService.unregisterComponentConfiguration(servicePid);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationChangeEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport java.util.Map;\n\nimport org.osgi.service.event.Event;\n\npublic class ConfigurationChangeEvent extends Event {\n\n    public static final String CONF_CHANGE_EVENT_TOPIC = \"org/eclipse/kura/core/configuration/event/CONF_CHANGE_EVENT_TOPIC\";\n    public static final String CONF_CHANGE_EVENT_SESSION_PROP = \"session\";\n    public static final String CONF_CHANGE_EVENT_PID_PROP = \"pid\";\n\n    public ConfigurationChangeEvent(Map<String, ?> properties) {\n        super(CONF_CHANGE_EVENT_TOPIC, properties);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceAuditFacade.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.osgi.framework.Filter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ConfigurationServiceAuditFacade extends ConfigurationServiceImpl {\n\n    private static final String CONFIGURATION_SERVICE_FAILURE = \"{} ConfigurationService - Failure - {}\";\n    private static final String CONFIGURATION_SERVICE_SUCCESS = \"{} ConfigurationService - Success - {}\";\n    private static final Logger auditLogger = LoggerFactory.getLogger(\"AuditLogger\");\n\n    @Override\n    public synchronized void createFactoryConfiguration(String factoryPid, String pid, Map<String, Object> properties,\n            boolean takeSnapshot) throws KuraException {\n        audit(() -> super.createFactoryConfiguration(factoryPid, pid, properties, takeSnapshot),\n                \"Create factory configuration \" + factoryPid + \" \" + pid);\n        postConfigurationChangedEvent(pid);\n    }\n\n    @Override\n    public synchronized void deleteFactoryConfiguration(String pid, boolean takeSnapshot) throws KuraException {\n        audit(() -> super.deleteFactoryConfiguration(pid, takeSnapshot), \"Delete factory configuration: \" + pid);\n        postConfigurationChangedEvent(pid);\n    }\n\n    @Override\n    public List<ComponentConfiguration> getComponentConfigurations() throws KuraException {\n        return audit(() -> super.getComponentConfigurations(), \"Get component configurations\");\n    }\n\n    @Override\n    public List<ComponentConfiguration> getComponentConfigurations(Filter filter) throws KuraException {\n        return audit(() -> super.getComponentConfigurations(filter), \"Get component configurations: \" + filter);\n    }\n\n    @Override\n    public ComponentConfiguration getComponentConfiguration(String pid) throws KuraException {\n        return audit(() -> super.getComponentConfiguration(pid), \"Get component configuration: \" + pid);\n    }\n\n    @Override\n    public synchronized void updateConfiguration(String pid, Map<String, Object> properties) throws KuraException {\n        audit(() -> super.updateConfiguration(pid, properties), \"Update configuration: \" + pid);\n        postConfigurationChangedEvent(pid);\n    }\n\n    @Override\n    public synchronized void updateConfiguration(String pid, Map<String, Object> properties, boolean takeSnapshot)\n            throws KuraException {\n        audit(() -> super.updateConfiguration(pid, properties, takeSnapshot), \"Update configuration: \" + pid);\n        postConfigurationChangedEvent(pid);\n    }\n\n    @Override\n    public synchronized void updateConfigurations(List<ComponentConfiguration> configs) throws KuraException {\n        audit(() -> super.updateConfigurations(configs), \"Update configurations: \" + formatConfigurationPids(configs));\n        postConfigurationChangedEvent(formatConfigurationPids(configs));\n    }\n\n    @Override\n    public synchronized void updateConfigurations(List<ComponentConfiguration> configs, boolean takeSnapshot)\n            throws KuraException {\n        audit(() -> super.updateConfigurations(configs, takeSnapshot),\n                \"Update configurations: \" + formatConfigurationPids(configs));\n        postConfigurationChangedEvent(formatConfigurationPids(configs));\n    }\n\n    @Override\n    public List<ComponentConfiguration> getSnapshot(long sid) throws KuraException {\n        return audit(() -> super.getSnapshot(sid), \"Get snapshot: \" + sid);\n    }\n\n    @Override\n    public long snapshot() throws KuraException {\n        postConfigurationChangedEvent(\"\");\n        return audit(super::snapshot, \"Take snapshot\");\n    }\n\n    @Override\n    public long rollback() throws KuraException {\n        postConfigurationChangedEvent(\"\");\n        return audit(() -> super.rollback(), \"Rollback latest snapshot\");\n    }\n\n    @Override\n    public synchronized void rollback(long id) throws KuraException {\n        audit(() -> super.rollback(id), \"Rollback snapshot: \" + id);\n        postConfigurationChangedEvent(\"\");\n    }\n\n    private static <T, E extends Throwable> T audit(final FallibleSupplier<T, E> task, final String message) throws E {\n        try {\n            final T result = task.get();\n            auditLogger.info(CONFIGURATION_SERVICE_SUCCESS, AuditContext.currentOrInternal(), message);\n            return result;\n        } catch (final Exception e) {\n            auditLogger.warn(CONFIGURATION_SERVICE_FAILURE, AuditContext.currentOrInternal(), message);\n            throw e;\n        }\n    }\n\n    private static <E extends Throwable> void audit(final FallibleTask<E> task, final String message) throws E {\n        try {\n            task.run();\n            auditLogger.info(CONFIGURATION_SERVICE_SUCCESS, AuditContext.currentOrInternal(), message);\n        } catch (final Exception e) {\n            auditLogger.warn(CONFIGURATION_SERVICE_FAILURE, AuditContext.currentOrInternal(), message);\n            throw e;\n        }\n    }\n\n    private String formatConfigurationPids(final List<ComponentConfiguration> configs) {\n        return configs.stream().map(ComponentConfiguration::getPid).reduce(\"\", (a, b) -> a + \" \" + b);\n    }\n\n    private interface FallibleSupplier<T, E extends Throwable> {\n\n        public T get() throws E;\n    }\n\n    private interface FallibleTask<E extends Throwable> {\n\n        public void run() throws E;\n    }\n\n    private void postConfigurationChangedEvent(String pid) {\n        Optional<AuditContext> auditContext = AuditContext.current();\n\n        if (auditContext.isPresent()) {\n            String sessionId = auditContext.get().getProperties().get(\"session.id\");\n\n            Map<String, String> properties = new HashMap<>();\n            properties.put(ConfigurationChangeEvent.CONF_CHANGE_EVENT_PID_PROP, pid);\n            properties.put(ConfigurationChangeEvent.CONF_CHANGE_EVENT_SESSION_PROP, sessionId);\n\n            if (sessionId != null) {\n                this.eventAdmin.postEvent(new ConfigurationChangeEvent(properties));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport static java.util.Objects.isNull;\nimport static java.util.Objects.requireNonNull;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardCopyOption;\nimport java.nio.file.attribute.PosixFilePermission;\nimport java.nio.file.attribute.PosixFilePermissions;\nimport java.util.Set;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.SortedSet;\nimport java.util.TreeSet;\nimport java.util.function.Function;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraIOException;\nimport org.eclipse.kura.KuraPartialSuccessException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.configuration.SelfConfiguringComponent;\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.configuration.metatype.OCDService;\nimport org.eclipse.kura.configuration.metatype.Scalar;\nimport org.eclipse.kura.core.configuration.metatype.Tocd;\nimport org.eclipse.kura.core.configuration.upgrade.ConfigurationUpgrade;\nimport org.eclipse.kura.core.configuration.util.CollectionsUtil;\nimport org.eclipse.kura.core.configuration.util.ComponentUtil;\nimport org.eclipse.kura.core.configuration.util.StringUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.system.SystemService;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.component.ComponentException;\nimport org.osgi.service.component.runtime.ServiceComponentRuntime;\nimport org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;\nimport org.osgi.service.event.EventAdmin;\nimport org.osgi.service.metatype.AttributeDefinition;\nimport org.osgi.service.metatype.MetaTypeService;\nimport org.osgi.service.metatype.ObjectClassDefinition;\nimport org.osgi.util.tracker.BundleTracker;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Implementation of ConfigurationService.\n */\npublic class ConfigurationServiceImpl implements ConfigurationService, OCDService {\n\n    private static final String GETTING_CONFIGURATION_ERROR = \"Error getting Configuration for component: {}. Ignoring it.\";\n\n    private static final Logger logger = LoggerFactory.getLogger(ConfigurationServiceImpl.class);\n    private static final Pattern SNAPSHOT_FILENAME_PATTERN = Pattern.compile(\"snapshot_(\\\\d+)\\\\.xml\");\n\n    private ComponentContext ctx;\n    private BundleContext bundleContext;\n\n    private BundleTracker<Bundle> bundleTracker;\n\n    @SuppressWarnings(\"unused\")\n    private MetaTypeService metaTypeService;\n    private ConfigurationAdmin configurationAdmin;\n    private SystemService systemService;\n    private CryptoService cryptoService;\n    private ServiceComponentRuntime scrService;\n    private Marshaller xmlMarshaller;\n    private Unmarshaller xmlUnmarshaller;\n    protected EventAdmin eventAdmin;\n\n    // contains all the PIDs (aka kura.service.pid) - both of configurable and self\n    // configuring components\n    private final Set<String> allActivatedPids;\n\n    // contains the self configuring components ONLY!\n    private final Set<String> activatedSelfConfigComponents;\n\n    // maps either service.pid or service.factoryPid to the related OCD\n    private final Map<String, Tocd> ocds;\n\n    // contains the service.factoryPid of all Factory Components\n    private final Set<TrackedComponentFactory> factoryPids;\n\n    // maps the kura.service.pid to the associated service.factoryPid\n    private final Map<String, String> factoryPidByPid;\n\n    // contains all the pids (kura.service.pid) which have to be deleted\n    private final Set<String> pendingDeletePids;\n\n    // maps the kura.service.pid to the associated service.pid\n    private final Map<String, String> servicePidByPid;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setConfigurationAdmin(ConfigurationAdmin configAdmin) {\n        this.configurationAdmin = configAdmin;\n    }\n\n    public void setMetaTypeService(MetaTypeService metaTypeService) {\n        this.metaTypeService = metaTypeService;\n    }\n\n    public void setSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    public void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void setScrService(ServiceComponentRuntime scrService) {\n        this.scrService = scrService;\n    }\n\n    public void setXmlMarshaller(final Marshaller marshaller) {\n        this.xmlMarshaller = marshaller;\n    }\n\n    public void setXmlUnmarshaller(final Unmarshaller unmarshaller) {\n        this.xmlUnmarshaller = unmarshaller;\n    }\n\n    public void setEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    public ConfigurationServiceImpl() {\n        this.allActivatedPids = new HashSet<>();\n        this.activatedSelfConfigComponents = new HashSet<>();\n        this.pendingDeletePids = new HashSet<>();\n        this.ocds = new HashMap<>();\n        this.factoryPids = new HashSet<>();\n        this.factoryPidByPid = new HashMap<>();\n        this.servicePidByPid = new HashMap<>();\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) throws InvalidSyntaxException {\n        logger.info(\"activate...\");\n\n        // save the bundle context\n        this.ctx = componentContext;\n        this.bundleContext = componentContext.getBundleContext();\n\n        // Load the latest snapshot and push it to ConfigurationAdmin\n        try {\n            loadLatestSnapshotInConfigAdmin();\n        } catch (Exception e) {\n            throw new ComponentException(\"Error loading latest snapshot\", e);\n        }\n\n        this.bundleTracker = new ComponentMetaTypeBundleTracker(this.ctx.getBundleContext(), this);\n        this.bundleTracker.open();\n    }\n\n    protected void addConfigurableComponent(final ServiceReference<ConfigurableComponent> reference) {\n\n        final String servicePid = makeString(reference.getProperty(Constants.SERVICE_PID));\n\n        if (servicePid == null) {\n            return;\n        }\n\n        final String kuraPid = makeString(reference.getProperty(ConfigurationService.KURA_SERVICE_PID));\n        final String factoryPid = makeString(reference.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID));\n\n        registerComponentConfiguration(kuraPid, servicePid, factoryPid);\n    }\n\n    protected void removeConfigurableComponent(final ServiceReference<ConfigurableComponent> reference) {\n\n        final String servicePid = makeString(reference.getProperty(Constants.SERVICE_PID));\n\n        if (servicePid == null) {\n            return;\n        }\n\n        final String kuraPid = makeString(reference.getProperty(ConfigurationService.KURA_SERVICE_PID));\n\n        unregisterComponentConfiguration(kuraPid);\n    }\n\n    protected void addSelfConfiguringComponent(final ServiceReference<SelfConfiguringComponent> reference) {\n\n        final String servicePid = makeString(reference.getProperty(Constants.SERVICE_PID));\n\n        if (servicePid == null) {\n            return;\n        }\n\n        final String kuraPid = makeString(reference.getProperty(ConfigurationService.KURA_SERVICE_PID));\n\n        registerSelfConfiguringComponent(kuraPid, servicePid);\n    }\n\n    protected void removeSelfConfiguringComponent(final ServiceReference<SelfConfiguringComponent> reference) {\n\n        final String servicePid = makeString(reference.getProperty(Constants.SERVICE_PID));\n\n        if (servicePid == null) {\n            return;\n        }\n\n        final String kuraPid = makeString(reference.getProperty(ConfigurationService.KURA_SERVICE_PID));\n\n        unregisterComponentConfiguration(kuraPid);\n\n    }\n\n    protected void deactivate() {\n        logger.info(\"deactivate...\");\n\n        if (this.bundleTracker != null) {\n            this.bundleTracker.close();\n            this.bundleTracker = null;\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public Set<String> getConfigurableComponentPids() {\n        if (this.allActivatedPids.isEmpty()) {\n            return Collections.emptySet();\n        }\n        return Collections.unmodifiableSet(this.allActivatedPids);\n    }\n\n    // Don't perform internal calls to this method\n    @Override\n    public List<ComponentConfiguration> getComponentConfigurations() throws KuraException {\n        return getComponentConfigurationsInternal();\n    }\n\n    @Override\n    public List<ComponentConfiguration> getComponentConfigurations(final Filter filter) throws KuraException {\n\n        if (filter == null) {\n            return getComponentConfigurationsInternal();\n        }\n\n        try {\n            final ServiceReference<?>[] refs = this.bundleContext.getAllServiceReferences(null, null);\n            final List<ComponentConfiguration> result = new ArrayList<>(refs.length);\n\n            for (final ServiceReference<?> ref : refs) {\n\n                if (!filter.match(ref)) {\n                    continue;\n                }\n\n                final Object kuraServicePid = ref.getProperty(KURA_SERVICE_PID);\n\n                if (kuraServicePid instanceof String) {\n                    final ComponentConfiguration config = getComponentConfigurationInternal((String) kuraServicePid);\n\n                    if (config != null) {\n                        result.add(config);\n                    }\n                }\n            }\n\n            return result;\n        } catch (final Exception e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e);\n        }\n\n    }\n\n    // Don't perform internal calls to this method\n    @Override\n    public ComponentConfiguration getComponentConfiguration(String pid) throws KuraException {\n        ComponentConfiguration tempConfig = getComponentConfigurationInternal(pid);\n        if (tempConfig != null && tempConfig.getConfigurationProperties() != null) {\n            decryptConfigurationProperties(tempConfig.getConfigurationProperties());\n        }\n        return tempConfig;\n    }\n\n    @Override\n    public synchronized void updateConfiguration(String pidToUpdate, Map<String, Object> propertiesToUpdate)\n            throws KuraException { // don't call this method internally\n        updateConfiguration(pidToUpdate, propertiesToUpdate, true);\n    }\n\n    @Override\n    public synchronized void updateConfiguration(String pidToUpdate, Map<String, Object> propertiesToUpdate,\n            boolean takeSnapshot) throws KuraException { // don't call this method internally\n        List<ComponentConfiguration> configs = new ArrayList<>();\n        ComponentConfigurationImpl cci = new ComponentConfigurationImpl(pidToUpdate, null, propertiesToUpdate);\n        configs.add(cci);\n        updateConfigurations(configs, takeSnapshot);\n    }\n\n    // Don't perform internal calls to this method\n    @Override\n    public synchronized void updateConfigurations(List<ComponentConfiguration> configsToUpdate) throws KuraException {\n        updateConfigurations(configsToUpdate, true);\n    }\n\n    @Override\n    public synchronized void updateConfigurations(List<ComponentConfiguration> configsToUpdate, boolean takeSnapshot)\n            throws KuraException { // don't call this method internally\n        for (ComponentConfiguration config : configsToUpdate) {\n            if (config != null) {\n                ComponentUtil.encryptConfigurationProperties(config.getConfigurationProperties(), this.cryptoService);\n            }\n        }\n\n        // only encrypted properties are passed to internal methods\n        updateConfigurationsInternal(configsToUpdate, takeSnapshot);\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs: Factory Management\n    //\n    // ----------------------------------------------------------------\n    @Override\n    public Set<String> getFactoryComponentPids() {\n        return Collections.unmodifiableSet(\n                this.factoryPids.stream().map(TrackedComponentFactory::getFactoryPid).collect(Collectors.toSet()));\n    }\n\n    @Override\n    public ComponentConfiguration getDefaultComponentConfiguration(String pid) throws KuraException {\n        ComponentConfiguration tempConfig = getDefaultComponentConfigurationInternal(pid);\n        if (tempConfig != null && tempConfig.getConfigurationProperties() != null) {\n            decryptConfigurationProperties(tempConfig.getConfigurationProperties());\n        }\n        return tempConfig;\n    }\n\n    @Override\n    public void createFactoryConfiguration(String factoryPid, String pid, Map<String, Object> properties,\n            boolean takeSnapshot) throws KuraException {\n\n        createFactoryConfigurationInternal(factoryPid, pid,\n                ComponentUtil.encryptConfigurationProperties(properties, this.cryptoService, true), takeSnapshot);\n    }\n\n    private synchronized void createFactoryConfigurationInternal(String factoryPid, String pid,\n            Map<String, Object> properties, boolean takeSnapshot) throws KuraException {\n        if (pid == null) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"pid cannot be null\");\n        } else if (this.servicePidByPid.containsKey(pid)) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"pid \" + pid + \" already exists\");\n        }\n\n        try {\n            // Second argument in createFactoryConfiguration is a bundle location. If left\n            // null the new bundle location\n            // will be bound to the location of the first bundle that registers a Managed\n            // Service Factory with a\n            // corresponding PID\n            logger.info(\"Creating new configuration for factory pid {} and pid {}\", factoryPid, pid);\n            String servicePid = this.configurationAdmin.createFactoryConfiguration(factoryPid, null).getPid();\n\n            logger.info(\"Updating newly created configuration for pid {}\", pid);\n\n            Map<String, Object> mergedProperties = new HashMap<>();\n            if (properties != null) {\n                mergedProperties.putAll(properties);\n            }\n\n            OCD ocd = this.ocds.get(factoryPid);\n            mergeWithDefaults(ocd, mergedProperties);\n\n            mergedProperties.put(ConfigurationService.KURA_SERVICE_PID, pid);\n\n            Dictionary<String, Object> dict = CollectionsUtil.mapToDictionary(mergedProperties);\n            Configuration config = this.configurationAdmin.getConfiguration(servicePid, \"?\");\n            config.update(dict);\n\n            registerComponentConfiguration(pid, servicePid, factoryPid);\n\n            this.pendingDeletePids.remove(pid);\n\n            if (takeSnapshot) {\n                snapshot();\n            }\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e,\n                    \"Cannot create component instance for factory \" + factoryPid);\n        }\n    }\n\n    @Override\n    public synchronized void deleteFactoryConfiguration(String pid, boolean takeSnapshot) throws KuraException {\n        if (pid == null) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"pid cannot be null\");\n        }\n\n        try {\n            final Configuration[] configurations = this.configurationAdmin.listConfigurations(null);\n\n            if (configurations == null) {\n                logger.warn(\"ConfigurationAdmin has no configurations\");\n                return;\n            }\n\n            final Optional<Configuration> config = Arrays.stream(configurations).filter(c -> {\n                final Object kuraServicePid = c.getProperties().get(KURA_SERVICE_PID);\n                final String factoryPid = c.getFactoryPid();\n                return pid.equals(kuraServicePid) && factoryPid != null;\n            }).findAny();\n\n            if (!config.isPresent()) {\n                logger.warn(\"The component with kura.service.pid {} does not exist or it is not a Factory Component\",\n                        pid);\n                return;\n            }\n\n            logger.info(\"Deleting factory configuration for component with pid {}...\", pid);\n\n            config.get().delete();\n\n            unregisterComponentConfiguration(pid);\n\n            this.pendingDeletePids.add(pid);\n\n            if (takeSnapshot) {\n                snapshot();\n            }\n            logger.info(\"Deleting factory configuration for component with pid {}...done\", pid);\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e, \"Cannot delete component instance \" + pid);\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs: Snapshot Management\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public long snapshot() throws KuraException {\n        logger.info(\"Writing snapshot - Getting component configurations...\");\n\n        List<ComponentConfiguration> configs = buildCurrentConfiguration(null);\n\n        return saveSnapshot(configs);\n    }\n\n    @Override\n    public long rollback() throws KuraException {\n        // get the second-last most recent snapshot\n        // and rollback to that one.\n        Set<Long> ids = getSnapshots();\n        if (ids.size() < 2) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND, null, \"No Snapshot Available\");\n        }\n\n        // rollback to the second last snapshot\n        Long[] snapshots = ids.toArray(new Long[] {});\n        Long id = snapshots[ids.size() - 2];\n\n        rollback(id);\n        return id;\n    }\n\n    @Override\n    public void rollback(long id) throws KuraException {\n        logger.info(\"Rolling back to snapshot {}...\", id);\n\n        List<Throwable> causes = new ArrayList<>();\n        final Map<String, ComponentConfiguration> snapshotConfigs = getSnapshotConfigs(id);\n        final Map<String, Configuration> currentConfigs = getCurrentConfigs();\n        Iterator<Entry<String, Configuration>> currentConfigsIterator = currentConfigs.entrySet().iterator();\n\n        while (currentConfigsIterator.hasNext()) {\n            manageCurrentConfigs(causes, snapshotConfigs, currentConfigsIterator);\n        }\n\n        for (final ComponentConfiguration snapshotConfig : snapshotConfigs.values()) {\n            manageSnapshotConfigs(causes, currentConfigs, snapshotConfig);\n        }\n\n        this.pendingDeletePids.clear();\n\n        if (!causes.isEmpty()) {\n            throw new KuraPartialSuccessException(\"Rollback\", causes);\n        }\n\n        final SortedSet<Long> snapshotIds = getSnapshotsInternal();\n\n        if (snapshotIds.isEmpty() || id != snapshotIds.last()) {\n            saveSnapshot(snapshotConfigs.values());\n        }\n\n    }\n\n    @Override\n    public Set<Long> getSnapshots() throws KuraException {\n        return getSnapshotsInternal();\n    }\n\n    @Override\n    public List<ComponentConfiguration> getSnapshot(long sid) throws KuraException {\n        List<ComponentConfiguration> returnConfigs = new ArrayList<>();\n\n        XmlComponentConfigurations xmlConfigs = loadEncryptedSnapshotFileContent(sid);\n        if (xmlConfigs != null) {\n            List<ComponentConfiguration> configs = xmlConfigs.getConfigurations();\n            for (ComponentConfiguration config : configs) {\n                if (config != null) {\n                    try {\n                        decryptConfigurationProperties(config.getConfigurationProperties());\n                    } catch (Throwable t) {\n                        logger.warn(\"Error during snapshot password decryption\");\n                    }\n                }\n            }\n\n            returnConfigs.addAll(xmlConfigs.getConfigurations());\n        }\n\n        return returnConfigs;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Package APIs\n    //\n    // ----------------------------------------------------------------\n    synchronized void registerComponentOCD(String metatypePid, Tocd ocd, boolean isFactory, final Bundle provider)\n            throws KuraException {\n        // metatypePid is either the 'pid' or 'factoryPid' attribute of the MetaType\n        // Designate element\n        // 'pid' matches a service.pid, not a kura.service.pid\n        logger.info(\"Registering metatype pid: {} ...\", metatypePid);\n\n        this.ocds.put(metatypePid, ocd);\n\n        if (isFactory) {\n            registerFactoryComponentOCD(metatypePid, ocd, provider);\n        } else {\n            try {\n                updateWithDefaultConfiguration(metatypePid, ocd);\n            } catch (IOException e) {\n                throw new KuraIOException(e);\n            }\n        }\n    }\n\n    synchronized void onBundleRemoved(final Bundle bundle) {\n        this.factoryPids.removeIf(factory -> {\n            final Bundle provider = factory.getProviderBundle();\n            return provider.getSymbolicName().equals(bundle.getSymbolicName())\n                    && provider.getVersion().equals(bundle.getVersion());\n        });\n    }\n\n    synchronized void registerComponentConfiguration(final String pid, final String servicePid,\n            final String factoryPid) {\n        if (pid == null || servicePid == null) {\n            logger.warn(\"Either PID (kura.service.pid) {} or Service PID (service.pid) {} is null\", pid, servicePid);\n            return;\n        }\n\n        if (!this.allActivatedPids.contains(pid)) {\n            // register the component instance\n            logger.info(\"Registering ConfigurableComponent - {}....\", pid);\n            this.servicePidByPid.put(pid, servicePid);\n            if (factoryPid != null) {\n                this.factoryPidByPid.put(pid, factoryPid);\n                Tocd factoryOCD = this.ocds.get(factoryPid);\n                if (factoryOCD != null) {\n                    try {\n                        updateWithDefaultConfiguration(pid, factoryOCD);\n                    } catch (IOException e) {\n                        logger.info(\"Error seeding updated configuration for pid: {}\", pid);\n                    }\n                }\n            }\n            this.allActivatedPids.add(pid);\n            logger.info(\"Registering ConfigurableComponent - {}....Done\", pid);\n        }\n    }\n\n    synchronized void registerSelfConfiguringComponent(final String pid, final String servicePid) {\n        if (pid == null) {\n            logger.warn(\"PID (kura.service.pid) is null\");\n            return;\n        }\n        logger.info(\"Registering SelfConfiguringComponent - {}....\", pid);\n        if (!this.allActivatedPids.contains(pid)) {\n            this.allActivatedPids.add(pid);\n        }\n        if (!this.activatedSelfConfigComponents.contains(pid)) {\n            this.servicePidByPid.put(pid, servicePid);\n            this.activatedSelfConfigComponents.add(pid);\n        }\n        logger.info(\"Registering SelfConfiguringComponent - {}....Done\", pid);\n    }\n\n    synchronized void unregisterComponentConfiguration(String pid) {\n        if (pid == null) {\n            logger.warn(\"pid is null\");\n            return;\n        }\n        logger.info(\"Removing component configuration for pid {}\", pid);\n        this.servicePidByPid.remove(pid);\n        this.factoryPidByPid.remove(pid);\n        this.activatedSelfConfigComponents.remove(pid);\n        this.allActivatedPids.remove(pid);\n    }\n\n    boolean mergeWithDefaults(OCD ocd, Map<String, Object> properties) {\n        boolean changed = false;\n        Set<String> keys = properties.keySet();\n\n        Map<String, Object> defaults = getDefaultProperties(ocd);\n        Set<String> defaultsKeys = defaults.keySet();\n\n        defaultsKeys.removeAll(keys);\n        if (!defaultsKeys.isEmpty()) {\n\n            changed = true;\n            logger.info(\"Merging configuration for pid: {}\", ocd.getId());\n            for (String key : defaultsKeys) {\n\n                Object value = defaults.get(key);\n                properties.put(key, value);\n                logger.debug(\"Merged configuration properties with property with name: {} and default value {}\", key,\n                        value);\n            }\n        }\n        return changed;\n    }\n\n    Map<String, Object> getDefaultProperties(OCD ocd) {\n        return ComponentUtil.getDefaultProperties(ocd, this.ctx);\n    }\n\n    void decryptConfigurationProperties(Map<String, Object> configProperties) {\n        for (Entry<String, Object> property : configProperties.entrySet()) {\n            Object configValue = property.getValue();\n\n            if (configValue instanceof Password || configValue instanceof Password[]) {\n                Object decryptedValue;\n                try {\n                    decryptedValue = decryptPasswordProperties(configValue);\n                    configProperties.put(property.getKey(), decryptedValue);\n                } catch (KuraException e) {\n                    logger.error(\"Failed to decrypt password properties\", e);\n                }\n            }\n        }\n\n    }\n\n    private Object decryptPasswordProperties(Object encryptedValue) throws KuraException {\n        Object decryptedValue = null;\n        if (encryptedValue instanceof Password) {\n            decryptedValue = decryptPassword((Password) encryptedValue);\n        } else if (encryptedValue instanceof Password[]) {\n            Password[] encryptedPasswords = (Password[]) encryptedValue;\n            Password[] decryptedPasswords = new Password[encryptedPasswords.length];\n            for (int i = 0; i < encryptedPasswords.length; i++) {\n                decryptedPasswords[i] = decryptPassword(encryptedPasswords[i]);\n            }\n            decryptedValue = decryptedPasswords;\n        }\n        return decryptedValue;\n    }\n\n    private Password decryptPassword(Password encryptedPassword) throws KuraException {\n        return new Password(this.cryptoService.decryptAes(encryptedPassword.getPassword()));\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private APIs\n    //\n    // ----------------------------------------------------------------\n\n    private synchronized void updateConfigurationsInternal(List<ComponentConfiguration> configsToUpdate,\n            boolean takeSnapshot) throws KuraException {\n        List<Throwable> causes = new ArrayList<>();\n        List<ComponentConfiguration> configs = buildCurrentConfiguration(configsToUpdate);\n\n        updateConfigurationInternal(configsToUpdate, configs, causes);\n\n        // this step creates any not yet existing factory configuration present in\n        // configsToUpdate\n        for (ComponentConfiguration config : configsToUpdate) {\n            String factoryPid = null;\n            final Map<String, Object> properties = config.getConfigurationProperties();\n            if (properties != null) {\n                factoryPid = (String) properties.get(ConfigurationAdmin.SERVICE_FACTORYPID);\n            }\n            if (factoryPid != null && !this.allActivatedPids.contains(config.getPid())) {\n                ConfigurationUpgrade.upgrade(config, this.bundleContext);\n                String pid = config.getPid();\n                logger.info(\"Creating configuration with pid: {} and factory pid: {}\", pid, factoryPid);\n                try {\n                    createFactoryConfigurationInternal(factoryPid, pid, properties, false);\n                    configs.add(config);\n                } catch (KuraException e) {\n                    logger.warn(\"Error creating configuration with pid: {} and factory pid: {}\", pid, factoryPid, e);\n                }\n            }\n        }\n\n        if (takeSnapshot && configs != null && !configs.isEmpty()) {\n            saveSnapshot(configs);\n        }\n\n        if (!causes.isEmpty()) {\n            throw new KuraPartialSuccessException(\"updateConfigurations\", causes);\n        }\n    }\n\n    private void updateConfigurationInternal(List<ComponentConfiguration> configsToUpdate,\n            List<ComponentConfiguration> configs, List<Throwable> causes) {\n        for (ComponentConfiguration config : configs) {\n            for (ComponentConfiguration configToUpdate : configsToUpdate) {\n                if (config.getPid().equals(configToUpdate.getPid())) {\n                    try {\n                        updateConfigurationInternal(config.getPid(), config.getConfigurationProperties(), false);\n                    } catch (KuraException e) {\n                        logger.warn(\"Error during updateConfigurations for component \" + config.getPid(), e);\n                        causes.add(e);\n                    }\n                    break;\n                }\n            }\n        }\n    }\n\n    // returns configurations with encrypted passwords\n    private List<ComponentConfiguration> getComponentConfigurationsInternal() throws KuraException {\n        List<ComponentConfiguration> configs = new ArrayList<>();\n\n        // assemble all the configurations we have\n        // clone the list to avoid concurrent modifications\n        List<String> allPids = new ArrayList<>(this.allActivatedPids);\n        for (String pid : allPids) {\n            try {\n                ComponentConfiguration cc = getComponentConfigurationInternal(pid);\n                if (cc != null) {\n                    configs.add(cc);\n                }\n            } catch (Exception e) {\n                throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e,\n                        \"Error getting configuration for component \" + pid);\n            }\n        }\n        return configs;\n    }\n\n    // returns configurations with encrypted passwords\n    private ComponentConfiguration getComponentConfigurationInternal(String pid) {\n        ComponentConfiguration cc;\n        if (!this.activatedSelfConfigComponents.contains(pid)) {\n            cc = getConfigurableComponentConfiguration(pid);\n        } else {\n            cc = getSelfConfiguringComponentConfiguration(pid);\n        }\n        return cc;\n    }\n\n    private ComponentConfiguration getDefaultComponentConfigurationInternal(String pid) {\n        ComponentConfiguration cc;\n        if (!this.activatedSelfConfigComponents.contains(pid)) {\n            cc = getConfigurableComponentDefaultConfiguration(pid);\n        } else {\n            cc = getSelfConfiguringComponentDefaultConfiguration(pid);\n        }\n        return cc;\n    }\n\n    private ComponentConfiguration getConfigurableComponentDefaultConfiguration(String pid) {\n        Tocd ocd = getOCDForPid(pid);\n        Map<String, Object> props = ComponentUtil.getDefaultProperties(ocd, this.ctx);\n        return new ComponentConfigurationImpl(pid, ocd, props);\n    }\n\n    private ComponentConfiguration getSelfConfiguringComponentDefaultConfiguration(String pid) {\n        ComponentConfiguration cc = null;\n        try {\n            String filter = String.format(\"(kura.service.pid=%s)\", pid);\n            ServiceReference<?>[] refs = this.ctx.getBundleContext().getServiceReferences((String) null, filter);\n            if (refs != null && refs.length > 0) {\n                ServiceReference<?> ref = refs[0];\n                Object obj = this.ctx.getBundleContext().getService(ref);\n                try {\n                    cc = getSelfConfiguringComponentDefaultConfigurationInternal(obj, pid);\n                } finally {\n                    this.ctx.getBundleContext().ungetService(ref);\n                }\n            }\n        } catch (InvalidSyntaxException e) {\n            logger.error(GETTING_CONFIGURATION_ERROR, pid, e);\n        }\n\n        return cc;\n    }\n\n    private ComponentConfiguration getSelfConfiguringComponentDefaultConfigurationInternal(Object obj, String pid) {\n        ComponentConfiguration cc = null;\n        if (obj instanceof SelfConfiguringComponent) {\n            SelfConfiguringComponent selfConfigComp = (SelfConfiguringComponent) obj;\n            try {\n                ComponentConfiguration tempCc = selfConfigComp.getConfiguration();\n                if (tempCc.getPid() == null || !tempCc.getPid().equals(pid)) {\n                    logger.error(\n                            \"Invalid pid for returned Configuration of SelfConfiguringComponent with pid: {} Ignoring it.\",\n                            pid);\n                    return cc;\n                }\n\n                OCD ocd = tempCc.getDefinition();\n                if (ocd != null) {\n                    Map<String, Object> props = ComponentUtil.getDefaultProperties(ocd, this.ctx);\n                    cc = new ComponentConfigurationImpl(pid, (Tocd) ocd, props);\n                }\n            } catch (KuraException e) {\n                logger.error(GETTING_CONFIGURATION_ERROR, pid, e);\n            }\n        } else {\n            logger.error(\"Component {} is not a SelfConfiguringComponent. Ignoring it.\", obj);\n        }\n        return cc;\n    }\n\n    private void updateWithDefaultConfiguration(String pid, Tocd ocd) throws IOException {\n        String servicePid = this.servicePidByPid.get(pid);\n        if (servicePid == null) {\n            servicePid = pid;\n        }\n        Configuration config = this.configurationAdmin.getConfiguration(servicePid, \"?\");\n        if (config != null) {\n            // get the properties from ConfigurationAdmin if any are present\n            Map<String, Object> props = new HashMap<>();\n            if (config.getProperties() != null) {\n                props.putAll(CollectionsUtil.dictionaryToMap(config.getProperties(), ocd));\n            }\n\n            if (!props.containsKey(ConfigurationService.KURA_SERVICE_PID)) {\n                props.put(ConfigurationService.KURA_SERVICE_PID, pid);\n            }\n\n            // merge the current properties, if any, with the defaults from metatype\n            mergeWithDefaults(ocd, props);\n\n            config.update(CollectionsUtil.mapToDictionary(props));\n            logger.info(\"Seeding updated configuration for pid: {}\", pid);\n        }\n    }\n\n    private void registerFactoryComponentOCD(String metatypePid, Tocd ocd, final Bundle provider) throws KuraException {\n        this.factoryPids.add(new TrackedComponentFactory(metatypePid, provider));\n\n        for (Map.Entry<String, String> entry : this.factoryPidByPid.entrySet()) {\n            if (entry.getValue().equals(metatypePid) && this.servicePidByPid.get(entry.getKey()) != null) {\n                try {\n                    updateWithDefaultConfiguration(entry.getKey(), ocd);\n                } catch (IOException e) {\n                    throw new KuraIOException(e);\n                }\n            }\n        }\n    }\n\n    private boolean allSnapshotsAreUnencrypted() {\n        Set<Long> snapshotIDs;\n        try {\n            snapshotIDs = getSnapshots();\n        } catch (KuraException e) {\n            return false;\n        }\n\n        for (Long snapshot : snapshotIDs) {\n            try {\n                loadEncryptedSnapshotFileContent(snapshot);\n                return false;\n            } catch (Exception e) {\n                // Do nothing...\n            }\n        }\n        return true;\n    }\n\n    private static String readFully(final File file) throws IOException {\n        final char[] buf = new char[4096];\n        final StringBuilder builder = new StringBuilder();\n\n        try (final FileReader r = new FileReader(file)) {\n            int rd;\n\n            while ((rd = r.read(buf, 0, buf.length)) > 0) {\n                builder.append(buf, 0, rd);\n            }\n        }\n\n        return builder.toString();\n    }\n\n    private void encryptPlainSnapshots() throws KuraException, IOException {\n        Set<Long> snapshotIDs = getSnapshots();\n        if (snapshotIDs == null || snapshotIDs.isEmpty()) {\n            return;\n        }\n        Long[] snapshots = snapshotIDs.toArray(new Long[] {});\n\n        for (Long snapshot : snapshots) {\n            File fSnapshot = getSnapshotFile(snapshot);\n            if (fSnapshot == null || !fSnapshot.exists()) {\n                throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, snapshot);\n            }\n\n            final XmlComponentConfigurations xmlConfigs = unmarshal(new FileInputStream(fSnapshot),\n                    XmlComponentConfigurations.class);\n\n            ComponentUtil.encryptConfigs(xmlConfigs.getConfigurations(), this.cryptoService);\n\n            // Writes an encrypted snapshot with encrypted passwords.\n            writeSnapshot(snapshot, xmlConfigs);\n        }\n    }\n\n    private long saveSnapshot(Collection<? extends ComponentConfiguration> configs) throws KuraException {\n        List<ComponentConfiguration> configsToSave = configs.stream()\n                .map(cc -> new ComponentConfigurationImpl(cc.getPid(), null, cc.getConfigurationProperties()))\n                .collect(Collectors.toList());\n\n        // Build the XML structure\n        XmlComponentConfigurations conf = new XmlComponentConfigurations();\n        conf.setConfigurations(configsToSave);\n\n        // Write it to disk: marshall\n        long sid = new Date().getTime();\n\n        // Do not save the snapshot in the past\n        SortedSet<Long> snapshotIDs = (SortedSet<Long>) getSnapshots();\n        if (snapshotIDs != null && !snapshotIDs.isEmpty()) {\n            Long lastestID = snapshotIDs.last();\n\n            if (lastestID != null && sid <= lastestID) {\n                logger.warn(\"Snapshot ID: {} is in the past. Adjusting ID to: {} + 1\", sid, lastestID);\n                sid = lastestID + 1;\n            }\n        }\n\n        // Write snapshot\n        writeSnapshot(sid, conf);\n\n        // Garbage Collector for number of Snapshots Saved\n        garbageCollectionOldSnapshots();\n        return sid;\n    }\n\n    private void writeSnapshot(long sid, XmlComponentConfigurations conf) throws KuraException {\n        File fSnapshot = getSnapshotFile(sid);\n        if (fSnapshot == null) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND);\n        }\n\n        File tempSnapshotFile = getTempSnapshotFile(fSnapshot);\n\n        try {\n            storeSnapshotData(conf, fSnapshot, tempSnapshotFile);\n            finalizeSnapshotWrite(fSnapshot, tempSnapshotFile);\n        } finally {\n            if (tempSnapshotFile.exists()) {\n                try {\n                    Files.delete(tempSnapshotFile.toPath());\n                } catch (IOException e) {\n                    logger.warn(\"Failed to delete temporary snapshot file: {}\", tempSnapshotFile.getAbsolutePath(), e);\n                }\n            }\n        }\n\n    }\n\n    private void finalizeSnapshotWrite(File fSnapshot, File tempSnapshotFile) throws KuraIOException {\n        try {\n            setSnapshotFilePermissions(fSnapshot, tempSnapshotFile);\n\n            // Consolidate snapshot writing\n            Files.move(tempSnapshotFile.toPath(), fSnapshot.toPath(), StandardCopyOption.REPLACE_EXISTING,\n                    StandardCopyOption.ATOMIC_MOVE);\n        } catch (IOException e) {\n            throw new KuraIOException(e);\n        }\n\n    }\n\n    private void setSnapshotFilePermissions(File fSnapshot, File tempSnapshotFile) throws IOException {\n        try {\n            Set<PosixFilePermission> perms = PosixFilePermissions.fromString(\"rw-------\");\n            Files.setPosixFilePermissions(tempSnapshotFile.toPath(), perms);\n\n        } catch (UnsupportedOperationException e1) {\n            // POSIX permissions not supported on this file system, log and continue\n            logger.warn(\"Unable to set POSIX file permissions for snapshot file: {}\", fSnapshot.getAbsolutePath(), e1);\n        }\n    }\n\n    private void storeSnapshotData(XmlComponentConfigurations conf, File fSnapshot, File tempSnapshotFile)\n            throws KuraException {\n        // Write the temporary snapshot\n        try (FileOutputStream fos = new FileOutputStream(tempSnapshotFile);\n                OutputStream encryptedStream = this.cryptoService.aesEncryptingStream(fos)) {\n\n            logger.info(\"Writing snapshot - Saving {}...\", fSnapshot.getAbsolutePath());\n\n            marshal(encryptedStream, conf);\n            encryptedStream.flush();\n            fos.flush();\n            fos.getFD().sync();\n\n            logger.info(\"Writing snapshot - Saving {}... Done.\", fSnapshot.getAbsolutePath());\n        } catch (IOException e) {\n            throw new KuraIOException(e);\n        }\n    }\n\n    private File getTempSnapshotFile(File fSnapshot) throws KuraIOException {\n        File tempSnapshotFile;\n        try {\n            tempSnapshotFile = File.createTempFile(fSnapshot.getName(), null, new File(fSnapshot.getParent()));\n        } catch (IOException ex) {\n            throw new KuraIOException(ex);\n        }\n        return tempSnapshotFile;\n    }\n\n    private ComponentConfiguration getConfigurableComponentConfiguration(String pid) {\n        ComponentConfiguration cc = null;\n        try {\n\n            Tocd ocd = getOCDForPid(pid);\n\n            String servicePid = this.servicePidByPid.get(pid);\n\n            if (servicePid != null) {\n                Configuration cfg = this.configurationAdmin.getConfiguration(servicePid, \"?\");\n                Map<String, Object> props = CollectionsUtil.dictionaryToMap(cfg.getProperties(), ocd);\n\n                cc = new ComponentConfigurationImpl(pid, ocd, props);\n            }\n        } catch (Exception e) {\n            logger.error(\"Error getting Configuration for component: \" + pid + \". Ignoring it.\", e);\n        }\n        return cc;\n    }\n\n    private ComponentConfiguration getSelfConfiguringComponentConfiguration(String pid) {\n        ComponentConfiguration cc = null;\n        final ServiceReference<?>[] refs = ServiceUtil.getServiceReferences(this.bundleContext,\n                SelfConfiguringComponent.class, null);\n\n        try {\n            for (ServiceReference<?> ref : refs) {\n                String ppid = (String) ref.getProperty(KURA_SERVICE_PID);\n                final SelfConfiguringComponent selfConfigComp = (SelfConfiguringComponent) this.bundleContext\n                        .getService(ref);\n                if (pid.equals(ppid)) {\n\n                    cc = selfConfigComp.getConfiguration();\n                    if (!isValidSelfConfiguringComponent(pid, cc)) {\n                        return null;\n                    }\n                }\n            }\n        } catch (KuraException e) {\n            logger.error(GETTING_CONFIGURATION_ERROR, pid, e);\n        } finally {\n            ServiceUtil.ungetServiceReferences(this.bundleContext, refs);\n        }\n\n        return cc;\n    }\n\n    private boolean isValidSelfConfiguringComponent(String pid, ComponentConfiguration cc) {\n\n        if (isNull(cc) || cc.getPid() == null || !cc.getPid().equals(pid)) {\n            logger.error(\n                    \"Invalid pid for returned Configuration of SelfConfiguringComponent with pid: {}. Ignoring it.\",\n                    pid);\n            return false;\n        }\n\n        OCD ocd = cc.getDefinition();\n        if (isNull(ocd) || isNull(ocd.getAD())) {\n            return false;\n        }\n\n        List<AD> ads = ocd.getAD();\n\n        for (AD ad : ads) {\n            String adId = ad.getId();\n            String adType = ad.getType().value();\n\n            if (isNull(adId) || isNull(adType)) {\n                logger.error(\n                        \"null required type for AD id: {} for returned Configuration of SelfConfiguringComponent with pid: {}\",\n                        adId, pid);\n                return false;\n            }\n\n            Map<String, Object> props = cc.getConfigurationProperties();\n            if (!isNull(props) && !isNull(props.get(adId)) && !isMatchingADType(pid, adId, adType, props.get(adId))) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private boolean isMatchingADType(String pid, String adId, String adType, Object value) {\n        boolean result = false;\n        try {\n            logger.debug(\"pid: {}, property name: {}, value: {}\", pid, adId, value);\n            Scalar propertyScalar = getScalarFromObject(value);\n            Scalar adScalar = Scalar.fromValue(adType);\n            if (propertyScalar != adScalar) {\n                logger.error(\n                        \"Type: {} for property named: {} does not match the AD type: {} for returned Configuration of SelfConfiguringComponent with pid: {}\",\n                        propertyScalar.name(), adId, adType, pid);\n            }\n            result = true;\n        } catch (IllegalArgumentException e) {\n            logger.error(\n                    \"Invalid class for property named: {} for returned Configuration of SelfConfiguringComponent with pid: {}\",\n                    adId, pid);\n        }\n        return result;\n    }\n\n    private Scalar getScalarFromObject(Object p) {\n        Class<?> clazz = p.getClass();\n        if (clazz.isArray()) {\n            Object[] tempArray = (Object[]) p;\n            if (tempArray.length > 0 && tempArray[0] != null) {\n                clazz = tempArray[0].getClass();\n            } else {\n                clazz = clazz.getComponentType();\n            }\n        }\n        return Scalar.fromValue(clazz.getSimpleName());\n    }\n\n    private TreeSet<Long> getSnapshotsInternal() {\n        // keeps the list of snapshots ordered\n        TreeSet<Long> ids = new TreeSet<>();\n        String configDir = getSnapshotsDirectory();\n        if (configDir != null) {\n            File fConfigDir = new File(configDir);\n            File[] files = fConfigDir.listFiles();\n            if (files != null) {\n\n                for (File file : files) {\n                    Matcher m = SNAPSHOT_FILENAME_PATTERN.matcher(file.getName());\n                    if (m.matches()) {\n                        ids.add(Long.parseLong(m.group(1)));\n                    }\n                }\n            }\n        }\n        return ids;\n    }\n\n    String getSnapshotsDirectory() {\n        return this.systemService.getKuraSnapshotsDirectory();\n    }\n\n    private File getSnapshotFile(long id) {\n        String configDir = getSnapshotsDirectory();\n\n        if (configDir == null) {\n            return null;\n        }\n\n        StringBuilder sbSnapshot = new StringBuilder(configDir);\n        sbSnapshot.append(File.separator).append(\"snapshot_\").append(id).append(\".xml\");\n\n        String snapshot = sbSnapshot.toString();\n        return new File(snapshot);\n    }\n\n    private void garbageCollectionOldSnapshots() {\n        // get the current snapshots and compared with the maximum number we\n        // need to keep\n        TreeSet<Long> sids = getSnapshotsInternal();\n\n        int currCount = sids.size();\n        int maxCount = this.systemService.getKuraSnapshotsCount();\n        while (currCount > maxCount && !sids.isEmpty()) { // stop if count reached or no more snapshots remain\n\n            // preserve snapshot ID 0 as this will be considered the seeding\n            // one.\n            long sid = sids.pollFirst();\n            File fSnapshot = getSnapshotFile(sid);\n            if (sid == 0 || fSnapshot == null) {\n                continue;\n            }\n\n            Path fSnapshotPath = fSnapshot.toPath();\n            try {\n                if (Files.deleteIfExists(fSnapshotPath)) {\n                    logger.info(\"Snapshots Garbage Collector. Deleted {}\", fSnapshotPath);\n                    currCount--;\n                }\n            } catch (IOException e) {\n                logger.warn(\"Snapshots Garbage Collector. Deletion failed for {}\", fSnapshotPath, e);\n            }\n        }\n    }\n\n    private void loadLatestSnapshotInConfigAdmin() throws KuraException {\n        //\n        // save away initial configuration\n        List<ComponentConfiguration> configs = buildCurrentConfiguration(null);\n        if (configs == null) {\n            return;\n        }\n        for (ComponentConfiguration config : configs) {\n            if (config != null) {\n                Map<String, Object> props = config.getConfigurationProperties();\n                if (props != null) {\n                    String factoryPid = (String) props.get(ConfigurationAdmin.SERVICE_FACTORYPID);\n\n                    if (factoryPid != null) {\n                        createFactoryConfigurationInternal(factoryPid, config.getPid(), props, false);\n                    } else {\n                        loadConfiguration(config, props);\n                    }\n                }\n            }\n        }\n    }\n\n    private void loadConfiguration(ComponentConfiguration config, Map<String, Object> props) {\n        try {\n            logger.debug(\"Pushing config to config admin: {}\", config.getPid());\n\n            // push it to the ConfigAdmin\n            Configuration cfg = this.configurationAdmin.getConfiguration(config.getPid(), \"?\");\n\n            // set kura.service.pid if missing\n            Map<String, Object> newProperties = new HashMap<>(props);\n            if (!newProperties.containsKey(ConfigurationService.KURA_SERVICE_PID)) {\n                newProperties.put(ConfigurationService.KURA_SERVICE_PID, config.getPid());\n            }\n\n            cfg.update(CollectionsUtil.mapToDictionary(newProperties));\n\n        } catch (IOException e) {\n            logger.warn(\"Error seeding initial properties to ConfigAdmin for pid: {}\", config.getPid(), e);\n        }\n    }\n\n    private List<ComponentConfiguration> loadLatestSnapshotConfigurations() throws KuraException {\n        //\n        // Get the latest snapshot file to use as initialization\n        Set<Long> snapshotIDs = getSnapshots();\n        if (snapshotIDs == null || snapshotIDs.isEmpty()) {\n            return Collections.emptyList();\n        }\n\n        Long[] snapshots = snapshotIDs.toArray(new Long[] {});\n        Long lastestID = snapshots[snapshotIDs.size() - 1];\n\n        //\n        // Unmarshall\n        logger.info(\"Loading init configurations from: {}...\", lastestID);\n\n        List<ComponentConfiguration> configs = null;\n        try {\n            XmlComponentConfigurations xmlConfigs = loadEncryptedSnapshotFileContent(lastestID);\n            if (xmlConfigs != null) {\n                configs = xmlConfigs.getConfigurations();\n            }\n        } catch (Exception e) {\n            logger.info(\"Unable to decrypt snapshot! Fallback to unencrypted snapshots mode.\");\n            try {\n                if (allSnapshotsAreUnencrypted()) {\n                    encryptPlainSnapshots();\n                    configs = loadLatestSnapshotConfigurations();\n                }\n            } catch (Exception ex) {\n                throw new KuraIOException(ex);\n            }\n        }\n\n        return configs;\n    }\n\n    XmlComponentConfigurations loadEncryptedSnapshotFileContent(long snapshotID) throws KuraException {\n        File fSnapshot = getSnapshotFile(snapshotID);\n        if (fSnapshot == null || !fSnapshot.exists()) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND,\n                    fSnapshot != null ? fSnapshot.getAbsolutePath() : \"null\");\n        }\n\n        InputStream decryptedStream = null;\n        try {\n            decryptedStream = this.cryptoService.aesDecryptingStream(new FileInputStream(fSnapshot));\n        } catch (FileNotFoundException e) {\n            logger.error(\"Error loading file from disk\", e);\n            return null;\n        }\n\n        XmlComponentConfigurations xmlConfigs = null;\n\n        try {\n            xmlConfigs = unmarshal(decryptedStream, XmlComponentConfigurations.class);\n        } catch (KuraException e) {\n            logger.warn(\"Error parsing xml\", e);\n        }\n\n        return xmlConfigs;\n    }\n\n    private void updateConfigurationInternal(String pid, Map<String, Object> properties, boolean snapshotOnConfirmation)\n            throws KuraException {\n        logger.debug(\"Attempting update configuration for {}\", pid);\n\n        if (!this.allActivatedPids.contains(pid)) {\n            logger.info(\"UpdatingConfiguration ignored as ConfigurableComponent {} is NOT tracked.\", pid);\n            return;\n        }\n        if (properties == null) {\n            logger.info(\"UpdatingConfiguration ignored as properties for ConfigurableComponent {} are NULL.\", pid);\n            return;\n        }\n\n        // get the OCD from the registered ConfigurableComponents\n        OCD registerdOCD = getRegisteredOCD(pid);\n        if (registerdOCD == null) {\n            logger.info(\"UpdatingConfiguration ignored as OCD for pid {} cannot be found.\", pid);\n            return;\n        }\n\n        Map<String, Object> mergedProperties = new HashMap<>();\n        mergeWithDefaults(registerdOCD, mergedProperties);\n\n        if (!this.activatedSelfConfigComponents.contains(pid)) {\n            try {\n                // get the current running configuration for the selected component\n                Configuration config = this.configurationAdmin.getConfiguration(this.servicePidByPid.get(pid), \"?\");\n                Map<String, Object> runningProps = CollectionsUtil.dictionaryToMap(config.getProperties(),\n                        registerdOCD);\n\n                mergedProperties.putAll(runningProps);\n            } catch (IOException e) {\n                logger.info(\"merge with running failed!\");\n                throw new KuraException(KuraErrorCode.CONFIGURATION_UPDATE, e, pid);\n            }\n        }\n\n        mergedProperties.putAll(properties);\n\n        if (!mergedProperties.containsKey(ConfigurationService.KURA_SERVICE_PID)) {\n            mergedProperties.put(ConfigurationService.KURA_SERVICE_PID, pid);\n        }\n\n        try {\n            updateComponentConfiguration(pid, mergedProperties, snapshotOnConfirmation);\n            logger.info(\"Updating Configuration of ConfigurableComponent {} ... Done.\", pid);\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_UPDATE, e, pid);\n        }\n    }\n\n    private void updateComponentConfiguration(String pid, Map<String, Object> mergedProperties,\n            boolean snapshotOnConfirmation) throws KuraException, IOException {\n        if (!this.activatedSelfConfigComponents.contains(pid)) {\n\n            // load the ocd to do the validation\n            BundleContext bundleCtx = this.ctx.getBundleContext();\n            // FIXME: why the returned ocd is always null?\n            ObjectClassDefinition ocd = ComponentUtil.getObjectClassDefinition(bundleCtx,\n                    this.servicePidByPid.get(pid));\n\n            // Validate the properties to be applied and set them\n            validateProperties(pid, ocd, mergedProperties);\n        } else {\n            // FIXME: validation of properties for self-configuring\n            // components\n        }\n\n        // Update the new properties\n        // use ConfigurationAdmin to do the update\n        Configuration config = this.configurationAdmin.getConfiguration(this.servicePidByPid.get(pid), \"?\");\n        config.update(CollectionsUtil.mapToDictionary(mergedProperties));\n\n        if (snapshotOnConfirmation) {\n            snapshot();\n        }\n    }\n\n    private OCD getRegisteredOCD(String pid) {\n        // try to get the OCD from the registered ConfigurableComponents\n        OCD registeredOCD = getOCDForPid(pid);\n        // otherwise try to get it from the registered SelfConfiguringComponents\n        if (registeredOCD == null) {\n            ComponentConfiguration config = getSelfConfiguringComponentConfiguration(pid);\n            if (config != null) {\n                registeredOCD = config.getDefinition();\n            }\n        }\n        return registeredOCD;\n    }\n\n    private void validateProperties(String pid, ObjectClassDefinition ocd, Map<String, Object> updatedProps)\n            throws KuraException {\n        if (ocd == null) {\n            return;\n        }\n\n        // build a map of all the attribute definitions\n        List<AttributeDefinition> definitions = Arrays.asList(ocd.getAttributeDefinitions(ObjectClassDefinition.ALL));\n        Map<String, AttributeDefinition> attributeDefinitions = definitions.stream()\n                .collect(Collectors.toMap(AttributeDefinition::getID, Function.identity()));\n\n        // loop over the proposed property values\n        // and validate them against the definition\n        for (Entry<String, Object> property : updatedProps.entrySet()) {\n\n            String key = property.getKey();\n            AttributeDefinition attributeDefinition = attributeDefinitions.get(key);\n\n            if (attributeDefinition == null) {\n                // For the attribute for which we do not have a definition, just accept them.\n                continue;\n            }\n\n            validateAttribute(property, attributeDefinition);\n        }\n\n        // make sure all required properties are set\n        OCD ocdFull = getOCDForPid(pid);\n        if (ocdFull != null) {\n            for (AD attrDef : ocdFull.getAD()) {\n                // to the required attributes make sure a value is defined.\n                if (attrDef.isRequired() && updatedProps.get(attrDef.getId()) == null) {\n                    // if the default one is not defined, throw exception.\n                    throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, attrDef.getId());\n                }\n            }\n        }\n    }\n\n    private void validateAttribute(Entry<String, Object> property, AttributeDefinition attributeDefinition)\n            throws KuraException {\n        // validate the attribute value\n        String stringValue = StringUtil.valueToString(property.getValue());\n        if (stringValue != null) {\n            String result = attributeDefinition.validate(stringValue);\n            if (result != null && !result.isEmpty()) {\n                throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, attributeDefinition.getID(),\n                        stringValue, result);\n            }\n        }\n    }\n\n    private synchronized List<ComponentConfiguration> buildCurrentConfiguration(\n            List<ComponentConfiguration> configsToUpdate) throws KuraException {\n        List<ComponentConfiguration> result = new ArrayList<>();\n\n        mergeConfigurations(configsToUpdate, result);\n        addSnapshotConfigurations(result);\n\n        // remove configurations being deleted\n        for (String deletedPid : this.pendingDeletePids) {\n            for (ComponentConfiguration config : result) {\n                if (config.getPid().equals(deletedPid)) {\n                    result.remove(config);\n                    break;\n                }\n            }\n        }\n\n        for (final ComponentConfiguration config : result) {\n            ConfigurationUpgrade.upgrade(config, this.bundleContext);\n        }\n\n        return result;\n\n    }\n\n    private void addSnapshotConfigurations(List<ComponentConfiguration> result) throws KuraException {\n        // complete the returned configurations adding the snapshot configurations\n        // of those components not yet in the list.\n        List<ComponentConfiguration> snapshotConfigs = loadLatestSnapshotConfigurations();\n        if (snapshotConfigs != null && !snapshotConfigs.isEmpty()) {\n            for (ComponentConfiguration snapshotConfig : snapshotConfigs) {\n                boolean found = false;\n                for (ComponentConfiguration config : result) {\n                    if (config.getPid().equals(snapshotConfig.getPid())) {\n                        found = true;\n                        break;\n                    }\n                }\n                if (!found) {\n                    // Add old configurations (or not yet tracked ones) present\n                    result.add(snapshotConfig);\n                }\n            }\n        }\n    }\n\n    private void mergeConfigurations(List<ComponentConfiguration> configsToUpdate, List<ComponentConfiguration> result)\n            throws KuraException {\n        // Merge the current configuration of registered components with the provided\n        // configurations.\n        // It is assumed that the PIDs in the provided configurations is a subset of the\n        // registered PIDs.\n\n        List<ComponentConfiguration> currentConfigs = getComponentConfigurationsInternal();\n        if (configsToUpdate == null || configsToUpdate.isEmpty()) {\n            result.addAll(currentConfigs);\n            return;\n        }\n\n        for (ComponentConfiguration currentConfig : currentConfigs) {\n            // add new configuration obtained by merging its properties with the ones\n            // provided\n            ComponentConfiguration cc = currentConfig;\n            String pid = currentConfig.getPid();\n            for (ComponentConfiguration configToUpdate : configsToUpdate) {\n                if (configToUpdate.getPid().equals(pid)) {\n                    Map<String, Object> props = getAllProperties(currentConfig, configToUpdate);\n                    cc = new ComponentConfigurationImpl(pid, (Tocd) configToUpdate.getDefinition(), props);\n                    break;\n                }\n            }\n            result.add(cc);\n        }\n    }\n\n    private Map<String, Object> getAllProperties(ComponentConfiguration currentConfig,\n            ComponentConfiguration configToUpdate) {\n        Map<String, Object> props = new HashMap<>();\n        if (currentConfig.getConfigurationProperties() != null) {\n            props.putAll(currentConfig.getConfigurationProperties());\n        }\n        if (configToUpdate.getConfigurationProperties() != null) {\n            props.putAll(configToUpdate.getConfigurationProperties());\n        }\n        return props;\n    }\n\n    private Tocd getOCDForPid(String pid) {\n        Tocd ocd = this.ocds.get(this.factoryPidByPid.get(pid));\n        if (ocd == null) {\n            ocd = this.ocds.get(pid);\n        }\n        return ocd;\n    }\n\n    /**\n     * Convert property value to string\n     *\n     * @param value\n     *            the input value\n     * @return the string property value, or {@code null}\n     */\n    private static String makeString(Object value) {\n        if (value == null) {\n            return null;\n        }\n        if (value instanceof String) {\n            return (String) value;\n        }\n        return value.toString();\n    }\n\n    @Override\n    public List<ComponentConfiguration> getFactoryComponentOCDs() {\n        return this.factoryPids.stream().map(factory -> {\n            final String factoryPid = factory.getFactoryPid();\n            return new ComponentConfigurationImpl(factoryPid, this.ocds.get(factoryPid), new HashMap<>());\n        }).collect(Collectors.toList());\n    }\n\n    private ComponentConfiguration getComponentDefinition(String pid) {\n        final Tocd ocd = this.ocds.get(pid);\n        Map<String, Object> defaultProperties = new HashMap<>();\n        if (ocd != null) {\n            try {\n                defaultProperties = ComponentUtil.getDefaultProperties(ocd, this.ctx);\n            } catch (Exception e) {\n                logger.warn(\"Failed to get default properties for component: {}\", pid, e);\n            }\n        }\n        return new ComponentConfigurationImpl(pid, ocd, defaultProperties);\n    }\n\n    @Override\n    public ComponentConfiguration getFactoryComponentOCD(String factoryPid) {\n        if (!this.factoryPids.contains(new TrackedComponentFactory(factoryPid, null))) {\n            return null;\n        }\n        return getComponentDefinition(factoryPid);\n    }\n\n    private static boolean implementsAnyService(ComponentDescriptionDTO component, String[] classes) {\n        final String[] services = component.serviceInterfaces;\n        if (services == null) {\n            return false;\n        }\n        for (String className : classes) {\n            for (String s : services) {\n                if (s.equals(className)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public List<ComponentConfiguration> getServiceProviderOCDs(String... classNames) {\n        return this.scrService.getComponentDescriptionDTOs().stream()\n                .filter(component -> implementsAnyService(component, classNames)).map(c -> c.name)\n                .map(this::getComponentDefinition).filter(Objects::nonNull).collect(Collectors.toList());\n    }\n\n    @Override\n    public List<ComponentConfiguration> getServiceProviderOCDs(Class<?>... classes) {\n        final String[] classNames = new String[classes.length];\n        for (int i = 0; i < classes.length; i++) {\n            classNames[i] = classes[i].getName();\n        }\n        return getServiceProviderOCDs(classNames);\n    }\n\n    protected <T> T unmarshal(final InputStream input, final Class<T> clazz) throws KuraException {\n        try {\n            return requireNonNull(this.xmlUnmarshaller.unmarshal(input, clazz));\n        } catch (final Exception e) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, \"configuration\", e);\n        }\n    }\n\n    protected void marshal(final OutputStream out, final Object object) throws KuraException {\n        try {\n            this.xmlMarshaller.marshal(out, object);\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, \"configuration\", e);\n        }\n    }\n\n    private void manageSnapshotConfigs(List<Throwable> causes, final Map<String, Configuration> currentConfigs,\n            final ComponentConfiguration snapshotConfig) {\n        final Optional<Configuration> optionalCurrentConfig = Optional\n                .ofNullable(currentConfigs.get(snapshotConfig.getPid()));\n\n        try {\n            logger.info(\"Processing configuration rollback for component with pid {}...\", snapshotConfig.getPid());\n            rollbackConfigurationInternal(snapshotConfig, optionalCurrentConfig);\n        } catch (IOException e) {\n            logger.warn(\"Failed to rollback configuration for pid {}\", snapshotConfig.getPid(), e);\n            causes.add(e);\n        }\n    }\n\n    private void manageCurrentConfigs(List<Throwable> causes, final Map<String, ComponentConfiguration> snapshotConfigs,\n            Iterator<Entry<String, Configuration>> currentConfigsIterator) {\n        final Entry<String, Configuration> currentConfigEntry = currentConfigsIterator.next();\n        final Optional<ComponentConfiguration> optionalSnapshotConfig = Optional\n                .ofNullable(snapshotConfigs.get(currentConfigEntry.getKey()));\n\n        if (!isFactoryComponent(currentConfigEntry)) {\n\n            if (!optionalSnapshotConfig.isPresent() && this.allActivatedPids.contains(currentConfigEntry.getKey())) {\n                try {\n                    rollbackToDefaultConfig(currentConfigEntry);\n                } catch (IOException e) {\n                    logger.warn(\"Failed to revert to factory configuration {}\", currentConfigEntry.getKey(), e);\n                    causes.add(e);\n                }\n            }\n\n        } else if (!optionalSnapshotConfig.isPresent() || !Objects.equals(currentConfigEntry.getValue().getFactoryPid(),\n                optionalSnapshotConfig.get().getConfigurationProperties().get(ConfigurationAdmin.SERVICE_FACTORYPID))) {\n\n            try {\n                deleteFactoryComponent(currentConfigsIterator, currentConfigEntry);\n            } catch (IOException e) {\n                logger.warn(\"Failed to delete configuration {}\", currentConfigEntry.getKey(), e);\n                causes.add(e);\n            }\n        }\n    }\n\n    private void rollbackConfigurationInternal(final ComponentConfiguration snapshotConfig,\n            final Optional<Configuration> existingConfig) throws IOException {\n        final Optional<String> factoryPid = Optional\n                .ofNullable(snapshotConfig.getConfigurationProperties().get(ConfigurationAdmin.SERVICE_FACTORYPID))\n                .filter(String.class::isInstance).map(String.class::cast);\n\n        final Map<String, Object> result = snapshotConfig.getConfigurationProperties();\n\n        final Optional<OCD> ocd = Optional.ofNullable(getRegisteredOCD(snapshotConfig.getPid()));\n\n        if (ocd.isPresent()) {\n            mergeWithDefaults(ocd.get(), result);\n        }\n\n        final Dictionary<String, Object> resultAsDictionary = CollectionsUtil.mapToDictionary(result);\n\n        resultAsDictionary.put(KURA_SERVICE_PID, snapshotConfig.getPid());\n        resultAsDictionary.remove(Constants.SERVICE_PID);\n\n        final Configuration target;\n\n        if (existingConfig.isPresent()) {\n            target = existingConfig.get();\n        } else if (factoryPid.isPresent()) {\n            logger.info(\"Creating new factory configuration for pid {} and factory pid {}\", snapshotConfig.getPid(),\n                    factoryPid.get());\n            target = this.configurationAdmin.createFactoryConfiguration(factoryPid.get(), null);\n        } else {\n            logger.info(\"Creating new configuration for pid {}\", snapshotConfig.getPid());\n            target = this.configurationAdmin.getConfiguration(snapshotConfig.getPid());\n        }\n\n        final Dictionary<String, Object> currentProperties = target.getProperties();\n\n        if (currentProperties != null) {\n            currentProperties.remove(Constants.SERVICE_PID);\n        }\n\n        if (!CollectionsUtil.equals(resultAsDictionary, currentProperties)) {\n            logger.info(\"Updating configuration for pid {}\", snapshotConfig.getPid());\n            target.update(resultAsDictionary);\n            if (factoryPid.isPresent()) {\n                registerComponentConfiguration(snapshotConfig.getPid(), target.getPid(), factoryPid.get());\n            }\n        } else {\n            logger.info(\"No need to update configuration for pid {}\", snapshotConfig.getPid());\n        }\n    }\n\n    private void deleteFactoryComponent(Iterator<Entry<String, Configuration>> currentConfigsIterator,\n            final Entry<String, Configuration> currentConfigEntry) throws IOException {\n        logger.info(\"Deleting factory configuration for component with pid {}...\", currentConfigEntry.getKey());\n        currentConfigEntry.getValue().delete();\n        currentConfigsIterator.remove();\n        unregisterComponentConfiguration(currentConfigEntry.getKey());\n    }\n\n    private void rollbackToDefaultConfig(final Entry<String, Configuration> currentConfigEntry) throws IOException {\n        logger.info(\"Rolling back to default configuration for component pid: '{}'\", currentConfigEntry.getKey());\n        rollbackConfigurationInternal(\n                new ComponentConfigurationImpl(currentConfigEntry.getKey(), null, new HashMap<>()),\n                Optional.of(currentConfigEntry.getValue()));\n    }\n\n    private boolean isFactoryComponent(final Entry<String, Configuration> currentConfigEntry) {\n        return currentConfigEntry.getValue().getFactoryPid() != null;\n    }\n\n    private Map<String, Configuration> getCurrentConfigs() throws KuraException {\n\n        Map<String, Configuration> currentConfigs = new HashMap<>();\n\n        try {\n            Configuration[] currentKuraServiceConfigs = this.configurationAdmin\n                    .listConfigurations(\"(\" + KURA_SERVICE_PID + \"=*)\");\n\n            if (currentKuraServiceConfigs != null) {\n                currentConfigs = Arrays.stream(currentKuraServiceConfigs).filter(this::isKuraServicePidString)\n                        .collect(Collectors.toMap(this::getKuraServicePid, Function.identity()));\n            }\n\n        } catch (final IOException | InvalidSyntaxException e) {\n            throw new KuraException(KuraErrorCode.IO_ERROR, e);\n        }\n        return currentConfigs;\n    }\n\n    private boolean isKuraServicePidString(Configuration config) {\n        return config.getProperties().get(KURA_SERVICE_PID) instanceof String;\n    }\n\n    private String getKuraServicePid(Configuration config) {\n        return (String) config.getProperties().get(KURA_SERVICE_PID);\n    }\n\n    private Map<String, ComponentConfiguration> getSnapshotConfigs(long id) throws KuraException {\n        XmlComponentConfigurations xmlConfigs = loadEncryptedSnapshotFileContent(id);\n        List<ComponentConfiguration> configs = xmlConfigs.getConfigurations();\n\n        return ComponentUtil.toMap(configs);\n    }\n\n    private static final class TrackedComponentFactory {\n\n        private final String factoryPid;\n        private final Bundle provider;\n\n        public TrackedComponentFactory(final String factoryPid, final Bundle provider) {\n            this.factoryPid = factoryPid;\n            this.provider = provider;\n        }\n\n        public String getFactoryPid() {\n            return this.factoryPid;\n        }\n\n        public Bundle getProviderBundle() {\n            return this.provider;\n        }\n\n        @Override\n        public int hashCode() {\n            final int prime = 31;\n            int result = 1;\n            result = prime * result + (this.factoryPid == null ? 0 : this.factoryPid.hashCode());\n            return result;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (obj == null || getClass() != obj.getClass()) {\n                return false;\n            }\n            TrackedComponentFactory other = (TrackedComponentFactory) obj;\n            if (this.factoryPid == null) {\n                if (other.factoryPid != null) {\n                    return false;\n                }\n            } else if (!this.factoryPid.equals(other.factoryPid)) {\n                return false;\n            }\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/Password.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\n/**\n *\n * @author matteo.maiero\n *\n */\n\n@Deprecated\npublic class Password {\n\n    private final char[] password;\n\n    public Password(String password) {\n        super();\n        this.password = password.toCharArray();\n    }\n\n    public Password(char[] password) {\n        super();\n        this.password = password;\n    }\n\n    public char[] getPassword() {\n        return this.password;\n    }\n\n    @Override\n    public String toString() {\n        return new String(this.password);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlComponentConfigurations.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport java.util.List;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\n\n/**\n * Utility class to serialize a set of configurations.\n * This is used to serialize a full snapshot.\n */\npublic class XmlComponentConfigurations {\n\n    private List<ComponentConfiguration> configurations;\n\n    public XmlComponentConfigurations() {\n    }\n\n    public List<ComponentConfiguration> getConfigurations() {\n        return this.configurations;\n    }\n\n    public void setConfigurations(List<ComponentConfiguration> configurations) {\n        this.configurations = configurations;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlConfigPropertiesAdapted.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\n/**\n * Helper class to serialize a property in XML.\n */\npublic class XmlConfigPropertiesAdapted {\n\n    private XmlConfigPropertyAdapted[] properties;\n\n    public XmlConfigPropertiesAdapted() {\n    }\n\n    public XmlConfigPropertyAdapted[] getProperties() {\n        return this.properties;\n    }\n\n    public void setProperties(XmlConfigPropertyAdapted[] properties) {\n        this.properties = properties;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlConfigPropertiesAdapter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.core.configuration.XmlConfigPropertyAdapted.ConfigPropertyType;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceReference;\n\n/**\n * Helper class to serialize a set of properties in XML.\n */\npublic class XmlConfigPropertiesAdapter {\n\n    public XmlConfigPropertiesAdapted marshal(Map<String, Object> props) throws Exception {\n        List<XmlConfigPropertyAdapted> adaptedValues = new ArrayList<>();\n        if (props != null) {\n\n            for (Entry<String, Object> prop : props.entrySet()) {\n\n                XmlConfigPropertyAdapted adaptedValue = new XmlConfigPropertyAdapted();\n\n                String key = prop.getKey();\n                adaptedValue.setName(key);\n\n                Object value = prop.getValue();\n                if (value instanceof String) {\n                    adaptedValue.setArray(false);\n                    adaptedValue.setType(ConfigPropertyType.STRING_TYPE);\n                    adaptedValue.setValues(new String[] { value.toString() });\n                } else if (value instanceof Long) {\n                    adaptedValue.setArray(false);\n                    adaptedValue.setType(ConfigPropertyType.LONG_TYPE);\n                    adaptedValue.setValues(new String[] { value.toString() });\n                } else if (value instanceof Double) {\n                    adaptedValue.setArray(false);\n                    adaptedValue.setType(ConfigPropertyType.DOUBLE_TYPE);\n                    adaptedValue.setValues(new String[] { value.toString() });\n                } else if (value instanceof Float) {\n                    adaptedValue.setArray(false);\n                    adaptedValue.setType(ConfigPropertyType.FLOAT_TYPE);\n                    adaptedValue.setValues(new String[] { value.toString() });\n                } else if (value instanceof Integer) {\n                    adaptedValue.setArray(false);\n                    adaptedValue.setType(ConfigPropertyType.INTEGER_TYPE);\n                    adaptedValue.setValues(new String[] { value.toString() });\n                } else if (value instanceof Byte) {\n                    adaptedValue.setArray(false);\n                    adaptedValue.setType(ConfigPropertyType.BYTE_TYPE);\n                    adaptedValue.setValues(new String[] { value.toString() });\n                } else if (value instanceof Character) {\n                    adaptedValue.setArray(false);\n                    adaptedValue.setType(ConfigPropertyType.CHAR_TYPE);\n                    adaptedValue.setValues(new String[] { value.toString() });\n                } else if (value instanceof Boolean) {\n                    adaptedValue.setArray(false);\n                    adaptedValue.setType(ConfigPropertyType.BOOLEAN_TYPE);\n                    adaptedValue.setValues(new String[] { value.toString() });\n                } else if (value instanceof Short) {\n                    adaptedValue.setArray(false);\n                    adaptedValue.setType(ConfigPropertyType.SHORT_TYPE);\n                    adaptedValue.setValues(new String[] { value.toString() });\n                } else if (value instanceof Password) {\n                    BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();\n                    ServiceReference<CryptoService> cryptoServiceRef = bundleContext\n                            .getServiceReference(CryptoService.class);\n                    CryptoService cryptoService = bundleContext.getService(cryptoServiceRef);\n\n                    adaptedValue.setArray(false);\n                    adaptedValue.setEncrypted(true);\n                    adaptedValue.setType(ConfigPropertyType.PASSWORD_TYPE);\n                    adaptedValue.setValues(new String[] { cryptoService.encodeBase64(value.toString()) });\n                } else if (value instanceof String[]) {\n                    adaptedValue.setArray(true);\n                    adaptedValue.setType(ConfigPropertyType.STRING_TYPE);\n                    adaptedValue.setValues((String[]) value);\n                } else if (value instanceof Long[]) {\n                    adaptedValue.setArray(true);\n                    adaptedValue.setType(ConfigPropertyType.LONG_TYPE);\n                    Long[] nativeValues = (Long[]) value;\n                    String[] stringValues = new String[nativeValues.length];\n                    for (int i = 0; i < nativeValues.length; i++) {\n                        if (nativeValues[i] != null) {\n                            stringValues[i] = nativeValues[i].toString();\n                        }\n                    }\n                    adaptedValue.setValues(stringValues);\n                } else if (value instanceof Double[]) {\n                    adaptedValue.setArray(true);\n                    adaptedValue.setType(ConfigPropertyType.DOUBLE_TYPE);\n                    Double[] nativeValues = (Double[]) value;\n                    String[] stringValues = new String[nativeValues.length];\n                    for (int i = 0; i < nativeValues.length; i++) {\n                        if (nativeValues[i] != null) {\n                            stringValues[i] = nativeValues[i].toString();\n                        }\n                    }\n                    adaptedValue.setValues(stringValues);\n                } else if (value instanceof Float[]) {\n                    adaptedValue.setArray(true);\n                    adaptedValue.setType(ConfigPropertyType.FLOAT_TYPE);\n                    Float[] nativeValues = (Float[]) value;\n                    String[] stringValues = new String[nativeValues.length];\n                    for (int i = 0; i < nativeValues.length; i++) {\n                        if (nativeValues[i] != null) {\n                            stringValues[i] = nativeValues[i].toString();\n                        }\n                    }\n                    adaptedValue.setValues(stringValues);\n                } else if (value instanceof Integer[]) {\n                    adaptedValue.setArray(true);\n                    adaptedValue.setType(ConfigPropertyType.INTEGER_TYPE);\n                    Integer[] nativeValues = (Integer[]) value;\n                    String[] stringValues = new String[nativeValues.length];\n                    for (int i = 0; i < nativeValues.length; i++) {\n                        if (nativeValues[i] != null) {\n                            stringValues[i] = nativeValues[i].toString();\n                        }\n                    }\n                    adaptedValue.setValues(stringValues);\n                } else if (value instanceof Byte[]) {\n                    adaptedValue.setArray(true);\n                    adaptedValue.setType(ConfigPropertyType.BYTE_TYPE);\n                    Byte[] nativeValues = (Byte[]) value;\n                    String[] stringValues = new String[nativeValues.length];\n                    for (int i = 0; i < nativeValues.length; i++) {\n                        if (nativeValues[i] != null) {\n                            stringValues[i] = nativeValues[i].toString();\n                        }\n                    }\n                    adaptedValue.setValues(stringValues);\n                } else if (value instanceof Character[]) {\n                    adaptedValue.setArray(true);\n                    adaptedValue.setType(ConfigPropertyType.CHAR_TYPE);\n                    Character[] nativeValues = (Character[]) value;\n                    String[] stringValues = new String[nativeValues.length];\n                    for (int i = 0; i < nativeValues.length; i++) {\n                        if (nativeValues[i] != null) {\n                            stringValues[i] = nativeValues[i].toString();\n                        }\n                    }\n                    adaptedValue.setValues(stringValues);\n                } else if (value instanceof Boolean[]) {\n                    adaptedValue.setArray(true);\n                    adaptedValue.setType(ConfigPropertyType.BOOLEAN_TYPE);\n                    Boolean[] nativeValues = (Boolean[]) value;\n                    String[] stringValues = new String[nativeValues.length];\n                    for (int i = 0; i < nativeValues.length; i++) {\n                        if (nativeValues[i] != null) {\n                            stringValues[i] = nativeValues[i].toString();\n                        }\n                    }\n                    adaptedValue.setValues(stringValues);\n                } else if (value instanceof Short[]) {\n                    adaptedValue.setArray(true);\n                    adaptedValue.setType(ConfigPropertyType.SHORT_TYPE);\n                    Short[] nativeValues = (Short[]) value;\n                    String[] stringValues = new String[nativeValues.length];\n                    for (int i = 0; i < nativeValues.length; i++) {\n                        if (nativeValues[i] != null) {\n                            stringValues[i] = nativeValues[i].toString();\n                        }\n                    }\n                    adaptedValue.setValues(stringValues);\n                } else if (value instanceof Password[]) {\n                    BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();\n                    ServiceReference<CryptoService> cryptoServiceRef = bundleContext\n                            .getServiceReference(CryptoService.class);\n                    CryptoService cryptoService = bundleContext.getService(cryptoServiceRef);\n\n                    adaptedValue.setArray(true);\n                    adaptedValue.setEncrypted(true);\n                    adaptedValue.setType(ConfigPropertyType.PASSWORD_TYPE);\n                    Password[] nativeValues = (Password[]) value;\n                    String[] stringValues = new String[nativeValues.length];\n                    for (int i = 0; i < nativeValues.length; i++) {\n                        if (nativeValues[i] != null) {\n                            stringValues[i] = cryptoService.encodeBase64(nativeValues[i].toString());\n                        }\n                    }\n                    adaptedValue.setValues(stringValues);\n                }\n\n                if (adaptedValue.getValues() == null || adaptedValue.getValues().length > 0) {\n                    adaptedValues.add(adaptedValue);\n                }\n            }\n        }\n\n        XmlConfigPropertiesAdapted result = new XmlConfigPropertiesAdapted();\n        result.setProperties(adaptedValues.toArray(new XmlConfigPropertyAdapted[] {}));\n        return result;\n    }\n\n    public Map<String, Object> unmarshal(XmlConfigPropertiesAdapted adaptedPropsAdapted) throws Exception {\n        Map<String, Object> properties = new HashMap<>();\n        XmlConfigPropertyAdapted[] adaptedProps = adaptedPropsAdapted.getProperties();\n        if (adaptedProps == null) {\n            return properties;\n        }\n        for (XmlConfigPropertyAdapted adaptedProp : adaptedProps) {\n            String propName = adaptedProp.getName();\n            ConfigPropertyType type = adaptedProp.getType();\n            if (type != null) {\n                Object propvalue = null;\n                if (adaptedProp.getArray() == false) {\n                    switch (adaptedProp.getType()) {\n                    case STRING_TYPE:\n                        propvalue = adaptedProp.getValues()[0];\n                        break;\n                    case LONG_TYPE:\n                        propvalue = Long.parseLong(adaptedProp.getValues()[0]);\n                        break;\n                    case DOUBLE_TYPE:\n                        propvalue = Double.parseDouble(adaptedProp.getValues()[0]);\n                        break;\n                    case FLOAT_TYPE:\n                        propvalue = Float.parseFloat(adaptedProp.getValues()[0]);\n                        break;\n                    case INTEGER_TYPE:\n                        propvalue = Integer.parseInt(adaptedProp.getValues()[0]);\n                        break;\n                    case BYTE_TYPE:\n                        propvalue = Byte.parseByte(adaptedProp.getValues()[0]);\n                        break;\n                    case CHAR_TYPE:\n                        String s = adaptedProp.getValues()[0];\n                        propvalue = Character.valueOf(s.charAt(0));\n                        break;\n                    case BOOLEAN_TYPE:\n                        propvalue = Boolean.parseBoolean(adaptedProp.getValues()[0]);\n                        break;\n                    case SHORT_TYPE:\n                        propvalue = Short.parseShort(adaptedProp.getValues()[0]);\n                        break;\n                    case PASSWORD_TYPE:\n                        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();\n                        ServiceReference<CryptoService> cryptoServiceRef = bundleContext\n                                .getServiceReference(CryptoService.class);\n                        CryptoService cryptoService = bundleContext.getService(cryptoServiceRef);\n\n                        propvalue = adaptedProp.getValues()[0];\n                        if (adaptedProp.isEncrypted()) {\n                            try {\n                                propvalue = new Password(cryptoService.decryptAes(((String) propvalue).toCharArray()));\n                            } catch (KuraException e) {\n                                propvalue = new Password(cryptoService.decodeBase64((String) propvalue));\n                            }\n                        } else {\n                            propvalue = new Password((String) propvalue);\n                        }\n                        break;\n                    }\n                } else {\n                    // If we are dealing with an empty array, skip this element.\n                    // Starting from 1.2.0 an empty array will never be present in a snapshot.\n                    if (adaptedProp.getValues() == null) {\n                        continue;\n                    }\n                    switch (adaptedProp.getType()) {\n                    case STRING_TYPE:\n                        propvalue = adaptedProp.getValues();\n                        break;\n                    case LONG_TYPE:\n                        Long[] longValues = new Long[adaptedProp.getValues().length];\n                        for (int i = 0; i < adaptedProp.getValues().length; i++) {\n                            if (adaptedProp.getValues()[i] != null) {\n                                longValues[i] = Long.parseLong(adaptedProp.getValues()[i]);\n                            }\n                        }\n                        propvalue = longValues;\n                        break;\n                    case DOUBLE_TYPE:\n                        Double[] doubleValues = new Double[adaptedProp.getValues().length];\n                        for (int i = 0; i < adaptedProp.getValues().length; i++) {\n                            if (adaptedProp.getValues()[i] != null) {\n                                doubleValues[i] = Double.parseDouble(adaptedProp.getValues()[i]);\n                            }\n                        }\n                        propvalue = doubleValues;\n                        break;\n                    case FLOAT_TYPE:\n                        Float[] floatValues = new Float[adaptedProp.getValues().length];\n                        for (int i = 0; i < adaptedProp.getValues().length; i++) {\n                            if (adaptedProp.getValues()[i] != null) {\n                                floatValues[i] = Float.parseFloat(adaptedProp.getValues()[i]);\n                            }\n                        }\n                        propvalue = floatValues;\n                        break;\n                    case INTEGER_TYPE:\n                        Integer[] intValues = new Integer[adaptedProp.getValues().length];\n                        for (int i = 0; i < adaptedProp.getValues().length; i++) {\n                            if (adaptedProp.getValues()[i] != null) {\n                                intValues[i] = Integer.parseInt(adaptedProp.getValues()[i]);\n                            }\n                        }\n                        propvalue = intValues;\n                        break;\n                    case BYTE_TYPE:\n                        Byte[] byteValues = new Byte[adaptedProp.getValues().length];\n                        for (int i = 0; i < adaptedProp.getValues().length; i++) {\n                            if (adaptedProp.getValues()[i] != null) {\n                                byteValues[i] = Byte.parseByte(adaptedProp.getValues()[i]);\n                            }\n                        }\n                        propvalue = byteValues;\n                        break;\n                    case CHAR_TYPE:\n                        Character[] charValues = new Character[adaptedProp.getValues().length];\n                        for (int i = 0; i < adaptedProp.getValues().length; i++) {\n                            if (adaptedProp.getValues()[i] != null) {\n                                String s = adaptedProp.getValues()[i];\n                                charValues[i] = Character.valueOf(s.charAt(0));\n                            }\n                        }\n                        propvalue = charValues;\n                        break;\n                    case BOOLEAN_TYPE:\n                        Boolean[] booleanValues = new Boolean[adaptedProp.getValues().length];\n                        for (int i = 0; i < adaptedProp.getValues().length; i++) {\n                            if (adaptedProp.getValues()[i] != null) {\n                                booleanValues[i] = Boolean.parseBoolean(adaptedProp.getValues()[i]);\n                            }\n                        }\n                        propvalue = booleanValues;\n                        break;\n                    case SHORT_TYPE:\n                        Short[] shortValues = new Short[adaptedProp.getValues().length];\n                        for (int i = 0; i < adaptedProp.getValues().length; i++) {\n                            if (adaptedProp.getValues()[i] != null) {\n                                shortValues[i] = Short.parseShort(adaptedProp.getValues()[i]);\n                            }\n                        }\n                        propvalue = shortValues;\n                        break;\n                    case PASSWORD_TYPE:\n                        BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();\n                        ServiceReference<CryptoService> cryptoServiceRef = bundleContext\n                                .getServiceReference(CryptoService.class);\n                        CryptoService cryptoService = bundleContext.getService(cryptoServiceRef);\n\n                        Password[] pwdValues = new Password[adaptedProp.getValues().length];\n                        for (int i = 0; i < adaptedProp.getValues().length; i++) {\n                            if (adaptedProp.getValues()[i] != null) {\n                                if (adaptedProp.isEncrypted()) {\n                                    try {\n                                        pwdValues[i] = new Password(\n                                                cryptoService.decryptAes(adaptedProp.getValues()[i].toCharArray()));\n                                    } catch (KuraException e) {\n                                        pwdValues[i] = new Password(\n                                                cryptoService.decodeBase64(adaptedProp.getValues()[i]));\n                                    }\n                                } else {\n                                    pwdValues[i] = new Password(adaptedProp.getValues()[i]);\n                                }\n                            }\n                        }\n                        propvalue = pwdValues;\n                        break;\n                    }\n                }\n                properties.put(propName, propvalue);\n            }\n        }\n        return properties;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlConfigPropertyAdapted.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\n/**\n * Helper class to serialize a property in XML.\n */\npublic class XmlConfigPropertyAdapted {\n\n    public enum ConfigPropertyType {\n        STRING_TYPE,\n        LONG_TYPE,\n        DOUBLE_TYPE,\n        FLOAT_TYPE,\n        INTEGER_TYPE,\n        BYTE_TYPE,\n        CHAR_TYPE,\n        BOOLEAN_TYPE,\n        SHORT_TYPE,\n        PASSWORD_TYPE\n    }\n\n    private String name;\n\n    private boolean array;\n\n    private boolean encrypted;\n\n    private ConfigPropertyType type;\n\n    private String[] values;\n\n    public XmlConfigPropertyAdapted() {\n    }\n\n    public XmlConfigPropertyAdapted(String name, ConfigPropertyType type, String[] values) {\n        super();\n\n        this.name = name;\n        this.type = type;\n        this.values = values;\n        this.encrypted = false;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public boolean getArray() {\n        return this.array;\n    }\n\n    public void setArray(boolean array) {\n        this.array = array;\n    }\n\n    public ConfigPropertyType getType() {\n        return this.type;\n    }\n\n    public void setType(ConfigPropertyType type) {\n        this.type = type;\n    }\n\n    public boolean isEncrypted() {\n        return this.encrypted;\n    }\n\n    public void setEncrypted(boolean encrypted) {\n        this.encrypted = encrypted;\n    }\n\n    public String[] getValues() {\n        return this.values;\n    }\n\n    public void setValues(String[] values) {\n        this.values = values;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlSnapshotIdResult.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport java.util.List;\n\n/**\n * Utility class to serialize a set of snapshot ids.\n */\npublic class XmlSnapshotIdResult {\n\n    private List<Long> snapshotIds;\n\n    public XmlSnapshotIdResult() {\n    }\n\n    public List<Long> getSnapshotIds() {\n        return this.snapshotIds;\n    }\n\n    public void setSnapshotIds(List<Long> snapshotIds) {\n        this.snapshotIds = snapshotIds;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/ObjectFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\n/**\n * This object contains factory methods for each\n * Java content interface and Java element interface\n * generated in the org.eclipse.kura.core.configuration.metatype package.\n * <p>\n * An ObjectFactory allows you to programmatically\n * construct new instances of the Java representation\n * for XML content. The Java representation of XML\n * content can consist of schema derived interfaces\n * and classes representing the binding of schema\n * type definitions, element declarations and model\n * groups. Factory methods for each of these are\n * provided in this class.\n *\n */\n\npublic class ObjectFactory {\n\n    /**\n     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package:\n     * org.eclipse.kura.core.configuration.metatype\n     *\n     */\n    public ObjectFactory() {\n    }\n\n    /**\n     * Create an instance of {@link Ticon }\n     *\n     */\n    public Ticon createTicon() {\n        return new Ticon();\n    }\n\n    /**\n     * Create an instance of {@link Tattribute }\n     *\n     */\n    public Tattribute createTattribute() {\n        return new Tattribute();\n    }\n\n    /**\n     * Create an instance of {@link Tmetadata }\n     *\n     */\n    public Tmetadata createTmetadata() {\n        return new Tmetadata();\n    }\n\n    /**\n     * Create an instance of {@link Tdesignate }\n     *\n     */\n    public Tdesignate createTdesignate() {\n        return new Tdesignate();\n    }\n\n    /**\n     * Create an instance of {@link Tad }\n     *\n     */\n    public Tad createTad() {\n        return new Tad();\n    }\n\n    /**\n     * Create an instance of {@link Tobject }\n     *\n     */\n    public Tobject createTobject() {\n        return new Tobject();\n    }\n\n    /**\n     * Create an instance of {@link Tocd }\n     *\n     */\n    public Tocd createTocd() {\n        return new Tocd();\n    }\n\n    /**\n     * Create an instance of {@link Toption }\n     *\n     */\n    public Toption createToption() {\n        return new Toption();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tad.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.xml.namespace.QName;\n\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.Option;\nimport org.eclipse.kura.configuration.metatype.Scalar;\nimport org.w3c.dom.Element;\n\n/**\n * <p>\n * Java class for Tad complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tad\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"Option\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Toption\" maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *       &lt;attribute name=\"name\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"description\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"id\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"type\" use=\"required\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tscalar\" />\n *       &lt;attribute name=\"cardinality\" type=\"{http://www.w3.org/2001/XMLSchema}int\" default=\"0\" />\n *       &lt;attribute name=\"min\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"max\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"default\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}boolean\" default=\"true\" />\n *       &lt;anyAttribute/>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n *\n *\n */\n\npublic class Tad implements AD {\n\n    protected List<Toption> option;\n    protected List<Object> any;\n    protected String name;\n    protected String description;\n    protected String id;\n    protected Tscalar type;\n    protected Integer cardinality;\n    protected String min;\n    protected String max;\n    protected String _default;\n    protected Boolean required;\n    private final Map<QName, String> otherAttributes = new HashMap<>();\n\n    /**\n     * Gets the value of the option property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the option property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getOption().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Toption }\n     *\n     *\n     */\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public List<Option> getOption() {\n        if (this.option == null) {\n            this.option = new ArrayList<>();\n        }\n        return (List<Option>) (List<?>) this.option;\n    }\n\n    public void setOption(Toption o) {\n        if (this.option == null) {\n            this.option = new ArrayList<>();\n        }\n        this.option.add(o);\n    }\n\n    /**\n     * Gets the value of the any property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the any property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAny().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Element }\n     * {@link Object }\n     *\n     *\n     */\n    public List<Object> getAny() {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        return this.any;\n    }\n\n    /**\n     * Gets the value of the name property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getName() {\n        return this.name;\n    }\n\n    /**\n     * Sets the value of the name property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setName(String value) {\n        this.name = value;\n    }\n\n    /**\n     * Gets the value of the description property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getDescription() {\n        return this.description;\n    }\n\n    /**\n     * Sets the value of the description property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setDescription(String value) {\n        this.description = value;\n    }\n\n    /**\n     * Gets the value of the id property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getId() {\n        return this.id;\n    }\n\n    /**\n     * Sets the value of the id property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setId(String value) {\n        this.id = value;\n    }\n\n    /**\n     * Gets the value of the type property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Tscalar }\n     *\n     */\n    @Override\n    public Scalar getType() {\n        return Scalar.valueOf(this.type.name());\n    }\n\n    /**\n     * Sets the value of the type property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link Tscalar }\n     *\n     */\n    public void setType(Tscalar value) {\n        this.type = value;\n    }\n\n    /**\n     * Gets the value of the cardinality property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Integer }\n     *\n     */\n    @Override\n    public int getCardinality() {\n        if (this.cardinality == null) {\n            return 0;\n        } else {\n            return this.cardinality;\n        }\n    }\n\n    /**\n     * Sets the value of the cardinality property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link Integer }\n     *\n     */\n    public void setCardinality(Integer value) {\n        this.cardinality = value;\n    }\n\n    /**\n     * Gets the value of the min property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getMin() {\n        return this.min;\n    }\n\n    /**\n     * Sets the value of the min property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setMin(String value) {\n        this.min = value;\n    }\n\n    /**\n     * Gets the value of the max property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getMax() {\n        return this.max;\n    }\n\n    /**\n     * Sets the value of the max property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setMax(String value) {\n        this.max = value;\n    }\n\n    /**\n     * Gets the value of the default property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getDefault() {\n        return this._default;\n    }\n\n    /**\n     * Sets the value of the default property.\n     * Commas ',' need to be escaped with '\\' if not intended to separate\n     * elements of the array.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }.\n     *            If cardinality = n > 1 is specified, then must contain at most n String elements separated by ','.\n     *\n     */\n    public void setDefault(String value) {\n        this._default = value;\n    }\n\n    /**\n     * Gets the value of the required property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Boolean }\n     *\n     */\n    @Override\n    public boolean isRequired() {\n        if (this.required == null) {\n            return true;\n        } else {\n            return this.required;\n        }\n    }\n\n    /**\n     * Sets the value of the required property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link Boolean }\n     *\n     */\n    public void setRequired(Boolean value) {\n        this.required = value;\n    }\n\n    /**\n     * Gets a map that contains attributes that aren't bound to any typed property on this class.\n     *\n     * <p>\n     * the map is keyed by the name of the attribute and\n     * the value is the string value of the attribute.\n     *\n     * the map returned by this method is live, and you can add new attribute\n     * by updating the map directly. Because of this design, there's no setter.\n     *\n     *\n     * @return\n     *         always non-null\n     */\n    public Map<QName, String> getOtherAttributes() {\n        return this.otherAttributes;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tattribute.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.xml.namespace.QName;\n\nimport org.eclipse.kura.configuration.metatype.Attribute;\nimport org.w3c.dom.Element;\n\n/**\n * <p>\n * Java class for Tattribute complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tattribute\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"Value\" type=\"{http://www.w3.org/2001/XMLSchema}string\" maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *       &lt;attribute name=\"adref\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"content\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;anyAttribute/>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n *\n *\n */\npublic class Tattribute implements Attribute {\n\n    protected List<String> value;\n    protected List<Object> any;\n    protected String adref;\n    protected String content;\n    private final Map<QName, String> otherAttributes = new HashMap<>();\n\n    /**\n     * Gets the value of the value property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the value property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getValue().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link String }\n     *\n     *\n     */\n    @Override\n    public List<String> getValue() {\n        if (this.value == null) {\n            this.value = new ArrayList<>();\n        }\n        return this.value;\n    }\n\n    /**\n     * Gets the value of the any property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the any property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAny().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Element }\n     * {@link Object }\n     *\n     *\n     */\n    public List<Object> getAny() {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        return this.any;\n    }\n\n    /**\n     * Gets the value of the adref property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getAdref() {\n        return this.adref;\n    }\n\n    /**\n     * Sets the value of the adref property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setAdref(String value) {\n        this.adref = value;\n    }\n\n    /**\n     * Gets the value of the content property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getContent() {\n        return this.content;\n    }\n\n    /**\n     * Sets the value of the content property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setContent(String value) {\n        this.content = value;\n    }\n\n    /**\n     * Gets a map that contains attributes that aren't bound to any typed property on this class.\n     *\n     * <p>\n     * the map is keyed by the name of the attribute and\n     * the value is the string value of the attribute.\n     *\n     * the map returned by this method is live, and you can add new attribute\n     * by updating the map directly. Because of this design, there's no setter.\n     *\n     *\n     * @return\n     *         always non-null\n     */\n    public Map<QName, String> getOtherAttributes() {\n        return this.otherAttributes;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tdesignate.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.xml.namespace.QName;\n\nimport org.eclipse.kura.configuration.metatype.Designate;\nimport org.w3c.dom.Element;\n\n/**\n * <p>\n * Java class for Tdesignate complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tdesignate\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"Object\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tobject\"/>\n *         &lt;any processContents='lax' maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *       &lt;attribute name=\"pid\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"factoryPid\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"bundle\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"optional\" type=\"{http://www.w3.org/2001/XMLSchema}boolean\" default=\"false\" />\n *       &lt;attribute name=\"merge\" type=\"{http://www.w3.org/2001/XMLSchema}boolean\" default=\"false\" />\n *       &lt;anyAttribute/>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n *\n *\n */\n\npublic class Tdesignate implements Designate {\n\n    protected Tobject object;\n    protected List<Object> any;\n    protected String pid;\n    protected String factoryPid;\n    protected String bundle;\n    protected Boolean optional;\n    protected Boolean merge;\n    private final Map<QName, String> otherAttributes = new HashMap<>();\n\n    /**\n     * Gets the value of the object property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Tobject }\n     *\n     */\n    @Override\n    public Tobject getObject() {\n        return this.object;\n    }\n\n    /**\n     * Sets the value of the object property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link Tobject }\n     *\n     */\n    public void setObject(Tobject value) {\n        this.object = value;\n    }\n\n    /**\n     * Gets the value of the any property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the any property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAny().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Element }\n     * {@link Object }\n     *\n     *\n     */\n    public List<Object> getAny() {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        return this.any;\n    }\n\n    /**\n     * Gets the value of the pid property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getPid() {\n        return this.pid;\n    }\n\n    /**\n     * Sets the value of the pid property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setPid(String value) {\n        this.pid = value;\n    }\n\n    /**\n     * Gets the value of the factoryPid property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getFactoryPid() {\n        return this.factoryPid;\n    }\n\n    /**\n     * Sets the value of the factoryPid property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setFactoryPid(String value) {\n        this.factoryPid = value;\n    }\n\n    /**\n     * Gets the value of the bundle property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getBundle() {\n        return this.bundle;\n    }\n\n    /**\n     * Sets the value of the bundle property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setBundle(String value) {\n        this.bundle = value;\n    }\n\n    /**\n     * Gets the value of the optional property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Boolean }\n     *\n     */\n    @Override\n    public boolean isOptional() {\n        if (this.optional == null) {\n            return false;\n        } else {\n            return this.optional;\n        }\n    }\n\n    /**\n     * Sets the value of the optional property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link Boolean }\n     *\n     */\n    public void setOptional(Boolean value) {\n        this.optional = value;\n    }\n\n    /**\n     * Gets the value of the merge property.\n     *\n     * @return\n     *         possible object is\n     *         {@link Boolean }\n     *\n     */\n    @Override\n    public boolean isMerge() {\n        if (this.merge == null) {\n            return false;\n        } else {\n            return this.merge;\n        }\n    }\n\n    /**\n     * Sets the value of the merge property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link Boolean }\n     *\n     */\n    public void setMerge(Boolean value) {\n        this.merge = value;\n    }\n\n    /**\n     * Gets a map that contains attributes that aren't bound to any typed property on this class.\n     *\n     * <p>\n     * the map is keyed by the name of the attribute and\n     * the value is the string value of the attribute.\n     *\n     * the map returned by this method is live, and you can add new attribute\n     * by updating the map directly. Because of this design, there's no setter.\n     *\n     *\n     * @return\n     *         always non-null\n     */\n    public Map<QName, String> getOtherAttributes() {\n        return this.otherAttributes;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Ticon.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.xml.namespace.QName;\n\nimport org.eclipse.kura.configuration.metatype.Icon;\nimport org.w3c.dom.Element;\n\n/**\n * <p>\n * Java class for Ticon complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Ticon\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;any processContents='lax' maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *       &lt;attribute name=\"resource\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"size\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}positiveInteger\" />\n *       &lt;anyAttribute/>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n *\n *\n */\n\npublic class Ticon implements Icon {\n\n    protected List<Object> any;\n    protected String resource;\n    protected BigInteger size;\n    private final Map<QName, String> otherAttributes = new HashMap<>();\n\n    /**\n     * Gets the value of the any property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the any property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAny().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Element }\n     * {@link Object }\n     *\n     *\n     */\n    public List<Object> getAny() {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        return this.any;\n    }\n\n    public void setAny(Object o) {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        this.any.add(o);\n    }\n\n    /**\n     * Gets the value of the resource property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getResource() {\n        return this.resource;\n    }\n\n    /**\n     * Sets the value of the resource property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setResource(String value) {\n        this.resource = value;\n    }\n\n    /**\n     * Gets the value of the size property.\n     *\n     * @return\n     *         possible object is\n     *         {@link BigInteger }\n     *\n     */\n    @Override\n    public BigInteger getSize() {\n        return this.size;\n    }\n\n    /**\n     * Sets the value of the size property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link BigInteger }\n     *\n     */\n    public void setSize(BigInteger value) {\n        this.size = value;\n    }\n\n    /**\n     * Gets a map that contains attributes that aren't bound to any typed property on this class.\n     *\n     * <p>\n     * the map is keyed by the name of the attribute and\n     * the value is the string value of the attribute.\n     *\n     * the map returned by this method is live, and you can add new attribute\n     * by updating the map directly. Because of this design, there's no setter.\n     *\n     *\n     * @return\n     *         always non-null\n     */\n    public Map<QName, String> getOtherAttributes() {\n        return this.otherAttributes;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tmetadata.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.xml.namespace.QName;\n\nimport org.eclipse.kura.configuration.metatype.Designate;\nimport org.eclipse.kura.configuration.metatype.MetaData;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.w3c.dom.Element;\n\n/**\n * <p>\n * Java class for Tmetadata complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tmetadata\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"OCD\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tocd\" maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *         &lt;element name=\"Designate\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tdesignate\" maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *       &lt;attribute name=\"localization\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;anyAttribute/>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n *\n *\n */\n\npublic class Tmetadata implements MetaData {\n\n    protected List<Tocd> ocd;\n    protected List<Tdesignate> designate;\n    protected List<Object> any;\n    protected String localization;\n    private final Map<QName, String> otherAttributes = new HashMap<>();\n\n    /**\n     * Gets the value of the ocd property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the ocd property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getOCD().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Tocd }\n     *\n     *\n     */\n    @Override\n    public List<OCD> getOCD() {\n        if (this.ocd == null) {\n            this.ocd = new ArrayList<>();\n        }\n        return new ArrayList<>(this.ocd);\n    }\n\n    public void setOCD(Tocd element) {\n        if (this.ocd == null) {\n            this.ocd = new ArrayList<>();\n        }\n        this.ocd.add(element);\n    }\n\n    /**\n     * Gets the value of the designate property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the designate property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getDesignate().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Tdesignate }\n     *\n     *\n     */\n    @Override\n    public List<Designate> getDesignate() {\n        if (this.designate == null) {\n            this.designate = new ArrayList<>();\n        }\n        return new ArrayList<>(this.designate);\n    }\n\n    public void setDesignate(Tdesignate td) {\n        if (this.designate == null) {\n            this.designate = new ArrayList<>();\n        }\n        this.designate.add(td);\n    }\n\n    /**\n     * Gets the value of the any property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the any property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAny().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Element }\n     * {@link Object }\n     *\n     *\n     */\n    public List<Object> getAny() {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        return this.any;\n    }\n\n    public void getAny(Object o) {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        this.any.add(o);\n    }\n\n    /**\n     * Gets the value of the localization property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getLocalization() {\n        return this.localization;\n    }\n\n    /**\n     * Sets the value of the localization property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setLocalization(String value) {\n        this.localization = value;\n    }\n\n    /**\n     * Gets a map that contains attributes that aren't bound to any typed property on this class.\n     *\n     * <p>\n     * the map is keyed by the name of the attribute and\n     * the value is the string value of the attribute.\n     *\n     * the map returned by this method is live, and you can add new attribute\n     * by updating the map directly. Because of this design, there's no setter.\n     *\n     *\n     * @return\n     *         always non-null\n     */\n    public Map<QName, String> getOtherAttributes() {\n        return this.otherAttributes;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tobject.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.xml.namespace.QName;\n\nimport org.eclipse.kura.configuration.metatype.Attribute;\nimport org.eclipse.kura.configuration.metatype.TObject;\nimport org.w3c.dom.Element;\n\n/**\n * <p>\n * Java class for Tobject complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tobject\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"Attribute\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tattribute\" maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *       &lt;attribute name=\"ocdref\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;anyAttribute/>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n *\n *\n */\n\npublic class Tobject implements TObject {\n\n    protected List<Tattribute> attribute;\n    protected List<Object> any;\n    protected String ocdref;\n    private final Map<QName, String> otherAttributes = new HashMap<>();\n\n    /**\n     * Gets the value of the attribute property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the attribute property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAttribute().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Tattribute }\n     *\n     *\n     */\n    @Override\n    public List<Attribute> getAttribute() {\n        if (this.attribute == null) {\n            this.attribute = new ArrayList<>();\n        }\n        return new ArrayList<>(this.attribute);\n    }\n\n    /**\n     * Gets the value of the any property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the any property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAny().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Element }\n     * {@link Object }\n     *\n     *\n     */\n    public List<Object> getAny() {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        return this.any;\n    }\n\n    /**\n     * Gets the value of the ocdref property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getOcdref() {\n        return this.ocdref;\n    }\n\n    /**\n     * Sets the value of the ocdref property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setOcdref(String value) {\n        this.ocdref = value;\n    }\n\n    /**\n     * Gets a map that contains attributes that aren't bound to any typed property on this class.\n     *\n     * <p>\n     * the map is keyed by the name of the attribute and\n     * the value is the string value of the attribute.\n     *\n     * the map returned by this method is live, and you can add new attribute\n     * by updating the map directly. Because of this design, there's no setter.\n     *\n     *\n     * @return\n     *         always non-null\n     */\n    public Map<QName, String> getOtherAttributes() {\n        return this.otherAttributes;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tocd.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.xml.namespace.QName;\n\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.Icon;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.w3c.dom.Element;\n\n/**\n * <p>\n * Java class for Tocd complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Tocd\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;element name=\"AD\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Tad\" maxOccurs=\"unbounded\"/>\n *         &lt;element name=\"Icon\" type=\"{http://www.osgi.org/xmlns/metatype/v1.2.0}Ticon\" maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *         &lt;any processContents='lax' namespace='##other' maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *       &lt;attribute name=\"name\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"description\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"id\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;anyAttribute/>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n *\n *\n */\n\npublic class Tocd implements OCD {\n\n    protected List<Tad> ad;\n    protected List<Ticon> icon;\n    protected List<Object> any;\n    protected String name;\n    protected String description;\n    protected String id;\n    private final Map<QName, String> otherAttributes = new HashMap<>();\n\n    /**\n     * Gets the value of the ad property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the ad property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAD().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Tad }\n     *\n     *\n     */\n    @Override\n    public List<AD> getAD() {\n        if (this.ad == null) {\n            this.ad = new ArrayList<>();\n        }\n        return new ArrayList<>(this.ad);\n    }\n\n    public void addAD(Tad tad) {\n        if (this.ad == null) {\n            this.ad = new ArrayList<>();\n        }\n\n        this.ad.add(tad);\n    }\n\n    /**\n     * Gets the value of the icon property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the icon property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getIcon().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Ticon }\n     *\n     *\n     */\n    @Override\n    public List<Icon> getIcon() {\n        if (this.icon == null) {\n            this.icon = new ArrayList<>();\n        }\n        return new ArrayList<>(this.icon);\n    }\n\n    public void setIcon(Ticon ti) {\n        if (this.icon == null) {\n            this.icon = new ArrayList<>();\n        }\n        this.icon.add(ti);\n    }\n\n    /**\n     * Gets the value of the any property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the any property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAny().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Element }\n     * {@link Object }\n     *\n     *\n     */\n    public List<Object> getAny() {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        return this.any;\n    }\n\n    public void setAny(Object o) {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        this.any.add(o);\n    }\n\n    /**\n     * Gets the value of the name property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getName() {\n        return this.name;\n    }\n\n    /**\n     * Sets the value of the name property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setName(String value) {\n        this.name = value;\n    }\n\n    /**\n     * Gets the value of the description property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getDescription() {\n        return this.description;\n    }\n\n    /**\n     * Sets the value of the description property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setDescription(String value) {\n        this.description = value;\n    }\n\n    /**\n     * Gets the value of the id property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getId() {\n        return this.id;\n    }\n\n    /**\n     * Sets the value of the id property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setId(String value) {\n        this.id = value;\n    }\n\n    /**\n     * Gets a map that contains attributes that aren't bound to any typed property on this class.\n     *\n     * <p>\n     * the map is keyed by the name of the attribute and\n     * the value is the string value of the attribute.\n     *\n     * the map returned by this method is live, and you can add new attribute\n     * by updating the map directly. Because of this design, there's no setter.\n     *\n     *\n     * @return\n     *         always non-null\n     */\n    public Map<QName, String> getOtherAttributes() {\n        return this.otherAttributes;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Toption.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.xml.namespace.QName;\n\nimport org.eclipse.kura.configuration.metatype.Option;\nimport org.w3c.dom.Element;\n\n/**\n * <p>\n * Java class for Toption complex type.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n *\n * <pre>\n * &lt;complexType name=\"Toption\">\n *   &lt;complexContent>\n *     &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}anyType\">\n *       &lt;sequence>\n *         &lt;any processContents='lax' maxOccurs=\"unbounded\" minOccurs=\"0\"/>\n *       &lt;/sequence>\n *       &lt;attribute name=\"label\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;attribute name=\"value\" use=\"required\" type=\"{http://www.w3.org/2001/XMLSchema}string\" />\n *       &lt;anyAttribute/>\n *     &lt;/restriction>\n *   &lt;/complexContent>\n * &lt;/complexType>\n * </pre>\n *\n *\n */\n\npublic class Toption implements Option {\n\n    protected List<Object> any;\n    protected String label;\n    protected String value;\n    private final Map<QName, String> otherAttributes = new HashMap<>();\n\n    /**\n     * Gets the value of the any property.\n     *\n     * <p>\n     * This accessor method returns a reference to the live list,\n     * not a snapshot. Therefore any modification you make to the\n     * returned list will be present inside the JAXB object.\n     * This is why there is not a <CODE>set</CODE> method for the any property.\n     *\n     * <p>\n     * For example, to add a new item, do as follows:\n     *\n     * <pre>\n     * getAny().add(newItem);\n     * </pre>\n     *\n     *\n     * <p>\n     * Objects of the following type(s) are allowed in the list\n     * {@link Element }\n     * {@link Object }\n     *\n     *\n     */\n    public List<Object> getAny() {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        return this.any;\n    }\n\n    public void setAny(Object o) {\n        if (this.any == null) {\n            this.any = new ArrayList<>();\n        }\n        this.any.add(o);\n    }\n\n    /**\n     * Gets the value of the label property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getLabel() {\n        return this.label;\n    }\n\n    /**\n     * Sets the value of the label property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setLabel(String value) {\n        this.label = value;\n    }\n\n    /**\n     * Gets the value of the value property.\n     *\n     * @return\n     *         possible object is\n     *         {@link String }\n     *\n     */\n    @Override\n    public String getValue() {\n        return this.value;\n    }\n\n    /**\n     * Sets the value of the value property.\n     *\n     * @param value\n     *            allowed object is\n     *            {@link String }\n     *\n     */\n    public void setValue(String value) {\n        this.value = value;\n    }\n\n    /**\n     * Gets a map that contains attributes that aren't bound to any typed property on this class.\n     *\n     * <p>\n     * the map is keyed by the name of the attribute and\n     * the value is the string value of the attribute.\n     *\n     * the map returned by this method is live, and you can add new attribute\n     * by updating the map directly. Because of this design, there's no setter.\n     *\n     *\n     * @return\n     *         always non-null\n     */\n    public Map<QName, String> getOtherAttributes() {\n        return this.otherAttributes;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tscalar.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n\n/**\n * <p>\n * Java class for Tscalar.\n *\n * <p>\n * The following schema fragment specifies the expected content contained within this class.\n * <p>\n *\n * <pre>\n * &lt;simpleType name=\"Tscalar\">\n *   &lt;restriction base=\"{http://www.w3.org/2001/XMLSchema}string\">\n *     &lt;enumeration value=\"String\"/>\n *     &lt;enumeration value=\"Long\"/>\n *     &lt;enumeration value=\"Double\"/>\n *     &lt;enumeration value=\"Float\"/>\n *     &lt;enumeration value=\"Integer\"/>\n *     &lt;enumeration value=\"Byte\"/>\n *     &lt;enumeration value=\"Char\"/>\n *     &lt;enumeration value=\"Boolean\"/>\n *     &lt;enumeration value=\"Short\"/>\n *     &lt;enumeration value=\"Password\"/>\n *   &lt;/restriction>\n * &lt;/simpleType>\n * </pre>\n *\n */\npublic enum Tscalar {\n    STRING(\"String\"),\n    LONG(\"Long\"),\n    DOUBLE(\"Double\"),\n    FLOAT(\"Float\"),\n    INTEGER(\"Integer\"),\n    BYTE(\"Byte\"),\n    CHAR(\"Char\"),\n    BOOLEAN(\"Boolean\"),\n    SHORT(\"Short\"),\n    PASSWORD(\"Password\");\n\n    private final String value;\n\n    Tscalar(String v) {\n        this.value = v;\n    }\n\n    public String value() {\n        return this.value;\n    }\n\n    public static Tscalar fromValue(String v) {\n        for (Tscalar c : Tscalar.values()) {\n            if (c.value.equals(v)) {\n                return c;\n            }\n        }\n        throw new IllegalArgumentException(v);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation,\n// vhudson-jaxb-ri-2.2-147\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.11.25 at 06:05:15 PM CET\n//\n\npackage org.eclipse.kura.core.configuration.metatype;\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n//\n// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in\n// JDK 6\n// See <a href=\"http://java.sun.com/xml/jaxb\">http://java.sun.com/xml/jaxb</a>\n// Any modifications to this file will be lost upon recompilation of the source schema.\n// Generated on: 2012.10.26 at 02:11:54 PM CEST\n//\n\npackage org.eclipse.kura.core.configuration;\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/upgrade/ConfigurationUpgrade.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration.upgrade;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.component.ComponentConstants;\n\npublic class ConfigurationUpgrade {\n\n    private static final String KURA_CLOUD_SERVICE_FACTORY_PID = \"kura.cloud.service.factory.pid\";\n    private static final String FACTORY_PID = \"org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory\";\n\n    private static final String CLOUD_SERVICE_FACTORY_PID = \"org.eclipse.kura.cloud.CloudService\";\n    private static final String DATA_SERVICE_FACTORY_PID = \"org.eclipse.kura.data.DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    private static final String CLOUD_SERVICE_PID = \"org.eclipse.kura.cloud.CloudService\";\n    private static final String DATA_SERVICE_PID = \"org.eclipse.kura.data.DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    private static final String DATA_SERVICE_REFERENCE_NAME = \"DataService\";\n    private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = \"DataTransportService\";\n    private static final String REFERENCE_TARGET_VALUE_FORMAT = \"(\" + ConfigurationService.KURA_SERVICE_PID + \"=%s)\";\n\n    public static void upgrade(final ComponentConfiguration config, final BundleContext bundleContext) {\n\n        if (config == null) {\n            return;\n        }\n\n        String pid = config.getPid();\n        final Map<String, Object> props = config.getConfigurationProperties();\n\n        if (props == null) {\n            return;\n        }\n\n        final Object factoryPid = props.get(ConfigurationAdmin.SERVICE_FACTORYPID);\n\n        if (CLOUD_SERVICE_PID.equals(pid)) {\n            props.put(ConfigurationAdmin.SERVICE_FACTORYPID, CLOUD_SERVICE_FACTORY_PID);\n            String name = DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n            props.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, DATA_SERVICE_PID));\n            props.put(KURA_CLOUD_SERVICE_FACTORY_PID, FACTORY_PID);\n        } else if (DATA_SERVICE_PID.equals(pid)) {\n            props.put(ConfigurationAdmin.SERVICE_FACTORYPID, DATA_SERVICE_FACTORY_PID);\n            String name = DATA_TRANSPORT_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX;\n            props.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, DATA_TRANSPORT_SERVICE_PID));\n            props.put(KURA_CLOUD_SERVICE_FACTORY_PID, FACTORY_PID);\n        } else if (DATA_TRANSPORT_SERVICE_PID.equals(pid)) {\n            props.put(ConfigurationAdmin.SERVICE_FACTORYPID, DATA_TRANSPORT_SERVICE_FACTORY_PID);\n            props.put(KURA_CLOUD_SERVICE_FACTORY_PID, FACTORY_PID);\n        } else if (WireAssetConfigurationUpgrade.WIRE_ASSET_FACTORY_PID.equals(factoryPid)) {\n            WireAssetConfigurationUpgrade.upgrade(props);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/upgrade/WireAssetConfigurationUpgrade.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.core.configuration.upgrade;\n\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\npublic final class WireAssetConfigurationUpgrade {\n\n    static final String WIRE_ASSET_FACTORY_PID = \"org.eclipse.kura.wire.WireAsset\";\n\n    private static final String CHANNEL_PROPERTY_SEPARATOR = \"#\";\n    private static final String CHANNEL_NAME_PROPERTY_SUFFIX = CHANNEL_PROPERTY_SEPARATOR + \"+name\";\n    private static final String EMIT_ALL_CHANNELS_PROP_NAME = \"emit.all.channels\";\n\n    private WireAssetConfigurationUpgrade() {\n    }\n\n    static void upgrade(final Map<String, Object> properties) {\n        if (properties.containsKey(EMIT_ALL_CHANNELS_PROP_NAME)) {\n            return;\n        }\n\n        properties.put(EMIT_ALL_CHANNELS_PROP_NAME, false);\n        final Set<String> channelNames = getChannelNames(properties);\n\n        for (final String channelName : channelNames) {\n            properties.put(channelName + CHANNEL_NAME_PROPERTY_SUFFIX, channelName);\n        }\n    }\n\n    static Set<String> getChannelNames(final Map<String, Object> properties) {\n\n        final Set<String> channelNames = new HashSet<>();\n\n        for (final Entry<String, Object> e : properties.entrySet()) {\n            final String key = e.getKey();\n            final int index = key.indexOf(CHANNEL_PROPERTY_SEPARATOR);\n            if (index == -1) {\n                continue;\n            }\n            final String channelName = key.substring(0, index);\n            channelNames.add(channelName);\n        }\n\n        return channelNames;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/util/CollectionsUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration.util;\n\nimport java.util.Dictionary;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Hashtable;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.configuration.metatype.Scalar;\n\npublic class CollectionsUtil {\n\n    public static Map<String, Object> dictionaryToMap(Dictionary<String, Object> dictionary, OCD ocd) {\n        if (dictionary == null) {\n            return null;\n        }\n\n        Map<String, AD> ads = new HashMap<>();\n        if (ocd != null) {\n            for (AD ad : ocd.getAD()) {\n                ads.put(ad.getId(), ad);\n            }\n        }\n        Map<String, Object> map = new HashMap<>();\n        Enumeration<String> keys = dictionary.keys();\n        while (keys.hasMoreElements()) {\n\n            String key = keys.nextElement();\n            Object value = dictionary.get(key);\n            AD ad = ads.get(key);\n            if (ad != null && ad.getType() != null && Scalar.PASSWORD.equals(ad.getType())) {\n                if (value instanceof char[]) {\n                    map.put(key, new Password((char[]) value));\n                } else if (value instanceof String[]) {\n                    map.put(key, convertStringsToPasswords((String[]) value));\n                } else {\n                    map.put(key, new Password(value.toString()));\n                }\n            } else {\n                map.put(key, value);\n            }\n        }\n        return map;\n    }\n\n    private static Password[] convertStringsToPasswords(String[] value) {\n        Password[] result = new Password[value.length];\n\n        for (int i = 0; i < value.length; i++) {\n            result[i] = new Password(value[i]);\n        }\n        return result;\n    }\n\n    public static Dictionary<String, Object> mapToDictionary(Map<String, Object> map) {\n        if (map == null) {\n            return null;\n        }\n\n        Dictionary<String, Object> dictionary = new Hashtable<>();\n        Iterator<String> keys = map.keySet().iterator();\n        while (keys.hasNext()) {\n            String key = keys.next();\n            Object value = map.get(key);\n            if (value != null) {\n                // TODO: this should be removed in next version. Password values\n                // should be kept as they are and not mapped to String objects. This\n                // was originally done due to Password class not in APIs, but this is\n                // not the condition anymore. This change would cause third party code\n                // to receive Password objects instead of strings. At the other side,\n                // managing everything with Password objects would make everything\n                // more logic and consistent.\n                if (value instanceof Password) {\n                    dictionary.put(key, value.toString());\n                } else if (value instanceof Password[]) {\n                    Password[] passwordArray = (Password[]) value;\n                    String[] passwords = new String[passwordArray.length];\n                    for (int i = 0; i < passwordArray.length; i++) {\n                        passwords[i] = passwordArray[i].toString();\n                    }\n                    dictionary.put(key, passwords);\n                } else {\n                    dictionary.put(key, value);\n                }\n            }\n        }\n        return dictionary;\n    }\n\n    public static boolean equals(final Dictionary<String, Object> first, final Dictionary<String, Object> second) {\n        if (first == null || second == null) {\n            return first == second;\n        }\n\n        if (first.size() != second.size()) {\n            return false;\n        }\n\n        final Enumeration<String> keys = first.keys();\n\n        while (keys.hasMoreElements()) {\n            final String key = keys.nextElement();\n\n            if (!Objects.deepEquals(first.get(key), second.get(key))) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/util/ComponentUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc \n *******************************************************************************/\npackage org.eclipse.kura.core.configuration.util;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport javax.xml.stream.FactoryConfigurationError;\nimport javax.xml.stream.XMLStreamException;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.Designate;\nimport org.eclipse.kura.configuration.metatype.MetaData;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.configuration.metatype.Scalar;\nimport org.eclipse.kura.core.configuration.metatype.Tmetadata;\nimport org.eclipse.kura.core.configuration.metatype.Tocd;\nimport org.eclipse.kura.core.util.IOUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.metatype.MetaTypeInformation;\nimport org.osgi.service.metatype.MetaTypeService;\nimport org.osgi.service.metatype.ObjectClassDefinition;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Utility class to handle the loading of the meta-information\n * of a bundle or one of its Services/Components.\n */\npublic class ComponentUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(ComponentUtil.class);\n    private static final String OSGI_INF_METATYPE = \"OSGI-INF/metatype/\";\n\n    private ComponentUtil() {\n        // Do nothing...\n    }\n\n    /**\n     * Returns a Map with all the MetaType Object Class Definitions contained in the bundle.\n     *\n     * @param ctx\n     * @param bnd\n     * @return\n     */\n    public static Map<String, Tmetadata> getMetadata(BundleContext ctx, Bundle bnd) {\n        final Map<String, Tmetadata> bundleMetadata = new HashMap<>();\n\n        final ServiceReference<MetaTypeService> ref = ctx.getServiceReference(MetaTypeService.class);\n        final MetaTypeService metaTypeService = ctx.getService(ref);\n\n        try {\n            final MetaTypeInformation mti = metaTypeService.getMetaTypeInformation(bnd);\n            if (mti != null) {\n\n                final List<String> pids = new ArrayList<>();\n                pids.addAll(Arrays.asList(mti.getPids()));\n                pids.addAll(Arrays.asList(mti.getFactoryPids()));\n                for (String pid : pids) {\n\n                    final Tmetadata metadata;\n                    try {\n                        metadata = readMetadata(bnd, pid);\n                        if (metadata != null) {\n                            bundleMetadata.put(pid, metadata);\n                        }\n                    } catch (Exception e) {\n                        // ignore: Metadata for the specified pid is not found\n                        logger.warn(\"Error loading Metadata for pid \" + pid, e);\n                    }\n                }\n            }\n        } finally {\n            ctx.ungetService(ref);\n        }\n\n        return bundleMetadata;\n    }\n\n    /**\n     * Returns the Designate for the given pid\n     */\n    public static Designate getDesignate(final Tmetadata metadata, final String pid) {\n\n        if (metadata == null || pid == null) {\n            return null;\n        }\n\n        final List<Designate> designates = metadata.getDesignate();\n        if (designates == null) {\n            return null;\n        }\n\n        for (final Designate designate : designates) {\n            if (pid.equals(designate.getPid())) {\n                return designate;\n            }\n            if (pid.equals(designate.getFactoryPid())) {\n                return designate;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Returns the Designate for the given pid\n     */\n    public static OCD getOCD(Tmetadata metadata, String pid) {\n        if (metadata.getOCD() != null && !metadata.getOCD().isEmpty()) {\n            for (OCD ocd : metadata.getOCD()) {\n                if (ocd.getId() != null && ocd.getId().equals(pid)) {\n                    return ocd;\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Returns a Map with all the MetaType Object Class Definitions contained in the bundle.\n     *\n     * @param ctx\n     * @param bnd\n     * @return\n     */\n    public static Map<String, OCD> getObjectClassDefinition(BundleContext ctx, Bundle bnd) {\n        Map<String, OCD> bundleDefaults = new HashMap<>();\n\n        ServiceReference<MetaTypeService> ref = ctx.getServiceReference(MetaTypeService.class);\n        MetaTypeService metaTypeService = ctx.getService(ref);\n        MetaTypeInformation mti = metaTypeService.getMetaTypeInformation(bnd);\n        if (mti != null) {\n\n            String[] pids = mti.getPids();\n            if (pids != null) {\n                for (String pid : pids) {\n                    OCD ocd = null;\n                    try {\n                        ocd = readObjectClassDefinition(bnd, pid);\n                        if (ocd != null) {\n                            bundleDefaults.put(pid, ocd);\n                        }\n                    } catch (Exception e) {\n                        // ignore: OCD for the specified pid is not found\n                        logger.warn(\"Error loading OCD for pid \" + pid, e);\n                    }\n                }\n            }\n        }\n        return bundleDefaults;\n    }\n\n    /**\n     * Returns the ObjectClassDefinition for the provided Service pid\n     * as returned by the native OSGi MetaTypeService.\n     * The returned ObjectClassDefinition is a thick object tied to\n     * OSGi framework which masks certain attributes of the OCD XML\n     * file - like required and min/max values - but which exposes\n     * business logic like the validate method for each attribute.\n     *\n     * @param ctx\n     * @param pid\n     * @return\n     */\n    public static ObjectClassDefinition getObjectClassDefinition(BundleContext ctx, String pid) {\n        //\n        ServiceReference<MetaTypeService> ref = ctx.getServiceReference(MetaTypeService.class);\n        MetaTypeService metaTypeService = ctx.getService(ref);\n        MetaTypeInformation mti = metaTypeService.getMetaTypeInformation(ctx.getBundle());\n\n        ObjectClassDefinition ocd = null;\n        try {\n            if (mti != null) {\n                ocd = mti.getObjectClassDefinition(pid, null); // default locale\n            }\n        } catch (IllegalArgumentException iae) {\n            // ignore: OCD for the specified pid is not found\n        }\n        return ocd;\n    }\n\n    /**\n     * Returned the Tmetadata as parsed from the XML file.\n     * The returned Tmetadata is just an object representation of the Metadata\n     * element contained in the XML MetaData file and it does not\n     * contain any extra post-processing of the loaded information.\n     *\n     * @param ctx\n     * @param pid\n     *            ID of the service whose OCD should be loaded\n     * @return\n     * @throws IOException\n     * @throws XMLStreamException\n     * @throws FactoryConfigurationError\n     */\n    public static Tmetadata readMetadata(Bundle bundle, String pid)\n            throws IOException, KuraException, FactoryConfigurationError {\n        Tmetadata metaData = null;\n        StringBuilder sbMetatypeXmlName = new StringBuilder();\n        sbMetatypeXmlName.append(OSGI_INF_METATYPE).append(pid).append(\".xml\");\n\n        String metatypeXmlName = sbMetatypeXmlName.toString();\n        String metatypeXml = IOUtil.readResource(bundle, metatypeXmlName);\n        if (metatypeXml != null) {\n            metaData = unmarshal(metatypeXml, Tmetadata.class);\n        }\n        return metaData;\n    }\n\n    /**\n     * Returned the ObjectClassDefinition as parsed from the XML file.\n     * The returned OCD is just an object representation of the OCD\n     * element contained in the XML MetaData file and it does not\n     * contain any extra post-processing of the loaded information.\n     *\n     * @param resourceUrl\n     *            Url of the MetaData XML file which needs to be loaded\n     * @return\n     * @throws IOException\n     * @throws XMLStreamException\n     * @throws FactoryConfigurationError\n     */\n    public static OCD readObjectClassDefinition(URL resourceUrl)\n            throws IOException, FactoryConfigurationError, KuraException {\n        OCD ocd = null;\n        String metatypeXml = IOUtil.readResource(resourceUrl);\n        if (metatypeXml != null) {\n            MetaData metaData = unmarshal(metatypeXml, MetaData.class);\n            if (metaData.getOCD() != null && !metaData.getOCD().isEmpty()) {\n                ocd = metaData.getOCD().get(0);\n            } else {\n                logger.warn(\"Cannot find OCD for component with url: {}\", resourceUrl);\n            }\n        }\n        return ocd;\n    }\n\n    /**\n     * Returned the ObjectClassDefinition as parsed from the XML file.\n     * The returned OCD is just an object representation of the OCD\n     * element contained in the XML MetaData file and it does not\n     * contain any extra post-processing of the loaded information.\n     *\n     * @param pid\n     *            ID of the service whose OCD should be loaded\n     * @return\n     * @throws IOException\n     * @throws XMLStreamException\n     * @throws FactoryConfigurationError\n     */\n    public static Tocd readObjectClassDefinition(String pid)\n            throws IOException, KuraException, FactoryConfigurationError {\n        Tocd ocd = null;\n        StringBuilder sbMetatypeXmlName = new StringBuilder();\n        sbMetatypeXmlName.append(OSGI_INF_METATYPE).append(pid).append(\".xml\");\n\n        String metatypeXmlName = sbMetatypeXmlName.toString();\n        String metatypeXml = IOUtil.readResource(metatypeXmlName);\n        if (metatypeXml != null) {\n            Tmetadata metaData = unmarshal(metatypeXml, Tmetadata.class);\n            if (metaData.getOCD() != null && !metaData.getOCD().isEmpty()) {\n                ocd = (Tocd) metaData.getOCD().get(0);\n            } else {\n                logger.warn(\"Cannot find OCD for component with pid: {}\", pid);\n            }\n        }\n        return ocd;\n    }\n\n    /**\n     * Returned the ObjectClassDefinition as parsed from the XML file.\n     * The returned OCD is just an object representation of the OCD\n     * element contained in the XML MetaData file and it does not\n     * contain any extra post-processing of the loaded information.\n     *\n     * @param ctx\n     * @param pid\n     *            ID of the service whose OCD should be loaded\n     * @return\n     * @throws IOException\n     * @throws XMLStreamException\n     * @throws FactoryConfigurationError\n     */\n    public static Tocd readObjectClassDefinition(Bundle bundle, String pid)\n            throws IOException, KuraException, FactoryConfigurationError {\n        Tocd ocd = null;\n        StringBuilder sbMetatypeXmlName = new StringBuilder();\n        sbMetatypeXmlName.append(OSGI_INF_METATYPE).append(pid).append(\".xml\");\n\n        String metatypeXmlName = sbMetatypeXmlName.toString();\n        String metatypeXml = IOUtil.readResource(bundle, metatypeXmlName);\n        if (metatypeXml != null) {\n            Tmetadata metaData = unmarshal(metatypeXml, Tmetadata.class);\n            if (metaData.getOCD() != null && !metaData.getOCD().isEmpty()) {\n                ocd = (Tocd) metaData.getOCD().get(0);\n            }\n        }\n        return ocd;\n    }\n\n    public static Map<String, Object> getDefaultProperties(OCD ocd, ComponentContext ctx) {\n        //\n        // reconcile by looping through the ocd properties\n        Map<String, Object> defaults = null;\n        defaults = new HashMap<>();\n        if (ocd != null) {\n\n            List<AD> attrDefs = ocd.getAD();\n            if (attrDefs != null) {\n\n                for (AD attrDef : attrDefs) {\n\n                    String id = attrDef.getId();\n                    Object defaultValue = getDefaultValue(attrDef, ctx);\n                    if (defaults.get(id) == null && defaultValue != null) {\n                        defaults.put(id, defaultValue);\n                    }\n                }\n            }\n        }\n        return defaults;\n    }\n\n    private static Object getDefaultValue(AD attrDef, ComponentContext ctx) {\n        // get the default value string from the AD\n        // then split it by comma-separate list\n        // keeping in mind the possible escape sequence \"\\,\"\n        String defaultValue = attrDef.getDefault();\n        if (defaultValue == null || defaultValue.isEmpty()) {\n            return null;\n        }\n\n        Object[] objectValues = null;\n        Scalar type = attrDef.getType();\n        if (type != null) {\n            String[] defaultValues = StringUtil.splitValues(defaultValue);\n\n            // convert string values into object values\n            int cardinality = attrDef.getCardinality();\n            objectValues = getObjectValue(type, defaultValues, ctx);\n            if (objectValues != null && (cardinality == 0 || cardinality == 1 || cardinality == -1)) {\n\n                // return one single object\n                // if cardinality is 0 or abs(1)\n                return objectValues[0];\n            }\n        } else {\n            logger.warn(\"Unknown type for attribute {}\", attrDef.getId());\n        }\n        return objectValues;\n    }\n\n    private static Object[] getObjectValue(Scalar type, String[] defaultValues, ComponentContext ctx) {\n        List<Object> values = new ArrayList<>();\n        switch (type) {\n        case BOOLEAN:\n            for (String value : defaultValues) {\n                values.add(Boolean.valueOf(value));\n            }\n            return values.toArray(new Boolean[] {});\n\n        case BYTE:\n            for (String value : defaultValues) {\n                values.add(Byte.valueOf(value));\n            }\n            return values.toArray(new Byte[] {});\n\n        case CHAR:\n            for (String value : defaultValues) {\n                values.add(Character.valueOf(value.charAt(0)));\n            }\n            return values.toArray(new Character[] {});\n\n        case DOUBLE:\n            for (String value : defaultValues) {\n                values.add(Double.valueOf(value));\n            }\n            return values.toArray(new Double[] {});\n\n        case FLOAT:\n            for (String value : defaultValues) {\n                values.add(Float.valueOf(value));\n            }\n            return values.toArray(new Float[] {});\n\n        case INTEGER:\n            for (String value : defaultValues) {\n                values.add(Integer.valueOf(value));\n            }\n            return values.toArray(new Integer[] {});\n\n        case LONG:\n            for (String value : defaultValues) {\n                values.add(Long.valueOf(value));\n            }\n            return values.toArray(new Long[] {});\n\n        case SHORT:\n            for (String value : defaultValues) {\n                values.add(Short.valueOf(value));\n            }\n            return values.toArray(new Short[] {});\n\n        case PASSWORD:\n            ServiceReference<CryptoService> sr = ctx.getBundleContext().getServiceReference(CryptoService.class);\n            CryptoService cryptoService = ctx.getBundleContext().getService(sr);\n            for (String value : defaultValues) {\n                try {\n                    values.add(new Password(cryptoService.encryptAes(value.toCharArray())));\n                } catch (Exception e) {\n                    values.add(new Password(value));\n                }\n            }\n            return values.toArray(new Password[] {});\n\n        case STRING:\n            return defaultValues;\n        }\n\n        return null;\n    }\n\n    private static ServiceReference<Unmarshaller>[] getXmlUnmarshallers() {\n        String filterString = String.format(\"(&(kura.service.pid=%s))\",\n                \"org.eclipse.kura.xml.marshaller.unmarshaller.provider\");\n        return ServiceUtil.getServiceReferences(FrameworkUtil.getBundle(ComponentUtil.class).getBundleContext(),\n                Unmarshaller.class, filterString);\n    }\n\n    private static void ungetServiceReferences(final ServiceReference<?>[] refs) {\n        ServiceUtil.ungetServiceReferences(FrameworkUtil.getBundle(ComponentUtil.class).getBundleContext(), refs);\n    }\n\n    protected static <T> T unmarshal(String string, Class<T> clazz) throws KuraException {\n        T result = null;\n        ServiceReference<Unmarshaller>[] unmarshallerSRs = getXmlUnmarshallers();\n        try {\n            for (final ServiceReference<Unmarshaller> unmarshallerSR : unmarshallerSRs) {\n                Unmarshaller unmarshaller = FrameworkUtil.getBundle(ComponentUtil.class).getBundleContext()\n                        .getService(unmarshallerSR);\n                result = unmarshaller.unmarshal(string, clazz);\n            }\n        } catch (Exception e) {\n            logger.warn(\"Failed to extract persisted configuration.\");\n        } finally {\n            ungetServiceReferences(unmarshallerSRs);\n        }\n        if (result == null) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, \"value\");\n        }\n        return result;\n    }\n\n    /*\n     * Encrypt a list of {@link org.eclipse.kura.ComponentConfiguration}s using the given CryptoService\n     */\n    public static void encryptConfigs(List<ComponentConfiguration> configs, final CryptoService cryptoService) {\n        if (configs != null) {\n            for (ComponentConfiguration config : configs) {\n                encryptConfigurationProperties(config.getConfigurationProperties(), cryptoService);\n            }\n        }\n    }\n\n    /*\n     * Encrypt a map of properties using the given CryptoService\n     */\n    public static void encryptConfigurationProperties(Map<String, Object> propertiesToUpdate,\n            final CryptoService cryptoService) {\n        encryptConfigurationProperties(propertiesToUpdate, cryptoService, false);\n    }\n\n    public static Map<String, Object> encryptConfigurationProperties(final Map<String, Object> original,\n            final CryptoService cryptoService, final boolean clone) {\n        if (original == null) {\n            return null;\n        }\n\n        Optional<Map<String, Object>> result = Optional.empty();\n\n        if (!clone) {\n            result = Optional.of(original);\n        }\n\n        for (Entry<String, Object> property : original.entrySet()) {\n            Object configValue = property.getValue();\n            if (configValue instanceof Password || configValue instanceof Password[]) {\n\n                final Map<String, Object> resultProperties;\n\n                if (result.isPresent()) {\n                    resultProperties = result.get();\n                } else {\n                    resultProperties = new HashMap<>(original);\n                    result = Optional.of(resultProperties);\n                }\n\n                try {\n                    Object encryptedValue = encryptPasswordProperties(configValue, cryptoService);\n                    resultProperties.put(property.getKey(), encryptedValue);\n                } catch (KuraException e) {\n                    logger.warn(\"Failed to encrypt Password property: {}\", property.getKey());\n                    resultProperties.remove(property.getKey());\n                }\n            }\n        }\n\n        return result.orElse(original);\n    }\n\n    private static Object encryptPasswordProperties(Object configValue, final CryptoService cryptoService)\n            throws KuraException {\n        Object encryptedValue = null;\n        if (configValue instanceof Password) {\n            encryptedValue = encryptPassword((Password) configValue, cryptoService);\n\n        } else if (configValue instanceof Password[]) {\n            Password[] passwordArray = (Password[]) configValue;\n            Password[] encryptedPasswords = new Password[passwordArray.length];\n\n            for (int i = 0; i < passwordArray.length; i++) {\n                encryptedPasswords[i] = encryptPassword(passwordArray[i], cryptoService);\n            }\n            encryptedValue = encryptedPasswords;\n        }\n        return encryptedValue;\n    }\n\n    private static boolean isEncrypted(Password configPassword, final CryptoService cryptoService) {\n        boolean result = false;\n        try {\n            cryptoService.decryptAes(configPassword.getPassword());\n            result = true;\n        } catch (Exception e) {\n            // Do nothing...\n        }\n        return result;\n    }\n\n    private static Password encryptPassword(Password password, final CryptoService cryptoService) throws KuraException {\n        if (!isEncrypted(password, cryptoService)) {\n            return new Password(cryptoService.encryptAes(password.getPassword()));\n        }\n        return password;\n    }\n\n    /*\n     * Converts a list of {@link org.eclipse.kura.core.configuration.ComponentConfiguration}s to a map whose keys are\n     * the component pids.\n     */\n    public static Map<String, ComponentConfiguration> toMap(final List<ComponentConfiguration> configs) {\n        return configs.stream().collect(Collectors.toMap(ComponentConfiguration::getPid, Function.identity()));\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/util/StringUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.configuration.util;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.eclipse.kura.configuration.Password;\n\npublic class StringUtil {\n\n    private static final char DELIMITER = ',';\n    private static final char ESCAPE = '\\\\';\n\n    private StringUtil() {\n        // Do nothing...\n    }\n\n    public static String[] splitValues(String strValues) {\n        if (strValues == null) {\n            return null;\n        }\n\n        // The trick is to strip out unescaped whitespace characters before and\n        // after the input string as well as before and after each\n        // individual token within the input string without losing any escaped\n        // whitespace characters. Whitespace between two non-whitespace\n        // characters may or may not be escaped. Also, any character may be\n        // escaped. The escape character is '\\'. The delimiter is ','.\n        List<String> values = new ArrayList<>();\n        StringBuilder buffer = new StringBuilder();\n        // Loop over the characters within the input string and extract each\n        // value token.\n        for (int i = 0; i < strValues.length(); i++) {\n            char c1 = strValues.charAt(i);\n            switch (c1) {\n            case DELIMITER:\n                // When the delimiter is encountered, add the extracted\n                // token to the result and prepare the buffer to receive the\n                // next token.\n                values.add(buffer.toString());\n                buffer.delete(0, buffer.length());\n                break;\n            case ESCAPE:\n                // When the escape is encountered, add the immediately\n                // following character to the token, unless the end of the\n                // input has been reached. Note this will result in loop\n                // counter 'i' being incremented twice, once here and once\n                // at the end of the loop.\n                if (i + 1 < strValues.length()) {\n                    buffer.append(strValues.charAt(++i));\n                }\n                // If the ESCAPE character occurs as the last character\n                // of the string, ignore it.\n                break;\n            default:\n                // For all other characters, add them to the current token\n                // unless dealing with unescaped whitespace at the beginning\n                // or end. We know the whitespace is unescaped because it\n                // would have been handled in the ESCAPE case otherwise.\n                if (Character.isWhitespace(c1)) {\n                    // Ignore unescaped whitespace at the beginning of the\n                    // token.\n                    if (buffer.length() == 0) {\n                        continue;\n                    }\n                    // If the whitespace is not at the beginning, look\n                    // forward, starting with the next character, to see if\n                    // it's in the middle or at the end. Unescaped\n                    // whitespace in the middle is okay.\n                    for (int j = i + 1; j < strValues.length(); j++) {\n                        // Keep looping until the end of the string is\n                        // reached or a non-whitespace character other than\n                        // the escape is seen.\n                        char c2 = strValues.charAt(j);\n                        if (!Character.isWhitespace(c2)) {\n                            // If the current character is not the DELIMITER, all whitespace\n                            // characters are significant and should be added to the token.\n                            // Otherwise, they're at the end and should be ignored. But watch\n                            // out for an escape character at the end of the input. Ignore it\n                            // and any previous insignificant whitespace if it exists.\n                            if (c2 == ESCAPE && j + 1 >= strValues.length()) {\n                                continue;\n                            }\n                            if (c2 != DELIMITER) {\n                                buffer.append(strValues.substring(i, j));\n                            }\n                            // Let loop counter i catch up with the inner loop but keep in\n                            // mind it will still be incremented at the end of the outer loop.\n                            i = j - 1;\n                            break;\n                        }\n                    }\n                } else {\n                    // For non-whitespace characters.\n                    buffer.append(c1);\n                }\n            }\n        }\n        // Don't forget to add the last token.\n        values.add(buffer.toString());\n        return values.toArray(new String[] {});\n    }\n\n    public static String valueToString(Object value) {\n        String result = null;\n        if (value == null) {\n            result = null;\n        } else if (value instanceof String) {\n            result = value.toString();\n        } else if (value instanceof Long) {\n            result = value.toString();\n        } else if (value instanceof Double) {\n            result = value.toString();\n        } else if (value instanceof Float) {\n            result = value.toString();\n        } else if (value instanceof Integer) {\n            result = value.toString();\n        } else if (value instanceof Byte) {\n            result = value.toString();\n        } else if (value instanceof Character) {\n            result = value.toString();\n        } else if (value instanceof Boolean) {\n            result = value.toString();\n        } else if (value instanceof Short) {\n            result = value.toString();\n        } else if (value instanceof Password) {\n            result = value.toString();\n        } else if (value instanceof String[]) {\n            StringBuilder sb = new StringBuilder();\n            String[] ss = (String[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        } else if (value instanceof Long[]) {\n            StringBuilder sb = new StringBuilder();\n            Long[] ss = (Long[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        } else if (value instanceof Double[]) {\n            StringBuilder sb = new StringBuilder();\n            Double[] ss = (Double[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        } else if (value instanceof Float[]) {\n            StringBuilder sb = new StringBuilder();\n            Float[] ss = (Float[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        } else if (value instanceof Integer[]) {\n            StringBuilder sb = new StringBuilder();\n            Integer[] ss = (Integer[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        } else if (value instanceof Byte[]) {\n            StringBuilder sb = new StringBuilder();\n            Byte[] ss = (Byte[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        } else if (value instanceof Character[]) {\n            StringBuilder sb = new StringBuilder();\n            Character[] ss = (Character[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        } else if (value instanceof Boolean[]) {\n            StringBuilder sb = new StringBuilder();\n            Boolean[] ss = (Boolean[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        } else if (value instanceof Short[]) {\n            StringBuilder sb = new StringBuilder();\n            Short[] ss = (Short[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        } else if (value instanceof Password[]) {\n            StringBuilder sb = new StringBuilder();\n            String[] ss = (String[]) value;\n            for (int i = 0; i < ss.length; i++) {\n                if (ss[i] != null) {\n                    sb.append(escapeString(ss[i].toString()));\n                    if (i != ss.length - 1) {\n                        sb.append(\",\");\n                    }\n                }\n            }\n            result = sb.toString();\n        }\n        return result;\n    }\n\n    public static String escapeString(String s) {\n        String escaped = s;\n        escaped = escaped.replace(\"\\\\\", \"\\\\\\\\\");\n        escaped = escaped.replace(\",\", \"\\\\,\");\n        escaped = escaped.replace(\" \", \"\\\\ \");\n        return escaped;\n    }\n\n    public static String unescapeString(String s) {\n        String value = s;\n\n        // remove all space at the beginning of the string which are not escaped\n        value = value.replaceAll(\"^((?<!\\\\\\\\) )*\", \"\");\n\n        // remove all space at the end of the string which are not escaped\n        value = value.replaceAll(\"((?<!\\\\\\\\) )*$\", \"\");\n\n        // replace all escaped spaces with just space\n        // The pattern covers for any even number of backslashes before the space char\n        value = value.replaceAll(\"\\\\\\\\(\\\\\\\\\\\\\\\\)* \", \" \");\n\n        // replace all escaped comma with just comma\n        // The pattern covers for any even number of backslashes before the comma char\n        value = value.replaceAll(\"\\\\\\\\(\\\\\\\\\\\\\\\\)*,\", \",\");\n\n        return value;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.crypto/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.crypto\nBundle-SymbolicName: org.eclipse.kura.core.crypto;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: javax.crypto,\n javax.crypto.spec,\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.4,1.5)\",\n org.eclipse.kura.security.keystore;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.1,2.0)\",\n org.slf4j;version=\"1.6.0\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nExport-Package: org.eclipse.kura.core.crypto\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.crypto/OSGI-INF/crypto.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n    Red Hat Inc\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"optional\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.crypto.CryptoService\">\n   <implementation class=\"org.eclipse.kura.core.crypto.CryptoServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.crypto.CryptoService\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.crypto.CryptoService\"/>\n   <reference bind=\"setSystemService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.system.SystemService\" name=\"SystemService\" policy=\"static\" unbind=\"unsetSystemService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.crypto/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.crypto/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.crypto/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about_files/,\\\n               about.html\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.crypto/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.crypto</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.core.crypto.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.crypto/src/main/java/org/eclipse/kura/core/crypto/CryptoServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.crypto;\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.CharacterCodingException;\nimport java.nio.charset.CharsetDecoder;\nimport java.nio.charset.CharsetEncoder;\nimport java.nio.charset.CodingErrorAction;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.InvalidKeyException;\nimport java.security.Key;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.util.Arrays;\nimport java.util.Base64;\nimport java.util.Optional;\nimport java.util.Properties;\n\nimport javax.crypto.BadPaddingException;\nimport javax.crypto.Cipher;\nimport javax.crypto.CipherInputStream;\nimport javax.crypto.CipherOutputStream;\nimport javax.crypto.IllegalBlockSizeException;\nimport javax.crypto.NoSuchPaddingException;\nimport javax.crypto.spec.GCMParameterSpec;\nimport javax.crypto.spec.SecretKeySpec;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.system.SystemService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CryptoServiceImpl implements CryptoService {\n\n    private static final Logger logger = LoggerFactory.getLogger(CryptoServiceImpl.class);\n\n    private static final String PARAMETER_EXCEPTION_CAUSE = \"parameter\";\n    private static final String DECRYPT_EXCEPTION_CAUSE = \"decrypt\";\n    private static final String VALUE_EXCEPTION_CAUSE = \"value\";\n\n    private static final String ALGORITHM = \"AES\";\n    private static final String CIPHER = \"AES/GCM/NoPadding\";\n    private static final int AUTH_TAG_LENGTH_BIT = 128;\n    private static final int IV_SIZE = 12;\n    private static final String ENCRYPTED_STRING_SEPARATOR = \"-\";\n    private static final byte[] DEFAULT_SECRET_KEY = \"rv;ipse329183!@#\".getBytes(StandardCharsets.UTF_8);\n    private static final String SECRET_KEY_CREDENTIAL_ID = \"kura_encryption_key\";\n    private static final String SECRET_KEY_SYSTEM_PROPERTY_NAME = \"org.eclipse.kura.core.crypto.secretKey\";\n\n    private String keystorePasswordPath;\n\n    private final SecureRandom random = new SecureRandom();\n    private SystemService systemService;\n    private Optional<byte[]> secretKey;\n\n    public void setSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    public void unsetSystemService(SystemService systemService) {\n        this.systemService = null;\n    }\n\n    protected void activate() {\n\n        this.secretKey = loadCustomEncryptionKey().filter(CryptoServiceImpl::isEncryptionKeyValid);\n\n        this.keystorePasswordPath = this.systemService.getKuraDataDirectory() + File.separator + \"store.save\";\n    }\n\n    private Optional<byte[]> loadCustomEncryptionKey() {\n        try {\n            final Optional<SystemdCredentialLoader> loader = SystemdCredentialLoader.fromEnv();\n\n            if (loader.isPresent()) {\n\n                final Optional<byte[]> keyFromSystemd = loader.get().loadCredential(SECRET_KEY_CREDENTIAL_ID);\n\n                if (keyFromSystemd.isPresent()) {\n                    logger.debug(\"using key from systemd\");\n                    return Optional.of(keyFromSystemd.get());\n                }\n            }\n\n        } catch (final Exception e) {\n            logger.warn(\"Unexpected exception loading encryption provided by systemd\", e);\n        }\n\n        return Optional.ofNullable(System.getProperty(SECRET_KEY_SYSTEM_PROPERTY_NAME)).filter(k -> !k.isEmpty())\n                .map(k -> {\n                    logger.debug(\"using key from system properties\");\n                    return k.getBytes(StandardCharsets.UTF_8);\n                });\n    }\n\n    private static boolean isEncryptionKeyValid(final byte[] key) {\n\n        return (key.length == 16 || key.length == 24 || key.length == 32) && !Arrays.equals(key, DEFAULT_SECRET_KEY);\n    }\n\n    @Override\n    public char[] encryptAes(char[] value) throws KuraException {\n\n        try {\n            Key key = generateKey();\n            Cipher c = Cipher.getInstance(CIPHER);\n            byte[] iv = new byte[IV_SIZE];\n            this.random.nextBytes(iv);\n            c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(AUTH_TAG_LENGTH_BIT, iv));\n            byte[] encryptedBytes = c.doFinal(charArrayToByteArray(value));\n            String ivString = base64Encode(iv);\n            String encryptedMessage = base64Encode(encryptedBytes);\n\n            return (ivString + ENCRYPTED_STRING_SEPARATOR + encryptedMessage).toCharArray();\n        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {\n            throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, \"encrypt\");\n        } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | CharacterCodingException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, VALUE_EXCEPTION_CAUSE);\n        } catch (InvalidAlgorithmParameterException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, PARAMETER_EXCEPTION_CAUSE);\n        }\n\n    }\n\n    @Override\n    public OutputStream aesEncryptingStream(OutputStream stream) throws KuraException {\n        try {\n            Key key = generateKey();\n            Cipher c = Cipher.getInstance(CIPHER);\n\n            byte[] iv = new byte[IV_SIZE];\n            this.random.nextBytes(iv);\n            c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(AUTH_TAG_LENGTH_BIT, iv));\n\n            stream.write(base64Encode(iv).getBytes(StandardCharsets.UTF_8));\n            stream.write(ENCRYPTED_STRING_SEPARATOR.getBytes(StandardCharsets.UTF_8));\n\n            final OutputStream base64Encoder = Base64.getEncoder().wrap(stream);\n\n            return new CipherOutputStream(base64Encoder, c);\n\n        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {\n            throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, \"encrypt\");\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.IO_ERROR, e);\n        } catch (InvalidAlgorithmParameterException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, PARAMETER_EXCEPTION_CAUSE);\n        } catch (InvalidKeyException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, VALUE_EXCEPTION_CAUSE);\n        }\n    }\n\n    private byte[] charArrayToByteArray(char[] value) throws CharacterCodingException {\n\n        ByteBuffer byteBuffer;\n        try {\n            byteBuffer = getUtf8Encoder().encode(CharBuffer.wrap(value));\n        } catch (CharacterCodingException e) {\n            // fallback for backward compatibility\n            byteBuffer = ByteBuffer.wrap(new String(value).getBytes());\n        }\n        byte[] encodedBytes = new byte[byteBuffer.limit()];\n        byteBuffer.get(encodedBytes);\n\n        return encodedBytes;\n    }\n\n    private char[] byteArrayToCharArray(byte[] value) throws CharacterCodingException {\n        CharBuffer charBuffer;\n        try {\n            charBuffer = getUtf8Decoder().decode(ByteBuffer.wrap(value));\n        } catch (CharacterCodingException e) {\n            // fallback for backward compatibility\n            charBuffer = CharBuffer.wrap(new String(value).toCharArray());\n        }\n        char[] decodedChar = new char[charBuffer.limit()];\n        charBuffer.get(decodedChar);\n\n        return decodedChar;\n    }\n\n    private CharsetEncoder getUtf8Encoder() {\n        CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder();\n        encoder.onMalformedInput(CodingErrorAction.REPORT);\n        encoder.onUnmappableCharacter(CodingErrorAction.REPORT);\n\n        return encoder;\n    }\n\n    private CharsetDecoder getUtf8Decoder() {\n        CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();\n        decoder.onMalformedInput(CodingErrorAction.REPORT);\n        decoder.onUnmappableCharacter(CodingErrorAction.REPORT);\n\n        return decoder;\n    }\n\n    private byte[] base64Decode(String internalStringValue) {\n        return Base64.getDecoder().decode(internalStringValue);\n    }\n\n    private String base64Encode(byte[] encryptedBytes) {\n        return Base64.getEncoder().encodeToString(encryptedBytes);\n    }\n\n    @Override\n    public char[] decryptAes(char[] encryptedValue) throws KuraException {\n        if (encryptedValue.length == 0) {\n            return new char[0];\n        }\n\n        try {\n            String internalStringValue = new String(encryptedValue);\n\n            String[] internalStringValueArray = internalStringValue.split(ENCRYPTED_STRING_SEPARATOR);\n            if (internalStringValueArray.length != 2) {\n                throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE);\n            }\n            String encodedIv = internalStringValueArray[0];\n            String encodedValue = internalStringValueArray[1];\n\n            byte[] iv = base64Decode(encodedIv);\n            byte[] decodedValue = base64Decode(encodedValue);\n            if (encryptedValue.length > 0 && decodedValue.length == 0) {\n                throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE);\n            }\n\n            Cipher c = Cipher.getInstance(CIPHER);\n            c.init(Cipher.DECRYPT_MODE, generateKey(), new GCMParameterSpec(AUTH_TAG_LENGTH_BIT, iv));\n            byte[] decryptedBytes = c.doFinal(decodedValue);\n\n            return byteArrayToCharArray(decryptedBytes);\n        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {\n            throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, DECRYPT_EXCEPTION_CAUSE);\n        } catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException | CharacterCodingException e) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE);\n        } catch (InvalidAlgorithmParameterException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, PARAMETER_EXCEPTION_CAUSE);\n        }\n    }\n\n    @Override\n    public InputStream aesDecryptingStream(InputStream encryptedStream) throws KuraException {\n        try {\n\n            final BufferedInputStream buffered = new BufferedInputStream(encryptedStream);\n\n            final ByteArrayOutputStream encodedIv = new ByteArrayOutputStream();\n\n            int b;\n\n            for (b = buffered.read(); b != -1 && b != '-'; b = buffered.read()) {\n                encodedIv.write(b);\n            }\n\n            if (b == -1) {\n                throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE);\n            }\n\n            byte[] iv = base64Decode(new String(encodedIv.toByteArray(), StandardCharsets.UTF_8));\n\n            buffered.mark(1);\n\n            if (buffered.read() == -1) {\n                throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE);\n            }\n\n            buffered.reset();\n\n            final InputStream decodedStream = Base64.getDecoder().wrap(buffered);\n\n            Cipher c = Cipher.getInstance(CIPHER);\n            c.init(Cipher.DECRYPT_MODE, generateKey(), new GCMParameterSpec(AUTH_TAG_LENGTH_BIT, iv));\n\n            return new CipherInputStream(decodedStream, c);\n\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, e);\n        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {\n            throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, DECRYPT_EXCEPTION_CAUSE);\n        } catch (InvalidKeyException e) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE);\n        } catch (InvalidAlgorithmParameterException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, PARAMETER_EXCEPTION_CAUSE);\n        }\n    }\n\n    @Override\n    @Deprecated\n    public String encryptAes(String value) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,\n            IllegalBlockSizeException, BadPaddingException {\n        char[] encryptedValue = null;\n        try {\n            encryptedValue = encryptAes(value.toCharArray());\n        } catch (KuraException e) {\n            Throwable t = e.getCause();\n            if (t instanceof NoSuchAlgorithmException) {\n                throw (NoSuchAlgorithmException) t;\n            } else if (t instanceof NoSuchPaddingException) {\n                throw (NoSuchPaddingException) t;\n            } else if (t instanceof InvalidKeyException) {\n                throw (InvalidKeyException) t;\n            } else if (t instanceof IllegalBlockSizeException) {\n                throw (IllegalBlockSizeException) t;\n            } else if (t instanceof BadPaddingException) {\n                throw (BadPaddingException) t;\n            }\n        }\n\n        return new String(encryptedValue);\n    }\n\n    @Override\n    @Deprecated\n    public String decryptAes(String encryptedValue) throws NoSuchAlgorithmException, NoSuchPaddingException,\n            InvalidKeyException, IOException, IllegalBlockSizeException, BadPaddingException {\n        try {\n            return new String(decryptAes(encryptedValue.toCharArray()));\n        } catch (KuraException e) {\n            throw new IOException();\n        }\n    }\n\n    @Override\n    public String encodeBase64(String stringValue) throws UnsupportedEncodingException {\n        if (stringValue == null) {\n            return null;\n        }\n\n        return base64Encode(stringValue.getBytes(StandardCharsets.UTF_8));\n    }\n\n    @Override\n    public String decodeBase64(String encodedValue) throws NoSuchAlgorithmException, UnsupportedEncodingException {\n        if (encodedValue == null) {\n            return null;\n        }\n\n        return new String(base64Decode(encodedValue), StandardCharsets.UTF_8);\n    }\n\n    @Override\n    public char[] getKeyStorePassword(String keyStorePath) {\n        Properties props = new Properties();\n        char[] password = null;\n\n        File f = new File(this.keystorePasswordPath);\n        if (!f.exists()) {\n            return \"changeit\".toCharArray();\n        }\n\n        try (FileInputStream fis = new FileInputStream(this.keystorePasswordPath);) {\n            props.load(fis);\n            Object value = props.get(keyStorePath);\n            if (value != null) {\n                String encryptedPassword = (String) value;\n                password = decryptAes(encryptedPassword.toCharArray());\n            }\n        } catch (FileNotFoundException e) {\n            logger.warn(\"File not found exception while getting keystore password - \", e);\n        } catch (IOException e) {\n            logger.warn(\"IOException while getting keystore password - \", e);\n        } catch (KuraException e) {\n            logger.warn(\"KuraException while getting keystore password - \", e);\n        }\n\n        return password;\n    }\n\n    @Override\n    public void setKeyStorePassword(String keyStorePath, char[] password) throws KuraException {\n        Properties props = new Properties();\n        try (FileInputStream fis = new FileInputStream(this.keystorePasswordPath)) {\n            props.load(fis);\n        } catch (IOException e) {\n            // Not loading from an existing file\n        }\n        char[] encryptedPassword = encryptAes(password);\n        props.put(keyStorePath, new String(encryptedPassword));\n\n        try (FileOutputStream fos = new FileOutputStream(this.keystorePasswordPath);) {\n            props.store(fos, \"Do not edit this file. It's automatically generated by Kura\");\n            fos.flush();\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e);\n        }\n    }\n\n    @Override\n    @Deprecated\n    public void setKeyStorePassword(String keyStorePath, String password) throws IOException {\n        try {\n            setKeyStorePassword(keyStorePath, password.toCharArray());\n        } catch (KuraException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public boolean isFrameworkSecure() {\n        return false;\n    }\n\n    private Key generateKey() {\n\n        if (!this.secretKey.isPresent()) {\n            logger.warn(\"A user defined encryption key has not been provided or is invalid.\"\n                    + \" The default well known key is in use.\"\n                    + \" Please reinstall Kura and provide a valid encryption key of length 16, 24, or 32 bytes (characters)\"\n                    + \" as explained in the Eclipse Kura documentation.\");\n            return new SecretKeySpec(DEFAULT_SECRET_KEY, ALGORITHM);\n        }\n\n        return new SecretKeySpec(this.secretKey.get(), ALGORITHM);\n    }\n\n    @Override\n    public String hash(String s, String algorithm) throws NoSuchAlgorithmException, UnsupportedEncodingException {\n        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);\n        messageDigest.reset();\n        messageDigest.update(s.getBytes(StandardCharsets.UTF_8));\n\n        byte[] encodedBytes = messageDigest.digest();\n        return base64Encode(encodedBytes);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.crypto/src/main/java/org/eclipse/kura/core/crypto/SystemdCredentialLoader.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.crypto;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Optional;\n\npublic class SystemdCredentialLoader {\n\n    private static final String CREDENTIALS_DIRECTORY_ENV = \"CREDENTIALS_DIRECTORY\";\n    private final File credentialRoot;\n\n    public SystemdCredentialLoader(final File credentialRoot) {\n        this.credentialRoot = credentialRoot;\n    }\n\n    public static Optional<SystemdCredentialLoader> fromEnv() {\n        return Optional.ofNullable(System.getenv(CREDENTIALS_DIRECTORY_ENV)).map(File::new).filter(File::isDirectory)\n                .map(SystemdCredentialLoader::new);\n    }\n\n    public Optional<byte[]> loadCredential(final String name) throws IOException {\n\n        final File credentialFile = new File(this.credentialRoot, name);\n\n        if (!credentialFile.exists()) {\n            return Optional.empty();\n        }\n\n        try (final InputStream in = new FileInputStream(credentialFile);\n                final ByteArrayOutputStream out = new ByteArrayOutputStream()) {\n            final byte[] buf = new byte[1024];\n\n            for (int rd = in.read(buf); rd != -1; rd = in.read(buf)) {\n                out.write(buf, 0, rd);\n            }\n\n            return Optional.of(out.toByteArray());\n        }\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.identity\nBundle-SymbolicName: org.eclipse.kura.core.identity;singleton:=true\nBundle-Version: 2.0.0.qualifier\nImport-Package: org.eclipse.kura;version=\"[1.7,2.0)\",\n org.eclipse.kura.audit;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.identity;version=\"[1.2,1.3)\",\n org.eclipse.kura.identity.configuration.extension;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.useradmin;version=\"[1.1,2.0)\",\n org.eclipse.kura.util.validation;version=\"[1.0,2.0)\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.slf4j;version=\"1.7.36\"\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/OSGI-INF/org.eclipse.kura.core.identity.IdentityServiceImpl.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" immediate=\"true\" name=\"org.eclipse.kura.core.identity.IdentityServiceImpl\">\n   <implementation class=\"org.eclipse.kura.core.identity.IdentityServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.identity.IdentityService\"/>\n   </service>\n   <reference bind=\"setUserAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.useradmin.UserAdmin\" name=\"UserAdmin\" policy=\"static\"/>\n   <reference bind=\"setIdentityConfigurationExtension\" cardinality=\"0..n\" interface=\"org.eclipse.kura.identity.configuration.extension.IdentityConfigurationExtension\" name=\"IdentityConfigurationExtension\" policy=\"dynamic\" unbind=\"unsetIdentityConfigurationExtension\"/>\n   <reference bind=\"setCryptoService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.crypto.CryptoService\" name=\"CryptoService\" policy=\"static\"/>\n   <reference bind=\"setPasswordStrengthVerificationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.identity.PasswordStrengthVerificationService\" name=\"PasswordStrengthVerificationService\" policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/build.properties",
    "content": "#\n#  Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\nsrc.includes = about.html,\\\n               about_files/\nadditional.bundles = org.osgi.service.component.annotations,\\\n                     org.osgi.service.metatype.annotations"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.identity</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.core.identity.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>biz.aQute.bnd</groupId>\n\t\t\t\t<artifactId>bnd-maven-plugin</artifactId>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/IdentityServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.core.identity;\n\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.identity.store.TemporaryIdentityStore;\nimport org.eclipse.kura.core.identity.store.TemporaryIdentityStoreAdapter;\nimport org.eclipse.kura.core.identity.store.UserAdminIdentityStore;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.identity.AdditionalConfigurations;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityConfigurationComponent;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.PasswordHash;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.identity.Permission;\nimport org.eclipse.kura.identity.configuration.extension.IdentityConfigurationExtension;\nimport org.eclipse.kura.util.useradmin.UserAdminHelper;\nimport org.eclipse.kura.util.useradmin.UserAdminHelper.AuthenticationException;\nimport org.osgi.service.useradmin.UserAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@SuppressWarnings(\"restriction\")\npublic class IdentityServiceImpl implements IdentityService {\n\n    private static final String IDENTITY_SERVICE_FAILURE_FORMAT_STRING = \"{} IdentityService - Failure - {}\";\n    private static final String IDENTITY_SERVICE_SUCCESS_FORMAT_STRING = \"{} IdentityService - Success - {}\";\n\n    private static final Logger auditLogger = LoggerFactory.getLogger(\"AuditLogger\");\n    private static final Logger logger = LoggerFactory.getLogger(IdentityServiceImpl.class);\n\n    public static final String PASSWORD_PROPERTY = \"kura.password\";\n    public static final String KURA_NEED_PASSWORD_CHANGE = \"kura.need.password.change\";\n\n    private UserAdmin userAdmin;\n    private CryptoService cryptoService;\n    private UserAdminHelper userAdminHelper;\n    private PasswordStrengthVerificationService passwordStrengthVerificationService;\n\n    private final Map<String, IdentityConfigurationExtension> extensions = new ConcurrentHashMap<>();\n    private final TemporaryIdentityStore temporaryStore = new TemporaryIdentityStore();\n    private TemporaryIdentityStoreAdapter temporaryIdentityStore;\n    private UserAdminIdentityStore userAdminIdentityStore;\n\n    public void setCryptoService(final CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void setUserAdmin(final UserAdmin userAdmin) {\n        this.userAdmin = userAdmin;\n    }\n\n    public void setPasswordStrengthVerificationService(\n            final PasswordStrengthVerificationService passwordStrengthVerificationService) {\n        this.passwordStrengthVerificationService = passwordStrengthVerificationService;\n    }\n\n    public synchronized void setIdentityConfigurationExtension(\n            final IdentityConfigurationExtension identityConfigurationExtension, final Map<String, Object> properties) {\n        final Object kuraServicePid = properties.get(ConfigurationService.KURA_SERVICE_PID);\n\n        if (!(kuraServicePid instanceof String)) {\n            logger.warn(\"found {} registered without setting the {} service property, service will not be tracked\",\n                    IdentityConfigurationExtension.class.getSimpleName(), ConfigurationService.KURA_SERVICE_PID);\n            return;\n        }\n\n        this.extensions.put((String) kuraServicePid, identityConfigurationExtension);\n    }\n\n    public synchronized void unsetIdentityConfigurationExtension(\n            final IdentityConfigurationExtension identityConfigurationExtension, final Map<String, Object> properties) {\n        final Object kuraServicePid = properties.get(ConfigurationService.KURA_SERVICE_PID);\n\n        if (kuraServicePid instanceof String) {\n            this.extensions.remove(kuraServicePid);\n        }\n    }\n\n    public void activate() {\n        this.userAdminHelper = new UserAdminHelper(this.userAdmin, this.cryptoService);\n        this.temporaryIdentityStore = new TemporaryIdentityStoreAdapter(this.temporaryStore,\n                this.passwordStrengthVerificationService, this::computePasswordHash);\n        this.userAdminIdentityStore = new UserAdminIdentityStore(this.userAdminHelper, this.extensions, logger,\n                this::computePasswordHash);\n    }\n\n    public void deactivate() {\n        this.temporaryStore.shutdown();\n    }\n\n    @Override\n    public synchronized boolean createIdentity(final String name) throws KuraException {\n        ValidationUtil.validateNewIdentityName(name);\n        return createIdentity(new IdentityConfiguration(name, Collections.emptyList()));\n    }\n\n    @Override\n    public synchronized boolean createIdentity(final IdentityConfiguration configuration) throws KuraException {\n        final String name = configuration.getName();\n\n        ValidationUtil.validateNewIdentityName(name);\n\n        if (this.temporaryIdentityStore.exists(name) || this.userAdminHelper.getUser(name).isPresent()) {\n            return false;\n        }\n\n        audit(() -> {\n            this.userAdminHelper.createUser(name);\n\n            if (!configuration.getComponents().isEmpty()) {\n                validateIdentityConfiguration(configuration);\n                this.userAdminIdentityStore.updateIdentityConfiguration(configuration);\n            }\n        }, \"Create identity \" + name);\n\n        return true;\n    }\n\n    @Override\n    public synchronized boolean deleteIdentity(final String name) throws KuraException {\n        if (this.temporaryIdentityStore.exists(name)) {\n            return audit(() -> this.temporaryIdentityStore.deleteIdentity(name), \"Delete temporary identity \" + name);\n        }\n\n        if (this.userAdminIdentityStore.exists(name)) {\n            return audit(() -> this.userAdminIdentityStore.deleteIdentity(name), \"Delete identity \" + name);\n        }\n\n        return false;\n    }\n\n    @Override\n    public synchronized List<IdentityConfiguration> getIdentitiesConfiguration(\n            Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) throws KuraException {\n        final List<IdentityConfiguration> result = new ArrayList<>();\n\n        result.addAll(this.userAdminIdentityStore.getIdentitiesConfiguration(componentsToReturn));\n        result.addAll(this.temporaryIdentityStore.getIdentitiesConfiguration(componentsToReturn));\n\n        return result;\n    }\n\n    @Override\n    public synchronized Optional<IdentityConfiguration> getIdentityConfiguration(String name,\n            Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) throws KuraException {\n\n        final Optional<IdentityConfiguration> temporaryIdentity = this.temporaryIdentityStore\n                .getIdentityConfiguration(name, componentsToReturn);\n        if (temporaryIdentity.isPresent()) {\n            return temporaryIdentity;\n        }\n\n        return this.userAdminIdentityStore.getIdentityConfiguration(name, componentsToReturn);\n    }\n\n    @Override\n    public IdentityConfiguration getIdentityDefaultConfiguration(String identityName,\n            Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) throws KuraException {\n        final List<IdentityConfigurationComponent> components = new ArrayList<>();\n\n        if (componentsToReturn.contains(PasswordConfiguration.class)) {\n            components.add(new PasswordConfiguration(false, false, Optional.empty(), Optional.empty()));\n        }\n\n        if (componentsToReturn.contains(AssignedPermissions.class)) {\n            components.add(new AssignedPermissions(Collections.emptySet()));\n        }\n\n        if (componentsToReturn.contains(AdditionalConfigurations.class)) {\n            components.add(getAdditionalConfigurationsDefaults(identityName));\n        }\n\n        return new IdentityConfiguration(identityName, components);\n    }\n\n    @Override\n    public void validateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException {\n        audit(() -> {\n            final Optional<PasswordConfiguration> passwordCofiguration = identityConfiguration\n                    .getComponent(PasswordConfiguration.class);\n\n            if (passwordCofiguration.isPresent()) {\n                validatePasswordConfiguration(identityConfiguration, passwordCofiguration.get());\n            }\n\n            final Optional<AdditionalConfigurations> additionalConfigurations = identityConfiguration\n                    .getComponent(AdditionalConfigurations.class);\n\n            if (additionalConfigurations.isPresent()) {\n                validateAdditionalConfigurations(identityConfiguration, additionalConfigurations.get());\n            }\n\n            final Optional<AssignedPermissions> assignedPermissions = identityConfiguration\n                    .getComponent(AssignedPermissions.class);\n\n            if (assignedPermissions.isPresent()) {\n                validateAssignedPermissions(assignedPermissions.get());\n            }\n\n        }, \"Validate configuration for identity\" + identityConfiguration.getName());\n\n    }\n\n    @Override\n    public synchronized void updateIdentityConfiguration(final IdentityConfiguration identityConfiguration)\n            throws KuraException {\n\n        audit(() -> {\n            if (this.temporaryIdentityStore.exists(identityConfiguration.getName())) {\n                validateIdentityConfiguration(identityConfiguration);\n                this.temporaryIdentityStore.updateIdentityConfiguration(identityConfiguration);\n                return;\n            }\n\n            if (!this.userAdminIdentityStore.exists(identityConfiguration.getName())) {\n                throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Identity does not exist\");\n            }\n\n            validateIdentityConfiguration(identityConfiguration);\n\n            this.userAdminIdentityStore.updateIdentityConfiguration(identityConfiguration);\n        }, \"Update configuration for identity \" + identityConfiguration.getName());\n\n    }\n\n    @Override\n    public synchronized boolean createPermission(final Permission permission) throws KuraException {\n        if (this.userAdminHelper.getPermission(permission.getName()).isPresent()) {\n            return false;\n        }\n\n        ValidationUtil.validateNewPermissionName(permission.getName());\n\n        this.userAdminHelper.getOrCreatePermission(permission.getName());\n        return true;\n    }\n\n    @Override\n    public synchronized boolean deletePermission(final Permission permission) throws KuraException {\n        if (!this.userAdminHelper.getPermission(permission.getName()).isPresent()) {\n            return false;\n        }\n\n        this.userAdminHelper.deletePremission(permission.getName());\n        return true;\n    }\n\n    @Override\n    public synchronized Set<Permission> getPermissions() {\n        return new UserAdminHelper(this.userAdmin, this.cryptoService).getDefinedPermissions().stream()\n                .map(Permission::new).collect(Collectors.toSet());\n    }\n\n    @Override\n    public PasswordHash computePasswordHash(final char[] password) throws KuraException {\n        try {\n            final String result = this.cryptoService.sha256Hash(new String(password));\n\n            for (int i = 0; i < password.length; i++) {\n                password[i] = ' ';\n            }\n\n            return new PasswordHashImpl(result);\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, \"failed to compute password hash\");\n        }\n    }\n\n    @Override\n    public void checkPassword(String identityName, char[] password) throws KuraException {\n        final PasswordConfiguration passwordConfiguration = getIdentityConfiguration(identityName,\n                Collections.singleton(PasswordConfiguration.class))\n                        .flatMap(i -> i.getComponent(PasswordConfiguration.class))\n                        .orElseThrow(() -> new KuraException(KuraErrorCode.SECURITY_EXCEPTION));\n\n        if (!passwordConfiguration.isPasswordAuthEnabled() || !Objects.equals(passwordConfiguration.getPasswordHash(),\n                Optional.of(computePasswordHash(password)))) {\n            throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION,\n                    \"Password authentication is not enabled or password does not match\");\n        }\n    }\n\n    @Override\n    public void checkPermission(String identityName, Permission permission) throws KuraException {\n        final Optional<IdentityConfiguration> temporaryIdentity = this.temporaryStore.getIdentity(identityName);\n        if (temporaryIdentity.isPresent()) {\n            final Optional<AssignedPermissions> assignedPermissions = temporaryIdentity.get()\n                    .getComponent(AssignedPermissions.class);\n\n            if (!assignedPermissions.isPresent()) {\n                throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION,\n                        \"The specified permission is not assigned to the given identity\");\n            }\n\n            final boolean hasPermission = assignedPermissions.get().getPermissions().stream()\n                    .anyMatch(p -> Objects.equals(p.getName(), permission.getName()));\n            if (!hasPermission) {\n                throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION,\n                        \"The specified permission is not assigned to the given identity\");\n            }\n\n            return;\n        }\n\n        try {\n            this.userAdminHelper.requirePermissions(identityName, permission.getName());\n        } catch (AuthenticationException e) {\n            throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION,\n                    \"The specified permission is not assigned to the given identity\");\n        }\n    }\n\n    private AdditionalConfigurations getAdditionalConfigurationsDefaults(final String name) {\n        final List<ComponentConfiguration> additionalConfigurations = new ArrayList<>();\n\n        for (final IdentityConfigurationExtension extension : this.extensions.values()) {\n            try {\n                extension.getDefaultConfiguration(name).ifPresent(additionalConfigurations::add);\n            } catch (final Exception e) {\n                logger.warn(\"Failed to get identity additional configuration defaults from extension\", e);\n            }\n        }\n\n        return new AdditionalConfigurations(additionalConfigurations);\n    }\n\n    private void validatePasswordConfiguration(final IdentityConfiguration identityConfiguration,\n            final PasswordConfiguration passwordCofiguration) throws KuraException {\n        if (!passwordCofiguration.isPasswordAuthEnabled()) {\n            return;\n        }\n\n        final Optional<char[]> newPassword = passwordCofiguration.getNewPassword();\n\n        if (newPassword.isPresent()) {\n\n            ValidationUtil.validateNewPassword(identityConfiguration.getName(), newPassword.get(),\n                    passwordStrengthVerificationService);\n\n        } else {\n            final boolean hasPersistedPasswordHash = this.userAdminHelper.getUser(identityConfiguration.getName())\n                    .filter(u -> u.getCredentials().get(PASSWORD_PROPERTY) != null).isPresent();\n            final boolean hasTemporaryPasswordHash = this.temporaryStore.getIdentity(identityConfiguration.getName())\n                    .flatMap(config -> config.getComponent(PasswordConfiguration.class))\n                    .flatMap(PasswordConfiguration::getPasswordHash).isPresent();\n            if (!hasPersistedPasswordHash && !hasTemporaryPasswordHash) {\n                throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                        \"Password authentication is enabled but no password has been provided or is currently assigned\");\n            }\n        }\n    }\n\n    private void validateAssignedPermissions(final AssignedPermissions assignedPermissions) throws KuraException {\n        for (final Permission permission : assignedPermissions.getPermissions()) {\n            if (!this.userAdminHelper.getPermission(permission.getName()).isPresent()) {\n                throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Permission does not exist\");\n            }\n        }\n    }\n\n    private void validateAdditionalConfigurations(final IdentityConfiguration identityConfiguration,\n            final AdditionalConfigurations additionalConfigurations) throws KuraException {\n        for (final ComponentConfiguration config : additionalConfigurations.getConfigurations()) {\n\n            final Optional<IdentityConfigurationExtension> extension = Optional\n                    .ofNullable(this.extensions.get(config.getPid()));\n\n            if (!extension.isPresent()) {\n                throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                        \"Configuration extension pid is not registered\");\n            }\n\n            extension.get().validateConfiguration(identityConfiguration.getName(), config);\n\n        }\n    }\n\n    @Override\n    public synchronized void createTemporaryIdentity(final String identityName, final Duration lifetime)\n            throws KuraException {\n\n        createTemporaryIdentity(new IdentityConfiguration(identityName, Collections.emptyList()), lifetime);\n    }\n\n    @Override\n    public synchronized void createTemporaryIdentity(final IdentityConfiguration identityConfiguration,\n            final Duration lifetime) throws KuraException {\n\n        final String identityName = identityConfiguration.getName();\n\n        ValidationUtil.validateNewIdentityName(identityName);\n\n        // Check if identity already exists (temporary or regular)\n        if (this.temporaryStore.exists(identityName)) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                    \"A temporary identity with name '\" + identityName + \"' already exists\");\n        }\n        if (this.userAdminHelper.getUser(identityName).isPresent()) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                    \"An identity with name '\" + identityName + \"' already exists\");\n        }\n\n        audit(() -> {\n            if (lifetime == null || lifetime.isZero() || lifetime.isNegative()) {\n                throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                        \"Temporary identity lifetime must be positive\");\n            }\n\n            validateIdentityConfiguration(identityConfiguration);\n            this.temporaryIdentityStore.createIdentity(identityConfiguration, lifetime);\n\n        }, \"Create temporary identity \" + identityName);\n    }\n\n    public static <T, E extends Throwable> T audit(final FallibleSupplier<T, E> task, final String message) throws E {\n        try {\n            final T result = task.get();\n            auditLogger.info(IDENTITY_SERVICE_SUCCESS_FORMAT_STRING, AuditContext.currentOrInternal(), message);\n            return result;\n        } catch (final Exception e) {\n            auditLogger.warn(IDENTITY_SERVICE_FAILURE_FORMAT_STRING, AuditContext.currentOrInternal(), message);\n            throw e;\n        }\n    }\n\n    public static <E extends Throwable> void audit(final FallibleTask<E> task, final String message) throws E {\n        try {\n            task.run();\n            auditLogger.info(IDENTITY_SERVICE_SUCCESS_FORMAT_STRING, AuditContext.currentOrInternal(), message);\n        } catch (final Exception e) {\n            auditLogger.warn(IDENTITY_SERVICE_FAILURE_FORMAT_STRING, AuditContext.currentOrInternal(), message);\n            throw e;\n        }\n    }\n\n    public interface FallibleSupplier<T, E extends Throwable> {\n\n        public T get() throws E;\n    }\n\n    public interface FallibleTask<E extends Throwable> {\n\n        public void run() throws E;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/LoginBannerServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.identity;\n\nimport java.util.Optional;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.function.BooleanSupplier;\nimport java.util.function.Supplier;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.identity.LoginBannerService;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.ConfigurationPolicy;\nimport org.osgi.service.component.annotations.Modified;\nimport org.osgi.service.metatype.annotations.Designate;\n\n@Component(immediate = true, name = LoginBannerServiceOptions.PID, //\n        configurationPolicy = ConfigurationPolicy.REQUIRE, property = \"kura.ui.service.hide:Boolean=true\")\n@Designate(ocd = LoginBannerServiceOptions.class)\npublic class LoginBannerServiceImpl implements LoginBannerService, ConfigurableComponent {\n\n    private final AtomicReference<LoginBannerServiceOptions> options;\n\n    @Activate\n    public LoginBannerServiceImpl(final LoginBannerServiceOptions options) {\n        this.options = new AtomicReference<>(options);\n    }\n\n    @Modified\n    public void updated(final LoginBannerServiceOptions options) {\n        this.options.set(options);\n    }\n\n    @Override\n    public Optional<String> getPreLoginBanner() {\n        final LoginBannerServiceOptions currentOptions = this.options.get();\n\n        return getMessage(currentOptions::pre_login_banner_enabled, currentOptions::pre_login_banner_content);\n    }\n\n    @Override\n    public Optional<String> getPostLoginBanner() {\n        final LoginBannerServiceOptions currentOptions = this.options.get();\n\n        return getMessage(currentOptions::post_login_banner_enabled, currentOptions::post_login_banner_content);\n    }\n\n    private static final Optional<String> getMessage(final BooleanSupplier enabled, final Supplier<String> message) {\n        if (enabled.getAsBoolean()) {\n            return Optional.ofNullable(message.get()).map(String::trim).filter(s -> !s.isEmpty());\n        } else {\n            return Optional.empty();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/LoginBannerServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.identity;\n\nimport org.osgi.service.component.annotations.ComponentPropertyType;\nimport org.osgi.service.metatype.annotations.AttributeDefinition;\nimport org.osgi.service.metatype.annotations.ObjectClassDefinition;\n\n@ObjectClassDefinition(id = LoginBannerServiceOptions.PID, name = \"Login Banner\", //\n        description = \"This component allows to enable and configure pre and post login banners that can be shown by Kura user interfaces.\")\n@ComponentPropertyType\npublic @interface LoginBannerServiceOptions {\n\n    public static final String PID = \"org.eclipse.kura.identity.LoginBannerService\";\n\n    @AttributeDefinition(name = \"Pre Login Banner Enabled\", //\n            description = \"If enabled, a customizable banner will be shown before user login.\")\n    public boolean pre_login_banner_enabled() default true;\n\n    @AttributeDefinition(name = \"Pre Login Banner Content\", //\n            description = \"The message to be shown in the pre login banner, if the feature is enabled.|TextArea\")\n    public String pre_login_banner_content() default \"WARNING: This is a secure system. The details of this login attempt have been recorded for future inspection by the system administrator. Log out now if you are not authorized to use this device.\";\n\n    @AttributeDefinition(name = \"Post Login Banner Enabled\", //\n            description = \"If enabled, a customizable banner will be shown after successful user login.\")\n    public boolean post_login_banner_enabled() default false;\n\n    @AttributeDefinition(name = \"Post Login Banner Content\", //\n            description = \"The message to be shown in the post login banner, if the feature is enabled.|TextArea\")\n    public String post_login_banner_content() default \"Sample Banner Content\";\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/PasswordHashImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.identity;\n\nimport java.util.Objects;\n\nimport org.eclipse.kura.identity.PasswordHash;\n\npublic class PasswordHashImpl implements PasswordHash {\n\n    private final String hash;\n\n    public PasswordHashImpl(String hash) {\n        super();\n        this.hash = hash;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.hash);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof PasswordHashImpl)) {\n            return false;\n        }\n        PasswordHashImpl other = (PasswordHashImpl) obj;\n        return Objects.equals(this.hash, other.hash);\n    }\n\n    @Override\n    public String toString() {\n        return this.hash;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/PasswordHasher.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.core.identity;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.identity.PasswordHash;\n\npublic interface PasswordHasher {\n\n    PasswordHash hash(char[] password) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/PasswordStrengthVerificationServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.identity;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.identity.PasswordStrengthRequirements;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.util.validation.PasswordStrengthValidators;\nimport org.eclipse.kura.util.validation.Validator;\nimport org.eclipse.kura.util.validation.ValidatorOptions;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.ConfigurationPolicy;\nimport org.osgi.service.component.annotations.Modified;\nimport org.osgi.service.metatype.annotations.Designate;\n\n@SuppressWarnings(\"restriction\")\n@Component(immediate = true, name = PasswordStrengthVerificationServiceOptions.PID, //\n        configurationPolicy = ConfigurationPolicy.REQUIRE, property = \"kura.ui.service.hide:Boolean=true\")\n@Designate(ocd = PasswordStrengthVerificationServiceOptions.class)\npublic class PasswordStrengthVerificationServiceImpl\n        implements PasswordStrengthVerificationService, ConfigurableComponent {\n\n    private final AtomicReference<PasswordStrengthRequirements> requirements;\n\n    @Activate\n    public PasswordStrengthVerificationServiceImpl(final PasswordStrengthVerificationServiceOptions options) {\n        this.requirements = new AtomicReference<>(buildPasswordStrengthRequirements(options));\n    }\n\n    @Modified\n    public void updated(final PasswordStrengthVerificationServiceOptions options) {\n        this.requirements.set(buildPasswordStrengthRequirements(options));\n    }\n\n    @Override\n    public PasswordStrengthRequirements getPasswordStrengthRequirements() {\n        return this.requirements.get();\n    }\n\n    @Override\n    public void checkPasswordStrength(char[] password) throws KuraException {\n        List<Validator<String>> validators = buildValidators(null);\n        checkPasswordStrength(password, validators);\n    }\n\n    @Override\n    public void checkPasswordStrength(String identityName, char[] password) throws KuraException {\n        List<Validator<String>> validators = buildValidators(identityName);\n        checkPasswordStrength(password, validators);\n    }\n\n    private List<Validator<String>> buildValidators(String identityName) {\n        PasswordStrengthRequirements currentRequirements = getPasswordStrengthRequirements();\n        ValidatorOptions validatorOptions = new ValidatorOptions(currentRequirements.getPasswordMinimumLength(), //\n                currentRequirements.digitsRequired(), //\n                currentRequirements.bothCasesRequired(), //\n                currentRequirements.specialCharactersRequired());\n\n        List<Validator<String>> validators = new ArrayList<>(PasswordStrengthValidators.fromConfig(validatorOptions));\n        if (identityName != null && !identityName.trim().isEmpty()) {\n            validators.add(PasswordStrengthValidators.requireDifferentNameAndPassword(identityName));\n        }\n        return validators;\n    }\n\n    private void checkPasswordStrength(char[] password, List<Validator<String>> validators) throws KuraException {\n        final List<String> errors = new ArrayList<>();\n\n        for (final Validator<String> validator : validators) {\n            validator.validate(new String(password), errors::add);\n        }\n\n        if (!errors.isEmpty()) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Password strength requirements not satisfied: \"\n                    + errors.stream().collect(Collectors.joining(\"; \")));\n        }\n    }\n\n    private static PasswordStrengthRequirements buildPasswordStrengthRequirements(\n            final PasswordStrengthVerificationServiceOptions options) {\n        return new PasswordStrengthRequirements(options.new_password_min_length(),\n                options.new_password_require_digits(), options.new_password_require_special_characters(),\n                options.new_password_require_both_cases());\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/PasswordStrengthVerificationServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.identity;\n\nimport org.osgi.service.component.annotations.ComponentPropertyType;\nimport org.osgi.service.metatype.annotations.AttributeDefinition;\nimport org.osgi.service.metatype.annotations.ObjectClassDefinition;\n\n@ObjectClassDefinition(id = PasswordStrengthVerificationServiceOptions.PID, name = \"Password Strength\", //\n        description = \"This component allows to configure the strength requirements for new passwords.\")\n@ComponentPropertyType\npublic @interface PasswordStrengthVerificationServiceOptions {\n\n    public static final String PID = \"org.eclipse.kura.identity.PasswordStrengthVerificationService\";\n\n    @AttributeDefinition(name = \"Minimum password length\", //\n            min = \"0\", //\n            description = \"The minimum length to be enforced for new passwords. Set to 0 to disable.\")\n    public int new_password_min_length() default 12;\n\n    @AttributeDefinition(name = \"Require digits in new password\", //\n            description = \"If set to true, new passwords will be accepted only if containing at least one digit.\")\n    public boolean new_password_require_digits() default true;\n\n    @AttributeDefinition(name = \"Require special characters in new password\", //\n            description = \"If set to true, new passwords will be accepted only if containing at least one non alphanumeric character.\")\n    public boolean new_password_require_special_characters() default true;\n\n    @AttributeDefinition(name = \"Require uppercase and lowercase characters in new passwords\", //\n            description = \"If set to true, new passwords will be accepted only if containing both\"\n                    + \" uppercase and lowercase alphanumeric characters.\")\n    public boolean new_password_require_both_cases() default true;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/ValidationUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.identity;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.regex.Pattern;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\n\npublic class ValidationUtil {\n\n    private static final String NEW_PASSWORD = \"New password\";\n    private static final String PERMISSION_NAME = \"Permission name\";\n    private static final String IDENTITY_NAME = \"Identity name\";\n\n    private ValidationUtil() {\n    }\n\n    public static void validateNewPassword(final char[] password,\n            final PasswordStrengthVerificationService passwordStrengthVerificationService) throws KuraException {\n        if (password == null || password.length == 0) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"New password cannot be empty\");\n        }\n\n        requireMaximumLength(NEW_PASSWORD, password, 255);\n\n        requireNoWhitespaceCharacters(NEW_PASSWORD, password);\n\n        passwordStrengthVerificationService.checkPasswordStrength(password);\n    }\n\n    public static void validateNewPassword(String identityName, final char[] password,\n            final PasswordStrengthVerificationService passwordStrengthVerificationService) throws KuraException {\n        if (password == null || password.length == 0) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"New password cannot be empty\");\n        }\n\n        requireMaximumLength(NEW_PASSWORD, password, 255);\n\n        requireNoWhitespaceCharacters(NEW_PASSWORD, password);\n\n        passwordStrengthVerificationService.checkPasswordStrength(identityName, password);\n    }\n\n    public static void validateNewIdentityName(final String identityName) throws KuraException {\n        requireMinimumLength(IDENTITY_NAME, identityName, 3);\n\n        requireMaximumLength(IDENTITY_NAME, identityName, 255);\n\n        new PunctuatedAlphanumericSequenceValidator(IDENTITY_NAME, Arrays.asList('.', '_')).validate(identityName);\n    }\n\n    public static void validateNewPermissionName(final String permissionName) throws KuraException {\n        requireMinimumLength(PERMISSION_NAME, permissionName, 3);\n\n        requireMaximumLength(PERMISSION_NAME, permissionName, 255);\n\n        new PunctuatedAlphanumericSequenceValidator(PERMISSION_NAME, Collections.singletonList('.'))\n                .validate(permissionName);\n    }\n\n    private static void requireMinimumLength(final String parameterName, final String value, final int length)\n            throws KuraException {\n        if (value.length() < length) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                    parameterName + \" name must be at least \" + length + \" characters long\");\n        }\n    }\n\n    private static void requireMaximumLength(final String parameterName, final String value, final int length)\n            throws KuraException {\n        if (value.length() > length) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                    parameterName + \" must be at most \" + length + \" characters long\");\n        }\n    }\n\n    private static void requireMaximumLength(final String parameterName, final char[] value, final int length)\n            throws KuraException {\n        if (value.length > length) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                    parameterName + \" must be at most \" + length + \" characters long\");\n        }\n    }\n\n    private static void requireNoWhitespaceCharacters(final String parameterName, final char[] value)\n            throws KuraException {\n        for (int i = 0; i < value.length; i++) {\n            if (Character.isWhitespace(value[i])) {\n                throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                        parameterName + \" cannot contain whitespace characters\");\n            }\n        }\n    }\n\n    private static class PunctuatedAlphanumericSequenceValidator {\n\n        private final String parameterName;\n        private final List<Character> delimiters;\n\n        private static final Pattern ALPHANUMERIC_PATTERN = Pattern.compile(\"[a-zA-Z0-9]+\");\n\n        public PunctuatedAlphanumericSequenceValidator(final String parameterName, final List<Character> delimiters) {\n            this.parameterName = parameterName;\n            this.delimiters = delimiters;\n        }\n\n        private boolean isDelimiter(final char value) {\n            for (final char delimiter : delimiters) {\n                if (value == delimiter) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        private void requireNonEmptyAlphanumericString(final String value) throws KuraException {\n            if (!ALPHANUMERIC_PATTERN.matcher(value).matches()) {\n                throw new KuraException(KuraErrorCode.INVALID_PARAMETER, parameterName\n                        + \" must be composed of one or more non empty alphanumeric characters sequences separated by the following characters: \"\n                        + delimiters.stream().map(c -> \"\\'\" + c + \"\\'\").collect(Collectors.joining(\" \")));\n            }\n        }\n\n        public void validate(final String value) throws KuraException {\n            if (value.isEmpty()) {\n                return;\n            }\n\n            final StringBuilder component = new StringBuilder();\n\n            for (int i = 0; i < value.length(); i++) {\n                final char c = value.charAt(i);\n\n                if (isDelimiter(c)) {\n                    requireNonEmptyAlphanumericString(component.toString());\n                    component.setLength(0);\n                } else {\n                    component.append(c);\n                }\n            }\n\n            requireNonEmptyAlphanumericString(component.toString());\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/store/IdentityStore.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.core.identity.store;\n\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityConfigurationComponent;\n\ninterface IdentityStore {\n\n    boolean exists(String identityName) throws KuraException;\n\n    Optional<IdentityConfiguration> getIdentityConfiguration(String identityName,\n            Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) throws KuraException;\n\n    List<IdentityConfiguration> getIdentitiesConfiguration(\n            Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) throws KuraException;\n\n    void updateIdentityConfiguration(IdentityConfiguration identityConfiguration) throws KuraException;\n\n    boolean deleteIdentity(String identityName) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/store/TemporaryIdentityStore.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.core.identity.store;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * In-memory store for temporary identities that are not persisted.\n * Temporary identities use the same IdentityConfiguration structure as regular identities\n * but are stored in-memory only and have automatic expiration.\n */\npublic class TemporaryIdentityStore {\n\n    private static final Logger logger = LoggerFactory.getLogger(TemporaryIdentityStore.class);\n\n    private final Map<String, TemporaryIdentityRecord> identities = new ConcurrentHashMap<>();\n    private final ScheduledExecutorService expirationScheduler;\n\n    /**\n     * Record storing a temporary identity configuration and its expiration time.\n     */\n    static class TemporaryIdentityRecord {\n        final IdentityConfiguration configuration;\n        final Instant expiration;\n\n        TemporaryIdentityRecord(IdentityConfiguration configuration, Duration lifetime) {\n            this.configuration = configuration;\n            this.expiration = Instant.now().plus(lifetime);\n        }\n\n        TemporaryIdentityRecord(IdentityConfiguration configuration, Instant expiration) {\n            this.configuration = configuration;\n            this.expiration = expiration;\n        }\n\n        boolean isExpired() {\n            return Instant.now().isAfter(expiration);\n        }\n    }\n\n    /**\n     * Creates a new temporary identity store with automatic expiration cleanup.\n     */\n    public TemporaryIdentityStore() {\n        this.expirationScheduler = Executors.newSingleThreadScheduledExecutor(r -> {\n            Thread thread = new Thread(r, \"TemporaryIdentityStore-Cleanup\");\n            thread.setDaemon(true);\n            return thread;\n        });\n\n        // Schedule periodic cleanup every minute\n        this.expirationScheduler.scheduleWithFixedDelay(this::cleanupExpired, 1, 1, TimeUnit.MINUTES);\n    }\n\n    /**\n     * Creates a temporary identity with the given configuration and lifetime.\n     *\n     * @param name          the identity name\n     * @param configuration the identity configuration\n     * @param lifetime      the duration before automatic expiration\n     */\n    public void createIdentity(String name, IdentityConfiguration configuration, Duration lifetime) {\n        TemporaryIdentityRecord identityRecord = new TemporaryIdentityRecord(configuration, lifetime);\n        identities.put(name, identityRecord);\n\n        // Schedule individual expiration\n        scheduleExpiration(name, lifetime);\n\n        logger.info(\"Created temporary identity '{}' with expiration at {}\", name, identityRecord.expiration);\n    }\n\n    /**\n     * Retrieves a temporary identity configuration if it exists and is not expired.\n     *\n     * @param name the identity name\n     * @return the identity configuration if found and not expired, empty otherwise\n     */\n    public Optional<IdentityConfiguration> getIdentity(String name) {\n        TemporaryIdentityRecord identityRecord = identities.get(name);\n\n        if (identityRecord == null) {\n            return Optional.empty();\n        }\n\n        if (identityRecord.isExpired()) {\n            // Auto-cleanup expired identity\n            identities.remove(name);\n            logger.debug(\"Temporary identity '{}' has expired and was removed\", name);\n            return Optional.empty();\n        }\n\n        return Optional.of(identityRecord.configuration);\n    }\n\n    /**\n     * Checks if a temporary identity exists (and is not expired).\n     *\n     * @param name the identity name\n     * @return true if the identity exists and is not expired\n     */\n    public boolean exists(String name) {\n        return getIdentity(name).isPresent();\n    }\n\n    /**\n     * Deletes a temporary identity.\n     *\n     * @param name the identity name\n     * @return true if the identity was deleted, false if it didn't exist\n     */\n    public boolean deleteIdentity(String name) {\n        boolean removed = identities.remove(name) != null;\n        if (removed) {\n            logger.info(\"Deleted temporary identity '{}'\", name);\n        }\n        return removed;\n    }\n\n    /**\n     * Updates a temporary identity configuration while preserving its expiration.\n     *\n     * @param name the identity name\n     * @param configuration the new configuration\n     * @return true if the identity existed and was updated\n     */\n    public boolean updateIdentity(String name, IdentityConfiguration configuration) {\n        final TemporaryIdentityRecord identityRecord = identities.get(name);\n        if (identityRecord == null) {\n            return false;\n        }\n\n        if (identityRecord.isExpired()) {\n            identities.remove(name);\n            logger.debug(\"Temporary identity '{}' has expired and was removed\", name);\n            return false;\n        }\n\n        identities.put(name, new TemporaryIdentityRecord(configuration, identityRecord.expiration));\n        return true;\n    }\n\n    /**\n     * Returns all temporary identity names (not expired).\n     *\n     * @return array of identity names\n     */\n    public String[] getAllIdentityNames() {\n        // Remove expired entries first\n        cleanupExpired();\n        return identities.keySet().toArray(new String[0]);\n    }\n\n    /**\n     * Shuts down the expiration scheduler.\n     */\n    public void shutdown() {\n        logger.info(\"Shutting down temporary identity store\");\n        expirationScheduler.shutdown();\n        try {\n            if (!expirationScheduler.awaitTermination(5, TimeUnit.SECONDS)) {\n                expirationScheduler.shutdownNow();\n            }\n        } catch (InterruptedException e) {\n            expirationScheduler.shutdownNow();\n            Thread.currentThread().interrupt();\n        }\n        identities.clear();\n    }\n\n    /**\n     * Schedules the expiration of a temporary identity.\n     *\n     * @param name     the identity name\n     * @param lifetime the duration before expiration\n     */\n    private void scheduleExpiration(String name, Duration lifetime) {\n        expirationScheduler.schedule(() -> {\n            boolean removed = identities.remove(name) != null;\n            if (removed) {\n                logger.info(\"Temporary identity '{}' expired and was removed\", name);\n            }\n        }, lifetime.toMillis(), TimeUnit.MILLISECONDS);\n    }\n\n    /**\n     * Removes all expired identities.\n     */\n    private void cleanupExpired() {\n        identities.entrySet().removeIf(entry -> {\n            boolean expired = entry.getValue().isExpired();\n            if (expired) {\n                logger.debug(\"Cleaning up expired temporary identity '{}'\", entry.getKey());\n            }\n            return expired;\n        });\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/store/TemporaryIdentityStoreAdapter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.core.identity.store;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.time.Duration;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.identity.PasswordHasher;\nimport org.eclipse.kura.core.identity.ValidationUtil;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityConfigurationComponent;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.PasswordHash;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\n\npublic class TemporaryIdentityStoreAdapter implements IdentityStore {\n\n    private final TemporaryIdentityStore temporaryStore;\n    private final PasswordStrengthVerificationService passwordStrengthVerificationService;\n    private final PasswordHasher passwordHasher;\n\n    public TemporaryIdentityStoreAdapter(final TemporaryIdentityStore temporaryStore,\n            final PasswordStrengthVerificationService passwordStrengthVerificationService,\n            final PasswordHasher passwordHasher) {\n        this.temporaryStore = temporaryStore;\n        this.passwordStrengthVerificationService = passwordStrengthVerificationService;\n        this.passwordHasher = passwordHasher;\n    }\n\n    @Override\n    public boolean exists(final String identityName) {\n        return this.temporaryStore.exists(identityName);\n    }\n\n    @Override\n    public Optional<IdentityConfiguration> getIdentityConfiguration(final String identityName,\n            final Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) {\n        return this.temporaryStore.getIdentity(identityName)\n                .map(config -> filterIdentityConfiguration(config, componentsToReturn));\n    }\n\n    @Override\n    public List<IdentityConfiguration> getIdentitiesConfiguration(\n            final Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) {\n        final List<IdentityConfiguration> result = new ArrayList<>();\n\n        for (final String identityName : this.temporaryStore.getAllIdentityNames()) {\n            this.temporaryStore.getIdentity(identityName)\n                    .map(config -> filterIdentityConfiguration(config, componentsToReturn))\n                    .ifPresent(result::add);\n        }\n\n        return result;\n    }\n\n    @Override\n    public void updateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException {\n        final IdentityConfiguration existingConfiguration = this.temporaryStore\n                .getIdentity(identityConfiguration.getName())\n                .orElseGet(() -> new IdentityConfiguration(identityConfiguration.getName(), Collections.emptyList()));\n\n        final IdentityConfiguration processedConfiguration = processConfigurationForTemporaryStorage(\n                identityConfiguration, Optional.of(existingConfiguration));\n\n        final Map<Class<? extends IdentityConfigurationComponent>, IdentityConfigurationComponent> merged =\n                new HashMap<>();\n        for (final IdentityConfigurationComponent component : existingConfiguration.getComponents()) {\n            merged.put(component.getClass(), component);\n        }\n        for (final IdentityConfigurationComponent component : processedConfiguration.getComponents()) {\n            merged.put(component.getClass(), component);\n        }\n\n        final List<IdentityConfigurationComponent> mergedComponents = new ArrayList<>(merged.values());\n        final IdentityConfiguration mergedConfiguration = new IdentityConfiguration(identityConfiguration.getName(),\n                mergedComponents);\n\n        if (!this.temporaryStore.updateIdentity(identityConfiguration.getName(), mergedConfiguration)) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Temporary identity does not exist\");\n        }\n    }\n\n    @Override\n    public boolean deleteIdentity(final String identityName) {\n        return this.temporaryStore.deleteIdentity(identityName);\n    }\n\n    public void createIdentity(final IdentityConfiguration configuration, final Duration lifetime) throws KuraException {\n        final IdentityConfiguration processedConfiguration = processConfigurationForTemporaryStorage(configuration,\n                Optional.empty());\n        this.temporaryStore.createIdentity(configuration.getName(), processedConfiguration, lifetime);\n    }\n\n    private IdentityConfiguration filterIdentityConfiguration(final IdentityConfiguration configuration,\n            final Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) {\n        if (componentsToReturn.isEmpty()) {\n            return new IdentityConfiguration(configuration.getName(), Collections.emptyList());\n        }\n\n        final List<IdentityConfigurationComponent> filteredComponents = configuration.getComponents().stream()\n                .filter(component -> componentsToReturn.stream().anyMatch(clazz -> clazz.isInstance(component)))\n                .toList();\n\n        return new IdentityConfiguration(configuration.getName(), filteredComponents);\n    }\n\n    private PasswordConfiguration processPasswordForStorage(final String identityName,\n            final PasswordConfiguration passwordConfiguration, final Optional<PasswordHash> existingPasswordHash)\n            throws KuraException {\n\n        if (!passwordConfiguration.isPasswordAuthEnabled()) {\n            return new PasswordConfiguration(\n                    passwordConfiguration.isPasswordChangeNeeded(),\n                    false,\n                    Optional.empty(),\n                    Optional.empty());\n        }\n\n        final Optional<char[]> newPassword = passwordConfiguration.getNewPassword();\n\n        if (newPassword.isPresent()) {\n            ValidationUtil.validateNewPassword(identityName, newPassword.get(), this.passwordStrengthVerificationService);\n\n            final PasswordHash hash = this.passwordHasher.hash(newPassword.get());\n\n            return new PasswordConfiguration(\n                    passwordConfiguration.isPasswordChangeNeeded(),\n                    true,\n                    Optional.empty(),\n                    Optional.of(hash));\n        }\n\n        if (!existingPasswordHash.isPresent()) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                    \"Password authentication is enabled but no password has been provided\");\n        }\n\n        return new PasswordConfiguration(\n                passwordConfiguration.isPasswordChangeNeeded(),\n                true,\n                Optional.empty(),\n                existingPasswordHash);\n    }\n\n    private IdentityConfiguration processConfigurationForTemporaryStorage(\n            final IdentityConfiguration configuration, final Optional<IdentityConfiguration> existingConfiguration)\n            throws KuraException {\n\n        final String identityName = configuration.getName();\n        final Optional<PasswordHash> existingPasswordHash = existingConfiguration\n                .flatMap(config -> config.getComponent(PasswordConfiguration.class))\n                .flatMap(PasswordConfiguration::getPasswordHash);\n        final List<IdentityConfigurationComponent> processedComponents = new ArrayList<>();\n\n        for (final IdentityConfigurationComponent component : configuration.getComponents()) {\n            if (component instanceof PasswordConfiguration) {\n                processedComponents.add(\n                        processPasswordForStorage(identityName, (PasswordConfiguration) component, existingPasswordHash));\n            } else {\n                processedComponents.add(component);\n            }\n        }\n\n        return new IdentityConfiguration(identityName, processedComponents);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/store/UserAdminIdentityStore.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.core.identity.store;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.core.identity.IdentityServiceImpl;\nimport org.eclipse.kura.core.identity.PasswordHashImpl;\nimport org.eclipse.kura.core.identity.PasswordHasher;\nimport org.eclipse.kura.identity.AdditionalConfigurations;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityConfigurationComponent;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.Permission;\nimport org.eclipse.kura.identity.configuration.extension.IdentityConfigurationExtension;\nimport org.eclipse.kura.util.useradmin.UserAdminHelper;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.slf4j.Logger;\n\npublic class UserAdminIdentityStore implements IdentityStore {\n\n    private final UserAdminHelper userAdminHelper;\n    private final Map<String, IdentityConfigurationExtension> extensions;\n    private final Logger logger;\n    private final PasswordHasher passwordHasher;\n\n    public UserAdminIdentityStore(final UserAdminHelper userAdminHelper,\n            final Map<String, IdentityConfigurationExtension> extensions,\n            final Logger logger,\n            final PasswordHasher passwordHasher) {\n        this.userAdminHelper = userAdminHelper;\n        this.extensions = extensions;\n        this.logger = logger;\n        this.passwordHasher = passwordHasher;\n    }\n\n    @Override\n    public boolean exists(final String identityName) {\n        return this.userAdminHelper.getUser(identityName).isPresent();\n    }\n\n    @Override\n    public Optional<IdentityConfiguration> getIdentityConfiguration(final String identityName,\n            final Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) {\n        return this.userAdminHelper.getUser(identityName)\n                .map(user -> buildIdentity(identityName, user, componentsToReturn));\n    }\n\n    @Override\n    public List<IdentityConfiguration> getIdentitiesConfiguration(\n            final Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) {\n        final List<IdentityConfiguration> result = new ArrayList<>();\n        this.userAdminHelper.foreachUser((name, user) -> result.add(buildIdentity(name, user, componentsToReturn)));\n        return result;\n    }\n\n    @Override\n    public void updateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException {\n        final User user = this.userAdminHelper.getUser(identityConfiguration.getName())\n                .orElseThrow(() -> new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Identity does not exist\"));\n        updateIdentityConfigurationInternal(user, identityConfiguration);\n    }\n\n    @Override\n    public boolean deleteIdentity(final String identityName) throws KuraException {\n        if (!this.userAdminHelper.getUser(identityName).isPresent()) {\n            return false;\n        }\n\n        this.userAdminHelper.deleteUser(identityName);\n        return true;\n    }\n\n    private void updateIdentityConfigurationInternal(final User user, final IdentityConfiguration identity)\n            throws KuraException {\n\n        final String identityName = identity.getName();\n        final Optional<PasswordConfiguration> passwordData = identity.getComponent(PasswordConfiguration.class);\n\n        if (passwordData.isPresent()) {\n            updatePassword(identityName, passwordData.get(), user);\n        }\n\n        final Optional<AssignedPermissions> permissions = identity.getComponent(AssignedPermissions.class);\n\n        if (permissions.isPresent()) {\n            updateAssignedPermissions(identityName, permissions.get(), user);\n        }\n\n        final Optional<AdditionalConfigurations> additionalConfigurations = identity\n                .getComponent(AdditionalConfigurations.class);\n\n        if (additionalConfigurations.isPresent()) {\n            updateAdditionalConfigurations(identity.getName(), additionalConfigurations.get());\n        }\n    }\n\n    private IdentityConfiguration buildIdentity(final String name, final User user,\n            final Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn) {\n\n        final List<IdentityConfigurationComponent> components = new ArrayList<>();\n\n        if (componentsToReturn.contains(PasswordConfiguration.class)) {\n            components.add(getPasswordData(user));\n        }\n\n        if (componentsToReturn.contains(AssignedPermissions.class)) {\n            final Set<Permission> permissions = this.userAdminHelper.getIdentityPermissions(name).stream()\n                    .map(Permission::new).collect(Collectors.toSet());\n            components.add(new AssignedPermissions(permissions));\n        }\n\n        if (componentsToReturn.contains(AdditionalConfigurations.class)) {\n            components.add(getAdditionalConfigurations(name));\n        }\n\n        return new IdentityConfiguration(name, components);\n    }\n\n    private AdditionalConfigurations getAdditionalConfigurations(final String name) {\n        final List<ComponentConfiguration> additionalConfigurations = new ArrayList<>();\n\n        for (final IdentityConfigurationExtension extension : this.extensions.values()) {\n            try {\n                extension.getConfiguration(name).ifPresent(additionalConfigurations::add);\n            } catch (final Exception e) {\n                this.logger.warn(\"Failed to get identity additional configuration from extension\", e);\n            }\n        }\n\n        return new AdditionalConfigurations(additionalConfigurations);\n    }\n\n    private PasswordConfiguration getPasswordData(final User user) {\n        final Optional<String> passwordHash = Optional.ofNullable(user.getCredentials()\n                .get(IdentityServiceImpl.PASSWORD_PROPERTY))\n                .filter(String.class::isInstance).map(String.class::cast);\n\n        final boolean isPasswordChangeNeeded = Objects.equals(\"true\",\n                user.getProperties().get(IdentityServiceImpl.KURA_NEED_PASSWORD_CHANGE));\n\n        return new PasswordConfiguration(isPasswordChangeNeeded, passwordHash.isPresent(), Optional.empty(),\n                passwordHash.map(PasswordHashImpl::new));\n    }\n\n    private void updateAssignedPermissions(final String identityName, final AssignedPermissions assignedPermissions,\n            final User user) {\n        this.userAdminHelper.foreachPermission((name, group) -> {\n            final Permission permission = new Permission(name);\n            final List<Role> members = Optional.ofNullable(group.getMembers()).map(Arrays::asList)\n                    .orElse(Collections.emptyList());\n\n            if (assignedPermissions.getPermissions().contains(permission) && !members.contains(user)) {\n                IdentityServiceImpl.audit(() -> group.addMember(user),\n                        \"Add permission \" + permission.getName() + \" to identity \" + identityName);\n            } else if (!assignedPermissions.getPermissions().contains(permission) && members.contains(user)) {\n                IdentityServiceImpl.audit(() -> group.removeMember(user),\n                        \"Remove permission \" + permission.getName() + \" from identity \" + identityName);\n            }\n        });\n    }\n\n    private void updatePassword(final String identityName, final PasswordConfiguration passwordData, final User user)\n            throws KuraException {\n\n        final Dictionary<String, Object> properties = user.getProperties();\n\n        final Object currentIsPasswordChangeNeeded = properties.get(IdentityServiceImpl.KURA_NEED_PASSWORD_CHANGE);\n\n        if (passwordData.isPasswordChangeNeeded()) {\n            if (!\"true\".equals(currentIsPasswordChangeNeeded)) {\n                IdentityServiceImpl.audit(() -> setProperty(properties,\n                        IdentityServiceImpl.KURA_NEED_PASSWORD_CHANGE, \"true\"),\n                        \"Enable password change at next login for identity \" + identityName);\n            }\n        } else if (currentIsPasswordChangeNeeded != null) {\n            IdentityServiceImpl.audit(() -> removeProperty(properties, IdentityServiceImpl.KURA_NEED_PASSWORD_CHANGE),\n                    \"Disable password change at next login for identity \" + identityName);\n        }\n\n        final Dictionary<String, Object> credentials = user.getCredentials();\n        final Optional<char[]> newPassword = passwordData.getNewPassword();\n\n        final Object currentPasswordHash = credentials.get(IdentityServiceImpl.PASSWORD_PROPERTY);\n\n        if (passwordData.isPasswordAuthEnabled() && newPassword.isPresent()) {\n\n            IdentityServiceImpl.audit(() -> setProperty(credentials, IdentityServiceImpl.PASSWORD_PROPERTY,\n                    this.passwordHasher.hash(newPassword.get()).toString()),\n                    \"Update Kura password for identity \" + identityName);\n\n        } else if (!passwordData.isPasswordAuthEnabled() && currentPasswordHash != null) {\n            IdentityServiceImpl.audit(() -> removeProperty(credentials, IdentityServiceImpl.PASSWORD_PROPERTY),\n                    \"Disable Kura password for identity \" + identityName);\n        }\n    }\n\n    private void updateAdditionalConfigurations(final String identityName,\n            final AdditionalConfigurations additionalConfigurations) throws KuraException {\n\n        final FailureHandler failureHandler = new FailureHandler(this.logger);\n\n        for (final ComponentConfiguration config : additionalConfigurations.getConfigurations()) {\n            final String pid = config.getPid();\n\n            final Optional<IdentityConfigurationExtension> extension = Optional.ofNullable(this.extensions.get(pid));\n\n            if (!extension.isPresent()) {\n                failureHandler.addError(\"Configuration extension pid is not registered\");\n                continue;\n            }\n\n            try {\n                IdentityServiceImpl.audit(() -> extension.get().updateConfiguration(identityName, config),\n                        \"Update configuration for extension \" + pid + \" for identity \" + identityName);\n            } catch (final KuraException e) {\n                failureHandler.addError(e.getMessage());\n            }\n        }\n\n        failureHandler.throwIfFailuresOccurred(KuraErrorCode.CONFIGURATION_ERROR);\n    }\n\n    private void setProperty(final Dictionary<String, Object> properties, final String key, final Object value) {\n        if (!Objects.equals(properties.get(key), value)) {\n            properties.put(key, value);\n        }\n    }\n\n    private void removeProperty(final Dictionary<String, Object> properties, final String key) {\n        if (properties.get(key) != null) {\n            properties.remove(key);\n        }\n    }\n\n    private static final class FailureHandler {\n\n        private final Set<String> errors = new HashSet<>();\n        private final Logger logger;\n\n        private FailureHandler(final Logger logger) {\n            this.logger = logger;\n        }\n\n        private void addError(final String message) {\n            this.errors.add(message);\n            this.logger.error(message);\n        }\n\n        private void throwIfFailuresOccurred(final KuraErrorCode errorCode) throws KuraException {\n            if (!this.errors.isEmpty()) {\n                throw new KuraException(errorCode, this.errors.stream().collect(Collectors.joining(\"; \")));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/.gitignore",
    "content": "/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.inventory\nBundle-SymbolicName: org.eclipse.kura.core.inventory;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.apache.commons.io;version=\"1.4.9999\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,1.1)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.container.orchestration;version=\"[1.0,2.0)\",\n org.eclipse.kura.marshalling;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.5,2.0)\",\n org.eclipse.kura.util.service;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.deploymentadmin;version=\"1.0.0\",\n org.slf4j;version=\"1.6.4\"\nExport-Package: org.eclipse.kura.core.inventory;version=\"1.1.0\";x-internal:=true,\n org.eclipse.kura.core.inventory.resources;version=\"1.0.0\";x-internal:=true\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/OSGI-INF/inventory.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2021 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n    Red Hat Inc\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"optional\" deactivate=\"deactivate\" immediate=\"true\" name=\"org.eclipse.kura.core.inventory.InventoryHandlerV1\">\n   <implementation class=\"org.eclipse.kura.core.inventory.InventoryHandlerV1\"/>\n   <reference name=\"RequestHandlerRegistry\"\n              policy=\"dynamic\"\n              cardinality=\"0..n\" \n              bind=\"setRequestHandlerRegistry\"\n              unbind=\"unsetRequestHandlerRegistry\"\n              interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\"/>\n   <reference bind=\"setSystemService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.system.SystemService\" name=\"SystemService\" policy=\"static\" unbind=\"unsetSystemService\"/>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.core.inventory.InventoryHandlerV1\"/>\n   <reference bind=\"setDeploymentAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.deploymentadmin.DeploymentAdmin\" name=\"DeploymentAdmin\" policy=\"static\" unbind=\"unsetDeploymentAdmin\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.core.inventory.InventoryHandlerV1\"/>\n   </service>\n   <reference cardinality=\"0..1\" interface=\"org.eclipse.kura.container.orchestration.ContainerOrchestrationService\" name=\"ContainerOrchestrationService\" policy=\"dynamic\" bind=\"setContainerOrchestrationService\" unbind=\"unsetContainerOrchestrationService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/build.properties",
    "content": "#\n#  Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.eclipse.osgi\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n     Red Hat Inc\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.inventory</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.core.inventory.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\t\n\t<build>\n\t\t<plugins>\n        \t<plugin>\n        \t\t<groupId>org.apache.maven.plugins</groupId>\n        \t\t<artifactId>maven-checkstyle-plugin</artifactId>\n        \t\t<configuration>\n        \t\t\t<skip>true</skip>\n        \t\t</configuration>\n        \t</plugin>\n        </plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/InventoryHandlerV1.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory;\n\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraProcessExecutionErrorException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerContext;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ContainerOrchestrationService;\nimport org.eclipse.kura.container.orchestration.ImageInstanceDescriptor;\nimport org.eclipse.kura.core.inventory.resources.ContainerImage;\nimport org.eclipse.kura.core.inventory.resources.ContainerImages;\nimport org.eclipse.kura.core.inventory.resources.DockerContainer;\nimport org.eclipse.kura.core.inventory.resources.DockerContainers;\nimport org.eclipse.kura.core.inventory.resources.SystemBundle;\nimport org.eclipse.kura.core.inventory.resources.SystemBundleRef;\nimport org.eclipse.kura.core.inventory.resources.SystemBundles;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemResourcesInfo;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\nimport org.eclipse.kura.system.SystemService;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.deploymentadmin.BundleInfo;\nimport org.osgi.service.deploymentadmin.DeploymentAdmin;\nimport org.osgi.service.deploymentadmin.DeploymentPackage;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class InventoryHandlerV1 implements ConfigurableComponent, RequestHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(InventoryHandlerV1.class);\n    public static final String APP_ID = \"INVENTORY-V1\";\n\n    public static final String RESOURCE_DEPLOYMENT_PACKAGES = \"deploymentPackages\";\n    public static final String RESOURCE_BUNDLES = \"bundles\";\n    public static final String RESOURCE_SYSTEM_PACKAGES = \"systemPackages\";\n    public static final String RESOURCE_DOCKER_CONTAINERS = \"containers\";\n    public static final String RESOURCE_CONTAINER_IMAGES = \"images\";\n    public static final String INVENTORY = \"inventory\";\n\n    private static final String START = \"_start\";\n    private static final String STOP = \"_stop\";\n    private static final String DELETE = \"_delete\";\n\n    public static final List<String> START_BUNDLE = Arrays.asList(RESOURCE_BUNDLES, START);\n    public static final List<String> STOP_BUNDLE = Arrays.asList(RESOURCE_BUNDLES, STOP);\n\n    public static final List<String> START_CONTAINER = Arrays.asList(RESOURCE_DOCKER_CONTAINERS, START);\n    public static final List<String> STOP_CONTAINER = Arrays.asList(RESOURCE_DOCKER_CONTAINERS, STOP);\n\n    public static final List<String> DELETE_IMAGE = Arrays.asList(RESOURCE_CONTAINER_IMAGES, DELETE);\n\n    private static final String CANNOT_FIND_RESOURCE_MESSAGE = \"Cannot find resource with name: {}\";\n    private static final String NONE_RESOURCE_FOUND_MESSAGE = \"Expected one resource but found none\";\n    private static final String BAD_REQUEST_TOPIC_MESSAGE = \"Bad request topic: {}\";\n    private static final String ERROR_GETTING_RESOURCE = \"Error getting resource {}\";\n    private static final String MISSING_MESSAGE_BODY = \"missing message body\";\n\n    private DeploymentAdmin deploymentAdmin;\n    private SystemService systemService;\n    private BundleContext bundleContext;\n\n    private ContainerOrchestrationService containerOrchestrationService;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setContainerOrchestrationService(ContainerOrchestrationService containerOrchestrationService) {\n        this.containerOrchestrationService = containerOrchestrationService;\n    }\n\n    public void unsetContainerOrchestrationService(ContainerOrchestrationService containerOrchestrationService) {\n        if (this.containerOrchestrationService == containerOrchestrationService) {\n            this.containerOrchestrationService = null;\n        }\n    }\n\n    protected void setDeploymentAdmin(DeploymentAdmin deploymentAdmin) {\n        this.deploymentAdmin = deploymentAdmin;\n    }\n\n    protected void unsetDeploymentAdmin(DeploymentAdmin deploymentAdmin) {\n        if (this.deploymentAdmin == deploymentAdmin) {\n            this.deploymentAdmin = null;\n        }\n    }\n\n    public void setSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    public void unsetSystemService(SystemService systemService) {\n        if (this.systemService == systemService) {\n            this.systemService = null;\n        }\n    }\n\n    public void setRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) {\n        try {\n            requestHandlerRegistry.registerRequestHandler(APP_ID, this);\n        } catch (KuraException e) {\n            logger.info(\"Unable to register cloudlet {} in {}\", APP_ID, requestHandlerRegistry.getClass().getName());\n        }\n    }\n\n    public void unsetRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) {\n        try {\n            requestHandlerRegistry.unregister(APP_ID);\n        } catch (KuraException e) {\n            logger.info(\"Unable to register cloudlet {} in {}\", APP_ID, requestHandlerRegistry.getClass().getName());\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) {\n        logger.info(\"Inventory v1 is starting\");\n        this.bundleContext = componentContext.getBundleContext();\n    }\n\n    protected void deactivate() {\n        logger.info(\"Bundle {} is deactivating!\", APP_ID);\n        this.bundleContext = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Public methods\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public KuraMessage doGet(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException {\n\n        List<String> resources = extractResources(reqMessage);\n\n        KuraPayload resPayload;\n        if (resources.get(0).equals(INVENTORY)) {\n            resPayload = doGetInventory();\n        } else if (resources.get(0).equals(RESOURCE_DEPLOYMENT_PACKAGES)) {\n            resPayload = doGetPackages();\n        } else if (resources.get(0).equals(RESOURCE_BUNDLES)) {\n            resPayload = doGetBundles();\n        } else if (resources.get(0).equals(RESOURCE_SYSTEM_PACKAGES)) {\n            resPayload = doGetSystemPackages();\n        } else if (resources.get(0).equals(RESOURCE_DOCKER_CONTAINERS)) {\n            resPayload = doGetDockerContainers();\n        } else if (resources.get(0).equals(RESOURCE_CONTAINER_IMAGES)) {\n            resPayload = doGetContainerImages();\n        } else {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(CANNOT_FIND_RESOURCE_MESSAGE, resources.get(0));\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n\n        return new KuraMessage(resPayload);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private List<String> extractResources(KuraMessage reqMessage) throws KuraException {\n        Object requestObject = reqMessage.getProperties().get(ARGS_KEY.value());\n        List<String> resources;\n        if (requestObject instanceof List) {\n            resources = (List<String>) requestObject;\n        } else {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        if (resources.isEmpty()) {\n            logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources);\n            logger.error(NONE_RESOURCE_FOUND_MESSAGE);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n        return resources;\n    }\n\n    @Override\n    public KuraMessage doExec(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException {\n\n        final List<String> resources = extractResources(reqMessage);\n\n        try {\n            if (START_BUNDLE.equals(resources)) {\n                findFirstMatchingBundle(extractBundleRef(reqMessage)).start();\n                return success();\n            } else if (STOP_BUNDLE.equals(resources)) {\n                findFirstMatchingBundle(extractBundleRef(reqMessage)).stop();\n                return success();\n            } else if (START_CONTAINER.equals(resources)) {\n\n                if (this.containerOrchestrationService == null) {\n                    return notFound();\n                }\n\n                this.containerOrchestrationService\n                        .startContainer(findFirstMatchingContainer(extractContainerRef(reqMessage)).getContainerId());\n\n                return success();\n            } else if (STOP_CONTAINER.equals(resources)) {\n\n                if (this.containerOrchestrationService == null) {\n                    return notFound();\n                }\n\n                this.containerOrchestrationService\n                        .stopContainer(findFirstMatchingContainer(extractContainerRef(reqMessage)).getContainerId());\n                return success();\n            } else if (DELETE_IMAGE.equals(resources)) {\n\n                if (this.containerOrchestrationService == null) {\n                    return notFound();\n                }\n\n                this.containerOrchestrationService\n                        .deleteImage(findFirstMatchingImage(extractContainerImageRef(reqMessage)).getImageId());\n                return success();\n            }\n        } catch (final KuraException e) {\n            throw e;\n        } catch (final Exception e) {\n            logger.debug(\"unexpected exception dispatcing call\", e);\n            // this should result in response code 500\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE);\n        }\n\n        throw new KuraException(KuraErrorCode.NOT_FOUND);\n    }\n\n    @Override\n    public KuraMessage doDel(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException {\n\n        throw new KuraException(KuraErrorCode.NOT_FOUND);\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private methods\n    //\n    // ----------------------------------------------------------------\n\n    private KuraPayload doGetPackages() {\n        DeploymentPackage[] dps = this.deploymentAdmin.listDeploymentPackages();\n        SystemDeploymentPackages xdps = new SystemDeploymentPackages();\n        SystemDeploymentPackage[] axdp = new SystemDeploymentPackage[dps.length];\n\n        for (int i = 0; i < dps.length; i++) {\n            DeploymentPackage dp = dps[i];\n\n            BundleInfo[] bis = dp.getBundleInfos();\n            SystemBundle[] axbi = new SystemBundle[bis.length];\n\n            boolean dpSigned = true;\n\n            for (int j = 0; j < bis.length; j++) {\n\n                BundleInfo bi = bis[j];\n                SystemBundle xb = new SystemBundle(bi.getSymbolicName(), bi.getVersion().toString());\n\n                Bundle[] bundles = this.bundleContext.getBundles();\n                Optional<Bundle> bundle = Arrays.asList(bundles).stream()\n                        .filter(b -> b.getSymbolicName().equals(bi.getSymbolicName())).findFirst();\n                if (bundle.isPresent()) {\n                    boolean bundleSigned = true;\n                    if (bundle.get().getSignerCertificates(Bundle.SIGNERS_ALL).isEmpty()) {\n                        bundleSigned = false;\n                        dpSigned = false;\n                    }\n                    xb.setId(bundle.get().getBundleId());\n                    xb.setState(bundleStateToString(bundle.get().getState()));\n                    xb.setSigned(bundleSigned);\n                }\n\n                axbi[j] = xb;\n            }\n\n            SystemDeploymentPackage xdp = new SystemDeploymentPackage(dp.getName(), dp.getVersion().toString());\n\n            xdp.setBundleInfos(axbi);\n            xdp.setSigned(dpSigned);\n\n            axdp[i] = xdp;\n        }\n\n        xdps.setDeploymentPackages(axdp);\n\n        KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        try {\n            String s = marshal(xdps);\n            respPayload.setTimestamp(new Date());\n            respPayload.setBody(s.getBytes(StandardCharsets.UTF_8));\n        } catch (Exception e) {\n            logger.error(\"Error getting resource {}: {}\", RESOURCE_DEPLOYMENT_PACKAGES, e);\n        }\n        return respPayload;\n    }\n\n    private KuraPayload doGetBundles() {\n        Bundle[] bundles = this.bundleContext.getBundles();\n        SystemBundles systemBundles = new SystemBundles();\n        SystemBundle[] axb = new SystemBundle[bundles.length];\n\n        for (int i = 0; i < bundles.length; i++) {\n\n            Bundle bundle = bundles[i];\n            SystemBundle systemBundle = new SystemBundle(bundle.getSymbolicName(), bundle.getVersion().toString());\n\n            systemBundle.setId(bundle.getBundleId());\n\n            int state = bundle.getState();\n            systemBundle.setState(bundleStateToString(state));\n\n            systemBundle.setSigned(isSigned(bundle));\n\n            axb[i] = systemBundle;\n        }\n\n        systemBundles.setBundles(axb);\n\n        KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        try {\n            String s = marshal(systemBundles);\n            respPayload.setTimestamp(new Date());\n            respPayload.setBody(s.getBytes(StandardCharsets.UTF_8));\n        } catch (Exception e) {\n            logger.error(ERROR_GETTING_RESOURCE, RESOURCE_BUNDLES, e);\n        }\n        return respPayload;\n    }\n\n    private KuraPayload doGetInventory() {\n        List<SystemResourceInfo> inventory = new ArrayList<>();\n        // get System Packages\n        try {\n            inventory.addAll(this.systemService.getSystemPackages());\n        } catch (KuraProcessExecutionErrorException e) {\n            logger.error(ERROR_GETTING_RESOURCE, RESOURCE_SYSTEM_PACKAGES, e);\n        }\n\n        // get Bundles\n        Bundle[] bundles = this.bundleContext.getBundles();\n        Arrays.asList(bundles).stream().forEach(b -> inventory.add(\n                new SystemResourceInfo(b.getSymbolicName(), b.getVersion().toString(), SystemResourceType.BUNDLE)));\n\n        // get Deployment Packages\n        DeploymentPackage[] dps = this.deploymentAdmin.listDeploymentPackages();\n        Arrays.asList(dps).stream().forEach(dp -> inventory\n                .add(new SystemResourceInfo(dp.getName(), dp.getVersion().toString(), SystemResourceType.DP)));\n\n        // get Docker Containers\n        if (this.containerOrchestrationService != null) {\n            try {\n                logger.info(\"Creating docker inventory\");\n                List<ContainerInstanceDescriptor> containers = this.containerOrchestrationService\n                        .listContainerDescriptors();\n                containers.stream().forEach(\n                        container -> inventory.add(new SystemResourceInfo(container.getContainerName().replace(\"/\", \"\"),\n                                container.getContainerImage() + \":\" + container.getContainerImageTag().split(\":\")[0],\n                                SystemResourceType.DOCKER)));\n            } catch (Exception e) {\n                logger.error(\"Could not connect to docker\");\n            }\n\n        }\n\n        // get Container Images\n        if (this.containerOrchestrationService != null) {\n            try {\n                logger.info(\"Creating container images inventory\");\n                List<ImageInstanceDescriptor> images = this.containerOrchestrationService\n                        .listImageInstanceDescriptors();\n                images.stream().forEach(image -> inventory.add(new SystemResourceInfo(image.getImageName(),\n                        image.getImageTag(), SystemResourceType.CONTAINER_IMAGE)));\n            } catch (Exception e) {\n                logger.error(\"Could not connect to container-engine\");\n            }\n\n        }\n\n        inventory.sort(Comparator.comparing(SystemResourceInfo::getName));\n        SystemResourcesInfo systemResourcesInfo = new SystemResourcesInfo(inventory);\n\n        KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        try {\n            String s = marshal(systemResourcesInfo);\n            respPayload.setTimestamp(new Date());\n            respPayload.setBody(s.getBytes(StandardCharsets.UTF_8));\n        } catch (Exception e1) {\n            logger.error(\"Error getting inventory\", e1);\n            respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR);\n        }\n        return respPayload;\n    }\n\n    private KuraPayload doGetSystemPackages() {\n        List<SystemResourceInfo> systemResourceList;\n        KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        try {\n            systemResourceList = this.systemService.getSystemPackages();\n\n            List<SystemPackage> systemPackageList = new ArrayList<>();\n\n            systemResourceList.stream()\n                    .forEach(p -> systemPackageList.add(new SystemPackage(p.getName(), p.getVersion(), p.getType())));\n            SystemPackages systemPackages = new SystemPackages(systemPackageList);\n\n            String s = marshal(systemPackages);\n            respPayload.setTimestamp(new Date());\n            respPayload.setBody(s.getBytes(StandardCharsets.UTF_8));\n        } catch (Exception e) {\n            logger.error(ERROR_GETTING_RESOURCE, RESOURCE_SYSTEM_PACKAGES, e);\n            respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR);\n        }\n\n        return respPayload;\n    }\n\n    private KuraPayload doGetDockerContainers() {\n\n        if (this.containerOrchestrationService == null) {\n            return new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_NOTFOUND);\n        }\n\n        KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        try {\n            List<ContainerInstanceDescriptor> containers = this.containerOrchestrationService\n                    .listContainerDescriptors();\n\n            List<DockerContainer> containersList = new ArrayList<>();\n            containers.stream().forEach(p -> containersList.add(new DockerContainer(p)));\n\n            DockerContainers dockerContainers = new DockerContainers(containersList);\n            String s = marshal(dockerContainers);\n            respPayload.setTimestamp(new Date());\n            respPayload.setBody(s.getBytes(StandardCharsets.UTF_8));\n        } catch (Exception e) {\n            logger.error(ERROR_GETTING_RESOURCE, RESOURCE_SYSTEM_PACKAGES, e);\n            respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR);\n        }\n\n        return respPayload;\n    }\n\n    private KuraPayload doGetContainerImages() {\n\n        if (this.containerOrchestrationService == null) {\n            return new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_NOTFOUND);\n        }\n\n        KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        try {\n            List<ImageInstanceDescriptor> containers = this.containerOrchestrationService\n                    .listImageInstanceDescriptors();\n\n            List<ContainerImage> imageList = new ArrayList<>();\n            containers.stream().forEach(p -> imageList.add(new ContainerImage(p)));\n\n            ContainerImages containerImages = new ContainerImages(imageList);\n            String s = marshal(containerImages);\n            respPayload.setTimestamp(new Date());\n            respPayload.setBody(s.getBytes(StandardCharsets.UTF_8));\n        } catch (Exception e) {\n            logger.error(ERROR_GETTING_RESOURCE, RESOURCE_SYSTEM_PACKAGES, e);\n            respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR);\n        }\n\n        return respPayload;\n    }\n\n    private <T> ServiceReference<T>[] getJsonMarshallers(final Class<T> classz) {\n        String filterString = String.format(\"(kura.service.pid=%s)\",\n                \"org.eclipse.kura.json.marshaller.unmarshaller.provider\");\n        return ServiceUtil.getServiceReferences(this.bundleContext, classz, filterString);\n    }\n\n    private void ungetServiceReferences(final ServiceReference<?>[] refs) {\n        ServiceUtil.ungetServiceReferences(this.bundleContext, refs);\n    }\n\n    protected String marshal(Object object) {\n        String result = null;\n        ServiceReference<Marshaller>[] marshallerSRs = getJsonMarshallers(Marshaller.class);\n        try {\n            for (final ServiceReference<Marshaller> marshallerSR : marshallerSRs) {\n                Marshaller marshaller = this.bundleContext.getService(marshallerSR);\n                result = marshaller.marshal(object);\n                if (result != null) {\n                    break;\n                }\n            }\n        } catch (Exception e) {\n            logger.warn(\"Failed to marshal configuration.\");\n        } finally {\n            ungetServiceReferences(marshallerSRs);\n        }\n        return result;\n    }\n\n    public <T> T unmarshal(final String str, final Class<T> classz) throws KuraException {\n        T result = null;\n        ServiceReference<Unmarshaller>[] unmarshallerSRs = getJsonMarshallers(Unmarshaller.class);\n        try {\n            for (final ServiceReference<Unmarshaller> unmarshallerSR : unmarshallerSRs) {\n                Unmarshaller unmarshaller = this.bundleContext.getService(unmarshallerSR);\n                result = unmarshaller.unmarshal(str, classz);\n                if (result != null) {\n                    return result;\n                }\n            }\n        } catch (Exception e) {\n            logger.warn(\"Failed to unmarshal request.\");\n        } finally {\n            ungetServiceReferences(unmarshallerSRs);\n        }\n\n        throw new KuraException(KuraErrorCode.BAD_REQUEST);\n    }\n\n    private String bundleStateToString(int state) {\n        String stateString;\n\n        switch (state) {\n        case Bundle.UNINSTALLED:\n            stateString = \"UNINSTALLED\";\n            break;\n\n        case Bundle.INSTALLED:\n            stateString = \"INSTALLED\";\n            break;\n\n        case Bundle.RESOLVED:\n            stateString = \"RESOLVED\";\n            break;\n\n        case Bundle.STARTING:\n            stateString = \"STARTING\";\n            break;\n\n        case Bundle.STOPPING:\n            stateString = \"STOPPING\";\n            break;\n\n        case Bundle.ACTIVE:\n            stateString = \"ACTIVE\";\n            break;\n\n        default:\n            stateString = String.valueOf(state);\n        }\n\n        return stateString;\n    }\n\n    private boolean isSigned(Bundle bundle) {\n        return !bundle.getSignerCertificates(Bundle.SIGNERS_ALL).isEmpty();\n    }\n\n    private SystemBundleRef extractBundleRef(final KuraMessage message) throws KuraException {\n        final KuraPayload payload = message.getPayload();\n\n        final byte[] body = payload.getBody();\n\n        if (body == null) {\n            logger.warn(MISSING_MESSAGE_BODY);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        return unmarshal(new String(message.getPayload().getBody(), StandardCharsets.UTF_8), SystemBundleRef.class);\n    }\n\n    private ContainerInstanceDescriptor extractContainerRef(final KuraMessage message) throws KuraException {\n        final KuraPayload payload = message.getPayload();\n\n        final byte[] body = payload.getBody();\n\n        if (body == null) {\n            logger.warn(MISSING_MESSAGE_BODY);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        DockerContainer dc = unmarshal(new String(message.getPayload().getBody(), StandardCharsets.UTF_8),\n                DockerContainer.class);\n\n        try {\n            List<ContainerInstanceDescriptor> containerList = this.containerOrchestrationService\n                    .listContainerDescriptors();\n\n            for (ContainerInstanceDescriptor container : containerList) {\n                if (container.getContainerName().equals(dc.getContainerName())) {\n                    return container;\n                }\n            }\n            logger.warn(\"Failed to find container\");\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        } catch (Exception e) {\n            logger.warn(\"failed to access docker service\");\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n    }\n\n    private ImageInstanceDescriptor extractContainerImageRef(final KuraMessage message) throws KuraException {\n        final KuraPayload payload = message.getPayload();\n\n        final byte[] body = payload.getBody();\n\n        if (body == null) {\n            logger.warn(MISSING_MESSAGE_BODY);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        ContainerImage dc = unmarshal(new String(message.getPayload().getBody(), StandardCharsets.UTF_8),\n                ContainerImage.class);\n\n        try {\n            List<ImageInstanceDescriptor> imageList = this.containerOrchestrationService.listImageInstanceDescriptors();\n\n            for (ImageInstanceDescriptor image : imageList) {\n                if (image.getImageName().equals(dc.getImageName()) && image.getImageTag().equals(dc.getImageTag())) {\n                    return image;\n                }\n            }\n            logger.warn(\"Failed to find image\");\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        } catch (Exception e) {\n            logger.warn(\"failed to access docker service\");\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n    }\n\n    private Bundle findFirstMatchingBundle(final SystemBundleRef ref) throws KuraException {\n        for (final Bundle bundle : this.bundleContext.getBundles()) {\n            if (!bundle.getSymbolicName().equals(ref.getName())) {\n                continue;\n            }\n\n            final Optional<String> version = ref.getVersion();\n\n            if (!version.isPresent() || version.get().equals(bundle.getVersion().toString())) {\n                return bundle;\n            }\n        }\n\n        throw new KuraException(KuraErrorCode.NOT_FOUND);\n    }\n\n    private ContainerInstanceDescriptor findFirstMatchingContainer(final ContainerInstanceDescriptor ref)\n            throws KuraException {\n        for (final ContainerInstanceDescriptor container : this.containerOrchestrationService\n                .listContainerDescriptors()) {\n            if (container.getContainerName().equals(ref.getContainerName())) {\n                return container;\n            }\n        }\n\n        throw new KuraException(KuraErrorCode.NOT_FOUND);\n    }\n\n    private ImageInstanceDescriptor findFirstMatchingImage(final ImageInstanceDescriptor ref) throws KuraException {\n        for (final ImageInstanceDescriptor image : this.containerOrchestrationService.listImageInstanceDescriptors()) {\n            if (image.getImageName().equals(ref.getImageName()) && image.getImageTag().equals(ref.getImageTag())) {\n                return image;\n            }\n        }\n\n        throw new KuraException(KuraErrorCode.NOT_FOUND);\n    }\n\n    private static KuraMessage success() {\n        final KuraPayload response = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        response.setTimestamp(new Date());\n        return new KuraMessage(response);\n    }\n\n    private static KuraMessage notFound() {\n        final KuraPayload response = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_NOTFOUND);\n        response.setTimestamp(new Date());\n        return new KuraMessage(response);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/ContainerImage.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https:www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.core.inventory.resources;\n\nimport org.eclipse.kura.container.orchestration.ImageInstanceDescriptor;\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\n\npublic class ContainerImage extends SystemResourceInfo {\n\n    private String imageName = \"\";\n    private String imageTag = \"\";\n    private String imageId = \"\";\n    private String imageAuthor = \"\";\n    private String imageArch = \"\";\n    private long imageSize = 0;\n\n    public ContainerImage(String name, String version) {\n        super(name, version, SystemResourceType.CONTAINER_IMAGE);\n        this.imageName = name;\n        this.imageTag = version;\n    }\n\n    public ContainerImage(ImageInstanceDescriptor image) {\n        super(image.getImageName(), image.getImageTag(), SystemResourceType.CONTAINER_IMAGE);\n\n        this.imageName = image.getImageName();\n        this.imageTag = image.getImageTag();\n        this.imageId = image.getImageId();\n        this.imageAuthor = image.getImageAuthor();\n        this.imageArch = image.getImageArch();\n        this.imageSize = image.getImageSize();\n    }\n\n    public String getImageName() {\n        return imageName;\n    }\n\n    public void setImageName(String imageName) {\n        this.imageName = imageName;\n    }\n\n    public String getImageTag() {\n        return imageTag;\n    }\n\n    public void setImageTag(String imageTag) {\n        this.imageTag = imageTag;\n    }\n\n    public String getImageId() {\n        return imageId;\n    }\n\n    public void setImageId(String imageId) {\n        this.imageId = imageId;\n    }\n\n    public String getImageAuthor() {\n        return imageAuthor;\n    }\n\n    public void setImageAuthor(String imageAuthor) {\n        this.imageAuthor = imageAuthor;\n    }\n\n    public String getImageArch() {\n        return imageArch;\n    }\n\n    public void setImageArch(String imageArch) {\n        this.imageArch = imageArch;\n    }\n\n    public long getImageSize() {\n        return imageSize;\n    }\n\n    public void setImageSize(long imageSize) {\n        this.imageSize = imageSize;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/ContainerImages.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\nimport java.util.List;\n\npublic class ContainerImages {\n\n    private List<ContainerImage> images;\n\n    public ContainerImages(List<ContainerImage> images) {\n        this.images = images;\n    }\n\n    public List<ContainerImage> getContainerImages() {\n        return this.images;\n    }\n\n    public void setContainerImages(List<ContainerImage> images) {\n        this.images = images;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/DockerContainer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https:www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.core.inventory.resources;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ContainerPort;\nimport org.eclipse.kura.container.orchestration.ContainerState;\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\n\npublic class DockerContainer extends SystemResourceInfo {\n\n    private String containerName;\n    private String containerImage;\n    private String containerImageTag;\n    private String containerID;\n    private List<Integer> containerPortsExternal;\n    private List<Integer> containerPortsInternal;\n    private ContainerState containerState;\n\n    private Boolean isFrameworkManaged;\n\n    public DockerContainer(String name, String version) {\n        super(name, version, SystemResourceType.DOCKER);\n        this.containerName = name;\n    }\n\n    public DockerContainer(ContainerInstanceDescriptor container) {\n        super(container.getContainerName(), container.getContainerImage() + \":\" + container.getContainerImageTag(),\n                SystemResourceType.DOCKER);\n\n        this.containerName = container.getContainerName();\n        this.containerImage = container.getContainerImage();\n        this.containerImageTag = container.getContainerImageTag();\n\n        this.containerID = container.getContainerId();\n        this.containerPortsExternal = container.getContainerPorts().stream().map(ContainerPort::getExternalPort)\n                .collect(Collectors.toList());\n\n        this.containerPortsInternal = container.getContainerPorts().stream().map(ContainerPort::getInternalPort)\n                .collect(Collectors.toList());\n        this.containerState = container.getContainerState();\n        this.isFrameworkManaged = container.isFrameworkManaged();\n\n    }\n\n    public String getContainerName() {\n        return this.containerName;\n    }\n\n    public void setContainerName(String containerName) {\n        this.containerName = containerName;\n    }\n\n    public String getContainerImage() {\n        return this.containerImage;\n    }\n\n    public void setContainerImage(String containerImage) {\n        this.containerImage = containerImage;\n    }\n\n    public String getContainerImageTag() {\n        return this.containerImageTag;\n    }\n\n    public void setContainerImageTag(String containerImageTag) {\n        this.containerImageTag = containerImageTag;\n    }\n\n    public String getContainerId() {\n        return this.containerID;\n    }\n\n    public void setContainerId(String id) {\n        this.containerID = id;\n    }\n\n    public List<Integer> getContainerPortsExternal() {\n        return this.containerPortsExternal;\n    }\n\n    public List<Integer> getContainerPortsInternal() {\n        return this.containerPortsInternal;\n    }\n\n    public ContainerState getContainerState() {\n        return this.containerState;\n    }\n\n    public String getFrameworkContainerState() {\n\n        switch (containerState) {\n            case STARTING:\n                return \"installed\";\n            case ACTIVE:\n                return \"active\";\n            case FAILED:\n            case STOPPING:\n                return \"uninstalled\";\n            default:\n                return \"unknown\";\n        }\n    }\n\n    public void setContainerState(ContainerState containerState) {\n        this.containerState = containerState;\n    }\n\n    public Boolean isFrameworkManaged() {\n        return this.isFrameworkManaged;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/DockerContainers.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\nimport java.util.List;\n\npublic class DockerContainers {\n\n    private List<DockerContainer> containers;\n\n    public DockerContainers(List<DockerContainer> containers) {\n        this.containers = containers;\n    }\n\n    public List<DockerContainer> getDockerContainers() {\n        return this.containers;\n    }\n\n    public void setDockerContainers(List<DockerContainer> containers) {\n        this.containers = containers;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemBundle.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\n\npublic class SystemBundle extends SystemResourceInfo {\n\n    private long id;\n    private String state;\n    private boolean signed;\n\n    public SystemBundle(String name, String version) {\n        super(name, version, SystemResourceType.BUNDLE);\n    }\n\n    public long getId() {\n        return this.id;\n    }\n\n    public void setId(long id) {\n        this.id = id;\n    }\n\n    public String getState() {\n        return this.state;\n    }\n\n    public void setState(String state) {\n        this.state = state;\n    }\n    \n    public void setSigned(boolean signed) {\n        this.signed = signed;\n    }\n\n    public boolean isSigned() {\n        return signed;\n    }\n    \n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemBundleRef.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\nimport java.util.Optional;\n\npublic class SystemBundleRef {\n\n    private final String name;\n    private final Optional<String> version;\n\n    public SystemBundleRef(String name, Optional<String> version) {\n        this.name = name;\n        this.version = version;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public Optional<String> getVersion() {\n        return version;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemBundles.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\npublic class SystemBundles {\n\n    private SystemBundle[] bundles;\n\n    public SystemBundle[] getBundles() {\n        return this.bundles;\n    }\n\n    public void setBundles(SystemBundle[] bundles) {\n        this.bundles = bundles;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemDeploymentPackage.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\n\npublic class SystemDeploymentPackage extends SystemResourceInfo {\n\n    private SystemBundle[] bundleInfos;\n    private boolean signed;\n\n    public SystemDeploymentPackage(String name, String version) {\n        super(name, version, SystemResourceType.DP);\n    }\n\n    public SystemBundle[] getBundleInfos() {\n        return this.bundleInfos;\n    }\n\n    public void setBundleInfos(SystemBundle[] bundleInfos) {\n        this.bundleInfos = bundleInfos;\n    }\n    \n    public void setSigned(boolean signed) {\n        this.signed = signed;\n    }\n\n    public boolean isSigned() {\n        return signed;\n    }\n    \n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemDeploymentPackages.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\npublic class SystemDeploymentPackages {\n\n    private SystemDeploymentPackage[] deploymentPackages;\n\n    public SystemDeploymentPackage[] getDeploymentPackages() {\n        return this.deploymentPackages;\n    }\n\n    public void setDeploymentPackages(SystemDeploymentPackage[] deploymentPackages) {\n        this.deploymentPackages = deploymentPackages;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemPackage.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\n\npublic class SystemPackage extends SystemResourceInfo {\n\n    public SystemPackage(String name) {\n        super(name);\n    }\n\n    public SystemPackage(String name, String version, SystemResourceType type) {\n        super(name, version, type);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemPackages.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\nimport java.util.List;\n\npublic class SystemPackages {\n\n    private List<SystemPackage> packages;\n\n    public SystemPackages(List<SystemPackage> packages) {\n        this.packages = packages;\n    }\n\n    public List<SystemPackage> getSystemPackages() {\n        return this.packages;\n    }\n\n    public void setSystemPackages(List<SystemPackage> packages) {\n        this.packages = packages;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemResourcesInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.inventory.resources;\n\nimport java.util.List;\n\nimport org.eclipse.kura.system.SystemResourceInfo;\n\npublic class SystemResourcesInfo {\n\n    private List<SystemResourceInfo> resources;\n\n    public SystemResourcesInfo(List<SystemResourceInfo> resources) {\n        this.resources = resources;\n    }\n\n    public List<SystemResourceInfo> getSystemResources() {\n        return this.resources;\n    }\n\n    public void setSysteResourcesInfo(List<SystemResourceInfo> resources) {\n        this.resources = resources;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.keystore\nBundle-SymbolicName: org.eclipse.kura.core.keystore;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: com.eclipsesource.json;version=\"0.9.5\",\n org.bouncycastle.asn1;version=\"1.78.1\",\n org.bouncycastle.asn1.cms;version=\"1.78.1\",\n org.bouncycastle.asn1.pkcs;version=\"1.78.1\",\n org.bouncycastle.asn1.x500;version=\"1.78.1\",\n org.bouncycastle.asn1.x509;version=\"1.78.1\",\n org.bouncycastle.cert;version=\"1.78.1\",\n org.bouncycastle.cert.jcajce;version=\"1.78.1\",\n org.bouncycastle.cms;version=\"1.78.1\",\n org.bouncycastle.jcajce.provider.asymmetric.dsa;version=\"1.78.1\",\n org.bouncycastle.jcajce.provider.asymmetric.ec;version=\"1.78.1\",\n org.bouncycastle.jcajce.provider.asymmetric.rsa;version=\"1.78.1\",\n org.bouncycastle.jce.provider;version=\"1.78.1\",\n org.bouncycastle.openssl;version=\"1.78.1\",\n org.bouncycastle.openssl.bc;version=\"1.78.1\",\n org.bouncycastle.openssl.jcajce;version=\"1.78.1\",\n org.bouncycastle.operator;version=\"1.78.1\",\n org.bouncycastle.operator.jcajce;version=\"1.78.1\",\n org.bouncycastle.pkcs;version=\"1.78.1\",\n org.bouncycastle.pkcs.jcajce;version=\"1.78.1\",\n org.bouncycastle.util;version=\"1.78.1\",\n org.bouncycastle.util.io.pem;version=\"1.78.1\",\n org.eclipse.kura;version=\"[1.6,2.0)\",\n org.eclipse.kura.certificate;version=\"[2.1,3.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.1,2.0)\",\n org.eclipse.kura.security.keystore;version=\"[1.2,1.3)\",\n org.eclipse.kura.system;version=\"[1.5,2.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.service;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.4.0\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.32\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nExport-Package: org.eclipse.kura.core.keystore.util;version=\"1.1.0\"\nEclipse-BuddyPolicy: ext\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/OSGI-INF/metatype/org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n\tSPDX-License-Identifier: EPL-2.0\n\n\tContributors:\n     Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\"\n         name=\"FilesystemKeystoreServiceImpl\"\n         description=\"The service allows to reference a Java Keystore in the filesystem. The default password provided can be randomized by the framework to get a per instance specific password.\">\n\n        <AD id=\"keystore.path\"\n            name=\"Keystore Path\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"/tmp/keystore.ks\"\n            description=\"Specifies the filesystem path to a Java Keystore. If not present the file will be created.\">\n        </AD>\n\n        <AD id=\"keystore.password\"\n            name=\"Keystore Password\"\n            type=\"Password\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"changeit\"\n            description=\"The password value associated to the keystore path specified.\">\n        </AD>\n\n        <AD id=\"randomize.password\"\n            name=\"Randomize Password\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"false\"\n            description=\"Specifies if the defined password will be randomized at the next keystore access. If this value is set to true and the keystore can be accessed, the password will be randomized and this field will automatically set to false.\">\n        </AD>\n\n        <AD id=\"crl.management.enabled\"\n            name=\"CRL Cache Enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"If enabled, the service will maintain a local CRL cache by periodically downloading and storing CRLs from HTTP distribution points. The distribution points specified in the trusted certificates added to keystore will be considered along with the HTTP URLs specified using the CRL URLs parameter.\">\n        </AD>\n        \n        <AD id=\"crl.urls\"\n            name=\"CRL URLs\"\n            type=\"String\"\n            cardinality=\"5\"\n            required=\"false\"\n            default=\"\"\n            description=\"Alllows to specify a list of HTTP CRL distribution points that will be considered along with the HTTP distribution points specified in the trusted certificates added to keystore.\">\n        </AD>\n\n        <AD id=\"crl.update.interval\"\n            name=\"CRL Force Update Interval\"\n            type=\"Long\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"1\"\n            description=\"Defines a time interval for forcing the update of cached CRLs, this interval will be considered in addition to CRL next update date.\">\n        </AD>\n\n        <AD id=\"crl.update.interval.time.unit\"\n            name=\"CRL Force Update Interval Time Unit\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"DAYS\"\n            description=\"The time unit for the CRL Update Interval parameter\">\n            <Option label=\"SECONDS\" value=\"SECONDS\" />\n            <Option label=\"MINUTES\" value=\"MINUTES\" />\n            <Option label=\"HOURS\" value=\"HOURS\" />\n            <Option label=\"DAYS\" value=\"DAYS\" />\n        </AD>\n\n        <AD id=\"crl.check.interval\"\n            name=\"CRL Check Interval\"\n            type=\"Long\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"5\"\n            description=\"Defines a time interval for the periodic check of stored CRLs. Durning the periodic check the stored CRLs will be processed and updated if needed.\">\n        </AD>\n\n        <AD id=\"crl.check.interval.time.unit\"\n            name=\"CRL Check Interval Time Unit\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"MINUTES\"\n            description=\"The time unit for the CRL Check Interval parameter\">\n            <Option label=\"SECONDS\" value=\"SECONDS\" />\n            <Option label=\"MINUTES\" value=\"MINUTES\" />\n            <Option label=\"HOURS\" value=\"HOURS\" />\n            <Option label=\"DAYS\" value=\"DAYS\" />\n        </AD>\n\n        <AD id=\"crl.store.path\"\n            name=\"CRL Store Path\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"\"\n            description=\"Defines the path of the CRL store file, as an absolute path. If left empty, a default store file path will be computed by adding a .crl suffix to the value of the Keystore Path parameter.\">\n        </AD>\n\n        <AD id=\"verify.crl\"\n            name=\"Enable CRL Verification\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"If set to true, the downloaded CRLs will be stored only if signed with the public key of one of trusted certificates in this keystore.\">\n        </AD>\n\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\" factoryPid=\"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\">\n        <Object ocdref=\"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/OSGI-INF/metatype/org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n\tSPDX-License-Identifier: EPL-2.0\n\n\tContributors:\n     Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl\"\n         name=\"FilesystemKeystoreServiceImpl\"\n         description=\"The service allows to expose a PKCS11 module as a KeystoreService. See the https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html document for more information about the configuration parameters.\">\n\n        <AD id=\"library.path\"\n            name=\"PKCS11 Implementation Library Path\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"/lib/libmypkcs11.so\"\n            description=\"The path to the PKCS11 implementation library shared object. e.g. /lib/libmypkcs11.so\">\n        </AD>\n\n        <AD id=\"pin\"\n            name=\"Pin\"\n            type=\"Password\"\n            cardinality=\"0\"\n            required=\"false\"\n            description=\"The PIN to be used for PKCS11 operations.\">\n        </AD>\n        \n        <AD id=\"slot\"\n            name=\"Slot\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            min=\"0\"\n            required=\"false\"\n            description=\"The slot parameter as an integer. This parameter is optional, at most one of the slot and slotListIndex properties can be specified.\">\n        </AD>\n\n        <AD id=\"slot.list.index\"\n            name=\"Slot List Index\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"false\"\n            description=\"The slotListIndex parameter as an integer. This parameter is optional, at most one of the slot and slotListIndex properties can be specified.\">\n        </AD>\n        \n        <AD id=\"enabled.mechanisms\"\n            name=\"Enabled Mechanisms\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            description=\"The enabledMechanisms parameter as a list of whitespace separated strings. The curly braces must be omitted.\">\n        </AD>\n        \n        <AD id=\"disabled.mechanisms\"\n            name=\"Disabled Mechanisms\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            description=\"The disabledMechanisms parameter as a list of whitespace separated strings. The curly braces must be omitted.\">\n        </AD>\n        \n        <AD id=\"attributes\"\n            name=\"Attributes\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            description=\"The attributes parameter. The value of this field will be appended to the provider configuration.|TextArea\">\n        </AD>\n        \n        <AD id=\"crl.store.path\"\n            name=\"CRL Store Path\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            description=\"The path where to store the cached CRLs. If left empty, the CRLs will be stored in a new file in the security subfolder of the Kura user configuration directory.\">\n        </AD>\n        \n        <AD id=\"crl.urls\"\n            name=\"CRL URLs\"\n            type=\"String\"\n            cardinality=\"5\"\n            required=\"false\"\n            default=\"\"\n            description=\"Alllows to specify a list of HTTP CRL distribution points that will be considered along with the HTTP distribution points specified in the trusted certificates added to keystore.\">\n        </AD>\n\n        <AD id=\"crl.update.interval\"\n            name=\"CRL Force Update Interval\"\n            type=\"Long\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"1\"\n            description=\"Defines a time interval for forcing the update of cached CRLs, this interval will be considered in addition to CRL next update date.\">\n        </AD>\n\n        <AD id=\"crl.update.interval.time.unit\"\n            name=\"CRL Force Update Interval Time Unit\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"DAYS\"\n            description=\"The time unit for the CRL Update Interval parameter\">\n            <Option label=\"SECONDS\" value=\"SECONDS\" />\n            <Option label=\"MINUTES\" value=\"MINUTES\" />\n            <Option label=\"HOURS\" value=\"HOURS\" />\n            <Option label=\"DAYS\" value=\"DAYS\" />\n        </AD>\n\n        <AD id=\"crl.check.interval\"\n            name=\"CRL Check Interval\"\n            type=\"Long\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"5\"\n            description=\"Defines a time interval for the periodic check of stored CRLs. Durning the periodic check the stored CRLs will be processed and updated if needed.\">\n        </AD>\n\n        <AD id=\"crl.check.interval.time.unit\"\n            name=\"CRL Check Interval Time Unit\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"MINUTES\"\n            description=\"The time unit for the CRL Check Interval parameter\">\n            <Option label=\"SECONDS\" value=\"SECONDS\" />\n            <Option label=\"MINUTES\" value=\"MINUTES\" />\n            <Option label=\"HOURS\" value=\"HOURS\" />\n            <Option label=\"DAYS\" value=\"DAYS\" />\n        </AD>\n\n        <AD id=\"crl.store.path\"\n            name=\"CRL Store Path\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"\"\n            description=\"Defines the path of the CRL store file, as an absolute path. If left empty, a default store file path will be computed by adding a .crl suffix to the value of the Keystore Path parameter.\">\n        </AD>\n\n        <AD id=\"verify.crl\"\n            name=\"Enable CRL Verification\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"If set to true, the downloaded CRLs will be stored only if signed with the public key of one of trusted certificates in this keystore.\">\n        </AD>\n\n    </OCD>\n\n    <Designate factoryPid=\"org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl\">\n        <Object ocdref=\"org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl\"/>\n    </Designate>\n</MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/OSGI-INF/org.eclipse.kura.core.keystore.keystoreService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2021 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"false\" modified=\"updated\" name=\"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\">\n   <implementation class=\"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.security.keystore.KeystoreService\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n\n\t<property name=\"service.pid\" value=\"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImplerviceImpl\"/>\n\t<reference name=\"CryptoService\"\n              interface=\"org.eclipse.kura.crypto.CryptoService\"\n              bind=\"setCryptoService\"\n              cardinality=\"1..1\"\n              policy=\"static\"/>\n    <reference name=\"ConfigurationService\"\n              bind=\"setConfigurationService\"\n              interface=\"org.eclipse.kura.configuration.ConfigurationService\"/>\n    <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n    <property name=\"kura.ui.service.hide\" type=\"String\" value=\"true\"/>\n    <reference bind=\"setEventAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.event.EventAdmin\" name=\"EventAdmin\" policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/OSGI-INF/org.eclipse.kura.core.keystore.pkcs11KeystoreService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"false\" modified=\"updated\" name=\"org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl\">\n   <implementation class=\"org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.security.keystore.KeystoreService\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n\t<reference name=\"CryptoService\"\n              interface=\"org.eclipse.kura.crypto.CryptoService\"\n              bind=\"setCryptoService\"\n              cardinality=\"1..1\"\n              policy=\"static\"/>\n    <reference name=\"SystemService\"\n              bind=\"setSystemService\"\n              interface=\"org.eclipse.kura.system.SystemService\"\n              cardinality=\"1..1\"\n              policy=\"static\"/>\n    <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n    <property name=\"kura.ui.service.hide\" type=\"String\" value=\"true\"/>\n    <reference bind=\"setEventAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.event.EventAdmin\" name=\"EventAdmin\" policy=\"static\"/>\n</scr:component>"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/build.properties",
    "content": "#\n#  Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about_files/,\\\n               about.html\nadditional.bundles = org.eclipse.osgi,\\\n                     org.eclipse.osgi.util,\\\n                     org.eclipse.kura.api\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.keystore</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/BaseKeystoreService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore;\n\nimport static java.util.Objects.isNull;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.KeyStore;\nimport java.security.KeyStore.Entry;\nimport java.security.KeyStore.PasswordProtection;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStore.ProtectionParameter;\nimport java.security.KeyStore.SecretKeyEntry;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.Provider;\nimport java.security.PublicKey;\nimport java.security.SecureRandom;\nimport java.security.Security;\nimport java.security.cert.CRL;\nimport java.security.cert.CertStore;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CollectionCertStoreParameters;\nimport java.security.cert.X509CRL;\nimport java.security.cert.X509Certificate;\nimport java.security.spec.AlgorithmParameterSpec;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Calendar;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.security.auth.x500.X500Principal;\n\nimport org.bouncycastle.asn1.x500.X500Name;\nimport org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;\nimport org.bouncycastle.cert.X509CertificateHolder;\nimport org.bouncycastle.cert.X509v3CertificateBuilder;\nimport org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\nimport org.bouncycastle.openssl.jcajce.JcaPEMWriter;\nimport org.bouncycastle.operator.ContentSigner;\nimport org.bouncycastle.operator.OperatorCreationException;\nimport org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;\nimport org.bouncycastle.pkcs.PKCS10CertificationRequest;\nimport org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;\nimport org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;\nimport org.bouncycastle.util.io.pem.PemObject;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.keystore.crl.CRLManager;\nimport org.eclipse.kura.core.keystore.crl.CRLManager.CRLVerifier;\nimport org.eclipse.kura.core.keystore.crl.CRLManagerOptions;\nimport org.eclipse.kura.core.keystore.crl.StoredCRL;\nimport org.eclipse.kura.security.keystore.KeystoreChangedEvent;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.EventAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class BaseKeystoreService implements KeystoreService, ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(BaseKeystoreService.class);\n\n    protected static final String NULL_INPUT_PARAMS_MESSAGE = \"Input parameters cannot be null!\";\n    protected static final String KURA_SERVICE_PID = \"kura.service.pid\";\n    protected static final String PEM_CERTIFICATE_REQUEST_TYPE = \"CERTIFICATE REQUEST\";\n\n    protected EventAdmin eventAdmin;\n\n    protected Optional<CRLManager> crlManager = Optional.empty();\n\n    protected String ownPid;\n\n    protected ComponentContext componentContext;\n\n    private CRLManagerOptions crlManagerOptions;\n\n    static {\n        Security.addProvider(new BouncyCastleProvider());\n    }\n\n    public void setEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    protected abstract KeystoreInstance loadKeystore() throws KuraException;\n\n    protected abstract void saveKeystore(KeystoreInstance keystore)\n            throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException;\n\n    protected abstract String getCrlStorePath();\n\n    @Override\n    public KeyStore getKeyStore() throws KuraException {\n\n        return loadKeystore().getKeystore();\n    }\n\n    public void activate(ComponentContext context, Map<String, Object> properties) {\n        this.componentContext = context;\n\n        this.ownPid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n        this.crlManagerOptions = new CRLManagerOptions(properties);\n\n        updateCRLManager(this.crlManagerOptions);\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"Bundle {} is updating!\", properties.get(KURA_SERVICE_PID));\n\n        final CRLManagerOptions newCRLManagerOptions = new CRLManagerOptions(properties);\n\n        if (!this.crlManagerOptions.equals(newCRLManagerOptions)) {\n            this.crlManagerOptions = newCRLManagerOptions;\n\n            updateCRLManager(newCRLManagerOptions);\n        }\n    }\n\n    public void deactivate() {\n        shutdownCRLManager();\n    }\n\n    @Override\n    public Entry getEntry(String alias) throws KuraException {\n        if (isNull(alias)) {\n            throw new IllegalArgumentException(\"Key Pair alias cannot be null!\");\n        }\n        KeystoreInstance ks = loadKeystore();\n\n        try {\n            if (ks.getKeystore().entryInstanceOf(alias, PrivateKeyEntry.class)\n                    || ks.getKeystore().entryInstanceOf(alias, SecretKeyEntry.class)) {\n                return ks.getKeystore().getEntry(alias, new PasswordProtection(ks.getPassword()));\n            } else {\n                return ks.getKeystore().getEntry(alias, null);\n            }\n        } catch (GeneralSecurityException e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, e, \"Failed to get the entry \" + alias);\n        }\n    }\n\n    @Override\n    public void setEntry(String alias, Entry entry) throws KuraException {\n        if (isNull(alias) || alias.trim().isEmpty() || isNull(entry)) {\n            throw new IllegalArgumentException(\"Input cannot be null or empty!\");\n        }\n        KeystoreInstance ks = loadKeystore();\n\n        final ProtectionParameter protectionParameter;\n\n        if (entry instanceof TrustedCertificateEntry) {\n            protectionParameter = null;\n        } else {\n            protectionParameter = new PasswordProtection(ks.getPassword());\n        }\n        try {\n            ks.getKeystore().setEntry(alias, entry, protectionParameter);\n            saveKeystore(ks);\n            tryAddToCrlManagement(entry);\n            postChangedEvent();\n        } catch (GeneralSecurityException | IOException e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, e, \"Failed to set the entry \" + alias);\n        }\n\n    }\n\n    @Override\n    public Map<String, Entry> getEntries() throws KuraException {\n        Map<String, Entry> result = new HashMap<>();\n\n        KeyStore ks = getKeyStore();\n        try {\n            List<String> aliases = Collections.list(ks.aliases());\n\n            for (String alias : aliases) {\n                Entry tempEntry = getEntry(alias);\n                result.put(alias, tempEntry);\n            }\n            return result;\n        } catch (GeneralSecurityException e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, e, \"Failed to get the entries\");\n        }\n    }\n\n    @Override\n    public void deleteEntry(String alias) throws KuraException {\n        if (isNull(alias)) {\n            throw new IllegalArgumentException(\"Alias cannot be null!\");\n        }\n        final Optional<Entry> currentEntry = Optional.ofNullable(getEntry(alias));\n\n        if (!currentEntry.isPresent()) {\n            return;\n        }\n\n        KeystoreInstance ks = loadKeystore();\n        try {\n            ks.getKeystore().deleteEntry(alias);\n            saveKeystore(ks);\n            tryRemoveFromCrlManagement(currentEntry.get());\n            postChangedEvent();\n        } catch (GeneralSecurityException | IOException e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, e, \"Failed to delete entry \" + alias);\n        }\n    }\n\n    @Override\n    public List<KeyManager> getKeyManagers(String algorithm) throws KuraException {\n        if (isNull(algorithm)) {\n            throw new IllegalArgumentException(\"Algorithm cannot be null!\");\n        }\n        KeystoreInstance ks = loadKeystore();\n        try {\n            KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);\n            kmf.init(ks.getKeystore(), ks.getPassword());\n\n            return Arrays.asList(kmf.getKeyManagers());\n        } catch (GeneralSecurityException e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, e,\n                    \"Failed to get the key managers for algorithm \" + algorithm);\n        }\n    }\n\n    @Override\n    public List<KeyManager> getKeyManagers(String algorithm, String provider) throws KuraException {\n        if (isNull(algorithm)) {\n            throw new IllegalArgumentException(\"Algorithm cannot be null!\");\n        }\n        if (isNull(provider)) {\n            throw new IllegalArgumentException(\"Provider cannot be null!\");\n        }\n        KeystoreInstance ks = loadKeystore();\n        try {\n            KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm, provider);\n            kmf.init(ks.getKeystore(), ks.getPassword());\n\n            return Arrays.asList(kmf.getKeyManagers());\n        } catch (GeneralSecurityException e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, e,\n                    \"Failed to get the key managers for algorithm \" + algorithm + \" and provider \" + provider);\n        }\n    }\n\n    @Override\n    public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes)\n            throws KuraException {\n        createKeyPair(alias, algorithm, keySize, signatureAlgorithm, attributes, new SecureRandom());\n    }\n\n    @Override\n    public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes,\n            SecureRandom secureRandom) throws KuraException {\n        if (isNull(algorithm) || algorithm.trim().isEmpty() || isNull(secureRandom) || isNull(alias)\n                || isNull(attributes) || attributes.trim().isEmpty() || isNull(signatureAlgorithm)\n                || signatureAlgorithm.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"Parameters cannot be null or empty!\");\n        }\n        KeyPair keyPair;\n        try {\n            KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm, \"BC\");\n            keyGen.initialize(keySize, secureRandom);\n            keyPair = keyGen.generateKeyPair();\n            setEntry(alias, new PrivateKeyEntry(keyPair.getPrivate(),\n                    generateCertificateChain(keyPair, signatureAlgorithm, attributes)));\n        } catch (GeneralSecurityException | OperatorCreationException e) {\n            logger.error(\"Error occured. Exception: {}.\", e.getClass());\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n    }\n\n    @Override\n    public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter,\n            String signatureAlgorithm, String attributes, SecureRandom secureRandom) throws KuraException {\n\n        if (isNull(algorithm) || algorithm.trim().isEmpty() || isNull(secureRandom) || isNull(alias)\n                || isNull(attributes) || attributes.trim().isEmpty() || isNull(signatureAlgorithm)\n                || signatureAlgorithm.trim().isEmpty() || isNull(algorithmParameter)) {\n            throw new IllegalArgumentException(\"Parameters cannot be null or empty!\");\n        }\n        KeyPair keyPair;\n        try {\n            KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm, \"BC\");\n            keyGen.initialize(algorithmParameter, secureRandom);\n            keyPair = keyGen.generateKeyPair();\n            setEntry(alias, new PrivateKeyEntry(keyPair.getPrivate(),\n                    generateCertificateChain(keyPair, signatureAlgorithm, attributes)));\n        } catch (GeneralSecurityException | OperatorCreationException e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n    }\n\n    @Override\n    public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter,\n            String signatureAlgorithm, String attributes) throws KuraException {\n        createKeyPair(alias, algorithm, algorithmParameter, signatureAlgorithm, attributes, new SecureRandom());\n\n    }\n\n    @Override\n    public String getCSR(KeyPair keypair, X500Principal principal, String signerAlg) throws KuraException {\n\n        if (isNull(principal) || isNull(keypair) || isNull(signerAlg) || signerAlg.trim().isEmpty()) {\n            throw new IllegalArgumentException(NULL_INPUT_PARAMS_MESSAGE);\n        }\n\n        try (StringWriter str = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(str);) {\n            ContentSigner signer = new JcaContentSignerBuilder(signerAlg).build(keypair.getPrivate());\n            PKCS10CertificationRequest csr = getCSRAsPKCS10Builder(keypair, principal).build(signer);\n\n            PemObject pemCSR = new PemObject(PEM_CERTIFICATE_REQUEST_TYPE, csr.getEncoded());\n\n            pemWriter.writeObject(pemCSR);\n            pemWriter.flush();\n            return str.toString();\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, e, \"Failed to get CSR\");\n        } catch (OperatorCreationException e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, e, \"Failed to get CSR\");\n        }\n    }\n\n    @Override\n    public String getCSR(String alias, X500Principal principal, String signerAlg) throws KuraException {\n        if (isNull(principal) || isNull(alias) || alias.trim().isEmpty() || isNull(signerAlg)\n                || signerAlg.trim().isEmpty()) {\n            throw new IllegalArgumentException(NULL_INPUT_PARAMS_MESSAGE);\n        }\n\n        Entry entry = getEntry(alias);\n        if (entry == null) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n        if (!(entry instanceof PrivateKeyEntry)) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n        PrivateKey privateKey = ((PrivateKeyEntry) entry).getPrivateKey();\n        PublicKey publicKey = ((PrivateKeyEntry) entry).getCertificate().getPublicKey();\n        KeyPair keyPair = new KeyPair(publicKey, privateKey);\n        return getCSR(keyPair, principal, signerAlg);\n    }\n\n    protected PKCS10CertificationRequestBuilder getCSRAsPKCS10Builder(KeyPair keyPair, X500Principal principal) {\n        if (isNull(principal) || isNull(keyPair)) {\n            throw new IllegalArgumentException(NULL_INPUT_PARAMS_MESSAGE);\n        }\n        return new JcaPKCS10CertificationRequestBuilder(principal, keyPair.getPublic());\n\n    }\n\n    @Override\n    public List<String> getAliases() throws KuraException {\n        KeyStore ks = getKeyStore();\n        try {\n            return Collections.list(ks.aliases());\n        } catch (GeneralSecurityException e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, e, \"Failed to get aliases\");\n        }\n    }\n\n    @Override\n    public Collection<CRL> getCRLs() {\n\n        final Optional<CRLManager> currentCRLManager = this.crlManager;\n\n        if (!currentCRLManager.isPresent()) {\n            return Collections.emptyList();\n        } else {\n            return new ArrayList<>(currentCRLManager.get().getCrls());\n        }\n\n    }\n\n    @Override\n    public CertStore getCRLStore() throws KuraException {\n        final Optional<CRLManager> currentCRLManager = this.crlManager;\n\n        try {\n            if (!currentCRLManager.isPresent()) {\n                return CertStore.getInstance(\"Collection\", new CollectionCertStoreParameters());\n            } else {\n                return currentCRLManager.get().getCertStore();\n            }\n        } catch (final Exception e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e);\n        }\n    }\n\n    @Override\n    public void addCRL(X509CRL crl) throws KuraException {\n        this.crlManager.ifPresent(manager -> {\n            StoredCRL storedCRL = new StoredCRL(Collections.emptySet(), crl);\n            manager.getCRLStore().storeCRL(storedCRL);\n        });\n    }\n\n    protected void postChangedEvent() {\n        this.eventAdmin.postEvent(new KeystoreChangedEvent(ownPid));\n    }\n\n    protected X509Certificate[] generateCertificateChain(KeyPair keyPair, String signatureAlgorithm, String attributes)\n            throws OperatorCreationException, CertificateException {\n        Provider bcProvider = new BouncyCastleProvider();\n        Security.addProvider(bcProvider);\n        long now = System.currentTimeMillis();\n        Date startDate = new Date(now);\n        X500Name dnName = new X500Name(attributes);\n        // Use the timestamp as serial number\n        BigInteger certSerialNumber = new BigInteger(Long.toString(now));\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(startDate);\n        calendar.add(Calendar.YEAR, 1);\n        Date endDate = calendar.getTime();\n\n        SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());\n        X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(dnName, certSerialNumber, startDate,\n                endDate, dnName, subjectPublicKeyInfo);\n        ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(bcProvider)\n                .build(keyPair.getPrivate());\n        X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner);\n\n        return new X509Certificate[] { new JcaX509CertificateConverter().getCertificate(certificateHolder) };\n    }\n\n    protected Optional<X509Certificate> extractCertificate(final Entry entry) {\n        if (!(entry instanceof TrustedCertificateEntry)) {\n            return Optional.empty();\n        }\n\n        final TrustedCertificateEntry trustedCertificateEntry = (TrustedCertificateEntry) entry;\n        final Certificate certificate = trustedCertificateEntry.getTrustedCertificate();\n\n        if (!(certificate instanceof X509Certificate)) {\n            return Optional.empty();\n        } else {\n            return Optional.of((X509Certificate) certificate);\n        }\n\n    }\n\n    protected boolean tryAddToCrlManagement(final Entry entry) {\n        final Optional<X509Certificate> certificate = extractCertificate(entry);\n        final Optional<CRLManager> currentCrlManager = this.crlManager;\n\n        if (certificate.isPresent() && currentCrlManager.isPresent()) {\n            return currentCrlManager.get().addTrustedCertificate(certificate.get());\n        } else {\n            return false;\n        }\n    }\n\n    protected boolean tryRemoveFromCrlManagement(final Entry entry) {\n        final Optional<X509Certificate> certificate = extractCertificate(entry);\n        final Optional<CRLManager> currentCrlManager = this.crlManager;\n\n        if (certificate.isPresent() && currentCrlManager.isPresent()) {\n            return currentCrlManager.get().removeTrustedCertificate(certificate.get());\n        } else {\n            return false;\n        }\n    }\n\n    protected void updateCRLManager(final CRLManagerOptions newCRLManagerOptions) {\n        shutdownCRLManager();\n\n        if (this.crlManagerOptions.isCrlManagementEnabled()) {\n\n            final CRLManager currentCRLManager = new CRLManager(\n                    this.crlManagerOptions.getStoreFile().orElseGet(() -> new File(getCrlStorePath())), 5000,\n                    newCRLManagerOptions.getCrlCheckIntervalMs(), newCRLManagerOptions.getCrlUpdateIntervalMs(),\n                    getCRLVerifier(newCRLManagerOptions));\n\n            currentCRLManager.setListener(Optional.of(this::postChangedEvent));\n\n            for (final URI uri : newCRLManagerOptions.getCrlURIs()) {\n                currentCRLManager.addDistributionPoint(Collections.singleton(uri));\n            }\n\n            try {\n                for (final Entry e : getEntries().values()) {\n                    if (!(e instanceof TrustedCertificateEntry)) {\n                        continue;\n                    }\n\n                    final TrustedCertificateEntry certEntry = (TrustedCertificateEntry) e;\n\n                    final Certificate cert = certEntry.getTrustedCertificate();\n\n                    if (cert instanceof X509Certificate) {\n                        currentCRLManager.addTrustedCertificate((X509Certificate) cert);\n                    }\n                }\n\n            } catch (final Exception e) {\n                logger.warn(\"failed to add current trusted certificates to CRL manager\", e);\n            }\n\n            this.crlManager = Optional.of(currentCRLManager);\n        }\n    }\n\n    protected CRLVerifier getCRLVerifier(final CRLManagerOptions options) {\n        if (!options.isCRLVerificationEnabled()) {\n            return crl -> true;\n        }\n\n        return crl -> {\n            try {\n                for (final Entry e : getEntries().values()) {\n                    if (!(e instanceof TrustedCertificateEntry)) {\n                        continue;\n                    }\n\n                    final TrustedCertificateEntry trustedCertEntry = (TrustedCertificateEntry) e;\n\n                    if (verifyCRL(crl, trustedCertEntry)) {\n                        return true;\n                    }\n                }\n                return false;\n            } catch (final Exception e) {\n                logger.warn(\"Exception verifying CRL\", e);\n                return false;\n            }\n        };\n    }\n\n    protected void shutdownCRLManager() {\n        if (this.crlManager.isPresent()) {\n            this.crlManager.get().close();\n            this.crlManager = Optional.empty();\n        }\n    }\n\n    protected boolean verifyCRL(X509CRL crl, final TrustedCertificateEntry trustedCertEntry) {\n        try {\n            crl.verify(trustedCertEntry.getTrustedCertificate().getPublicKey());\n            return true;\n        } catch (final Exception e) {\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/FilesystemKeystoreServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore;\n\nimport static org.eclipse.kura.core.keystore.FilesystemKeystoreServiceOptions.KEY_KEYSTORE_PASSWORD;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.math.BigInteger;\nimport java.security.KeyStore;\nimport java.security.KeyStore.Entry;\nimport java.security.KeyStore.PasswordProtection;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.security.UnrecoverableEntryException;\nimport java.security.cert.CertificateException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraRuntimeException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FilesystemKeystoreServiceImpl extends BaseKeystoreService {\n\n    private static final Logger logger = LoggerFactory.getLogger(FilesystemKeystoreServiceImpl.class);\n\n    private CryptoService cryptoService;\n    private ConfigurationService configurationService;\n\n    private FilesystemKeystoreServiceOptions keystoreServiceOptions;\n\n    private ScheduledExecutorService selfUpdaterExecutor;\n    private ScheduledFuture<?> selfUpdaterFuture;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void setConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public void activate(ComponentContext context, Map<String, Object> properties) {\n        logger.info(\"Bundle {} is starting!\", properties.get(KURA_SERVICE_PID));\n        this.componentContext = context;\n\n        this.keystoreServiceOptions = new FilesystemKeystoreServiceOptions(properties, this.cryptoService);\n        this.selfUpdaterExecutor = Executors.newSingleThreadScheduledExecutor();\n\n        if (!keystoreExists(this.keystoreServiceOptions.getKeystorePath())) {\n            try {\n                createKeystore(this.keystoreServiceOptions);\n            } catch (Exception e) {\n                logger.error(\"Keystore file creation failed\", e);\n            }\n        }\n\n        if (this.keystoreServiceOptions.needsRandomPassword()) {\n            setRandomPassword();\n        }\n\n        super.activate(context, properties);\n\n        logger.info(\"Bundle {} has started!\", properties.get(KURA_SERVICE_PID));\n    }\n\n    @Override\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"Bundle {} is updating!\", properties.get(KURA_SERVICE_PID));\n        FilesystemKeystoreServiceOptions newOptions = new FilesystemKeystoreServiceOptions(properties,\n                this.cryptoService);\n\n        if (!this.keystoreServiceOptions.equals(newOptions)) {\n            logger.info(\"Perform update...\");\n\n            if (!this.keystoreServiceOptions.getKeystorePath().equals(newOptions.getKeystorePath())) {\n                updateKeystorePath(newOptions);\n            } else {\n                checkAndUpdateKeystorePassword(newOptions);\n            }\n\n            this.keystoreServiceOptions = new FilesystemKeystoreServiceOptions(properties, this.cryptoService);\n\n        }\n\n        super.updated(properties);\n\n        logger.info(\"Bundle {} has updated!\", properties.get(KURA_SERVICE_PID));\n    }\n\n    @Override\n    public void deactivate() {\n        logger.info(\"Bundle {} is deactivating!\", this.keystoreServiceOptions.getProperties().get(KURA_SERVICE_PID));\n\n        if (this.selfUpdaterFuture != null && !this.selfUpdaterFuture.isDone()) {\n\n            logger.info(\"Self updater task running. Stopping it\");\n\n            this.selfUpdaterFuture.cancel(true);\n        }\n\n        super.deactivate();\n    }\n\n    @Override\n    protected void saveKeystore(KeystoreInstance ks)\n            throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException {\n        try (FileOutputStream tsOutStream = new FileOutputStream(this.keystoreServiceOptions.getKeystorePath());) {\n            ks.getKeystore().store(tsOutStream, ks.getPassword());\n        }\n    }\n\n    @Override\n    protected KeystoreInstance loadKeystore() throws KuraException {\n        return loadKeystore(this.keystoreServiceOptions);\n    }\n\n    @Override\n    protected String getCrlStorePath() {\n        return this.keystoreServiceOptions.getKeystorePath() + \".crl\";\n    }\n\n    private void checkAndUpdateKeystorePassword(final FilesystemKeystoreServiceOptions options) {\n        try {\n            final KeystoreInstance ks = loadKeystore(this.keystoreServiceOptions);\n\n            final char[] configPassword = options.getKeystorePassword(cryptoService);\n\n            if (!Arrays.equals(ks.getPassword(), configPassword)) {\n                setKeystorePassword(ks, configPassword);\n            }\n\n        } catch (final Exception e) {\n            logger.warn(\"failed to load or update keystore password\", e);\n        }\n    }\n\n    private boolean keystoreExists(String keystorePath) {\n        return keystorePath != null && new File(keystorePath).isFile();\n    }\n\n    private void createKeystore(FilesystemKeystoreServiceOptions options) throws Exception {\n        String keystorePath = options.getKeystorePath();\n        char[] passwordChar = options.getKeystorePassword(this.cryptoService);\n        if (keystorePath == null) {\n            return;\n        }\n        File fKeyStore = new File(keystorePath);\n        if (!fKeyStore.createNewFile()) {\n            logger.error(\"Keystore file already exists at location {}\", keystorePath);\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, \"keystore.path\", keystorePath,\n                    \"file already exists\");\n        }\n\n        // Immediately save the keystore with the default password to allow to be loaded with the default password.\n        try (OutputStream os = new FileOutputStream(fKeyStore)) {\n            KeyStore newKeystore = KeyStore.getInstance(KeyStore.getDefaultType());\n            newKeystore.load(null, passwordChar);\n            newKeystore.store(os, passwordChar);\n            os.flush();\n        } catch (Exception e) {\n            logger.error(\"Unable to load and store the keystore\", e);\n            throw e;\n        }\n\n        setKeystorePassword(this.loadKeystore(options), passwordChar);\n    }\n\n    private void updateKeystorePath(FilesystemKeystoreServiceOptions newOptions) {\n        if (!keystoreExists(newOptions.getKeystorePath())) {\n            try {\n                createKeystore(newOptions);\n            } catch (Exception e) {\n                logger.error(\"Keystore file creation failed\", e);\n            }\n        }\n\n        try {\n            loadKeystore(newOptions);\n        } catch (final Exception e) {\n            logger.warn(\"Keystore {} not accessible!\", newOptions.getKeystorePath());\n        }\n    }\n\n    private void setRandomPassword() {\n\n        try {\n            final KeystoreInstance keystore = loadKeystore(this.keystoreServiceOptions);\n\n            char[] newPassword = new BigInteger(160, new SecureRandom()).toString(32).toCharArray();\n\n            setKeystorePassword(keystore, newPassword);\n\n            Map<String, Object> props = new HashMap<>(this.keystoreServiceOptions.getProperties());\n            props.put(KEY_KEYSTORE_PASSWORD, new String(this.cryptoService.encryptAes(newPassword)));\n            this.keystoreServiceOptions = new FilesystemKeystoreServiceOptions(props, this.cryptoService);\n\n            updatePasswordInConfigService(newPassword);\n        } catch (Exception e) {\n            logger.warn(\"Keystore password change failed\", e);\n        }\n    }\n\n    private synchronized void saveKeystore(KeystoreInstance ks, char[] keyStorePassword)\n            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {\n        try (FileOutputStream tsOutStream = new FileOutputStream(((KeystoreInstanceImpl) ks).path)) {\n            ks.getKeystore().store(tsOutStream, keyStorePassword);\n        }\n    }\n\n    private void updatePasswordInConfigService(char[] newPassword) {\n        final String pid = this.keystoreServiceOptions.getPid();\n\n        Map<String, Object> props = new HashMap<>();\n        props.putAll(this.keystoreServiceOptions.getProperties());\n        props.put(FilesystemKeystoreServiceOptions.KEY_KEYSTORE_PATH, this.keystoreServiceOptions.getKeystorePath());\n        props.put(FilesystemKeystoreServiceOptions.KEY_KEYSTORE_PASSWORD, new Password(newPassword));\n        props.put(FilesystemKeystoreServiceOptions.KEY_RANDOMIZE_PASSWORD, false);\n\n        this.selfUpdaterFuture = this.selfUpdaterExecutor.scheduleAtFixedRate(() -> {\n            try {\n                if (this.componentContext.getServiceReference() != null\n                        && this.configurationService.getComponentConfiguration(pid) != null\n                        && this.configurationService.getComponentConfiguration(pid).getDefinition() != null) {\n                    this.configurationService.updateConfiguration(pid, props);\n                    throw new KuraRuntimeException(KuraErrorCode.CONFIGURATION_SNAPSHOT_TAKING,\n                            \"Updated. The task will be terminated.\");\n                } else {\n                    logger.info(\"No service or configuration available yet.\");\n                }\n            } catch (KuraException e) {\n                logger.warn(\"Cannot get/update configuration for pid: {}\", pid, e);\n            }\n        }, 1000, 1000, TimeUnit.MILLISECONDS);\n    }\n\n    private synchronized void setKeystorePassword(KeystoreInstance ks, char[] password) {\n        try {\n            updateKeyEntriesPasswords(ks, password);\n            saveKeystore(ks, password);\n\n            this.cryptoService.setKeyStorePassword(((KeystoreInstanceImpl) ks).path, password);\n        } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | UnrecoverableEntryException\n                | IOException e) {\n            logger.warn(\"Failed to change keystore password\");\n        } catch (KuraException e) {\n            logger.warn(\"Failed to persist keystore password\");\n        }\n    }\n\n    private static void updateKeyEntriesPasswords(KeystoreInstance ks, char[] newPassword)\n            throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException {\n        Enumeration<String> aliases = ks.getKeystore().aliases();\n        while (aliases.hasMoreElements()) {\n            String alias = aliases.nextElement();\n            if (ks.getKeystore().isKeyEntry(alias)) {\n                PasswordProtection oldPP = new PasswordProtection(ks.getPassword());\n                Entry entry = ks.getKeystore().getEntry(alias, oldPP);\n                PasswordProtection newPP = new PasswordProtection(newPassword);\n                ks.getKeystore().setEntry(alias, entry, newPP);\n            }\n        }\n    }\n\n    private synchronized KeystoreInstance loadKeystore(final FilesystemKeystoreServiceOptions options)\n            throws KuraException {\n        final List<char[]> passwords = new ArrayList<>(2);\n\n        passwords.add(options.getKeystorePassword(cryptoService));\n\n        char[] passwordInCrypto = null;\n\n        try {\n            passwordInCrypto = this.cryptoService.getKeyStorePassword(options.getKeystorePath());\n            if (passwordInCrypto != null) {\n                passwords.add(passwordInCrypto);\n            }\n        } catch (final Exception e) {\n            logger.debug(\"failed to retrieve password\", e);\n        }\n\n        final KeystoreInstance result = new KeystoreLoader(options.getKeystorePath(), passwords).loadKeystore();\n\n        if (!Arrays.equals(passwordInCrypto, result.getPassword())) {\n            this.cryptoService.setKeyStorePassword(((KeystoreInstanceImpl) result).path, result.getPassword());\n        }\n\n        return result;\n    }\n\n    private static class KeystoreLoader {\n\n        private final String path;\n        private final List<char[]> passwords;\n\n        KeystoreLoader(final String path, final List<char[]> passwords) {\n            this.path = path;\n            this.passwords = passwords;\n        }\n\n        private KeyStore loadKeystore(final String path, final char[] password)\n                throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {\n            return KeyStore.getInstance(new File(path), password);\n        }\n\n        KeystoreInstance loadKeystore() throws KuraException {\n\n            for (final char[] password : this.passwords) {\n                try {\n                    final KeyStore keyStore = loadKeystore(path, password);\n\n                    return new KeystoreInstanceImpl(keyStore, password, this.path);\n                } catch (final Exception e) {\n                    logger.debug(\"failed to load keystore\", e);\n                }\n            }\n\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"Failed to get the KeyStore\");\n\n        }\n    }\n\n    private static class KeystoreInstanceImpl implements KeystoreInstance {\n\n        private final KeyStore keystore;\n        private final char[] password;\n        private final String path;\n\n        public KeystoreInstanceImpl(final KeyStore keystore, final char[] password, final String path) {\n            this.keystore = keystore;\n            this.password = password;\n            this.path = path;\n        }\n\n        @Override\n        public KeyStore getKeystore() {\n            return keystore;\n        }\n\n        @Override\n        public char[] getPassword() {\n            return password;\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/FilesystemKeystoreServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore;\n\nimport static java.util.Objects.isNull;\n\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.nio.file.InvalidPathException;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FilesystemKeystoreServiceOptions {\n\n    private static final Logger logger = LoggerFactory.getLogger(FilesystemKeystoreServiceOptions.class);\n\n    private static final String KEY_SERVICE_PID = \"kura.service.pid\";\n    static final String KEY_KEYSTORE_PATH = \"keystore.path\";\n    static final String KEY_KEYSTORE_PASSWORD = \"keystore.password\";\n    static final String KEY_RANDOMIZE_PASSWORD = \"randomize.password\";\n\n    private static final String DEFAULT_KEYSTORE_PATH = \"/tmp/keystore.ks\";\n    private static final boolean DEFAULT_RANDOMIZE_PASSWORD = false;\n    static final String DEFAULT_KEYSTORE_PASSWORD = \"changeit\";\n\n    private final Map<String, Object> properties;\n    private final String pid;\n    private final String keystorePath;\n    private final Password keystorePassword;\n    private final boolean randomPassword;\n\n    public FilesystemKeystoreServiceOptions(Map<String, Object> properties, final CryptoService cryptoService) {\n        if (isNull(properties) || isNull(cryptoService)) {\n            throw new IllegalArgumentException(\"Input parameters cannot be null!\");\n        }\n\n        this.properties = properties;\n\n        this.pid = (String) properties.get(KEY_SERVICE_PID);\n\n        String keyStorePath = (String) properties.getOrDefault(KEY_KEYSTORE_PATH, DEFAULT_KEYSTORE_PATH);\n        try {\n            this.keystorePath = validateAndNormalize(keyStorePath);\n        } catch (Exception e) {\n            logger.error(\"Keystore path {} not valid\", keyStorePath);\n            throw new IllegalArgumentException(\"Invalid keystore path\");\n        }\n\n        this.keystorePassword = extractPassword(properties, cryptoService);\n\n        this.randomPassword = (boolean) properties.getOrDefault(KEY_RANDOMIZE_PASSWORD, DEFAULT_RANDOMIZE_PASSWORD);\n    }\n\n    private String validateAndNormalize(String keystorePath) throws URISyntaxException, InvalidPathException {\n        Paths.get(keystorePath); // throw InvalidPathException if invalid\n        return new URI(keystorePath).normalize().toString();\n    }\n\n    private static Password extractPassword(final Map<String, Object> properties, final CryptoService cryptoService) {\n        final Object optionsPassword = properties.get(KEY_KEYSTORE_PASSWORD);\n\n        if (optionsPassword instanceof String) {\n            return new Password((String) optionsPassword);\n        }\n\n        try {\n            return new Password(cryptoService.encryptAes(DEFAULT_KEYSTORE_PASSWORD.toCharArray()));\n        } catch (final Exception e) {\n            logger.warn(\"failed to encrypt default keystore password\", e);\n            return new Password(DEFAULT_KEYSTORE_PASSWORD);\n        }\n    }\n\n    public Map<String, Object> getProperties() {\n        return this.properties;\n    }\n\n    public String getPid() {\n        return this.pid;\n    }\n\n    public String getKeystorePath() {\n        return this.keystorePath;\n    }\n\n    public char[] getKeystorePassword(final CryptoService cryptoService) {\n        try {\n            return cryptoService.decryptAes(this.keystorePassword.getPassword());\n        } catch (final Exception e) {\n            return this.keystorePassword.getPassword();\n        }\n    }\n\n    public boolean needsRandomPassword() {\n        return this.randomPassword;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(Arrays.hashCode(keystorePassword.getPassword()), keystorePath, pid, randomPassword);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        FilesystemKeystoreServiceOptions other = (FilesystemKeystoreServiceOptions) obj;\n        return Arrays.equals(keystorePassword.getPassword(), other.keystorePassword.getPassword())\n                && Objects.equals(keystorePath, other.keystorePath) && Objects.equals(pid, other.pid)\n                && randomPassword == other.randomPassword;\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/KeystoreInstance.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore;\n\nimport java.security.KeyStore;\n\npublic interface KeystoreInstance {\n\n    public KeyStore getKeystore();\n\n    public char[] getPassword();\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/PKCS11KeystoreServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Method;\nimport java.nio.file.Files;\nimport java.security.KeyStore;\nimport java.security.KeyStore.Entry;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.Provider;\nimport java.security.SecureRandom;\nimport java.security.Security;\nimport java.security.cert.CertificateException;\nimport java.security.spec.AlgorithmParameterSpec;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class PKCS11KeystoreServiceImpl extends BaseKeystoreService {\n\n    private static final Logger logger = LoggerFactory.getLogger(PKCS11KeystoreServiceImpl.class);\n\n    Optional<Provider> provider = Optional.empty();\n    private PKCS11KeystoreServiceOptions options;\n\n    private CryptoService cryptoService;\n    private SystemService systemService;\n\n    public void setCryptoService(final CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void setSystemService(final SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    @Override\n    public void activate(ComponentContext context, Map<String, Object> properties) {\n\n        super.activate(context, properties);\n\n        options = new PKCS11KeystoreServiceOptions(properties, ownPid);\n\n    }\n\n    @Override\n    public void updated(Map<String, Object> properties) {\n\n        super.updated(properties);\n\n        PKCS11KeystoreServiceOptions newOptions = new PKCS11KeystoreServiceOptions(properties, ownPid);\n\n        if (!newOptions.equals(this.options)) {\n            logger.info(\"Options changed...\");\n\n            removeProvider();\n            this.options = newOptions;\n        }\n\n    }\n\n    @Override\n    public void deactivate() {\n\n        removeProvider();\n\n        super.deactivate();\n    }\n\n    @Override\n    protected KeystoreInstance loadKeystore() throws KuraException {\n        final Provider currentProvider = getOrRegisterProvider();\n\n        try {\n            final KeyStore store = KeyStore.getInstance(\"PKCS11\", currentProvider);\n\n            final char[] pin = this.options.getPin(cryptoService).orElse(null);\n\n            store.load(null, pin);\n\n            return new KeystoreInstanceImpl(store, pin);\n\n        } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {\n            removeProvider();\n            logger.warn(\"Keystore exception\", e);\n            throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION);\n        }\n    }\n\n    @Override\n    protected void saveKeystore(KeystoreInstance keystore) {\n        // no need\n    }\n\n    @Override\n    public void setEntry(String alias, Entry entry) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED);\n    }\n\n    @Override\n    public void deleteEntry(String alias) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED);\n    }\n\n    @Override\n    public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter,\n            String signatureAlgorithm, String attributes) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED);\n    }\n\n    @Override\n    public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter,\n            String signatureAlgorithm, String attributes, SecureRandom secureRandom) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED);\n    }\n\n    @Override\n    public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes)\n            throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED);\n    }\n\n    @Override\n    public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes,\n            SecureRandom secureRandom) throws KuraException {\n        throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED);\n    }\n\n    @Override\n    protected String getCrlStorePath() {\n        return this.options.getCrlStorePath().orElseGet(\n                () -> this.systemService.getKuraUserConfigDirectory() + \"/security/pkcs11.\" + ownPid + \".crl\");\n    }\n\n    private synchronized Provider getOrRegisterProvider() throws KuraException {\n        if (provider.isPresent()) {\n            return provider.get();\n        }\n\n        logger.info(\"Registering provider...\");\n\n        final String config = this.options.buildSunPKCS11ProviderConfig()\n                .orElseThrow(() -> new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_UNDEFINED, \"library.path\"));\n\n        logger.debug(\"PKCS11 config: {}\", config);\n\n        final String javaVersion = System.getProperty(\"java.version\");\n\n        final Provider newProvider;\n\n        if (javaVersion.startsWith(\"1.\")) {\n            newProvider = registerProviderJava8(config);\n        } else {\n            newProvider = registerProviderJava9(config);\n        }\n\n        this.provider = Optional.of(newProvider);\n\n        logger.info(\"Registering provider...done\");\n\n        return newProvider;\n    }\n\n    private Provider registerProviderJava8(final String config) throws KuraException {\n        try {\n            final Class<?> providerClass = Class.forName(\"sun.security.pkcs11.SunPKCS11\");\n\n            final Constructor<?> ctor = providerClass.getConstructor(InputStream.class);\n\n            final Provider newProvider = (Provider) ctor.newInstance(new ByteArrayInputStream(config.getBytes()));\n\n            Security.addProvider(newProvider);\n\n            return newProvider;\n\n        } catch (final Exception e) {\n            logger.warn(\"failed to load PKCS11 provider\", e);\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE);\n        }\n    }\n\n    private Provider registerProviderJava9(final String config) throws KuraException {\n\n        try {\n            Provider newProvider = Security.getProvider(\"SunPKCS11\");\n\n            final Method configure = Provider.class.getMethod(\"configure\", String.class);\n\n            final File configFile = Files.createTempFile(null, null).toFile();\n\n            try {\n                try (final OutputStream out = new FileOutputStream(configFile)) {\n                    out.write(config.getBytes());\n                }\n\n                newProvider = (Provider) configure.invoke(newProvider, configFile.getAbsolutePath());\n                Security.addProvider(newProvider);\n                return newProvider;\n            } finally {\n                Files.deleteIfExists(configFile.toPath());\n            }\n\n        } catch (final Exception e) {\n            logger.warn(\"failed to load PKCS11 provider\", e);\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE);\n        }\n    }\n\n    private synchronized void removeProvider() {\n        if (!provider.isPresent()) {\n            return;\n        }\n\n        logger.info(\"Removing provider...\");\n        Security.removeProvider(provider.get().getName());\n\n        provider = Optional.empty();\n        logger.info(\"Removing provider...done\");\n    }\n\n    private class KeystoreInstanceImpl implements KeystoreInstance {\n\n        private final KeyStore keystore;\n        private final char[] password;\n\n        KeystoreInstanceImpl(KeyStore keystore, char[] password) {\n            this.keystore = keystore;\n            this.password = password;\n        }\n\n        @Override\n        public KeyStore getKeystore() {\n            return keystore;\n        }\n\n        @Override\n        public char[] getPassword() {\n            return password;\n        }\n\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/PKCS11KeystoreServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore;\n\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class PKCS11KeystoreServiceOptions {\n\n    private static final Property<String> PKCS11_LIBRARY_PROPERTY = new Property<>(\"library.path\", String.class);\n    private static final Property<String> PIN_PROPERTY = new Property<>(\"pin\", String.class);\n    private static final Property<Integer> SLOT_PROPERTY = new Property<>(\"slot\", Integer.class);\n    private static final Property<Integer> SLOT_LIST_INDEX_PROPERTY = new Property<>(\"slot.list.index\", Integer.class);\n    private static final Property<String> ENABLED_MECHANISMS_PROPERTY = new Property<>(\"enabled.mechanisms\",\n            String.class);\n    private static final Property<String> DISABLED_MECHANISMS_PROPERTY = new Property<>(\"disabled.mechanisms\",\n            String.class);\n    private static final Property<String> ATTRIBUTES_PROPERTY = new Property<>(\"attributes\", String.class);\n    private static final Property<String> CRL_STORE_PATH = new Property<>(\"crl.store.path\", String.class);\n\n    private final String ownPid;\n    private final Optional<String> libraryPath;\n    private final Optional<String> pin;\n    private final Optional<Integer> slot;\n    private final Optional<Integer> slotListIndex;\n    private final Optional<String> enabledMechanisms;\n    private final Optional<String> disabledMechanisms;\n    private final Optional<String> attributes;\n    private final Optional<String> crlStorePath;\n\n    public PKCS11KeystoreServiceOptions(final Map<String, Object> properties, final String ownPid) {\n        this.libraryPath = PKCS11_LIBRARY_PROPERTY.getOptional(properties);\n        this.pin = PIN_PROPERTY.getOptional(properties);\n        this.ownPid = ownPid;\n        this.slot = SLOT_PROPERTY.getOptional(properties);\n        this.slotListIndex = SLOT_LIST_INDEX_PROPERTY.getOptional(properties);\n        this.enabledMechanisms = ENABLED_MECHANISMS_PROPERTY.getOptional(properties).filter(s -> !s.trim().isEmpty());\n        this.disabledMechanisms = DISABLED_MECHANISMS_PROPERTY.getOptional(properties).filter(s -> !s.trim().isEmpty());\n        this.attributes = ATTRIBUTES_PROPERTY.getOptional(properties).filter(s -> !s.trim().isEmpty());\n        this.crlStorePath = CRL_STORE_PATH.getOptional(properties).filter(s -> !s.trim().isEmpty());\n    }\n\n    public Optional<String> getLibraryPath() {\n        return libraryPath;\n    }\n\n    public Optional<char[]> getPin(final CryptoService cryptoService) throws KuraException {\n        if (!pin.isPresent()) {\n            return Optional.empty();\n        }\n\n        return Optional.of(cryptoService.decryptAes(pin.get().toCharArray()));\n    }\n\n    public String getOwnPid() {\n        return ownPid;\n    }\n\n    public Optional<Integer> getSlot() {\n        return slot;\n    }\n\n    public Optional<Integer> getSlotListIndex() {\n        return slotListIndex;\n    }\n\n    public Optional<String> getEnabledMechanisms() {\n        return enabledMechanisms;\n    }\n\n    public Optional<String> getDisabledMechanisms() {\n        return disabledMechanisms;\n    }\n\n    public Optional<String> getAttributes() {\n        return attributes;\n    }\n\n    public Optional<String> getCrlStorePath() {\n        return crlStorePath;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(attributes, crlStorePath, disabledMechanisms, enabledMechanisms, libraryPath, ownPid, pin,\n                slot, slotListIndex);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof PKCS11KeystoreServiceOptions)) {\n            return false;\n        }\n        PKCS11KeystoreServiceOptions other = (PKCS11KeystoreServiceOptions) obj;\n        return Objects.equals(attributes, other.attributes) && Objects.equals(crlStorePath, other.crlStorePath)\n                && Objects.equals(disabledMechanisms, other.disabledMechanisms)\n                && Objects.equals(enabledMechanisms, other.enabledMechanisms)\n                && Objects.equals(libraryPath, other.libraryPath) && Objects.equals(ownPid, other.ownPid)\n                && Objects.equals(pin, other.pin) && Objects.equals(slot, other.slot)\n                && Objects.equals(slotListIndex, other.slotListIndex);\n    }\n\n    public Optional<String> buildSunPKCS11ProviderConfig() {\n        if (!this.libraryPath.isPresent()) {\n            return Optional.empty();\n        }\n\n        final StringBuilder builder = new StringBuilder();\n\n        builder.append(\"library = \").append(libraryPath.get()).append('\\n');\n\n        builder.append(\"name = kura.provider.\").append(ownPid).append('\\n');\n\n        if (slot.isPresent()) {\n            builder.append(\"slot = \").append(slot.get()).append('\\n');\n        }\n\n        if (slotListIndex.isPresent()) {\n            builder.append(\"slotListIndex = \").append(slotListIndex.get()).append('\\n');\n        }\n\n        if (enabledMechanisms.isPresent()) {\n            builder.append(\"enabledMechanisms = { \").append(enabledMechanisms.get()).append(\" }\\n\");\n        }\n\n        if (disabledMechanisms.isPresent()) {\n            builder.append(\"disabledMechanisms = { \").append(disabledMechanisms.get()).append(\" }\\n\");\n        }\n\n        if (attributes.isPresent()) {\n            builder.append(attributes.get());\n        }\n\n        return Optional.of(builder.toString());\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/crl/CRLManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.crl;\n\nimport java.io.Closeable;\nimport java.io.File;\nimport java.net.URI;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertStore;\nimport java.security.cert.X509CRL;\nimport java.security.cert.X509Certificate;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.OptionalLong;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.core.keystore.util.CRLUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CRLManager implements Closeable {\n\n    private static final Logger logger = LoggerFactory.getLogger(CRLManager.class);\n\n    private final CRLStore store;\n    private final ScheduledExecutorService updateExecutor = Executors.newSingleThreadScheduledExecutor();\n    private final ExecutorService downloadExecutor = Executors.newCachedThreadPool();\n\n    private final List<DistributionPointState> referencedDistributionPoints = new ArrayList<>();\n    private final long forceUpdateIntervalNanos;\n    private final long periodicReckeckIntervalMs;\n    private final CRLVerifier verifier;\n\n    private Optional<ScheduledFuture<?>> updateTask = Optional.empty();\n    private Optional<Listener> listener;\n\n    public CRLManager(final File storeFile, final long storeDelayMs, final long periodicRecheckIntervalMs,\n            final long forceUpdateIntervalMs, final CRLVerifier verifier) {\n        this.store = new CRLStore(storeFile, storeDelayMs);\n        this.periodicReckeckIntervalMs = periodicRecheckIntervalMs;\n        this.forceUpdateIntervalNanos = Duration.ofMillis(forceUpdateIntervalMs).toNanos();\n        this.verifier = verifier;\n        requestUpdate();\n    }\n\n    public void setListener(final Optional<Listener> listener) {\n        this.listener = listener;\n    }\n\n    public synchronized boolean addDistributionPoint(final Set<URI> uris) {\n        logger.info(\"referencing distribution points: {}\", uris);\n\n        final Optional<DistributionPointState> existing = this.referencedDistributionPoints.stream()\n                .filter(p -> p.distributionPoints.equals(uris)).findAny();\n\n        if (existing.isPresent()) {\n            existing.get().ref();\n            return false;\n        } else {\n            this.referencedDistributionPoints.add(new DistributionPointState(uris));\n            requestUpdate();\n            return true;\n        }\n    }\n\n    public synchronized boolean removeDistributionPoint(final Set<URI> uris) {\n        logger.info(\"unreferencing distribution points: {}\", uris);\n\n        if (this.referencedDistributionPoints.removeIf(p -> p.distributionPoints.equals(uris) && p.unref() <= 0)) {\n            requestUpdate();\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public boolean addTrustedCertificate(final X509Certificate entry) {\n\n        final Set<URI> distributionPoints;\n\n        try {\n            distributionPoints = CRLUtil.getCrlURIs(entry);\n        } catch (final Exception e) {\n            logger.warn(\"failed to get distribution points for {}\", entry.getSubjectX500Principal(), e);\n            return false;\n        }\n\n        if (distributionPoints.isEmpty()) {\n            logger.info(\"certificate {} has no CRL distribution points\", entry.getSubjectX500Principal());\n            return false;\n        }\n\n        return addDistributionPoint(distributionPoints);\n    }\n\n    public boolean removeTrustedCertificate(final X509Certificate entry) {\n\n        try {\n            final Set<URI> distributionPoints = CRLUtil.getCrlURIs(entry);\n\n            return removeDistributionPoint(distributionPoints);\n\n        } catch (final Exception e) {\n            logger.warn(\"failed to get distribution points for {}\", entry.getSubjectX500Principal(), e);\n            return false;\n        }\n    }\n\n    public synchronized List<X509CRL> getCrls() {\n        return this.store.getCRLs().stream().map(StoredCRL::getCrl).collect(Collectors.toList());\n    }\n\n    public CertStore getCertStore() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {\n        return this.store.getCertStore();\n    }\n\n    public CRLStore getCRLStore() {\n        return this.store;\n    }\n\n    @Override\n    public void close() {\n        this.listener = Optional.empty();\n        this.updateExecutor.shutdown();\n        this.downloadExecutor.shutdown();\n    }\n\n    private void requestUpdate() {\n        if (this.updateTask.isPresent()) {\n            this.updateTask.get().cancel(false);\n        }\n\n        this.updateTask = Optional.of(this.updateExecutor.scheduleWithFixedDelay(this::update, 5000,\n                this.periodicReckeckIntervalMs, TimeUnit.MILLISECONDS));\n    }\n\n    private synchronized void update() {\n\n        boolean changed = false;\n        final long now = System.nanoTime();\n\n        for (final DistributionPointState state : this.referencedDistributionPoints) {\n\n            final Optional<StoredCRL> storedCrl = this.store.getCRLs().stream()\n                    .filter(c -> c.getDistributionPoints().equals(state.distributionPoints)).findAny();\n\n            if (!storedCrl.isPresent() || storedCrl.get().isExpired() || !state.lastDownloadInstantNanos.isPresent()\n                    || now - state.lastDownloadInstantNanos.getAsLong() > this.forceUpdateIntervalNanos) {\n                final CompletableFuture<X509CRL> future = CRLUtil.fetchCRL(state.distributionPoints,\n                        this.downloadExecutor);\n\n                try {\n                    final X509CRL crl = future.get(1, TimeUnit.MINUTES);\n\n                    changed |= validateAndStoreCRL(now, state, storedCrl, crl);\n                } catch (final InterruptedException e) {\n                    Thread.currentThread().interrupt();\n                    logger.warn(\"failed to download CRL\", e);\n                    future.cancel(true);\n                } catch (final Exception e) {\n                    logger.warn(\"failed to download CRL\", e);\n                    future.cancel(true);\n                }\n            }\n        }\n\n        changed |= this.store.removeCRLs(c -> this.referencedDistributionPoints.stream()\n                .noneMatch(p -> p.distributionPoints.equals(c.getDistributionPoints())));\n\n        if (changed) {\n            this.listener.ifPresent(Listener::onCRLCacheChanged);\n        }\n    }\n\n    private boolean validateAndStoreCRL(final long now, final DistributionPointState state,\n            final Optional<StoredCRL> storedCrl, final X509CRL newCrl) {\n\n        if (storedCrl.isPresent()) {\n            final X509CRL stored = storedCrl.get().getCrl();\n\n            if (stored.equals(newCrl)) {\n                logger.info(\"current CRL is up to date\");\n                state.lastDownloadInstantNanos = OptionalLong.of(now);\n                return false;\n            }\n\n            if (!stored.getIssuerX500Principal().equals(newCrl.getIssuerX500Principal())) {\n                logger.warn(\"CRL issuer differs, not updating CRL\");\n                return false;\n            }\n        }\n\n        if (this.verifier.verifyCRL(newCrl)) {\n            this.store.storeCRL(new StoredCRL(state.distributionPoints, newCrl));\n            state.lastDownloadInstantNanos = OptionalLong.of(now);\n            return true;\n        } else {\n            logger.warn(\"CRL verification failed\");\n            return false;\n        }\n    }\n\n    private class DistributionPointState {\n\n        private int refCnt = 1;\n        private OptionalLong lastDownloadInstantNanos = OptionalLong.empty();\n        private final Set<URI> distributionPoints;\n\n        public DistributionPointState(Set<URI> distributionPoints) {\n            this.distributionPoints = distributionPoints;\n        }\n\n        int ref() {\n            this.refCnt++;\n            return this.refCnt;\n        }\n\n        int unref() {\n            this.refCnt--;\n            return this.refCnt;\n        }\n    }\n\n    public interface CRLVerifier {\n\n        public boolean verifyCRL(final X509CRL crl);\n    }\n\n    public interface Listener {\n\n        public void onCRLCacheChanged();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/crl/CRLManagerOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.crl;\n\nimport java.io.File;\nimport java.net.URI;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.util.configuration.Property;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CRLManagerOptions {\n\n    private static final Logger logger = LoggerFactory.getLogger(CRLManagerOptions.class);\n\n    private static final Property<Boolean> CRL_MANAGEMENT_ENABLED = new Property<>(\"crl.management.enabled\", false);\n    private static final Property<Long> CRL_UPDATE_INTERVAL = new Property<>(\"crl.update.interval\", 1L);\n    private static final Property<String> CRL_UPDATE_INTERVAL_TIME_UNIT = new Property<>(\n            \"crl.update.interval.time.unit\", TimeUnit.DAYS.name());\n    private static final Property<Long> CRL_CHECK_INTERVAL = new Property<>(\"crl.check.interval\", 5L);\n    private static final Property<String> CRL_CHECK_INTERVAL_TIME_UNIT = new Property<>(\"crl.check.interval.time.unit\",\n            TimeUnit.MINUTES.name());\n    private static final Property<String[]> CRL_URLS = new Property<>(\"crl.urls\", new String[0]);\n    private static final Property<String> CRL_STORE_PATH = new Property<>(\"crl.store.path\", String.class);\n    private static final Property<Boolean> CRL_VERIFICATION_ENABLED = new Property<>(\"verify.crl\", true);\n\n    private final boolean crlManagementEnabled;\n    private final long crlUpdateIntervalMs;\n    private final long crlCheckIntervalMs;\n    private final Set<URI> crlURIs;\n    private final Optional<File> crlStore;\n    private final boolean verifyCRL;\n\n    public CRLManagerOptions(final Map<String, Object> properties) {\n        this.crlManagementEnabled = CRL_MANAGEMENT_ENABLED.get(properties);\n        this.crlUpdateIntervalMs = extractInterval(properties, CRL_UPDATE_INTERVAL, CRL_UPDATE_INTERVAL_TIME_UNIT);\n        this.crlCheckIntervalMs = extractInterval(properties, CRL_CHECK_INTERVAL, CRL_CHECK_INTERVAL_TIME_UNIT);\n        this.crlURIs = extractCrlURIs(properties);\n        this.crlStore = CRL_STORE_PATH.getOptional(properties).filter(s -> !s.trim().isEmpty()).map(File::new);\n        this.verifyCRL = CRL_VERIFICATION_ENABLED.get(properties);\n    }\n\n    public boolean isCrlManagementEnabled() {\n        return this.crlManagementEnabled;\n    }\n\n    public long getCrlUpdateIntervalMs() {\n        return this.crlUpdateIntervalMs;\n    }\n\n    public long getCrlCheckIntervalMs() {\n        return crlCheckIntervalMs;\n    }\n\n    public Set<URI> getCrlURIs() {\n        return this.crlURIs;\n    }\n\n    public Optional<File> getStoreFile() {\n        return this.crlStore;\n    }\n\n    public boolean isCRLVerificationEnabled() {\n        return verifyCRL;\n    }\n\n    private static long extractInterval(final Map<String, Object> properties, final Property<Long> valueProperty,\n            final Property<String> timeUnitProperty) {\n        final long updateInterval = valueProperty.get(properties);\n        final TimeUnit timeUnit = TimeUnit.valueOf(timeUnitProperty.get(properties));\n\n        return timeUnit.toMillis(updateInterval);\n    }\n\n    private static Set<URI> extractCrlURIs(final Map<String, Object> properties) {\n        final String[] values = CRL_URLS.get(properties);\n\n        final Set<URI> result = new HashSet<>();\n\n        for (final String value : values) {\n            if (value == null || value.trim().isEmpty()) {\n                continue;\n            }\n\n            try {\n                result.add(new URI(value));\n            } catch (final Exception e) {\n                logger.warn(\"failed to parse URL: {}\", value, e);\n            }\n        }\n\n        return result;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(crlCheckIntervalMs, crlManagementEnabled, crlStore, crlURIs, crlUpdateIntervalMs,\n                verifyCRL);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof CRLManagerOptions)) {\n            return false;\n        }\n        CRLManagerOptions other = (CRLManagerOptions) obj;\n        return crlCheckIntervalMs == other.crlCheckIntervalMs && crlManagementEnabled == other.crlManagementEnabled\n                && Objects.equals(crlStore, other.crlStore) && Objects.equals(crlURIs, other.crlURIs)\n                && crlUpdateIntervalMs == other.crlUpdateIntervalMs && verifyCRL == other.verifyCRL;\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/crl/CRLStore.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.crl;\n\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.net.URI;\nimport java.nio.file.Files;\nimport java.nio.file.StandardCopyOption;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertStore;\nimport java.security.cert.CollectionCertStoreParameters;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Predicate;\n\nimport org.eclipse.kura.core.keystore.util.MappingCollection;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonValue;\n\npublic class CRLStore implements Closeable {\n\n    private static final Logger logger = LoggerFactory.getLogger(CRLStore.class);\n\n    private final File storeFile;\n    private final Map<Set<URI>, StoredCRL> crls = new HashMap<>();\n    private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();\n    private final long storeDelayMs;\n    private Optional<ScheduledFuture<?>> storeTask = Optional.empty();\n\n    public CRLStore(final File storeFile, final long storeDelayMs) {\n        this.storeFile = storeFile;\n        this.storeDelayMs = storeDelayMs;\n\n        if (storeFile.exists()) {\n            load();\n        } else {\n            final File parent = storeFile.getParentFile();\n\n            if (!parent.isDirectory() && !parent.mkdirs()) {\n                logger.warn(\"failed to create directory: {}\", parent);\n            }\n        }\n    }\n\n    public synchronized void storeCRL(final StoredCRL crl) {\n        this.crls.put(crl.getDistributionPoints(), crl);\n        requestStore();\n    }\n\n    public synchronized boolean removeCRLs(final Predicate<StoredCRL> predicate) {\n\n        boolean changed = false;\n\n        final Iterator<StoredCRL> iter = this.crls.values().iterator();\n\n        while (iter.hasNext()) {\n            final StoredCRL next = iter.next();\n\n            if (predicate.test(next)) {\n                logger.info(\"removing CRL: {}\", next.getCrl().getIssuerX500Principal());\n                changed = true;\n                iter.remove();\n            }\n        }\n\n        if (changed) {\n            requestStore();\n        }\n\n        return changed;\n    }\n\n    public Optional<StoredCRL> getCrl(final Set<URI> distributionPoints) {\n        return Optional.ofNullable(this.crls.get(distributionPoints));\n    }\n\n    public synchronized List<StoredCRL> getCRLs() {\n        return new ArrayList<>(crls.values());\n    }\n\n    public CertStore getCertStore() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {\n        return CertStore.getInstance(\"Collection\",\n                new CollectionCertStoreParameters(new MappingCollection<>(crls.values(), StoredCRL::getCrl)));\n    }\n\n    private void requestStore() {\n        final Optional<ScheduledFuture<?>> currentTask = this.storeTask;\n\n        if (currentTask.isPresent()) {\n            currentTask.get().cancel(false);\n        }\n\n        this.storeTask = Optional.of(this.executor.schedule(this::store, storeDelayMs, TimeUnit.MILLISECONDS));\n    }\n\n    private synchronized void load() {\n        try {\n            try (final Reader in = new InputStreamReader(new FileInputStream(this.storeFile))) {\n\n                final JsonArray array = Json.parse(in).asArray();\n\n                for (final JsonValue value : array) {\n                    final StoredCRL crl = StoredCRL.fromJson(value.asObject());\n\n                    logger.info(\"loaded CRL for {}\", crl.getCrl().getIssuerX500Principal());\n                    this.crls.put(crl.getDistributionPoints(), crl);\n                }\n            }\n        } catch (final Exception e) {\n            logger.warn(\"failed to load CRLs\", e);\n        }\n    }\n\n    private void store() {\n        try {\n            logger.info(\"storing CRLs...\");\n\n            final List<StoredCRL> currentCrls = getCRLs();\n\n            final JsonArray array = new JsonArray();\n\n            for (final StoredCRL crl : currentCrls) {\n                array.add(crl.toJson());\n            }\n\n            final File tmpFile = new File(this.storeFile.getParent(), this.storeFile.getName() + \"_\");\n\n            try (final Writer out = new FileWriter(tmpFile)) {\n                array.writeTo(out);\n            }\n\n            Files.move(tmpFile.toPath(), this.storeFile.toPath(), StandardCopyOption.REPLACE_EXISTING,\n                    StandardCopyOption.ATOMIC_MOVE);\n\n            logger.info(\"storing CRLs...done\");\n        } catch (final Exception e) {\n            logger.warn(\"failed to store CRLs\", e);\n        }\n    }\n\n    @Override\n    public void close() throws IOException {\n        executor.shutdown();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/crl/StoredCRL.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.crl;\n\nimport java.io.IOException;\nimport java.net.URI;\nimport java.security.cert.CRLException;\nimport java.security.cert.X509CRL;\nimport java.util.Base64;\nimport java.util.Base64.Decoder;\nimport java.util.Base64.Encoder;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.bouncycastle.cert.X509CRLHolder;\nimport org.bouncycastle.cert.jcajce.JcaX509CRLConverter;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.JsonValue;\n\npublic class StoredCRL {\n\n    private static final Logger logger = LoggerFactory.getLogger(StoredCRL.class);\n\n    private static final String DISTRIBUTION_POINTS_KEY = \"dps\";\n    private static final String BODY_KEY = \"body\";\n\n    private final Set<URI> distributionPoints;\n    private final X509CRL crl;\n\n    public StoredCRL(final Set<URI> distributionPoints, final X509CRL crl) {\n        this.distributionPoints = distributionPoints;\n        this.crl = crl;\n    }\n\n    public Set<URI> getDistributionPoints() {\n        return distributionPoints;\n    }\n\n    public X509CRL getCrl() {\n        return crl;\n    }\n\n    public boolean isExpired() {\n        final long now = System.currentTimeMillis();\n        final Date nextUpdate = crl.getNextUpdate();\n\n        return nextUpdate != null && nextUpdate.getTime() < now;\n    }\n\n    public static StoredCRL fromJson(final JsonObject object) throws IOException, CRLException {\n        final Set<URI> dps = new HashSet<>();\n\n        final JsonArray dpsArray = object.get(DISTRIBUTION_POINTS_KEY).asArray();\n\n        for (final JsonValue value : dpsArray) {\n            try {\n                dps.add(new URI(value.asString()));\n            } catch (final Exception e) {\n                logger.warn(\"failed to parse URI\", e);\n            }\n        }\n\n        final String body = object.get(BODY_KEY).asString();\n\n        final Decoder decoder = Base64.getDecoder();\n\n        final byte[] decoded = decoder.decode(body);\n\n        final X509CRLHolder holder = new X509CRLHolder(decoded);\n        return new StoredCRL(dps, new JcaX509CRLConverter().getCRL(holder));\n    }\n\n    public JsonObject toJson() throws CRLException {\n        final JsonObject result = new JsonObject();\n\n        final JsonArray dpsArray = new JsonArray();\n\n        for (final URI uri : this.distributionPoints) {\n            dpsArray.add(uri.toString());\n        }\n\n        result.add(DISTRIBUTION_POINTS_KEY, dpsArray);\n\n        final Encoder encoder = Base64.getEncoder();\n\n        final String body = encoder.encodeToString(crl.getEncoded());\n\n        result.add(BODY_KEY, body);\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/CRLUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URI;\nimport java.net.URLConnection;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509CRL;\nimport java.security.cert.X509Certificate;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutorService;\n\nimport org.bouncycastle.asn1.ASN1IA5String;\nimport org.bouncycastle.asn1.ASN1InputStream;\nimport org.bouncycastle.asn1.DEROctetString;\nimport org.bouncycastle.asn1.x509.CRLDistPoint;\nimport org.bouncycastle.asn1.x509.DistributionPoint;\nimport org.bouncycastle.asn1.x509.DistributionPointName;\nimport org.bouncycastle.asn1.x509.Extension;\nimport org.bouncycastle.asn1.x509.GeneralName;\nimport org.bouncycastle.asn1.x509.GeneralNames;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CRLUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(CRLUtil.class);\n\n    private CRLUtil() {\n    }\n\n    public static Set<URI> getCrlURIs(final X509Certificate cert) throws IOException {\n        final byte[] crlDistributionPoints = cert.getExtensionValue(Extension.cRLDistributionPoints.getId());\n\n        if (crlDistributionPoints == null) {\n            return Collections.emptySet();\n        }\n\n        try (final ASN1InputStream in0 = new ASN1InputStream(crlDistributionPoints);\n                final ASN1InputStream in = new ASN1InputStream(((DEROctetString) in0.readObject()).getOctets())) {\n\n            final DistributionPoint[] distributionPoints = CRLDistPoint.getInstance(in.readObject())\n                    .getDistributionPoints();\n\n            if (distributionPoints == null) {\n                return Collections.emptySet();\n            }\n\n            final Set<URI> result = new HashSet<>();\n\n            for (final DistributionPoint distributionPoint : distributionPoints) {\n\n                final DistributionPointName distributionPointName = distributionPoint.getDistributionPoint();\n\n                if (distributionPointName == null\n                        || distributionPointName.getType() != DistributionPointName.FULL_NAME) {\n                    logger.warn(\"failed to get distribution point name\");\n                    continue;\n                }\n\n                final GeneralName[] generalNames = GeneralNames.getInstance(distributionPointName.getName()).getNames();\n\n                for (final GeneralName name : generalNames) {\n                    if (name.getTagNo() == GeneralName.uniformResourceIdentifier) {\n                        final String uriString = ASN1IA5String.getInstance(name.getName()).getString();\n                        parseURI(uriString).ifPresent(result::add);\n                    }\n                }\n            }\n\n            return result;\n        }\n    }\n\n    public static CompletableFuture<X509CRL> fetchCRL(final Set<URI> uris, final ExecutorService executor) {\n        final CompletableFuture<X509CRL> result = new CompletableFuture<>();\n\n        executor.execute(() -> {\n            for (final URI uri : uris) {\n                logger.info(\"fetching CRL from: {}...\", uri);\n\n                try (final InputStream in = openConnection(uri)) {\n                    final CertificateFactory cf = CertificateFactory.getInstance(\"X.509\");\n                    final X509CRL crl = (X509CRL) cf.generateCRL(in);\n                    logger.info(\"fetching CRL from: {}...done\", uri);\n                    result.complete(crl);\n                    return;\n                } catch (final Exception e) {\n                    logger.warn(\"failed to fetch CRL from {}\", uri, e);\n                }\n\n                if (Thread.interrupted()) {\n                    logger.warn(\"interrupted\");\n                    result.completeExceptionally(new InterruptedException());\n                    return;\n                }\n            }\n            result.completeExceptionally(new IOException(\"failed to download CRL from: \" + uris));\n        });\n\n        return result;\n    }\n\n    private static InputStream openConnection(final URI uri) throws IOException {\n        final URLConnection connection = uri.toURL().openConnection();\n\n        if (connection instanceof HttpURLConnection) {\n            ((HttpURLConnection) connection).setRequestProperty(\"Accept\", \"*/*\");\n            ((HttpURLConnection) connection).setRequestProperty(\"Connection\", \"Close\");\n        }\n\n        return connection.getInputStream();\n    }\n\n    private static Optional<URI> parseURI(final String value) {\n        try {\n            return Optional.of(new URI(value));\n        } catch (final Exception e) {\n            logger.warn(\"failed to parse distribution point URL\", e);\n            return Optional.empty();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/CertificateInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * Identifies a certificate with its alias and the corresponding keystore name.\n * Further certificate information can be added (i.e. subjectDN, issuer, ecc.)\n *\n * @since 2.2\n */\npublic class CertificateInfo extends EntryInfo {\n\n    private String subjectDN;\n    private Collection<List<?>> subjectAN;\n    private String issuer;\n    private long startDate;\n    private long expirationDate;\n    private String algorithm;\n    private int size;\n    private String certificate;\n    private EntryType type = EntryType.TRUSTED_CERTIFICATE;\n\n    public CertificateInfo(String keystoreName, String alias) {\n        super(keystoreName, alias);\n    }\n\n    public String getSubjectDN() {\n        return this.subjectDN;\n    }\n\n    public void setSubjectDN(String subjectDN) {\n        this.subjectDN = subjectDN;\n    }\n\n    public Collection<List<?>> getSubjectAN() {\n        return this.subjectAN;\n    }\n\n    public void setSubjectAN(Collection<List<?>> subjectAN) {\n        this.subjectAN = subjectAN;\n    }\n\n    public String getIssuer() {\n        return this.issuer;\n    }\n\n    public void setIssuer(String issuer) {\n        this.issuer = issuer;\n    }\n\n    public long getStartDate() {\n        return this.startDate;\n    }\n\n    public void setStartDate(long startDate) {\n        this.startDate = startDate;\n    }\n\n    public long getExpirationDate() {\n        return this.expirationDate;\n    }\n\n    public void setExpirationDate(long expirationDate) {\n        this.expirationDate = expirationDate;\n    }\n\n    public String getAlgorithm() {\n        return this.algorithm;\n    }\n\n    public void setAlgorithm(String algorithm) {\n        this.algorithm = algorithm;\n    }\n\n    public int getSize() {\n        return this.size;\n    }\n\n    public void setSize(int size) {\n        this.size = size;\n    }\n\n    public String getCertificate() {\n        return this.certificate;\n    }\n\n    public void setCertificate(String certificate) {\n        this.certificate = certificate;\n    }\n\n    public EntryType getType() {\n        return this.type;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/CertificateUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *   Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.core.keystore.util;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.math.BigInteger;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.KeyFactory;\nimport java.security.KeyPair;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.Provider;\nimport java.security.PublicKey;\nimport java.security.Security;\nimport java.security.cert.CertStore;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.CollectionCertStoreParameters;\nimport java.security.cert.TrustAnchor;\nimport java.security.cert.X509Certificate;\nimport java.security.spec.X509EncodedKeySpec;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.bouncycastle.asn1.pkcs.PrivateKeyInfo;\nimport org.bouncycastle.asn1.x500.X500Name;\nimport org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;\nimport org.bouncycastle.cert.X509CertificateHolder;\nimport org.bouncycastle.cert.X509v3CertificateBuilder;\nimport org.bouncycastle.cert.jcajce.JcaCertStore;\nimport org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\nimport org.bouncycastle.openssl.PEMEncryptedKeyPair;\nimport org.bouncycastle.openssl.PEMKeyPair;\nimport org.bouncycastle.openssl.PEMParser;\nimport org.bouncycastle.openssl.bc.BcPEMDecryptorProvider;\nimport org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;\nimport org.bouncycastle.openssl.jcajce.JcaPEMWriter;\nimport org.bouncycastle.operator.ContentSigner;\nimport org.bouncycastle.operator.InputDecryptorProvider;\nimport org.bouncycastle.operator.OperatorCreationException;\nimport org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;\nimport org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;\nimport org.bouncycastle.pkcs.PKCSException;\nimport org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder;\nimport org.bouncycastle.util.Store;\nimport org.bouncycastle.util.io.pem.PemObject;\nimport org.bouncycastle.util.io.pem.PemReader;\n\npublic class CertificateUtil {\n\n    private CertificateUtil() {\n\n    }\n\n    public static java.security.cert.X509Certificate toJavaX509Certificate(Object o) throws Exception {\n        CertificateFactory fac = CertificateFactory.getInstance(\"X509\");\n        if (o instanceof X509CertificateHolder) {\n            return (java.security.cert.X509Certificate) fac\n                    .generateCertificate(new ByteArrayInputStream(((X509CertificateHolder) o).getEncoded()));\n        } else if (o instanceof X509Certificate) {\n            return (java.security.cert.X509Certificate) fac\n                    .generateCertificate(new ByteArrayInputStream(((X509Certificate) o).getEncoded()));\n        } else if (o instanceof java.security.cert.X509Certificate) {\n            return (java.security.cert.X509Certificate) o;\n        } else if (o instanceof PemObject) {\n            return (java.security.cert.X509Certificate) fac\n                    .generateCertificate(new ByteArrayInputStream(((PemObject) o).getContent()));\n        }\n        throw new IllegalArgumentException(\"Object not one of X509CertificateHolder, X509Certificate or PemObject.\");\n    }\n\n    public static Set<TrustAnchor> toTrustAnchor(List<X509Certificate> certificates) throws Exception {\n\n        Set<TrustAnchor> out = new HashSet<>();\n        for (X509Certificate c : certificates) {\n            out.add(new TrustAnchor(c, null));\n        }\n\n        return out;\n    }\n\n    public static String x509CertificateToPem(final Certificate cert) throws IOException {\n        final StringWriter writer = new StringWriter();\n        final JcaPEMWriter pemWriter = new JcaPEMWriter(writer);\n        pemWriter.writeObject(cert);\n        pemWriter.flush();\n        pemWriter.close();\n        return writer.toString();\n    }\n\n    public static List<X509Certificate> readPemCertificates(String pemString) throws Exception {\n        List<X509Certificate> certs = new ArrayList<>();\n        try (Reader r = new StringReader(pemString); PemReader reader = new PemReader(r);) {\n\n            PemObject o;\n\n            while ((o = reader.readPemObject()) != null) {\n                certs.add(toJavaX509Certificate(o));\n            }\n        }\n        return certs;\n    }\n\n    /**\n     *\n     * @param pemString\n     *            String in PEM format with PKCS#8 syntax\n     * @param password\n     * @return\n     * @throws IOException\n     * @throws PKCSException\n     */\n    public static PrivateKey readEncryptedPrivateKey(String pemString, String password)\n            throws IOException, PKCSException {\n        try (Reader r = new StringReader(pemString); PEMParser pemParser = new PEMParser(r);) {\n\n            PrivateKeyInfo privateKeyInfo;\n            JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(\"BC\");\n\n            Object o = pemParser.readObject();\n\n            if (o instanceof PKCS8EncryptedPrivateKeyInfo) {\n\n                PKCS8EncryptedPrivateKeyInfo epki = (PKCS8EncryptedPrivateKeyInfo) o;\n\n                JcePKCSPBEInputDecryptorProviderBuilder builder = new JcePKCSPBEInputDecryptorProviderBuilder()\n                        .setProvider(\"BC\");\n\n                InputDecryptorProvider idp = builder.build(password.toCharArray());\n                privateKeyInfo = epki.decryptPrivateKeyInfo(idp);\n            } else if (o instanceof PEMEncryptedKeyPair) {\n\n                PEMEncryptedKeyPair epki = (PEMEncryptedKeyPair) o;\n                PEMKeyPair pkp = epki.decryptKeyPair(new BcPEMDecryptorProvider(password.toCharArray()));\n\n                privateKeyInfo = pkp.getPrivateKeyInfo();\n            } else {\n                throw new PKCSException(\"Invalid encrypted private key class: \" + o.getClass().getName());\n            }\n            return converter.getPrivateKey(privateKeyInfo);\n        }\n    }\n\n    public static PublicKey readPublicKey(String pemString, String algorithm) throws Exception {\n        KeyFactory factory = KeyFactory.getInstance(algorithm);\n\n        try (Reader r = new StringReader(pemString); PemReader pemReader = new PemReader(r)) {\n\n            PemObject pemObject = pemReader.readPemObject();\n            byte[] content = pemObject.getContent();\n            X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);\n            return factory.generatePublic(pubKeySpec);\n        }\n    }\n\n    public static X509Certificate[] generateCertificateChain(KeyPair keyPair, String signatureAlgorithm,\n            String attributes, Date startDate, Date endDate) throws OperatorCreationException, CertificateException {\n        Provider bcProvider = new BouncyCastleProvider();\n        Security.addProvider(bcProvider);\n        X500Name dnName = new X500Name(attributes);\n\n        // Use the timestamp as serial number\n        BigInteger certSerialNumber = BigInteger.valueOf(System.currentTimeMillis());\n\n        SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());\n        X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(dnName, certSerialNumber, startDate,\n                endDate, dnName, subjectPublicKeyInfo);\n        ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(bcProvider)\n                .build(keyPair.getPrivate());\n        X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner);\n\n        return new X509Certificate[] { new JcaX509CertificateConverter().getCertificate(certificateHolder) };\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static Store<X509CertificateHolder> toX509CertificateHolderStore(String pemString) throws Exception {\n\n        List<X509Certificate> certs = readPemCertificates(pemString);\n\n        List<X509CertificateHolder> x509CertificateHolderCerts = certs.stream().map(cert -> {\n            try {\n                return new X509CertificateHolder(cert.getEncoded());\n            } catch (CertificateEncodingException | IOException e) {\n                throw new RuntimeException(e);\n            }\n        }).collect(Collectors.toList());\n\n        return new JcaCertStore(x509CertificateHolderCerts);\n    }\n\n    public static CertStore toCertStore(Store<?> store) throws Exception {\n        List<?> certificatesX509 = store.getMatches(null).stream().map(t -> {\n            try {\n                return toJavaX509Certificate(t);\n            } catch (Exception ignore) {\n            }\n            return null;\n        }).collect(Collectors.toList());\n\n        try {\n            return CertStore.getInstance(\"Collection\", new CollectionCertStoreParameters(certificatesX509));\n        } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException e) {\n            throw new Exception(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/CsrInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\npublic class CsrInfo extends EntryInfo {\n\n    private String signatureAlgorithm;\n    private String attributes;\n\n    public CsrInfo(String keystoreServicePid, String alias) {\n        super(keystoreServicePid, alias);\n    }\n\n    public String getSignatureAlgorithm() {\n        return this.signatureAlgorithm;\n    }\n\n    public void setSignatureAlgorithm(String signatureAlgorithm) {\n        this.signatureAlgorithm = signatureAlgorithm;\n    }\n\n    public String getAttributes() {\n        return this.attributes;\n    }\n\n    public void setAttributes(String attributes) {\n        this.attributes = attributes;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/EntryInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\npublic class EntryInfo {\n\n    private final String keystoreServicePid;\n    private final String alias;\n\n    public EntryInfo(String keystoreServicePid, String alias) {\n        this.keystoreServicePid = keystoreServicePid;\n        this.alias = alias;\n    }\n\n    public String getKeystoreServicePid() {\n        return this.keystoreServicePid;\n    }\n\n    public String getAlias() {\n        return this.alias;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/EntryType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\npublic enum EntryType {\n\n    TRUSTED_CERTIFICATE,\n    PRIVATE_KEY,\n    KEY_PAIR,\n    CSR;\n\n    public static EntryType valueOfType(String type) {\n        for (EntryType e : values()) {\n            if (e.name().equals(type)) {\n                return e;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/KeyPairInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\npublic class KeyPairInfo extends EntryInfo {\n\n    private String algorithm;\n    private int size;\n    private String signatureAlgorithm;\n    private String attributes;\n\n    public KeyPairInfo(String keystoreName, String alias) {\n        super(keystoreName, alias);\n    }\n\n    public String getAlgorithm() {\n        return this.algorithm;\n    }\n\n    public void setAlgorithm(String algorithm) {\n        this.algorithm = algorithm;\n    }\n\n    public int getSize() {\n        return this.size;\n    }\n\n    public void setSize(int size) {\n        this.size = size;\n    }\n\n    public String getSignatureAlgorithm() {\n        return this.signatureAlgorithm;\n    }\n\n    public void setSignatureAlgorithm(String signatureAlgorithm) {\n        this.signatureAlgorithm = signatureAlgorithm;\n    }\n\n    public String getAttributes() {\n        return this.attributes;\n    }\n\n    public void setAttributes(String attributes) {\n        this.attributes = attributes;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/KeystoreUtils.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.nio.charset.StandardCharsets;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.PrivateKey;\nimport java.security.Security;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Collection;\n\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\nimport org.bouncycastle.openssl.PEMParser;\nimport org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;\n\npublic class KeystoreUtils {\n\n    private KeystoreUtils() {\n        // Empty constructor\n    }\n\n    public static PrivateKeyEntry createPrivateKey(String privateKey, String publicKey)\n            throws IOException, GeneralSecurityException {\n        // Works with RSA and DSA. EC is not supported since the certificate is encoded\n        // with ECDSA while the corresponding private key with EC.\n        // This cause an error when the PrivateKeyEntry is generated.\n        Certificate[] certs = parsePublicCertificates(publicKey);\n\n        Security.addProvider(new BouncyCastleProvider());\n        PEMParser pemParser = new PEMParser(new StringReader(privateKey));\n        Object object = pemParser.readObject();\n        pemParser.close();\n        JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(\"BC\");\n        PrivateKey privkey = null;\n        if (object instanceof org.bouncycastle.asn1.pkcs.PrivateKeyInfo) {\n            privkey = converter.getPrivateKey((org.bouncycastle.asn1.pkcs.PrivateKeyInfo) object);\n        } else if (object instanceof org.bouncycastle.openssl.PEMKeyPair) {\n            privkey = converter.getKeyPair((org.bouncycastle.openssl.PEMKeyPair) object).getPrivate();\n        } else {\n            throw new IOException(\"PrivateKey not recognized.\");\n        }\n        return new PrivateKeyEntry(privkey, certs);\n    }\n\n    public static X509Certificate[] parsePublicCertificates(String certificates) throws CertificateException {\n        CertificateFactory certFactory = CertificateFactory.getInstance(\"X.509\");\n        ByteArrayInputStream is = new ByteArrayInputStream(certificates.getBytes(StandardCharsets.UTF_8));\n\n        final Collection<? extends Certificate> decodedCertificates = certFactory.generateCertificates(is);\n\n        final ArrayList<X509Certificate> result = new ArrayList<>();\n\n        for (final Certificate cert : decodedCertificates) {\n            if (!(cert instanceof X509Certificate)) {\n                throw new CertificateException(\"Provided certificate is not a X509Certificate\");\n            }\n\n            result.add((X509Certificate) cert);\n        }\n\n        return result.toArray(new X509Certificate[result.size()]);\n    }\n\n    public static TrustedCertificateEntry createCertificateEntry(String certificate) throws CertificateException {\n        CertificateFactory certFactory = CertificateFactory.getInstance(\"X.509\");\n        ByteArrayInputStream is = new ByteArrayInputStream(certificate.getBytes(StandardCharsets.UTF_8));\n        X509Certificate cert = (X509Certificate) certFactory.generateCertificate(is);\n        return new TrustedCertificateEntry(cert);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/MappingCollection.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\npublic class MappingCollection<T, U> implements Collection<U> {\n\n    private final Collection<T> source;\n    private final Function<T, U> func;\n\n    public MappingCollection(final Collection<T> source, final Function<T, U> func) {\n        this.source = source;\n        this.func = func;\n    }\n\n    @Override\n    public int size() {\n        return source.size();\n    }\n\n    @Override\n    public boolean isEmpty() {\n        return source.isEmpty();\n    }\n\n    @Override\n    public boolean contains(Object o) {\n        return source.stream().map(func).collect(Collectors.toList()).contains(o);\n    }\n\n    @Override\n    public Iterator<U> iterator() {\n        final Iterator<T> iter = source.iterator();\n        return new Iterator<U>() {\n\n            @Override\n            public boolean hasNext() {\n                return iter.hasNext();\n            }\n\n            @Override\n            public U next() {\n                return func.apply(iter.next());\n            }\n        };\n    }\n\n    @Override\n    public Object[] toArray() {\n        return source.stream().map(func).collect(Collectors.toList()).toArray();\n    }\n\n    @Override\n    public <V> V[] toArray(V[] a) {\n        return source.stream().map(func).collect(Collectors.toList()).toArray(a);\n    }\n\n    @Override\n    public boolean add(U e) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean remove(Object o) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean containsAll(Collection<?> c) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean addAll(Collection<? extends U> c) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean removeAll(Collection<?> c) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean retainAll(Collection<?> c) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void clear() {\n        throw new UnsupportedOperationException();\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/PrivateKeyInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\npublic class PrivateKeyInfo extends EntryInfo {\n\n    private String algorithm;\n    private int size;\n    private String privateKey;\n    private String[] certificateChain;\n    private EntryType type = EntryType.PRIVATE_KEY;\n\n    public PrivateKeyInfo(String keystoreServicePid, String alias) {\n        super(keystoreServicePid, alias);\n    }\n\n    public String getAlgorithm() {\n        return this.algorithm;\n    }\n\n    public void setAlgorithm(String algorithm) {\n        this.algorithm = algorithm;\n    }\n\n    public int getSize() {\n        return this.size;\n    }\n\n    public void setSize(int size) {\n        this.size = size;\n    }\n\n    public String getPrivateKey() {\n        return this.privateKey;\n    }\n\n    public void setPrivateKey(String privateKey) {\n        this.privateKey = privateKey;\n    }\n\n    public String[] getCertificateChain() {\n        return this.certificateChain;\n    }\n\n    public void setCertificateChain(String[] certificateChain) {\n        this.certificateChain = certificateChain;\n    }\n\n    public EntryType getType() {\n        return this.type;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.status\nBundle-SymbolicName: org.eclipse.kura.core.status;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.gpio;version=\"[1.0,2.0)\",\n org.eclipse.kura.status;version=\"[1.0,1.1)\",\n org.eclipse.kura.system;version=\"[1.0,2.0)\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/OSGI-INF/status.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" name=\"org.eclipse.kura.status.CloudConnectionStatusService\">\n   <implementation class=\"org.eclipse.kura.core.status.CloudConnectionStatusServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.status.CloudConnectionStatusService\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.status.CloudConnectionStatusService\"/>\n   <reference name=\"SystemService\" \n              cardinality=\"1..1\" \n              policy=\"static\"\n              bind=\"setSystemService\"\n              unbind=\"unsetSystemService\"\n              interface=\"org.eclipse.kura.system.SystemService\"/>\n   <reference name=\"GPIOService\" \n              cardinality=\"0..1\" \n              policy=\"dynamic\"\n              bind=\"setGPIOService\"\n              unbind=\"unsetGPIOService\"\n              interface=\"org.eclipse.kura.gpio.GPIOService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.eclipse.osgi,\\\n                     org.eclipse.kura.core\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n     Red Hat Inc\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.status</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.core.status.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/CloudConnectionStatusServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.status;\n\nimport java.io.File;\nimport java.util.HashSet;\nimport java.util.Optional;\nimport java.util.Properties;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport org.eclipse.kura.core.status.GpioLedManager.GpioIdentifier;\nimport org.eclipse.kura.core.status.runnables.BlinkStatusRunnable;\nimport org.eclipse.kura.core.status.runnables.HeartbeatStatusRunnable;\nimport org.eclipse.kura.core.status.runnables.LogStatusRunnable;\nimport org.eclipse.kura.core.status.runnables.OnOffStatusRunnable;\nimport org.eclipse.kura.core.status.runnables.StatusRunnable;\nimport org.eclipse.kura.gpio.GPIOService;\nimport org.eclipse.kura.status.CloudConnectionStatusComponent;\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\nimport org.eclipse.kura.status.CloudConnectionStatusService;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudConnectionStatusServiceImpl implements CloudConnectionStatusService {\n\n    private static final String STATUS_NOTIFICATION_URL = \"ccs.status.notification.url\";\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudConnectionStatusServiceImpl.class);\n\n    private SystemService systemService;\n    private Optional<GPIOService> gpioService = Optional.empty();\n\n    private final ExecutorService notificationExecutor;\n    private Future<?> notificationWorker;\n\n    private final IdleStatusComponent idleComponent;\n\n    private CloudConnectionStatusEnum currentStatus = null;\n\n    private final HashSet<CloudConnectionStatusComponent> componentRegistry = new HashSet<>();\n\n    private Properties properties;\n\n    private StatusRunnable statusRunnable;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n    public CloudConnectionStatusServiceImpl() {\n        super();\n        this.notificationExecutor = Executors.newSingleThreadExecutor();\n        this.idleComponent = new IdleStatusComponent();\n    }\n\n    public void setSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    public void unsetSystemService(SystemService systemService) {\n        this.systemService = null;\n    }\n\n    public void setGPIOService(GPIOService gpioService) {\n        this.gpioService = Optional.of(gpioService);\n    }\n\n    public void unsetGPIOService(GPIOService gpioService) {\n        this.gpioService = Optional.empty();\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) {\n        logger.info(\"Activating CloudConnectionStatus service...\");\n\n        String urlFromConfig = this.systemService.getProperties().getProperty(STATUS_NOTIFICATION_URL,\n                CloudConnectionStatusURL.CCS + CloudConnectionStatusURL.NONE);\n\n        this.properties = CloudConnectionStatusURL.parseURL(urlFromConfig);\n\n        register(this.idleComponent);\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.info(\"Deactivating CloudConnectionStatus service...\");\n\n        this.notificationExecutor.shutdownNow();\n\n        unregister(this.idleComponent);\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Cloud Connection Status APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public void register(CloudConnectionStatusComponent component) {\n        this.componentRegistry.add(component);\n        internalUpdateStatus();\n    }\n\n    @Override\n    public void unregister(CloudConnectionStatusComponent component) {\n        this.componentRegistry.remove(component);\n        internalUpdateStatus();\n    }\n\n    @Override\n    public boolean updateStatus(CloudConnectionStatusComponent component, CloudConnectionStatusEnum status) {\n        try {\n            component.setNotificationStatus(status);\n            internalUpdateStatus();\n        } catch (Exception ex) {\n            return false;\n        }\n        return true;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private Methods\n    //\n    // ----------------------------------------------------------------\n\n    private void internalUpdateStatus() {\n\n        CloudConnectionStatusComponent maxPriorityComponent = this.idleComponent;\n\n        for (CloudConnectionStatusComponent c : this.componentRegistry) {\n            if (c.getNotificationPriority() > maxPriorityComponent.getNotificationPriority()) {\n                maxPriorityComponent = c;\n            }\n        }\n\n        if (this.currentStatus == null || this.currentStatus != maxPriorityComponent.getNotificationStatus()) {\n            this.currentStatus = maxPriorityComponent.getNotificationStatus();\n\n            if (this.statusRunnable != null) {\n                this.statusRunnable.stopRunnable();\n            }\n            if (this.notificationWorker != null) {\n                this.notificationWorker.cancel(true);\n                this.notificationWorker = null;\n            }\n\n            // Avoid NPE if CloudConnectionStatusComponent doesn't initialize its internal status.\n            // Defaults to OFF\n            this.currentStatus = this.currentStatus == null ? CloudConnectionStatusEnum.OFF : this.currentStatus;\n\n            this.statusRunnable = getRunnable(this.currentStatus);\n            this.notificationWorker = this.notificationExecutor.submit(this.statusRunnable);\n        }\n    }\n\n    private StatusRunnable getRunnable(CloudConnectionStatusEnum status) {\n        StatusRunnable runnable = null;\n\n        StatusNotificationTypeEnum notificationType = Optional\n                .ofNullable(this.properties.get(CloudConnectionStatusURL.NOTIFICATION_TYPE))\n                .filter(StatusNotificationTypeEnum.class::isInstance).map(StatusNotificationTypeEnum.class::cast)\n                .orElseGet(() -> {\n                    logger.warn(\"Invalid {} property, disabiling cloud connection status notifications\",\n                            STATUS_NOTIFICATION_URL);\n                    return StatusNotificationTypeEnum.NONE;\n                });\n\n        switch (notificationType) {\n        case LED:\n            if (this.properties.get(\"linux_led\") instanceof String) {\n                runnable = getLinuxStatusWorker(status);\n            }\n            if (runnable == null && this.properties.get(\"led\") instanceof GpioIdentifier) {\n                runnable = getGpioStatusWorker(status);\n            }\n            if (runnable == null) {\n                runnable = getLogStatusWorker(status);\n            }\n            break;\n        case LOG:\n            runnable = getLogStatusWorker(status);\n            break;\n        default:\n            runnable = getNoneStatusWorker();\n        }\n        return runnable;\n    }\n\n    private StatusRunnable getNoneStatusWorker() {\n        return new StatusRunnable() {\n\n            @Override\n            public void run() {\n                /* Empty runnable */ }\n\n            @Override\n            public void stopRunnable() {\n                /* Empty runnable */\n            }\n        };\n    }\n\n    private StatusRunnable getLogStatusWorker(CloudConnectionStatusEnum status) {\n        return new LogStatusRunnable(status);\n    }\n\n    private StatusRunnable getLinuxStatusWorker(CloudConnectionStatusEnum status) {\n        StatusRunnable runnable = null;\n\n        String ledPath = this.properties.getProperty(\"linux_led\");\n        File f = new File(ledPath);\n        if (f.exists() && f.isDirectory()) {\n            LedManager linuxLedManager = new LinuxLedManager(ledPath);\n            runnable = createLedRunnable(status, linuxLedManager);\n        }\n        return runnable;\n    }\n\n    private StatusRunnable getGpioStatusWorker(CloudConnectionStatusEnum status) {\n        if (!this.gpioService.isPresent()) {\n            return null;\n        }\n\n        final Object rawIdentifier = this.properties.get(\"led\");\n        final GpioIdentifier identifier;\n\n        if (rawIdentifier instanceof GpioIdentifier) {\n            identifier = (GpioIdentifier) rawIdentifier;\n        } else {\n            throw new IllegalStateException(\"invaild gpio identifier: \" + rawIdentifier);\n        }\n\n        final boolean inverted = Boolean.TRUE.equals(this.properties.get(\"inverted\"));\n        LedManager gpioLedManager = new GpioLedManager(this.gpioService.get(), identifier, inverted);\n\n        return createLedRunnable(status, gpioLedManager);\n    }\n\n    private StatusRunnable createLedRunnable(CloudConnectionStatusEnum status, LedManager linuxLedManager) {\n        StatusRunnable runnable;\n        switch (status) {\n        case ON:\n            runnable = new OnOffStatusRunnable(linuxLedManager, true);\n            break;\n        case OFF:\n            runnable = new OnOffStatusRunnable(linuxLedManager, false);\n            break;\n        case SLOW_BLINKING:\n            runnable = new BlinkStatusRunnable(linuxLedManager);\n            break;\n        case FAST_BLINKING:\n            runnable = new BlinkStatusRunnable(linuxLedManager);\n            break;\n        default:\n            runnable = new HeartbeatStatusRunnable(linuxLedManager);\n        }\n        return runnable;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/CloudConnectionStatusURL.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Locale;\nimport java.util.Properties;\n\nimport org.eclipse.kura.core.status.GpioLedManager.GpioIdentifier;\nimport org.eclipse.kura.core.status.GpioLedManager.GpioName;\nimport org.eclipse.kura.core.status.GpioLedManager.GpioTerminal;\n\npublic class CloudConnectionStatusURL {\n\n    public static final String NOTIFICATION_TYPE = \"notification_type\";\n    public static final String CCS = \"ccs:\";\n    public static final String LED = \"led:\";\n    public static final String LED_NAME_PREFIX = \"name:\";\n    public static final String LED_TERMINAL_PREFIX = \"terminal:\";\n    public static final String LINUX_LED = \"linux_led:\";\n    public static final String LOG = \"log\";\n    public static final String NONE = \"none\";\n\n    public static final String INVERTED = \":inverted\";\n\n    private static final String CASE_INSENSITIVE_PREFIX = \"(?i)\";\n    private static final String CCS_NOTIFICATION_URLS_SEPARATOR = \";\";\n\n    private CloudConnectionStatusURL() {\n    }\n\n    public static Properties parseURL(String ccsUrl) {\n        requireNonNull(ccsUrl);\n\n        String urlImage = ccsUrl;\n\n        Properties props = new Properties();\n\n        if (urlImage.toLowerCase(Locale.ENGLISH).startsWith(CCS)) {\n            urlImage = urlImage.replaceAll(CASE_INSENSITIVE_PREFIX + CCS, \"\");\n            props.put(\"url\", ccsUrl);\n\n            String[] urls = urlImage.split(CCS_NOTIFICATION_URLS_SEPARATOR);\n            for (String url : urls) {\n                props.putAll(parseUrlType(url));\n            }\n        } else {\n            props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.NONE);\n        }\n\n        return props;\n    }\n\n    private static Properties parseUrlType(String urlImage) {\n        Properties props = new Properties();\n        String urlLowerCase = urlImage.toLowerCase(Locale.ENGLISH);\n        if (urlLowerCase.startsWith(LED)) {\n            // Cloud Connection Status on LED\n            String ledString = urlImage.substring(4);\n            try {\n\n                final boolean inverted = urlLowerCase.endsWith(INVERTED);\n\n                if (inverted) {\n                    ledString = ledString.substring(0, ledString.length() - INVERTED.length());\n                }\n\n                props.put(\"inverted\", inverted);\n\n                final GpioIdentifier identifier = parseLedIdentifier(ledString);\n\n                props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.LED);\n                props.put(\"led\", identifier);\n            } catch (Exception ex) {\n                // Do nothing\n            }\n        } else if (urlLowerCase.startsWith(LINUX_LED)) {\n            String ledPath = urlImage.substring(LINUX_LED.length());\n            props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.LED);\n            props.put(\"linux_led\", ledPath);\n        } else if (urlLowerCase.startsWith(LOG)) {\n            props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.LOG);\n        } else if (urlLowerCase.startsWith(NONE)) {\n            props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.NONE);\n        }\n        return props;\n    }\n\n    private static GpioIdentifier parseLedIdentifier(final String identifier) {\n        if (identifier.toLowerCase().startsWith(LED_NAME_PREFIX)) {\n            final String name = identifier.substring(LED_NAME_PREFIX.length());\n\n            if (!name.isEmpty()) {\n                return new GpioName(name);\n            }\n        } else {\n            final String number;\n\n            if (identifier.toLowerCase().startsWith(LED_TERMINAL_PREFIX)) {\n                number = identifier.substring(LED_TERMINAL_PREFIX.length());\n            } else {\n                number = identifier;\n            }\n\n            return new GpioTerminal(Integer.parseInt(number.trim()));\n        }\n\n        throw new IllegalArgumentException(\"invalid GPIO identifier \" + identifier);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/GpioLedManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status;\n\nimport java.io.IOException;\nimport java.util.Objects;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.gpio.GPIOService;\nimport org.eclipse.kura.gpio.KuraClosedDeviceException;\nimport org.eclipse.kura.gpio.KuraGPIODeviceException;\nimport org.eclipse.kura.gpio.KuraGPIODirection;\nimport org.eclipse.kura.gpio.KuraGPIOMode;\nimport org.eclipse.kura.gpio.KuraGPIOPin;\nimport org.eclipse.kura.gpio.KuraGPIOTrigger;\nimport org.eclipse.kura.gpio.KuraUnavailableDeviceException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class GpioLedManager implements LedManager {\n\n    private static final Logger logger = LoggerFactory.getLogger(GpioLedManager.class);\n\n    private final GpioIdentifier identifier;\n    private final GPIOService gpioService;\n    private final boolean inverted;\n\n    public GpioLedManager(GPIOService gpioService, GpioIdentifier identifier) {\n        this(gpioService, identifier, false);\n    }\n\n    public GpioLedManager(GPIOService gpioService, GpioIdentifier identifier, boolean inverted) {\n        this.identifier = identifier;\n        this.gpioService = gpioService;\n        this.inverted = inverted;\n    }\n\n    public void writeLed(boolean enabled) throws KuraException {\n        final KuraGPIOPin notificationLED;\n\n        if (identifier instanceof GpioTerminal) {\n            notificationLED = this.gpioService.getPinByTerminal(((GpioTerminal) identifier).getNumber(),\n                    KuraGPIODirection.OUTPUT, KuraGPIOMode.OUTPUT_OPEN_DRAIN, KuraGPIOTrigger.NONE);\n        } else {\n            notificationLED = this.gpioService.getPinByName(((GpioName) identifier).getName(), KuraGPIODirection.OUTPUT,\n                    KuraGPIOMode.OUTPUT_OPEN_DRAIN, KuraGPIOTrigger.NONE);\n        }\n\n        try {\n            if (!notificationLED.isOpen()) {\n                notificationLED.open();\n                logger.info(\"CloudConnectionStatus active on LED {}.\", identifier);\n            }\n            notificationLED.setValue(enabled ^ inverted);\n\n        } catch (KuraGPIODeviceException | KuraUnavailableDeviceException | IOException e) {\n            logger.error(\"Error activating CloudConnectionStatus LED!\");\n            throw new KuraException(KuraErrorCode.UNAVAILABLE_DEVICE);\n        } catch (KuraClosedDeviceException e) {\n            logger.error(\"Error accessing to the specified LED!\");\n            throw new KuraException(KuraErrorCode.UNAVAILABLE_DEVICE);\n        }\n    }\n\n    public interface GpioIdentifier {\n    }\n\n    public static class GpioTerminal implements GpioIdentifier {\n\n        private final int number;\n\n        public GpioTerminal(final int number) {\n            this.number = number;\n        }\n\n        public int getNumber() {\n            return number;\n        }\n\n        @Override\n        public String toString() {\n            return Integer.toString(number);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(number);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (!(obj instanceof GpioTerminal)) {\n                return false;\n            }\n            GpioTerminal other = (GpioTerminal) obj;\n            return number == other.number;\n        }\n\n    }\n\n    public static class GpioName implements GpioIdentifier {\n\n        private final String name;\n\n        public GpioName(String name) {\n            this.name = name;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        @Override\n        public String toString() {\n            return name;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(name);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (!(obj instanceof GpioName)) {\n                return false;\n            }\n            GpioName other = (GpioName) obj;\n            return Objects.equals(name, other.name);\n        }\n\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/IdleStatusComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status;\n\nimport org.eclipse.kura.status.CloudConnectionStatusComponent;\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\nimport org.eclipse.kura.status.CloudConnectionStatusService;\n\npublic class IdleStatusComponent implements CloudConnectionStatusComponent {\n\n    @Override\n    public int getNotificationPriority() {\n        return CloudConnectionStatusService.PRIORITY_MIN;\n    }\n\n    @Override\n    public CloudConnectionStatusEnum getNotificationStatus() {\n        return CloudConnectionStatusEnum.OFF;\n    }\n\n    @Override\n    public void setNotificationStatus(CloudConnectionStatusEnum status) {\n        // We need a always present minimum priority status of OFF, se we don't want\n        // the default notification status to be changed.\n\n        // Do nothing\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/LedManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status;\n\nimport org.eclipse.kura.KuraException;\n\npublic interface LedManager {\n\n    public void writeLed(boolean enabled) throws KuraException;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/LinuxLedManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status;\n\nimport java.io.BufferedWriter;\nimport java.io.FileWriter;\nimport java.io.IOException;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class LinuxLedManager implements LedManager {\n\n    private static final Logger logger = LoggerFactory.getLogger(LinuxLedManager.class);\n\n    private final String brightnessPath;\n\n    public LinuxLedManager(String ledPath) {\n        this.brightnessPath = ledPath + \"/brightness\";\n    }\n\n    @Override\n    public void writeLed(boolean enabled) throws KuraException {\n        try (FileWriter ledFileWriter = new FileWriter(this.brightnessPath);\n                BufferedWriter ledBufferedWriter = new BufferedWriter(ledFileWriter)) {\n            if (enabled) {\n                ledBufferedWriter.write(\"1\");\n            } else {\n                ledBufferedWriter.write(\"0\");\n            }\n            ledBufferedWriter.flush();\n        } catch (IOException e) {\n            logger.error(\"Error accessing the specified LED!\");\n            throw new KuraException(KuraErrorCode.UNAVAILABLE_DEVICE);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/StatusNotificationTypeEnum.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status;\n\npublic enum StatusNotificationTypeEnum {\n    \n    LED,\n    LOG,\n    NONE;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/BlinkStatusRunnable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status.runnables;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.status.LedManager;\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\n\npublic class BlinkStatusRunnable implements StatusRunnable {\n\n    private final LedManager ledManager;\n\n    private boolean enabled;\n\n    public BlinkStatusRunnable(LedManager ledManager) {\n        this.ledManager = ledManager;\n        this.enabled = true;\n    }\n\n    @Override\n    public void run() {\n        while (this.enabled) {\n            try {\n                this.ledManager.writeLed(true);\n                Thread.sleep(CloudConnectionStatusEnum.SLOW_BLINKING_ON_TIME);\n                this.ledManager.writeLed(false);\n                Thread.sleep(CloudConnectionStatusEnum.SLOW_BLINKING_OFF_TIME);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                this.enabled = false;\n            } catch (KuraException e) {\n                this.enabled = false;\n            }\n        }\n    }\n\n    @Override\n    public void stopRunnable() {\n        this.enabled = false;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/HeartbeatStatusRunnable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status.runnables;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.status.LedManager;\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\n\npublic class HeartbeatStatusRunnable implements StatusRunnable {\n\n    private final LedManager ledManager;\n\n    private boolean enabled;\n\n    public HeartbeatStatusRunnable(LedManager ledManager) {\n        this.ledManager = ledManager;\n        this.enabled = true;\n    }\n\n    @Override\n    public void run() {\n        while (this.enabled) {\n            try {\n                this.ledManager.writeLed(true);\n                Thread.sleep(CloudConnectionStatusEnum.HEARTBEAT_SYSTOLE_DURATION);\n                this.ledManager.writeLed(false);\n                Thread.sleep(CloudConnectionStatusEnum.HEARTBEAT_SYSTOLE_DURATION);\n                this.ledManager.writeLed(true);\n                Thread.sleep(CloudConnectionStatusEnum.HEARTBEAT_DIASTOLE_DURATION);\n                this.ledManager.writeLed(false);\n                Thread.sleep(CloudConnectionStatusEnum.HEARTBEAT_PAUSE_DURATION);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                this.enabled = false;\n            } catch (KuraException e) {\n                this.enabled = false;\n            }\n        }\n    }\n\n    @Override\n    public void stopRunnable() {\n        this.enabled = false;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/LogStatusRunnable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status.runnables;\n\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class LogStatusRunnable implements StatusRunnable {\n\n    private static final Logger logger = LoggerFactory.getLogger(LogStatusRunnable.class);\n\n    private final CloudConnectionStatusEnum status;\n\n    public LogStatusRunnable(CloudConnectionStatusEnum status) {\n        this.status = status;\n    }\n\n    @Override\n    public void run() {\n        switch (this.status) {\n        case ON:\n            logger.info(\"Notification LED on\");\n            break;\n        case SLOW_BLINKING:\n            logger.info(\"Notification LED slow blinking\");\n            break;\n        case FAST_BLINKING:\n            logger.info(\"Notification LED fast blinking\");\n            break;\n        case HEARTBEAT:\n            logger.info(\"Notification LED heartbeating\");\n            break;\n        default:\n            logger.info(\"Notification LED off\");\n        }\n    }\n\n    @Override\n    public void stopRunnable() {\n        return;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/OnOffStatusRunnable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status.runnables;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.status.LedManager;\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\n\npublic class OnOffStatusRunnable implements StatusRunnable {\n\n    private final LedManager ledManager;\n    private boolean ledEnabled = false;\n\n    private boolean enabled;\n\n    public OnOffStatusRunnable(LedManager ledManager, boolean ledEnabled) {\n        this.ledManager = ledManager;\n        this.ledEnabled = ledEnabled;\n        this.enabled = true;\n    }\n\n    @Override\n    public void run() {\n        while (this.enabled) {\n            try {\n                this.ledManager.writeLed(this.ledEnabled);\n                Thread.sleep(CloudConnectionStatusEnum.PERIODIC_STATUS_CHECK_DELAY);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                this.enabled = false;\n            } catch (KuraException e) {\n                this.enabled = false;\n            }\n        }\n    }\n\n    @Override\n    public void stopRunnable() {\n        this.enabled = false;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/StatusRunnable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status.runnables;\n\npublic interface StatusRunnable extends Runnable {\n\n    public void stopRunnable();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.system\nBundle-SymbolicName: org.eclipse.kura.core.system;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: \n org.apache.commons.io;version=\"[2.4,3.0)\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.net;version=\"[2.0,3.0)\",\n org.eclipse.kura.system;version=\"[1.9,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/OSGI-INF/system.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.system.SystemService\">\n   <implementation class=\"org.eclipse.kura.core.system.SystemServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.system.SystemService\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.system.SystemService\"/>\n   <reference bind=\"setExecutorService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.executor.PrivilegedExecutorService\" name=\"PrivilegedExecutorService\" policy=\"static\" unbind=\"unsetExecutorService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/OSGI-INF/systemAdmin.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" immediate=\"true\" name=\"org.eclipse.kura.system.SystemAdminService\">\n   <implementation class=\"org.eclipse.kura.core.system.SystemAdminServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.system.SystemAdminService\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.system.SystemAdminService\"/>\n   <reference bind=\"setExecutorService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.executor.PrivilegedExecutorService\" name=\"PrivilegedExecutorService\" policy=\"static\" unbind=\"unsetExecutorService\"/>        \n </scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/,\\\n           src/main/resources/\noutput.. = target/classes/\nbin.includes = .,\\\n               OSGI-INF/,\\\n               META-INF/,\\\n               about.html,\\\n               about_files/\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n\tSPDX-License-Identifier: EPL-2.0\n\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<artifactId>org.eclipse.kura.core.system</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/src/main/java/org/eclipse/kura/core/system/SuperSystemService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.system;\n\nimport java.io.ByteArrayOutputStream;\nimport java.nio.charset.StandardCharsets;\n\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Superclass of SystemService.\n */\n@SuppressWarnings(\"checkstyle:hideUtilityClassConstructor\")\npublic class SuperSystemService {\n\n    private static final Logger logger = LoggerFactory.getLogger(SuperSystemService.class);\n\n    protected static String runSystemCommand(String[] commandLine, boolean runInShell,\n            CommandExecutorService executorService, boolean allowFailure) {\n        String response = \"\";\n        Command command = new Command(commandLine);\n        command.setTimeout(60);\n        command.setOutputStream(new ByteArrayOutputStream());\n        command.setExecuteInAShell(runInShell);\n        CommandStatus status = executorService.execute(command);\n        if (status.getExitStatus().isSuccessful() || allowFailure) {\n            response = new String(((ByteArrayOutputStream) status.getOutputStream()).toByteArray(),\n                    StandardCharsets.UTF_8);\n        } else {\n            if (logger.isErrorEnabled()) {\n                logger.error(\"failed to run commands {}\", String.join(\" \", commandLine));\n            }\n        }\n        return response;\n    }\n\n    protected static String runSystemCommand(String[] commandLine, boolean runInShell,\n            CommandExecutorService executorService) {\n        return runSystemCommand(commandLine, runInShell, executorService, false);\n    }\n\n    protected static String runSystemCommand(String commandLine, boolean runInShell,\n            CommandExecutorService executorService, boolean allowFailure) {\n        return runSystemCommand(commandLine.split(\"\\\\s+\"), runInShell, executorService, allowFailure);\n    }\n\n    protected static String runSystemCommand(String commandLine, boolean runInShell,\n            CommandExecutorService executorService) {\n        return runSystemCommand(commandLine.split(\"\\\\s+\"), runInShell, executorService);\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/src/main/java/org/eclipse/kura/core/system/SystemAdminServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.system;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.text.DateFormat;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.eclipse.kura.system.SystemAdminService;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SystemAdminServiceImpl extends SuperSystemService implements SystemAdminService {\n\n    private static final Logger logger = LoggerFactory.getLogger(SystemAdminServiceImpl.class);\n\n    private static final String OS_LINUX = \"Linux\";\n    private static final String OS_MAC_OSX = \"Mac OS X\";\n    private static final String OS_WINDOWS = \"windows\";\n    private static final String UNKNOWN = \"UNKNOWN\";\n\n    @SuppressWarnings(\"unused\")\n    private ComponentContext ctx;\n    private CommandExecutorService executorService;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setExecutorService(CommandExecutorService executorService) {\n        this.executorService = executorService;\n    }\n\n    public void unsetExecutorService(CommandExecutorService executorService) {\n        this.executorService = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) {\n        //\n        // save the bundle context\n        this.ctx = componentContext;\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        this.ctx = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public String getUptime() {\n\n        String uptimeStr = UNKNOWN;\n        long uptime = 0;\n\n        if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n            try {\n                String[] lastBootUpTime = runSystemCommand(\"wmic os get LastBootUpTime \", false, this.executorService)\n                        .split(\"\\n\");\n                if (lastBootUpTime[0].toLowerCase().startsWith(\"lastbootuptime\")) {\n                    String lastBoot = lastBootUpTime[2];\n                    DateFormat df = new SimpleDateFormat(\"yyyyMMddHHmmss\");\n                    Date bootDate = df.parse(lastBoot);\n                    uptime = System.currentTimeMillis() - bootDate.getTime();\n                    uptimeStr = Long.toString(uptime);\n                }\n            } catch (Exception e) {\n                uptimeStr = \"0\";\n                logger.error(\"Could not read uptime\", e);\n            }\n        } else if (OS_LINUX.equals(getOsName())) {\n            File file;\n            FileReader fr = null;\n            BufferedReader br = null;\n            try {\n                file = new File(\"/proc/uptime\");\n                fr = new FileReader(file);\n                br = new BufferedReader(fr);\n\n                String line = br.readLine();\n                if (line != null) {\n                    uptime = (long) (Double.parseDouble(line.substring(0, line.indexOf(\" \"))) * 1000);\n                    uptimeStr = Long.toString(uptime);\n                }\n            } catch (Exception e) {\n                logger.error(\"Could not read uptime\", e);\n            } finally {\n                if (br != null) {\n                    try {\n                        br.close();\n                    } catch (IOException e) {\n                    }\n                }\n                if (fr != null) {\n                    try {\n                        fr.close();\n                    } catch (IOException e) {\n                    }\n                }\n            }\n        } else if (OS_MAC_OSX.equals(getOsName())) {\n            try {\n                String lastBootupSysCmd = runSystemCommand(\"sysctl -n kern.boottime\", false, this.executorService);\n\n                if (!lastBootupSysCmd.isEmpty()) {\n                    String[] uptimePairs = lastBootupSysCmd.substring(1, lastBootupSysCmd.indexOf(\"}\")).replace(\" \", \"\")\n                            .split(\",\");\n                    String[] uptimeSeconds = uptimePairs[0].split(\"=\");\n                    uptime = System.currentTimeMillis() - (long) (Double.parseDouble(uptimeSeconds[1]));\n                    uptimeStr = Long.toString(uptime);\n                }\n            } catch (Exception e) {\n                uptimeStr = \"0\";\n                logger.error(\"Could not read uptime\", e);\n            }\n        }\n        return uptimeStr;\n    }\n\n    @Override\n    public void reboot() {\n        if (OS_LINUX.equals(getOsName()) || OS_MAC_OSX.equals(getOsName())) {\n            executeCommand(new String[] { \"reboot\" });\n        } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n            executeCommand(new String[] { \"shutdown\", \"-r\" });\n        } else {\n            logger.error(\"Unsupported OS for reboot()\");\n        }\n    }\n\n    @Override\n    public void sync() {\n        if (OS_LINUX.equals(getOsName()) || OS_MAC_OSX.equals(getOsName())) {\n            executeCommand(new String[] { \"sync\" });\n        } else {\n            logger.error(\"Unsupported OS for sync()\");\n        }\n    }\n\n    private void executeCommand(String[] cmd) {\n        Command command = new Command(cmd);\n        command.setTimeout(60);\n        CommandStatus status = this.executorService.execute(command);\n        if (status.getExitStatus().isSuccessful()) {\n            logger.error(\"failed to issue {} command\", cmd[0]);\n        }\n    }\n\n    private String getOsName() {\n        return System.getProperty(\"os.name\");\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.core.system/src/main/java/org/eclipse/kura/core/system/SystemServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.system;\n\nimport static java.lang.Thread.currentThread;\nimport static java.util.Objects.isNull;\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.net.InetAddress;\nimport java.net.NetworkInterface;\nimport java.net.SocketException;\nimport java.net.StandardProtocolFamily;\nimport java.net.URL;\nimport java.net.UnknownHostException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.DirectoryStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.security.AccessController;\nimport java.security.PrivilegedAction;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Properties;\nimport java.util.StringJoiner;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.regex.Pattern;\n\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.kura.KuraProcessExecutionErrorException;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.eclipse.kura.net.NetInterfaceStatus;\nimport org.eclipse.kura.system.ExtendedProperties;\nimport org.eclipse.kura.system.InternetConnectionStatus;\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.framework.Bundle;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.component.ComponentException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SystemServiceImpl extends SuperSystemService implements SystemService {\n\n    private ScheduledExecutorService internetCheckerExecutor;\n\n    private static final String DEFAULT_INTERNET_CONNECTION_STATUS_CHECK_IP = \"198.41.30.198\";\n    private static final String DEFAULT_INTERNET_CONNECTION_STATUS_CHECK_HOST = \"eclipse.org\";\n    private static final String SYS_CLASS_NET = \"/sys/class/net/\";\n    private static final Logger logger = LoggerFactory.getLogger(SystemServiceImpl.class);\n    private static final String PROPERTY_PROVIDER_SUFFIX = \".provider\";\n    private static final String DMIDECODE_COMMAND = \"dmidecode -t system\";\n    private static final String SPACES_REGEX = \":\\\\s+\";\n    private static final String BIN_SH = \"/bin/sh\";\n    private static final String LINUX_2_6_34_12_WR4_3_0_0_STANDARD = \"2.6.34.12-WR4.3.0.0_standard\";\n    private static final String LINUX_2_6_34_9_WR4_2_0_0_STANDARD = \"2.6.34.9-WR4.2.0.0_standard\";\n    private static final String CLOUDBEES_SECURITY_SETTINGS_PATH = \"/private/eurotech/settings-security.xml\";\n    private static final String LOG4J_CONFIGURATION = \"log4j.configuration\";\n    private static final String DPA_CONFIGURATION = \"dpa.configuration\";\n    private static final String KURA_PATH = \"/opt/eclipse/kura\";\n    private static final String OS_WINDOWS = \"windows\";\n\n    private static final int INTERNET_CHECK_TIME_INTERVAL = 30000;\n\n    private static boolean onCloudbees = false;\n\n    private Properties kuraProperties;\n    private ComponentContext componentContext;\n\n    private CommandExecutorService executorService;\n\n    private String primaryInterfaceMacAddress;\n\n    private final AtomicReference<InternetConnectionStatus> currentInternetStatus = new AtomicReference<>(\n            InternetConnectionStatus.UNAVAILABLE);\n\n    private ScheduledFuture<?> currentTask;\n\n    public void setExecutorService(CommandExecutorService executorService) {\n        this.executorService = executorService;\n    }\n\n    public void unsetExecutorService(CommandExecutorService executorService) {\n        this.executorService = null;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    @SuppressWarnings({ \"rawtypes\", \"unchecked\", \"checkstyle:methodLength\" })\n    protected void activate(ComponentContext componentContext) {\n        this.componentContext = componentContext;\n\n        AccessController.doPrivileged((PrivilegedAction) () -> {\n            try {\n                // privileged code goes here, for example:\n                onCloudbees = new File(CLOUDBEES_SECURITY_SETTINGS_PATH).exists();\n                return null; // nothing to return\n            } catch (Exception e) {\n                logger.warn(\"Unable to execute privileged in SystemService\");\n                return null;\n            }\n        });\n\n        // load the defaults from the kura.properties files\n        Properties kuraDefaults = new Properties();\n        boolean updateTriggered = false;\n        try {\n            // special cases for older versions to fix relative path bug in v2.0.4 and earlier\n            if (System.getProperty(KURA_CONFIG) != null\n                    && System.getProperty(KURA_CONFIG).trim().equals(\"file:kura/kura.properties\")) {\n                System.setProperty(KURA_CONFIG, \"file:/opt/eclipse/kura/framework/kura.properties\");\n                updateTriggered = true;\n                logger.warn(\"Overridding invalid kura.properties location\");\n            }\n            if (System.getProperty(DPA_CONFIGURATION) != null\n                    && System.getProperty(DPA_CONFIGURATION).trim().equals(\"kura/dpa.properties\")) {\n                System.setProperty(DPA_CONFIGURATION, \"/opt/eclipse/kura/packages/dpa.properties\");\n                updateTriggered = true;\n                logger.warn(\"Overridding invalid dpa.properties location\");\n            }\n            if (System.getProperty(LOG4J_CONFIGURATION) != null\n                    && System.getProperty(LOG4J_CONFIGURATION).trim().equals(\"file:kura/log4j.properties\")) {\n                System.setProperty(LOG4J_CONFIGURATION, \"file:/opt/eclipse/kura/user/log4j.properties\");\n                updateTriggered = true;\n                logger.warn(\"Overridding invalid log4j.properties location\");\n            }\n\n            // load the default kura.properties\n            // look for kura.properties as resource in the classpath\n            // if not found, look for such file in the kura.home directory\n            String kuraHome = System.getProperty(KEY_KURA_HOME_DIR);\n            String kuraFrameworkConfig = System.getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR);\n            String kuraUserConfig = System.getProperty(KEY_KURA_USER_CONFIG_DIR);\n            String kuraConfig = System.getProperty(KURA_CONFIG);\n            String kuraProps = readResource(KURA_PROPS_FILE);\n\n            if (kuraProps != null) {\n                kuraDefaults.load(new StringReader(kuraProps));\n                logger.info(\"Loaded Jar Resource kura.properties.\");\n            } else if (kuraConfig != null) {\n                loadKuraDefaults(kuraDefaults, kuraConfig);\n            } else if (kuraFrameworkConfig != null) {\n                File kuraPropsFile = new File(kuraFrameworkConfig + File.separator + KURA_PROPS_FILE);\n                if (kuraPropsFile.exists()) {\n                    try (final FileReader fr = new FileReader(kuraPropsFile)) {\n                        kuraDefaults.load(fr);\n                    }\n                    logger.info(\"Loaded File kura.properties: {}\", kuraPropsFile);\n                } else {\n                    logger.warn(\"File does not exist: {}\", kuraPropsFile);\n                }\n\n            } else {\n                logger.error(\"Could not locate kura.properties file\");\n            }\n\n            // Try to reload kuraHome with the value set in kura.properties file.\n            if (kuraHome == null) {\n                kuraHome = kuraDefaults.getProperty(KEY_KURA_HOME_DIR);\n            }\n            // Try to reload kuraFrameworkConfig with the value set in kura.properties file.\n            if (kuraFrameworkConfig == null) {\n                kuraFrameworkConfig = kuraDefaults.getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR);\n            }\n            // Try to reload kurauserConfig with the value set in kura.properties file.\n            if (kuraUserConfig == null) {\n                kuraUserConfig = kuraDefaults.getProperty(KEY_KURA_USER_CONFIG_DIR);\n            }\n\n            // load custom kura properties\n            // look for kura_custom.properties as resource in the classpath\n            // if not found, look for such file in the kura.user.config directory\n            Properties kuraCustomProps = new Properties();\n            String kuraCustomConfig = System.getProperty(KURA_CUSTOM_CONFIG);\n            String kuraCustomProperties = readResource(KURA_CUSTOM_PROPS_FILE);\n\n            if (kuraCustomProperties != null) {\n                kuraCustomProps.load(new StringReader(kuraCustomProperties));\n                logger.info(\"Loaded Jar Resource: {}\", KURA_CUSTOM_PROPS_FILE);\n            } else if (kuraCustomConfig != null) {\n                loadKuraCustom(kuraCustomProps, kuraCustomConfig);\n            } else if (kuraUserConfig != null) {\n                File kuraCustomPropsFile = new File(kuraUserConfig + File.separator + KURA_CUSTOM_PROPS_FILE);\n                if (kuraCustomPropsFile.exists()) {\n                    Reader reader = new FileReader(kuraCustomPropsFile);\n                    try {\n                        kuraCustomProps.load(reader);\n                    } finally {\n                        reader.close();\n                    }\n                    logger.info(\"Loaded File {}: {}\", KURA_CUSTOM_PROPS_FILE, kuraCustomPropsFile);\n                } else {\n                    logger.warn(\"File does not exist: {}\", kuraCustomPropsFile);\n                }\n            } else {\n                logger.info(\"Did not locate a kura_custom.properties file in {}\", kuraUserConfig);\n            }\n\n            // Override defaults with values from kura_custom.properties\n            kuraDefaults.putAll(kuraCustomProps);\n\n            // more path overrides based on earlier Kura problem with relative paths\n            if (kuraDefaults.getProperty(KEY_KURA_HOME_DIR) != null\n                    && kuraDefaults.getProperty(KEY_KURA_HOME_DIR).trim().equals(\"kura\")) {\n                kuraDefaults.setProperty(KEY_KURA_HOME_DIR, KURA_PATH);\n                updateTriggered = true;\n                logger.warn(\"Overridding invalid kura.home location\");\n            }\n            if (kuraDefaults.getProperty(KEY_KURA_PLUGINS_DIR) != null\n                    && kuraDefaults.getProperty(KEY_KURA_PLUGINS_DIR).trim().equals(\"kura/plugins\")) {\n                kuraDefaults.setProperty(KEY_KURA_PLUGINS_DIR, \"/opt/eclipse/kura/plugins\");\n                updateTriggered = true;\n                logger.warn(\"Overridding invalid kura.plugins location\");\n            }\n            if (kuraDefaults.getProperty(KEY_KURA_PACKAGES_DIR) != null\n                    && kuraDefaults.getProperty(KEY_KURA_PACKAGES_DIR).trim().equals(\"kura/packages\")) {\n                kuraDefaults.setProperty(KEY_KURA_PACKAGES_DIR, \"/opt/eclipse/kura/data/packages\");\n                updateTriggered = true;\n                logger.warn(\"Overridding invalid kura.packages location\");\n            }\n\n            if (updateTriggered) {\n                File directory;       // Desired current working directory\n\n                directory = new File(KURA_PATH).getAbsoluteFile();\n                if (directory.exists() || directory.mkdirs()) {\n                    String oldDir = System.getProperty(\"user.dir\");\n                    if (System.setProperty(\"user.dir\", directory.getAbsolutePath()) != null) {\n                        logger.warn(\"Changed working directory to /opt/eclipse/kura from {}\", oldDir);\n                    }\n                }\n            }\n\n            // build the m_kuraProperties instance with the defaults\n            this.kuraProperties = new Properties(kuraDefaults);\n\n            // take care of the CloudBees environment\n            // that is run in the continuous integration.\n            if (onCloudbees) {\n                this.kuraProperties.put(KEY_OS_NAME, OS_CLOUDBEES);\n            }\n\n            // Put the Net Admin and Web interface availability property so that is available through a get.\n            Boolean hasNetAdmin = Boolean.valueOf(this.kuraProperties.getProperty(KEY_KURA_HAVE_NET_ADMIN, \"true\"));\n            this.kuraProperties.put(KEY_KURA_HAVE_NET_ADMIN, hasNetAdmin);\n            logger.info(\"Kura has net admin? {}\", hasNetAdmin);\n            String webInterfaceEnabled = this.kuraProperties.getProperty(KEY_KURA_HAVE_WEB_INTER, \"true\");\n            this.kuraProperties.put(KEY_KURA_HAVE_WEB_INTER, webInterfaceEnabled);\n            logger.info(\"Is Kura web interface enabled? {}\", webInterfaceEnabled);\n            String kuraVersion = this.kuraProperties.getProperty(KEY_KURA_VERSION, \"version-unknown\");\n            this.kuraProperties.put(KEY_KURA_VERSION, kuraVersion);\n            logger.info(\"Kura version? {}\", kuraVersion);\n\n            if (System.getProperty(KEY_KURA_NAME) != null) {\n                this.kuraProperties.put(KEY_KURA_NAME, System.getProperty(KEY_KURA_NAME));\n            }\n            if (System.getProperty(KEY_KURA_VERSION) != null) {\n                this.kuraProperties.put(KEY_KURA_VERSION, System.getProperty(KEY_KURA_VERSION));\n            }\n            if (System.getProperty(KEY_DEVICE_NAME) != null) {\n                this.kuraProperties.put(KEY_DEVICE_NAME, System.getProperty(KEY_DEVICE_NAME));\n            }\n            if (System.getProperty(KEY_PLATFORM) != null) {\n                this.kuraProperties.put(KEY_PLATFORM, System.getProperty(KEY_PLATFORM));\n            }\n            if (System.getProperty(KEY_MODEL_ID) != null) {\n                this.kuraProperties.put(KEY_MODEL_ID, System.getProperty(KEY_MODEL_ID));\n            }\n            if (System.getProperty(KEY_MODEL_NAME) != null) {\n                this.kuraProperties.put(KEY_MODEL_NAME, System.getProperty(KEY_MODEL_NAME));\n            }\n            if (System.getProperty(KEY_PART_NUMBER) != null) {\n                this.kuraProperties.put(KEY_PART_NUMBER, System.getProperty(KEY_PART_NUMBER));\n            }\n            if (System.getProperty(KEY_SERIAL_NUM) != null) {\n                this.kuraProperties.put(KEY_SERIAL_NUM, System.getProperty(KEY_SERIAL_NUM));\n            }\n            if (System.getProperty(KEY_BIOS_VERSION) != null) {\n                this.kuraProperties.put(KEY_BIOS_VERSION, System.getProperty(KEY_BIOS_VERSION));\n            }\n            if (System.getProperty(KEY_FIRMWARE_VERSION) != null) {\n                this.kuraProperties.put(KEY_FIRMWARE_VERSION, System.getProperty(KEY_FIRMWARE_VERSION));\n            }\n            if (System.getProperty(KEY_PRIMARY_NET_IFACE) != null) {\n                this.kuraProperties.put(KEY_PRIMARY_NET_IFACE, System.getProperty(KEY_PRIMARY_NET_IFACE));\n            }\n            if (System.getProperty(KEY_KURA_HOME_DIR) != null) {\n                this.kuraProperties.put(KEY_KURA_HOME_DIR, System.getProperty(KEY_KURA_HOME_DIR));\n            }\n            if (System.getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR) != null) {\n                this.kuraProperties.put(KEY_KURA_FRAMEWORK_CONFIG_DIR,\n                        System.getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR));\n            }\n            if (System.getProperty(KEY_KURA_USER_CONFIG_DIR) != null) {\n                this.kuraProperties.put(KEY_KURA_USER_CONFIG_DIR, System.getProperty(KEY_KURA_USER_CONFIG_DIR));\n            }\n            if (System.getProperty(KEY_KURA_PLUGINS_DIR) != null) {\n                this.kuraProperties.put(KEY_KURA_PLUGINS_DIR, System.getProperty(KEY_KURA_PLUGINS_DIR));\n            }\n            if (System.getProperty(KEY_KURA_PACKAGES_DIR) != null) {\n                this.kuraProperties.put(KEY_KURA_PACKAGES_DIR, System.getProperty(KEY_KURA_PACKAGES_DIR));\n            }\n            if (System.getProperty(KEY_KURA_DATA_DIR) != null) {\n                this.kuraProperties.put(KEY_KURA_DATA_DIR, System.getProperty(KEY_KURA_DATA_DIR));\n            }\n            if (System.getProperty(KEY_KURA_TMP_DIR) != null) {\n                this.kuraProperties.put(KEY_KURA_TMP_DIR, System.getProperty(KEY_KURA_TMP_DIR));\n            }\n            if (System.getProperty(KEY_KURA_SNAPSHOTS_DIR) != null) {\n                this.kuraProperties.put(KEY_KURA_SNAPSHOTS_DIR, System.getProperty(KEY_KURA_SNAPSHOTS_DIR));\n            }\n            if (System.getProperty(KEY_KURA_SNAPSHOTS_COUNT) != null) {\n                this.kuraProperties.put(KEY_KURA_SNAPSHOTS_COUNT, System.getProperty(KEY_KURA_SNAPSHOTS_COUNT));\n            }\n            if (System.getProperty(KEY_KURA_HAVE_NET_ADMIN) != null) {\n                this.kuraProperties.put(KEY_KURA_HAVE_NET_ADMIN, System.getProperty(KEY_KURA_HAVE_NET_ADMIN));\n            }\n            if (System.getProperty(KEY_KURA_HAVE_WEB_INTER) != null) {\n                this.kuraProperties.put(KEY_KURA_HAVE_WEB_INTER, System.getProperty(KEY_KURA_HAVE_WEB_INTER));\n            }\n            if (System.getProperty(KEY_KURA_STYLE_DIR) != null) {\n                this.kuraProperties.put(KEY_KURA_STYLE_DIR, System.getProperty(KEY_KURA_STYLE_DIR));\n            }\n            if (System.getProperty(KEY_KURA_WIFI_TOP_CHANNEL) != null) {\n                this.kuraProperties.put(KEY_KURA_WIFI_TOP_CHANNEL, System.getProperty(KEY_KURA_WIFI_TOP_CHANNEL));\n            }\n            if (System.getProperty(KEY_KURA_KEY_STORE_PWD) != null) {\n                this.kuraProperties.put(KEY_KURA_KEY_STORE_PWD, System.getProperty(KEY_KURA_KEY_STORE_PWD));\n            }\n            if (System.getProperty(KEY_KURA_TRUST_STORE_PWD) != null) {\n                this.kuraProperties.put(KEY_KURA_TRUST_STORE_PWD, System.getProperty(KEY_KURA_TRUST_STORE_PWD));\n            }\n            if (System.getProperty(KEY_FILE_COMMAND_ZIP_MAX_SIZE) != null) {\n                this.kuraProperties.put(KEY_FILE_COMMAND_ZIP_MAX_SIZE,\n                        System.getProperty(KEY_FILE_COMMAND_ZIP_MAX_SIZE));\n            }\n            if (System.getProperty(KEY_FILE_COMMAND_ZIP_MAX_NUMBER) != null) {\n                this.kuraProperties.put(KEY_FILE_COMMAND_ZIP_MAX_NUMBER,\n                        System.getProperty(KEY_FILE_COMMAND_ZIP_MAX_NUMBER));\n            }\n            if (System.getProperty(KEY_OS_ARCH) != null) {\n                this.kuraProperties.put(KEY_OS_ARCH, System.getProperty(KEY_OS_ARCH));\n            }\n            if (System.getProperty(KEY_OS_NAME) != null) {\n                this.kuraProperties.put(KEY_OS_NAME, System.getProperty(KEY_OS_NAME));\n            }\n            if (System.getProperty(KEY_OS_VER) != null) {\n                this.kuraProperties.put(KEY_OS_VER, getOsVersion()); // System.getProperty(KEY_OS_VER)\n            }\n            if (System.getProperty(KEY_OS_DISTRO) != null) {\n                this.kuraProperties.put(KEY_OS_DISTRO, System.getProperty(KEY_OS_DISTRO));\n            }\n            if (System.getProperty(KEY_OS_DISTRO_VER) != null) {\n                this.kuraProperties.put(KEY_OS_DISTRO_VER, System.getProperty(KEY_OS_DISTRO_VER));\n            }\n            if (System.getProperty(KEY_JAVA_VERSION) != null) {\n                this.kuraProperties.put(KEY_JAVA_VERSION, System.getProperty(KEY_JAVA_VERSION));\n            }\n            if (System.getProperty(KEY_JAVA_VENDOR) != null) {\n                this.kuraProperties.put(KEY_JAVA_VENDOR, System.getProperty(KEY_JAVA_VENDOR));\n            }\n            if (System.getProperty(KEY_JAVA_VM_NAME) != null) {\n                this.kuraProperties.put(KEY_JAVA_VM_NAME, System.getProperty(KEY_JAVA_VM_NAME));\n            }\n            if (System.getProperty(KEY_JAVA_VM_VERSION) != null) {\n                this.kuraProperties.put(KEY_JAVA_VM_VERSION, System.getProperty(KEY_JAVA_VM_VERSION));\n            }\n            if (System.getProperty(KEY_JAVA_VM_INFO) != null) {\n                this.kuraProperties.put(KEY_JAVA_VM_INFO, System.getProperty(KEY_JAVA_VM_INFO));\n            }\n            if (System.getProperty(KEY_JAVA_VM_VENDOR) != null) {\n                this.kuraProperties.put(KEY_JAVA_VM_VENDOR, System.getProperty(KEY_JAVA_VM_VENDOR));\n            }\n            if (System.getProperty(KEY_JDK_VENDOR_VERSION) != null) {\n                this.kuraProperties.put(KEY_JDK_VENDOR_VERSION, System.getProperty(KEY_JDK_VENDOR_VERSION));\n            }\n            if (System.getProperty(KEY_OSGI_FW_NAME) != null) {\n                this.kuraProperties.put(KEY_OSGI_FW_NAME, System.getProperty(KEY_OSGI_FW_NAME));\n            }\n            if (System.getProperty(KEY_OSGI_FW_VERSION) != null) {\n                this.kuraProperties.put(KEY_OSGI_FW_VERSION, System.getProperty(KEY_OSGI_FW_VERSION));\n            }\n            if (System.getProperty(KEY_JAVA_HOME) != null) {\n                this.kuraProperties.put(KEY_JAVA_HOME, System.getProperty(KEY_JAVA_HOME));\n            }\n            if (System.getProperty(KEY_FILE_SEP) != null) {\n                this.kuraProperties.put(KEY_FILE_SEP, System.getProperty(KEY_FILE_SEP));\n            }\n            if (System.getProperty(CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE) != null) {\n                this.kuraProperties.put(CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE,\n                        System.getProperty(CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE));\n            }\n            if (System.getProperty(DB_URL_PROPNAME) != null) {\n                this.kuraProperties.put(DB_URL_PROPNAME, System.getProperty(DB_URL_PROPNAME));\n            }\n            if (System.getProperty(DB_CACHE_ROWS_PROPNAME) != null) {\n                this.kuraProperties.put(DB_CACHE_ROWS_PROPNAME, System.getProperty(DB_CACHE_ROWS_PROPNAME));\n            }\n            if (System.getProperty(DB_LOB_FILE_PROPNAME) != null) {\n                this.kuraProperties.put(DB_LOB_FILE_PROPNAME, System.getProperty(DB_LOB_FILE_PROPNAME));\n            }\n            if (System.getProperty(DB_DEFRAG_LIMIT_PROPNAME) != null) {\n                this.kuraProperties.put(DB_DEFRAG_LIMIT_PROPNAME, System.getProperty(DB_DEFRAG_LIMIT_PROPNAME));\n            }\n            if (System.getProperty(DB_LOG_DATA_PROPNAME) != null) {\n                this.kuraProperties.put(DB_LOG_DATA_PROPNAME, System.getProperty(DB_LOG_DATA_PROPNAME));\n            }\n            if (System.getProperty(DB_LOG_SIZE_PROPNAME) != null) {\n                this.kuraProperties.put(DB_LOG_SIZE_PROPNAME, System.getProperty(DB_LOG_SIZE_PROPNAME));\n            }\n            if (System.getProperty(DB_NIO_PROPNAME) != null) {\n                this.kuraProperties.put(DB_NIO_PROPNAME, System.getProperty(DB_NIO_PROPNAME));\n            }\n            if (System.getProperty(DB_WRITE_DELAY_MILLIES_PROPNAME) != null) {\n                this.kuraProperties.put(DB_WRITE_DELAY_MILLIES_PROPNAME,\n                        System.getProperty(DB_WRITE_DELAY_MILLIES_PROPNAME));\n            }\n            if (System.getProperty(KEY_CPU_VERSION) != null) {\n                this.kuraProperties.put(KEY_CPU_VERSION, System.getProperty(KEY_CPU_VERSION));\n            }\n            if (System.getProperty(KEY_COMMAND_USER) != null) {\n                this.kuraProperties.put(KEY_COMMAND_USER, System.getProperty(KEY_COMMAND_USER));\n            }\n            if (System.getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST) != null) {\n                this.kuraProperties.put(KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST,\n                        System.getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST));\n            }\n            if (System.getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_IP) != null) {\n                this.kuraProperties.put(KEY_INTERNET_CONNECTION_STATUS_CHECK_IP,\n                        System.getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_IP));\n            }\n\n            if (getKuraHome() == null) {\n                logger.error(\"Did not initialize kura.home\");\n            } else {\n                logger.info(\"Kura home directory is {}\", getKuraHome());\n                createDirIfNotExists(getKuraHome());\n            }\n            if (getKuraFrameworkConfigDirectory() == null) {\n                logger.error(\"Did not initialize kura.framework.config\");\n            } else {\n                logger.info(\"Kura framework configuration directory is {}\", getKuraFrameworkConfigDirectory());\n                createDirIfNotExists(getKuraFrameworkConfigDirectory());\n            }\n            if (getKuraUserConfigDirectory() == null) {\n                logger.error(\"Did not initialize kura.user.config\");\n            } else {\n                logger.info(\"Kura user configuration directory is {}\", getKuraUserConfigDirectory());\n                createDirIfNotExists(getKuraUserConfigDirectory());\n            }\n            if (getKuraSnapshotsDirectory() == null) {\n                logger.error(\"Did not initialize kura.snapshots\");\n            } else {\n                logger.info(\"Kura snapshots directory is {}\", getKuraSnapshotsDirectory());\n                createDirIfNotExists(getKuraSnapshotsDirectory());\n            }\n            if (getKuraTemporaryConfigDirectory() == null) {\n                logger.error(\"Did not initialize kura.tmp\");\n            } else {\n                logger.info(\"Kura tmp directory is {}\", getKuraTemporaryConfigDirectory());\n                createDirIfNotExists(getKuraTemporaryConfigDirectory());\n            }\n\n            logger.info(\"Kura version {} is starting\", getKuraVersion());\n        } catch (IOException e) {\n            throw new ComponentException(\"Error loading default properties\", e);\n        }\n\n        this.internetCheckerExecutor = Executors.newSingleThreadScheduledExecutor(r -> {\n            final Thread result = Executors.defaultThreadFactory().newThread(r);\n            result.setName(\"internet-status-checker\");\n            return result;\n        });\n\n        this.currentTask = this.internetCheckerExecutor.scheduleAtFixedRate(this::checkInternetTask, 5000,\n                INTERNET_CHECK_TIME_INTERVAL, TimeUnit.MILLISECONDS);\n    }\n\n    private void loadKuraCustom(Properties kuraCustomProps, String kuraCustomConfig) {\n        try {\n            final URL kuraConfigUrl = new URL(kuraCustomConfig);\n            try (InputStream in = kuraConfigUrl.openStream()) {\n                kuraCustomProps.load(in);\n            }\n            logger.info(\"Loaded URL kura_custom.properties: {}\", kuraCustomConfig);\n        } catch (Exception e) {\n            logger.warn(\"Could not open kuraCustomConfig URL: \", e);\n        }\n    }\n\n    private void loadKuraDefaults(Properties kuraDefaults, String kuraConfig) {\n        try {\n            final URL kuraConfigUrl = new URL(kuraConfig);\n            try (InputStream in = kuraConfigUrl.openStream()) {\n                kuraDefaults.load(in);\n            }\n            logger.info(\"Loaded URL kura.properties: {}\", kuraConfig);\n        } catch (Exception e) {\n            logger.warn(\"Could not open kuraConfig URL\", e);\n        }\n    }\n\n    protected String readResource(String resource) throws IOException {\n        if (resource == null) {\n            return null;\n        }\n\n        final URL resourceUrl = currentThread().getContextClassLoader().getResource(resource);\n\n        if (resourceUrl == null) {\n            return null;\n        }\n\n        return IOUtils.toString(resourceUrl);\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        this.componentContext = null;\n        this.kuraProperties = null;\n\n        if (this.currentTask != null) {\n            this.currentTask.cancel(true);\n        }\n\n        if (this.internetCheckerExecutor != null) {\n            this.internetCheckerExecutor.shutdown();\n            try {\n                this.internetCheckerExecutor.awaitTermination(5000, TimeUnit.MILLISECONDS);\n            } catch (InterruptedException e) {\n                currentThread().interrupt();\n                this.internetCheckerExecutor.shutdownNow();\n            }\n        }\n    }\n\n    public void updated(Map<String, Object> properties) {\n        // nothing to do\n        // all properties of the System service are read-only\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs\n    //\n    // ----------------------------------------------------------------\n\n    /**\n     * Returns all KuraProperties for this system. The returned instances is\n     * initialized by loading the kura.properties file. Properties defined at\n     * the System level - for example using the java -D command line flag -\n     * are used to overwrite the values loaded from the kura.properties file\n     * in a hierarchical configuration fashion.\n     */\n    @Override\n    public Properties getProperties() {\n        return this.kuraProperties;\n    }\n\n    @Override\n    public String getPrimaryMacAddress() {\n        String primaryNetworkInterfaceName = getPrimaryNetworkInterfaceName();\n\n        if (OS_MAC_OSX.equals(getOsName())) {\n            return getPrimaryMacAddressOSX(primaryNetworkInterfaceName);\n        } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n            return getPrimaryMacAddressWindows(primaryNetworkInterfaceName);\n        } else {\n            return getPrimaryMacAddressLinux(primaryNetworkInterfaceName);\n        }\n    }\n\n    private String getPrimaryMacAddressOSX(String primaryNetworkInterfaceName) {\n        String macAddress = null;\n        try {\n            logger.info(\"executing: ifconfig and looking for {}\", primaryNetworkInterfaceName);\n            List<String> out = Arrays\n                    .asList(runSystemCommand(\"ifconfig\", false, this.executorService).split(\"\\\\r?\\\\n\"));\n            ListIterator<String> iterator = out.listIterator();\n            String line;\n            while (iterator.hasNext()) {\n                line = iterator.next();\n                if (line.startsWith(primaryNetworkInterfaceName)) {\n                    // get the next line and save the MAC\n                    line = iterator.next();\n                    if (line == null) {\n                        throw new IOException(\"Null input!\");\n                    }\n                    if (!line.trim().startsWith(\"ether\")) {\n                        line = iterator.next();\n                    }\n                    String[] splitLine = line.split(\" \");\n                    if (splitLine.length > 0) {\n                        macAddress = splitLine[1].toUpperCase();\n                    }\n                }\n            }\n        } catch (IOException e) {\n            logger.error(\"Failed to get network interfaces\", e);\n        }\n        return macAddress;\n    }\n\n    private String getPrimaryMacAddressWindows(String primaryNetworkInterfaceName) {\n        if (!isNull(this.primaryInterfaceMacAddress)) {\n            return this.primaryInterfaceMacAddress;\n        }\n\n        try {\n            logger.info(\"executing: InetAddress.getLocalHost {}\", primaryNetworkInterfaceName);\n            InetAddress ip = InetAddress.getLocalHost();\n            // Windows options are either ethX or wlanX, and eth0 may really not be the correct one\n            InetAddress ip2 = getPrimaryIPWindows(\"eth\");\n            if (ip2 == null) {\n                ip2 = getPrimaryIPWindows(\"wlan\");\n            }\n            if (ip2 != null) {\n                ip = ip2;\n            }\n            NetworkInterface network = NetworkInterface.getByInetAddress(ip);\n            byte[] mac = network.getHardwareAddress();\n            this.primaryInterfaceMacAddress = hardwareAddressToString(mac);\n            logger.info(\"macAddress {}\", this.primaryInterfaceMacAddress);\n        } catch (UnknownHostException | SocketException e) {\n            logger.error(e.getLocalizedMessage());\n        }\n        return this.primaryInterfaceMacAddress;\n    }\n\n    private String getPrimaryMacAddressLinux(String primaryNetworkInterfaceName) {\n\n        if (!isNull(this.primaryInterfaceMacAddress)) {\n            return this.primaryInterfaceMacAddress;\n        }\n\n        try {\n            Optional<File> interfaceSysfsDir = Optional.empty();\n\n            try (final DirectoryStream<Path> s = Files.newDirectoryStream(new File(SYS_CLASS_NET).toPath())) {\n\n                for (final Path p : s) {\n                    final File file = p.toFile();\n\n                    if (Objects.equals(primaryNetworkInterfaceName, file.getName().split(\"@\")[0])) {\n                        interfaceSysfsDir = Optional.of(file);\n                        break;\n                    }\n                }\n            }\n\n            if (!interfaceSysfsDir.isPresent()) {\n                logger.error(\"Failed to find primary network interface\");\n                return null;\n            }\n\n            try (final FileInputStream in = new FileInputStream(new File(interfaceSysfsDir.get(), \"address\"));\n                    final BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {\n\n                this.primaryInterfaceMacAddress = r.readLine().trim().toUpperCase();\n            }\n\n        } catch (final Exception e) {\n            logger.error(\"Failed to get network interface address\", e);\n            return null;\n        }\n\n        return this.primaryInterfaceMacAddress;\n    }\n\n    /**\n     * Returns ip of the first interface name of which begins with <code>prefix</code>.\n     *\n     * @param prefix\n     *            network interface name prefix e.g. eth, wlan\n     * @return ip of the first interface name of which begins with prefix; null if none found with ip\n     * @throws SocketException\n     */\n    private InetAddress getPrimaryIPWindows(String prefix) throws SocketException {\n        InetAddress ip = null;\n\n        Enumeration<NetworkInterface> networks = NetworkInterface.getNetworkInterfaces();\n        while (networks.hasMoreElements()) {\n            NetworkInterface network = networks.nextElement();\n            if (network.getName().startsWith(prefix)) {\n                Enumeration<InetAddress> ips = network.getInetAddresses();\n                if (ips.hasMoreElements()) {\n                    ip = ips.nextElement();\n                    break;\n                }\n            }\n        }\n\n        return ip;\n    }\n\n    @Override\n    public String getPrimaryNetworkInterfaceName() {\n        final Optional<String> propertyValue = getProperty(KEY_PRIMARY_NET_IFACE);\n\n        if (propertyValue.isPresent()) {\n            return propertyValue.get();\n        } else {\n            if (OS_MAC_OSX.equals(getOsName())) {\n                return \"en0\";\n            } else if (OS_LINUX.equals(getOsName())) {\n                return \"eth0\";\n            } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n                return OS_WINDOWS;\n            } else {\n                logger.error(\"Unsupported platform\");\n                return null;\n            }\n        }\n    }\n\n    @Override\n    public String getPlatform() {\n        return getProperty(KEY_PLATFORM).orElse(null);\n    }\n\n    @Override\n    public String getOsArch() {\n        final Optional<String> override = getProperty(KEY_OS_ARCH);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_OS_ARCH);\n    }\n\n    @Override\n    public String getOsName() {\n        final Optional<String> override = getProperty(KEY_OS_NAME);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_OS_NAME);\n    }\n\n    @Override\n    public String getOsVersion() {\n        final Optional<String> override = getProperty(KEY_OS_VER);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        StringBuilder sbOsVersion = new StringBuilder();\n        sbOsVersion.append(System.getProperty(KEY_OS_VER));\n        if (OS_LINUX.equals(getOsName())) {\n            File linuxKernelVersion = null;\n\n            linuxKernelVersion = new File(\"/proc/sys/kernel/version\");\n            if (linuxKernelVersion.exists()) {\n                StringBuilder kernelVersionData = new StringBuilder();\n                try (FileReader fr = new FileReader(linuxKernelVersion); BufferedReader in = new BufferedReader(fr)) {\n                    String tempLine = null;\n                    while ((tempLine = in.readLine()) != null) {\n                        kernelVersionData.append(\" \");\n                        kernelVersionData.append(tempLine);\n                    }\n                    sbOsVersion.append(kernelVersionData.toString());\n                } catch (IOException e) {\n                    logger.error(\"Failed to get OS version\", e);\n                }\n            }\n\n        }\n\n        return sbOsVersion.toString();\n    }\n\n    @Override\n    public String getOsDistro() {\n        return getProperty(KEY_OS_DISTRO).orElse(null);\n    }\n\n    @Override\n    public String getOsDistroVersion() {\n        return getProperty(KEY_OS_DISTRO_VER).orElse(null);\n    }\n\n    @Override\n    public String getJavaVendor() {\n        final Optional<String> override = getProperty(KEY_JAVA_VENDOR);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_JAVA_VENDOR);\n    }\n\n    @Override\n    public String getJavaVersion() {\n        final Optional<String> override = getProperty(KEY_JAVA_VERSION);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_JAVA_VERSION);\n    }\n\n    @Override\n    public String getJavaVmName() {\n        final Optional<String> override = getProperty(KEY_JAVA_VM_NAME);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_JAVA_VM_NAME);\n    }\n\n    @Override\n    public String getJavaVmVersion() {\n        final Optional<String> override = getProperty(KEY_JAVA_VM_VERSION);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_JAVA_VM_VERSION);\n    }\n\n    @Override\n    public String getJavaVmInfo() {\n        final Optional<String> override = getProperty(KEY_JAVA_VM_INFO);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_JAVA_VM_INFO);\n    }\n\n    @Override\n    public String getOsgiFwName() {\n        final Optional<String> override = getProperty(KEY_OSGI_FW_NAME);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_OSGI_FW_NAME);\n    }\n\n    @Override\n    public String getOsgiFwVersion() {\n        final Optional<String> override = getProperty(KEY_OSGI_FW_VERSION);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_OSGI_FW_VERSION);\n    }\n\n    @Override\n    public int getNumberOfProcessors() {\n        try {\n            return Runtime.getRuntime().availableProcessors();\n        } catch (Throwable t) {\n            // NoSuchMethodError on pre-1.4 runtimes\n        }\n        return -1;\n    }\n\n    @Override\n    public long getTotalMemory() {\n        return Runtime.getRuntime().totalMemory() / 1024;\n    }\n\n    @Override\n    public long getFreeMemory() {\n        return Runtime.getRuntime().freeMemory() / 1024;\n    }\n\n    @Override\n    public String getFileSeparator() {\n        final Optional<String> override = getProperty(KEY_FILE_SEP);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_FILE_SEP);\n    }\n\n    @Override\n    public String getJavaHome() {\n        final Optional<String> override = getProperty(KEY_JAVA_HOME);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_JAVA_HOME);\n    }\n\n    public String getKuraName() {\n        return getProperty(KEY_KURA_NAME).orElse(null);\n    }\n\n    @Override\n    public String getKuraVersion() {\n        return getProperty(KEY_KURA_VERSION).orElse(null);\n    }\n\n    @Override\n    public String getKuraMarketplaceCompatibilityVersion() {\n        final Optional<String> override = getProperty(KEY_KURA_MARKETPLACE_COMPATIBILITY_VERSION);\n        final String marketplaceCompatibilityVersion;\n\n        if (override.isPresent()) {\n            marketplaceCompatibilityVersion = override.get();\n        } else {\n            marketplaceCompatibilityVersion = getKuraVersion();\n        }\n\n        return marketplaceCompatibilityVersion.replaceAll(\"KURA[-_ ]\", \"\").replaceAll(\"[-_]\", \".\");\n    }\n\n    @Override\n    public String getKuraFrameworkConfigDirectory() {\n        return getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR).orElse(null);\n    }\n\n    @Override\n    public String getKuraUserConfigDirectory() {\n        return getProperty(KEY_KURA_USER_CONFIG_DIR).orElse(null);\n    }\n\n    @Override\n    public String getKuraHome() {\n        return getProperty(KEY_KURA_HOME_DIR).orElse(null);\n    }\n\n    public String getKuraPluginsDirectory() {\n        return getProperty(KEY_KURA_PLUGINS_DIR).orElse(null);\n    }\n\n    @Override\n    public String getKuraDataDirectory() {\n        return getProperty(KEY_KURA_DATA_DIR).orElse(null);\n    }\n\n    @Override\n    public String getKuraTemporaryConfigDirectory() {\n        return getProperty(KEY_KURA_TMP_DIR).orElse(null);\n    }\n\n    @Override\n    public String getKuraSnapshotsDirectory() {\n        return getProperty(KEY_KURA_SNAPSHOTS_DIR).orElse(null);\n    }\n\n    @Override\n    public int getKuraSnapshotsCount() {\n        return getIntegerPropertyValue(KEY_KURA_SNAPSHOTS_COUNT, 10);\n    }\n\n    @Override\n    public int getKuraWifiTopChannel() {\n        return getIntegerPropertyValue(KEY_KURA_WIFI_TOP_CHANNEL, Integer.MAX_VALUE);\n    }\n\n    @Override\n    public String getKuraStyleDirectory() {\n        return getProperty(KEY_KURA_STYLE_DIR).orElse(null);\n    }\n\n    @Override\n    public String getKuraWebEnabled() {\n        return getProperty(KEY_KURA_HAVE_WEB_INTER).orElse(null);\n    }\n\n    @Override\n    public int getFileCommandZipMaxUploadSize() {\n        return getIntegerPropertyValue(KEY_FILE_COMMAND_ZIP_MAX_SIZE, 100);\n    }\n\n    @Override\n    public int getFileCommandZipMaxUploadNumber() {\n        return getIntegerPropertyValue(KEY_FILE_COMMAND_ZIP_MAX_NUMBER, 1024);\n    }\n\n    @Override\n    public String getBiosVersion() {\n        final Optional<String> override = getProperty(KEY_BIOS_VERSION);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        String biosVersion = UNSUPPORTED;\n\n        if (OS_LINUX.equals(getOsName())) {\n            if (LINUX_2_6_34_9_WR4_2_0_0_STANDARD.equals(getOsVersion())\n                    || LINUX_2_6_34_12_WR4_3_0_0_STANDARD.equals(getOsVersion())) {\n                biosVersion = runSystemCommand(\"eth_vers_bios\", false, this.executorService);\n            } else {\n                String biosTmp = runSystemCommand(\"dmidecode -s bios-version\", false, this.executorService);\n                if (biosTmp.length() > 0 && !biosTmp.contains(\"Permission denied\")) {\n                    biosVersion = biosTmp;\n                }\n            }\n        } else if (OS_MAC_OSX.equals(getOsName())) {\n            String[] cmds = { BIN_SH, \"-c\", \"system_profiler SPHardwareDataType | grep 'Boot ROM'\" };\n            String biosTmp = runSystemCommand(cmds, true, this.executorService);\n            if (biosTmp.contains(\": \")) {\n                biosVersion = biosTmp.split(SPACES_REGEX)[1];\n            }\n        } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n            String[] cmds = { \"wmic\", \"bios\", \"get\", \"smbiosbiosversion\" };\n            String biosTmp = runSystemCommand(cmds, false, this.executorService);\n            if (biosTmp.contains(\"SMBIOSBIOSVersion\")) {\n                biosVersion = biosTmp.split(\"SMBIOSBIOSVersion\\\\s+\")[1];\n                biosVersion = biosVersion.trim();\n            }\n        }\n\n        return biosVersion;\n    }\n\n    @Override\n    public String getDeviceName() {\n        final Optional<String> override = getProperty(KEY_DEVICE_NAME);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        String deviceName = UNKNOWN;\n        if (OS_MAC_OSX.equals(getOsName())) {\n            String displayTmp = runSystemCommand(\"scutil --get ComputerName\", false, this.executorService);\n            if (displayTmp.length() > 0) {\n                deviceName = displayTmp;\n            }\n        } else if (OS_LINUX.equals(getOsName()) || OS_CLOUDBEES.equals(getOsName())\n                || getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n            String displayTmp = runSystemCommand(\"hostname\", false, this.executorService);\n            if (displayTmp.length() > 0) {\n                deviceName = displayTmp;\n            }\n        }\n        return deviceName;\n    }\n\n    @Override\n    public String getFirmwareVersion() {\n        final Optional<String> override = getProperty(KEY_FIRMWARE_VERSION);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        String fwVersion = UNSUPPORTED;\n\n        if (OS_LINUX.equals(getOsName()) && getOsVersion() != null) {\n            if (getOsVersion().startsWith(LINUX_2_6_34_9_WR4_2_0_0_STANDARD)\n                    || getOsVersion().startsWith(LINUX_2_6_34_12_WR4_3_0_0_STANDARD)) {\n                fwVersion = runSystemCommand(\"eth_vers_cpld\", false, this.executorService) + \" \"\n                        + runSystemCommand(\"eth_vers_uctl\", false, this.executorService);\n            } else if (getOsVersion().startsWith(\"3.0.35-12.09.01+yocto\")) {\n                fwVersion = runSystemCommand(\"eth_vers_avr\", false, this.executorService);\n            }\n        }\n        return fwVersion;\n    }\n\n    @Override\n    public String getModelId() {\n        final Optional<String> override = getProperty(KEY_MODEL_ID);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        String modelId = UNKNOWN;\n\n        if (OS_MAC_OSX.equals(getOsName())) {\n            String modelTmp = runSystemCommand(\"sysctl -b hw.model\", false, this.executorService);\n            if (modelTmp.length() > 0) {\n                modelId = modelTmp;\n            }\n        } else if (OS_LINUX.equals(getOsName())) {\n            String modelTmp = runSystemCommand(DMIDECODE_COMMAND, false, this.executorService);\n            if (modelTmp.contains(\"Version: \")) {\n                modelId = modelTmp.split(\"Version:\\\\s+\")[1].split(\"\\n\")[0];\n            }\n        } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n            String[] cmds = { \"wmic\", \"baseboard\", \"get\", \"Version\" };\n            String biosTmp = runSystemCommand(cmds, false, this.executorService);\n            if (biosTmp.contains(\"Version\")) {\n                modelId = biosTmp.split(\"Version\\\\s+\")[1];\n                modelId = modelId.trim();\n            }\n        }\n\n        return modelId;\n    }\n\n    @Override\n    public String getModelName() {\n        final Optional<String> override = getProperty(KEY_MODEL_NAME);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        String modelName = UNKNOWN;\n\n        if (OS_MAC_OSX.equals(getOsName())) {\n            String[] cmds = { BIN_SH, \"-c\", \"system_profiler SPHardwareDataType | grep 'Model Name'\" };\n            String modelTmp = runSystemCommand(cmds, true, this.executorService);\n            if (modelTmp.contains(\": \")) {\n                modelName = modelTmp.split(SPACES_REGEX)[1];\n            }\n        } else if (OS_LINUX.equals(getOsName())) {\n            String modelTmp = runSystemCommand(DMIDECODE_COMMAND, false, this.executorService);\n            if (modelTmp.contains(\"Product Name: \")) {\n                modelName = modelTmp.split(\"Product Name:\\\\s+\")[1].split(\"\\n\")[0];\n            }\n        } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n            String[] cmds = { \"wmic\", \"baseboard\", \"get\", \"Product\" };\n            String biosTmp = runSystemCommand(cmds, false, this.executorService);\n            if (biosTmp.contains(\"Product\")) {\n                modelName = biosTmp.split(\"Product\\\\s+\")[1];\n                modelName = modelName.trim();\n            }\n        }\n\n        return modelName;\n    }\n\n    @Override\n    public String getPartNumber() {\n        final Optional<String> override = getProperty(KEY_PART_NUMBER);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        String partNumber = UNSUPPORTED;\n\n        if (OS_LINUX.equals(getOsName()) && (LINUX_2_6_34_9_WR4_2_0_0_STANDARD.equals(getOsVersion())\n                || LINUX_2_6_34_12_WR4_3_0_0_STANDARD.equals(getOsVersion()))) {\n            partNumber = runSystemCommand(\"eth_partno_bsp\", false, this.executorService) + \" \"\n                    + runSystemCommand(\"eth_partno_epr\", false, this.executorService);\n        }\n\n        return partNumber;\n    }\n\n    @Override\n    public String getSerialNumber() {\n        final Optional<String> override = getProperty(KEY_SERIAL_NUM);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        String serialNum = UNKNOWN;\n\n        if (OS_MAC_OSX.equals(getOsName())) {\n            String[] cmds = { BIN_SH, \"-c\", \"system_profiler SPHardwareDataType | grep 'Serial Number'\" };\n            String serialTmp = runSystemCommand(cmds, true, this.executorService);\n            if (serialTmp.contains(\": \")) {\n                serialNum = serialTmp.split(SPACES_REGEX)[1];\n            }\n        } else if (OS_LINUX.equals(getOsName())) {\n            String serialTmp = runSystemCommand(DMIDECODE_COMMAND, false, this.executorService);\n            if (serialTmp.contains(\"Serial Number: \")) {\n                serialNum = serialTmp.split(\"Serial Number:\\\\s+\")[1].split(\"\\n\")[0];\n            }\n        } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n            String[] cmds = { \"wmic\", \"bios\", \"get\", \"SerialNumber\" };\n            String biosTmp = runSystemCommand(cmds, false, this.executorService);\n            if (biosTmp.contains(\"SerialNumber\")) {\n                serialNum = biosTmp.split(\"SerialNumber\\\\s+\")[1];\n                serialNum = serialNum.trim();\n            }\n        }\n\n        return serialNum;\n    }\n\n    @Override\n    public char[] getJavaKeyStorePassword() {\n        final Optional<String> keyStorePwd = getProperty(KEY_KURA_KEY_STORE_PWD);\n        if (keyStorePwd.isPresent()) {\n            return keyStorePwd.get().toCharArray();\n        }\n        return new char[0];\n    }\n\n    @Override\n    public char[] getJavaTrustStorePassword() {\n        final Optional<String> trustStorePwd = getProperty(KEY_KURA_TRUST_STORE_PWD);\n        if (trustStorePwd.isPresent()) {\n            return trustStorePwd.get().toCharArray();\n        }\n        return new char[0];\n    }\n\n    @Override\n    public Bundle[] getBundles() {\n        if (this.componentContext == null) {\n            return null;\n        }\n        return this.componentContext.getBundleContext().getBundles();\n    }\n\n    @Override\n    public List<SystemResourceInfo> getSystemPackages() throws KuraProcessExecutionErrorException {\n\n        List<SystemResourceInfo> packagesInfo = new ArrayList<>();\n        CommandStatus debStatus = execute(new String[] { \"dpkg-query\", \"-W\" });\n        if (debStatus.getExitStatus().isSuccessful()\n                && ((ByteArrayOutputStream) debStatus.getOutputStream()).size() > 0) {\n            parseSystemPackages(packagesInfo, debStatus, SystemResourceType.DEB);\n        }\n\n        CommandStatus rpmStatus = execute(\n                new String[] { \"rpm\", \"-qa\", \"--queryformat\", \"'%{NAME} %{VERSION}-%{RELEASE}\\n'\" });\n        if (rpmStatus.getExitStatus().isSuccessful()\n                && ((ByteArrayOutputStream) rpmStatus.getOutputStream()).size() > 0) {\n            parseSystemPackages(packagesInfo, rpmStatus, SystemResourceType.RPM);\n        }\n\n        CommandStatus apkStatus = execute(new String[] { \"apk\", \"list\", \"-I\", \"|\", \"awk\", \"'{ print $1 }'\" });\n        if (apkStatus.getExitStatus().isSuccessful()\n                && ((ByteArrayOutputStream) apkStatus.getOutputStream()).size() > 0) {\n            parseSystemPackages(packagesInfo, apkStatus, SystemResourceType.APK);\n        }\n\n        if (!debStatus.getExitStatus().isSuccessful() && !rpmStatus.getExitStatus().isSuccessful()\n                && !apkStatus.getExitStatus().isSuccessful()) {\n            throw new KuraProcessExecutionErrorException(\"Failed to retrieve system packages.\");\n        }\n        return packagesInfo;\n    }\n\n    private void parseSystemPackages(List<SystemResourceInfo> packagesInfo, CommandStatus status,\n            SystemResourceType type) {\n        String[] packages = new String(((ByteArrayOutputStream) status.getOutputStream()).toByteArray(),\n                StandardCharsets.UTF_8).split(\"\\n\");\n        Arrays.asList(packages).stream().forEach(p -> {\n            String[] fields = p.split(\"\\\\s+\"); // this works for dpkg and rpm where separator for version and name is a\n                                               // sequence of spaces\n            if (fields.length >= 2) {\n                packagesInfo.add(new SystemResourceInfo(fields[0], fields[1], type));\n            } else {\n                // apk case: need more complex parsing\n                String[] nameAndVersion = getApkNameAndVersion(fields[0]);\n                packagesInfo.add(new SystemResourceInfo(nameAndVersion[0], nameAndVersion[1], type));\n            }\n        });\n    }\n\n    /**\n     * An APK package name consists of the name and the version separated by \"-\".\n     * The name and the version itself can contain \"-\".\n     * Assumptions are that the fullName starts with the package name and ends with the version.\n     *\n     * @param fullName\n     *            of the APK software package, e.g. \"busybox-extras-1.31.1-r10\"\n     * @return String array with name in position 0 and version in position 1\n     */\n    private String[] getApkNameAndVersion(String fullName) {\n        String[] split = fullName.split(\"-\");\n        StringBuilder name = new StringBuilder();\n        StringBuilder version = new StringBuilder();\n        int matchIndex = 1000;\n        Pattern pattern = Pattern.compile(\"^([0-9]+.?)\");\n\n        for (int i = 0; i < split.length; i++) {\n            String s = split[i];\n\n            // version is never at the beginning\n            if (i > 0 && i < matchIndex) {\n                if (pattern.matcher(s).lookingAt()) {\n                    version.append(s);\n                    matchIndex = i;\n                } else {\n                    name.append(\"-\");\n                    name.append(s);\n                }\n            }\n\n            // everything else after match is version\n            if (i > matchIndex) {\n                version.append(\"-\");\n                version.append(s);\n            }\n        }\n\n        return new String[] { split[0] + name.toString(), version.toString() };\n    }\n\n    private CommandStatus execute(String[] commandLine) {\n        Command command = new Command(commandLine);\n        command.setExecuteInAShell(true);\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        ByteArrayOutputStream err = new ByteArrayOutputStream();\n        command.setErrorStream(err);\n        command.setOutputStream(out);\n        CommandStatus status = this.executorService.execute(command);\n        if (logger.isDebugEnabled()) {\n            logger.debug(\"execute command {} :: exited with code - {}\", command, status.getExitStatus().getExitCode());\n            logger.debug(\"execute stderr {}\", new String(err.toByteArray(), StandardCharsets.UTF_8));\n            logger.debug(\"execute stdout {}\", new String(out.toByteArray(), StandardCharsets.UTF_8));\n        }\n        return status;\n    }\n\n    @Override\n    public List<String> getDeviceManagementServiceIgnore() {\n        final Optional<String> servicesToIgnore = getProperty(CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE);\n        List<String> services = new ArrayList<>();\n        if (servicesToIgnore.isPresent() && !servicesToIgnore.get().trim().isEmpty()) {\n            String[] servicesArray = servicesToIgnore.get().split(\",\");\n            if (servicesArray != null && servicesArray.length > 0) {\n                services = Arrays.asList(servicesArray);\n            }\n        }\n\n        return services;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private Methods\n    //\n    // ----------------------------------------------------------------\n\n    private static void createDirIfNotExists(String fileName) {\n        // Make sure the configuration directory exists - create it if not\n        File file = new File(fileName);\n        if (!file.exists() && !file.mkdirs()) {\n            logger.error(\"Failed to create the temporary configuration directory: {}\", fileName);\n            if (Boolean.getBoolean(\"org.eclipse.kura.core.dontExitOnFailure\")) {\n                throw new RuntimeException(\n                        String.format(\"Failed to create the temporary configuration directory: %s\", fileName));\n            }\n            System.exit(-1);\n        }\n    }\n\n    @Override\n    public String getHostname() {\n        String hostname = UNKNOWN;\n\n        if (OS_MAC_OSX.equals(getOsName())) {\n            hostname = runSystemCommand(\"scutil --get ComputerName\", false, this.executorService);\n        } else if (OS_LINUX.equals(getOsName()) || OS_CLOUDBEES.equals(getOsName())\n                || getOsName().toLowerCase().startsWith(OS_WINDOWS)) {\n            hostname = runSystemCommand(\"hostname\", false, this.executorService);\n        }\n\n        return hostname;\n    }\n\n    @Override\n    public String getNetVirtualDevicesConfig() {\n        String status = NetInterfaceStatus.netIPv4StatusDisabled.name();\n        String virtualDefaultConfig = this.kuraProperties.getProperty(KEY_KURA_NET_VIRTUAL_DEVICES_CONFIG);\n        if (virtualDefaultConfig != null && virtualDefaultConfig.equalsIgnoreCase(\"unmanaged\")) {\n            status = NetInterfaceStatus.netIPv4StatusUnmanaged.name();\n        }\n        return status;\n    }\n\n    private static String hardwareAddressToString(byte[] macAddress) {\n        if (macAddress == null) {\n            return \"N/A\";\n        }\n\n        if (macAddress.length != 6) {\n            throw new IllegalArgumentException(\"macAddress is invalid\");\n        }\n\n        StringJoiner sj = new StringJoiner(\":\");\n        for (byte item : macAddress) {\n            sj.add(String.format(\"%02X\", item));\n        }\n\n        return sj.toString();\n    }\n\n    @Override\n    public String getCpuVersion() {\n        final Optional<String> override = getProperty(KEY_CPU_VERSION);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        if (OS_LINUX.equals(getOsName())) {\n            try {\n                return probeCpuVersionLinux();\n            } catch (final Exception e) {\n                // do nothing\n            }\n        }\n\n        return \"unknown\";\n    }\n\n    private static String probeCpuVersionLinux() throws IOException {\n        try (final BufferedReader reader = new BufferedReader(new FileReader(\"/proc/cpuinfo\"))) {\n            String line;\n\n            while ((line = reader.readLine()) != null) {\n                final int separatorIndex = line.indexOf(':');\n\n                if (separatorIndex == -1) {\n                    continue;\n                }\n\n                final String key = line.substring(0, separatorIndex).trim();\n\n                if (key.equals(\"model name\")) {\n                    return line.substring(separatorIndex + 1).trim();\n                }\n            }\n        }\n\n        throw new IOException(\"Could not retrieve cpu version\");\n    }\n\n    protected Optional<String> getProperty(final String key) {\n        final String prop = this.kuraProperties.getProperty(key);\n\n        if (prop != null) {\n            return Optional.of(prop);\n        }\n\n        final String externalProvider = this.kuraProperties.getProperty(key + PROPERTY_PROVIDER_SUFFIX);\n\n        if (externalProvider != null) {\n            final String result = processCommandOutput(runSystemCommand(externalProvider, true, this.executorService));\n\n            if (result != null && !result.isEmpty()) {\n                return Optional.of(result);\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    private String processCommandOutput(final String result) {\n        if (result == null) {\n            return null;\n        }\n\n        final String trimmed = result.trim();\n\n        if (trimmed.isEmpty()) {\n            return trimmed;\n        }\n\n        int i;\n\n        for (i = trimmed.length() - 1; i > 0; i--) {\n            if (trimmed.charAt(i) != '\\n') {\n                break;\n            }\n        }\n\n        return trimmed.substring(0, i + 1);\n    }\n\n    @Override\n    public Optional<ExtendedProperties> getExtendedProperties() {\n        return Optional.empty();\n    }\n\n    @Override\n    public String getCommandUser() {\n        final Optional<String> override = getProperty(KEY_COMMAND_USER);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return \"unknown\";\n    }\n\n    @Override\n    public boolean isLegacyBluetoothBeaconScan() {\n        final Optional<String> override = getProperty(KEY_LEGACY_BT_BEACON_SCAN);\n        if (override.isPresent()) {\n            return Boolean.parseBoolean(override.get());\n        }\n\n        return false;\n    }\n\n    @Override\n    public boolean isLegacyPPPLoggingEnabled() {\n        final Optional<String> override = getProperty(KEY_LEGACY_PPP_LOGGING);\n        if (override.isPresent()) {\n            return Boolean.parseBoolean(override.get());\n        }\n\n        return false;\n    }\n\n    @Override\n    public String getJavaVmVendor() {\n        final Optional<String> override = getProperty(KEY_JAVA_VM_VENDOR);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_JAVA_VM_VENDOR);\n    }\n\n    @Override\n    public String getJdkVendorVersion() {\n        final Optional<String> override = getProperty(KEY_JDK_VENDOR_VERSION);\n        if (override.isPresent()) {\n            return override.get();\n        }\n\n        return System.getProperty(KEY_JDK_VENDOR_VERSION);\n    }\n\n    @Override\n    public Optional<String> getDefaultLogManager() {\n        return getProperty(KEY_DEFAULT_LOG_MANAGER);\n    }\n\n    @Override\n    public boolean isWPA3WifiSecurityEnabled() {\n        final Optional<String> isWPA3enabled = getProperty(KEY_WPA3_WIFI_SECURITY_ENABLE);\n        if (isWPA3enabled.isPresent()) {\n            return Boolean.parseBoolean(isWPA3enabled.get());\n        }\n\n        return false;\n    }\n\n    @Override\n    public int getNetworkConfigurationTimeout() {\n        return getIntegerPropertyValue(KEY_NETWORK_CONFIGURATION_TIMEOUT, 30);\n    }\n\n    @Override\n    public String getInternetConnectionStatusCheckHost() {\n        return getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST)\n                .orElse(DEFAULT_INTERNET_CONNECTION_STATUS_CHECK_HOST);\n    }\n\n    @Override\n    public String getInternetConnectionStatusCheckIp() {\n        return getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_IP).orElse(DEFAULT_INTERNET_CONNECTION_STATUS_CHECK_IP);\n    }\n\n    private int getIntegerPropertyValue(String propertyName, int defaultValue) {\n        final Optional<String> propertyValue = getProperty(propertyName);\n        if (propertyValue.isPresent() && !propertyValue.get().trim().isEmpty()) {\n            try {\n                return Integer.parseInt(propertyValue.get());\n            } catch (NumberFormatException e) {\n                logger.error(\"Cannot parse integer value for property {}: {}. Set it to default {}.\", propertyName,\n                        propertyValue.get(), defaultValue, e);\n            }\n        }\n        return defaultValue;\n    }\n\n    @Override\n    public InternetConnectionStatus getInternetConnectionStatus() {\n        return this.currentInternetStatus.get();\n    }\n\n    private void checkInternetTask() {\n        if (this.executorService == null) {\n            return;\n        }\n\n        InternetConnectionStatus oldStatus = this.currentInternetStatus.get();\n\n        try {\n\n            if (isPingable(StandardProtocolFamily.INET, getInternetConnectionStatusCheckHost())\n                    || isPingable(StandardProtocolFamily.INET6, getInternetConnectionStatusCheckHost())) {\n                updateStatus(oldStatus, InternetConnectionStatus.FULL);\n                return;\n            }\n\n            if (isPingable(StandardProtocolFamily.INET, getInternetConnectionStatusCheckIp())\n                    || isPingable(StandardProtocolFamily.INET6, getInternetConnectionStatusCheckIp())) {\n                updateStatus(oldStatus, InternetConnectionStatus.IP_ONLY);\n                return;\n            }\n\n            updateStatus(oldStatus, InternetConnectionStatus.UNAVAILABLE);\n        } catch (Exception e) {\n            logger.error(\"Error while checking internet connection status\", e);\n        }\n    }\n\n    private void updateStatus(InternetConnectionStatus oldStatus, InternetConnectionStatus newStatus) {\n        this.currentInternetStatus.set(newStatus);\n        if (newStatus != oldStatus) {\n            logger.debug(\"Internet connection status changed to {}\", newStatus);\n        }\n    }\n\n    private boolean isPingable(StandardProtocolFamily protocol, String address) {\n        String version;\n\n        switch (protocol) {\n        case INET:\n            version = \"-4\";\n            break;\n\n        case INET6:\n            version = \"-6\";\n            break;\n        default:\n            throw new IllegalArgumentException(\"Unexpected protocol: \" + protocol);\n        }\n\n        try {\n            // -c 5: send 5 ping requests,\n            // -W 5: wait for 1 seconds max for each reply\n            CommandStatus status = this.executorService\n                    .execute(new Command(new String[] { \"ping\", version, address, \"-c\", \"5\", \"-W\", \"1\" }));\n            return status.getExitStatus().isSuccessful();\n        } catch (Exception e) {\n            logger.trace(\"Error while executing ping command\", e);\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/.gitignore",
    "content": "lib/"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.db.h2db.provider\nBundle-SymbolicName: org.eclipse.kura.db.h2db.provider;singleton:=true\nBundle-Version: 1.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.7,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.connection.listener;version=\"1.0.0\",\n org.eclipse.kura.crypto;version=\"1.3.0\",\n org.eclipse.kura.data;version=\"[1.1,2.0)\",\n org.eclipse.kura.db;version=\"[2.0,2.1)\",\n org.eclipse.kura.message.store;version=\"[1.0,2.0)\",\n org.eclipse.kura.message.store.provider;version=\"[1.0,1.1)\",\n org.eclipse.kura.type;version=\"[1.1,2.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0,1.1)\",\n org.eclipse.kura.util.jdbc;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.message.store;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.store.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.wire.store;version=\"[1.0,1.1)\",\n org.eclipse.kura.wire;version=\"[2.0,3.0)\",\n org.eclipse.kura.wire.store.provider;version=\"[1.0,1.1)\",\n org.h2;version=\"2.4.240\",\n org.h2.api;version=\"2.4.240\",\n org.h2.jdbcx;version=\"2.4.240\",\n org.h2.tools;version=\"2.4.240\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.component;version=\"1.4.0\",\n org.slf4j;version=\"1.7.32\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/OSGI-INF/h2db.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" enabled=\"true\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" modified=\"updated\" name=\"org.eclipse.kura.core.db.H2DbService\">\n   <implementation class=\"org.eclipse.kura.internal.db.h2db.provider.H2DbServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.db.BaseDbService\"/>\n      <provide interface=\"org.eclipse.kura.db.H2DbService\"/>\n      <provide interface=\"org.eclipse.kura.message.store.provider.MessageStoreProvider\"/>\n      <provide interface=\"org.eclipse.kura.wire.store.provider.WireRecordStoreProvider\"/>\n      <provide interface=\"org.eclipse.kura.wire.store.provider.QueryableWireRecordStoreProvider\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.core.db.H2DbService\"/>\n   <reference bind=\"setCryptoService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.crypto.CryptoService\" name=\"CryptoService\" policy=\"static\" unbind=\"unsetCryptoService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/OSGI-INF/h2dbserver.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.core.db.H2DbServer\">\n   <implementation class=\"org.eclipse.kura.internal.db.h2db.provider.H2DbServer\"/>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.core.db.H2DbServer\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/OSGI-INF/metatype/org.eclipse.kura.core.db.H2DbServer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.core.db.H2DbServer\" \n         name=\"H2DbServer\" \n         description=\"H2 based database server.\">\n\n        <AD id=\"db.server.enabled\"\n            name=\"db.server.enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"false\"\n            description=\"Specifies whether the DB server is enabled or not.\"/>\n\n        <AD id=\"db.server.type\"\n            name=\"db.server.type\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"TCP\"\n            description=\"Specifies the server type, see http://www.h2database.com/javadoc/org/h2/tools/Server.html for more details.\">\n            <Option label=\"WEB\" value=\"WEB\" />\n            <Option label=\"TCP\" value=\"TCP\" />\n            <Option label=\"PG\" value=\"PG\" />\n        </AD>\n\n        <AD id=\"db.server.commandline\"\n            name=\"db.server.commandline\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"-tcpPort 9123 -tcpAllowOthers -ifExists\"\n            description=\"Specifies the parameters for the server, see http://www.h2database.com/javadoc/org/h2/tools/Server.html for more details. The listening port must be manually openend in the Firewall configuration section in order to allow external connections.\"/>\n        \n    </OCD>\n    <Designate pid=\"org.eclipse.kura.core.db.H2DbServer\" factoryPid=\"org.eclipse.kura.core.db.H2DbServer\">\n        <Object ocdref=\"org.eclipse.kura.core.db.H2DbServer\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/OSGI-INF/metatype/org.eclipse.kura.core.db.H2DbService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.core.db.H2DbService\" \n         name=\"DbService\" \n         description=\"H2 based database service.\">\n\n        <AD id=\"db.connector.url\"\n            name=\"Connector URL\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"jdbc:h2:mem:kuradb\"\n            description=\"JDBC connector URL of the database instance. See http://www.h2database.com/html/features.html for more information. \n            Passing the USER and PASSWORD parameters in the connector URL is not supported, these paramters will be ignored if present. \n            Please use the db.user and db.password fields to provide the credentials.\n\t    In case of persisted databases, the database file path is subject to limitations. \n            Please make sure to read official H2DbService documentation before creating a new database.\"/>\n\n        <AD id=\"db.user\"\n            name=\"User\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"SA\"\n            description=\"Specifies the user for the database connection.\"/>\n\n        <AD id=\"db.password\"\n            name=\"Password\"\n            type=\"Password\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"\"\n            description=\"Specifies the password. The default password is the empty string.\"/>\n            \n        <AD id=\"db.checkpoint.interval.seconds\"\n            name=\"Checkpoint interval (seconds)\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"900\"\n            min=\"5\"\n            description=\"H2DbService instances support running periodic checkpoints to ensure data consistency. This parameter specifies the interval in seconds between two successive checkpoints. This setting has no effect for in-memory database instances.\"/>\n            \n        <AD id=\"db.defrag.interval.minutes\"\n            name=\"Defrag interval (minutes)\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"15\"\n            min=\"0\"\n            description=\"H2DbService instances support running periodic defragmentation. This parameter specifies the interval in minutes beetween two successive checkpoints, set to zero to disable. This setting has no effect for in-memory database instances. Existing database connections will be closed during the defragmentation process and need to be reopened by the applications.\"/>    \n            \n         <AD id=\"db.connection.pool.max.size\"\n            name=\"Connection pool max size\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"10\"\n            min=\"1\"\n            description=\"The H2DbService manages connections using a connection pool. This parameter defines the maximum number of connections for the pool\"/>\n        </OCD>\n    <Designate pid=\"org.eclipse.kura.core.db.H2DbService\" factoryPid=\"org.eclipse.kura.core.db.H2DbService\">\n        <Object ocdref=\"org.eclipse.kura.core.db.H2DbService\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/build.properties",
    "content": "#\n#  Copyright (c) 2024 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput..  = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about_files/,\\\n               about.html\nsrc.includes = about.html,\\\n               about_files/\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.db.h2db.provider</artifactId>\n\t<version>1.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbMessageStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.db.h2db.provider;\n\nimport java.io.ByteArrayInputStream;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Timestamp;\nimport java.sql.Types;\nimport java.util.Date;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.message.store.StoredMessage;\nimport org.eclipse.kura.message.store.StoredMessage.Builder;\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.util.jdbc.JdbcUtil;\nimport org.eclipse.kura.util.message.store.AbstractJdbcMessageStoreImpl;\nimport org.eclipse.kura.util.message.store.JdbcMessageStoreQueries;\nimport org.h2.api.ErrorCode;\n\n@SuppressWarnings(\"restriction\")\npublic class H2DbMessageStoreImpl extends AbstractJdbcMessageStoreImpl {\n\n    private static final String CREATE_INDEX_IF_NOT_EXISTS = \"CREATE INDEX IF NOT EXISTS \";\n\n    private static final String UPDATE = \"UPDATE \";\n\n    private static final String DELETE_FROM = \"DELETE FROM \";\n\n    private static final String SELECT_MESSAGE_METADATA_FROM = \"SELECT id, topic, qos, retain, createdOn, publishedOn, \"\n            + \"publishedMessageId, confirmedOn, priority, sessionId, droppedOn FROM \";\n\n    private static final String ALTER_TABLE = \"ALTER TABLE \";\n\n    private static final int PAYLOAD_BYTE_SIZE_THRESHOLD = 200;\n    /**\n     * The error with code 22003 is thrown when a value is out of range when\n     * converting to another data type.\n     */\n    private static final int NUMERIC_VALUE_OUT_OF_RANGE_1 = 22003;\n    /**\n     * The error with code 22004 is thrown when a value is out of range when\n     * converting to another column's data type.\n     */\n    private static final int NUMERIC_VALUE_OUT_OF_RANGE_2 = 22004;\n\n    private String sqlSetNextId;\n    private String sqlGetFreeId;\n\n    public H2DbMessageStoreImpl(final ConnectionProvider provider, final String table) throws KuraStoreException {\n        super(provider, table);\n\n        initDb();\n    }\n\n    private void initDb() throws KuraStoreException {\n        this.sqlSetNextId = ALTER_TABLE + super.escapedTableName + \" ALTER COLUMN id RESTART WITH ?;\";\n        this.sqlGetFreeId = \"SELECT A.X FROM SYSTEM_RANGE(1, 2147483647) AS A LEFT OUTER JOIN \" + this.escapedTableName\n                + \" AS B ON A.X = B.ID WHERE B.ID IS NULL LIMIT 1\";\n\n        super.createTable();\n        super.createIndexes();\n    }\n\n    @Override\n    protected JdbcMessageStoreQueries buildSqlMessageStoreQueries() {\n\n        return JdbcMessageStoreQueries.builder().withSqlCreateTable(\"CREATE TABLE IF NOT EXISTS \"\n                + super.escapedTableName\n                + \" (id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, topic VARCHAR(32767 CHARACTERS), qos INTEGER, retain BOOLEAN, \"\n                + \"createdOn TIMESTAMP, publishedOn TIMESTAMP, publishedMessageId INTEGER, confirmedOn TIMESTAMP, \"\n                + \"smallPayload VARBINARY, largePayload BLOB(16777216), priority INTEGER,\"\n                + \" sessionId VARCHAR(32767 CHARACTERS), droppedOn TIMESTAMP);\")\n                .withSqlMessageCount(\"SELECT COUNT(*) FROM \" + super.escapedTableName + \";\")\n                .withSqlStore(\"INSERT INTO \" + super.escapedTableName\n                        + \" (topic, qos, retain, createdOn, publishedOn, publishedMessageId, confirmedOn, smallPayload, largePayload, priority, \"\n                        + \"sessionId, droppedOn) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\")\n                .withSqlGetMessage(\n                        \"SELECT id, topic, qos, retain, createdOn, publishedOn, publishedMessageId, confirmedOn, \"\n                                + \"smallPayload, largePayload, priority, sessionId, droppedOn FROM \"\n                                + this.escapedTableName + \" WHERE id = ?\")\n                .withSqlGetNextMessage(\"SELECT a.id, a.topic, a.qos, a.retain, a.createdOn, a.publishedOn, \"\n                        + \"a.publishedMessageId, a.confirmedOn, a.smallPayload, a.largePayload, a.priority, a.sessionId, a.droppedOn FROM \"\n                        + this.escapedTableName + \" AS a JOIN (SELECT id, publishedOn FROM \" + super.escapedTableName\n                        + \" ORDER BY publishedOn ASC NULLS FIRST, priority ASC, createdOn ASC LIMIT 1) AS b \"\n                        + \"WHERE a.id = b.id AND b.publishedOn IS NULL;\")\n                .withSqlSetPublishedQoS1(UPDATE + super.escapedTableName\n                        + \" SET publishedOn = ?, publishedMessageId = ?, sessionId = ? WHERE id = ?;\")\n                .withSqlSetPublishedQoS0(UPDATE + super.escapedTableName + \" SET publishedOn = ? WHERE id = ?;\")\n                .withSqlSetConfirmed(UPDATE + this.escapedTableName + \" SET confirmedOn = ? WHERE id = ?;\")\n                .withSqlAllUnpublishedMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName\n                        + \" WHERE publishedOn IS NULL ORDER BY priority ASC, createdOn ASC;\")\n                .withSqlAllInFlightMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName\n                        + \" WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL AND droppedOn IS NULL \"\n                        + \"ORDER BY priority ASC, createdOn ASC\")\n                .withSqlAllDroppedInFlightMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName\n                        + \" WHERE droppedOn IS NOT NULL ORDER BY priority ASC, createdOn ASC;\")\n                .withSqlUnpublishAllInFlightMessages(UPDATE + super.escapedTableName\n                        + \" SET publishedOn = NULL WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL;\")\n                .withSqlDropAllInFlightMessages(UPDATE + super.escapedTableName\n                        + \" SET droppedOn = ? WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL;\")\n                .withSqlDeleteDroppedMessages(DELETE_FROM + super.escapedTableName\n                        + \" WHERE droppedOn <= DATEADD('MILLISECOND', ?, TIMESTAMP '1970-01-01 00:00:00') AND droppedOn IS NOT NULL;\")\n                .withSqlDeleteConfirmedMessages(DELETE_FROM + super.escapedTableName\n                        + \" WHERE confirmedOn <= DATEADD('MILLISECOND', ?, TIMESTAMP '1970-01-01 00:00:00') AND confirmedOn IS NOT NULL;\")\n                .withSqlDeletePublishedMessages(DELETE_FROM + super.escapedTableName\n                        + \" WHERE qos = 0 AND publishedOn <= DATEADD('MILLISECOND', ?, TIMESTAMP '1970-01-01 00:00:00') AND publishedOn IS NOT NULL;\")\n                .withSqlCreateNextMessageIndex(\n                        CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + \"_nextMsg\") + \" ON \"\n                                + super.escapedTableName + \" (publishedOn ASC, priority ASC, createdOn ASC, qos);\")\n                .withSqlCreatePublishedOnIndex(\n                        CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + \"_PUBLISHEDON\") + \" ON \"\n                                + this.escapedTableName + \" (publishedOn DESC);\")\n                .withSqlCreateConfirmedOnIndex(\n                        CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + \"_CONFIRMEDON\") + \" ON \"\n                                + this.escapedTableName + \" (confirmedOn DESC);\")\n                .withSqlCreateDroppedOnIndex(\n                        CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + \"_DROPPEDON\") + \" ON \"\n                                + this.escapedTableName + \" (droppedOn DESC);\")\n                .build();\n    }\n\n    @Override\n    public synchronized int store(String topic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraStoreException {\n\n        validate(topic);\n\n        try {\n            return (int) storeInternal(topic, payload, qos, retain, priority);\n        } catch (KuraStoreException e) {\n            handleKuraStoreException(e);\n            return (int) storeInternal(topic, payload, qos, retain, priority);\n        }\n\n    }\n\n    private void handleKuraStoreException(final KuraStoreException e) throws KuraStoreException {\n\n        final Throwable cause = e.getCause();\n\n        if (!(cause instanceof SQLException)) {\n            throw e;\n        }\n\n        final int errorCode = ((SQLException) cause).getErrorCode();\n\n        if (errorCode == NUMERIC_VALUE_OUT_OF_RANGE_1 || errorCode == NUMERIC_VALUE_OUT_OF_RANGE_2\n                || errorCode == ErrorCode.SEQUENCE_EXHAUSTED || errorCode == ErrorCode.DUPLICATE_KEY_1) {\n\n            if (super.getMessageCountInternal() >= Integer.MAX_VALUE) {\n                throw new KuraStoreException(\"Table size is greater or equal than integer max value\");\n            }\n\n            final int freeId = super.connectionProvider.withPreparedStatement(this.sqlGetFreeId,\n                    (c, stmt) -> JdbcUtil.getFirstColumnValue(stmt::executeQuery, ResultSet::getInt),\n                    \"failed to get free ID\");\n\n            super.execute(this.sqlSetNextId, freeId);\n            return;\n        }\n\n        throw e;\n    }\n\n    @Override\n    protected synchronized long storeInternal(String topic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraStoreException {\n\n        final Timestamp now = new Timestamp(new Date().getTime());\n\n        return super.connectionProvider.withConnection(c -> {\n\n            final long result;\n\n            try (PreparedStatement pstmt = c.prepareStatement(super.queries.getSqlStore(), new String[] { \"id\" })) {\n                pstmt.setString(1, topic);\n                pstmt.setInt(2, qos);\n                pstmt.setBoolean(3, retain);\n                pstmt.setTimestamp(4, now, this.utcCalendar);\n                pstmt.setTimestamp(5, null);\n                pstmt.setInt(6, -1);\n                pstmt.setTimestamp(7, null);\n\n                if (payload == null || payload.length < PAYLOAD_BYTE_SIZE_THRESHOLD) {\n                    pstmt.setBytes(8, payload);\n                    pstmt.setNull(9, Types.BLOB);\n                } else {\n                    pstmt.setNull(8, Types.VARBINARY);\n                    pstmt.setBinaryStream(9, new ByteArrayInputStream(payload), payload.length);\n                }\n\n                pstmt.setInt(10, priority);\n                pstmt.setString(11, null);\n                pstmt.setTimestamp(12, null);\n\n                pstmt.execute();\n\n                result = (long) JdbcUtil.getFirstColumnValue(pstmt::getGeneratedKeys, ResultSet::getInt);\n\n            }\n\n            c.commit();\n\n            return result;\n        }, \"Cannot store message\");\n\n    }\n\n    @Override\n    protected Builder buildStoredMessageBuilder(ResultSet rs, boolean includePayload) throws SQLException {\n        StoredMessage.Builder result = super.buildStoredMessageBuilder(rs, false);\n\n        if (includePayload) {\n            byte[] payload = rs.getBytes(\"smallPayload\");\n            if (payload == null) {\n                payload = rs.getBytes(\"largePayload\");\n            }\n\n            result = result.withPayload(payload);\n        }\n\n        return result;\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbQueryableWireRecordStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.db.h2db.provider;\n\nimport static java.util.Objects.isNull;\n\nimport java.sql.Blob;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.util.Optional;\n\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.util.wire.store.AbstractJdbcQueryableWireRecordStoreImpl;\n\n@SuppressWarnings(\"restriction\")\npublic class H2DbQueryableWireRecordStoreImpl extends AbstractJdbcQueryableWireRecordStoreImpl {\n\n    protected H2DbQueryableWireRecordStoreImpl(ConnectionProvider provider) {\n        super(provider);\n    }\n\n    @Override\n    protected Optional<Object> extractColumnValue(final ResultSet rset, final ResultSetMetaData rmet, final int i)\n            throws SQLException {\n        Object dbExtractedData = rset.getObject(i);\n\n        if (isNull(dbExtractedData)) {\n            return Optional.empty();\n        }\n\n        if (dbExtractedData instanceof Blob) {\n            final Blob dbExtractedBlob = (Blob) dbExtractedData;\n            final int dbExtractedBlobLength = (int) dbExtractedBlob.length();\n            dbExtractedData = dbExtractedBlob.getBytes(1, dbExtractedBlobLength);\n        }\n\n        return Optional.of(dbExtractedData);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbServer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.h2db.provider;\n\nimport java.sql.SQLException;\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.h2.tools.Server;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class H2DbServer implements ConfigurableComponent {\n\n    enum ServerType {\n        WEB,\n        TCP,\n        PG\n    }\n\n    private static final Logger logger = LoggerFactory.getLogger(H2DbServer.class);\n    private Server server;\n\n    protected void activate(Map<String, Object> properties) {\n        logger.info(\"activating...\");\n        updated(properties);\n        logger.info(\"activating...done\");\n    }\n\n    protected void updated(Map<String, Object> properties) {\n        logger.info(\"updating...\");\n        restartServer(new H2DbServerOptions(properties));\n        logger.info(\"updating...done\");\n    }\n\n    protected void deactivate() {\n        logger.info(\"deactivating...\");\n        shutdownServer();\n        logger.info(\"deactivating...done\");\n    }\n\n    private void restartServer(H2DbServerOptions configuration) {\n        shutdownServer();\n        Server newServer = null;\n        if (configuration.isServerEnabled()) {\n            try {\n                logger.info(\"Starting DB server...\");\n                final String[] commandline = configuration.getServerCommandLine().split(\" \");\n                logger.debug(\"Server type: {}, commandline: {}\", configuration.getServerType(), commandline);\n                switch (configuration.getServerType()) {\n                case TCP:\n                    newServer = Server.createTcpServer(commandline);\n                    break;\n                case WEB:\n                    newServer = Server.createWebServer(commandline);\n                    break;\n                case PG:\n                    newServer = Server.createPgServer(commandline);\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"Unknown server type\");\n                }\n                newServer.start();\n                this.server = newServer;\n                logger.info(\"Starting DB server...done\");\n            } catch (SQLException e) {\n                logger.error(\"Failed to start server\", e);\n                shutdownServer(newServer);\n            }\n        }\n    }\n\n    private void shutdownServer() {\n        shutdownServer(this.server);\n        this.server = null;\n    }\n\n    private void shutdownServer(Server server) {\n        if (server != null) {\n            try {\n                logger.info(\"Shutting down DB server...\");\n                server.stop();\n                logger.info(\"Shutting down DB server...done\");\n            } catch (Exception e) {\n                logger.error(\"failed to shutdown DB server\", e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbServerOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.h2db.provider;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.internal.db.h2db.provider.H2DbServer.ServerType;\n\nclass H2DbServerOptions {\n\n    private static final String DB_SERVER_ENABLED_PROP_NAME = \"db.server.enabled\";\n    private static final String DB_SERVER_TYPE_PROP_NAME = \"db.server.type\";\n    private static final String DB_COMMAND_LINE_PROP_NAME = \"db.server.commandline\";\n\n    private static final Boolean DB_SERVER_ENABLED_DEFAULT = false;\n    private static final String DB_SERVER_COMMAND_LINE_DEFAULT = \"-tcpPort 9123 -tcpAllowOthers -ifExists\";\n\n    private final Boolean isServerEnabled;\n    private final ServerType serverType;\n    private final String serverCommandLine;\n\n    @SuppressWarnings(\"unchecked\")\n    private <T> T getSafe(Object o, T defaultValue) {\n        if (defaultValue.getClass().isInstance(o)) {\n            return (T) o;\n        }\n        return defaultValue;\n    }\n\n    public H2DbServerOptions(Map<String, Object> properties) {\n        this.isServerEnabled = getSafe(properties.get(DB_SERVER_ENABLED_PROP_NAME), DB_SERVER_ENABLED_DEFAULT);\n        this.serverCommandLine = getSafe(properties.get(DB_COMMAND_LINE_PROP_NAME), DB_SERVER_COMMAND_LINE_DEFAULT);\n\n        final String serverTypeString = (String) properties.getOrDefault(DB_SERVER_TYPE_PROP_NAME, \"TCP\");\n\n        if (ServerType.WEB.name().equals(serverTypeString)) {\n            this.serverType = ServerType.WEB;\n        } else if (ServerType.PG.name().equals(serverTypeString)) {\n            this.serverType = ServerType.PG;\n        } else {\n            this.serverType = ServerType.TCP;\n        }\n    }\n\n    public Boolean isServerEnabled() {\n        return this.isServerEnabled;\n    }\n\n    public ServerType getServerType() {\n        return this.serverType;\n    }\n\n    public String getServerCommandLine() {\n        return this.serverCommandLine;\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.h2db.provider;\n\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.ThreadPoolExecutor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.connection.listener.ConnectionListener;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.db.H2DbService;\nimport org.eclipse.kura.message.store.provider.MessageStore;\nimport org.eclipse.kura.message.store.provider.MessageStoreProvider;\nimport org.eclipse.kura.util.jdbc.SQLFunction;\nimport org.eclipse.kura.util.store.listener.ConnectionListenerManager;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.eclipse.kura.wire.store.provider.QueryableWireRecordStoreProvider;\nimport org.eclipse.kura.wire.store.provider.WireRecordStore;\nimport org.eclipse.kura.wire.store.provider.WireRecordStoreProvider;\nimport org.h2.jdbcx.JdbcConnectionPool;\nimport org.h2.jdbcx.JdbcDataSource;\nimport org.h2.tools.DeleteDbFiles;\nimport org.osgi.service.component.ComponentException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class H2DbServiceImpl implements H2DbService, MessageStoreProvider, WireRecordStoreProvider,\n        ConfigurableComponent, QueryableWireRecordStoreProvider {\n\n    private static final String ANONYMOUS_MEM_INSTANCE_JDBC_URL = \"jdbc:h2:mem:\";\n    private static Map<String, H2DbServiceImpl> activeInstances = Collections.synchronizedMap(new HashMap<>());\n\n    private static final int MAX_LENGTH_INPLACE_LOB_VALUE = 2000000000;\n\n    private static Logger logger = LoggerFactory.getLogger(H2DbServiceImpl.class);\n\n    static {\n\n        // load the driver\n        // Use this way of loading the driver as it is required for OSGi\n        // Just loading the class with Class.forName is not sufficient.\n        try {\n            DriverManager.registerDriver(new org.h2.Driver());\n        } catch (SQLException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private H2DbServiceOptions configuration;\n\n    private JdbcDataSource dataSource;\n    private JdbcConnectionPool connectionPool;\n\n    private char[] lastSessionPassword = null;\n\n    private CryptoService cryptoService;\n\n    private ScheduledExecutorService executor;\n\n    private ScheduledFuture<?> checkpointTask;\n    private ScheduledFuture<?> defragTask;\n\n    private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true);\n    private final AtomicInteger pendingUpdates = new AtomicInteger();\n    private final ThreadLocal<Boolean> isOnExecutor = ThreadLocal.withInitial(() -> false);\n\n    private ConnectionListenerManager listenerManager = new ConnectionListenerManager();\n\n    private final ThreadPoolExecutor executorService = new ThreadPoolExecutor(0, 10, 0L, TimeUnit.MILLISECONDS,\n            new LinkedBlockingQueue<>());\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void unsetCryptoService(CryptoService cryptoService) {\n        if (this.cryptoService.equals(cryptoService)) {\n            this.cryptoService = null;\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    public void activate(final Map<String, Object> properties) {\n        logger.info(\"activating...\");\n\n        final String kuraServicePid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n        final ThreadFactory defaultFactory = this.executorService.getThreadFactory();\n        final AtomicInteger threadNumber = new AtomicInteger();\n\n        this.executorService.setThreadFactory(r -> {\n            final Thread result = defaultFactory.newThread(() -> {\n                this.isOnExecutor.set(true);\n                r.run();\n            });\n            result.setName(\"H2DbService_\" + kuraServicePid + \"_\" + threadNumber.getAndIncrement());\n            return result;\n        });\n\n        this.executor = Executors.newSingleThreadScheduledExecutor();\n        updated(properties);\n\n        logger.info(\"activating...done\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        this.pendingUpdates.incrementAndGet();\n        this.executor.submit(() -> updateInternal(properties));\n    }\n\n    public void deactivate() {\n        logger.info(\"deactivate...\");\n        this.executor.shutdown();\n        try {\n            this.executor.awaitTermination(1, TimeUnit.MINUTES);\n        } catch (InterruptedException e1) {\n            logger.warn(\"Interrupted while waiting for db shutdown\");\n            Thread.currentThread().interrupt();\n        }\n\n        this.isOnExecutor.remove();\n        this.executorService.shutdown();\n        awaitExecutorServiceTermination();\n\n        try {\n            shutdownDb();\n        } catch (SQLException e) {\n            logger.warn(\"got exception while shutting down the database\", e);\n        }\n        this.listenerManager.shutdown();\n        logger.info(\"deactivate...done\");\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Service APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public Connection getConnection() throws SQLException {\n        if (this.pendingUpdates.get() > 0) {\n            syncWithExecutor();\n        }\n\n        final Lock lock = this.rwLock.readLock();\n        lock.lock();\n        try {\n            return getConnectionInternal();\n        } finally {\n            lock.unlock();\n        }\n    }\n\n    private <T> T withConnectionInternal(ConnectionCallable<T> callable) throws SQLException {\n        final Lock executorlock = this.rwLock.readLock();\n        executorlock.lock();\n        Connection connection = null;\n        try {\n            connection = getConnectionInternal();\n            return callable.call(connection);\n        } catch (final SQLException e) {\n            logger.warn(\"Db operation failed\");\n            rollback(connection);\n            throw e;\n        } finally {\n            close(connection);\n            executorlock.unlock();\n        }\n    }\n\n    @Override\n    public <T> T withConnection(ConnectionCallable<T> callable) throws SQLException {\n        if (this.pendingUpdates.get() > 0) {\n            syncWithExecutor();\n        }\n\n        if (Boolean.TRUE.equals(this.isOnExecutor.get())) {\n            return withConnectionInternal(callable);\n        }\n\n        final Future<T> result = this.executorService.submit(() -> withConnectionInternal(callable));\n\n        try {\n            return result.get();\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new SQLException(e);\n        } catch (ExecutionException e) {\n            if (e.getCause() instanceof SQLException) {\n                throw (SQLException) e.getCause();\n            } else if (e.getCause() instanceof RuntimeException) {\n                throw (RuntimeException) e.getCause();\n            }\n            throw new IllegalStateException(e);\n        }\n\n    }\n\n    @Override\n    public void rollback(Connection conn) {\n        try {\n            if (conn != null) {\n                conn.rollback();\n            }\n        } catch (SQLException e) {\n            logger.error(\"Error during Connection rollback.\", e);\n        }\n    }\n\n    @Override\n    public void close(ResultSet... rss) {\n        if (rss != null) {\n            for (ResultSet rs : rss) {\n                try {\n                    if (rs != null) {\n                        rs.close();\n                    }\n                } catch (SQLException e) {\n                    logger.error(\"Error during ResultSet closing\", e);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void close(Statement... stmts) {\n        if (stmts != null) {\n            for (Statement stmt : stmts) {\n                try {\n                    if (stmt != null) {\n                        stmt.close();\n                    }\n                } catch (SQLException e) {\n                    logger.error(\"Error during Statement closing\", e);\n                }\n            }\n        }\n    }\n\n    @Override\n    public void close(Connection conn) {\n        try {\n            if (conn != null) {\n                conn.close();\n            }\n        } catch (SQLException e) {\n            logger.error(\"Error during Connection closing\", e);\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private methods\n    //\n    // ----------------------------------------------------------------\n\n    private void updateInternal(final Map<String, Object> properties) {\n        final Lock lock = this.rwLock.writeLock();\n        lock.lock();\n        try {\n            logger.info(\"updating...\");\n\n            H2DbServiceOptions newConfiguration = new H2DbServiceOptions(properties);\n\n            shutdownIfUrlOrUserChanged(newConfiguration);\n\n            if (newConfiguration.isRemote()) {\n                throw new IllegalArgumentException(\"Remote databases are not supported\");\n            }\n\n            final String baseUrl = newConfiguration.getBaseUrl();\n            if (baseUrl.equals(ANONYMOUS_MEM_INSTANCE_JDBC_URL)) {\n                throw new IllegalArgumentException(\"Anonymous in-memory databases instances are not supported\");\n            }\n\n            if (isManagedByAnotherInstance(baseUrl)) {\n                throw new IllegalStateException(\"Another H2DbService instance is managing the same DB URL,\"\n                        + \" please change the DB URL or deactivate the other instance\");\n            }\n\n            final char[] passwordFromConfig = newConfiguration.getEncryptedPassword();\n            final char[] password = this.lastSessionPassword != null ? this.lastSessionPassword : passwordFromConfig;\n\n            if (this.connectionPool == null) {\n                openConnectionPool(newConfiguration, decryptPassword(password));\n                this.lastSessionPassword = password;\n            }\n            setParameters(newConfiguration);\n\n            if (!newConfiguration.isZipBased() && !Arrays.equals(password, passwordFromConfig)) {\n                final String decryptedPassword = decryptPassword(passwordFromConfig);\n                changePassword(newConfiguration.getUser(), decryptedPassword);\n                this.dataSource.setPassword(decryptedPassword);\n                this.lastSessionPassword = passwordFromConfig;\n            }\n\n            if (newConfiguration.isFileBased()) {\n                restartCheckpointTask(newConfiguration);\n                restartDefragTask(newConfiguration);\n            }\n\n            if (this.configuration == null\n                    || newConfiguration.getConnectionPoolMaxSize() != this.configuration.getConnectionPoolMaxSize()) {\n                this.executorService.setMaximumPoolSize(newConfiguration.getConnectionPoolMaxSize());\n            }\n\n            this.configuration = newConfiguration;\n            activeInstances.put(baseUrl, this);\n\n            logger.info(\"updating...done\");\n        } catch (Exception e) {\n            try {\n                shutdownDb();\n            } catch (SQLException sqlException) {\n                disposeConnectionPool();\n            }\n            stopCheckpointTask();\n            logger.error(\"Database initialization failed\", e);\n        } finally {\n            lock.unlock();\n            this.pendingUpdates.decrementAndGet();\n        }\n    }\n\n    private void shutdownIfUrlOrUserChanged(H2DbServiceOptions newConfiguration) throws SQLException {\n        if (this.configuration != null) {\n            final boolean urlChanged = !this.configuration.getDbUrl().equals(newConfiguration.getDbUrl());\n            final boolean userChanged = !this.configuration.getUser().equalsIgnoreCase(newConfiguration.getUser());\n            if (urlChanged || userChanged) {\n                shutdownDb();\n            }\n        }\n    }\n\n    private void awaitExecutorServiceTermination() {\n        try {\n            this.executorService.awaitTermination(1, TimeUnit.MINUTES);\n        } catch (InterruptedException e1) {\n            logger.warn(\"Interrupted while waiting for db shutdown\");\n            Thread.currentThread().interrupt();\n        }\n    }\n\n    private void setParameters(H2DbServiceOptions configuration) throws SQLException {\n        if (!configuration.isFileBasedLogLevelSpecified()) {\n            executeInternal(\"SET TRACE_LEVEL_FILE 0\");\n        }\n\n        // Set the maximum length for which a lob is created inline, regardless of the\n        // connection string.\n        if (configuration.isInMemory()) {\n            executeInternal(\"SET MAX_LENGTH_INPLACE_LOB \" + MAX_LENGTH_INPLACE_LOB_VALUE);\n        }\n\n        this.connectionPool.setMaxConnections(configuration.getConnectionPoolMaxSize());\n    }\n\n    private void syncWithExecutor() {\n        try {\n            this.executor.submit(() -> {\n            }).get();\n        } catch (final InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new IllegalStateException(e);\n        } catch (final Exception e1) {\n            throw new IllegalStateException(e1);\n        }\n    }\n\n    private Connection getConnectionInternal() throws SQLException {\n        if (this.connectionPool == null) {\n            throw new SQLException(\"Database instance not initialized\");\n        }\n\n        Connection conn = null;\n        try {\n            conn = this.connectionPool.getConnection();\n        } catch (SQLException e) {\n            logger.error(\"Error getting connection\", e);\n            this.listenerManager.dispatchDisconnected();\n            throw new SQLException(\"Error getting connection\");\n        }\n        return conn;\n    }\n\n    private void executeInternal(String sql) throws SQLException {\n        Connection conn = null;\n        Statement stmt = null;\n        try {\n            conn = getConnectionInternal();\n            stmt = conn.createStatement();\n            stmt.execute(sql);\n            conn.commit();\n        } catch (SQLException e) {\n            rollback(conn);\n            throw e;\n        } finally {\n            close(stmt);\n            close(conn);\n        }\n    }\n\n    private void shutdownDb() throws SQLException {\n        this.lastSessionPassword = null;\n        if (this.connectionPool == null) {\n            return;\n        }\n\n        stopDefragTask();\n        stopCheckpointTask();\n\n        Connection conn = null;\n        Statement stmt = null;\n        try {\n            conn = this.dataSource.getConnection();\n            stmt = conn.createStatement();\n            stmt.execute(\"SHUTDOWN\");\n        } finally {\n            close(stmt);\n            close(conn);\n        }\n\n        disposeConnectionPool();\n        this.listenerManager.dispatchDisconnected();\n        activeInstances.remove(this.configuration.getBaseUrl());\n    }\n\n    private void openConnectionPool(H2DbServiceOptions configuration, String password) {\n        logger.info(\"Opening database with url: {}\", configuration.getDbUrl());\n\n        this.dataSource = new JdbcDataSource();\n\n        this.dataSource.setURL(configuration.getDbUrl());\n        this.dataSource.setUser(configuration.getUser());\n        this.dataSource.setPassword(password);\n\n        this.connectionPool = JdbcConnectionPool.create(this.dataSource);\n\n        openDatabase(configuration, true);\n    }\n\n    private void openDatabase(H2DbServiceOptions configuration, boolean deleteDbOnError) {\n        Connection conn = null;\n        try {\n            conn = getConnectionInternal();\n            this.listenerManager.dispatchConnected();\n        } catch (SQLException e) {\n            logger.error(\"Failed to open database\", e);\n            if (deleteDbOnError && configuration.isFileBased()) {\n                logger.warn(\"Deleting database files...\");\n                deleteDbFiles(configuration);\n                logger.warn(\"Deleting database files...done\");\n                openDatabase(configuration, false);\n            } else {\n                disposeConnectionPool();\n                throw new ComponentException(e);\n            }\n        } finally {\n            close(conn);\n        }\n    }\n\n    private void deleteDbFiles(H2DbServiceOptions configuration) {\n        try {\n            final String directory = configuration.getDbDirectory();\n            final String dbName = configuration.getDatabaseName();\n            if (directory == null || dbName == null) {\n                logger.warn(\"Failed to determine database directory or name, not deleting db\");\n                return;\n            }\n            DeleteDbFiles.execute(directory, dbName, false);\n        } catch (Exception e) {\n            logger.warn(\"Failed to remove DB files\", e);\n        }\n    }\n\n    private void disposeConnectionPool() {\n        if (this.connectionPool != null) {\n            this.connectionPool.dispose();\n            this.connectionPool = null;\n        }\n    }\n\n    private String decryptPassword(char[] encryptedPassword) throws KuraException {\n        final char[] decodedPasswordChars = this.cryptoService.decryptAes(encryptedPassword);\n        return new String(decodedPasswordChars);\n    }\n\n    private void changePassword(String user, String newPassword) throws SQLException {\n        executeInternal(\"ALTER USER \" + user + \" SET PASSWORD '\" + newPassword + \"'\");\n    }\n\n    private boolean isManagedByAnotherInstance(String baseUrl) {\n        final H2DbServiceImpl owner = activeInstances.get(baseUrl);\n        return owner != null && owner != this;\n    }\n\n    private void restartCheckpointTask(final H2DbServiceOptions config) {\n        stopCheckpointTask();\n        final long delaySeconds = config.getCheckpointIntervalSeconds();\n        if (delaySeconds <= 0) {\n            return;\n        }\n        this.checkpointTask = this.executor.scheduleWithFixedDelay(new CheckpointTask(), delaySeconds, delaySeconds,\n                TimeUnit.SECONDS);\n    }\n\n    private void stopCheckpointTask() {\n        if (this.checkpointTask != null) {\n            this.checkpointTask.cancel(false);\n            this.checkpointTask = null;\n        }\n    }\n\n    private void restartDefragTask(final H2DbServiceOptions config) {\n        stopDefragTask();\n        final long delayMinutes = config.getDefragIntervalMinutes();\n        if (delayMinutes <= 0) {\n            return;\n        }\n        this.checkpointTask = this.executor.scheduleWithFixedDelay(new DefragTask(config), delayMinutes, delayMinutes,\n                TimeUnit.MINUTES);\n    }\n\n    private void stopDefragTask() {\n        if (this.defragTask != null) {\n            this.defragTask.cancel(false);\n            this.defragTask = null;\n        }\n    }\n\n    private class CheckpointTask implements Runnable {\n\n        @Override\n        public void run() {\n            try {\n                logger.info(\"performing checkpoint...\");\n                executeInternal(\"CHECKPOINT SYNC\");\n                logger.info(\"performing checkpoint...done\");\n            } catch (final SQLException e) {\n                logger.error(\"checkpoint failed\", e);\n            }\n        }\n    }\n\n    private class DefragTask implements Runnable {\n\n        private final H2DbServiceOptions configuration;\n\n        public DefragTask(final H2DbServiceOptions configuration) {\n            this.configuration = configuration;\n        }\n\n        private void shutdownDefrag() throws SQLException {\n            Connection conn = null;\n            Statement stmt = null;\n            try {\n                conn = H2DbServiceImpl.this.dataSource.getConnection();\n                stmt = conn.createStatement();\n                stmt.execute(\"SHUTDOWN DEFRAG\");\n            } finally {\n                close(stmt);\n                close(conn);\n            }\n        }\n\n        @Override\n        public void run() {\n            final Lock lock = H2DbServiceImpl.this.rwLock.writeLock();\n            lock.lock();\n            try {\n                logger.info(\"shutting down and defragmenting db...\");\n                shutdownDefrag();\n                disposeConnectionPool();\n                final String password = decryptPassword(this.configuration.getEncryptedPassword());\n                openConnectionPool(this.configuration, password);\n                logger.info(\"shutting down and defragmenting db...done\");\n            } catch (final Exception e) {\n                logger.error(\"failed to shutdown and defrag db\", e);\n            } finally {\n                lock.unlock();\n            }\n        }\n    }\n\n    @Override\n    public MessageStore openMessageStore(String name) throws KuraStoreException {\n\n        return new H2DbMessageStoreImpl(this::withConnectionAdapter, name);\n    }\n\n    @Override\n    public WireRecordStore openWireRecordStore(String name) throws KuraStoreException {\n\n        return new H2DbWireRecordStoreImpl(this::withConnectionAdapter, name);\n    }\n\n    @Override\n    public List<WireRecord> performQuery(String query) throws KuraStoreException {\n\n        return new H2DbQueryableWireRecordStoreImpl(this::withConnectionAdapter).performQuery(query);\n    }\n\n    @SuppressWarnings(\"restriction\")\n    private <T> T withConnectionAdapter(final SQLFunction<Connection, T> callable) throws SQLException {\n\n        return this.withConnection(callable::call);\n    }\n\n    @Override\n    public void addListener(ConnectionListener listener) {\n        this.listenerManager.add(listener);\n\n    }\n\n    @Override\n    public void removeListener(ConnectionListener listener) {\n        this.listenerManager.remove(listener);\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.h2db.provider;\n\nimport java.io.File;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nclass H2DbServiceOptions {\n\n    private static final Property<String> CONNECTOR_URL_PROP = new Property<>(\"db.connector.url\", \"jdbc:h2:mem:kuradb\");\n    private static final Property<String> USER_PROP = new Property<>(\"db.user\", \"SA\");\n    private static final Property<String> PASSWORD_PROP = new Property<>(\"db.password\", \"\");\n    private static final Property<Integer> CHECKPOINT_INTERVAL_SECONDS_PROP = new Property<>(\n            \"db.checkpoint.interval.seconds\", 900);\n    private static final Property<Integer> DEFRAG_INTERVAL_MINUTES_PROP = new Property<>(\"db.defrag.interval.minutes\",\n            20);\n    private static final Property<Integer> CONNECTION_POOL_MAX_SIZE = new Property<>(\"db.connection.pool.max.size\", 10);\n\n    private static final Pattern FILE_LOG_LEVEL_PATTERN = generatePatternForProperty(\"trace_level_file\");\n    private static final Pattern USER_PATTERN = generatePatternForProperty(\"user\");\n    private static final Pattern PASSWORD_PATTERN = generatePatternForProperty(\"password\");\n\n    private static final Pattern JDBC_URL_PARSE_PATTERN = Pattern.compile(\"jdbc:([^:]+):(([^:]+):)?([^;]*)(;.*)?\");\n\n    private final String dbUrl;\n    private final String user;\n    private final char[] password;\n    private final long checkpointIntervalSeconds;\n    private final long defragIntervalMinutes;\n    private final int maxConnectionPoolSize;\n\n    private boolean isInMemory;\n    private boolean isFileBased;\n    private boolean isZipBased;\n    private boolean isRemote;\n    private boolean isFileBasedLogLevelSpecified;\n\n    private String baseUrl;\n    private String dbDirectory;\n    private String dbName;\n\n    public H2DbServiceOptions(Map<String, Object> properties) {\n        this.password = PASSWORD_PROP.get(properties).toCharArray();\n        this.user = USER_PROP.get(properties);\n        this.checkpointIntervalSeconds = CHECKPOINT_INTERVAL_SECONDS_PROP.get(properties);\n        this.defragIntervalMinutes = DEFRAG_INTERVAL_MINUTES_PROP.get(properties);\n        this.maxConnectionPoolSize = CONNECTION_POOL_MAX_SIZE.get(properties);\n\n        String dbUrlProp = CONNECTOR_URL_PROP.get(properties);\n\n        dbUrlProp = USER_PATTERN.matcher(dbUrlProp).replaceAll(\"\");\n        dbUrlProp = PASSWORD_PATTERN.matcher(dbUrlProp).replaceAll(\"\");\n\n        this.dbUrl = dbUrlProp;\n        computeUrlParts();\n    }\n\n    private static Pattern generatePatternForProperty(String property) {\n        StringBuilder patternStringBuilder = new StringBuilder();\n        patternStringBuilder.append(';');\n        for (int i = 0; i < property.length(); i++) {\n            final char c = property.charAt(i);\n            patternStringBuilder.append('[').append(Character.toLowerCase(c)).append(Character.toUpperCase(c))\n                    .append(']');\n        }\n        patternStringBuilder.append(\"=[^;]*\");\n        return Pattern.compile(patternStringBuilder.toString());\n    }\n\n    private void computeUrlParts() {\n        final Matcher jdbcUrlMatcher = JDBC_URL_PARSE_PATTERN.matcher(this.dbUrl);\n\n        if (!jdbcUrlMatcher.matches()) {\n            throw new IllegalArgumentException(\"Invalid DB URL\");\n        }\n\n        String driver = jdbcUrlMatcher.group(1);\n        if (driver == null || !\"h2\".equals(driver)) {\n            throw new IllegalArgumentException(\"JDBC driver must be h2\");\n        }\n\n        String protocol = jdbcUrlMatcher.group(3);\n        String url = jdbcUrlMatcher.group(4);\n        if (protocol == null && \".\".equals(url)) {\n            // jdbc:h2:. is a shorthand for jdbc:h2:mem:\n            protocol = \"mem\";\n            url = \"\";\n        } else {\n            if (protocol == null) {\n                protocol = \"file\";\n            }\n            if (url == null) {\n                url = \"\";\n            }\n        }\n\n        parseProtocol(protocol);\n\n        this.baseUrl = \"jdbc:h2:\" + protocol + ':' + url;\n\n        if (this.isFileBased) {\n            File file = new File(url);\n            this.dbDirectory = file.getParent();\n            if (this.dbDirectory == null) {\n                this.dbDirectory = \".\";\n            }\n            this.dbName = file.getName();\n        }\n\n        this.isFileBasedLogLevelSpecified = FILE_LOG_LEVEL_PATTERN.matcher(this.dbUrl).find();\n    }\n\n    private void parseProtocol(String protocol) {\n        if (\"mem\".equals(protocol)) {\n            this.isInMemory = true;\n        } else if (\"file\".equals(protocol)) {\n            this.isFileBased = true;\n        } else if (\"zip\".equals(protocol)) {\n            this.isZipBased = true;\n        } else {\n            this.isRemote = true;\n        }\n    }\n\n    public String getDbUrl() {\n        return this.dbUrl;\n    }\n\n    public boolean isFileBased() {\n        return this.isFileBased;\n    }\n\n    public boolean isInMemory() {\n        return this.isInMemory;\n    }\n\n    public boolean isZipBased() {\n        return this.isZipBased;\n    }\n\n    public boolean isRemote() {\n        return this.isRemote;\n    }\n\n    public String getDbDirectory() {\n        return this.dbDirectory;\n    }\n\n    public String getDatabaseName() {\n        return this.dbName;\n    }\n\n    public long getCheckpointIntervalSeconds() {\n        return this.checkpointIntervalSeconds;\n    }\n\n    public long getDefragIntervalMinutes() {\n        return this.defragIntervalMinutes;\n    }\n\n    public String getBaseUrl() {\n        return this.baseUrl;\n    }\n\n    public String getUser() {\n        return this.user;\n    }\n\n    public char[] getEncryptedPassword() {\n        return this.password;\n    }\n\n    public int getConnectionPoolMaxSize() {\n        return this.maxConnectionPoolSize;\n    }\n\n    public boolean isFileBasedLogLevelSpecified() {\n        return this.isFileBasedLogLevelSpecified;\n    }\n\n    private static class Property<T> {\n\n        private final String key;\n        private final T defaultValue;\n\n        public Property(String key, T defaultValue) {\n            this.key = key;\n            this.defaultValue = defaultValue;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public T get(Map<String, Object> properties) {\n            final Object value = properties.get(this.key);\n            if (this.defaultValue.getClass().isInstance(value)) {\n                return (T) value;\n            }\n            return this.defaultValue;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbWireRecordStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.db.h2db.provider;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.type.BooleanValue;\nimport org.eclipse.kura.type.ByteArrayValue;\nimport org.eclipse.kura.type.DataType;\nimport org.eclipse.kura.type.DoubleValue;\nimport org.eclipse.kura.type.FloatValue;\nimport org.eclipse.kura.type.IntegerValue;\nimport org.eclipse.kura.type.LongValue;\nimport org.eclipse.kura.type.StringValue;\nimport org.eclipse.kura.type.TypedValue;\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.util.wire.store.AbstractJdbcWireRecordStoreImpl;\nimport org.eclipse.kura.util.wire.store.JdbcWireRecordStoreQueries;\n\n@SuppressWarnings(\"restriction\")\npublic class H2DbWireRecordStoreImpl extends AbstractJdbcWireRecordStoreImpl {\n\n    private static final Map<Class<? extends TypedValue<?>>, String> TYPE_MAPPING = buildTypeMapping();\n\n    public H2DbWireRecordStoreImpl(final ConnectionProvider provider, final String tableName)\n            throws KuraStoreException {\n        super(provider, tableName);\n\n        super.createTable();\n        super.createTimestampIndex();\n    }\n\n    @Override\n    protected JdbcWireRecordStoreQueries buildSqlWireRecordStoreQueries() {\n        return JdbcWireRecordStoreQueries.builder()\n                .withSqlAddColumn(\"ALTER TABLE \" + super.escapedTableName + \" ADD COLUMN {0} {1};\")\n                .withSqlCreateTable(\n                        \"CREATE TABLE IF NOT EXISTS \" + super.escapedTableName + \" (ID BIGINT GENERATED BY DEFAULT \"\n                                + \"AS IDENTITY(START WITH 1 INCREMENT BY 1) PRIMARY KEY, TIMESTAMP BIGINT);\")\n                .withSqlRowCount(\"SELECT COUNT(*) FROM \" + super.escapedTableName + \";\")\n                .withSqlDeleteRangeTable(\"DELETE FROM \" + super.escapedTableName + \" WHERE ID IN (SELECT ID FROM \"\n                        + super.escapedTableName + \" ORDER BY ID ASC LIMIT {0});\")\n                .withSqlDropColumn(\"ALTER TABLE \" + super.escapedTableName + \" DROP COLUMN {0};\")\n                .withSqlInsertRecord(\"INSERT INTO \" + super.escapedTableName + \" ({0}) VALUES ({1});\")\n                .withSqlTruncateTable(\"TRUNCATE TABLE \" + super.escapedTableName + \";\")\n                .withSqlCreateTimestampIndex(\n                        \"CREATE INDEX IF NOT EXISTS \" + super.escapeIdentifier(tableName + \"_TIMESTAMP\")\n                                + \" ON \" + super.escapedTableName + \" (TIMESTAMP DESC);\")\n                .build();\n    }\n\n    @Override\n    protected Optional<String> getMappedSqlType(final TypedValue<?> value) {\n        return Optional.ofNullable(value).flatMap(v -> Optional.ofNullable(TYPE_MAPPING.get(v.getClass())));\n    }\n\n    private static Map<Class<? extends TypedValue<?>>, String> buildTypeMapping() {\n        final Map<Class<? extends TypedValue<?>>, String> result = new HashMap<>();\n\n        result.put(StringValue.class, \"VARCHAR(102400)\");\n        result.put(IntegerValue.class, \"INTEGER\");\n        result.put(LongValue.class, \"BIGINT\");\n        result.put(BooleanValue.class, \"BOOLEAN\");\n        result.put(DoubleValue.class, \"DOUBLE\");\n        result.put(FloatValue.class, \"FLOAT\");\n        result.put(ByteArrayValue.class, \"BLOB\");\n\n        return Collections.unmodifiableMap(result);\n    }\n\n    @Override\n    protected boolean isCorrectColumnType(final TypedValue<?> value, String mappedType, String actualType) {\n\n        final boolean mappedTypeEquals = Objects.equals(mappedType, actualType);\n\n        if (mappedTypeEquals) {\n            return true;\n        }\n\n        final DataType dataType = value.getType();\n\n        if (dataType == DataType.DOUBLE || dataType == DataType.FLOAT) {\n            return \"DOUBLE PRECISION\".equals(actualType) || actualType.startsWith(\"FLOAT\");\n        } else if (dataType == DataType.STRING) {\n            return actualType.startsWith(\"CHARACTER VARYING\");\n        } else if (dataType == DataType.BYTE_ARRAY) {\n            return \"BINARY LARGE OBJECT\".equals(actualType);\n        } else {\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/.gitignore",
    "content": "lib/"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.db.sqlite.provider\nBundle-SymbolicName: org.eclipse.kura.db.sqlite.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nBundle-Activator: org.eclipse.kura.internal.db.sqlite.provider.SqliteProviderActivator\nImport-Package: com.zaxxer.hikari;version=\"2.7.9\",\n org.eclipse.kura;version=\"[1.7,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.connection.listener;version=\"1.0.0\",\n org.eclipse.kura.crypto;version=\"1.3.0\",\n org.eclipse.kura.data;version=\"[1.1,2.0)\",\n org.eclipse.kura.db;version=\"[2.0,2.1)\",\n org.eclipse.kura.message.store;version=\"[1.0,2.0)\",\n org.eclipse.kura.message.store.provider;version=\"[1.0,1.1)\",\n org.eclipse.kura.type;version=\"[1.1,2.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0,1.1)\",\n org.eclipse.kura.util.jdbc;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.message.store;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.store.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.wire.store;version=\"[1.0,1.1)\",\n org.eclipse.kura.wire;version=\"[2.0,3.0)\",\n org.eclipse.kura.wire.store.provider;version=\"[1.0,1.1)\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.component;version=\"1.4.0\",\n org.slf4j;version=\"1.7.32\",\n org.sqlite;version=\"3.39.3.0\",\n org.sqlite.core;version=\"3.39.3.0\",\n org.sqlite.date;version=\"3.39.3.0\",\n org.sqlite.javax;version=\"3.39.3.0\",\n org.sqlite.jdbc3;version=\"3.39.3.0\",\n org.sqlite.jdbc4;version=\"3.39.3.0\",\n org.sqlite.util;version=\"3.39.3.0\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/OSGI-INF/metatype/org.eclipse.kura.db.SQLiteDbService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.db.SQLiteDbService\" \n         name=\"SqliteDbService\" \n         description=\"SQLite based database service.\">\n\n        <AD id=\"db.mode\"\n            name=\"Database Mode\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"IN_MEMORY\"\n            description=\"Defines the database mode. If set to In Memory, the database data will be stored in RAM only, and it will be lost if the service instance is removed or if the framework is restarted. If set to Persisted, the database data will be stored on the file system, in the location defined by the Persisted Database Path parameter.\">\n            <Option label=\"In Memory\" value=\"IN_MEMORY\"/>\n            <Option label=\"Persisted\" value=\"PERSISTED\"/>\n         </AD>\n\n         <AD id=\"db.path\"\n            name=\"Persisted Database Path\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"/opt/mydb.sqlite\"\n            description=\"Defines the database path. The parameter value should be set to the absolute path to the database file (it should end with the database file name, it is not enough to specify only the parent directory). This parameter is only relevant for persisted databases.\">\n         </AD>\n         \n         <AD id=\"db.key\"\n            name=\"Encryption Key\"\n            type=\"Password\"\n            cardinality=\"0\" \n            required=\"false\"\n            description=\"Allows to specify a key/passphrase for encrypting the database file. This feature requires a SQLite binary with an encryption extension, and is only relevant for persisted databases. The key format can be specified using the Encryption Key Format parameter. If the value of this parameter is changed, the encryption key of the database will be updated accordingly. This parameter can be left empty to create an unencrypted database or to decrypt an encrypted one.\"/>\n            \n         <AD id=\"db.key.format\"\n            name=\"Encryption Key Format\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"ASCII\"\n            description=\"Allows to specify the format of the Encryption Key parameter value. The possible values are ASCII (an ASCII string), Hex SSE (the key is an hexadecimal string to be used with the SSE extension) or Hex SQLCipher (the key is an hexadecimal string to be used with the SQLCipher extension)\">\n            <Option label=\"ASCII\" value=\"ASCII\"/>\n            <Option label=\"Hex SSE\" value=\"HEX_SSE\"/>\n            <Option label=\"Hex SQLCipher\" value=\"HEX_SQLCIPHER\"/>\n         </AD>\n\n         <AD id=\"db.journal.mode\"\n            name=\"Journal Mode\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"WAL\"\n            description=\"The database journal mode (see https://www.sqlite.org/pragma.html#pragma_journal_mode for more details). If set to Rollback Journal the DELETE journal mode will be used. This parameter is only relevant for persisted databases.\">\n            <Option label=\"Rollback Journal\" value=\"ROLLBACK_JOURNAL\"/>\n            <Option label=\"WAL\" value=\"WAL\"/>\n         </AD>\n\n         <AD id=\"db.defrag.enabled\"\n            name=\"Defrag enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"Enables or disables the database defragmentation. Use the Defrag Interval parameter to specify the interval.\" />\n\n         <AD id=\"db.defrag.interval.seconds\"\n            name=\"Defrag Interval (seconds)\"\n            type=\"Long\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"900\"\n            min=\"60\"\n            description=\"SqliteDbService instances support running periodic defragmentation using the VACUUM command (https://www.sqlite.org/lang_vacuum.html). This parameter specifies the interval in seconds beetween two consecutive defragmentations. This parameter is only relevant for persisted databases.\"/>\n\n         <AD id=\"db.wal.checkpoint.enabled\"\n            name=\"Checkpoint enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"Enables or disables checkpoints in WAL journal mode. Use the WAL Checkpoint Interval parameter to specify the interval.\"/>\n\n         <AD id=\"db.wal.checkpoint.interval.seconds\"\n            name=\"WAL Checkpoint Interval (Seconds)\"\n            type=\"Long\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"600\"\n            min=\"60\"\n            description=\"SqliteDbService instances support running periodic periodic WAL checkpoints (https://www.sqlite.org/pragma.html#pragma_wal_checkpoint). Checkpoints will be performed in TRUNCATE mode. This parameter specifies the interval in seconds beetween two consecutive checkpoints. This parameter is only relevant for persisted databases in WAL Journal Mode.\"/>\n\n         <AD id=\"db.connection.pool.max.size\"\n            name=\"Connection Pool Max Size\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"10\"\n            min=\"1\"\n            description=\"The SqliteDbService manages connections using a connection pool. This parameter defines the maximum number of connections for the pool. Only 1 connection is available in In Memory mode.\"/>\n\n        <AD id=\"delete.db.files.on.failure\"\n            name=\"Delete Database Files On Failure\"\n            type=\"Boolean\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"true\"\n            description=\"If set to true, the database files will be deleted in case of failure in opening a persisted database. This is intended as a last resort measure for keeping the database service operational, especially in the case when it is used as a cloud connection message store.\"/>\n\n        <AD id=\"debug.shell.access.enabled\"\n            name=\"Debug Shell Access Enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"false\"\n            description=\"Enables or disables the interaction with this database instance using the sqlitedbg OSGi console command\"/>\n\n        </OCD>\n    <Designate factoryPid=\"org.eclipse.kura.db.SQLiteDbService\">\n        <Object ocdref=\"org.eclipse.kura.db.SQLiteDbService\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/OSGI-INF/org.eclipse.kura.db.SQLiteDbService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" enabled=\"true\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" modified=\"updated\" name=\"org.eclipse.kura.db.SQLiteDbService\">\n   <implementation class=\"org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.db.BaseDbService\"/>\n      <provide interface=\"org.eclipse.kura.message.store.provider.MessageStoreProvider\"/>\n      <provide interface=\"org.eclipse.kura.wire.store.provider.WireRecordStoreProvider\"/>\n      <provide interface=\"org.eclipse.kura.wire.store.provider.QueryableWireRecordStoreProvider\"/>\n   </service>\n   <reference bind=\"setDebugShell\" cardinality=\"1..1\" interface=\"org.eclipse.kura.internal.db.sqlite.provider.SqliteDebugShell\" name=\"SqliteDebugShell\" policy=\"static\"/>\n   <reference bind=\"setCryptoService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.crypto.CryptoService\" name=\"CryptoService\" policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/OSGI-INF/org.eclipse.kura.internal.db.sqlite.provider.SqliteDebugShell.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" enabled=\"true\" name=\"org.eclipse.kura.internal.db.sqlite.provider.SqliteDebugShell\">\n   <implementation class=\"org.eclipse.kura.internal.db.sqlite.provider.SqliteDebugShell\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.internal.db.sqlite.provider.SqliteDebugShell\"/>\n   </service>\n   <property name=\"osgi.command.scope\" type=\"String\" value=\"sqlitedbg\"/>\n   <property name=\"osgi.command.function\" type=\"String\">\n      executeQuery\n   </property>\n   <reference bind=\"setDbService\" cardinality=\"0..n\" interface=\"org.eclipse.kura.db.BaseDbService\" name=\"BaseDbService\" policy=\"dynamic\" unbind=\"unsetDbService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/build.properties",
    "content": "#\n#  Copyright (c) 2022 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput..  = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about_files/,\\\n               about.html\nsrc.includes = about.html,\\\n               about_files/\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.db.sqlite.provider</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/ConnectionPoolManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.BooleanSupplier;\nimport java.util.function.Consumer;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.sqlite.SQLiteDataSource;\n\nimport com.zaxxer.hikari.HikariConfig;\nimport com.zaxxer.hikari.HikariDataSource;\nimport com.zaxxer.hikari.HikariPoolMXBean;\n\npublic class ConnectionPoolManager {\n\n    private static final Logger logger = LoggerFactory.getLogger(ConnectionPoolManager.class);\n\n    private static final Long ACTIVE_CONNECTION_WAIT_TIMEOUT = 30000L;\n\n    private HikariDataSource hikariDatasource;\n    private SQLiteDataSource sqliteDataSource;\n\n    public ConnectionPoolManager(final SQLiteDataSource sqliteDataSource, final int maxConnectionCount) {\n\n        HikariConfig config = new HikariConfig();\n\n        config.setDataSource(sqliteDataSource);\n        config.setMaximumPoolSize(maxConnectionCount);\n        config.setConnectionTimeout(ACTIVE_CONNECTION_WAIT_TIMEOUT);\n        config.setAllowPoolSuspension(true);\n        config.setIdleTimeout(0);\n        config.setMaxLifetime(0);\n\n        this.sqliteDataSource = sqliteDataSource;\n        this.hikariDatasource = new HikariDataSource(config);\n    }\n\n    public Connection getConnection() throws SQLException {\n        logger.debug(\"getting connection\");\n\n        return this.hikariDatasource.getConnection();\n    }\n\n    void withExclusiveConnection(final Consumer<Connection> consumer) {\n\n        HikariPoolMXBean hikariPoolMXBean = this.hikariDatasource.getHikariPoolMXBean();\n\n        waitNoActiveConnections(hikariPoolMXBean, Optional.empty());\n\n        try {\n            try (final Connection conn = this.sqliteDataSource.getConnection()) {\n                consumer.accept(conn);\n            }\n\n        } catch (final Exception e) {\n            logger.warn(\"Exception while running task with exclusive connection\", e);\n        } finally {\n            hikariPoolMXBean.resumePool();\n        }\n    }\n\n    private void waitNoActiveConnections(HikariPoolMXBean hikariPoolMXBean, Optional<Long> timeoutMs) {\n        hikariPoolMXBean.suspendPool();\n\n        waitCondition(() -> hikariPoolMXBean.getActiveConnections() <= 0, timeoutMs);\n    }\n\n    public void shutdown(final Optional<Long> waitIdleTimeoutMs) {\n\n        HikariPoolMXBean hikariPoolMXBean = this.hikariDatasource.getHikariPoolMXBean();\n\n        if (waitIdleTimeoutMs.isPresent()) {\n            waitNoActiveConnections(hikariPoolMXBean, waitIdleTimeoutMs);\n        }\n\n        if (hikariPoolMXBean.getActiveConnections() > 0) {\n            logger.warn(\"Closing connection pool with {} active connections\", hikariPoolMXBean.getActiveConnections());\n        }\n\n        this.hikariDatasource.close();\n    }\n\n    private boolean waitCondition(final BooleanSupplier condition, final Optional<Long> timeoutMs) {\n\n        final long end = timeoutMs.map(t -> System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(t))\n                .orElse(Long.MAX_VALUE);\n\n        while (System.nanoTime() < end) {\n\n            if (condition.getAsBoolean()) {\n                return true;\n            }\n\n            try {\n                Thread.sleep(100);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/DatabaseLoader.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.EncryptionKeyFormat;\nimport org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.EncryptionKeySpec;\nimport org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.JournalMode;\nimport org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.Mode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.sqlite.SQLiteConfig;\nimport org.sqlite.SQLiteDataSource;\n\npublic class DatabaseLoader {\n\n    private static final Logger logger = LoggerFactory.getLogger(DatabaseLoader.class);\n\n    private final SqliteDbServiceOptions newOptions;\n    private final Optional<SqliteDbServiceOptions> oldOptions;\n    private final CryptoService cryptoService;\n\n    public DatabaseLoader(final SqliteDbServiceOptions newOptions, final Optional<SqliteDbServiceOptions> oldOptions,\n            final CryptoService cryptoService) {\n        this.newOptions = newOptions;\n        this.oldOptions = oldOptions;\n        this.cryptoService = cryptoService;\n    }\n\n    public SQLiteDataSource openDataSource() throws SQLException, KuraException {\n        try {\n            return openDataSourceInternal();\n        } catch (final Exception e) {\n\n            final boolean isConfigurationAttributeInvalidException = (e instanceof KuraException\n                    && ((KuraException) e).getCode() == KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID);\n\n            if (this.newOptions.isDeleteDbFilesOnFailure() && this.newOptions.getMode() != Mode.IN_MEMORY\n                    && !isConfigurationAttributeInvalidException) {\n                logger.warn(\"failed to open database, deleting database files and retrying\", e);\n                deleteDbFiles(newOptions.getPath());\n                return openDataSourceInternal();\n            }\n\n            throw e;\n        }\n\n    }\n\n    protected SQLiteDataSource openDataSourceInternal() throws SQLException, KuraException {\n\n        final String dbUrl = this.newOptions.getDbUrl();\n\n        if (newOptions.getMode() != Mode.PERSISTED) {\n            return openDataSource(dbUrl, Optional.empty(), Optional.empty());\n        }\n\n        final List<Optional<EncryptionKeySpec>> applicableEncryptionKeys = new ArrayList<>();\n\n        final Optional<EncryptionKeySpec> keyFromNewOptions = this.newOptions.getEncryptionKey(cryptoService);\n\n        addEncryptionKey(applicableEncryptionKeys, keyFromNewOptions, \"key from new options\");\n\n        if (this.oldOptions.isPresent()) {\n            try {\n                addEncryptionKey(applicableEncryptionKeys, this.oldOptions.get().getEncryptionKey(cryptoService),\n                        \"key from old options\");\n            } catch (final Exception e) {\n                logger.warn(\"failed to get key from old options\", e);\n            }\n        }\n\n        addEncryptionKey(applicableEncryptionKeys, getCryptoServiceEntry(newOptions.getPath()),\n                \"key from CryptoService\");\n\n        applicableEncryptionKeys.add(Optional.empty());\n\n        Exception lastException = null;\n        final Optional<JournalMode> journalMode = Optional.of(this.newOptions.getJournalMode());\n\n        for (final Optional<EncryptionKeySpec> encryptionKey : applicableEncryptionKeys) {\n            try {\n                SQLiteDataSource result = openDataSource(dbUrl, encryptionKey, journalMode);\n\n                if (!encryptionKey.equals(keyFromNewOptions)) {\n                    changeEncryptionKey(result, keyFromNewOptions, newOptions);\n                    result = openDataSource(dbUrl, keyFromNewOptions, journalMode);\n                }\n\n                updateCryptoServiceEntry(newOptions.getPath(), keyFromNewOptions);\n\n                return result;\n            } catch (final Exception e) {\n                logger.debug(\"database open attempt failed\", e);\n                lastException = e;\n                // try next one\n            }\n        }\n\n        throw new SQLException(\"Failed to open database\", lastException);\n    }\n\n    private void addEncryptionKey(final List<Optional<EncryptionKeySpec>> applicableEncryptionKeys,\n            final Optional<EncryptionKeySpec> keyFromNewOptions, final String type) {\n        if (keyFromNewOptions.isPresent()) {\n            logger.debug(\"adding {}\", type);\n            applicableEncryptionKeys.add(keyFromNewOptions);\n        }\n    }\n\n    private void updateCryptoServiceEntry(final String dbPath, final Optional<EncryptionKeySpec> keyFromOptions)\n            throws KuraException {\n        final String entryKey = getCryptoServicePasswordEntryKey(dbPath);\n        final char[] entryValue = encodeCrtpyoServicePasswordEntry(keyFromOptions).toCharArray();\n\n        final char[] currentValue = this.cryptoService.getKeyStorePassword(entryKey);\n\n        if (!Arrays.equals(entryValue, currentValue)) {\n            this.cryptoService.setKeyStorePassword(entryKey, entryValue);\n        }\n    }\n\n    private String getCryptoServicePasswordEntryKey(final String dbPath) {\n        return \"sqlite:db:\" + dbPath;\n    }\n\n    private String encodeCrtpyoServicePasswordEntry(final Optional<EncryptionKeySpec> encryptionKey) {\n        if (encryptionKey.isPresent()) {\n            return encryptionKey.get().getFormat().name() + \":\" + encryptionKey.get().getKey();\n        } else {\n            return \"\";\n        }\n    }\n\n    private Optional<EncryptionKeySpec> getCryptoServiceEntry(final String dbPath) {\n        try {\n            final String raw = new String(\n                    this.cryptoService.getKeyStorePassword(getCryptoServicePasswordEntryKey(dbPath)));\n\n            final int index = raw.indexOf(':');\n\n            final EncryptionKeyFormat format = EncryptionKeyFormat.valueOf(raw.substring(0, index));\n            final String key = raw.substring(index + 1);\n\n            return Optional.of(new EncryptionKeySpec(key, format));\n        } catch (final Exception e) {\n            return Optional.empty();\n        }\n    }\n\n    protected SQLiteDataSource openDataSource(final String url, final Optional<EncryptionKeySpec> encryptionKey,\n            final Optional<JournalMode> journalMode) throws SQLException {\n        final SQLiteConfig config = new SQLiteConfig();\n\n        if (encryptionKey.isPresent()) {\n            config.setPragma(SQLiteConfig.Pragma.PASSWORD, encryptionKey.get().getKey());\n            config.setHexKeyMode(encryptionKey.get().getFormat().toHexKeyMode());\n        }\n\n        if (journalMode.isPresent()) {\n            config.setJournalMode(journalMode.get() == JournalMode.ROLLBACK_JOURNAL ? SQLiteConfig.JournalMode.DELETE\n                    : SQLiteConfig.JournalMode.WAL);\n        }\n\n        final SQLiteDataSource dataSource = buildDataSource(config);\n        dataSource.setUrl(url);\n\n        dataSource.getConnection().close();\n        return dataSource;\n    }\n\n    protected void changeEncryptionKey(final SQLiteDataSource dataSource,\n            final Optional<EncryptionKeySpec> encryptionKey, final SqliteDbServiceOptions options) throws SQLException {\n        logger.info(\"Updating encryption key for {}\", dataSource.getUrl());\n\n        try (final Connection connection = dataSource.getConnection()) {\n\n            if (encryptionKey.isPresent()) {\n                final EncryptionKeySpec encryptionKeySpec = encryptionKey.get();\n\n                final String key = encryptionKey.get().getKey().replace(\"'\", \"''\");\n\n                if (encryptionKeySpec.getFormat() == EncryptionKeyFormat.HEX_SQLCIPHER) {\n                    executeQuery(connection, \"PRAGMA rekey = \\\"x'\" + key + \"'\\\";\");\n                } else if (encryptionKeySpec.getFormat() == EncryptionKeyFormat.HEX_SSE) {\n                    executeQuery(connection, \"PRAGMA hexrekey = '\" + key + \"';\");\n                } else {\n                    executeQuery(connection, \"PRAGMA rekey = '\" + key + \"';\");\n                }\n            } else {\n                executeQuery(connection, \"PRAGMA rekey = '';\");\n            }\n\n            SqliteUtil.vacuum(connection, options);\n        }\n\n    }\n\n    protected void deleteDbFiles(final String dbPath) {\n        final List<String> paths = Arrays.asList(dbPath, dbPath + \"-wal\", dbPath + \"-journal\", dbPath + \"-shm\");\n\n        for (final String path : paths) {\n            try {\n                deleteFile(new File(path));\n            } catch (final Exception e) {\n                logger.warn(\"failed to delete database file\", e);\n            }\n        }\n    }\n\n    protected void executeQuery(final Connection connection, final String query) throws SQLException {\n        try (final Statement stmt = connection.createStatement()) {\n            stmt.execute(query);\n        }\n    }\n\n    protected SQLiteDataSource buildDataSource(final SQLiteConfig config) {\n        return new SQLiteDataSource(config);\n    }\n\n    protected void deleteFile(final File file) throws IOException {\n        if (file.exists()) {\n            logger.info(\"deleting database file: {}\", file.getAbsolutePath());\n            Files.delete(file.toPath());\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteDbServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.connection.listener.ConnectionListener;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.db.BaseDbService;\nimport org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.Mode;\nimport org.eclipse.kura.message.store.provider.MessageStore;\nimport org.eclipse.kura.message.store.provider.MessageStoreProvider;\nimport org.eclipse.kura.util.jdbc.SQLFunction;\nimport org.eclipse.kura.util.store.listener.ConnectionListenerManager;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.eclipse.kura.wire.store.provider.QueryableWireRecordStoreProvider;\nimport org.eclipse.kura.wire.store.provider.WireRecordStore;\nimport org.eclipse.kura.wire.store.provider.WireRecordStoreProvider;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.sqlite.SQLiteDataSource;\nimport org.sqlite.SQLiteJDBCLoader;\n\npublic class SqliteDbServiceImpl implements BaseDbService, ConfigurableComponent, MessageStoreProvider,\n        WireRecordStoreProvider, QueryableWireRecordStoreProvider {\n\n    private static final Set<String> OPEN_URLS = new HashSet<>();\n\n    private static final Logger logger = LoggerFactory.getLogger(SqliteDbServiceImpl.class);\n\n    private CryptoService cryptoService;\n    private SqliteDebugShell debugShell;\n\n    private Optional<DbState> state = Optional.empty();\n    private ConnectionListenerManager listenerManager = new ConnectionListenerManager();\n\n    public void setDebugShell(final SqliteDebugShell debugShell) {\n        this.debugShell = debugShell;\n    }\n\n    public void setCryptoService(final CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void activate(final Map<String, Object> properties) {\n\n        logger.info(\"activating...\");\n        try {\n            logger.info(\"SQLite driver is in native mode: {}\", SQLiteJDBCLoader.isNativeMode());\n        } catch (Exception e) {\n            logger.info(\"Failed to determine if SQLite driver is in native mode\", e);\n        }\n\n        updated(properties);\n\n        logger.info(\"activating...done\");\n    }\n\n    public synchronized void updated(final Map<String, Object> properties) {\n        logger.info(\"updating...\");\n\n        final SqliteDbServiceOptions newOptions = new SqliteDbServiceOptions(properties);\n        this.debugShell.setPidAllowed(newOptions.getKuraServicePid(), newOptions.isDebugShellAccessEnabled());\n\n        final Optional<SqliteDbServiceOptions> oldOptions = this.state.map(DbState::getOptions);\n\n        if (!oldOptions.equals(Optional.of(newOptions))) {\n            shutdown();\n            try {\n                this.state = Optional.of(new DbState(newOptions, oldOptions, cryptoService));\n            } catch (final Exception e) {\n                logger.warn(\"Failed to initialize the database instance\", e);\n            }\n        }\n\n        logger.info(\"updating...done\");\n    }\n\n    public synchronized void deactivate() {\n        logger.info(\"deactivating...\");\n\n        shutdown();\n\n        logger.info(\"deactivating...done\");\n    }\n\n    private void shutdown() {\n        if (this.state.isPresent()) {\n            this.state.get().shutdown();\n            this.state = Optional.empty();\n            this.listenerManager.dispatchDisconnected();\n        }\n    }\n\n    @Override\n    public synchronized Connection getConnection() throws SQLException {\n\n        if (this.state.isPresent()) {\n            Connection connection;\n            try {\n                connection = this.state.get().getConnection();\n            } catch (SQLException e) {\n                this.listenerManager.dispatchDisconnected();\n                throw e;\n            }\n            return connection;\n        } else {\n            this.listenerManager.dispatchDisconnected();\n            throw new SQLException(\"Database is not initialized\");\n        }\n\n    }\n\n    private class DbState {\n\n        private final Optional<ScheduledExecutorService> executor;\n        private final ConnectionPoolManager connectionPool;\n        private final SqliteDbServiceOptions options;\n\n        public DbState(SqliteDbServiceOptions options, final Optional<SqliteDbServiceOptions> oldOptions,\n                final CryptoService cryptoService) throws SQLException, KuraException {\n            this.options = options;\n            tryClaimFile();\n\n            try {\n                logger.info(\"opening database with url: {}...\", options.getDbUrl());\n\n                final SQLiteDataSource dataSource = new DatabaseLoader(options, oldOptions, cryptoService)\n                        .openDataSource();\n\n                int maxConnectionCount = options.getMode() == Mode.PERSISTED ? options.getConnectionPoolMaxSize() : 1;\n\n                this.connectionPool = new ConnectionPoolManager(dataSource, maxConnectionCount);\n\n                if (options.isPeriodicDefragEnabled() || options.isPeriodicWalCheckpointEnabled()) {\n                    this.executor = Optional.of(Executors.newSingleThreadScheduledExecutor());\n                } else {\n                    this.executor = Optional.empty();\n                }\n\n                if (options.isPeriodicDefragEnabled()) {\n                    this.executor.get().scheduleWithFixedDelay(this::defrag, options.getDefragIntervalSeconds(),\n                            options.getDefragIntervalSeconds(), TimeUnit.SECONDS);\n                }\n\n                if (options.isPeriodicWalCheckpointEnabled()) {\n                    this.executor.get().scheduleWithFixedDelay(this::walCheckpoint,\n                            options.getWalCheckpointIntervalSeconds(), options.getWalCheckpointIntervalSeconds(),\n                            TimeUnit.SECONDS);\n                }\n\n                logger.info(\"opening database with url: {}...done\", options.getDbUrl());\n                SqliteDbServiceImpl.this.listenerManager.dispatchConnected();\n            } catch (final Exception e) {\n                releaseFile();\n                throw e;\n            }\n        }\n\n        public SqliteDbServiceOptions getOptions() {\n            return this.options;\n        }\n\n        public Connection getConnection() throws SQLException {\n            return this.connectionPool.getConnection();\n        }\n\n        private void walCheckpoint() {\n            try (final Connection connection = getConnection()) {\n                SqliteUtil.walCeckpoint(connection, options);\n            } catch (Exception e) {\n                logger.warn(\"failed to close connection\", e);\n            }\n        }\n\n        private void defrag() {\n            this.connectionPool.withExclusiveConnection(conn -> SqliteUtil.vacuum(conn, options));\n        }\n\n        private void tryClaimFile() {\n            if (options.getMode() != Mode.PERSISTED) {\n                return;\n            }\n\n            synchronized (OPEN_URLS) {\n                if (OPEN_URLS.contains(options.getPath())) {\n                    throw new IllegalStateException(\"Another database instance is managing the same database file\");\n                }\n                OPEN_URLS.add(options.getPath());\n            }\n        }\n\n        private void releaseFile() {\n            if (options.getMode() != Mode.PERSISTED) {\n                return;\n            }\n\n            synchronized (OPEN_URLS) {\n                OPEN_URLS.remove(options.getPath());\n            }\n        }\n\n        public void shutdown() {\n\n            try {\n                if (this.executor.isPresent()) {\n                    this.executor.get().shutdown();\n                    try {\n                        this.executor.get().awaitTermination(120, TimeUnit.SECONDS);\n                    } catch (final InterruptedException e) {\n                        logger.warn(\"Interrupted while waiting for executor shutdown\");\n                        Thread.currentThread().interrupt();\n                    }\n                }\n\n                logger.info(\"closing database with url: {}...\", options.getDbUrl());\n                this.connectionPool.shutdown(Optional.of(120 * 1000L));\n                logger.info(\"closing database with url: {}...done\", options.getDbUrl());\n            } finally {\n                releaseFile();\n            }\n        }\n    }\n\n    @Override\n    public void rollback(Connection conn) {\n        try {\n            if (conn != null) {\n                conn.rollback();\n            }\n        } catch (SQLException e) {\n            logger.error(\"Error during Connection rollback.\", e);\n        }\n    }\n\n    @Override\n    public void close(ResultSet... rss) {\n        if (rss == null) {\n            return;\n        }\n\n        for (ResultSet rs : rss) {\n            try {\n                if (rs != null) {\n                    rs.close();\n                }\n            } catch (SQLException e) {\n                logger.error(\"Error during ResultSet closing\", e);\n            }\n        }\n    }\n\n    @Override\n    public void close(Statement... stmts) {\n        if (stmts == null) {\n            return;\n        }\n\n        for (Statement stmt : stmts) {\n            try {\n                if (stmt != null) {\n                    stmt.close();\n                }\n            } catch (SQLException e) {\n                logger.error(\"Error during Statement closing\", e);\n            }\n        }\n    }\n\n    @Override\n    public void close(Connection conn) {\n        try {\n            if (conn != null) {\n                conn.close();\n            }\n        } catch (SQLException e) {\n            logger.error(\"Error during Connection closing\", e);\n        }\n    }\n\n    @Override\n    public MessageStore openMessageStore(String name) throws KuraStoreException {\n\n        return new SqliteMessageStoreImpl(this::withConnection, name);\n    }\n\n    @Override\n    public WireRecordStore openWireRecordStore(String name) throws KuraStoreException {\n\n        return new SqliteWireRecordStoreImpl(this::withConnection, name);\n    }\n\n    @Override\n    @SuppressWarnings(\"restriction\")\n    public List<WireRecord> performQuery(String query) throws KuraStoreException {\n\n        return new SqliteQueryableWireRecordStoreImpl(this::withConnection).performQuery(query);\n    }\n\n    @SuppressWarnings(\"restriction\")\n    private <T> T withConnection(final SQLFunction<Connection, T> callable) throws SQLException {\n\n        try (final Connection conn = this.getConnection()) {\n            return callable.call(conn);\n        }\n    }\n\n    @Override\n    public void addListener(ConnectionListener listener) {\n        this.listenerManager.add(listener);\n\n    }\n\n    @Override\n    public void removeListener(ConnectionListener listener) {\n        this.listenerManager.remove(listener);\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteDbServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.util.configuration.Property;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.sqlite.SQLiteConfig.HexKeyMode;\n\nclass SqliteDbServiceOptions {\n\n    private static final String ENCRYPTION_KEY = \"Encryption Key\";\n    private static final Logger logger = LoggerFactory.getLogger(SqliteDbServiceOptions.class);\n\n    private static final Pattern HEX_PATTERN = Pattern.compile(\"[0-9a-fA-F]+\");\n\n    public enum Mode {\n        IN_MEMORY,\n        PERSISTED\n    }\n\n    public enum JournalMode {\n        ROLLBACK_JOURNAL,\n        WAL\n    }\n\n    public enum EncryptionKeyFormat {\n\n        ASCII,\n        HEX_SSE,\n        HEX_SQLCIPHER;\n\n        public HexKeyMode toHexKeyMode() {\n            if (this == EncryptionKeyFormat.ASCII) {\n                return HexKeyMode.NONE;\n            } else if (this == EncryptionKeyFormat.HEX_SSE) {\n                return HexKeyMode.SSE;\n            } else if (this == EncryptionKeyFormat.HEX_SQLCIPHER) {\n                return HexKeyMode.SQLCIPHER;\n            } else {\n                throw new IllegalStateException();\n            }\n        }\n    }\n\n    public static class EncryptionKeySpec {\n\n        private final String key;\n        private final EncryptionKeyFormat format;\n\n        public EncryptionKeySpec(final String key, final EncryptionKeyFormat format) {\n            this.key = key;\n            this.format = format;\n        }\n\n        public String getKey() {\n            return this.key;\n        }\n\n        public EncryptionKeyFormat getFormat() {\n            return this.format;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(this.format, this.key);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (!(obj instanceof EncryptionKeySpec)) {\n                return false;\n            }\n            EncryptionKeySpec other = (EncryptionKeySpec) obj;\n            return this.format == other.format && Objects.equals(this.key, other.key);\n        }\n\n    }\n\n    private static final Property<String> MODE_PROPERTY = new Property<>(\"db.mode\", Mode.IN_MEMORY.name());\n    private static final Property<String> PATH_PROPERTY = new Property<>(\"db.path\", \"/opt/mydb.sqlite\");\n    private static final Property<Integer> CONNECTION_POOL_MAX_SIZE_PROPERTY = new Property<>(\n            \"db.connection.pool.max.size\", 10);\n    private static final Property<String> JOURNAL_MODE_PROPERTY = new Property<>(\"db.journal.mode\",\n            JournalMode.WAL.name());\n    private static final Property<Boolean> DEFRAG_ENABLED_PROPERTY = new Property<>(\"db.defrag.enabled\", true);\n    private static final Property<Long> DEFRAG_INTERVAL_SECONDS_PROPERTY = new Property<>(\"db.defrag.interval.seconds\",\n            900L);\n    private static final Property<Boolean> WAL_CHECHPOINT_ENABLED_PROPERTY = new Property<>(\"db.wal.checkpoint.enabled\",\n            true);\n\n    private static final Property<Long> WAL_CHECKPOINT_INTERVAL_SECONDS_PROPERTY = new Property<>(\n            \"db.wal.checkpoint.interval.seconds\", 600L);\n    private static final Property<Boolean> DEBUG_SHELL_ACCESS_ENABLED_PROPERTY = new Property<>(\n            \"debug.shell.access.enabled\", false);\n    private static final Property<String> ENCRYPTION_KEY_PROPERTY = new Property<>(\"db.key\", String.class);\n    private static final Property<String> ENCRYPTION_KEY_FORMAT_PROPERTY = new Property<>(\"db.key.format\",\n            EncryptionKeyFormat.ASCII.name());\n    private static final Property<Boolean> DELETE_DB_FILES_ON_FAILURE = new Property<>(\"delete.db.files.on.failure\",\n            true);\n    private static final Property<String> KURA_SERVICE_PID_PROPERTY = new Property<>(\n            ConfigurationService.KURA_SERVICE_PID, \"sqlitedb\");\n\n    private final Mode mode;\n    private final String path;\n    private final String kuraServicePid;\n    private final boolean isDebugShellAccessEnabled;\n    private final boolean defragEnabled;\n    private final long defragIntervalSeconds;\n    private final boolean walCheckpointEnabled;\n    private final long walCheckpointIntervalSeconds;\n    private final int maxConnectionPoolSize;\n    private final JournalMode journalMode;\n    private final Optional<String> encryptionKey;\n    private final EncryptionKeyFormat encryptionKeyFormat;\n    private final boolean deleteDbFilesOnFailure;\n\n    public SqliteDbServiceOptions(Map<String, Object> properties) {\n        this.mode = extractMode(properties);\n        this.path = sanitizePath(PATH_PROPERTY.get(properties));\n        this.kuraServicePid = KURA_SERVICE_PID_PROPERTY.get(properties);\n        this.maxConnectionPoolSize = CONNECTION_POOL_MAX_SIZE_PROPERTY.get(properties);\n        this.defragEnabled = DEFRAG_ENABLED_PROPERTY.get(properties);\n        this.defragIntervalSeconds = DEFRAG_INTERVAL_SECONDS_PROPERTY.get(properties);\n        this.walCheckpointEnabled = WAL_CHECHPOINT_ENABLED_PROPERTY.get(properties);\n        this.walCheckpointIntervalSeconds = WAL_CHECKPOINT_INTERVAL_SECONDS_PROPERTY.get(properties);\n        this.journalMode = extractJournalMode(properties);\n        this.isDebugShellAccessEnabled = DEBUG_SHELL_ACCESS_ENABLED_PROPERTY.get(properties);\n        this.encryptionKey = ENCRYPTION_KEY_PROPERTY.getOptional(properties).filter(s -> !s.trim().isEmpty());\n        this.encryptionKeyFormat = extractEncryptionKeyFormat(properties);\n        this.deleteDbFilesOnFailure = DELETE_DB_FILES_ON_FAILURE.get(properties);\n    }\n\n    public Mode getMode() {\n        return this.mode;\n    }\n\n    public String getPath() {\n        return this.path;\n    }\n\n    public int getConnectionPoolMaxSize() {\n        return this.maxConnectionPoolSize;\n    }\n\n    public boolean isDebugShellAccessEnabled() {\n        return this.isDebugShellAccessEnabled;\n    }\n\n    public long getDefragIntervalSeconds() {\n        return this.defragIntervalSeconds;\n    }\n\n    public JournalMode getJournalMode() {\n        return this.journalMode;\n    }\n\n    public String getKuraServicePid() {\n        return this.kuraServicePid;\n    }\n\n    public long getWalCheckpointIntervalSeconds() {\n        return this.walCheckpointIntervalSeconds;\n    }\n\n    public EncryptionKeyFormat getEncryptionKeyFormat() {\n        return this.encryptionKeyFormat;\n    }\n\n    public boolean isDeleteDbFilesOnFailure() {\n        return this.deleteDbFilesOnFailure;\n    }\n\n    public Optional<EncryptionKeySpec> getEncryptionKey(final CryptoService cryptoService) throws KuraException {\n        if (this.encryptionKey.isPresent()) {\n            String decrypted = new String(cryptoService.decryptAes(this.encryptionKey.get().toCharArray()));\n\n            final EncryptionKeyFormat format = getEncryptionKeyFormat();\n\n            decrypted = format == EncryptionKeyFormat.ASCII ? expectAscii(decrypted) : expectHexString(decrypted);\n\n            return Optional.of(new EncryptionKeySpec(decrypted, format));\n        } else {\n            return Optional.empty();\n        }\n    }\n\n    public boolean isPeriodicWalCheckpointEnabled() {\n        return this.mode != Mode.IN_MEMORY && this.journalMode == JournalMode.WAL && this.walCheckpointEnabled;\n    }\n\n    public boolean isPeriodicDefragEnabled() {\n        return this.mode != Mode.IN_MEMORY && this.defragEnabled;\n    }\n\n    private String expectAscii(final String value) throws KuraException {\n        if (StandardCharsets.US_ASCII.newEncoder().canEncode(value)) {\n            return value;\n        } else {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, ENCRYPTION_KEY, \"\",\n                    \"Encryption key contains non ASCII characters\");\n        }\n    }\n\n    private String expectHexString(final String string) throws KuraException {\n        if (string.length() % 2 != 0) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, ENCRYPTION_KEY, \"\",\n                    \"Hex encryption key length must be a multiple of 2\");\n        }\n\n        if (!HEX_PATTERN.matcher(string).matches()) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, ENCRYPTION_KEY, \"\",\n                    \"Hex encryption must contain only digits and or letters from \\\"a\\\" to \\\"f\\\"\");\n        }\n\n        return string.toUpperCase();\n    }\n\n    private static Mode extractMode(final Map<String, Object> properties) {\n        try {\n            return Mode.valueOf(MODE_PROPERTY.get(properties));\n        } catch (final Exception e) {\n            logger.warn(\"failed to parse db mode, falling back to IN_MEMORY\", e);\n            return Mode.IN_MEMORY;\n        }\n    }\n\n    private static JournalMode extractJournalMode(final Map<String, Object> properties) {\n        try {\n            return JournalMode.valueOf(JOURNAL_MODE_PROPERTY.get(properties));\n        } catch (final Exception e) {\n            logger.warn(\"failed to parse db journal mode, falling back to ROLLBACK_JOURNAL\", e);\n            return JournalMode.ROLLBACK_JOURNAL;\n        }\n    }\n\n    public String getDbUrl() {\n        if (this.mode == Mode.PERSISTED) {\n            return \"jdbc:sqlite:file:\" + this.path;\n        } else {\n            return \"jdbc:sqlite:file:\" + this.kuraServicePid + \"?mode=memory&cache=shared\";\n        }\n    }\n\n    private static EncryptionKeyFormat extractEncryptionKeyFormat(final Map<String, Object> properties) {\n        try {\n            return EncryptionKeyFormat.valueOf(ENCRYPTION_KEY_FORMAT_PROPERTY.get(properties));\n        } catch (final Exception e) {\n            return EncryptionKeyFormat.ASCII;\n        }\n    }\n\n    private static final String sanitizePath(final String path) {\n        final int index = path.indexOf('?');\n\n        if (index != -1) {\n            return path.substring(0, index);\n        } else {\n            return path;\n        }\n    }\n\n    public boolean isDefragEnabled() {\n        return this.defragEnabled;\n    }\n\n    public boolean isWalCheckpointEnabled() {\n        return this.walCheckpointEnabled;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.defragEnabled, this.defragIntervalSeconds, this.deleteDbFilesOnFailure,\n                this.encryptionKey, this.encryptionKeyFormat, this.isDebugShellAccessEnabled, this.journalMode,\n                this.kuraServicePid, this.maxConnectionPoolSize, this.mode, this.path, this.walCheckpointEnabled,\n                this.walCheckpointIntervalSeconds);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if ((obj == null) || (getClass() != obj.getClass())) {\n            return false;\n        }\n        SqliteDbServiceOptions other = (SqliteDbServiceOptions) obj;\n        return this.defragEnabled == other.defragEnabled && this.defragIntervalSeconds == other.defragIntervalSeconds\n                && this.deleteDbFilesOnFailure == other.deleteDbFilesOnFailure\n                && Objects.equals(this.encryptionKey, other.encryptionKey)\n                && this.encryptionKeyFormat == other.encryptionKeyFormat\n                && this.isDebugShellAccessEnabled == other.isDebugShellAccessEnabled\n                && this.journalMode == other.journalMode && Objects.equals(this.kuraServicePid, other.kuraServicePid)\n                && this.maxConnectionPoolSize == other.maxConnectionPoolSize && this.mode == other.mode\n                && Objects.equals(this.path, other.path) && this.walCheckpointEnabled == other.walCheckpointEnabled\n                && this.walCheckpointIntervalSeconds == other.walCheckpointIntervalSeconds;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteDebugShell.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.db.BaseDbService;\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class SqliteDebugShell {\n\n    private static final Property<String> KURA_SERVICE_PID = new Property<>(ConfigurationService.KURA_SERVICE_PID,\n            String.class);\n\n    private final Map<String, BaseDbService> dbServices = new HashMap<>();\n    private final Set<String> allowedPids = new HashSet<>();\n\n    public void setDbService(final BaseDbService dbService, final Map<String, Object> properties) {\n        final Optional<String> kuraServiePid = KURA_SERVICE_PID.getOptional(properties);\n\n        if (kuraServiePid.isPresent()) {\n            dbServices.put(kuraServiePid.get(), dbService);\n        }\n    }\n\n    public void unsetDbService(final BaseDbService dbService) {\n        this.dbServices.values().removeIf(s -> s == dbService);\n    }\n\n    synchronized void setPidAllowed(final String pid, final boolean allowed) {\n        if (!allowed) {\n            this.allowedPids.remove(pid);\n        } else {\n            this.allowedPids.add(pid);\n        }\n    }\n\n    public synchronized void executeQuery(final String dbServicePid, final String sql) throws SQLException {\n        if (!allowedPids.contains(dbServicePid) || !dbServices.containsKey(dbServicePid)) {\n            throw new IllegalArgumentException(\"Database instance with pid \" + dbServicePid + \" is not available\");\n        }\n\n        final BaseDbService dbService = this.dbServices.get(dbServicePid);\n\n        try (final Connection conn = dbService.getConnection(); final Statement statement = conn.createStatement()) {\n\n            final boolean hasResultSet = statement.execute(sql);\n\n            if (!hasResultSet) {\n                System.out.println(statement.getUpdateCount() + \" rows changed\");\n                return;\n            }\n\n            try (final ResultSet result = statement.getResultSet()) {\n\n                final ResultSetMetaData meta = result.getMetaData();\n\n                final StringBuilder builder = new StringBuilder();\n\n                for (int i = 1; i <= meta.getColumnCount(); i++) {\n                    builder.append(\"| \").append(meta.getColumnName(i)).append(\"\\t\");\n                }\n\n                builder.append(\"|\");\n                System.out.println(builder.toString());\n\n                while (result.next()) {\n                    builder.setLength(0);\n\n                    for (int i = 1; i <= meta.getColumnCount(); i++) {\n                        builder.append(\"| \").append(result.getObject(i)).append(\"\\t\");\n                    }\n\n                    builder.append(\"|\");\n                    System.out.println(builder.toString());\n                }\n\n            }\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteMessageStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.util.message.store.AbstractJdbcMessageStoreImpl;\nimport org.eclipse.kura.util.message.store.JdbcMessageStoreQueries;\n\n@SuppressWarnings(\"restriction\")\npublic class SqliteMessageStoreImpl extends AbstractJdbcMessageStoreImpl {\n\n    private static final String CREATE_INDEX_IF_NOT_EXISTS = \"CREATE INDEX IF NOT EXISTS \";\n\n    private static final String UPDATE = \"UPDATE \";\n\n    private static final String DELETE_FROM = \"DELETE FROM \";\n\n    private static final String SELECT_MESSAGE_METADATA_FROM = \"SELECT id, topic, qos, retain, createdOn, publishedOn, \"\n            + \"publishedMessageId, confirmedOn, priority, sessionId, droppedOn FROM \";\n\n    private final String sqlResetId;\n    private final String sqlDeleteMessage;\n\n    public SqliteMessageStoreImpl(final ConnectionProvider provider, final String table) throws KuraStoreException {\n        super(provider, table);\n\n        this.sqlResetId = UPDATE + \" sqlite_sequence SET seq = 0 WHERE name = \" + this.escapedTableName + \";\";\n        this.sqlDeleteMessage = DELETE_FROM + super.escapedTableName + \" WHERE id = ?;\";\n\n        createTable();\n        createIndexes();\n    }\n\n    @Override\n    protected JdbcMessageStoreQueries buildSqlMessageStoreQueries() {\n\n        return JdbcMessageStoreQueries.builder()\n                .withSqlCreateTable(\"CREATE TABLE IF NOT EXISTS \" + super.escapedTableName\n                        + \" (id INTEGER PRIMARY KEY AUTOINCREMENT, topic VARCHAR, qos INTEGER, retain BOOLEAN, \"\n                        + \"createdOn DATETIME, publishedOn DATETIME, publishedMessageId INTEGER, confirmedOn DATETIME, \"\n                        + \"payload BLOB, priority INTEGER, sessionId VARCHAR, droppedOn DATETIME);\")\n                .withSqlMessageCount(\"SELECT COUNT(*) FROM \" + super.escapedTableName + \";\")\n                .withSqlStore(\"INSERT INTO \" + escapedTableName\n                        + \" (topic, qos, retain, createdOn, publishedOn, publishedMessageId, confirmedOn, payload, priority, \"\n                        + \"sessionId, droppedOn) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);\")\n                .withSqlGetMessage(\n                        \"SELECT id, topic, qos, retain, createdOn, publishedOn, publishedMessageId, confirmedOn, \"\n                                + \"payload, priority, sessionId, droppedOn FROM \" + super.escapedTableName\n                                + \" WHERE id = ?\")\n                .withSqlGetNextMessage(\"SELECT a.id, a.topic, a.qos, a.retain, a.createdOn, a.publishedOn, \"\n                        + \"a.publishedMessageId, a.confirmedOn, a.payload, a.priority, a.sessionId, a.droppedOn FROM \"\n                        + escapedTableName + \" AS a JOIN (SELECT id, publishedOn FROM \" + super.escapedTableName\n                        + \" ORDER BY publishedOn ASC NULLS FIRST, priority ASC, createdOn ASC LIMIT 1) AS b \"\n                        + \"WHERE a.id = b.id AND b.publishedOn IS NULL;\")\n                .withSqlSetPublishedQoS1(UPDATE + super.escapedTableName\n                        + \" SET publishedOn = ?, publishedMessageId = ?, sessionId = ? WHERE id = ?;\")\n                .withSqlSetPublishedQoS0(UPDATE + super.escapedTableName + \" SET publishedOn = ? WHERE id = ?;\")\n                .withSqlSetConfirmed(UPDATE + escapedTableName + \" SET confirmedOn = ? WHERE id = ?;\")\n                .withSqlAllUnpublishedMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName\n                        + \" WHERE publishedOn IS NULL ORDER BY priority ASC, createdOn ASC;\")\n                .withSqlAllInFlightMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName\n                        + \" WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL AND droppedOn IS NULL \"\n                        + \"ORDER BY priority ASC, createdOn ASC\")\n                .withSqlAllDroppedInFlightMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName\n                        + \" WHERE droppedOn IS NOT NULL ORDER BY priority ASC, createdOn ASC;\")\n                .withSqlUnpublishAllInFlightMessages(UPDATE + super.escapedTableName\n                        + \" SET publishedOn = NULL WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL;\")\n                .withSqlDropAllInFlightMessages(UPDATE + super.escapedTableName\n                        + \" SET droppedOn = ? WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL;\")\n                .withSqlDeleteDroppedMessages(\n                        DELETE_FROM + super.escapedTableName + \" WHERE droppedOn <= ? AND droppedOn IS NOT NULL;\")\n                .withSqlDeleteConfirmedMessages(\n                        DELETE_FROM + super.escapedTableName + \" WHERE confirmedOn <= ? AND confirmedOn IS NOT NULL;\")\n                .withSqlDeletePublishedMessages(DELETE_FROM + super.escapedTableName\n                        + \" WHERE qos = 0 AND publishedOn <= ? AND publishedOn IS NOT NULL;\")\n                .withSqlCreateNextMessageIndex(\n                        CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + \"_nextMsg\") + \" ON \"\n                                + this.escapedTableName + \" (publishedOn ASC, priority ASC, createdOn ASC, qos);\")\n                .withSqlCreatePublishedOnIndex(\n                        CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + \"_PUBLISHEDON\") + \" ON \"\n                                + this.escapedTableName + \" (publishedOn DESC);\")\n                .withSqlCreateConfirmedOnIndex(\n                        CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + \"_CONFIRMEDON\") + \" ON \"\n                                + this.escapedTableName + \" (confirmedOn DESC);\")\n                .withSqlCreateDroppedOnIndex(\n                        CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + \"_DROPPEDON\") + \" ON \"\n                                + this.escapedTableName + \" (droppedOn DESC);\")\n                .build();\n    }\n\n    @Override\n    public synchronized int store(String topic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraStoreException {\n\n        validate(topic);\n\n        final long id = super.storeInternal(topic, payload, qos, retain, priority);\n\n        if (id > Integer.MAX_VALUE) {\n            super.execute(this.sqlDeleteMessage, id);\n\n            if (super.getMessageCountInternal() >= Integer.MAX_VALUE) {\n                throw new KuraStoreException(\"Table size is greater or equal than integer max value\");\n            }\n\n            super.execute(this.sqlResetId);\n            return (int) super.storeInternal(topic, payload, qos, retain, priority);\n        }\n\n        return (int) id;\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteProviderActivator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport java.io.File;\nimport java.util.Optional;\n\nimport org.osgi.framework.BundleActivator;\nimport org.osgi.framework.BundleContext;\n\npublic class SqliteProviderActivator implements BundleActivator {\n\n    private static final String SQLITE_TMPDIR_PROPERTY_KEY = \"org.sqlite.tmpdir\";\n\n    private boolean locationChanged = false;\n\n    @Override\n    public void start(final BundleContext context) throws Exception {\n        final Optional<String> sqliteTmpDir = Optional.ofNullable(System.getProperty(SQLITE_TMPDIR_PROPERTY_KEY));\n\n        if (!sqliteTmpDir.isPresent() || !new File(sqliteTmpDir.get()).isDirectory()) {\n\n            final Optional<File> bundleStorageAreaLocation = Optional.ofNullable(context.getDataFile(\"\"));\n\n            if (bundleStorageAreaLocation.isPresent()) {\n                System.setProperty(SQLITE_TMPDIR_PROPERTY_KEY, bundleStorageAreaLocation.get().getAbsolutePath());\n                locationChanged = true;\n            }\n        }\n    }\n\n    @Override\n    public void stop(final BundleContext context) throws Exception {\n        if (locationChanged) {\n            System.clearProperty(SQLITE_TMPDIR_PROPERTY_KEY);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteQueryableWireRecordStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.util.Optional;\n\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.util.wire.store.AbstractJdbcQueryableWireRecordStoreImpl;\n\n@SuppressWarnings(\"restriction\")\npublic class SqliteQueryableWireRecordStoreImpl extends AbstractJdbcQueryableWireRecordStoreImpl {\n\n    protected SqliteQueryableWireRecordStoreImpl(ConnectionProvider provider) {\n        super(provider);\n    }\n\n    @Override\n    protected Optional<Object> extractColumnValue(ResultSet resultSet, ResultSetMetaData metadata, int columnIndex)\n            throws SQLException {\n        Object dbExtractedData = resultSet.getObject(columnIndex);\n\n        if (dbExtractedData == null) {\n            return Optional.empty();\n        }\n\n        final String typeName = metadata.getColumnTypeName(columnIndex);\n\n        if (\"INT\".equals(typeName)) {\n            dbExtractedData = resultSet.getInt(columnIndex);\n        } else if (\"BIGINT\".equals(typeName) || \"INTEGER\".equals(typeName)) {\n            dbExtractedData = resultSet.getLong(columnIndex);\n        } else if (\"BOOLEAN\".equals(typeName)) {\n            dbExtractedData = resultSet.getBoolean(columnIndex);\n        } else if (\"BLOB\".equals(typeName)) {\n            dbExtractedData = resultSet.getBytes(columnIndex);\n        }\n\n        return Optional.of(dbExtractedData);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport java.sql.Connection;\nimport java.sql.Statement;\n\nimport org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.JournalMode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class SqliteUtil {\n\n    private static final String VACUUM_STATEMENT = \"VACUUM;\";\n    private static final String WAL_CHECKPOINT_STATEMENT = \"PRAGMA wal_checkpoint(TRUNCATE);\";\n\n    private static final Logger logger = LoggerFactory.getLogger(SqliteUtil.class);\n\n    private SqliteUtil() {\n    }\n\n    public static void walCeckpoint(final Connection connection, final SqliteDbServiceOptions options) {\n        logger.info(\"performing WAL checkpoint on database with url: {}...\", options.getDbUrl());\n\n        try (final Statement statement = connection.createStatement()) {\n            statement.executeUpdate(WAL_CHECKPOINT_STATEMENT);\n        } catch (final Exception e) {\n            logger.warn(\"WAL checkpoint failed\", e);\n        }\n\n        logger.info(\"performing WAL checkpoint on database with url: {}...done\", options.getDbUrl());\n    }\n\n    public static void vacuum(final Connection connection, final SqliteDbServiceOptions options) {\n        logger.info(\"defragmenting database with url: {}...\", options.getDbUrl());\n\n        try (final Statement statement = connection.createStatement()) {\n\n            statement.executeUpdate(VACUUM_STATEMENT);\n\n        } catch (final Exception e) {\n            logger.warn(\"VACUUM command failed\", e);\n        }\n\n        if (options.getJournalMode() == JournalMode.WAL) {\n            walCeckpoint(connection, options);\n        }\n\n        logger.info(\"defragmenting database with url: {}...done\", options.getDbUrl());\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteWireRecordStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.type.BooleanValue;\nimport org.eclipse.kura.type.ByteArrayValue;\nimport org.eclipse.kura.type.DoubleValue;\nimport org.eclipse.kura.type.FloatValue;\nimport org.eclipse.kura.type.IntegerValue;\nimport org.eclipse.kura.type.LongValue;\nimport org.eclipse.kura.type.StringValue;\nimport org.eclipse.kura.type.TypedValue;\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.util.wire.store.AbstractJdbcWireRecordStoreImpl;\nimport org.eclipse.kura.util.wire.store.JdbcWireRecordStoreQueries;\n\n@SuppressWarnings(\"restriction\")\npublic class SqliteWireRecordStoreImpl extends AbstractJdbcWireRecordStoreImpl {\n\n    private static final Map<Class<? extends TypedValue<?>>, String> TYPE_MAPPING = buildTypeMapping();\n\n    public SqliteWireRecordStoreImpl(final ConnectionProvider provider, final String tableName)\n            throws KuraStoreException {\n        super(provider, tableName);\n\n        super.createTable();\n        super.createTimestampIndex();\n    }\n\n    @Override\n    protected JdbcWireRecordStoreQueries buildSqlWireRecordStoreQueries() {\n        return JdbcWireRecordStoreQueries.builder()\n                .withSqlAddColumn(\"ALTER TABLE \" + super.escapedTableName + \" ADD COLUMN {0} {1};\")\n                .withSqlCreateTable(\"CREATE TABLE IF NOT EXISTS \" + super.escapedTableName\n                        + \" (ID INTEGER PRIMARY KEY AUTOINCREMENT, TIMESTAMP BIGINT);\")\n                .withSqlRowCount(\"SELECT COUNT(*) FROM \" + super.escapedTableName + \";\")\n                .withSqlDeleteRangeTable(\"DELETE FROM \" + super.escapedTableName + \" WHERE ID IN (SELECT ID FROM \"\n                        + super.escapedTableName + \" ORDER BY ID ASC LIMIT {0});\")\n                .withSqlDropColumn(\"ALTER TABLE \" + super.escapedTableName + \" DROP COLUMN {0};\")\n                .withSqlInsertRecord(\"INSERT INTO \" + super.escapedTableName + \" ({0}) VALUES ({1});\")\n                .withSqlTruncateTable(\"DELETE FROM \" + super.escapedTableName + \";\")\n                .withSqlCreateTimestampIndex(\n                        \"CREATE INDEX IF NOT EXISTS \" + super.escapeIdentifier(tableName + \"_TIMESTAMP\") + \" ON \"\n                                + super.escapedTableName + \" (TIMESTAMP DESC);\")\n                .build();\n    }\n\n    @Override\n    protected Optional<String> getMappedSqlType(final TypedValue<?> value) {\n        return Optional.ofNullable(value).flatMap(v -> Optional.ofNullable(TYPE_MAPPING.get(v.getClass())));\n    }\n\n    private static Map<Class<? extends TypedValue<?>>, String> buildTypeMapping() {\n        final Map<Class<? extends TypedValue<?>>, String> result = new HashMap<>();\n\n        result.put(StringValue.class, \"TEXT\");\n        result.put(IntegerValue.class, \"INT\");\n        result.put(LongValue.class, \"BIGINT\");\n        result.put(BooleanValue.class, \"BOOLEAN\");\n        result.put(DoubleValue.class, \"DOUBLE\");\n        result.put(FloatValue.class, \"FLOAT\");\n        result.put(ByteArrayValue.class, \"BLOB\");\n\n        return Collections.unmodifiableMap(result);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.docs/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.docs\nBundle-SymbolicName: org.eclipse.kura.docs\nBundle-Version: 1.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.docs/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.docs/build.properties",
    "content": "#\n# Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\nsource.. = src/\noutput.. = bin/\nbin.includes = META-INF/,\\\n               about.html\njars.extra.classpath = platform:/plugin/org.eclipse.kura.api\n               .\n"
  },
  {
    "path": "kura/org.eclipse.kura.docs/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2016, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.docs</artifactId>\n\t<version>1.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<tycho.extras.version>1.6.0</tycho.extras.version>\n\t</properties>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<!-- Append to jars.extra.classpath in build.properties\n\t\t\t\t\t file to add bundle to Javadocs creation -->\n\t\t\t\t<groupId>org.eclipse.tycho.extras</groupId>\n\t\t\t    <artifactId>tycho-document-bundle-plugin</artifactId>\n\t\t\t    <version>${tycho.extras.version}</version>\n\t\t\t    <executions>\n\t\t\t\t     <execution>\n\t\t\t\t     \t<id>eclipse-javadoc</id>\n\t\t\t\t      \t<phase>generate-resources</phase>\n\t\t\t\t      \t<goals>\n\t\t\t\t       \t\t<goal>javadoc</goal>\n\t\t\t\t      \t</goals>\n\t\t\t\t      \t<configuration>\n\t\t\t\t       \t\t<skipTocGen>true</skipTocGen>\n\t\t\t\t       \t\t<javadocOptions>\n\t\t\t\t       \t\t\t<additionalArguments>\n\t\t\t\t       \t\t\t\t<additionalArgument>-windowtitle \"Eclipse Kura ${project.parent.version}\"</additionalArgument>\n\t\t\t\t       \t\t\t\t<additionalArgument>-doctitle \"Eclipse Kura ${project.parent.version}\"</additionalArgument>\n\t\t\t\t       \t\t\t</additionalArguments>\n\t\t\t\t       \t\t</javadocOptions>\n\t\t\t\t      \t</configuration>\n\t\t\t     \t</execution>\n\t\t\t    </executions>\n\t\t\t</plugin>\n\t\t</plugins>\t\n\t</build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.driver.block\nBundle-SymbolicName: org.eclipse.kura.driver.block\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nImport-Package: org.eclipse.kura;version=\"[1.2, 2.0)\",\n org.eclipse.kura.channel;version=\"[1.0,2.0)\",\n org.eclipse.kura.channel.listener;version=\"[1.0, 2.0)\",\n org.eclipse.kura.driver;version=\"[1.0,2.0)\",\n org.eclipse.kura.type;version=\"[1.0,2.0)\",\n org.slf4j;version=\"[1.7, 2.0)\"\nExport-Package: org.eclipse.kura.driver.binary;version=\"1.1.0\",\n org.eclipse.kura.driver.binary.adapter;version=\"1.0.0\",\n org.eclipse.kura.driver.block;version=\"1.0.0\",\n org.eclipse.kura.driver.block.task;version=\"1.0.0\"\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/build.properties",
    "content": "source.. = \tsrc/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>org.eclipse.kura.driver.block</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.driver.block.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/AbstractBinaryData.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.binary;\n\nimport static java.util.Objects.requireNonNull;\n\npublic abstract class AbstractBinaryData<T> implements BinaryData<T> {\n\n    protected final Endianness endianness;\n    protected final int size;\n\n    /**\n     * Creates a new {@link BinaryData} instance.\n     *\n     * @param endianness\n     *            the endianness of the data\n     * @param size\n     *            the size of the data\n     */\n    public AbstractBinaryData(Endianness endianness, int size) {\n        requireNonNull(endianness, \"Endianness cannot be null\");\n        if (size <= 0) {\n            throw new IllegalArgumentException(\"Size must be positive\");\n        }\n        this.endianness = endianness;\n        this.size = size;\n    }\n\n    /**\n     * @return the endianness of the data\n     */\n    public Endianness getEndianness() {\n        return this.endianness;\n    }\n\n    /**\n     * @return the size of the data\n     */\n    public int getSize() {\n        return this.size;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/BinaryData.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\n/**\n * This class can be used to read/write a block of data in a {@link Buffer} to/from an instance of type T.\n *\n * @param <T>\n *            the type to be used for reading or writing.\n */\npublic interface BinaryData<T> {\n\n    /**\n     * @return the endianness of the data\n     */\n    public Endianness getEndianness();\n\n    /**\n     * @return the size of the data\n     */\n    public int getSize();\n\n    /**\n     * Writes the provided value into the provided {@link Buffer}\n     *\n     * @param buf\n     *            a {@link Buffer} instance to be written\n     * @param offset\n     *            the offset at which the data will be written\n     * @param value\n     *            the value to be written\n     */\n    public abstract void write(Buffer buf, int offset, T value);\n\n    /**\n     *\n     * @param buf\n     *            a {@link Buffer} from which the data needs to be read\n     * @param the\n     *            offset from which the data will be read\n     * @return the obtained value\n     */\n    public abstract T read(Buffer buf, int offset);\n\n    public abstract Class<T> getValueType();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/BinaryDataTypes.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\npublic final class BinaryDataTypes {\n\n    public static final BinaryData<Integer> UINT8 = new UInt8();\n    public static final BinaryData<Integer> INT8 = new Int8();\n\n    public static final BinaryData<Integer> UINT16_LE = new UInt16(Endianness.LITTLE_ENDIAN);\n    public static final BinaryData<Integer> UINT16_BE = new UInt16(Endianness.BIG_ENDIAN);\n\n    public static final BinaryData<Integer> INT16_LE = new Int16(Endianness.LITTLE_ENDIAN);\n    public static final BinaryData<Integer> INT16_BE = new Int16(Endianness.BIG_ENDIAN);\n\n    public static final BinaryData<Long> UINT32_LE = new UInt32(Endianness.LITTLE_ENDIAN);\n    public static final BinaryData<Long> UINT32_BE = new UInt32(Endianness.BIG_ENDIAN);\n\n    public static final BinaryData<Integer> INT32_LE = new Int32(Endianness.LITTLE_ENDIAN);\n    public static final BinaryData<Integer> INT32_BE = new Int32(Endianness.BIG_ENDIAN);\n\n    public static final BinaryData<Long> INT64_LE = new Int64(Endianness.LITTLE_ENDIAN);\n    public static final BinaryData<Long> INT64_BE = new Int64(Endianness.BIG_ENDIAN);\n\n    public static final BinaryData<java.lang.Float> FLOAT_LE = new Float(Endianness.LITTLE_ENDIAN);\n    public static final BinaryData<java.lang.Float> FLOAT_BE = new Float(Endianness.BIG_ENDIAN);\n\n    public static final BinaryData<java.lang.Double> DOUBLE_LE = new Double(Endianness.LITTLE_ENDIAN);\n    public static final BinaryData<java.lang.Double> DOUBLE_BE = new Double(Endianness.BIG_ENDIAN);\n\n    public static final List<String> NAMES = Collections.unmodifiableList(\n            Arrays.asList(\"UINT8\", \"INT8\", \"UINT16_LE\", \"UINT16_BE\", \"INT16_LE\", \"INT16_BE\", \"UINT32_LE\", \"UINT32_BE\",\n                    \"INT32_LE\", \"INT32_BE\", \"INT64_LE\", \"INT64_BE\", \"FLOAT_LE\", \"FLOAT_BE\", \"DOUBLE_LE\", \"DOUBLE_BE\"));\n\n    public static final List<BinaryData<?>> VALUES = Collections\n            .unmodifiableList(Arrays.asList(UINT8, INT8, UINT16_LE, UINT16_BE, INT16_LE, INT16_BE, UINT32_LE, UINT32_BE,\n                    INT32_LE, INT32_BE, INT64_LE, INT64_BE, FLOAT_LE, FLOAT_BE, DOUBLE_LE, DOUBLE_BE));\n\n    public static BinaryData<?> parse(String s) {\n        for (int i = 0; i < NAMES.size(); i++) {\n            if (NAMES.get(i).equals(s)) {\n                return VALUES.get(i);\n            }\n        }\n        throw new IllegalArgumentException();\n    }\n\n    private BinaryDataTypes() {\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Buffer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\npublic interface Buffer {\n\n    public void put(int offset, byte value);\n\n    public byte get(int offset);\n\n    public default void write(int offset, int length, byte[] data) {\n        for (int i = 0; i < length; i++) {\n            put(offset + i, data[i]);\n        }\n    }\n\n    public default void write(int offset, byte[] data) {\n        write(offset, data.length, data);\n    }\n\n    public default void read(int offset, int length, byte[] data) {\n        for (int i = 0; i < length; i++) {\n            data[i] = get(offset + i);\n        }\n    }\n\n    public default void read(int offset, byte[] data) {\n        read(offset, data.length, data);\n    }\n\n    public default byte[] toArray() {\n        byte[] result = new byte[getLength()];\n        read(0, result);\n        return result;\n    }\n\n    public int getLength();\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/ByteArray.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.binary;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ByteArray extends AbstractBinaryData<byte[]> {\n\n    private static final Logger logger = LoggerFactory.getLogger(ByteArray.class);\n\n    public ByteArray(int size) {\n        super(Endianness.LITTLE_ENDIAN, size);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, byte[] value) {\n\n        final int transferSize = getTransferSize(buf, offset);\n\n        buf.write(offset, transferSize, value);\n    }\n\n    @Override\n    public byte[] read(final Buffer buf, final int offset) {\n\n        final int transferSize = getTransferSize(buf, offset);\n        byte[] data = new byte[transferSize];\n\n        buf.read(offset, data);\n\n        return data;\n    }\n\n    private int getTransferSize(final Buffer buf, final int offset) {\n\n        final int size = getSize();\n        final int bufferAvailable = buf.getLength() - offset;\n\n        if (bufferAvailable < size) {\n            logger.debug(\"received buffer is too small\");\n        }\n\n        return Math.min(bufferAvailable, size);\n    }\n\n    @Override\n    public Class<byte[]> getValueType() {\n        return byte[].class;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/ByteArrayBuffer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\npublic class ByteArrayBuffer implements Buffer {\n\n    private final byte[] data;\n\n    public ByteArrayBuffer(byte[] data) {\n        this.data = data;\n    }\n\n    @Override\n    public void put(int offset, byte value) {\n        this.data[offset] = value;\n    }\n\n    @Override\n    public byte get(int offset) {\n        return this.data[offset];\n    }\n\n    @Override\n    public int getLength() {\n        return this.data.length;\n    }\n\n    @Override\n    public void write(int offset, int length, byte[] data) {\n        System.arraycopy(data, 0, this.data, offset, length);\n    }\n\n    @Override\n    public void read(int offset, int length, byte[] data) {\n        System.arraycopy(this.data, offset, data, 0, length);\n    }\n\n    public byte[] getBackingArray() {\n        return this.data;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Double.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nclass Double extends AbstractBinaryData<java.lang.Double> {\n\n    public Double(Endianness endianness) {\n        super(endianness, 8);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, java.lang.Double d) {\n        long tmp = java.lang.Double.doubleToRawLongBits(d);\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            buf.put(offset, (byte) (tmp >> 56 & 0xff));\n            buf.put(offset + 1, (byte) (tmp >> 48 & 0xff));\n            buf.put(offset + 2, (byte) (tmp >> 40 & 0xff));\n            buf.put(offset + 3, (byte) (tmp >> 32 & 0xff));\n            buf.put(offset + 4, (byte) (tmp >> 24 & 0xff));\n            buf.put(offset + 5, (byte) (tmp >> 16 & 0xff));\n            buf.put(offset + 6, (byte) (tmp >> 8 & 0xff));\n            buf.put(offset + 7, (byte) (tmp & 0xff));\n        } else {\n            buf.put(offset, (byte) (tmp & 0xff));\n            buf.put(offset + 1, (byte) (tmp >> 8 & 0xff));\n            buf.put(offset + 2, (byte) (tmp >> 16 & 0xff));\n            buf.put(offset + 3, (byte) (tmp >> 24 & 0xff));\n            buf.put(offset + 4, (byte) (tmp >> 32 & 0xff));\n            buf.put(offset + 5, (byte) (tmp >> 40 & 0xff));\n            buf.put(offset + 6, (byte) (tmp >> 48 & 0xff));\n            buf.put(offset + 7, (byte) (tmp >> 56 & 0xff));\n        }\n    }\n\n    @Override\n    public java.lang.Double read(Buffer buf, int offset) {\n        long tmp;\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            tmp = buf.get(offset + 7) & 0xffL;\n            tmp |= (buf.get(offset + 6) & 0xffL) << 8;\n            tmp |= (buf.get(offset + 5) & 0xffL) << 16;\n            tmp |= (buf.get(offset + 4) & 0xffL) << 24;\n            tmp |= (buf.get(offset + 3) & 0xffL) << 32;\n            tmp |= (buf.get(offset + 2) & 0xffL) << 40;\n            tmp |= (buf.get(offset + 1) & 0xffL) << 48;\n            tmp |= (buf.get(offset) & 0xffL) << 56;\n        } else {\n            tmp = buf.get(offset) & 0xffL;\n            tmp |= (buf.get(offset + 1) & 0xffL) << 8;\n            tmp |= (buf.get(offset + 2) & 0xffL) << 16;\n            tmp |= (buf.get(offset + 3) & 0xffL) << 24;\n            tmp |= (buf.get(offset + 4) & 0xffL) << 32;\n            tmp |= (buf.get(offset + 5) & 0xffL) << 40;\n            tmp |= (buf.get(offset + 6) & 0xffL) << 48;\n            tmp |= (buf.get(offset + 7) & 0xffL) << 56;\n        }\n        return java.lang.Double.longBitsToDouble(tmp);\n    }\n\n    @Override\n    public Class<java.lang.Double> getValueType() {\n        return java.lang.Double.class;\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Endianness.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\npublic enum Endianness {\n    BIG_ENDIAN,\n    LITTLE_ENDIAN\n}"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Float.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nclass Float extends AbstractBinaryData<java.lang.Float> {\n\n    public Float(Endianness endianness) {\n        super(endianness, 4);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, java.lang.Float f) {\n        int tmp = java.lang.Float.floatToRawIntBits(f);\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            buf.put(offset, (byte) (tmp >> 24 & 0xff));\n            buf.put(offset + 1, (byte) (tmp >> 16 & 0xff));\n            buf.put(offset + 2, (byte) (tmp >> 8 & 0xff));\n            buf.put(offset + 3, (byte) (tmp & 0xff));\n        } else {\n            buf.put(offset, (byte) (tmp & 0xff));\n            buf.put(offset + 1, (byte) (tmp >> 8 & 0xff));\n            buf.put(offset + 2, (byte) (tmp >> 16 & 0xff));\n            buf.put(offset + 3, (byte) (tmp >> 24 & 0xff));\n        }\n    }\n\n    @Override\n    public java.lang.Float read(Buffer buf, int offset) {\n        int tmp;\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            tmp = buf.get(offset + 3) & 0xff;\n            tmp |= (buf.get(offset + 2) & 0xff) << 8;\n            tmp |= (buf.get(offset + 1) & 0xff) << 16;\n            tmp |= (buf.get(offset) & 0xff) << 24;\n        } else {\n            tmp = buf.get(offset) & 0xff;\n            tmp |= (buf.get(offset + 1) & 0xff) << 8;\n            tmp |= (buf.get(offset + 2) & 0xff) << 16;\n            tmp |= (buf.get(offset + 3) & 0xff) << 24;\n        }\n        return java.lang.Float.intBitsToFloat(tmp);\n    }\n\n    @Override\n    public Class<java.lang.Float> getValueType() {\n        return java.lang.Float.class;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int16.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nclass Int16 extends AbstractBinaryData<Integer> {\n\n    public Int16(Endianness endianness) {\n        super(endianness, 2);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, Integer value) {\n        final short val = (short) (int) value;\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            buf.put(offset, (byte) (val >> 8 & 0xff));\n            buf.put(offset + 1, (byte) (val & 0xff));\n        } else {\n            buf.put(offset, (byte) (val & 0xff));\n            buf.put(offset + 1, (byte) (val >> 8 & 0xff));\n        }\n    }\n\n    @Override\n    public Integer read(Buffer buf, int offset) {\n        short result;\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            result = (short) (buf.get(offset + 1) & 0xff);\n            result |= (buf.get(offset) & 0xff) << 8;\n        } else {\n            result = (short) (buf.get(offset) & 0xff);\n            result |= (buf.get(offset + 1) & 0xff) << 8;\n        }\n        return (int) result;\n    }\n\n    @Override\n    public Class<Integer> getValueType() {\n        return Integer.class;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int32.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nclass Int32 extends AbstractBinaryData<Integer> {\n\n    public Int32(Endianness endianness) {\n        super(endianness, 4);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, Integer value) {\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            buf.put(offset, (byte) (value >> 24 & 0xff));\n            buf.put(offset + 1, (byte) (value >> 16 & 0xff));\n            buf.put(offset + 2, (byte) (value >> 8 & 0xff));\n            buf.put(offset + 3, (byte) (value & 0xff));\n        } else {\n            buf.put(offset, (byte) (value & 0xff));\n            buf.put(offset + 1, (byte) (value >> 8 & 0xff));\n            buf.put(offset + 2, (byte) (value >> 16 & 0xff));\n            buf.put(offset + 3, (byte) (value >> 24 & 0xff));\n        }\n    }\n\n    @Override\n    public Integer read(Buffer buf, int offset) {\n        int result;\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            result = buf.get(offset + 3) & 0xff;\n            result |= (buf.get(offset + 2) & 0xff) << 8;\n            result |= (buf.get(offset + 1) & 0xff) << 16;\n            result |= (buf.get(offset) & 0xff) << 24;\n        } else {\n            result = buf.get(offset) & 0xff;\n            result |= (buf.get(offset + 1) & 0xff) << 8;\n            result |= (buf.get(offset + 2) & 0xff) << 16;\n            result |= (buf.get(offset + 3) & 0xff) << 24;\n        }\n        return result;\n    }\n\n    @Override\n    public Class<Integer> getValueType() {\n        return Integer.class;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int64.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nclass Int64 extends AbstractBinaryData<Long> {\n\n    public Int64(Endianness endianness) {\n        super(endianness, 8);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, Long value) {\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            buf.put(offset, (byte) (value >> 56 & 0xff));\n            buf.put(offset + 1, (byte) (value >> 48 & 0xff));\n            buf.put(offset + 2, (byte) (value >> 40 & 0xff));\n            buf.put(offset + 3, (byte) (value >> 32 & 0xff));\n            buf.put(offset + 4, (byte) (value >> 24 & 0xff));\n            buf.put(offset + 5, (byte) (value >> 16 & 0xff));\n            buf.put(offset + 6, (byte) (value >> 8 & 0xff));\n            buf.put(offset + 7, (byte) (value & 0xff));\n        } else {\n            buf.put(offset, (byte) (value & 0xff));\n            buf.put(offset + 1, (byte) (value >> 8 & 0xff));\n            buf.put(offset + 2, (byte) (value >> 16 & 0xff));\n            buf.put(offset + 3, (byte) (value >> 24 & 0xff));\n            buf.put(offset + 4, (byte) (value >> 32 & 0xff));\n            buf.put(offset + 5, (byte) (value >> 40 & 0xff));\n            buf.put(offset + 6, (byte) (value >> 48 & 0xff));\n            buf.put(offset + 7, (byte) (value >> 56 & 0xff));\n        }\n    }\n\n    @Override\n    public Long read(Buffer buf, int offset) {\n        long result;\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            result = buf.get(offset + 7) & 0xffL;\n            result |= (buf.get(offset + 6) & 0xffL) << 8;\n            result |= (buf.get(offset + 5) & 0xffL) << 16;\n            result |= (buf.get(offset + 4) & 0xffL) << 24;\n            result |= (buf.get(offset + 3) & 0xffL) << 32;\n            result |= (buf.get(offset + 2) & 0xffL) << 40;\n            result |= (buf.get(offset + 1) & 0xffL) << 48;\n            result |= (buf.get(offset) & 0xffL) << 56;\n        } else {\n            result = buf.get(offset) & 0xffL;\n            result |= (buf.get(offset + 1) & 0xffL) << 8;\n            result |= (buf.get(offset + 2) & 0xffL) << 16;\n            result |= (buf.get(offset + 3) & 0xffL) << 24;\n            result |= (buf.get(offset + 4) & 0xffL) << 32;\n            result |= (buf.get(offset + 5) & 0xffL) << 40;\n            result |= (buf.get(offset + 6) & 0xffL) << 48;\n            result |= (buf.get(offset + 7) & 0xffL) << 56;\n        }\n        return result;\n    }\n\n    @Override\n    public Class<Long> getValueType() {\n        return Long.class;\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int8.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nclass Int8 extends AbstractBinaryData<Integer> {\n\n    public Int8() {\n        super(Endianness.BIG_ENDIAN, 1);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, Integer value) {\n        buf.put(offset, (byte) (int) value);\n    }\n\n    @Override\n    public Integer read(Buffer buf, int offset) {\n        return (int) buf.get(offset);\n    }\n\n    @Override\n    public Class<Integer> getValueType() {\n        return Integer.class;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/TypeUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.binary;\n\nimport java.math.BigInteger;\nimport java.util.Arrays;\nimport java.util.function.Function;\n\nimport org.eclipse.kura.type.BooleanValue;\nimport org.eclipse.kura.type.ByteArrayValue;\nimport org.eclipse.kura.type.DataType;\nimport org.eclipse.kura.type.DoubleValue;\nimport org.eclipse.kura.type.FloatValue;\nimport org.eclipse.kura.type.IntegerValue;\nimport org.eclipse.kura.type.LongValue;\nimport org.eclipse.kura.type.StringValue;\nimport org.eclipse.kura.type.TypedValue;\n\npublic final class TypeUtil {\n\n    private static final String TO_NATIVE_TYPE_MESSAGE = \" to native type \";\n    private static final String CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE = \"Cannot convert from Kura data type \";\n    private static final String TO_KURA_DATA_TYPE_MESSAGE = \" to Kura data type \";\n    private static final String CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE = \"Cannot convert from native type \";\n\n    private TypeUtil() {\n    }\n\n    public static <T> Function<T, TypedValue<?>> toTypedValue(final Class<T> sourceType, final DataType targetType) {\n        if (targetType == DataType.STRING) {\n            return toStringTypedValue(sourceType);\n        } else if (targetType == DataType.BOOLEAN) {\n            return toBooleanTypedValue(sourceType, targetType);\n        } else if (Number.class.isAssignableFrom(sourceType)) {\n            return toNumericalTypedValue(sourceType, targetType);\n        } else if (targetType == DataType.BYTE_ARRAY) {\n            return toByteArrayTypedValue(sourceType, targetType);\n        } else if (sourceType == String.class) {\n            return fromStringValue(targetType);\n        }\n\n        throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + sourceType.getSimpleName()\n                + TO_KURA_DATA_TYPE_MESSAGE + targetType.name());\n    }\n\n    private static <T> Function<T, TypedValue<?>> fromStringValue(final DataType targetType) {\n        if (targetType == DataType.INTEGER) {\n            return value -> new IntegerValue(Integer.parseInt((String) value));\n        } else if (targetType == DataType.LONG) {\n            return value -> new LongValue(Long.parseLong((String) value));\n        } else if (targetType == DataType.FLOAT) {\n            return value -> new FloatValue(java.lang.Float.parseFloat((String) value));\n        } else if (targetType == DataType.DOUBLE) {\n            return value -> new DoubleValue(java.lang.Double.parseDouble((String) value));\n        }\n\n        throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + String.class.getSimpleName()\n                + TO_KURA_DATA_TYPE_MESSAGE + targetType.name());\n    }\n\n    private static <T> Function<T, TypedValue<?>> toNumericalTypedValue(final Class<T> sourceType,\n            final DataType targetType) {\n        if (targetType == DataType.INTEGER) {\n            return value -> new IntegerValue(((Number) value).intValue());\n        } else if (targetType == DataType.LONG) {\n            return value -> new LongValue(((Number) value).longValue());\n        } else if (targetType == DataType.FLOAT) {\n            return value -> new FloatValue(((Number) value).floatValue());\n        } else if (targetType == DataType.DOUBLE) {\n            return value -> new DoubleValue(((Number) value).doubleValue());\n        }\n        throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + sourceType.getSimpleName()\n                + TO_KURA_DATA_TYPE_MESSAGE + targetType.name());\n    }\n\n    private static <T> Function<T, TypedValue<?>> toBooleanTypedValue(final Class<T> sourceType,\n            final DataType targetType) {\n        if (sourceType == Boolean.class) {\n            return value -> new BooleanValue((Boolean) value);\n        } else if (sourceType == String.class) {\n            return value -> new BooleanValue(Boolean.parseBoolean((String) value));\n        } else if (sourceType.isAssignableFrom(Number.class)) {\n            return value -> new BooleanValue(((Number) value).doubleValue() != 0);\n        }\n        throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + sourceType.getSimpleName()\n                + TO_KURA_DATA_TYPE_MESSAGE + targetType.name());\n    }\n\n    private static <T> Function<T, TypedValue<?>> toStringTypedValue(final Class<T> sourceType) {\n        if (sourceType == byte[].class) {\n            return value -> new StringValue(Arrays.toString((byte[]) value));\n        } else {\n            return value -> new StringValue(value.toString());\n        }\n    }\n\n    private static <T> Function<T, TypedValue<?>> toByteArrayTypedValue(final Class<T> sourceType,\n            final DataType targetType) {\n        if (sourceType == byte[].class) {\n            return value -> new ByteArrayValue((byte[]) value);\n        }\n        throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + sourceType.getSimpleName()\n                + TO_KURA_DATA_TYPE_MESSAGE + targetType.name());\n    }\n\n    public static <T> Function<TypedValue<?>, T> fromTypedValue(final Class<T> targetType, final DataType sourceType) {\n        if (targetType == String.class) {\n            return toStringValue(sourceType);\n        } else if (targetType == Boolean.class) {\n            return toBooleanValue(targetType, sourceType);\n        } else if (targetType == byte[].class) {\n            return toByteArrayValue(targetType, sourceType);\n        } else if (sourceType == DataType.STRING) {\n            return fromStringTypedValue(targetType);\n        } else {\n            return fromNumericTypedValue(targetType, sourceType);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static <T> Function<TypedValue<?>, T> fromNumericTypedValue(final Class<T> targetType,\n            final DataType sourceType) {\n        if (targetType == Integer.class) {\n            return value -> (T) (Integer) ((Number) value.getValue()).intValue();\n        } else if (targetType == Long.class) {\n            return value -> (T) (Long) ((Number) value.getValue()).longValue();\n        } else if (targetType == java.lang.Float.class) {\n            return value -> (T) (java.lang.Float) ((Number) value.getValue()).floatValue();\n        } else if (targetType == java.lang.Double.class) {\n            return value -> (T) (java.lang.Double) ((Number) value.getValue()).doubleValue();\n        } else if (targetType == BigInteger.class) {\n            return value -> (T) BigInteger.valueOf(((Number) value.getValue()).longValue());\n        }\n\n        throw new IllegalArgumentException(CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE + sourceType.name()\n                + TO_NATIVE_TYPE_MESSAGE + targetType.getSimpleName());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static <T> Function<TypedValue<?>, T> fromStringTypedValue(final Class<T> targetType) {\n        if (targetType == Integer.class) {\n            return value -> (T) (Integer) Integer.parseInt((String) value.getValue());\n        } else if (targetType == Long.class) {\n            return value -> (T) (Long) Long.parseLong((String) value.getValue());\n        } else if (targetType == java.lang.Float.class) {\n            return value -> (T) (java.lang.Float) java.lang.Float.parseFloat((String) value.getValue());\n        } else if (targetType == java.lang.Double.class) {\n            return value -> (T) (java.lang.Double) java.lang.Double.parseDouble((String) value.getValue());\n        }\n\n        throw new IllegalArgumentException(CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE + DataType.STRING.name()\n                + TO_NATIVE_TYPE_MESSAGE + targetType.getSimpleName());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static <T> Function<TypedValue<?>, T> toBooleanValue(final Class<T> targetType, final DataType sourceType) {\n        if (sourceType == DataType.BOOLEAN) {\n            return value -> (T) value.getValue();\n        } else if (sourceType == DataType.STRING) {\n            return value -> (T) (Boolean) Boolean.parseBoolean((String) value.getValue());\n        } else if (sourceType != DataType.BYTE_ARRAY) {\n            return value -> (T) (Boolean) (((Number) value.getValue()).doubleValue() != 0);\n        }\n        throw new IllegalArgumentException(CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE + sourceType.name()\n                + TO_NATIVE_TYPE_MESSAGE + targetType.getSimpleName());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static <T> Function<TypedValue<?>, T> toStringValue(final DataType sourceType) {\n        if (sourceType == DataType.BYTE_ARRAY) {\n            return value -> (T) Arrays.toString((byte[]) value.getValue());\n        } else {\n            return value -> (T) value.toString();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static <T> Function<TypedValue<?>, T> toByteArrayValue(final Class<T> targetType,\n            final DataType sourceType) {\n        if (sourceType == DataType.BYTE_ARRAY) {\n            return value -> (T) (byte[]) value.getValue();\n        }\n        throw new IllegalArgumentException(CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE + sourceType.name()\n                + TO_NATIVE_TYPE_MESSAGE + targetType.getSimpleName());\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt16.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nclass UInt16 extends AbstractBinaryData<Integer> {\n\n    public UInt16(Endianness endianness) {\n        super(endianness, 2);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, Integer value) {\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            buf.put(offset, (byte) (value >> 8 & 0xff));\n            buf.put(offset + 1, (byte) (value & 0xff));\n        } else {\n            buf.put(offset, (byte) (value & 0xff));\n            buf.put(offset + 1, (byte) (value >> 8 & 0xff));\n        }\n    }\n\n    @Override\n    public Integer read(Buffer buf, int offset) {\n        int result;\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            result = buf.get(offset + 1) & 0xff;\n            result |= (buf.get(offset) & 0xff) << 8;\n        } else {\n            result = buf.get(offset) & 0xff;\n            result |= (buf.get(offset + 1) & 0xff) << 8;\n        }\n        return result;\n    }\n\n    @Override\n    public Class<Integer> getValueType() {\n        return Integer.class;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt32.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nclass UInt32 extends AbstractBinaryData<Long> {\n\n    public UInt32(Endianness endianness) {\n        super(endianness, 4);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, Long value) {\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            buf.put(offset, (byte) (value >> 24 & 0xff));\n            buf.put(offset + 1, (byte) (value >> 16 & 0xff));\n            buf.put(offset + 2, (byte) (value >> 8 & 0xff));\n            buf.put(offset + 3, (byte) (value & 0xff));\n        } else {\n            buf.put(offset, (byte) (value & 0xff));\n            buf.put(offset + 1, (byte) (value >> 8 & 0xff));\n            buf.put(offset + 2, (byte) (value >> 16 & 0xff));\n            buf.put(offset + 3, (byte) (value >> 24 & 0xff));\n        }\n    }\n\n    @Override\n    public Long read(Buffer buf, int offset) {\n        long result;\n        if (this.endianness == Endianness.BIG_ENDIAN) {\n            result = (long) buf.get(offset + 3) & 0xff;\n            result |= (long) (buf.get(offset + 2) & 0xff) << 8;\n            result |= (long) (buf.get(offset + 1) & 0xff) << 16;\n            result |= (long) (buf.get(offset) & 0xff) << 24;\n        } else {\n            result = buf.get(offset) & 0xff;\n            result |= (long) (buf.get(offset + 1) & 0xff) << 8;\n            result |= (long) (buf.get(offset + 2) & 0xff) << 16;\n            result |= (long) (buf.get(offset + 3) & 0xff) << 24;\n        }\n        return result;\n    }\n\n    @Override\n    public Class<Long> getValueType() {\n        return Long.class;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt8.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.binary;\n\nclass UInt8 extends AbstractBinaryData<Integer> {\n\n    public UInt8() {\n        super(Endianness.BIG_ENDIAN, 1);\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, Integer value) {\n        buf.put(offset, (byte) (value & 0xff));\n    }\n\n    @Override\n    public Integer read(Buffer buf, int offset) {\n        return (int) (buf.get(offset) & 0xff);\n    }\n\n    @Override\n    public Class<Integer> getValueType() {\n        return Integer.class;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UnsignedIntegerLE.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.binary;\n\nimport java.math.BigInteger;\n\npublic class UnsignedIntegerLE extends AbstractBinaryData<BigInteger> {\n\n    private final int startBitOffset;\n    private final int sizeBits;\n\n    public UnsignedIntegerLE(final int sizeBits, final int startBitOffset) {\n        super(Endianness.LITTLE_ENDIAN, getSizeBytes(sizeBits));\n        this.startBitOffset = startBitOffset;\n        this.sizeBits = sizeBits;\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, BigInteger value) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public BigInteger read(final Buffer buf, final int offset) {\n        final int sizeBytes = getSize();\n\n        final byte[] raw = new byte[sizeBytes];\n\n        int srcBit = offset * 8 + startBitOffset;\n        final int srcEnd = srcBit + sizeBits;\n\n        int dstBit = 0;\n\n        while (srcBit < srcEnd) {\n            final int srcByte = srcBit / 8;\n            final int dstByte = dstBit / 8;\n\n            if ((buf.get(srcByte) & 0xff & (1 << (srcBit % 8))) != 0) {\n                raw[dstByte] |= (1 << (dstBit % 8));\n            }\n\n            srcBit++;\n            dstBit++;\n        }\n\n        for (int i = 0; i < sizeBytes / 2; i++) {\n            final byte tmp = raw[i];\n            raw[i] = raw[sizeBytes - i - 1];\n            raw[sizeBytes - i - 1] = tmp;\n        }\n\n        return new BigInteger(1, raw);\n    }\n\n    @Override\n    public Class<BigInteger> getValueType() {\n        return BigInteger.class;\n    }\n\n    private static int getSizeBytes(final int sizeBits) {\n        if (sizeBits <= 0) {\n            throw new IllegalArgumentException(\"bit size must be positive\");\n        }\n        return (int) Math.ceil((double) sizeBits / 8);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/GainOffset.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.binary.adapter;\n\nimport java.math.BigInteger;\nimport java.util.function.Function;\n\nimport org.eclipse.kura.driver.binary.BinaryData;\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.driver.binary.Endianness;\n\npublic class GainOffset implements BinaryData<Double> {\n\n    private final double gain;\n    private final double off;\n\n    private final Adapter<? extends Number> adapter;\n\n    public GainOffset(final BinaryData<? extends Number> wrapped, final double gain, final double offset) {\n        this.gain = gain;\n        this.off = offset;\n        this.adapter = new Adapter<>(wrapped);\n    }\n\n    @Override\n    public void write(final Buffer buf, final int offset, final Double value) {\n        final double d = value * gain + off;\n        adapter.write(buf, offset, d);\n    }\n\n    @Override\n    public Double read(Buffer buf, int offset) {\n        return adapter.read(buf, offset) * gain + off;\n    }\n\n    @Override\n    public Class<Double> getValueType() {\n        return Double.class;\n    }\n\n    @Override\n    public Endianness getEndianness() {\n        return adapter.getWrapped().getEndianness();\n    }\n\n    @Override\n    public int getSize() {\n        return adapter.getWrapped().getSize();\n    }\n\n    private static class Adapter<T extends Number> {\n\n        private final BinaryData<T> wrapped;\n        private final Function<java.lang.Double, T> fromDouble;\n\n        public Adapter(final BinaryData<T> wrapped) {\n            this.wrapped = wrapped;\n            this.fromDouble = fromDouble(wrapped.getValueType());\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        private static <T> Function<java.lang.Double, T> fromDouble(final Class<T> targetType) {\n            if (targetType == Byte.class) {\n                return value -> (T) (Byte) value.byteValue();\n            } else if (targetType == Short.class) {\n                return value -> (T) (Short) value.shortValue();\n            } else if (targetType == Integer.class) {\n                return value -> (T) (Integer) value.intValue();\n            } else if (targetType == Long.class) {\n                return value -> (T) (Long) value.longValue();\n            } else if (targetType == java.lang.Float.class) {\n                return value -> (T) (Float) value.floatValue();\n            } else if (targetType == java.lang.Double.class) {\n                return value -> (T) (Double) value.doubleValue();\n            } else if (targetType == BigInteger.class) {\n                return value -> (T) BigInteger.valueOf(value.longValue());\n            }\n\n            throw new IllegalArgumentException(\"cannot convert from double to \" + targetType.getSimpleName());\n        }\n\n        public void write(final Buffer buf, final int offset, final Double value) {\n            wrapped.write(buf, offset, fromDouble.apply(value));\n        }\n\n        public Double read(final Buffer buf, final int offset) {\n            return wrapped.read(buf, offset).doubleValue();\n        }\n\n        public BinaryData<T> getWrapped() {\n            return wrapped;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/StringData.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.binary.adapter;\n\nimport java.nio.charset.Charset;\n\nimport org.eclipse.kura.driver.binary.BinaryData;\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.driver.binary.Endianness;\n\npublic class StringData implements BinaryData<String> {\n\n    private final BinaryData<byte[]> wrapped;\n    private final Charset charset;\n\n    public StringData(final BinaryData<byte[]> wrapped, final Charset charset) {\n        this.wrapped = wrapped;\n        this.charset = charset;\n    }\n\n    @Override\n    public Endianness getEndianness() {\n        return wrapped.getEndianness();\n    }\n\n    @Override\n    public int getSize() {\n        return wrapped.getSize();\n    }\n\n    @Override\n    public void write(Buffer buf, int offset, String value) {\n        final byte[] raw = value.getBytes(charset);\n        wrapped.write(buf, offset, raw);\n    }\n\n    @Override\n    public String read(Buffer buf, int offset) {\n        final byte[] raw = wrapped.read(buf, offset);\n        return new String(raw, charset);\n    }\n\n    @Override\n    public Class<String> getValueType() {\n        return String.class;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/ToBoolean.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.binary.adapter;\n\nimport org.eclipse.kura.driver.binary.BinaryData;\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.driver.binary.Endianness;\n\npublic class ToBoolean implements BinaryData<Boolean> {\n\n    final BinaryData<?> wrapped;\n\n    public <T extends Number> ToBoolean(final BinaryData<T> wrapped) {\n        this.wrapped = wrapped;\n    }\n\n    @Override\n    public void write(final Buffer buf, final int offset, final Boolean value) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Boolean read(final Buffer buf, int offset) {\n        return ((Number) wrapped.read(buf, offset)).doubleValue() != 0;\n    }\n\n    @Override\n    public Class<Boolean> getValueType() {\n        return Boolean.class;\n    }\n\n    @Override\n    public Endianness getEndianness() {\n        return wrapped.getEndianness();\n    }\n\n    @Override\n    public int getSize() {\n        return wrapped.getSize();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/Block.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block;\n\n/**\n * A {@link Block} instance represents an interval on an abstract addressing space (e.g. a set of consecutive Modbus\n * registers or coils).\n */\npublic class Block {\n\n    private int start;\n    private int end;\n\n    /**\n     * Creates a new {@link Block} instance. If the provided start address is lesser than the provided end address, the\n     * two addresses will be swapped.\n     *\n     * @param start\n     *            the start address\n     * @param end\n     *            the end address\n     */\n    public Block(int start, int end) {\n        this.start = Math.min(start, end);\n        this.end = Math.max(start, end);\n    }\n\n    /**\n     * Sets the start address\n     *\n     * @param start\n     *            the start address\n     * @throws IllegalArgumentException\n     *             If the provided address is greater than the current end address\n     */\n    public void setStart(int start) {\n        if (start > getEnd()) {\n            throw new IllegalArgumentException(\"Start address must be less or equal than end address\");\n        }\n        this.start = start;\n    }\n\n    /**\n     * Sets the end address\n     *\n     * @param end\n     *            the end address\n     * @throws IllegalArgumentException\n     *             If the provided address is greater than the current start address\n     */\n    public void setEnd(int end) {\n        if (end < getStart()) {\n            throw new IllegalArgumentException(\"Start address must be less or equal than end address\");\n        }\n        this.end = end;\n    }\n\n    /**\n     * Returns the start address\n     *\n     * @return the start address\n     */\n    public int getStart() {\n        return this.start;\n    }\n\n    /**\n     * Returns the end address\n     *\n     * @return the end address\n     */\n    public int getEnd() {\n        return this.end;\n    }\n\n    /**\n     * Checks whether the provided address is contained by the interval represented by this {@link Block}.\n     * This method returns true if {@code getStart() <= address && getEnd() > address}\n     *\n     * @param address\n     *            the address to be checked\n     * @return {@code true} if the provided address is contained in this {@link Block}, {@code false} otherwise\n     */\n    public boolean contains(int address) {\n        return this.start <= address && this.end > address;\n    }\n\n    /**\n     * Checks whether the provided {@link Block} is contained by the interval represented by this {@link Block}.\n     * This method returns true if {@code this.getStart() <= other.getStart() && this.getEnd() >= other.getEnd()}\n     *\n     * @param address\n     *            the {@link Block} to be checked\n     * @return {@code true} if the provided address is contained in this {@link Block}, {@code false} otherwise\n     */\n    public boolean contains(Block other) {\n        return this.start <= other.start && this.end >= other.end;\n    }\n\n    @Override\n    public String toString() {\n        return \"[\" + this.start + \", \" + this.end + \"]\";\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/BlockAggregator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.NoSuchElementException;\nimport java.util.Spliterator;\nimport java.util.Spliterators;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\n/**\n * This class can be used to perform an aggregation process over a given list of blocks.\n *\n * The block set resulting from the aggregation always has the following properties:\n * <ul>\n * <li>It does not contain prohibited blocks (see {@link ProhibitedBlock})</li>\n * <li>It does not contain overlapping blocks</li>\n * <li>For each pair of blocks (b1, b2) belonging to the set, {@code b1.getStart() != b2.getEnd()}</li>\n * </ul>\n *\n * This class accepts a parameter, {@code minimumGapSize >= 0}:\n * <ul>\n * <li>If {@code minimumGapSize == 0 || minimumGapSize == 1} the resulting block set will represent the union of the\n * intervals represented by\n * the input block set.</li>\n * <li>If {@code minimumGapSize > 1} two non overlapping input blocks i1 and i2 such that\n * {@code i1.getEnd() < i2.getStart()} might be aggregated into a new block b2 such that\n * {@code b2.getStart() = i1.getStart()} and {@code b2.getEnd() = i2.getEnd()} if {@code i2.getStart() - i1.getEnd()}\n * is lesser than {@code minimumGapSize}</li>\n * </ul>\n *\n * <p>\n * The input block list must not contain conflicting blocks (two overlapping blocks such as one is prohibited and the\n * other is not). If this requirement is not satisfied the aggregation process will fail (see\n * {@link BlockAggregator#stream()}).\n * </p>\n *\n * <p>\n * The input block list can represent for example a list of addresses that need to be read/written from/to a remote\n * device using a specific protocol.\n * If the protocol allows to performs bulk read/writes (for example Modbus allows to read multiple consecutive\n * coils/register using a single request) this class can be used to aggregate a set of multiple \"small\" requests\n * spanning consecutive addresses into fewer and \"larger\" requests, reducing I/O time.\n * </p>\n *\n * <p>\n * The {@code minimumGapSize} parameter can be used to aggregate requests involving non consecutive intervals if they\n * are \"close enough\" according to the above criterion. In this case non explicitly requested data will be\n * transfered.\n * </p>\n *\n * @param <T>\n *            The type of the blocks obtained as result of the aggregation process.\n */\npublic class BlockAggregator<T extends Block> {\n\n    protected List<Block> blocks;\n    private final BlockFactory<T> factory;\n    private int minimumGapSize;\n\n    /**\n     * Creates a new {@link BlockAggregator} instance that operates on the given list of blocks.\n     * The provided list must be mutable as it will be sorted every time the {@link BlockAggregator#stream()} method is\n     * called.\n     *\n     * @param inputBlocks\n     *            a mutable list of input blocks.\n     * @param factory\n     *            a {@link BlockFactory} instance that will be used to create the output blocks during the aggregation\n     *            process.\n     */\n    public BlockAggregator(List<Block> inputBlocks, BlockFactory<T> factory) {\n        requireNonNull(inputBlocks, \"Input block list cannot be null\");\n        requireNonNull(factory, \"Block factory cannot be null\");\n        this.blocks = inputBlocks;\n        this.factory = factory;\n    }\n\n    /**\n     * <p>\n     * Sorts the input block list and the returns a {@link Stream} that yields the output blocks obtained from the\n     * aggregation process.\n     * </p>\n     * <p>\n     * The aggregation of the input blocks is performed lazily: the output blocks are produced on the fly when a\n     * terminal operation is applied to the resulting {@link Stream}.\n     * A terminal operation can be the iteration over an {@link Iterator} obtained from the {@link Stream}, or the\n     * invocation of the {@link Stream#collect(java.util.stream.Collector)} method.\n     * </p>\n     * <p>\n     * <b>Note</B>: If the input block list contains conflicting blocks an {@link IllegalArgumentException} will be\n     * thrown when the stream is consumed as soon as the conflict is detected.\n     * </p>\n     *\n     * @return the resulting {@link Stream}\n     */\n    @SuppressWarnings(\"unchecked\")\n    public Stream<T> stream() {\n        this.blocks.sort((Block o1, Block o2) -> o1.getStart() - o2.getStart());\n        return (Stream<T>) StreamSupport\n                .stream(Spliterators.spliteratorUnknownSize(new AggregatingIterator(this.blocks.listIterator()),\n                        Spliterator.ORDERED), false)\n                .filter(block -> !(block instanceof ProhibitedBlock));\n    }\n\n    /**\n     * Specifies the {@code minimumGapSize} parameter. The default for this parameter is 0.\n     *\n     * @param minimumGapSize\n     * @throws IllegalArgumentException\n     *             If the provided argument is negative\n     */\n    public void setMinimumGapSize(int minimumGapSize) {\n        if (minimumGapSize < 0) {\n            throw new IllegalArgumentException(\"Minimum gap size paramenter must be non negative\");\n        }\n        this.minimumGapSize = minimumGapSize;\n    }\n\n    /**\n     * Inserts a new {@link Block} into the input blocks list.\n     *\n     * @param block\n     *            the block to be inserted.\n     */\n    public void addBlock(Block block) {\n        requireNonNull(block, \"The provided block cannot be null\");\n        this.blocks.add(block);\n    }\n\n    private class AggregatingIterator implements Iterator<Block> {\n\n        private final ListIterator<Block> source;\n        private Block last;\n\n        public AggregatingIterator(ListIterator<Block> source) {\n            this.source = source;\n        }\n\n        private void extend(Block block, int end) {\n            block.setEnd(Math.max(block.getEnd(), end));\n        }\n\n        private void getNext() {\n            if (!this.source.hasNext()) {\n                return;\n            }\n            this.last = this.source.next();\n            if (!(this.last instanceof ProhibitedBlock)) {\n                this.last = BlockAggregator.this.factory.build(this.last.getStart(), this.last.getEnd());\n            }\n            while (this.source.hasNext()) {\n                final Block next = this.source.next();\n                final boolean isTypeDifferent = this.last instanceof ProhibitedBlock ^ next instanceof ProhibitedBlock;\n\n                if (this.last.getEnd() < next.getStart()) {\n                    if (BlockAggregator.this.minimumGapSize > 0\n                            && next.getStart() - this.last.getEnd() < BlockAggregator.this.minimumGapSize\n                            && !isTypeDifferent) {\n                        extend(this.last, next.getEnd());\n                        continue;\n                    } else {\n                        this.source.previous();\n                        break;\n                    }\n                }\n\n                if (this.last.getEnd() > next.getStart() && isTypeDifferent) {\n                    throw new IllegalArgumentException(\"Conflicting blocks: \" + this.last + \" \" + next);\n                }\n\n                if (isTypeDifferent) {\n                    this.source.previous();\n                    break;\n                }\n\n                extend(this.last, next.getEnd());\n            }\n        }\n\n        @Override\n        public boolean hasNext() {\n            if (this.last == null) {\n                getNext();\n            }\n            return this.last != null;\n        }\n\n        @Override\n        public Block next() {\n            if (this.last == null) {\n                getNext();\n            }\n            if (this.last == null) {\n                throw new NoSuchElementException();\n            }\n            Block result = this.last;\n            this.last = null;\n            return result;\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/BlockFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block;\n\n/**\n * This class is responsible of creating new blocks of type {@code T}.\n *\n * @param <T>\n *            The type of the returned block\n */\npublic interface BlockFactory<T extends Block> {\n\n    /**\n     * Creates a new block of type T, with the given start and end addresses.\n     *\n     * @param start\n     *            the start address of the new block\n     * @param end\n     *            the end address of the new block\n     * @return The new block\n     */\n    public T build(int start, int end);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/ProhibitedBlock.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block;\n\n/**\n * This class represents a prohibited interval over an abstract addressing space, that is an interval of addresses on\n * which it is not permitted to perform a specific operation (e.g. a non readable or non writable area).\n *\n * @see Block\n */\npublic class ProhibitedBlock extends Block {\n\n    public ProhibitedBlock(int start, int end) {\n        super(start, end);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/AbstractBlockDriver.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraRuntimeException;\nimport org.eclipse.kura.channel.ChannelFlag;\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.channel.ChannelStatus;\nimport org.eclipse.kura.channel.listener.ChannelListener;\nimport org.eclipse.kura.driver.Driver;\nimport org.eclipse.kura.driver.PreparedRead;\nimport org.eclipse.kura.driver.block.Block;\nimport org.eclipse.kura.driver.block.BlockFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * <p>\n * Provides an helper class that can be extended for implementing a {@link Driver} that supports the aggregation of\n * requests using a {@link BlockTaskAggregator}.\n * </p>\n * <p>\n * This class introduces the concept of domain. In general tasks that operate on different domains cannot be aggregated\n * together. Examples of such domains can be a (unit id, function code) pair in the Modbus protocol or a data block\n * (DB) in the case of the S7Comm protocol.\n * </p>\n * <p>\n * Implementors of this class must provide an implementation for the\n * {@link #getTaskFactoryForDomain(Object, Mode)} and {@link #toTasks(List, Mode)}\n * methods, see the description of the two methods for more details:\n * </p>\n * <ul>\n * <li>{@link #getTaskFactoryForDomain(Object, Mode)} must provide a {@link BlockFactory} that can be used for creating\n * {@link ToplevelBlockTask} instances responsible of implementing the data transfer operations for the specified\n * domain</li>\n * <li>{@link #toTasks(List, Mode)} must convert the configuration contained in the provided list of\n * {@link ChannelRecord} instances into a {@link Stream} of (domain, {@link BlockTask}) pairs.</li>\n * </ul>\n * <p>\n * This class provides a default implementation for the {@link #read(List)}, {@link #write(List)} and\n * {@link #prepareRead(List)} methods of the {@link Driver} interface.\n * </p>\n *\n * @param <T>\n *            the type of the domain, can be any type suitable for being used as an {@link java.util.HashMap} key\n */\npublic abstract class AbstractBlockDriver<T> implements Driver {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractBlockDriver.class);\n\n    /**\n     * This method must provide a {@link BlockFactory} that can be used for creating {@link ToplevelBlockTask} instances\n     * responsible of implementing the I/O operations for the specified domain.\n     *\n     * @param domain\n     *            the domain\n     * @param mode\n     *            the {@link Mode} for the returned {@link ToplevelBlockTask}\n     * @return the created {@link ToplevelBlockTask}\n     */\n    protected abstract BlockFactory<ToplevelBlockTask> getTaskFactoryForDomain(T domain, Mode mode);\n\n    /**\n     * <p>\n     * This method must return a {@link Stream} that yields (domain, {@link BlockTask}) pairs obtained by converting the\n     * {@link ChannelRecord} instances contained in the provided list.\n     * </p>\n     * <p>\n     * The {@link BlockTask} instances obtained from the stream will be aggregated and assigned to a\n     * {@link ToplevelBlockTask} parent. Tasks generated by the {@link Stream} returned by this method should not\n     * generally perform I/O operation but use the {@link Buffer} of their parent to implement their operations instead.\n     * </p>\n     * <p>\n     * If the specified mode is {@link Mode#READ}, only tasks having {@link Mode#READ} must be produces, if the\n     * specified mode is {@link Mode#WRITE}, the returned stream is allowed to produce tasks that are either in\n     * {@link Mode#WRITE} or {@link Mode#UPDATE} modes.\n     * </p>\n     *\n     *\n     * @param records\n     *            the list of {@link ChannelRecord} instances to be converted into {@link BlockTask} instances\n     * @param mode\n     *            the mode, can be either {@link Mode#READ} or {@link Mode#WRITE}\n     * @return a {@link Stream} yielding the converted tasks\n     */\n    protected abstract Stream<Pair<T, BlockTask>> toTasks(List<ChannelRecord> records, Mode mode);\n\n    /**\n     * Returns the minimum gap size parameter that will be used to aggregate tasks in {@link Mode#READ} for the\n     * specified domain. The default is 0. Tasks in {@link Mode#WRITE} mode will always be aggregated using 0 as the\n     * value of the {@code minimumGapSize} parameter.\n     *\n     * @param domain\n     *            the domain\n     * @return the minimum gap size for the provided domain\n     */\n    protected int getReadMinimumGapSizeForDomain(T domain) {\n        return 0;\n    }\n\n    /**\n     * This method is called immediately before an aggregation is performed for the specific domain and mode. This\n     * method can be overridden by implementors in order to customize the {@link BlockTaskAggregator} provided as\n     * argument, for example by adding prohibited blocks. The default implementation is no-op.\n     *\n     * @param domain\n     *            the domain\n     * @param mode\n     *            the {@link Mode} of the tasks to be aggregated, can be either {@link Mode#READ} or {@link Mode#WRITE}\n     * @param aggregator\n     *            the {@link BlockTaskAggregator} that will perform the aggregation\n     */\n    protected void beforeAggregation(T domain, Mode mode, BlockTaskAggregator aggregator) {\n    }\n\n    /**\n     * Perform the following operations:\n     * <ol>\n     * <li>The provided list of {@link ChannelRecods} instances are converted into {@link BlockTask} instances using the\n     * {@link #toTasks(List, Mode)} method.</li>\n     * <li>The resulting {@link BlockTask} instances are grouped by domain.</li>\n     * <li>An aggregation process is performed for each domain. If the {@link Mode#WRITE} is provided as parameter, and\n     * tasks in {@link Mode#UPDATE} mode are found in a domain, the aggregation will be performed using a\n     * {@link UpdateBlockTaskAggregator}. Otherwise a {@link BlockTaskAggregator} will be used.<br>\n     * The {@link BlockFactory} instances used for the aggregation will be obtained using the\n     * {@link #getTaskFactoryForDomain(Object, Mode)} method.</li>\n     * <li>The {@link ToplevelBlockTask} instances for all domains will be returned in the result list.</li>\n     * </ol>\n     *\n     * @param records\n     *            the {@link ChannelRecord} instances to be converted to {@link BlockTask} instances.\n     * @param mode\n     *            the mode\n     * @return the list of {@link BlockTask} instances resulting from the aggregation.\n     * @throws KuraException\n     *             if any exception is thrown during the process\n     */\n    protected List<BlockTask> optimize(List<ChannelRecord> records, Mode mode) throws KuraException {\n        try {\n            final ArrayList<BlockTask> resultTasks = new ArrayList<>();\n            final HashSet<T> domainsWithUpdateTasks = new HashSet<>();\n\n            final Function<Pair<T, BlockTask>, T> classifier;\n            if (mode == Mode.READ) {\n                classifier = pair -> pair.first;\n            } else {\n                classifier = pair -> {\n                    if (pair.second.getMode() == Mode.UPDATE) {\n                        domainsWithUpdateTasks.add(pair.first);\n                    }\n                    return pair.first;\n                };\n            }\n\n            final Map<T, ArrayList<Block>> groupedTasks = toTasks(records, mode).collect(Collectors.groupingBy(\n                    classifier, Collectors.mapping(pair -> pair.second, Collectors.toCollection(ArrayList::new))));\n\n            groupedTasks.entrySet().forEach(entry -> {\n                final T domain = entry.getKey();\n                final BlockTaskAggregator aggregator;\n                if (domainsWithUpdateTasks.contains(domain)) {\n                    aggregator = new UpdateBlockTaskAggregator(entry.getValue(),\n                            getTaskFactoryForDomain(domain, Mode.READ), getTaskFactoryForDomain(domain, Mode.WRITE));\n                    aggregator.setMinimumGapSize(getReadMinimumGapSizeForDomain(domain));\n                } else {\n                    aggregator = new BlockTaskAggregator(entry.getValue(), getTaskFactoryForDomain(domain, mode));\n                    if (mode == Mode.READ) {\n                        aggregator.setMinimumGapSize(getReadMinimumGapSizeForDomain(domain));\n                    }\n                }\n                beforeAggregation(domain, mode, aggregator);\n                aggregator.stream().forEach(resultTasks::add);\n            });\n\n            return resultTasks;\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, e);\n        }\n    }\n\n    /**\n     * Executes the provided {@link BlockTask}. Implementors can override this method, for example for catching any\n     * exception thrown by the task and implement error handling.\n     *\n     * @param task\n     *            the {@link BlockTask} to be run\n     */\n    protected void runTask(BlockTask task) {\n        try {\n            task.run();\n        } catch (Exception e) {\n            logger.warn(\"Task execution failed\", e);\n        }\n    }\n\n    @Override\n    public void registerChannelListener(final Map<String, Object> channelConfig, final ChannelListener listener)\n            throws ConnectionException {\n        throw new KuraRuntimeException(KuraErrorCode.OPERATION_NOT_SUPPORTED, \"register listener\");\n    }\n\n    @Override\n    public void unregisterChannelListener(final ChannelListener listener) throws ConnectionException {\n        throw new KuraRuntimeException(KuraErrorCode.OPERATION_NOT_SUPPORTED, \"unregister listener\");\n    }\n\n    @Override\n    public synchronized void read(final List<ChannelRecord> records) throws ConnectionException {\n        connect();\n        try {\n            optimize(records, Mode.READ).forEach(this::runTask);\n        } catch (Exception e) {\n            logger.warn(\"Unexpected exception during read\", e);\n            for (ChannelRecord record : records) {\n                record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e));\n                record.setTimestamp(System.currentTimeMillis());\n            }\n        }\n    }\n\n    @Override\n    public synchronized void write(final List<ChannelRecord> records) throws ConnectionException {\n        connect();\n        try {\n            optimize(records, Mode.WRITE).forEach(this::runTask);\n        } catch (Exception e) {\n            logger.warn(\"Unexpected exception during write\", e);\n            for (ChannelRecord record : records) {\n                record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e));\n                record.setTimestamp(System.currentTimeMillis());\n            }\n        }\n    }\n\n    protected PreparedRead createPreparedRead(List<ChannelRecord> records, List<BlockTask> tasks) {\n        return new BlockPreparedRead(records, tasks);\n    }\n\n    @Override\n    public synchronized PreparedRead prepareRead(List<ChannelRecord> records) {\n        try {\n            return createPreparedRead(records, optimize(records, Mode.READ));\n        } catch (KuraException e) {\n            for (ChannelRecord record : records) {\n                record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e));\n                record.setTimestamp(System.currentTimeMillis());\n            }\n            return createPreparedRead(records, Collections.emptyList());\n        }\n    }\n\n    public class BlockPreparedRead implements PreparedRead {\n\n        private final List<ChannelRecord> records;\n        private final List<BlockTask> tasks;\n\n        public BlockPreparedRead(List<ChannelRecord> records, List<BlockTask> tasks) {\n            this.records = records;\n            this.tasks = tasks;\n        }\n\n        @Override\n        public void close() throws Exception {\n        }\n\n        @Override\n        public List<ChannelRecord> execute() throws ConnectionException, KuraException {\n            synchronized (AbstractBlockDriver.this) {\n                connect();\n                for (BlockTask task : this.tasks) {\n                    runTask(task);\n                }\n                return this.records;\n            }\n        }\n\n        @Override\n        public List<ChannelRecord> getChannelRecords() {\n            return this.records;\n        }\n\n    }\n\n    public static final class Pair<U, V> {\n\n        private final U first;\n        private final V second;\n\n        public Pair(U first, V second) {\n            requireNonNull(first);\n            requireNonNull(second);\n            this.first = first;\n            this.second = second;\n        }\n\n        public U getFirst() {\n            return first;\n        }\n\n        public V getSecond() {\n            return second;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BinaryDataTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport java.io.IOException;\nimport java.util.function.Function;\n\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.driver.binary.BinaryData;\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.driver.binary.TypeUtil;\nimport org.eclipse.kura.type.DataType;\nimport org.eclipse.kura.type.TypedValue;\nimport org.eclipse.kura.type.TypedValues;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class BinaryDataTask<T> extends ChannelBlockTask {\n\n    private static final Logger logger = LoggerFactory.getLogger(BinaryDataTask.class);\n\n    private BinaryData<T> dataType;\n\n    private Function<T, TypedValue<?>> toTypedValue;\n    private Function<TypedValue<?>, T> fromTypedValue;\n\n    @SuppressWarnings(\"unchecked\")\n    public BinaryDataTask(ChannelRecord record, int offset, BinaryData<T> dataType, Mode mode) {\n        this(record, offset, dataType, TypedValues::newTypedValue, typedValue -> (T) typedValue.getValue(), mode);\n    }\n\n    public BinaryDataTask(ChannelRecord record, int offset, BinaryData<T> binaryDataType, DataType dataType,\n            Mode mode) {\n        this(record, offset, binaryDataType, TypeUtil.toTypedValue(binaryDataType.getValueType(), dataType),\n                TypeUtil.fromTypedValue(binaryDataType.getValueType(), dataType), mode);\n    }\n\n    public BinaryDataTask(ChannelRecord record, int offset, BinaryData<T> dataType,\n            Function<T, TypedValue<?>> toTypedValue, Function<TypedValue<?>, T> fromTypedValue, Mode mode) {\n        super(record, offset, offset + dataType.getSize(), mode);\n        this.dataType = dataType;\n        this.toTypedValue = toTypedValue;\n        this.fromTypedValue = fromTypedValue;\n    }\n\n    @Override\n    public void run() throws IOException {\n        final ToplevelBlockTask parent = getParent();\n        Buffer buffer = parent.getBuffer();\n\n        if (getMode() == Mode.READ) {\n            logger.debug(\"Read {}: offset: {}\", this.dataType.getClass().getSimpleName(), getStart());\n\n            final T result = this.dataType.read(buffer, getStart() - parent.getStart());\n\n            this.record.setValue(this.toTypedValue.apply(result));\n            onSuccess();\n        } else {\n            logger.debug(\"Write {}: offset: {}\", this.dataType.getClass().getSimpleName(), getStart());\n\n            T value = this.fromTypedValue.apply(this.record.getValue());\n\n            this.dataType.write(buffer, getStart() - parent.getStart(), value);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BitTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.type.BooleanValue;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class BitTask extends UpdateBlockTask {\n\n    private static final Logger logger = LoggerFactory.getLogger(BitTask.class);\n    private int bit;\n\n    public BitTask(ChannelRecord record, int start, int bit, Mode mode) {\n        super(record, start, start + 1, mode);\n        this.bit = bit;\n    }\n\n    public void setBit(int bit) {\n        this.bit = bit;\n    }\n\n    @Override\n    protected void runRead() {\n        final ToplevelBlockTask parent = getParent();\n        Buffer buffer = parent.getBuffer();\n\n        byte b = buffer.get(getStart() - parent.getStart());\n\n        final boolean result = (b >> this.bit & 0x01) == 1;\n\n        logger.debug(\"Reading Bit: offset {} bit index {} result {}\", getStart(), this.bit, result);\n\n        this.record.setValue(new BooleanValue(result));\n        onSuccess();\n    }\n\n    @Override\n    protected void runWrite() {\n        logger.warn(\"Write mode not supported\");\n        onFailure(new UnsupportedOperationException(\n                \"BitTask does not support WRITE mode, only READ and UPDATE modes are supported\"));\n    }\n\n    @Override\n    protected void runUpdate(ToplevelBlockTask write, ToplevelBlockTask read) {\n        Buffer outBuffer = write.getBuffer();\n        Buffer inBuffer = read.getBuffer();\n\n        final int previousValueOffset = getStart() - read.getStart();\n        final boolean value = (Boolean) this.record.getValue().getValue();\n\n        byte byteValue = inBuffer.get(previousValueOffset);\n\n        if (value) {\n            byteValue |= 1 << this.bit;\n        } else {\n            byteValue &= ~(1 << this.bit);\n        }\n\n        inBuffer.put(previousValueOffset, byteValue);\n        logger.debug(\"Write Bit: offset: {} value: {}\", getStart(), value);\n        outBuffer.put(getStart() - write.getStart(), byteValue);\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BlockTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.io.IOException;\n\nimport org.eclipse.kura.driver.block.Block;\n\n/**\n * This class represents an generic operation that involves a specific interval of addresses on a given address space.\n *\n * @see BlockTaskAggregator\n * @see ToplevelBlockTask\n */\npublic abstract class BlockTask extends Block {\n\n    private final Mode mode;\n    private ToplevelBlockTask parent;\n\n    /**\n     * Creates a new {@link BlockTask}\n     *\n     * @param start\n     *            the start address of the interval involved by the operation\n     * @param end\n     *            the end address of the interval involved by the operation\n     * @param mode\n     *            the {@link Mode} of the operation\n     */\n    public BlockTask(int start, int end, Mode mode) {\n        super(start, end);\n        requireNonNull(mode, \"The provided mode cannot be null\");\n        this.mode = mode;\n    }\n\n    /**\n     * Sets the parent of this task.\n     *\n     * @see BlockTaskAggregator\n     * @param parent\n     *            the parent task\n     */\n    public void setParent(ToplevelBlockTask parent) {\n        this.parent = parent;\n    }\n\n    /**\n     * Returns the parent of this task.\n     *\n     * @return the parent task, or {@code null} if this task has no parent.\n     */\n    public ToplevelBlockTask getParent() {\n        return this.parent;\n    }\n\n    /**\n     * Returns the {@link Mode} of this task.\n     *\n     * @return the {@link Mode} of this task\n     */\n    public Mode getMode() {\n        return this.mode;\n    }\n\n    /**\n     * Performs the operation described by this task.\n     *\n     * @throws IOException\n     *             If an I/O error occurs during the operation\n     */\n    public abstract void run() throws IOException;\n\n    /**\n     * Notifies this task that the operation performed by the parent task is failed.\n     *\n     * @param reason\n     *            An {@link Exception} instance describing the reason of the failure\n     */\n    public abstract void onFailure(Exception exception);\n\n    /**\n     * Notifies this task that the operation performed by the parent task failed.\n     */\n    public abstract void onSuccess();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BlockTaskAggregator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.driver.block.Block;\nimport org.eclipse.kura.driver.block.BlockAggregator;\nimport org.eclipse.kura.driver.block.BlockFactory;\n\n/**\n * <p>\n * Represents a specialized version of {@link BlockAggregator} that operates on {@link BlockTask} instances.\n * This class performs the aggregation of the input blocks in the same way as {@link BlockAggregator} does, and always\n * returns {@link ToplevelBlockTask} instances as result of the aggregation.\n * </p>\n *\n * <p>\n * If any {@link BlockTask} is found in the input block list, it will be assigned to the proper parent task in the\n * result list, basing on the start and end addresses of the two tasks.\n * <p>\n *\n * <p>\n * The result of the aggregation performed by this class is therefore a generally two level tree structure: the first\n * level of\n * the tree is composed by {@link ToplevelBlockTask} instances responsible of managing a data buffer, the second level\n * is composed by {@link BlockTask} instances that perform an operation using the buffer of the parent. See\n * {@link ToplevelBlockTask} for more information on this structure.\n * <p>\n *\n * @see ToplevelBlockTask\n * @see BlockTask\n */\npublic class BlockTaskAggregator extends BlockAggregator<ToplevelBlockTask> {\n\n    /**\n     * Creates a new {@link BlockAggregator} instance that operates on the given list of blocks.\n     * The provided list must be mutable as it will be sorted every time the {@link BlockAggregator#stream()} method is\n     * called.\n     *\n     * @param inputBlocks\n     *            a mutable list of input blocks.\n     * @param factory\n     *            a {@link BlockFactory} instance that will be used to create the output blocks during the aggregation\n     *            process.\n     */\n    public BlockTaskAggregator(List<Block> tasks, BlockFactory<ToplevelBlockTask> factory) {\n        super(tasks, factory);\n    }\n\n    @SuppressWarnings(\"checkstyle:innerAssignment\")\n    private void assignTasks(ToplevelBlockTask toplevelTask, ListIterator<Block> tasks) {\n        Block next = null;\n        while (tasks.hasNext() && (next = tasks.next()).getEnd() <= toplevelTask.getEnd()) {\n            if (next instanceof BlockTask) {\n                toplevelTask.addChild((BlockTask) next);\n            }\n        }\n        if (next != null) {\n            tasks.previous();\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Stream<ToplevelBlockTask> stream() {\n        final Stream<ToplevelBlockTask> result = super.stream();\n        final ListIterator<Block> blocks = this.blocks.listIterator();\n        return result.map(toplevelTask -> {\n            assignTasks(toplevelTask, blocks);\n            return toplevelTask;\n        });\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ByteArrayTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.driver.binary.ByteArray;\n\npublic class ByteArrayTask extends BinaryDataTask<byte[]> {\n\n    public ByteArrayTask(ChannelRecord record, int start, int end, Mode mode) {\n        super(record, start, new ByteArray(end - start), mode);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport static java.util.Objects.requireNonNull;\n\nimport org.eclipse.kura.channel.ChannelFlag;\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.channel.ChannelStatus;\n\n/**\n * A {@link BlockTask} that performs an operation involving a {@link ChannelRecord}. For example a\n * {@link ChannelBlockTask} instance in {@link Mode#READ} mode could extract some data from the {@link Buffer} of its\n * parent and store it in the {@link ChannelRecord}.\n *\n */\npublic abstract class ChannelBlockTask extends BlockTask {\n\n    protected final ChannelRecord record;\n\n    /**\n     * Creates a new {@link ChannelBlockTask} instance.\n     *\n     * @param record\n     *            the {@link ChannelRecord} instance\n     * @param start\n     *            the start address for this task\n     * @param end\n     *            the end address for this task\n     * @param mode\n     *            the mode of this task\n     */\n    public ChannelBlockTask(ChannelRecord record, int start, int end, Mode mode) {\n        super(start, end, mode);\n        requireNonNull(record, \"The provided channel record cannot be null\");\n        this.record = record;\n    }\n\n    public ChannelRecord getRecord() {\n        return record;\n    }\n\n    /**\n     * Sets the {@link ChannelStatus} of the associated {@link ChannelRecord} to report a success state\n     * and updates the timestamp.\n     */\n    @Override\n    public void onSuccess() {\n        this.record.setChannelStatus(new ChannelStatus(ChannelFlag.SUCCESS));\n        this.record.setTimestamp(System.currentTimeMillis());\n    }\n\n    /**\n     * Sets the {@link ChannelStatus} of the associated {@link ChannelRecord} to report the exception reported as\n     * parameter and updates the timestamp.\n     */\n    @Override\n    public void onFailure(Exception exception) {\n        this.record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, null, exception));\n        this.record.setTimestamp(System.currentTimeMillis());\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTaskWrapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.block.task;\n\npublic abstract class ChannelBlockTaskWrapper extends ChannelBlockTask {\n\n    private final ChannelBlockTask wrapped;\n\n    public ChannelBlockTaskWrapper(final ChannelBlockTask wrapped) {\n        super(wrapped.getRecord(), wrapped.getStart(), wrapped.getEnd(), wrapped.getMode());\n        this.wrapped = wrapped;\n    }\n\n    public ChannelBlockTask getWrappedTask() {\n        return wrapped;\n    }\n\n    @Override\n    public void setParent(final ToplevelBlockTask parent) {\n        super.setParent(parent);\n        wrapped.setParent(parent);\n    }\n\n    @Override\n    public int getStart() {\n        return wrapped.getStart();\n    }\n\n    @Override\n    public int getEnd() {\n        return wrapped.getEnd();\n    }\n\n    @Override\n    public void setEnd(int end) {\n        super.setEnd(end);\n        wrapped.setEnd(end);\n    }\n\n    @Override\n    public void setStart(int start) {\n        super.setStart(start);\n        wrapped.setStart(start);\n    }\n\n    @Override\n    public void onSuccess() {\n        wrapped.onSuccess();\n    }\n\n    @Override\n    public void onFailure(final Exception exception) {\n        wrapped.onFailure(exception);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelListenerBlockTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.block.task;\n\nimport java.io.IOException;\n\nimport org.eclipse.kura.channel.listener.ChannelEvent;\nimport org.eclipse.kura.channel.listener.ChannelListener;\n\npublic class ChannelListenerBlockTask extends ChannelBlockTaskWrapper {\n\n    private final ChannelListener listener;\n\n    public ChannelListenerBlockTask(final ChannelBlockTask wrapped, final ChannelListener listener) {\n        super(wrapped);\n\n        this.listener = listener;\n    }\n\n    public ChannelListener getListener() {\n        return listener;\n    }\n\n    @Override\n    public void run() throws IOException {\n        final ChannelBlockTask wrapped = getWrappedTask();\n\n        wrapped.run();\n\n        listener.onChannelEvent(new ChannelEvent(wrapped.getRecord()));\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/Mode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\n/**\n * Describes an operation performed by a {@link BlockTask}.\n */\npublic enum Mode {\n    /**\n     * The operation is a read\n     */\n    READ,\n    /**\n     * The operation is a write\n     */\n    WRITE,\n    /**\n     * The operation is a read-update-write.\n     *\n     * @see UpdateBlockTask\n     * @see UpdateBlockTaskAggregator\n     */\n    UPDATE\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/StringTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport java.nio.charset.StandardCharsets;\n\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.driver.binary.ByteArray;\nimport org.eclipse.kura.driver.binary.adapter.StringData;\n\npublic class StringTask extends BinaryDataTask<String> {\n\n    public StringTask(ChannelRecord record, int start, int end, Mode mode) {\n        super(record, start, new StringData(new ByteArray(end - start), StandardCharsets.US_ASCII), mode);\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ToplevelBlockTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.eclipse.kura.driver.binary.Buffer;\n\n/**\n * <p>\n * Represent a {@link BlockTask} that has a list of child tasks and maintains a {@link Buffer}.\n * </p>\n * <p>\n * Each child task operates on a subset of the interval described by this task and generally use the buffer provided by\n * this class to perform their operation.\n * </p>\n * <p>\n * The operation described by a {@link ToplevelBlockTask} generally involves transferring data\n * between a {@link Buffer} and device.\n * The children of a {@link ToplevelBlockTask} generally do not perform actual I/O operations but simply use the buffer\n * managed by an instance of this class by either filling or consuming it depending on the {@link Mode}. In particular:\n * </p>\n * <ul>\n * <li>If the {@link Mode} of a {@link ToplevelBlockTask} is {@link Mode#READ} calling the {@link BlockTask#run()}\n * method of this class will trigger the following operations:\n * <ol>\n * <li>The {@link ToplevelBlockTask#processBuffer()} method is called, its implementation must fill the {@link Buffer}\n * of this class with some data, usually obtained performing a read operation from some device.</li>\n * <li>\n * If previous step completes successfully the {@link BlockTask#run()} method of each children will be called. Each\n * child will use the data of the {@link Buffer} filled at previous step to perform its operation (for example\n * extracting some information from it). If the previous step fails the {@link BlockTask#onFailure(Exception)} method of\n * the children will be called to notify the failure.\n * </li>\n * </ol>\n * </li>\n * <li>If the {@link Mode} of a {@link ToplevelBlockTask} is {@link Mode#WRITE} calling the {@link BlockTask#run()}\n * method of this class will trigger the following operations:\n * <ol>\n * <li>\n * The {@link BlockTask#run()} method of each children will be called. Each\n * child should fill a portion of the {@link Buffer} of this class.\n * </li>\n * <li>\n * The {@link ToplevelBlockTask#processBuffer()} method is called, its implementation should use the {@link Buffer}\n * previously filled by the children, for example by transferring it to some device.\n * </li>\n * <li>\n * If previous step completes successfully the {@link BlockTask#onSuccess()} method of each children will be called. If\n * the previous step fails the {@link BlockTask#onFailure(Exception)} method of\n * the children will be called to notify the failure.\n * </li>\n * </ol>\n * </li>\n * </ul>\n */\npublic abstract class ToplevelBlockTask extends BlockTask {\n\n    private final ArrayList<BlockTask> children = new ArrayList<>();\n    private boolean isAborted;\n\n    public ToplevelBlockTask(int start, int end, Mode mode) {\n        super(start, end, mode);\n    }\n\n    /**\n     * Returns the {@link Buffer} managed by this {@link ToplevelBlockTask}. The result must not be null and its size\n     * must be equal to {@code this.getEnd() - this.getStart()}\n     *\n     * @return The {@link Buffer} managed by this {@link ToplevelBlockTask}.\n     */\n    public abstract Buffer getBuffer();\n\n    /**\n     * Performs an operation on the {@link Buffer} managed by this {@link ToplevelBlockTask}. See the class description\n     * for more information on the expected behavior of this method.\n     *\n     * @throws IOException\n     *             If some I/O error occur\n     */\n    public abstract void processBuffer() throws IOException;\n\n    /**\n     * Clears the list of children of this {@link ToplevelBlockTask}\n     */\n    public void clear() {\n        this.children.clear();\n    }\n\n    /**\n     * Returns the children of this {@link ToplevelBlockTask} as an unmodifiable list.\n     *\n     * @return The children of this task\n     */\n    public List<BlockTask> getChildren() {\n        return Collections.unmodifiableList(this.children);\n    }\n\n    /**\n     * Invokes the {@link BlockTask#run()} method on the children of this class.\n     *\n     * @throws IOException\n     *             If the {@link BlockTask#run()} method of a child throw an {@link IOException}\n     */\n    protected void runChildren() throws IOException {\n        this.isAborted = false;\n        for (BlockTask child : getChildren()) {\n            child.setParent(this);\n            child.run();\n            if (this.isAborted) {\n                break;\n            }\n        }\n    }\n\n    /**\n     * Adds a child to this {@link ToplevelBlockTask}\n     *\n     * @param child\n     *            the child to be added.\n     * @throws IllegalArgumentException\n     *             if the interval specified by the provided {@link BlockTask} is not contained by the interval\n     *             specified by this {@link ToplevelBlockTask}\n     */\n    public void addChild(BlockTask child) {\n        if (!this.contains(child)) {\n            throw new IllegalArgumentException(\"The child block must be contained by this block\");\n        }\n        this.children.add(child);\n    }\n\n    /**\n     * Aborts the operation performed by this {@link ToplevelBlockTask}, it can be called by a child if some\n     * non-recoverable error is detected. The {@link BlockTask#onFailure(Exception)} method of the children will be\n     * called to notify the error.\n     *\n     * @param exception\n     *            the reason for which the execution must be aborted.\n     */\n    public void abort(Exception exception) {\n        this.isAborted = true;\n        onFailure(exception);\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void run() throws IOException {\n        try {\n            if (getMode() == Mode.READ) {\n                processBuffer();\n                runChildren();\n            } else {\n                runChildren();\n                processBuffer();\n                onSuccess();\n            }\n        } catch (Exception e) {\n            onFailure(e);\n            throw e;\n        }\n    }\n\n    /**\n     * {@inheritDoc}}\n     */\n    @Override\n    public void onSuccess() {\n        for (BlockTask child : getChildren()) {\n            child.onSuccess();\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public void onFailure(Exception exception) {\n        for (BlockTask child : getChildren()) {\n            child.onFailure(exception);\n        }\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(super.toString());\n\n        if (!this.children.isEmpty()) {\n            builder.append(\" children: \");\n            for (BlockTask b : getChildren()) {\n                builder.append(b.toString());\n                builder.append(' ');\n            }\n        }\n\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/UpdateBlockTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport org.eclipse.kura.channel.ChannelRecord;\n\n/**\n * <p>\n * This is an helper class that can be used to implement read-update-write operations that involve an same interval of\n * addresses. An example of such operation can\n * be reading a block of data from a device, updating that data and then writing it back.\n * </p>\n * <p>\n * If an instance of this class is provided as input to a {@link UpdateBlockTaskAggregator}, and its {@link Mode} is\n * {@link Mode#UPDATE}, it will be assigned to two parent {@link ToplevelBlockTask} instances by the aggregator.\n * The first {@link ToplevelBlockTask} will provide the data needed by this class for the read part of its operation,\n * and the second {@link ToplevelBlockTask} can be used by this class to write back the modified data.\n * </p>\n * <p>\n * In the scenario above, the {@link BlockTask#run()} method of this class will be called twice, the first time for the\n * read part of the operation and the second time for the write. Implementors are not required to implement the\n * {@link BlockTask#run()} method directly but must implement the {@link UpdateBlockTask#runRead()},\n * {@link UpdateBlockTask#runWrite())} and {@link UpdateBlockTask#runUpdate(ToplevelBlockTask, ToplevelBlockTask)}\n * methods instead. See the description of these methods for more information.\n * </p>\n */\npublic abstract class UpdateBlockTask extends ChannelBlockTask {\n\n    private ToplevelBlockTask readParent;\n\n    public UpdateBlockTask(ChannelRecord record, int start, int end, Mode mode) {\n        super(record, start, end, mode);\n    }\n\n    /**\n     * Called if the {@link Mode} of this instance is {@link Mode#READ}. This method should behave in the same way as\n     * the {@link BlockTask#run()} method of a normal (non read-update-write) {@link BlockTask} instance in\n     * {@link Mode#READ} mode.\n     */\n    protected abstract void runRead();\n\n    /**\n     * Called if the {@link Mode} of this instance is {@link Mode#WRITE}. This method should behave in the same way as\n     * the {@link BlockTask#run()} method of a normal (non read-update-write) {@link BlockTask} instance in\n     * {@link Mode#WRITE} mode.\n     */\n    protected abstract void runWrite();\n\n    /**\n     * <p>\n     * Called if the {@link Mode} of this instance is {@link Mode#UPDATE}. The input data required for the operation can\n     * be retrieved from the {@link Buffer} of the {@code read} task, the data should be updated by this method and\n     * then written back to the {@link Buffer} of the {@code write} task.\n     * </p>\n     * <p>\n     * If the {@link Mode} of this task is {@link Mode#UPDATE}, the {@link UpdateBlockTask#runRead()} and\n     * {@link UpdateBlockTask#runWrite()} methods of this class will never be called.\n     * </p>\n     *\n     * @param write\n     *            the {@link ToplevelBlockTask} that contains the data for the read part of the read-update-write\n     *            operation performed by this class\n     * @param read\n     *            the {@link ToplevelBlockTask} that can be used for writing back the data resulting from the\n     *            operation performed by this class\n     */\n    protected abstract void runUpdate(ToplevelBlockTask write, ToplevelBlockTask read);\n\n    @Override\n    public void run() {\n        if (getMode() == Mode.READ) {\n            runRead();\n        } else if (getMode() == Mode.WRITE) {\n            runWrite();\n        } else {\n            final ToplevelBlockTask parent = getParent();\n            if (parent.getMode() == Mode.READ) {\n                this.readParent = parent;\n                return;\n            }\n\n            if (this.readParent == null) {\n                parent.abort(new IllegalStateException(\n                        \"UPDATE requested but read task did not succeed, operation aboreted\"));\n                return;\n            }\n\n            runUpdate(parent, this.readParent);\n            this.readParent = null;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/UpdateBlockTaskAggregator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.task;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.driver.block.Block;\nimport org.eclipse.kura.driver.block.BlockFactory;\nimport org.eclipse.kura.driver.block.ProhibitedBlock;\n\n/**\n * <p>\n * Represents a specialized version of {@link BlockTaskAggregator} that supports the aggregation of tasks whose\n * {@link Mode} is {@link Mode#UPDATE}. This class only supports the aggregation of tasks that are either in\n * {@link Mode#WRITE} or {@link Mode#UPDATE} mode.\n * </p>\n * <p>\n * <p>\n * If a task whose {@link Mode} is {@link Mode#UPDATE} is found in the input block list, it will be assigned to two\n * {@link ToplevelBlockTask} instances, both of them will contain the interval specified by the update task.\n * The first one will operate in {@link Mode#READ}, the second one in {@link Mode#WRITE}.\n * </p>\n * <p>\n * If the {@link ToplevelBlockTask} instances described above are executed in sequence, the {@link BlockTask#run()}\n * method of the update task will be called twice, the first time the parent of the update task will be assigned to the\n * {@link ToplevelBlockTask} in {@link Mode#READ} mode, the second time it will be assigned to the\n * {@link ToplevelBlockTask} in {@link Mode#WRITE} mode.\n * </p>\n * <p>\n * If a task that operates in {@link Mode#UPDATE} needs to be defined, the\n * {@link UpdateBlockTask} class should be extended.\n * </p>\n * <p>\n * If some tasks in {@link Mode#UPDATE} are found in the input block list, this class will perform two\n * separate aggregation processes: one for the {@link ToplevelBlockTask} instances required to fetch the data needed for\n * the read part of the read-update-write operations, and the other for the {@link ToplevelBlockTask} instances required\n * for the write part.\n * </p>\n *\n * @see ToplevelBlockTask\n * @see BlockTask\n */\npublic class UpdateBlockTaskAggregator extends BlockTaskAggregator {\n\n    private final BlockTaskAggregator readTaskAggregator;\n\n    /**\n     * Creates a new {@link UpdateBlockTaskAggregator} instance\n     *\n     * @param tasks\n     *            the list of input tasks\n     * @param readTaskFactory\n     *            a {@link BlockFactory} that will be used for creating the {@link ToplevelBlockTask} instances in\n     *            {@link Mode#READ} mode\n     * @param writeTaskFactory\n     *            a {@link BlockFactory} that will be used for creating the {@link ToplevelBlockTask} instances in\n     *            {@link Mode#WRITE} mode\n     * @throws IllegalArgumentException\n     *             if any task in {@link Mode#READ} is found in the input task list\n     */\n    public UpdateBlockTaskAggregator(List<Block> tasks, BlockFactory<ToplevelBlockTask> readTaskFactory,\n            BlockFactory<ToplevelBlockTask> writeTaskFactory) {\n        super(tasks, writeTaskFactory);\n        requireNonNull(readTaskFactory, \"Read tasks factory cannot be null\");\n        this.readTaskAggregator = createReadTaskAggregator(tasks, readTaskFactory);\n    }\n\n    private static BlockTaskAggregator createReadTaskAggregator(List<Block> tasks,\n            BlockFactory<ToplevelBlockTask> readTaskFactory) {\n        ArrayList<Block> updateTasks = tasks.stream().filter(block -> {\n            if (!(block instanceof BlockTask)) {\n                return false;\n            }\n            BlockTask task = (BlockTask) block;\n            if (task.getMode() == Mode.READ) {\n                throw new IllegalArgumentException(\"Read task are not supported by UpdateBlockTaskAggregator\");\n            }\n            return task.getMode() == Mode.UPDATE;\n        }).collect(Collectors.toCollection(ArrayList::new));\n        return new BlockTaskAggregator(updateTasks, readTaskFactory);\n    }\n\n    /**\n     * Sets the {@code minimumGapSize} that will be used for aggregating the {@link ToplevelBlockTask} tasks\n     * in {@link Mode#READ} mode, the {@link ToplevelBlockTask} instances in {@link Mode#WRITE} will always be\n     * aggregated with {@code minimumGapSize = 0}.\n     */\n    @Override\n    public void setMinimumGapSize(int minimumGapSize) {\n        this.readTaskAggregator.setMinimumGapSize(minimumGapSize);\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @throws IllegalArgumentException\n     *             if the provided task is in {@link Mode#READ} mode.\n     */\n    @Override\n    public void addBlock(Block block) {\n        boolean isBlockTask = block instanceof BlockTask;\n        if (isBlockTask && ((BlockTask) block).getMode() == Mode.READ) {\n            throw new IllegalArgumentException(\"Read task are not supported by UpdateBlockTaskAggregator\");\n        }\n        super.addBlock(block);\n        if (block instanceof ProhibitedBlock || isBlockTask && ((BlockTask) block).getMode() == Mode.UPDATE) {\n            this.readTaskAggregator.addBlock(block);\n        }\n    }\n\n    /**\n     * Returns a {@link Stream} yielding the result of the aggregation. The returned {@link Stream} will produce the\n     * {@link ToplevelBlockTask} instances in {@link Mode#READ} first and then the {@link ToplevelBlockTask} instances\n     * in {@link Mode#WRITE} mode.\n     */\n    @Override\n    public Stream<ToplevelBlockTask> stream() {\n        return Stream.concat(this.readTaskAggregator.stream(), super.stream());\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.helper.provider/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.helper.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Driver Helper Service Provider\nBundle-SymbolicName: org.eclipse.kura.driver.helper.provider\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.eclipse.kura.asset;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.driver;version=\"[1.0,1.1)\",\n org.eclipse.kura.driver.descriptor;version=\"[1.0,1.1)\",\n org.eclipse.kura.util.collection;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.service;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.8\",\n org.osgi.service.cm;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.2\",\n org.slf4j;version=\"1.6.4\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.helper.provider/OSGI-INF/DriverDescriptorComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    \n   Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n    Eurotech\n    Amit Kumar Mondal\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.driver.DriverService\">\n   <implementation class=\"org.eclipse.kura.internal.driver.DriverServiceImpl\"/>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.driver.DriverService\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.driver.DriverService\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.helper.provider/OSGI-INF/DriverServiceComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    \n   Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n    Eurotech\n    \n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.driver.descriptor.DriverDescriptorService\">\n   <implementation class=\"org.eclipse.kura.internal.driver.DriverDescriptorServiceImpl\"/>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.driver.descriptor.DriverDescriptorService\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.driver.descriptor.DriverDescriptorService\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.helper.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.driver.helper.provider/build.properties",
    "content": "#\n#  Copyright (c) 2016, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\tAmit Kumar Mondal\n#\n\nsource.. = src/main/java/\nsrc.includes = about.html\nbin.includes = META-INF/,\\\n               .,\\\n               about.html,\\\n               OSGI-INF/\nadditional.bundles = org.eclipse.osgi\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.helper.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2016, 2024 Red Hat Inc and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Red Hat Inc\n\t Amit Kumar Mondal\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.driver.helper.provider</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.driver.helper.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.helper.provider/src/main/java/org/eclipse/kura/internal/driver/DriverDescriptorServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.internal.driver;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID;\nimport static org.osgi.service.cm.ConfigurationAdmin.SERVICE_FACTORYPID;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.driver.Driver;\nimport org.eclipse.kura.driver.descriptor.DriverDescriptor;\nimport org.eclipse.kura.driver.descriptor.DriverDescriptorService;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class DriverDescriptorServiceImpl implements DriverDescriptorService {\n\n    private static final Logger logger = LoggerFactory.getLogger(DriverDescriptorServiceImpl.class);\n\n    private BundleContext bundleContext;\n\n    public void activate(ComponentContext componentContext) {\n        this.bundleContext = componentContext.getBundleContext();\n    }\n\n    @Override\n    public Optional<DriverDescriptor> getDriverDescriptor(String driverPid) {\n        requireNonNull(driverPid, \"Driver PID cannot be null\");\n        DriverDescriptor driverDescriptor = null;\n\n        String filterString = String.format(\"(&(kura.service.pid=%s))\", driverPid);\n\n        final ServiceReference<Driver>[] refs = getDriverServiceReferences(filterString);\n        try {\n            for (final ServiceReference<Driver> driverServiceReference : refs) {\n                String factoryPid = driverServiceReference.getProperty(SERVICE_FACTORYPID).toString();\n                Driver driver = this.bundleContext.getService(driverServiceReference);\n                driverDescriptor = newDriverDescriptor(driverPid, factoryPid, driver);\n            }\n        } finally {\n            ungetDriverServiceReferences(refs);\n        }\n\n        return Optional.ofNullable(driverDescriptor);\n    }\n\n    @Override\n    public List<DriverDescriptor> listDriverDescriptors() {\n        List<DriverDescriptor> driverDescriptors = new ArrayList<>();\n\n        final ServiceReference<Driver>[] refs = getDriverServiceReferences(null);\n        try {\n            for (final ServiceReference<Driver> driverServiceReference : refs) {\n                String driverPid = driverServiceReference.getProperty(KURA_SERVICE_PID).toString();\n                String factoryPid = driverServiceReference.getProperty(SERVICE_FACTORYPID).toString();\n                Driver driver = this.bundleContext.getService(driverServiceReference);\n                driverDescriptors.add(newDriverDescriptor(driverPid, factoryPid, driver));\n            }\n        } finally {\n            ungetDriverServiceReferences(refs);\n        }\n\n        return driverDescriptors;\n    }\n\n    private DriverDescriptor newDriverDescriptor(String driverPid, String factoryPid, Driver driver) {\n        Object channelDescriptorObj = null;\n        try {\n            channelDescriptorObj = driver.getChannelDescriptor().getDescriptor();\n        } catch (Exception e) {\n            logger.warn(\"Failed to get driver descriptor for pid: {}\", driverPid, e);\n        }\n        return new DriverDescriptor(driverPid, factoryPid, channelDescriptorObj);\n    }\n\n    protected ServiceReference<Driver>[] getDriverServiceReferences(final String filter) {\n        return ServiceUtil.getServiceReferences(this.bundleContext, Driver.class, filter);\n    }\n\n    protected void ungetDriverServiceReferences(final ServiceReference<Driver>[] refs) {\n        ServiceUtil.ungetServiceReferences(this.bundleContext, refs);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.helper.provider/src/main/java/org/eclipse/kura/internal/driver/DriverServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.internal.driver;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.driver.Driver.DRIVER_PID_PROPERTY_NAME;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.eclipse.kura.driver.Driver;\nimport org.eclipse.kura.driver.DriverService;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\n\n/**\n * The Class DriverServiceImpl is an implementation of the utility API\n * {@link DriverService} to provide useful factory methods for drivers\n */\npublic class DriverServiceImpl implements DriverService {\n\n    private BundleContext bundleContext;\n\n    public void activate(ComponentContext componentContext) {\n        this.bundleContext = componentContext.getBundleContext();\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public Driver getDriver(final String driverPid) {\n        requireNonNull(driverPid, \"Driver PID cannot be null\");\n\n        Driver driver = null;\n\n        String filterString = String.format(\"(&(kura.service.pid=%s))\", driverPid);\n        final ServiceReference<Driver>[] refs = getDriverServiceReferences(filterString);\n        try {\n            for (final ServiceReference<Driver> ref : refs) {\n                driver = this.bundleContext.getService(ref);\n            }\n        } finally {\n            ungetDriverServiceReferences(refs);\n        }\n        return driver;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public String getDriverPid(final Driver driver) {\n        requireNonNull(driver, \"Driver PID cannot be null\");\n        final ServiceReference<Driver>[] refs = getDriverServiceReferences(null);\n        try {\n            for (final ServiceReference<Driver> ref : refs) {\n                final Driver driverRef = this.bundleContext.getService(ref);\n                if (driverRef == driver) {\n                    return ref.getProperty(DRIVER_PID_PROPERTY_NAME).toString();\n                }\n            }\n        } finally {\n            ungetDriverServiceReferences(refs);\n        }\n        return null;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public List<Driver> listDrivers() {\n        final List<Driver> drivers = new ArrayList<>();\n        final ServiceReference<Driver>[] refs = getDriverServiceReferences(null);\n        try {\n            for (final ServiceReference<Driver> ref : refs) {\n                final Driver driverRef = this.bundleContext.getService(ref);\n                drivers.add(driverRef);\n            }\n        } finally {\n            ungetDriverServiceReferences(refs);\n        }\n        return drivers;\n    }\n\n    protected ServiceReference<Driver>[] getDriverServiceReferences(final String filter) {\n        return ServiceUtil.getServiceReferences(this.bundleContext, Driver.class, filter);\n    }\n\n    protected void ungetDriverServiceReferences(final ServiceReference<Driver>[] refs) {\n        ServiceUtil.ungetServiceReferences(this.bundleContext, refs);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/.gitignore",
    "content": "/dp/\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: S7 PLC Communication Driver\nBundle-SymbolicName: org.eclipse.kura.driver.s7plc.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: Moka7;version=\"[1.0,1.1)\",\n org.eclipse.kura;version=\"[1.2,2.0)\",\n org.eclipse.kura.channel;version=\"[1.0,2.0)\",\n org.eclipse.kura.channel.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.configuration.metatype;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.2,2.0)\",\n org.eclipse.kura.driver;version=\"[1.0,1.1)\",\n org.eclipse.kura.type;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.base;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.collection;version=\"[1.0,2.0)\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .,\n lib/org.eclipse.kura.driver.block.jar\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/OSGI-INF/S7PlcDriverComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    \n   Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n    Amit Kumar Mondal (admin@amitinside.com)\n    Eurotech\n    \n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" \n               name=\"org.eclipse.kura.driver.s7plc\"\n               activate=\"activate\" \n               deactivate=\"deactivate\" \n               modified=\"updated\"\n               enabled=\"true\" \n               configuration-policy=\"require\"> \n   <implementation class=\"org.eclipse.kura.internal.driver.s7plc.S7PlcDriver\"/>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.driver.s7plc\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.driver.Driver\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <reference bind=\"setCryptoService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.crypto.CryptoService\" name=\"CryptoService\" policy=\"static\" unbind=\"unsetCryptoService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/OSGI-INF/metatype/org.eclipse.kura.driver.s7plc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    \n    Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Amit Kumar Mondal (admin@amitinside.com)\n     Eurotech\n     \n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.driver.s7plc\" \n         name=\"S7PlcDriver\" \n         description=\"S7PLC Driver\">\n\n        <AD id=\"host.ip\"\n            name=\"host.ip\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            description=\"S7 PLC Host IP Address\">\n        </AD>\n        \n        <AD id=\"rack\"\n            name=\"rack\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            description=\"S7 PLC Rack\">\n        </AD>\n        \n        <AD id=\"slot\"\n            name=\"slot\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"2\"\n            description=\"S7 PLC Slot\">\n        </AD>\n        \n        <AD id=\"authenticate\"\n            name=\"authenticate\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"If set to true the driver will send to the PLC the session password provided in the configuration.\">\n        </AD>\n        \n        <AD id=\"password\"\n            name=\"password\"\n            type=\"Password\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"\"\n            description=\"The session password.\">\n        </AD>\n        \n        <AD id=\"read.minimum.gap.size\"\n            name=\"read.minimum.gap.size\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            description=\"Defines the minimum gap size for read requests in bytes, if set to a non zero value the driver will aggregate read requests for non consecutive addresses if their distance is lesser than this parameter.\">\n        </AD>\n\n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.driver.s7plc\" factoryPid=\"org.eclipse.kura.driver.s7plc\">\n        <Object ocdref=\"org.eclipse.kura.driver.s7plc\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/build.properties",
    "content": "source.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               lib/,\\\n               lib/org.eclipse.kura.driver.block.jar,\\\n               about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/lib/.gitignore",
    "content": "/*.jar\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n     Amit Kumar Mondal (admin@amitinside.com)\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.driver.s7plc.provider</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <optimizer.version>1.0.0</optimizer.version>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.basedir}/../test/org.eclipse.kura.internal.driver.s7plc.test/target/site/jacoco-aggregate/jacoco.xml\n        </sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.driver.block</artifactId>\n            <version>${optimizer.version}</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>3.8.1</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <outputDirectory>${project.build.directory}</outputDirectory>\n                            <includeArtifactIds>\n                                org.eclipse.kura.driver.block\n                            </includeArtifactIds>\n                            <stripVersion>false</stripVersion>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>generate-sources</phase>\n                        <id>copy-optimizer-jar</id>\n                        <configuration>\n                            <target>\n                                <copy\n                                    file=\"${project.build.directory}/org.eclipse.kura.driver.block-${optimizer.version}.jar\"\n                                    tofile=\"lib/org.eclipse.kura.driver.block.jar\" overwrite=\"true\" />\n                            </target>\n                        </configuration>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                    </execution>\n                    <execution>\n                        <phase>clean</phase>\n                        <id>clean-optimizer-jar</id>\n                        <configuration>\n                            <target>\n                                <delete file=\"lib/org.eclipse.kura.driver.block.optimizer.jar\"></delete>\n                            </target>\n                        </configuration>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcChannelDescriptor.java",
    "content": "/**\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal (admin@amitinside.com)\n */\npackage org.eclipse.kura.internal.driver.s7plc;\n\nimport java.util.List;\n\nimport org.eclipse.kura.core.configuration.metatype.Tad;\nimport org.eclipse.kura.core.configuration.metatype.Toption;\nimport org.eclipse.kura.core.configuration.metatype.Tscalar;\nimport org.eclipse.kura.driver.ChannelDescriptor;\nimport org.eclipse.kura.util.collection.CollectionUtil;\n\n/**\n * S7 PLC specific channel descriptor. The descriptor contains the following\n * attribute definition identifiers.\n *\n * <ul>\n * <li>area.no</li> denotes the Area Number\n * <li>offset</li> the offset\n * <li>byte.count</li> the number of bytes to read\n * </ul>\n */\npublic final class S7PlcChannelDescriptor implements ChannelDescriptor {\n\n    public static final String S7_ELEMENT_TYPE_ID = \"s7.data.type\";\n    public static final String DATA_BLOCK_NO_ID = \"data.block.no\";\n    public static final String BYTE_COUNT_ID = \"byte.count\";\n    public static final String OFFSET_ID = \"offset\";\n    public static final String BIT_INDEX_ID = \"bit.index\";\n\n    private Toption generateOption(S7PlcDataType type) {\n        Toption option = new Toption();\n        option.setLabel(type.name());\n        option.setValue(type.name());\n        return option;\n    }\n\n    /** {@inheritDoc} */\n    @Override\n    public Object getDescriptor() {\n        final List<Tad> elements = CollectionUtil.newArrayList();\n\n        final Tad s7ElementType = new Tad();\n        s7ElementType.setName(S7_ELEMENT_TYPE_ID);\n        s7ElementType.setId(S7_ELEMENT_TYPE_ID);\n        s7ElementType.setDescription(\"S7 Data Type\");\n        s7ElementType.setType(Tscalar.STRING);\n        s7ElementType.setRequired(true);\n        s7ElementType.setDefault(S7PlcDataType.INT.name());\n\n        for (S7PlcDataType t : S7PlcDataType.values()) {\n            s7ElementType.setOption(generateOption(t));\n        }\n\n        elements.add(s7ElementType);\n\n        final Tad areaNo = new Tad();\n        areaNo.setName(DATA_BLOCK_NO_ID);\n        areaNo.setId(DATA_BLOCK_NO_ID);\n        areaNo.setDescription(\"DB number\");\n        areaNo.setType(Tscalar.INTEGER);\n        areaNo.setRequired(true);\n        areaNo.setDefault(\"0\");\n\n        elements.add(areaNo);\n\n        final Tad offset = new Tad();\n        offset.setName(OFFSET_ID);\n        offset.setId(OFFSET_ID);\n        offset.setDescription(\"offset\");\n        offset.setType(Tscalar.INTEGER);\n        offset.setRequired(true);\n        offset.setDefault(\"0\");\n\n        elements.add(offset);\n\n        final Tad byteCount = new Tad();\n        byteCount.setName(BYTE_COUNT_ID);\n        byteCount.setId(BYTE_COUNT_ID);\n        byteCount.setDescription(\"Byte Count\");\n        byteCount.setType(Tscalar.INTEGER);\n        byteCount.setRequired(true);\n        byteCount.setDefault(\"0\");\n\n        elements.add(byteCount);\n\n        final Tad bitIndex = new Tad();\n        bitIndex.setName(BIT_INDEX_ID);\n        bitIndex.setId(BIT_INDEX_ID);\n        bitIndex.setDescription(\"Bit Index\");\n        bitIndex.setType(Tscalar.INTEGER);\n        bitIndex.setRequired(true);\n        bitIndex.setMin(\"0\");\n        bitIndex.setMax(\"7\");\n        bitIndex.setDefault(\"0\");\n\n        elements.add(bitIndex);\n\n        return elements;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcDataType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.internal.driver.s7plc;\n\npublic enum S7PlcDataType {\n\n    BOOL,\n    BYTE,\n    WORD,\n    DWORD,\n    INT,\n    DINT,\n    REAL,\n    CHAR\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcDomain.java",
    "content": "/**\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n */\n\npackage org.eclipse.kura.internal.driver.s7plc;\n\npublic class S7PlcDomain {\n\n    private final int db;\n\n    public S7PlcDomain(int db) {\n        this.db = db;\n    }\n\n    public int getDB() {\n        return this.db;\n    }\n\n    @Override\n    public int hashCode() {\n        return this.db;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        S7PlcDomain other = (S7PlcDomain) obj;\n        if (this.db != other.db) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcDriver.java",
    "content": "/**\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n */\n\npackage org.eclipse.kura.internal.driver.s7plc;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.driver.ChannelDescriptor;\nimport org.eclipse.kura.driver.block.BlockFactory;\nimport org.eclipse.kura.driver.block.task.AbstractBlockDriver;\nimport org.eclipse.kura.driver.block.task.BlockTask;\nimport org.eclipse.kura.driver.block.task.Mode;\nimport org.eclipse.kura.driver.block.task.ToplevelBlockTask;\nimport org.eclipse.kura.internal.driver.s7plc.task.S7PlcTaskBuilder;\nimport org.eclipse.kura.internal.driver.s7plc.task.S7PlcToplevelBlockTask;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport Moka7.S7;\nimport Moka7.S7Client;\n\n/**\n * The Kura S7PlcDriver is a S7 PLC Driver implementation for Kura Asset-Driver\n * Topology.<br/>\n * <br/>\n *\n * The Kura S7 PLC Driver can be used in cooperation with Kura Asset Model and in\n * isolation as well. In case of isolation, the properties needs to be provided\n * externally.<br/>\n * <br/>\n *\n * The required properties are enlisted in {@link S7PlcChannelDescriptor} and\n * the driver connection specific properties are enlisted in\n * {@link S7PlcOptions}\n *\n * @see S7PlcChannelDescriptor\n * @see S7PlcOptions\n */\npublic class S7PlcDriver extends AbstractBlockDriver<S7PlcDomain> implements ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(S7PlcDriver.class);\n\n    private S7ClientState state = new S7ClientState(new S7PlcOptions(Collections.emptyMap()));\n    private final AtomicReference<S7PlcOptions> options = new AtomicReference<>();\n\n    private CryptoService cryptoService;\n\n    public void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void unsetCryptoService() {\n        this.cryptoService = null;\n    }\n\n    public void activate(final Map<String, Object> properties) {\n        logger.debug(\"Activating S7 PLC Driver...\");\n        updated(properties);\n        logger.debug(\"Activating S7 PLC Driver... Done\");\n    }\n\n    public synchronized void deactivate() {\n        logger.debug(\"Deactivating S7 PLC Driver...\");\n        try {\n            disconnect();\n        } catch (final ConnectionException e) {\n            logger.error(\"Error while disconnecting...\", e);\n        }\n        logger.debug(\"Deactivating S7 PLC Driver.....Done\");\n    }\n\n    public void updated(final Map<String, Object> properties) {\n        logger.debug(\"Updating S7 PLC Driver...\");\n        this.options.set(new S7PlcOptions(properties));\n        logger.debug(\"Updating S7 PLC Driver... Done\");\n    }\n\n    private String decryptPassword(char[] encryptedPassword) throws KuraException {\n        final char[] decodedPasswordChars = this.cryptoService.decryptAes(encryptedPassword);\n        return new String(decodedPasswordChars);\n    }\n\n    private void authenticate(final S7ClientState state) throws ConnectionException {\n        logger.debug(\"Authenticating\");\n        int code;\n        try {\n            code = state.client.SetSessionPassword(decryptPassword(state.options.getPassword().toCharArray()));\n        } catch (Exception e) {\n            throw new ConnectionException(e);\n        }\n        if (code != 0) {\n            throw new ConnectionException(\"Authentication failed, SetSessionPassword() failed with code: \" + code);\n        }\n    }\n\n    @Override\n    public synchronized void connect() throws ConnectionException {\n        try {\n            final S7PlcOptions currentOptions = this.options.get();\n\n            if (this.state.options != currentOptions) {\n                logger.info(\"configuration changed, disconnecting...\");\n                disconnect();\n                this.state = createClientState(currentOptions);\n                logger.info(\"configuration changed, disconnecting...Done\");\n            }\n\n            if (!this.state.client.Connected) {\n                logger.debug(\"Connecting to S7 PLC...\");\n                this.state.client.SetConnectionType(S7.OP);\n                int code = this.state.client.ConnectTo(currentOptions.getIp(), currentOptions.getRack(),\n                        currentOptions.getSlot());\n                if (code != 0) {\n                    throw new ConnectionException(\"Failed to connect to PLC, ConnectTo() failed with code: \" + code);\n                }\n                if (currentOptions.shouldAuthenticate()) {\n                    authenticate(this.state);\n                }\n                logger.debug(\"Connecting to S7 PLC... Done\");\n            }\n        } catch (Exception e) {\n            throw new ConnectionException(\"Connection failed, unexpected exception\", e);\n        }\n    }\n\n    @Override\n    public synchronized void disconnect() throws ConnectionException {\n        if (this.state.client.Connected) {\n            logger.debug(\"Disconnecting from S7 PLC...\");\n            this.state.client.Disconnect();\n            logger.debug(\"Disconnecting from S7 PLC... Done\");\n        }\n    }\n\n    @Override\n    protected int getReadMinimumGapSizeForDomain(S7PlcDomain domain) {\n        return this.options.get().getMinimumGapSize();\n    }\n\n    @Override\n    protected BlockFactory<ToplevelBlockTask> getTaskFactoryForDomain(final S7PlcDomain domain, final Mode mode) {\n        return (start, end) -> new S7PlcToplevelBlockTask(S7PlcDriver.this, mode, domain.getDB(), start, end);\n    }\n\n    @Override\n    protected Stream<Pair<S7PlcDomain, BlockTask>> toTasks(List<ChannelRecord> records, Mode mode) {\n        return S7PlcTaskBuilder.build(records, mode);\n    }\n\n    @Override\n    public ChannelDescriptor getChannelDescriptor() {\n        return new S7PlcChannelDescriptor();\n    }\n\n    protected S7ClientState createClientState(final S7PlcOptions options) {\n        return new S7ClientState(options);\n    }\n\n    @Override\n    protected void runTask(BlockTask task) {\n        try {\n            task.run();\n        } catch (Moka7Exception e) {\n            handleMoka7IOException(e);\n        } catch (Exception e) {\n            logger.warn(\"Unexpected exception\", e);\n        }\n    }\n\n    private void handleMoka7IOException(Moka7Exception e) {\n        logger.warn(\"Operation failed due to IO error\", e);\n        if (e.getStatusCode() <= S7Client.errTCPConnectionReset) {\n            logger.warn(\"Connection problems detected, disconnecting, will attempt to reconnect at next read/write\");\n            try {\n                disconnect();\n            } catch (ConnectionException e1) {\n                logger.warn(\"Unable to Disconnect...\", e1);\n            }\n        }\n    }\n\n    public synchronized void write(int db, int offset, byte[] data) throws IOException {\n        int result = this.state.client.WriteArea(S7.S7AreaDB, db, offset, data.length, data);\n        if (result != 0) {\n            throw new Moka7Exception(\"DB: \" + db + \" off: \" + offset + \" len: \" + data.length + \" status: \" + result,\n                    result);\n        }\n    }\n\n    public synchronized void read(int db, int offset, byte[] data) throws IOException {\n        int result = this.state.client.ReadArea(S7.S7AreaDB, db, offset, data.length, data);\n        if (result != 0) {\n            throw new Moka7Exception(\"DB: \" + db + \" off: \" + offset + \" len: \" + data.length + \" status: \" + result,\n                    result);\n        }\n    }\n\n    @SuppressWarnings(\"serial\")\n    static final class Moka7Exception extends IOException {\n\n        /**\n         *\n         */\n        private static final long serialVersionUID = -6118257067654374279L;\n        private final int statusCode;\n\n        public Moka7Exception(String message, int statusCode) {\n            super(message);\n            this.statusCode = statusCode;\n        }\n\n        public int getStatusCode() {\n            return this.statusCode;\n        }\n    }\n\n    static final class S7ClientState {\n\n        private final S7Client client;\n        private final S7PlcOptions options;\n\n        S7ClientState(final S7PlcOptions options) {\n            this(options, new S7Client());\n        }\n\n        public S7ClientState(final S7PlcOptions options, final S7Client client) {\n            this.options = options;\n            this.client = client;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcOptions.java",
    "content": "/**\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal (admin@amitinside.com)\n */\n\npackage org.eclipse.kura.internal.driver.s7plc;\n\nimport java.util.Map;\n\nfinal class S7PlcOptions {\n\n    private static final Property<String> IP_PROP = new Property<>(\"host.ip\", \"\");\n    private static final Property<Boolean> AUTENTICATE_PROP = new Property<>(\"authenticate\", false);\n    private static final Property<String> PASSWORD_PROP = new Property<>(\"password\", \"\");\n    private static final Property<Integer> RACK_PROP = new Property<>(\"rack\", 0);\n    private static final Property<Integer> SLOT_PROP = new Property<>(\"slot\", 2);\n    private static final Property<Integer> MINIMUM_GAP_SIZE_PROP = new Property<>(\"read.minimum.gap.size\", 0);\n\n    private final String ip;\n    private final boolean authenticate;\n    private final String password;\n    private final int rack;\n    private final int slot;\n    private final int minimumGapSize;\n\n    S7PlcOptions(final Map<String, Object> properties) {\n        this.ip = IP_PROP.get(properties);\n        this.authenticate = AUTENTICATE_PROP.get(properties);\n        this.password = PASSWORD_PROP.get(properties);\n        this.rack = RACK_PROP.get(properties);\n        this.slot = SLOT_PROP.get(properties);\n        this.minimumGapSize = MINIMUM_GAP_SIZE_PROP.get(properties);\n    }\n\n    String getIp() {\n        return this.ip;\n    }\n\n    boolean shouldAuthenticate() {\n        return this.authenticate;\n    }\n\n    String getPassword() {\n        return this.password;\n    }\n\n    int getRack() {\n        return this.rack;\n    }\n\n    int getSlot() {\n        return this.slot;\n    }\n\n    int getMinimumGapSize() {\n        return this.minimumGapSize;\n    }\n\n    private static class Property<T> {\n\n        private final String key;\n        private final T defaultValue;\n\n        public Property(String key, T defaultValue) {\n            this.key = key;\n            this.defaultValue = defaultValue;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public T get(Map<String, Object> properties) {\n            final Object value = properties.get(this.key);\n            if (this.defaultValue.getClass().isInstance(value)) {\n                return (T) value;\n            }\n            return this.defaultValue;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/task/S7PlcTaskBuilder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.internal.driver.s7plc.task;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.channel.ChannelFlag;\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.channel.ChannelStatus;\nimport org.eclipse.kura.driver.binary.BinaryDataTypes;\nimport org.eclipse.kura.driver.block.task.AbstractBlockDriver.Pair;\nimport org.eclipse.kura.driver.block.task.BinaryDataTask;\nimport org.eclipse.kura.driver.block.task.BitTask;\nimport org.eclipse.kura.driver.block.task.BlockTask;\nimport org.eclipse.kura.driver.block.task.ByteArrayTask;\nimport org.eclipse.kura.driver.block.task.Mode;\nimport org.eclipse.kura.driver.block.task.StringTask;\nimport org.eclipse.kura.internal.driver.s7plc.S7PlcChannelDescriptor;\nimport org.eclipse.kura.internal.driver.s7plc.S7PlcDataType;\nimport org.eclipse.kura.internal.driver.s7plc.S7PlcDomain;\nimport org.eclipse.kura.type.DataType;\n\npublic final class S7PlcTaskBuilder {\n\n    private S7PlcTaskBuilder() {\n    }\n\n    private static int getAreaNo(ChannelRecord record) throws KuraException {\n        try {\n            return getIntProperty(record, S7PlcChannelDescriptor.DATA_BLOCK_NO_ID, \"Error while retrieving Area No\");\n        } catch (KuraException e) {\n            record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e));\n            record.setTimestamp(System.currentTimeMillis());\n            throw e;\n        }\n    }\n\n    private static int getIntProperty(ChannelRecord record, String propertyName, String failureMessage)\n            throws KuraException {\n        try {\n            return Integer.parseInt(record.getChannelConfig().get(propertyName).toString());\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, failureMessage);\n        }\n    }\n\n    private static void assertChannelType(ChannelRecord record, DataType channelType) throws KuraException {\n        if (channelType != record.getValueType()) {\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, \"Channel Value Type must be \" + channelType);\n        }\n    }\n\n    private static BlockTask build(ChannelRecord record, Mode mode) throws KuraException {\n\n        final Map<String, Object> channelConfig = record.getChannelConfig();\n\n        DataType type = record.getValueType();\n\n        int offset = getIntProperty(record, S7PlcChannelDescriptor.OFFSET_ID, \"Error while retrieving Area Offset\");\n        String s7DataTypeId = (String) channelConfig.get(S7PlcChannelDescriptor.S7_ELEMENT_TYPE_ID);\n\n        if (type == DataType.BYTE_ARRAY) {\n\n            int byteCount = getIntProperty(record, S7PlcChannelDescriptor.BYTE_COUNT_ID,\n                    \"Error while retrieving Byte Count\");\n            return new ByteArrayTask(record, offset, offset + byteCount, mode);\n\n        } else if (S7PlcDataType.INT.name().equals(s7DataTypeId)) {\n\n            return new BinaryDataTask<>(record, offset, BinaryDataTypes.INT16_BE, type, mode);\n\n        } else if (S7PlcDataType.DINT.name().equals(s7DataTypeId)) {\n\n            return new BinaryDataTask<>(record, offset, BinaryDataTypes.INT32_BE, type, mode);\n\n        } else if (S7PlcDataType.BOOL.name().equals(s7DataTypeId)) {\n\n            assertChannelType(record, DataType.BOOLEAN);\n            int bitIndex = getIntProperty(record, S7PlcChannelDescriptor.BIT_INDEX_ID,\n                    \"Error while retreiving bit index\");\n            return new BitTask(record, offset, bitIndex, mode == Mode.WRITE ? Mode.UPDATE : Mode.READ);\n\n        } else if (S7PlcDataType.WORD.name().equals(s7DataTypeId)) {\n\n            return new BinaryDataTask<>(record, offset, BinaryDataTypes.UINT16_BE, type, mode);\n\n        } else if (S7PlcDataType.DWORD.name().equals(s7DataTypeId)) {\n\n            return new BinaryDataTask<>(record, offset, BinaryDataTypes.UINT32_BE, type, mode);\n\n        } else if (S7PlcDataType.BYTE.name().equals(s7DataTypeId)) {\n\n            return new BinaryDataTask<>(record, offset, BinaryDataTypes.UINT8, type, mode);\n\n        } else if (S7PlcDataType.CHAR.name().equals(s7DataTypeId)) {\n\n            assertChannelType(record, DataType.STRING);\n            int byteCount = getIntProperty(record, S7PlcChannelDescriptor.BYTE_COUNT_ID,\n                    \"Error while retrieving Byte Count\");\n            return new StringTask(record, offset, offset + byteCount, mode);\n\n        } else if (S7PlcDataType.REAL.name().equals(s7DataTypeId)) {\n\n            return new BinaryDataTask<>(record, offset, BinaryDataTypes.FLOAT_BE, type, mode);\n\n        }\n\n        throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, \"Unable to determine operation\");\n\n    }\n\n    public static Stream<Pair<S7PlcDomain, BlockTask>> build(List<ChannelRecord> records, Mode mode) {\n        return records.stream().map((record) -> {\n            try {\n                final int db = S7PlcTaskBuilder.getAreaNo(record);\n                return new Pair<>(new S7PlcDomain(db), build(record, mode));\n            } catch (Exception e) {\n                record.setTimestamp(System.currentTimeMillis());\n                record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e));\n                return null;\n            }\n        }).filter(Objects::nonNull);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/task/S7PlcToplevelBlockTask.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.internal.driver.s7plc.task;\n\nimport java.io.IOException;\n\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.driver.binary.ByteArrayBuffer;\nimport org.eclipse.kura.driver.block.task.Mode;\nimport org.eclipse.kura.driver.block.task.ToplevelBlockTask;\nimport org.eclipse.kura.internal.driver.s7plc.S7PlcDriver;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class S7PlcToplevelBlockTask extends ToplevelBlockTask {\n\n    private static final Logger logger = LoggerFactory.getLogger(S7PlcDriver.class);\n\n    private final int areaNo;\n    private ByteArrayBuffer data;\n    private final S7PlcDriver driver;\n\n    public S7PlcToplevelBlockTask(S7PlcDriver driver, Mode mode, int dbNumber, int start, int end) {\n        super(start, end, mode);\n        this.areaNo = dbNumber;\n        this.driver = driver;\n    }\n\n    @Override\n    public void processBuffer() throws IOException {\n        if (getMode() == Mode.READ) {\n            logger.debug(\"Reading from PLC, DB{} offset: {} length: {}\", this.areaNo, getStart(),\n                    getBuffer().getLength());\n            this.driver.read(this.areaNo, getStart(), ((ByteArrayBuffer) getBuffer()).getBackingArray());\n        } else {\n            logger.debug(\"Writing to PLC, DB{} offset: {} length: {}\", this.areaNo, getStart(),\n                    getBuffer().getLength());\n            this.driver.write(this.areaNo, getStart(), ((ByteArrayBuffer) getBuffer()).getBackingArray());\n        }\n    }\n\n    @Override\n    public Buffer getBuffer() {\n        if (this.data == null) {\n            this.data = new ByteArrayBuffer(new byte[getEnd() - getStart()]);\n        }\n        return this.data;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Event Publisher\nBundle-SymbolicName: org.eclipse.kura.event.publisher;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: EUROTECH\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.publisher;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0.0,2.0.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.util.tracker;version=\"1.5.1\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/OSGI-INF/metatype/org.eclipse.kura.event.publisher.EventPublisher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2022 Eurotech and/or its affiliates. All rights reserved.\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.event.publisher.EventPublisher\" \n        name=\"EventPublisher\">\n\n\t\t<AD id=\"topic.prefix\"\n            name=\"Topic prefix\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"$EVT\"\n            description=\"The topic prefix to use for events publishing. Can be left empty.\">\n        </AD>\n\n\t\t<AD id=\"topic\"\n            name=\"Topic\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"\"\n            description=\"The message topic to use for publishing events.\">\n        </AD>\n\n        <AD id=\"qos\"\n            name=\"Qos\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            description=\"The desired quality of service for the log messages that have to be published. If Qos is 0,\n            the log message is delivered at most once, or it is not delivered at all. If Qos is set to 1, the message\n            is always delivered at least once.\">\n            <Option label=\"0\" value=\"0\" />\n            <Option label=\"1\" value=\"1\" />\n        </AD>\n\n        <AD id=\"retain\"\n            name=\"Retain\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\"\n            description=\"Default retaing flag for the published messages.\">\n        </AD>\n\n        <AD id=\"priority\"\n            name=\"Priority\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"7\"\n            description='Message priority. Priority level 0 (highest) should be used sparingly and reserved for\n            messages that should be sent with the minimum latency. Default is set to 7.'>\n        </AD>\n    </OCD>\n    \n    <Designate pid=\"org.eclipse.kura.event.publisher.EventPublisher\"\n    \tfactoryPid=\"org.eclipse.kura.event.publisher.EventPublisher\">\n        <Object ocdref=\"org.eclipse.kura.event.publisher.EventPublisher\"/>\n    </Designate>\n</MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/OSGI-INF/org.eclipse.kura.event.publisher.EventPublisher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2022 Eurotech and/or its affiliates. All rights reserved.\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n    name=\"org.eclipse.kura.event.publisher.EventPublisher\"\n    configuration-policy=\"require\"   \n    activate=\"activate\" deactivate=\"deactivate\" modified=\"updated\"\n    enabled=\"true\" immediate=\"true\">\n    \n    <implementation class=\"org.eclipse.kura.event.publisher.EventPublisher\"/>\n    \n    <service>\n        <provide interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"/>\n        <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n    </service>\n    \n    <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.event.publisher.EventPublisher\"/>\n    <property name=\"cloud.connection.factory.pid\" type=\"String\" value=\"org.eclipse.kura.cloud.CloudService\"/>\n    <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n    <property name=\"kura.ui.factory.hide\" type=\"String\" value=\"true\"/>\n</scr:component>"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/build.properties",
    "content": "###############################################################################\n# Copyright (c) 2022 Eurotech and/or its affiliates. All rights reserved. \n###############################################################################\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/\n"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    \n    <modelVersion>4.0.0</modelVersion>\n    <artifactId>org.eclipse.kura.event.publisher</artifactId>\n    <packaging>eclipse-plugin</packaging>\n    <version>2.0.0-SNAPSHOT</version>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n    \n    <properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\t\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/EventPublisher.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.event.publisher;\n\nimport static org.eclipse.kura.event.publisher.EventPublisherConstants.CONTROL;\nimport static org.eclipse.kura.event.publisher.EventPublisherConstants.FULL_TOPIC;\nimport static org.eclipse.kura.event.publisher.EventPublisherConstants.PRIORITY;\nimport static org.eclipse.kura.event.publisher.EventPublisherConstants.QOS;\nimport static org.eclipse.kura.event.publisher.EventPublisherConstants.RETAIN;\nimport static org.eclipse.kura.event.publisher.EventPublisherConstants.TOPIC_ACCOUNT_TOKEN;\nimport static org.eclipse.kura.event.publisher.EventPublisherConstants.TOPIC_CLIENT_ID_TOKEN;\nimport static org.eclipse.kura.event.publisher.EventPublisherConstants.TOPIC_SEPARATOR;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.event.publisher.helper.CloudEndpointServiceHelper;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class EventPublisher\n        implements CloudPublisher, ConfigurableComponent, CloudConnectionListener, CloudDeliveryListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(EventPublisher.class);\n\n    private static final String TOPIC_PATTERN_STRING = \"\\\\$([^\\\\s/]+)\";\n    private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING);\n\n    private BundleContext bundleContext;\n\n    private Set<CloudDeliveryListener> cloudDeliveryListeners = new HashSet<>();\n    private Set<CloudConnectionListener> cloudConnectionListeners = new HashSet<>();\n\n    private EventPublisherOptions options;\n    private final ExecutorService worker = Executors.newCachedThreadPool();\n\n    private CloudEndpointServiceHelper cloudHelper;\n\n    /*\n     * Activation APIs\n     */\n\n    public void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        logger.debug(\"Activating ConfigurationChangePublisher...\");\n\n        this.bundleContext = componentContext.getBundleContext();\n\n        updated(properties);\n\n        logger.debug(\"Activating ConfigurationChangePublisher... Done.\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.debug(\"Updating ConfigurationChangePublisher...\");\n        \n        this.options = new EventPublisherOptions(properties);\n        this.cloudHelper = new CloudEndpointServiceHelper(this.bundleContext, this.options.getCloudEndpointPid());\n\n        logger.debug(\"Updating ConfigurationChangePublisher... Done.\");\n    }\n\n    public void deactivate(ComponentContext componentContext) {\n        logger.debug(\"Deactivating ConfigurationChangePublisher...\");\n        this.cloudHelper.close();\n        logger.debug(\"Deactivating ConfigurationChangePublisher... Done.\");\n    }\n\n    /*\n     * CloudPublisher APIs\n     */\n\n    @Override\n    public String publish(KuraMessage message) throws KuraException {\n        if (message == null) {\n            throw new IllegalArgumentException(\"Kura message cannot be null\");\n        }\n\n        String resolvedAppTopic = fillAppTopicPlaceholders(this.options.getTopic(), message);\n        String fullTopic = encodeFullTopic(resolvedAppTopic);\n\n        Map<String, Object> publishMessageProps = new HashMap<>();\n        publishMessageProps.put(FULL_TOPIC, fullTopic);\n        publishMessageProps.put(QOS, this.options.getQos());\n        publishMessageProps.put(RETAIN, this.options.isRetain());\n        publishMessageProps.put(PRIORITY, this.options.getPriority());\n        publishMessageProps.put(CONTROL, true);\n\n        return this.cloudHelper.publish(new KuraMessage(message.getPayload(), publishMessageProps));\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.add(cloudConnectionListener);\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        this.cloudConnectionListeners.remove(cloudConnectionListener);\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.add(cloudDeliveryListener);\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        this.cloudDeliveryListeners.remove(cloudDeliveryListener);\n    }\n\n    /*\n     * CloudConnectionListener APIs\n     */\n\n    @Override\n    public void onDisconnected() {\n        this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onDisconnected));\n    }\n\n    @Override\n    public void onConnectionLost() {\n        this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionLost));\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionEstablished));\n    }\n\n    /*\n     * CloudDeliveryListener APIs\n     */\n\n    @Override\n    public void onMessageConfirmed(String messageId) {\n        this.cloudDeliveryListeners\n                .forEach(listener -> this.worker.execute(() -> listener.onMessageConfirmed(messageId)));\n    }\n\n    private String fillAppTopicPlaceholders(String appTopic, KuraMessage message) {\n        Matcher matcher = TOPIC_PATTERN.matcher(appTopic);\n        StringBuffer buffer = new StringBuffer();\n\n        while (matcher.find()) {\n            Map<String, Object> properties = message.getProperties();\n            if (properties.containsKey(matcher.group(1))) {\n                String replacement = matcher.group(0);\n\n                Object value = properties.get(matcher.group(1));\n                if (replacement != null) {\n                    matcher.appendReplacement(buffer, value.toString());\n                }\n            }\n        }\n        matcher.appendTail(buffer);\n        return buffer.toString();\n    }\n\n    private String encodeFullTopic(String appTopic) {\n        String accountName = TOPIC_ACCOUNT_TOKEN;\n        String clientId = TOPIC_CLIENT_ID_TOKEN;\n        String topicSeparator = TOPIC_SEPARATOR;\n\n        StringBuilder sb = new StringBuilder();\n\n        Optional<String> topicPrefix = this.options.getTopicPrefix();\n        if (topicPrefix.isPresent()) {\n            sb.append(topicPrefix.get()).append(topicSeparator);\n        }\n        sb.append(accountName).append(topicSeparator);\n        sb.append(clientId).append(topicSeparator).append(appTopic);\n\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/EventPublisherConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.event.publisher;\n\n\npublic final class EventPublisherConstants {\n\n    private EventPublisherConstants() {\n    }\n\n    public static final String TOPIC_ACCOUNT_TOKEN = \"#account-name\";\n    public static final String TOPIC_CLIENT_ID_TOKEN = \"#client-id\";\n    public static final String TOPIC_SEPARATOR = \"/\";\n    public static final String CONTROL = \"CONTROL\";\n    public static final String FULL_TOPIC = \"FULL_TOPIC\";\n    public static final String PRIORITY = \"PRIORITY\";\n    public static final String QOS = \"QOS\";\n    public static final String RETAIN = \"RETAIN\";\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/EventPublisherOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.event.publisher;\n\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class EventPublisherOptions {\n    \n    public static final String TOPIC_PREFIX_PROP_NAME = \"topic.prefix\";\n    public static final String TOPIC_PROP_NAME = \"topic\";\n    public static final String QOS_PROP_NAME = \"qos\";\n    public static final String RETAIN_PROP_NAME = \"retain\";\n    public static final String PRIORITY_PROP_NAME = \"priority\";\n\n    public static final String DEFAULT_TOPIC = \"EVENT_TOPIC\";\n    public static final int DEFAULT_QOS = 0;\n    public static final boolean DEFAULT_RETAIN = false;\n    public static final int DEFAULT_PRIORITY = 7;\n    public static final String DEFAULT_ENDPOINT_PID = \"org.eclipse.kura.cloud.CloudService\";\n\n    private static final Property<String> PROPERTY_CLOUD_SERVICE_PID = new Property<>(\n            CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), DEFAULT_ENDPOINT_PID);\n    private static final Property<String> PROPERTY_TOPIC_PREFIX = new Property<>(TOPIC_PREFIX_PROP_NAME, String.class);\n    private static final Property<String> PROPERTY_TOPIC = new Property<>(TOPIC_PROP_NAME, DEFAULT_TOPIC);\n    private static final Property<Integer> PROPERTY_QOS = new Property<>(QOS_PROP_NAME, DEFAULT_QOS);\n    private static final Property<Boolean> PROPERTY_RETAIN = new Property<>(RETAIN_PROP_NAME, DEFAULT_RETAIN);\n    private static final Property<Integer> PROPERTY_PRIORITY = new Property<>(PRIORITY_PROP_NAME, DEFAULT_PRIORITY);\n\n    private String cloudEndpointPid;\n    private Optional<String> topicPrefix;\n    private String topic;\n    private int qos;\n    private boolean retain;\n    private int priority;\n\n    public EventPublisherOptions(final Map<String, Object> properties) {\n        this.cloudEndpointPid = PROPERTY_CLOUD_SERVICE_PID.get(properties);\n        this.topicPrefix = PROPERTY_TOPIC_PREFIX.getOptional(properties);\n        this.topic = PROPERTY_TOPIC.get(properties);\n        this.qos = PROPERTY_QOS.get(properties);\n        this.retain = PROPERTY_RETAIN.get(properties);\n        this.priority = PROPERTY_PRIORITY.get(properties);\n    }\n\n    public String getCloudEndpointPid() {\n        return this.cloudEndpointPid;\n    }\n\n    public Optional<String> getTopicPrefix() {\n\n        if (this.topicPrefix.isPresent()) {\n            if (this.topicPrefix.get().length() == 0) {\n                return Optional.empty();\n            }\n            return Optional.of(removeTopicSeparatorsFromExtremes(this.topicPrefix.get()));\n        }\n\n        return this.topicPrefix;\n    }\n\n    public String getTopic() {\n        return removeTopicSeparatorsFromExtremes(this.topic);\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    public boolean isRetain() {\n        return this.retain;\n    }\n\n    public int getPriority() {\n        return this.priority;\n    }\n\n    private String removeTopicSeparatorsFromExtremes(String input) {\n        String result = new String(input);\n        if (result.startsWith(EventPublisherConstants.TOPIC_SEPARATOR)) {\n            result = result.substring(1);\n        }\n\n        if (result.endsWith(EventPublisherConstants.TOPIC_SEPARATOR)) {\n            result = result.substring(0, result.length() - 1);\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/helper/CloudEndpointServiceHelper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.event.publisher.helper;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudEndpointServiceHelper implements CloudEndpointTrackerListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudEndpointServiceHelper.class);\n\n    private CloudEndpointServiceTracker cloudEndpointTracker;\n    private BundleContext context;\n    private CloudEndpoint cloudEndpoint;\n\n    public CloudEndpointServiceHelper(BundleContext context, String endpointPid) {\n        this.context = context;\n\n        initCloudEndpointTracker(endpointPid);\n    }\n\n    public void close() {\n        if (this.cloudEndpointTracker != null) {\n            logger.debug(\"Closing CloudEndpoint tracker...\");\n            this.cloudEndpointTracker.close();\n            this.cloudEndpointTracker.unregisterCloudStackTrackerListener(this);\n            this.cloudEndpointTracker = null;\n            this.cloudEndpoint = null;\n            logger.debug(\"Closing CloudEndpoint tracker... Done.\");\n        }\n    }\n\n    public String publish(KuraMessage message) throws KuraException {\n        if (this.cloudEndpoint == null) {\n            throw new KuraException(KuraErrorCode.PROCESS_EXECUTION_ERROR, \"CloudEndpoint not available\");\n        }\n        \n        return this.cloudEndpoint.publish(message);\n    }\n\n    private void initCloudEndpointTracker(String endpointPid) {\n        try {\n            this.cloudEndpointTracker = new CloudEndpointServiceTracker(this.context, endpointPid);\n            this.cloudEndpointTracker.registerCloudStackTrackerListener(this);\n            this.cloudEndpointTracker.open();\n        } catch (InvalidSyntaxException e) {\n            logger.error(\"Service tracker filter setup exception.\", e);\n        }\n    }\n\n    @Override\n    public void onCloudEndpointAdded(CloudEndpoint cloudEndpoint) {\n        this.cloudEndpoint = cloudEndpoint;\n    }\n\n    @Override\n    public void onCloudEndpointRemoved(CloudEndpoint cloudEndpoint) {\n        this.cloudEndpoint = null;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/helper/CloudEndpointServiceTracker.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.event.publisher.helper;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.util.tracker.ServiceTracker;\n\npublic class CloudEndpointServiceTracker extends ServiceTracker<CloudEndpoint, CloudEndpoint> {\n\n    private Set<CloudEndpointTrackerListener> listeners = new HashSet<>();\n\n    public CloudEndpointServiceTracker(BundleContext context, String endpointPid) throws InvalidSyntaxException {\n        super(context, context.createFilter(String.format(\"(&(%s=%s)(%s=%s))\", Constants.OBJECTCLASS,\n                CloudEndpoint.class.getName(), ConfigurationService.KURA_SERVICE_PID, endpointPid)), null);\n    }\n\n    public void registerCloudStackTrackerListener(CloudEndpointTrackerListener listener) {\n        this.listeners.add(listener);\n    }\n\n    public void unregisterCloudStackTrackerListener(CloudEndpointTrackerListener listener) {\n        this.listeners.remove(listener);\n    }\n\n    @Override\n    public CloudEndpoint addingService(ServiceReference<CloudEndpoint> reference) {\n        CloudEndpoint endpoint = super.addingService(reference);\n\n        for (CloudEndpointTrackerListener listener : this.listeners) {\n            listener.onCloudEndpointAdded(endpoint);\n        }\n\n        return endpoint;\n    }\n\n    @Override\n    public void removedService(ServiceReference<CloudEndpoint> reference, CloudEndpoint service) {\n        super.removedService(reference, service);\n\n        for (CloudEndpointTrackerListener listener : this.listeners) {\n            listener.onCloudEndpointRemoved(service);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/helper/CloudEndpointTrackerListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.event.publisher.helper;\n\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\n\npublic interface CloudEndpointTrackerListener {\n\n    public void onCloudEndpointAdded(CloudEndpoint cloudEndpoint);\n\n    public void onCloudEndpointRemoved(CloudEndpoint cloudEndpoint);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.http.server.manager\nBundle-SymbolicName: org.eclipse.kura.http.server.manager\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nImport-Package: jakarta.servlet;version=\"5.0.0\",\n jakarta.servlet.http;version=\"5.0.0\",\n org.eclipse.jetty.ee10.servlet;version=\"12.0.14\",\n org.eclipse.jetty.http;version=\"12.0.14\",\n org.eclipse.jetty.server;version=\"12.0.14\",\n org.eclipse.jetty.server.handler;version=\"12.0.14\",\n org.eclipse.jetty.server.handler.gzip;version=\"12.0.14\",\n org.eclipse.jetty.session;version=\"12.0.14\",\n org.eclipse.jetty.util.component;version=\"12.0.14\",\n org.eclipse.jetty.util.compression;version=\"12.0.14\",\n org.eclipse.jetty.util.ssl;version=\"12.0.14\",\n org.eclipse.jetty.util.thread;version=\"12.0.14\",\n org.eclipse.kura;version=\"[1.5,2.0)\",\n org.eclipse.kura.configuration;version=\"1.2.0\",\n org.eclipse.kura.crypto;version=\"[1.2,2.0)\",\n org.eclipse.kura.security.keystore;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.6,2.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.component;version=\"1.3.0\",\n org.osgi.service.event;version=\"1.4.0\",\n org.slf4j;version=\"1.7.21\"\nRequire-Bundle: org.apache.felix.http.bridge;bundle-version=\"5.1.8\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/OSGI-INF/httpService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.2.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.http.server.manager.HttpService\">\n   <implementation class=\"org.eclipse.kura.http.server.manager.HttpService\"/>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.http.server.manager.HttpService\"/>\n   <service>\n       <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n       <provide interface=\"org.osgi.service.event.EventHandler\"/>\n   </service>\n\n   <reference name=\"KeystoreService\"\n           policy=\"static\"\n           policy-option=\"greedy\"\n           bind=\"setKeystoreService\"\n           cardinality=\"0..1\"\n           interface=\"org.eclipse.kura.security.keystore.KeystoreService\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   <property name=\"event.topics\" type=\"String\">org/eclipse/kura/security/keystore/KeystoreChangedEvent/KEYSTORE_CHANGED</property>\n   <reference bind=\"setDispatcherServlet\" cardinality=\"1..1\" interface=\"jakarta.servlet.http.HttpServlet\" name=\"HttpServlet\" policy=\"static\" target=\"(http.felix.dispatcher=*)\"/>\n   <reference bind=\"setEventListener\" cardinality=\"1..1\" interface=\"java.util.EventListener\" name=\"EventListener\" policy=\"static\" target=\"(http.felix.dispatcher=*)\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/OSGI-INF/metatype/org.eclipse.kura.http.server.manager.HttpService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2019, 2021 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.http.server.manager.HttpService\"\n         name=\"HttpService\"\n         description=\"This service allows the user to enable and configure the http and https connectors in Kura web server. Every change to this service will cause a restart of the web server and a possible temporary UI unavailability.\">\n\n        <AD id=\"http.ports\"\n            name=\"HTTP Ports\"\n            type=\"Integer\"\n            cardinality=\"3\"\n            required=\"false\"\n            min=\"1\"\n            max=\"65535\"\n            description=\"Specifies a list of ports for unencrypted HTTP. If set to an empty list, unencrypted HTTP will be disabled.\">\n        </AD>\n\n        <AD id=\"https.ports\"\n            name=\"HTTPS Without Certificate Authentication Ports\"\n            type=\"Integer\"\n            cardinality=\"3\"\n            required=\"false\"\n            min=\"1\"\n            max=\"65535\"\n            description=\"Specifies a list of ports for HTTPS without client side certificate authentication. If set to an empty list, HTTPS without client side certificate authentication will be disabled.\">\n        </AD>\n        \n        <AD id=\"https.client.auth.ports\"\n            name=\"HTTPS With Certificate Authentication Ports\"\n            type=\"Integer\"\n            cardinality=\"3\"\n            required=\"false\"\n            min=\"1\"\n            max=\"65535\"\n            description=\"Specifies a list of ports for HTTPS with client side certificate authentication. If set to an empty list, HTTPS with client side certificate authentication will be disabled.\">\n        </AD>\n        \n        <AD id=\"KeystoreService.target\"\n            name=\"KeystoreService Target Filter\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"(kura.service.pid=changeme)\"\n            description=\"Specifies, as an OSGi target filter, the pid of the KeystoreService used to manage the HTTPS Keystore.\">\n        </AD>\n      \n        <AD id=\"https.revocation.check.enabled\"\n            name=\"Revocation Check Enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"false\"\n            description=\"If enabled, the revocation status of client certificates will be checked during TLS handshake. If a revoked certificate is detected, the following handshake will fail. The revocation status will be checked using OCSP, CRLDP, or the CRLs cached by the attached KeystoreService instance, depending on the value of the Revocation Check Mode parameter. If not enabled, the revocation check will not be performed.\"/>\n\n        <AD id=\"ssl.revocation.mode\"\n            name=\"Revocation Check Mode\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"PREFER_OCSP\"\n            description=\"Specifies the mode for performing revocation check. This parameter is ignored if Revocation Check Enabled is set to false.\">\n            <Option label=\"Use OCSP first and then KeystoreService CRLs and CRLDP\" value=\"PREFER_OCSP\"/>\n            <Option label=\"Use KeystoreService CRLs and CRLDP first and then OCSP\" value=\"PREFER_CRL\"/>\n            <Option label=\"Use only KeystoreService CRLs and CRLDP\" value=\"CRL_ONLY\"/>\n        </AD>\n\n        <AD id=\"https.client.revocation.soft.fail\"\n            name=\"Revocation Soft-fail Enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"false\"\n            description=\"Specifies whether the revocation soft fail is enabled or not. If it is enabled and the gateway is not able to verify the revocation status of a client certificate (for example due to a connectivity problem), the certificate will be rejected. This parameter is ignored if Revocation Check Enabled is set to false.\"/>\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.http.server.manager.HttpService\">\n        <Object ocdref=\"org.eclipse.kura.http.server.manager.HttpService\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/build.properties",
    "content": "#\n# Copyright (c) 2019, 2025 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2019, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n\tSPDX-License-Identifier: EPL-2.0\n\n\tContributors:\n\t Eurotech\n\t s\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.http.server.manager</artifactId>\n\t<packaging>eclipse-plugin</packaging>\n\t<version>2.0.0-SNAPSHOT</version>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/src/main/java/org/eclipse/kura/http/server/manager/BaseSslContextFactory.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.http.server.manager;\n\nimport java.security.KeyStore;\n\nimport javax.net.ssl.KeyManager;\n\nimport org.eclipse.jetty.util.ssl.SslContextFactory;\nimport org.eclipse.kura.security.keystore.KeystoreService;\n\npublic class BaseSslContextFactory extends SslContextFactory.Server {\n\n    protected final KeystoreService keystoreService;\n\n    public BaseSslContextFactory(final KeystoreService keystoreService) {\n        this.keystoreService = keystoreService;\n    }\n\n    @Override\n    protected KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception {\n        return this.keystoreService.getKeyManagers(getKeyManagerFactoryAlgorithm()).toArray(new KeyManager[0]);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/src/main/java/org/eclipse/kura/http/server/manager/ClientAuthSslContextFactoryImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.http.server.manager;\n\nimport java.security.KeyStore;\nimport java.security.cert.CertPathValidator;\nimport java.security.cert.CertStore;\nimport java.security.cert.CollectionCertStoreParameters;\nimport java.security.cert.PKIXBuilderParameters;\nimport java.security.cert.PKIXRevocationChecker;\nimport java.security.cert.PKIXRevocationChecker.Option;\nimport java.security.cert.X509CertSelector;\nimport java.util.Collection;\nimport java.util.Set;\n\nimport org.eclipse.kura.security.keystore.KeystoreService;\n\npublic final class ClientAuthSslContextFactoryImpl extends BaseSslContextFactory {\n\n    private boolean isRevocationEnabled;\n    private Set<Option> revocationOptions;\n\n    public ClientAuthSslContextFactoryImpl(final KeystoreService keystoreService, final boolean isRevocationEnabled,\n            final Set<PKIXRevocationChecker.Option> revocationOptions) {\n        super(keystoreService);\n\n        this.isRevocationEnabled = isRevocationEnabled;\n        this.revocationOptions = revocationOptions;\n        setValidatePeerCerts(isRevocationEnabled);\n    }\n\n    @Override\n    protected PKIXBuilderParameters newPKIXBuilderParameters(KeyStore trustStore,\n            Collection<? extends java.security.cert.CRL> crls) throws Exception {\n        PKIXBuilderParameters pbParams = new PKIXBuilderParameters(trustStore, new X509CertSelector());\n\n        pbParams.setMaxPathLength(getMaxCertPathLength());\n        pbParams.setRevocationEnabled(this.isRevocationEnabled);\n\n        final PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) CertPathValidator.getInstance(\"PKIX\")\n                .getRevocationChecker();\n\n        revocationChecker.setOptions(this.revocationOptions);\n\n        pbParams.addCertPathChecker(revocationChecker);\n\n        if (getPkixCertPathChecker() != null) {\n            pbParams.addCertPathChecker(getPkixCertPathChecker());\n        }\n\n        try {\n            pbParams.addCertStore(this.keystoreService.getCRLStore());\n        } catch (Exception e) {\n            if (crls != null && !crls.isEmpty()) {\n                pbParams.addCertStore(CertStore.getInstance(\"Collection\", new CollectionCertStoreParameters(crls)));\n            }\n        }\n\n        return pbParams;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/src/main/java/org/eclipse/kura/http/server/manager/HttpService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.http.server.manager;\n\nimport java.util.EventListener;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.security.keystore.KeystoreChangedEvent;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.servlet.http.HttpServlet;\n\npublic class HttpService implements ConfigurableComponent, EventHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(HttpService.class);\n\n    private HttpServiceOptions options;\n\n    private KeystoreService keystoreService;\n    private HttpServlet dispatcherServlet;\n    private EventListener eventListener;\n\n    private String keystoreServicePid;\n\n    private JettyServerHolder jettyServerHolder;\n    private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();\n    private Future<?> restartTask = CompletableFuture.completedFuture(null);\n\n    public void setKeystoreService(KeystoreService keystoreService, final Map<String, Object> properties) {\n        this.keystoreService = keystoreService;\n        this.keystoreServicePid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n    }\n\n    public void setDispatcherServlet(HttpServlet dispatcherServlet) {\n        this.dispatcherServlet = dispatcherServlet;\n    }\n\n    public void setEventListener(EventListener eventListener) {\n        this.eventListener = eventListener;\n    }\n\n    public void activate(Map<String, Object> properties) {\n        logger.info(\"Activating {}\", this.getClass().getSimpleName());\n\n        this.options = new HttpServiceOptions(properties);\n\n        startHttpService(this.options);\n\n        logger.info(\"Activating... Done.\");\n    }\n\n    public synchronized void updated(Map<String, Object> properties) {\n        logger.info(\"Updating {}\", this.getClass().getSimpleName());\n\n        HttpServiceOptions updatedOptions = new HttpServiceOptions(properties);\n\n        if (!this.options.equals(updatedOptions)) {\n            logger.debug(\"Updating, new props\");\n            this.options = updatedOptions;\n\n            cancelRestartTask();\n            restartHttpService();\n        }\n\n        logger.info(\"Updating... Done.\");\n    }\n\n    public synchronized void deactivate() {\n        logger.info(\"Deactivating {}\", this.getClass().getSimpleName());\n\n        cancelRestartTask();\n        stopHttpService();\n        shutdownExecutor();\n    }\n\n    private synchronized void restartHttpService() {\n        stopHttpService();\n        startHttpService(this.options);\n    }\n\n    private synchronized void startHttpService(final HttpServiceOptions options) {\n        this.executorService.submit(() -> {\n            try {\n                logger.info(\"starting Jetty instance...\");\n                this.jettyServerHolder = new JettyServerHolder(options, Optional.ofNullable(this.keystoreService),\n                        this.dispatcherServlet, this.eventListener);\n                logger.info(\"starting Jetty instance...done\");\n            } catch (final Exception e) {\n                logger.error(\"Could not start Jetty Web server\", e);\n            }\n        });\n    }\n\n    private synchronized void stopHttpService() {\n        this.executorService.submit(() -> {\n            try {\n                logger.info(\"stopping Jetty instance...\");\n                if (this.jettyServerHolder != null) {\n                    this.jettyServerHolder.stop();\n                }\n            } catch (final Exception e) {\n                logger.error(\"Could not stop Jetty Web server\", e);\n            }\n        });\n    }\n\n    private synchronized void shutdownExecutor() {\n        try {\n            this.executorService.shutdown();\n            this.executorService.awaitTermination(30, TimeUnit.SECONDS);\n        } catch (final InterruptedException e) {\n            Thread.currentThread().interrupt();\n            logger.error(\"Could not stop executor\", e);\n        } finally {\n            this.executorService.shutdownNow();\n        }\n    }\n\n    private synchronized void cancelRestartTask() {\n        if (!this.restartTask.isDone()) {\n            this.restartTask.cancel(false);\n        }\n    }\n\n    private synchronized void scheduleDeferredRestart() {\n        cancelRestartTask();\n\n        try {\n            this.restartTask = this.executorService.schedule(this::restartHttpService, 10, TimeUnit.SECONDS);\n        } catch (final Exception e) {\n            logger.warn(\"failed to schedule restart task\", e);\n        }\n    }\n\n    @Override\n    public void handleEvent(final Event event) {\n        if (!(event instanceof KeystoreChangedEvent)) {\n            return;\n        }\n\n        final KeystoreChangedEvent keystoreChangedEvent = (KeystoreChangedEvent) event;\n\n        if (keystoreChangedEvent.getSenderPid().equals(keystoreServicePid)) {\n            scheduleDeferredRestart();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/src/main/java/org/eclipse/kura/http/server/manager/HttpServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.http.server.manager;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class HttpServiceOptions {\n\n    public enum RevocationCheckMode {\n        PREFER_OCSP,\n        PREFER_CRL,\n        CRL_ONLY\n    }\n\n    static final String PROP_HTTP_PORTS = \"http.ports\";\n    static final String PROP_HTTPS_PORTS = \"https.ports\";\n    static final String PROP_HTTPS_CLIENT_AUTH_PORTS = \"https.client.auth.ports\";\n\n    static final String PROP_REVOCATION_ENABLED = \"https.revocation.check.enabled\";\n    static final String PROP_REVOCATION_MODE = \"ssl.revocation.mode\";\n    static final String PROP_CRL_PATH = \"https.client.crl.path\";\n    static final String PROP_REVOCATION_SOFT_FAIL = \"https.client.revocation.soft.fail\";\n\n    static final String PROP_KEYSTORE_SERVICE = \"KeystoreService.target\";\n\n    private static final Property<Integer[]> HTTP_PORTS = new Property<>(PROP_HTTP_PORTS, new Integer[] {});\n    private static final Property<Integer[]> HTTPS_PORTS = new Property<>(PROP_HTTPS_PORTS, new Integer[] {});\n    private static final Property<Integer[]> HTTPS_CLIENT_AUTH_PORTS = new Property<>(PROP_HTTPS_CLIENT_AUTH_PORTS,\n            new Integer[] {});\n    private static final Property<Boolean> REVOCATION_ENABLED = new Property<>(PROP_REVOCATION_ENABLED, false);\n    private static final Property<String> REVOCATION_MODE = new Property<>(PROP_REVOCATION_MODE,\n            RevocationCheckMode.PREFER_OCSP.name());\n    private static final Property<Boolean> REVOCATION_SOFT_FAIL = new Property<>(PROP_REVOCATION_SOFT_FAIL, false);\n    private static final Property<String> KEYSTORE_SERVICE = new Property<>(PROP_KEYSTORE_SERVICE,\n            \"kura.service.pid=changeit\");\n\n    private final Set<Integer> httpPorts;\n    private final Set<Integer> httpsPorts;\n    private final Set<Integer> httpsWithClientAuthPorts;\n    private final boolean isRevocationEnabled;\n    private final RevocationCheckMode revocationCheckMode;\n    private final boolean isRevocationSoftFailEnabled;\n    private final String keystoreServicePid;\n\n    public HttpServiceOptions(final Map<String, Object> properties) {\n        this.httpPorts = loadIntArrayProperty(HTTP_PORTS.get(properties));\n        this.httpsPorts = loadIntArrayProperty(HTTPS_PORTS.get(properties));\n        this.httpsWithClientAuthPorts = loadIntArrayProperty(HTTPS_CLIENT_AUTH_PORTS.get(properties));\n        this.isRevocationEnabled = REVOCATION_ENABLED.get(properties);\n        this.revocationCheckMode = RevocationCheckMode.valueOf(REVOCATION_MODE.get(properties));\n        this.isRevocationSoftFailEnabled = REVOCATION_SOFT_FAIL.get(properties);\n\n        this.keystoreServicePid = KEYSTORE_SERVICE.get(properties);\n    }\n\n    public Set<Integer> getHttpPorts() {\n        return this.httpPorts;\n    }\n\n    public Set<Integer> getHttpsPorts() {\n        return this.httpsPorts;\n    }\n\n    public Set<Integer> getHttpsClientAuthPorts() {\n        return this.httpsWithClientAuthPorts;\n    }\n\n    public boolean isRevocationEnabled() {\n        return this.isRevocationEnabled;\n    }\n\n    public RevocationCheckMode getRevocationCheckMode() {\n        return this.revocationCheckMode;\n    }\n\n    public String getKeystoreServicePid() {\n        return this.keystoreServicePid;\n    }\n\n    public boolean isRevocationSoftFailEnabled() {\n        return this.isRevocationSoftFailEnabled;\n    }\n\n    private static Set<Integer> loadIntArrayProperty(final Integer[] list) {\n        if (list == null) {\n            return Collections.emptySet();\n        }\n\n        final Set<Integer> result = new HashSet<>();\n\n        for (final Integer value : list) {\n            if (value != null) {\n                result.add(value);\n            }\n        }\n\n        return Collections.unmodifiableSet(result);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(httpPorts, httpsPorts, httpsWithClientAuthPorts, isRevocationEnabled,\n                isRevocationSoftFailEnabled, keystoreServicePid, revocationCheckMode);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof HttpServiceOptions)) {\n            return false;\n        }\n        HttpServiceOptions other = (HttpServiceOptions) obj;\n        return Objects.equals(httpPorts, other.httpPorts) && Objects.equals(httpsPorts, other.httpsPorts)\n                && Objects.equals(httpsWithClientAuthPorts, other.httpsWithClientAuthPorts)\n                && isRevocationEnabled == other.isRevocationEnabled\n                && isRevocationSoftFailEnabled == other.isRevocationSoftFailEnabled\n                && Objects.equals(keystoreServicePid, other.keystoreServicePid)\n                && revocationCheckMode == other.revocationCheckMode;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/src/main/java/org/eclipse/kura/http/server/manager/JettyServerHolder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.http.server.manager;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.security.KeyStore;\nimport java.security.cert.PKIXRevocationChecker;\nimport java.util.Comparator;\nimport java.util.EnumSet;\nimport java.util.EventListener;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\nimport java.util.zip.Deflater;\n\nimport org.eclipse.jetty.ee10.servlet.ErrorHandler;\nimport org.eclipse.jetty.ee10.servlet.ServletContextHandler;\nimport org.eclipse.jetty.ee10.servlet.ServletHolder;\nimport org.eclipse.jetty.ee10.servlet.SessionHandler;\nimport org.eclipse.jetty.http.HttpMethod;\nimport org.eclipse.jetty.http.HttpStatus;\nimport org.eclipse.jetty.server.ConnectionFactory;\nimport org.eclipse.jetty.server.ForwardedRequestCustomizer;\nimport org.eclipse.jetty.server.HttpConfiguration;\nimport org.eclipse.jetty.server.HttpConfiguration.Customizer;\nimport org.eclipse.jetty.server.HttpConnectionFactory;\nimport org.eclipse.jetty.server.SecureRequestCustomizer;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.ServerConnector;\nimport org.eclipse.jetty.server.SslConnectionFactory;\nimport org.eclipse.jetty.server.handler.gzip.GzipHandler;\nimport org.eclipse.jetty.session.DefaultSessionIdManager;\nimport org.eclipse.jetty.session.HouseKeeper;\nimport org.eclipse.jetty.util.compression.CompressionPool;\nimport org.eclipse.jetty.util.compression.DeflaterPool;\nimport org.eclipse.jetty.util.thread.QueuedThreadPool;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.http.server.manager.HttpServiceOptions.RevocationCheckMode;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.servlet.DispatcherType;\nimport jakarta.servlet.Filter;\nimport jakarta.servlet.FilterChain;\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.ServletRequest;\nimport jakarta.servlet.ServletResponse;\nimport jakarta.servlet.SessionCookieConfig;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\npublic class JettyServerHolder {\n\n    private static final Logger logger = LoggerFactory.getLogger(JettyServerHolder.class);\n\n    private DeflaterPool deflaterPool = new DeflaterPool(CompressionPool.DEFAULT_CAPACITY, Deflater.BEST_COMPRESSION,\n            true);\n\n    private final HttpServiceOptions options;\n    private final Server server;\n    private final File workDir;\n\n    public JettyServerHolder(final HttpServiceOptions options, final Optional<KeystoreService> keystoreService,\n            final HttpServlet httpServlet, final EventListener eventListener) {\n        this.options = options;\n\n        this.server = new Server(new QueuedThreadPool(200, 8));\n        this.server.setErrorHandler(new KuraErrorHandler());\n\n        final BundleContext context = FrameworkUtil.getBundle(JettyServerHolder.class).getBundleContext();\n        this.workDir = new File(context.getDataFile(\"\"), \"jettyWorkDir_\" + System.nanoTime());\n\n        this.workDir.mkdir();\n\n        for (int port : this.options.getHttpPorts()) {\n            ServerConnector httpConnector = createHttpConnector(port);\n            addConnector(httpConnector);\n        }\n\n        if (keystoreService.isPresent()) {\n            for (int port : this.options.getHttpsPorts()) {\n                try {\n                    ServerConnector httpsConnector = createHttpsConnector(keystoreService.get(), port, false);\n                    addConnector(httpsConnector);\n                } catch (Exception e) {\n                    logger.error(\"Unable to create https connector\", e);\n                }\n            }\n            for (int port : this.options.getHttpsClientAuthPorts()) {\n                try {\n                    ServerConnector httpsConnector = createHttpsConnector(keystoreService.get(), port, true);\n                    addConnector(httpsConnector);\n                } catch (Exception e) {\n                    logger.error(\"Unable to create https connector\", e);\n                }\n            }\n        }\n\n        ServletHolder holder = new ServletHolder(httpServlet);\n        holder.setAsyncSupported(true);\n        holder.setInitOrder(0);\n\n        ServletContextHandler httpContext = createServletContextHandler();\n        httpContext.addServlet(holder, \"/*\");\n        httpContext.addFilter(new BlockHttpMethods(EnumSet.of(HttpMethod.TRACE)), \"/*\",\n                EnumSet.of(DispatcherType.REQUEST));\n        httpContext.addEventListener(eventListener);\n\n        this.server.setHandler(httpContext);\n\n        DefaultSessionIdManager idMgr = new DefaultSessionIdManager(server);\n        server.addBean(idMgr, true);\n\n        HouseKeeper houseKeeper = new HouseKeeper();\n        houseKeeper.setSessionIdManager(idMgr);\n        idMgr.setSessionHouseKeeper(houseKeeper);\n        try {\n            server.start();\n            SessionHandler sessionManager = httpContext.getSessionHandler();\n            sessionManager.addEventListener(eventListener);\n        } catch (Exception e) {\n            logger.error(\"Unable to start Jetty server\", e);\n        }\n\n    }\n\n    private ServletContextHandler createServletContextHandler() {\n\n        ServletContextHandler servletContextHandler = new ServletContextHandler();\n        servletContextHandler.setClassLoader(JettyServerHolder.class.getClassLoader());\n        servletContextHandler.setContextPath(\"/\");\n\n        servletContextHandler.setAttribute(\"jakarta.servlet.context.tempdir\", this.workDir);\n        SessionHandler handler = new SessionHandler();\n        servletContextHandler.setSessionHandler(handler);\n\n        final GzipHandler gzipHandler = new GzipHandler();\n        gzipHandler.setDeflaterPool(this.deflaterPool);\n\n        servletContextHandler.insertHandler(gzipHandler);\n\n        servletContextHandler.setErrorHandler(new ErrorHandler() {\n\n            @Override\n            protected void writeErrorPage(HttpServletRequest request, Writer writer, int code, String message,\n                    boolean showStacks) throws IOException {\n                // do nothing\n            }\n\n        });\n\n        final SessionCookieConfig cookieConfig = servletContextHandler.getSessionHandler().getSessionCookieConfig();\n\n        cookieConfig.setHttpOnly(true);\n\n        return servletContextHandler;\n\n    }\n\n    private void addConnector(ServerConnector httpConnector) {\n        try {\n            httpConnector.open();\n            this.server.addConnector(httpConnector);\n        } catch (IOException e) {\n            logger.error(\"Unable to start a connector {}\", httpConnector, e);\n        }\n    }\n\n    public ServerConnector createHttpConnector(int port) {\n\n        HttpConfiguration httpConfiguration = new HttpConfiguration();\n\n        final ServerConnector newConnector = new ServerConnector(this.server,\n                new HttpConnectionFactory(httpConfiguration));\n\n        customizeConnector(newConnector, port);\n\n        return newConnector;\n    }\n\n    private void customizeConnector(final ServerConnector serverConnector, final int port) {\n        serverConnector.setPort(port);\n        for (final ConnectionFactory factory : serverConnector.getConnectionFactories()) {\n            if (!(factory instanceof HttpConnectionFactory)) {\n                continue;\n            }\n\n            ((HttpConnectionFactory) factory).getHttpConfiguration().setSendServerVersion(false);\n        }\n        addCustomizer(serverConnector, new ForwardedRequestCustomizer());\n    }\n\n    private void addCustomizer(final ServerConnector connector, final Customizer customizer) {\n        for (final ConnectionFactory factory : connector.getConnectionFactories()) {\n            if (!(factory instanceof HttpConnectionFactory)) {\n                continue;\n            }\n\n            final HttpConnectionFactory httpConnectionFactory = (HttpConnectionFactory) factory;\n\n            httpConnectionFactory.getHttpConfiguration().setSendServerVersion(false);\n\n            List<Customizer> customizers = httpConnectionFactory.getHttpConfiguration().getCustomizers();\n            if (customizers == null) {\n                customizers = new LinkedList<>();\n                httpConnectionFactory.getHttpConfiguration().setCustomizers(customizers);\n            }\n\n            customizers.add(customizer);\n        }\n    }\n\n    private static class BlockHttpMethods implements Filter {\n\n        private final Set<String> blockedMethods;\n\n        public BlockHttpMethods(Set<HttpMethod> methods) {\n            this.blockedMethods = methods.stream().map(m -> m.toString().toLowerCase()).collect(Collectors.toSet());\n        }\n\n        @Override\n        public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)\n                throws IOException, ServletException {\n            if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {\n                final HttpServletRequest httpReq = (HttpServletRequest) req;\n                final HttpServletResponse httpRes = (HttpServletResponse) res;\n\n                if (blockedMethods.contains(httpReq.getMethod().toLowerCase())) {\n                    httpRes.sendError(HttpStatus.METHOD_NOT_ALLOWED_405);\n                    return;\n                }\n\n            }\n\n            chain.doFilter(req, res);\n\n        }\n\n    }\n\n    private ServerConnector createHttpsConnector(final KeystoreService keystoreService, final int port,\n            final boolean enableClientAuth) throws KuraException {\n\n        final BaseSslContextFactory sslContextFactory;\n\n        if (enableClientAuth) {\n            sslContextFactory = new ClientAuthSslContextFactoryImpl(keystoreService, this.options.isRevocationEnabled(),\n                    getRevocationCheckerOptions());\n        } else {\n            sslContextFactory = new BaseSslContextFactory(keystoreService);\n        }\n\n        final KeyStore keystore = keystoreService.getKeyStore();\n\n        sslContextFactory.setKeyStore(keystore);\n        sslContextFactory.setTrustStore(keystore);\n\n        sslContextFactory.setProtocol(\"TLS\");\n        sslContextFactory.setTrustManagerFactoryAlgorithm(\"PKIX\");\n\n        sslContextFactory.setWantClientAuth(enableClientAuth);\n        sslContextFactory.setNeedClientAuth(enableClientAuth);\n\n        final HttpConfiguration httpsConfig = new HttpConfiguration();\n\n        httpsConfig.addCustomizer(new SecureRequestCustomizer(false));\n\n        final ServerConnector connector = new ServerConnector(server,\n                new SslConnectionFactory(sslContextFactory, \"http/1.1\"), new HttpConnectionFactory(httpsConfig));\n        customizeConnector(connector, port);\n\n        return connector;\n    }\n\n    private EnumSet<PKIXRevocationChecker.Option> getRevocationCheckerOptions() {\n        if (!this.options.isRevocationEnabled()) {\n            return EnumSet.noneOf(PKIXRevocationChecker.Option.class);\n        }\n\n        final EnumSet<PKIXRevocationChecker.Option> checkerOptions;\n\n        if (this.options.getRevocationCheckMode() == RevocationCheckMode.CRL_ONLY) {\n            checkerOptions = EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS,\n                    PKIXRevocationChecker.Option.NO_FALLBACK);\n        } else if (this.options.getRevocationCheckMode() == RevocationCheckMode.PREFER_CRL) {\n            checkerOptions = EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS);\n        } else {\n            checkerOptions = EnumSet.noneOf(PKIXRevocationChecker.Option.class);\n        }\n\n        if (this.options.isRevocationSoftFailEnabled()) {\n            checkerOptions.add(PKIXRevocationChecker.Option.SOFT_FAIL);\n        }\n\n        return checkerOptions;\n    }\n\n    public void stop() {\n        try {\n            this.server.stop();\n        } catch (Exception e) {\n            logger.warn(\"Unable to stop the Jetty server\", e);\n        }\n\n        try (final Stream<Path> stream = Files.walk(this.workDir.toPath())) {\n            stream.map(Path::toFile).sorted(Comparator.reverseOrder()).forEach(File::delete);\n        } catch (Exception e) {\n            logger.warn(\"Unable to cleanp jetty workdir\", e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.http.server.manager/src/main/java/org/eclipse/kura/http/server/manager/KuraErrorHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *     Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.http.server.manager;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Writer;\nimport java.nio.charset.Charset;\n\nimport org.eclipse.jetty.server.Request;\nimport org.eclipse.jetty.server.handler.ErrorHandler;\n\npublic class KuraErrorHandler extends ErrorHandler {\n\n    @Override\n    protected void writeErrorHtml(Request request, Writer writer, Charset charset, int code, String message,\n            Throwable cause, boolean showStacks) throws IOException {\n        // do nothing\n    }\n\n    @Override\n    protected void writeErrorPlain(Request request, PrintWriter writer, int code, String message, Throwable cause,\n            boolean showStacks) {\n        // do nothing\n    }\n\n    @Override\n    protected void writeErrorJson(Request request, PrintWriter writer, int code, String message, Throwable cause,\n            boolean showStacks) {\n        // do nothing\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Kura Json Marshaller utility\nBundle-SymbolicName: org.eclipse.kura.json.marshaller.unmarshaller.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: com.eclipsesource.json;version=\"0.9.5\",\n com.google.gson;version=\"2.7.0\",\n org.apache.commons.io.build;version=\"[2.18,3.0)\",\n org.apache.commons.io.input;version=\"[2.18,3.0)\",\n org.eclipse.kura;version=\"[1.4,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.configuration;version=\"[2.0,3.0)\",\n org.eclipse.kura.core.inventory.resources;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.keystore.util;version=\"[1.0,2.0)\",\n org.eclipse.kura.marshalling;version=\"[1.1,1.2)\",\n org.eclipse.kura.message;version=\"[1.2,2.0)\",\n org.eclipse.kura.system;version=\"[1.5,2.0)\",\n org.eclipse.kura.wire;version=\"[2.0,3.0)\",\n org.eclipse.kura.wire.graph;version=\"[1.0,2.0)\",\n org.slf4j;version=\"1.7.25\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nExport-Package: org.eclipse.kura.internal.json.marshaller.unmarshaller;version=\"1.1.0\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/OSGI-INF/JsonMarshallerUnmarshallerComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    \n   Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n    Eurotech\n    \n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" enabled=\"true\" immediate=\"false\" name=\"org.eclipse.kura.json.marshaller.unmarshaller.provider\">\n   <implementation class=\"org.eclipse.kura.internal.json.marshaller.unmarshaller.JsonMarshallUnmarshallImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.marshalling.Marshaller\"/>\n      <provide interface=\"org.eclipse.kura.marshalling.Unmarshaller\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.json.marshaller.unmarshaller.provider\"/>\n   <property name=\"kura.service.pid\" value=\"org.eclipse.kura.json.marshaller.unmarshaller.provider\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/build.properties",
    "content": "#\n#  Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html,\\\n               OSGI-INF/\nsrc.includes = about.html\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.json.marshaller.unmarshaller.provider</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.json.marshaller.unmarshaller.provider.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/JsonMarshallUnmarshallImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.Reader;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.commons.io.input.CharSequenceInputStream;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraIOException;\nimport org.eclipse.kura.core.inventory.resources.ContainerImage;\nimport org.eclipse.kura.core.inventory.resources.ContainerImages;\nimport org.eclipse.kura.core.inventory.resources.DockerContainer;\nimport org.eclipse.kura.core.inventory.resources.DockerContainers;\nimport org.eclipse.kura.core.inventory.resources.SystemBundleRef;\nimport org.eclipse.kura.core.inventory.resources.SystemBundles;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemResourcesInfo;\nimport org.eclipse.kura.core.keystore.util.EntryInfo;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.keystore.KeystoreEntryInfoMapper;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonDecoder;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonEncoder;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.system.JsonJavaContainerImagesMapper;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.system.JsonJavaDockerContainersMapper;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.system.JsonJavaSystemBundleRefMapper;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.system.JsonJavaSystemBundlesMapper;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.system.JsonJavaSystemDeploymentPackagesMapper;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.system.JsonJavaSystemPackagesMapper;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.system.JsonJavaSystemResourcesMapper;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.wiregraph.WireGraphJsonMarshallUnmarshallImpl;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.wire.graph.WireGraphConfiguration;\n\npublic class JsonMarshallUnmarshallImpl implements Marshaller, Unmarshaller {\n\n    @Override\n    public String marshal(Object object) throws KuraException {\n\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n        marshal(outStream, object);\n        return new String(outStream.toByteArray(), StandardCharsets.UTF_8);\n    }\n\n    @Override\n    public void marshal(OutputStream outStream, Object object) throws KuraIOException {\n        try {\n            OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n\n            if (object instanceof WireGraphConfiguration) {\n                WireGraphJsonMarshallUnmarshallImpl.marshalWireGraphConfiguration(writer,\n                        (WireGraphConfiguration) object);\n            } else if (object instanceof KuraPayload) {\n                CloudPayloadJsonEncoder.marshal(writer, (KuraPayload) object);\n            } else if (object instanceof SystemDeploymentPackages) {\n                JsonJavaSystemDeploymentPackagesMapper.marshal(writer, (SystemDeploymentPackages) object);\n            } else if (object instanceof SystemBundles) {\n                JsonJavaSystemBundlesMapper.marshal(writer, (SystemBundles) object);\n            } else if (object instanceof SystemPackages) {\n                JsonJavaSystemPackagesMapper.marshal(writer, (SystemPackages) object);\n            } else if (object instanceof DockerContainers) {\n                JsonJavaDockerContainersMapper.marshal(writer, (DockerContainers) object);\n            } else if (object instanceof ContainerImages) {\n                JsonJavaContainerImagesMapper.marshal(writer, (ContainerImages) object);\n            } else if (object instanceof SystemResourcesInfo) {\n                JsonJavaSystemResourcesMapper.marshal(writer, (SystemResourcesInfo) object);\n            }\n\n            writer.flush();\n\n        } catch (IOException ex) {\n            throw new KuraIOException(ex);\n        }\n    }\n\n    @Override\n    public <T> T unmarshal(String inputString, Class<T> clazz) throws KuraException {\n\n        CharSequenceInputStream stream = CharSequenceInputStream.builder().setCharSequence(inputString)\n                .setBufferSize(8192).setCharset(StandardCharsets.UTF_8).get();\n\n        return unmarshal(stream, clazz);\n    }\n\n    @Override\n    public <T> T unmarshal(InputStream inputStream, Class<T> clazz) throws KuraException {\n        try {\n\n            final Reader jsonReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);\n\n            if (clazz.equals(WireGraphConfiguration.class)) {\n                return (T) WireGraphJsonMarshallUnmarshallImpl.unmarshalToWireGraphConfiguration(jsonReader);\n            } else if (clazz.equals(KuraPayload.class)) {\n                return (T) CloudPayloadJsonDecoder.buildFromReader(jsonReader);\n            } else if (EntryInfo.class.isAssignableFrom(clazz)) {\n                return (T) KeystoreEntryInfoMapper.unmarshal(jsonReader, clazz);\n            } else if (clazz.equals(SystemBundleRef.class)) {\n                return (T) JsonJavaSystemBundleRefMapper.unmarshal(jsonReader);\n            } else if (clazz.equals(DockerContainer.class)) {\n                return (T) JsonJavaDockerContainersMapper.unmarshal(jsonReader);\n            } else if (clazz.equals(ContainerImage.class)) {\n                return (T) JsonJavaContainerImagesMapper.unmarshal(jsonReader);\n            }\n        } catch (IOException ex) {\n            throw new KuraIOException(ex);\n        }\n\n        throw new IllegalArgumentException(\"Invalid parameter!\");\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/keystore/KeystoreEntryInfoMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.keystore;\n\nimport java.io.Reader;\n\nimport org.eclipse.kura.core.keystore.util.CertificateInfo;\nimport org.eclipse.kura.core.keystore.util.CsrInfo;\nimport org.eclipse.kura.core.keystore.util.EntryInfo;\nimport org.eclipse.kura.core.keystore.util.KeyPairInfo;\nimport org.eclipse.kura.core.keystore.util.PrivateKeyInfo;\n\nimport com.google.gson.Gson;\nimport com.google.gson.JsonObject;\nimport com.google.gson.JsonParser;\n\npublic class KeystoreEntryInfoMapper {\n\n    private KeystoreEntryInfoMapper() {\n        // empty constructor\n    }\n\n    public static EntryInfo unmarshal(Reader jsonReader, Class<?> clazz) {\n        final Gson gson = new Gson();\n        final JsonObject json = JsonParser.parseReader(jsonReader).getAsJsonObject();\n\n        if (clazz.equals(CertificateInfo.class)) {\n            return gson.fromJson(json, CertificateInfo.class);\n        } else if (clazz.equals(KeyPairInfo.class)) {\n            return gson.fromJson(json, KeyPairInfo.class);\n        } else if (clazz.equals(PrivateKeyInfo.class)) {\n            return gson.fromJson(json, PrivateKeyInfo.class);\n        } else if (clazz.equals(CsrInfo.class)) {\n            return gson.fromJson(json, CsrInfo.class);\n        } else {\n            return gson.fromJson(json, EntryInfo.class);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/message/CloudPayloadJsonDecoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.message;\n\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.BODY;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.METRICS;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.POSITION;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.SENTON;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.ALTITUDE;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.HEADING;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.LATITUDE;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.LONGITUDE;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.PRECISION;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.SATELLITES;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.SPEED;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.STATUS;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\nimport java.util.Date;\n\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.JsonValue;\n\n/**\n * This class contains all the necessary methods that can be used to decode a Json payload into a {@link KuraPayload}.\n *\n */\npublic class CloudPayloadJsonDecoder {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudPayloadJsonDecoder.class);\n\n    private CloudPayloadJsonDecoder() {\n    }\n\n    /**\n     * Builds a {@link KuraPayload} from a Json string. The method will try to parse the received Json in order to\n     * fill the corresponding {@link KuraPayload} fields.\n     * If the mapping fails, the entire string, received as argument, will be placed in the body of the returned\n     * {@link KuraPayload}.\n     *\n     * @param jsonReader\n     *            a Json encoded as a String.\n     * @return a {@link KuraPayload} that directly maps the received array.\n     * @throws IOException\n     */\n    public static KuraPayload buildFromReader(Reader jsonReader) throws IOException {\n\n        final JsonObject json = Json.parse(jsonReader).asObject();\n\n        KuraPayload payload = new KuraPayload();\n\n        try {\n            for (JsonObject.Member member : json) {\n                String name = member.getName();\n                JsonValue value = member.getValue();\n                if (SENTON.value().equalsIgnoreCase(name)) {\n                    decodeTimestamp(payload, value);\n                } else if (BODY.value().equalsIgnoreCase(name)) {\n                    decodeBody(payload, value);\n                } else if (POSITION.value().equalsIgnoreCase(name) && value.isObject()) {\n                    decodePosition(payload, value.asObject());\n                } else if (METRICS.value().equalsIgnoreCase(name) && value.isObject()) {\n                    decodeMetric(payload, value.asObject());\n                } else {\n                    throw new IllegalArgumentException(String.format(\"Unrecognized value: %s\", name));\n                }\n            }\n        } catch (Exception e) {\n            logger.warn(\"Cannot parse Json\", e);\n            payload = new KuraPayload();\n            payload.setBody(json.toString().getBytes(StandardCharsets.UTF_8));\n        }\n        return payload;\n    }\n\n    private static void decodeTimestamp(KuraPayload payload, JsonValue timestampValue) {\n        if (timestampValue != null && timestampValue.isNumber()) {\n            long timestamp = timestampValue.asLong();\n            payload.setTimestamp(new Date(timestamp));\n        }\n    }\n\n    private static void decodeBody(KuraPayload payload, JsonValue body) {\n        if (body != null && body.isString()) {\n            payload.setBody(Base64.getDecoder().decode(body.asString()));\n        }\n    }\n\n    private static void decodePosition(KuraPayload payload, JsonObject positionObject) {\n        KuraPosition position = new KuraPosition();\n\n        payload.setPosition(position);\n        for (JsonObject.Member member : positionObject) {\n            String name = member.getName();\n            JsonValue value = member.getValue();\n            if (LATITUDE.value().equalsIgnoreCase(name) && value.isNumber()) {\n                position.setLatitude(value.asDouble());\n            } else if (LONGITUDE.value().equalsIgnoreCase(name) && value.isNumber()) {\n                position.setLongitude(value.asDouble());\n            } else if (ALTITUDE.value().equalsIgnoreCase(name) && value.isNumber()) {\n                position.setAltitude(value.asDouble());\n            } else if (HEADING.value().equalsIgnoreCase(name) && value.isNumber()) {\n                position.setHeading(value.asDouble());\n            } else if (PRECISION.value().equalsIgnoreCase(name) && value.isNumber()) {\n                position.setPrecision(value.asDouble());\n            } else if (SATELLITES.value().equalsIgnoreCase(name) && value.isNumber()) {\n                position.setSatellites(value.asInt());\n            } else if (SPEED.value().equalsIgnoreCase(name) && value.isNumber()) {\n                position.setSpeed(value.asDouble());\n            } else if (CloudPayloadJsonFields.CloudPayloadJsonPositionFields.TIMESTAMP.value().equalsIgnoreCase(name)\n                    && value.isNumber()) {\n                position.setTimestamp(new Date(value.asLong()));\n            } else if (STATUS.value().equalsIgnoreCase(name) && value.isNumber()) {\n                position.setStatus(value.asInt());\n            } else {\n                throw new IllegalArgumentException(String.format(\"Cannot parse position: %s.\", name));\n            }\n        }\n    }\n\n    // It doesn't properly decode characters, ints, floats and byte arrays - the supported format has no metadata\n    private static void decodeMetric(KuraPayload payload, JsonObject metricsObject) {\n        if (metricsObject == null) {\n            throw new IllegalArgumentException(\"Cannot parse metric object!\");\n        }\n\n        for (JsonObject.Member member : metricsObject) {\n            String name = member.getName();\n            JsonValue value = member.getValue();\n\n            Object javaValue;\n            if (value.isNumber()) {\n                try {\n                    javaValue = value.asLong();\n                } catch (Exception e) {\n                    javaValue = value.asDouble();\n                }\n            } else if (value.isBoolean()) {\n                javaValue = value.asBoolean();\n            } else if (value.isString()) {\n                javaValue = value.asString();\n            } else {\n                throw new IllegalArgumentException(String.format(\"Unparsable metric %s\", name));\n            }\n            payload.addMetric(name, javaValue);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/message/CloudPayloadJsonEncoder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.message;\n\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.BODY;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.METRICS;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.POSITION;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.SENTON;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.ALTITUDE;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.HEADING;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.LATITUDE;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.LONGITUDE;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.PRECISION;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.SATELLITES;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.SPEED;\nimport static org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonFields.CloudPayloadJsonPositionFields.STATUS;\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.Base64;\nimport java.util.Date;\n\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.WriterConfig;\n\n/**\n * This class provides a set of methods that allow to encode the {@link KuraPayload} into a byte[] message.\n *\n */\npublic class CloudPayloadJsonEncoder {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudPayloadJsonEncoder.class);\n\n    private CloudPayloadJsonEncoder() {\n    }\n\n    /**\n     * This static method takes a {@link KuraPayload} and converts it into a {@code String}\n     *\n     * @param kuraPayload\n     *            a {@link KuraPayload} object that has to be converted.\n     * @return a String that maps the received {@link KuraPayload} object\n     * @throws IOException\n     * @throws IllegalArgumentException\n     *             if the conversion fails\n     */\n    public static void marshal(Writer writer, KuraPayload kuraPayload) throws IOException {\n        JsonObject json = Json.object();\n\n        encodeTimestamp(kuraPayload, json);\n\n        encodePosition(kuraPayload, json);\n\n        encodeMetrics(kuraPayload, json);\n\n        encodeBody(kuraPayload, json);\n\n        json.writeTo(writer, WriterConfig.MINIMAL);\n    }\n\n    private static void encodeBody(KuraPayload kuraPayload, JsonObject json) {\n        byte[] body = kuraPayload.getBody();\n        if (body != null) {\n            json.add(BODY.value(), Base64.getEncoder().encodeToString(body));\n        }\n    }\n\n    private static void encodeMetrics(KuraPayload kuraPayload, JsonObject json) {\n        JsonObject jsonMetrics = Json.object();\n        for (String name : kuraPayload.metricNames()) {\n            Object object = kuraPayload.getMetric(name);\n            if (object instanceof Boolean) {\n                jsonMetrics.add(name, (Boolean) object);\n            } else if (object instanceof Double) {\n                encodeDoubleMetric(jsonMetrics, name, object);\n            } else if (object instanceof Float) {\n                encodeFloatMetric(jsonMetrics, name, object);\n            } else if (object instanceof Integer) {\n                jsonMetrics.add(name, (Integer) object);\n            } else if (object instanceof Long) {\n                jsonMetrics.add(name, (Long) object);\n            } else if (object instanceof String) {\n                jsonMetrics.add(name, (String) object);\n            } else if (object instanceof byte[]) {\n                jsonMetrics.add(name, Base64.getEncoder().encodeToString((byte[]) object));\n            } else {\n                throw new IllegalArgumentException(\"Cannot encode this value: \" + object.toString());\n            }\n        }\n        json.add(METRICS.value(), jsonMetrics);\n    }\n\n    private static void encodeFloatMetric(JsonObject jsonMetrics, String name, Object object) {\n        encodeFloatProperty(jsonMetrics, name, object, \"discarding non finite float metric: {}={}\");\n    }\n\n    private static void encodeDoubleMetric(JsonObject jsonMetrics, String name, Object object) {\n        encodeDoubleProperty(jsonMetrics, name, object, \"discarding non finite double metric: {}={}\");\n    }\n\n    private static void encodePosition(KuraPayload kuraPayload, JsonObject json) {\n        KuraPosition position = kuraPayload.getPosition();\n\n        if (position == null) {\n            return;\n        }\n\n        JsonObject jsonPosition = Json.object();\n\n        encodePositionDouble(jsonPosition, LATITUDE.value(), position.getLatitude());\n\n        encodePositionDouble(jsonPosition, LONGITUDE.value(), position.getLongitude());\n\n        encodePositionDouble(jsonPosition, ALTITUDE.value(), position.getAltitude());\n\n        encodePositionDouble(jsonPosition, HEADING.value(), position.getHeading());\n\n        encodePositionDouble(jsonPosition, PRECISION.value(), position.getPrecision());\n\n        if (position.getSatellites() != null) {\n            jsonPosition.add(SATELLITES.value(), position.getSatellites());\n        }\n\n        encodePositionDouble(jsonPosition, SPEED.value(), position.getSpeed());\n\n        if (position.getTimestamp() != null) {\n            jsonPosition.add(CloudPayloadJsonFields.CloudPayloadJsonPositionFields.TIMESTAMP.value(),\n                    position.getTimestamp().getTime());\n        }\n        if (position.getStatus() != null) {\n            jsonPosition.add(STATUS.value(), position.getStatus());\n        }\n\n        json.add(POSITION.value(), jsonPosition);\n    }\n\n    private static void encodePositionDouble(final JsonObject object, final String metric, final Double value) {\n        if (value != null) {\n            encodeDoubleProperty(object, metric, value, \"discarding non finite double metric: position.{}={}\");\n        }\n    }\n\n    private static void encodeTimestamp(KuraPayload kuraPayload, JsonObject json) {\n        Date timestamp = kuraPayload.getTimestamp();\n        if (timestamp != null) {\n            json.add(SENTON.value(), timestamp.getTime());\n        }\n    }\n\n    private static void encodeFloatProperty(JsonObject object, String name, Object value, String errorMessageFormat) {\n        final Float floatValue = (Float) value;\n\n        if (Float.isFinite(floatValue)) {\n            object.add(name, floatValue);\n\n        } else {\n            logger.warn(errorMessageFormat, name, floatValue);\n        }\n    }\n\n    private static void encodeDoubleProperty(JsonObject object, String name, Object value, String errorMessageFormat) {\n        final Double doubleValue = (Double) value;\n\n        if (Double.isFinite(doubleValue)) {\n            object.add(name, doubleValue);\n\n        } else {\n            logger.warn(errorMessageFormat, name, doubleValue);\n        }\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/message/CloudPayloadJsonFields.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.message;\n\n/**\n * Represents the encoded fields of a Json payload.\n *\n */\npublic enum CloudPayloadJsonFields {\n    SENTON(\"sentOn\"),\n    POSITION(\"position\"),\n    METRICS(\"metrics\"),\n    BODY(\"body\");\n\n    public enum CloudPayloadJsonPositionFields {\n        LATITUDE(\"latitude\"),\n        LONGITUDE(\"longitude\"),\n        ALTITUDE(\"altitude\"),\n        HEADING(\"heading\"),\n        PRECISION(\"precision\"),\n        SATELLITES(\"satellites\"),\n        SPEED(\"speed\"),\n        TIMESTAMP(\"timestamp\"),\n        STATUS(\"status\");\n\n        private String value;\n\n        private CloudPayloadJsonPositionFields(final String value) {\n            this.value = value;\n        }\n\n        /**\n         * Returns the string representation of the constant\n         *\n         * @return the string value\n         */\n        public String value() {\n            return this.value;\n        }\n    }\n\n    private String value;\n\n    private CloudPayloadJsonFields(final String value) {\n        this.value = value;\n    }\n\n    /**\n     * Returns the string representation of the constant\n     *\n     * @return the string value\n     */\n    public String value() {\n        return this.value;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/system/JsonJavaContainerImagesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.system;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.util.Optional;\n\nimport org.eclipse.kura.core.inventory.resources.ContainerImage;\nimport org.eclipse.kura.core.inventory.resources.ContainerImages;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.WriterConfig;\n\npublic class JsonJavaContainerImagesMapper {\n\n    // Expected resulting json:\n    // {\n    // \"images\": [\n    // {\n    // \"name\" : \"rfkill\",\n    // \"version\": \"latest\",\n    // type\": \"CONTAINER_IMAGE\",\n    // }\n    // ]\n    // }\n\n    private static final String SYSTEM_IMAGES = \"images\";\n    private static final String SYSTEM_IMAGES_IMAGE_NAME = \"name\";\n    private static final String SYSTEM_IMAGES_IMAGE_VERSION = \"version\";\n    private static final String SYSTEM_IMAGES_IMAGE_TYPE = \"type\";\n\n    private JsonJavaContainerImagesMapper() {\n        // empty constructor\n    }\n\n    public static ContainerImage unmarshal(final Reader jsonReader) throws IOException {\n        final JsonObject object = Json.parse(jsonReader).asObject();\n\n        final String name = getStringValue(object, SYSTEM_IMAGES_IMAGE_NAME);\n        final String version = getStringValue(object, SYSTEM_IMAGES_IMAGE_VERSION);\n\n        return new ContainerImage(name, version);\n    }\n\n    public static void marshal(Writer writer, ContainerImages contianerImages) throws IOException {\n        JsonObject json = Json.object();\n        JsonArray images = new JsonArray();\n        contianerImages.getContainerImages().stream().forEach(p -> images.add(getJsonPackage(p)));\n        json.add(SYSTEM_IMAGES, images);\n\n        json.writeTo(writer, WriterConfig.MINIMAL);\n    }\n\n    private static JsonObject getJsonPackage(ContainerImage p) {\n        JsonObject jsonObject = new JsonObject();\n        jsonObject.add(SYSTEM_IMAGES_IMAGE_NAME, p.getName());\n        jsonObject.add(SYSTEM_IMAGES_IMAGE_VERSION, p.getVersion());\n        jsonObject.add(SYSTEM_IMAGES_IMAGE_TYPE, p.getTypeString());\n        return jsonObject;\n    }\n\n    private static Optional<String> getOptionalStringValue(final JsonObject object, final String name) {\n        return Optional.ofNullable(object.get(name)).map(s -> {\n            if (s.isString()) {\n                return s.asString();\n            } else {\n                throw new IllegalArgumentException(name + \" must be a string\");\n            }\n        });\n    }\n\n    private static String getStringValue(final JsonObject object, final String name) {\n        return getOptionalStringValue(object, name)\n                .orElseThrow(() -> new IllegalArgumentException(name + \" is required\"));\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/system/JsonJavaDockerContainersMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.system;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.util.Optional;\n\nimport org.eclipse.kura.core.inventory.resources.DockerContainer;\nimport org.eclipse.kura.core.inventory.resources.DockerContainers;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.WriterConfig;\n\npublic class JsonJavaDockerContainersMapper {\n\n    // Expected resulting json:\n    // {\n    // \"containers\": [\n    // {\n    // \"name\" : \"rfkill\",\n    // \"version\": \"nginx:latest\",\n    // \"type\": \"DOCKER\",\n    // \"state\" : \"active\",\n    // }\n    // ]\n    // }\n\n    private static final String SYSTEM_CONTAINERS = \"containers\";\n    private static final String SYSTEM_CONTAINERS_CONTAINER_NAME = \"name\";\n    private static final String SYSTEM_CONTAINERS_CONTAINER_VERSION = \"version\";\n    private static final String SYSTEM_CONTAINERS_CONTAINER_TYPE = \"type\";\n    private static final String SYSTEM_CONTAINERS_CONTAINER_STATE = \"state\";\n\n    private JsonJavaDockerContainersMapper() {\n        // empty constructor\n    }\n\n    public static DockerContainer unmarshal(final Reader jsonReader) throws IOException {\n        final JsonObject object = Json.parse(jsonReader).asObject();\n\n        final String name = getStringValue(object, SYSTEM_CONTAINERS_CONTAINER_NAME);\n        final String version = getStringValue(object, SYSTEM_CONTAINERS_CONTAINER_VERSION);\n\n        return new DockerContainer(name, version);\n\n    }\n\n    public static void marshal(Writer writer, DockerContainers dockerContainers) throws IOException {\n        JsonObject json = Json.object();\n        JsonArray containers = new JsonArray();\n        dockerContainers.getDockerContainers().stream().forEach(p -> containers.add(getJsonPackage(p)));\n        json.add(SYSTEM_CONTAINERS, containers);\n\n        json.writeTo(writer, WriterConfig.MINIMAL);\n    }\n\n    private static JsonObject getJsonPackage(DockerContainer p) {\n        JsonObject jsonObject = new JsonObject();\n        jsonObject.add(SYSTEM_CONTAINERS_CONTAINER_NAME, p.getName());\n        jsonObject.add(SYSTEM_CONTAINERS_CONTAINER_VERSION, p.getVersion());\n        jsonObject.add(SYSTEM_CONTAINERS_CONTAINER_TYPE, p.getTypeString());\n        jsonObject.add(SYSTEM_CONTAINERS_CONTAINER_STATE, p.getFrameworkContainerState());\n        return jsonObject;\n    }\n\n    private static Optional<String> getOptionalStringValue(final JsonObject object, final String name) {\n        return Optional.ofNullable(object.get(name)).map(s -> {\n            if (s.isString()) {\n                return s.asString();\n            } else {\n                throw new IllegalArgumentException(name + \" must be a string\");\n            }\n        });\n    }\n\n    private static String getStringValue(final JsonObject object, final String name) {\n        return getOptionalStringValue(object, name)\n                .orElseThrow(() -> new IllegalArgumentException(name + \" is required\"));\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/system/JsonJavaSystemBundleRefMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.system;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.util.Optional;\n\nimport org.eclipse.kura.core.inventory.resources.SystemBundleRef;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonObject;\n\npublic class JsonJavaSystemBundleRefMapper {\n\n    private JsonJavaSystemBundleRefMapper() {\n    }\n\n    private static final String NAME_KEY = \"name\";\n    private static final String VERSION_KEY = \"version\";\n\n    public static SystemBundleRef unmarshal(final Reader jsonReader) throws IOException {\n        final JsonObject object = Json.parse(jsonReader).asObject();\n\n        final String name = getStringValue(object, NAME_KEY);\n        final Optional<String> version = getOptionalStringValue(object, VERSION_KEY);\n\n        return new SystemBundleRef(name, version);\n    }\n\n    private static Optional<String> getOptionalStringValue(final JsonObject object, final String name) {\n        return Optional.ofNullable(object.get(name)).map(s -> {\n            if (s.isString()) {\n                return s.asString();\n            } else {\n                throw new IllegalArgumentException(name + \" must be a string\");\n            }\n        });\n    }\n\n    private static String getStringValue(final JsonObject object, final String name) {\n        return getOptionalStringValue(object, name)\n                .orElseThrow(() -> new IllegalArgumentException(name + \" is required\"));\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/system/JsonJavaSystemBundlesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.system;\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.Arrays;\n\nimport org.eclipse.kura.core.inventory.resources.SystemBundle;\nimport org.eclipse.kura.core.inventory.resources.SystemBundles;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.WriterConfig;\n\npublic class JsonJavaSystemBundlesMapper {\n\n    // Expected resulting json:\n    // {\n    // \"bundles\": [\n    // {\n    // \"name\" : \"org.eclipse.osgi\",\n    // \"version\": \"3.8.1.v20120830-144521\",\n    // \"id\": \"0\",\n    // \"state\" : \"ACTIVE\"\n    // }\n    // ]\n    // }\n\n    private static final String SYSTEM_BUNDLES = \"bundles\";\n    private static final String SYSTEM_BUNDLES_NAME = \"name\";\n    private static final String SYSTEM_BUNDLES_VERSION = \"version\";\n    private static final String SYSTEM_BUNDLES_ID = \"id\";\n    private static final String SYSTEM_BUNDLES_STATE = \"state\";\n    private static final String SYSTEM_BUNDLES_SIGNED = \"signed\";\n\n    private JsonJavaSystemBundlesMapper() {\n        // empty constructor\n    }\n\n    public static void marshal(Writer writer, SystemBundles systemBundles) throws IOException {\n        JsonObject json = Json.object();\n        JsonArray bundles = new JsonArray();\n        Arrays.asList(systemBundles.getBundles()).stream().forEach(sb -> bundles.add(getJsonBundle(sb)));\n        json.add(SYSTEM_BUNDLES, bundles);\n\n        json.writeTo(writer, WriterConfig.MINIMAL);\n    }\n\n    private static JsonObject getJsonBundle(SystemBundle sb) {\n        JsonObject jsonObject = new JsonObject();\n        jsonObject.add(SYSTEM_BUNDLES_NAME, sb.getName());\n        jsonObject.add(SYSTEM_BUNDLES_VERSION, sb.getVersion());\n        jsonObject.add(SYSTEM_BUNDLES_ID, sb.getId());\n        jsonObject.add(SYSTEM_BUNDLES_STATE, sb.getState());\n        jsonObject.add(SYSTEM_BUNDLES_SIGNED, sb.isSigned());\n        return jsonObject;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/system/JsonJavaSystemDeploymentPackagesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.system;\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.Arrays;\n\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.WriterConfig;\n\npublic class JsonJavaSystemDeploymentPackagesMapper {\n\n    // Expected resulting json:\n    // {\n    // \"packages\": [\n    // {\n    // \"name\" : \"org.eclipse.kura.demo.heater\",\n    // \"version\": \"1.2.0.qualifier\",\n    // \"bundles\": [\n    // {\n    // \"name\" : \"org.eclipse.kura.demo.heater\",\n    // \"version\" : \"1.0.1\"\n    // \"id\" : \"1\",\n    // \"state\" : \"ACTIVE\"\n    // }\n    // ]\n    // }\n    // ]\n    // }\n\n    private static final String DEPLOYMENT_PACKAGES = \"deploymentPackages\";\n    private static final String DP_NAME = \"name\";\n    private static final String DP_VERSION = \"version\";\n    private static final String DP_BUNDLES = \"bundles\";\n    private static final String DP_ID = \"id\";\n    private static final String DP_STATE = \"state\";\n    private static final String DP_SIGNED = \"signed\";\n\n    private JsonJavaSystemDeploymentPackagesMapper() {\n        // empty constructor\n    }\n\n    public static void marshal(Writer writer, SystemDeploymentPackages systemDPs) throws IOException {\n        JsonObject json = Json.object();\n        JsonArray dps = new JsonArray();\n        Arrays.asList(systemDPs.getDeploymentPackages()).stream().forEach(dp -> dps.add(getJsonDP(dp)));\n        json.add(DEPLOYMENT_PACKAGES, dps);\n\n        json.writeTo(writer, WriterConfig.MINIMAL);\n    }\n\n    private static JsonObject getJsonDP(SystemDeploymentPackage dp) {\n        JsonArray bundles = new JsonArray();\n        Arrays.asList(dp.getBundleInfos()).stream().forEach(b -> {\n            JsonObject jsonBundle = new JsonObject();\n            jsonBundle.add(DP_NAME, b.getName());\n            jsonBundle.add(DP_VERSION, b.getVersion());\n            jsonBundle.add(DP_ID, b.getId());\n            jsonBundle.add(DP_STATE, b.getState());\n            jsonBundle.add(DP_SIGNED, b.isSigned());\n            bundles.add(jsonBundle);\n        });\n        JsonObject jsonObject = new JsonObject();\n        jsonObject.add(DP_NAME, dp.getName());\n        jsonObject.add(DP_VERSION, dp.getVersion());\n        jsonObject.add(DP_BUNDLES, bundles);\n        jsonObject.add(DP_SIGNED, dp.isSigned());\n        return jsonObject;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/system/JsonJavaSystemPackagesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.system;\n\nimport java.io.IOException;\nimport java.io.Writer;\n\nimport org.eclipse.kura.core.inventory.resources.SystemPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemPackages;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.WriterConfig;\n\npublic class JsonJavaSystemPackagesMapper {\n\n    // Expected resulting json:\n    // {\n    // \"systemPackages\": [\n    // {\n    // \"name\" : \"rfkill\",\n    // \"version\": \"2.33.1-0.1\",\n    // type\": \"DEB\",\n    // }\n    // ]\n    // }\n\n    private static final String SYSTEM_PACKAGES = \"systemPackages\";\n    private static final String SYSTEM_PACKAGES_PACKAGE_NAME = \"name\";\n    private static final String SYSTEM_PACKAGES_PACKAGE_VERSION = \"version\";\n    private static final String SYSTEM_PACKAGES_PACKAGE_TYPE = \"type\";\n\n    private JsonJavaSystemPackagesMapper() {\n        // empty constructor\n    }\n\n    public static void marshal(Writer writer, SystemPackages systemPackages) throws IOException {\n        JsonObject json = Json.object();\n        JsonArray packages = new JsonArray();\n        systemPackages.getSystemPackages().stream().forEach(p -> packages.add(getJsonPackage(p)));\n        json.add(SYSTEM_PACKAGES, packages);\n\n        json.writeTo(writer, WriterConfig.MINIMAL);\n    }\n\n    private static JsonObject getJsonPackage(SystemPackage p) {\n        JsonObject jsonObject = new JsonObject();\n        jsonObject.add(SYSTEM_PACKAGES_PACKAGE_NAME, p.getName());\n        jsonObject.add(SYSTEM_PACKAGES_PACKAGE_VERSION, p.getVersion());\n        jsonObject.add(SYSTEM_PACKAGES_PACKAGE_TYPE, p.getTypeString());\n        return jsonObject;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/system/JsonJavaSystemResourcesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.system;\n\nimport java.io.IOException;\nimport java.io.Writer;\n\nimport org.eclipse.kura.core.inventory.resources.SystemResourcesInfo;\nimport org.eclipse.kura.system.SystemResourceInfo;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.WriterConfig;\n\npublic class JsonJavaSystemResourcesMapper {\n\n    // Expected resulting json:\n    // {\n    // \"inventory\": [\n    // {\n    // \"name\" : \"rfkill\",\n    // \"version\": \"2.33.1-0.1\",\n    // type\": \"DEB\",\n    // }\n    // ]\n    // }\n\n    private static final String INVENTORY = \"inventory\";\n    private static final String RESOURCE_NAME = \"name\";\n    private static final String RESOURCE_VERSION = \"version\";\n    private static final String RESOURCE_TYPE = \"type\";\n\n    private JsonJavaSystemResourcesMapper() {\n        // empty constructor\n    }\n\n    public static void marshal(Writer writer, SystemResourcesInfo systemResourcesInfo) throws IOException {\n        JsonObject json = Json.object();\n        JsonArray resources = new JsonArray();\n        systemResourcesInfo.getSystemResources().stream().forEach(sri -> resources.add(getJsonSystemResource(sri)));\n        json.add(INVENTORY, resources);\n\n        json.writeTo(writer, WriterConfig.MINIMAL);\n    }\n\n    private static JsonObject getJsonSystemResource(SystemResourceInfo sri) {\n        JsonObject jsonObject = new JsonObject();\n        jsonObject.add(RESOURCE_NAME, sri.getName());\n        jsonObject.add(RESOURCE_VERSION, sri.getVersion());\n        jsonObject.add(RESOURCE_TYPE, sri.getTypeString());\n        return jsonObject;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.json.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/wiregraph/WireGraphJsonMarshallUnmarshallImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.wiregraph;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.Writer;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.function.BiConsumer;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.core.configuration.ComponentConfigurationImpl;\nimport org.eclipse.kura.wire.graph.MultiportWireConfiguration;\nimport org.eclipse.kura.wire.graph.WireComponentConfiguration;\nimport org.eclipse.kura.wire.graph.WireGraphConfiguration;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.JsonValue;\nimport com.eclipsesource.json.WriterConfig;\n\n@SuppressWarnings(\"checkstyle:hideUtilityClassConstructor\")\npublic class WireGraphJsonMarshallUnmarshallImpl {\n\n    private static final String RENDERING_PROPERTIES_KEY = \"renderingProperties\";\n    private static final String OUTPUT_PORT_COUNT_KEY = \"outputPortCount\";\n    private static final String INPUT_PORT_COUNT_KEY = \"inputPortCount\";\n    private static final String PID_KEY = \"pid\";\n    private static final String OUTPUT_PORT_NAMES_KEY = \"outputPortNames\";\n    private static final String INPUT_PORT_NAMES_KEY = \"inputPortNames\";\n    private static final String POSITION_KEY = \"position\";\n    private static final String RECEIVER_PID_KEY = \"receiver\";\n    private static final String RECEIVER_PORT_KEY = \"receiverPort\";\n    private static final String EMITTER_PID_KEY = \"emitter\";\n    private static final String EMITTER_PORT_KEY = \"emitterPort\";\n    private static final String WIRES_KEY = \"wires\";\n    private static final String COMPONENTS_KEY = \"components\";\n\n    public WireGraphJsonMarshallUnmarshallImpl() {\n        // Public for testing purposes\n    }\n\n    public static void marshalWireGraphConfiguration(Writer writer, WireGraphConfiguration graphConfiguration)\n            throws IOException {\n        JsonArray wireConfigurationJson = marshalWireConfigurationList(graphConfiguration.getWireConfigurations());\n        JsonArray wireComponentConfigurationJson = marshalWireComponentConfigurationList(\n                graphConfiguration.getWireComponentConfigurations());\n\n        JsonObject wireGraphConfiguration = new JsonObject();\n        wireGraphConfiguration.add(COMPONENTS_KEY, wireComponentConfigurationJson);\n        wireGraphConfiguration.add(WIRES_KEY, wireConfigurationJson);\n\n        wireGraphConfiguration.writeTo(writer, WriterConfig.MINIMAL);\n    }\n\n    private static JsonObject marshalWireConfiguration(MultiportWireConfiguration wireConfig) {\n        JsonObject result = new JsonObject();\n        result.add(EMITTER_PID_KEY, wireConfig.getEmitterPid());\n        result.add(EMITTER_PORT_KEY, wireConfig.getEmitterPort());\n        result.add(RECEIVER_PID_KEY, wireConfig.getReceiverPid());\n        result.add(RECEIVER_PORT_KEY, wireConfig.getReceiverPort());\n        return result;\n    }\n\n    private static JsonArray marshalWireConfigurationList(List<MultiportWireConfiguration> wireConfigurations) {\n        JsonArray value = new JsonArray();\n        for (MultiportWireConfiguration wireConfiguration : wireConfigurations) {\n            value.add(marshalWireConfiguration(wireConfiguration));\n        }\n\n        return value;\n    }\n\n    private static JsonArray marshalWireComponentConfigurationList(\n            List<WireComponentConfiguration> wireComponentConfigurations) {\n\n        JsonArray value = new JsonArray();\n        for (WireComponentConfiguration wireComponentConfiguration : wireComponentConfigurations) {\n            String pid = wireComponentConfiguration.getConfiguration().getPid();\n            value.add(marshalComponentProperties(pid, wireComponentConfiguration.getProperties()));\n        }\n\n        return value;\n    }\n\n    private static JsonObject marshalComponentProperties(String pid, Map<String, Object> componentProperties) {\n        JsonObject result = new JsonObject();\n\n        JsonObject resultElems = new JsonObject();\n\n        JsonObject position = marshalPosition(componentProperties);\n        resultElems.add(POSITION_KEY, position);\n\n        JsonObject inputPortNames = marshalInputPortNames(componentProperties);\n        resultElems.add(INPUT_PORT_NAMES_KEY, inputPortNames);\n\n        JsonObject outputPortNames = marshalOutputPortNames(componentProperties);\n        resultElems.add(OUTPUT_PORT_NAMES_KEY, outputPortNames);\n\n        result.add(PID_KEY, pid);\n\n        addPropertyChecked(componentProperties, INPUT_PORT_COUNT_KEY, INPUT_PORT_COUNT_KEY, Integer.class, result::add);\n        addPropertyChecked(componentProperties, OUTPUT_PORT_COUNT_KEY, OUTPUT_PORT_COUNT_KEY, Integer.class,\n                result::add);\n\n        result.add(RENDERING_PROPERTIES_KEY, resultElems);\n\n        return result;\n    }\n\n    private static JsonObject marshalPosition(Map<String, Object> componentProperties) {\n        JsonObject positionElems = new JsonObject();\n\n        addPropertyChecked(componentProperties, \"x\", \"position.x\", Float.class, positionElems::add);\n        addPropertyChecked(componentProperties, \"y\", \"position.y\", Float.class, positionElems::add);\n\n        return positionElems;\n    }\n\n    private static JsonObject marshalInputPortNames(Map<String, Object> componentProperties) {\n\n        JsonObject inputPortElems = new JsonObject();\n        for (Entry<String, Object> mapEntry : componentProperties.entrySet()) {\n            if (mapEntry.getKey().startsWith(INPUT_PORT_NAMES_KEY) && mapEntry.getValue() instanceof String) {\n                String portNumber = mapEntry.getKey().split(\"\\\\.\")[1];\n                inputPortElems.add(portNumber, (String) mapEntry.getValue());\n            }\n        }\n\n        return inputPortElems;\n    }\n\n    private static JsonObject marshalOutputPortNames(Map<String, Object> componentProperties) {\n\n        JsonObject outputPortElems = new JsonObject();\n        for (Entry<String, Object> mapEntry : componentProperties.entrySet()) {\n            if (mapEntry.getKey().startsWith(OUTPUT_PORT_NAMES_KEY) && mapEntry.getValue() instanceof String) {\n                String portNumber = mapEntry.getKey().split(\"\\\\.\")[1];\n                outputPortElems.add(portNumber, (String) mapEntry.getValue());\n            }\n        }\n\n        return outputPortElems;\n    }\n\n    public static WireGraphConfiguration unmarshalToWireGraphConfiguration(Reader jsonReader) throws IOException {\n\n        List<WireComponentConfiguration> wireCompConfigList = new ArrayList<>();\n        List<MultiportWireConfiguration> wireConfigList = new ArrayList<>();\n\n        JsonObject json = Json.parse(jsonReader).asObject();\n\n        for (JsonObject.Member member : json) {\n            String name = member.getName();\n            JsonValue value = member.getValue();\n            if (WIRES_KEY.equalsIgnoreCase(name) && value.isArray()) {\n                wireConfigList = unmarshalWireConfiguration(value.asArray());\n            } else if (COMPONENTS_KEY.equalsIgnoreCase(name) && value.isArray()) {\n                wireCompConfigList = unmarshalWireComponentConfiguration(value.asArray());\n            }\n        }\n        return new WireGraphConfiguration(wireCompConfigList, wireConfigList);\n    }\n\n    private static List<MultiportWireConfiguration> unmarshalWireConfiguration(JsonArray array) {\n        List<MultiportWireConfiguration> wireConfigurationList = new ArrayList<>();\n\n        array.forEach(jsonWireConfigValue -> {\n            JsonObject jsonWireConfig = jsonWireConfigValue.asObject();\n\n            String emitterPid = null;\n            String receiverPid = null;\n            int emitterPort = 0;\n            int receiverPort = 0;\n\n            for (JsonObject.Member member : jsonWireConfig) {\n                String name = member.getName();\n                JsonValue value = member.getValue();\n                if (EMITTER_PID_KEY.equalsIgnoreCase(name) && value.isString()) {\n                    emitterPid = value.asString();\n                } else if (RECEIVER_PID_KEY.equalsIgnoreCase(name) && value.isString()) {\n                    receiverPid = value.asString();\n                } else if (EMITTER_PORT_KEY.equalsIgnoreCase(name) && value.isNumber()) {\n                    emitterPort = value.asInt();\n                } else if (RECEIVER_PORT_KEY.equalsIgnoreCase(name) && value.isNumber()) {\n                    receiverPort = value.asInt();\n                }\n\n            }\n\n            if (emitterPid != null && receiverPid != null) {\n                MultiportWireConfiguration wireConfiguration = new MultiportWireConfiguration(emitterPid, receiverPid,\n                        emitterPort, receiverPort);\n                wireConfigurationList.add(wireConfiguration);\n            }\n        });\n\n        return wireConfigurationList;\n    }\n\n    private static List<WireComponentConfiguration> unmarshalWireComponentConfiguration(JsonArray array) {\n        List<WireComponentConfiguration> wireComponentConfigurationList = new ArrayList<>();\n\n        Iterator<JsonValue> jsonIterator = array.iterator();\n        while (jsonIterator.hasNext()) {\n            Map<String, Object> properties = new HashMap<>();\n            String componentPid = null;\n            JsonObject jsonWireComponentConfiguration = jsonIterator.next().asObject();\n\n            for (JsonObject.Member member : jsonWireComponentConfiguration) {\n                String name = member.getName();\n                JsonValue value = member.getValue();\n                if (INPUT_PORT_COUNT_KEY.equalsIgnoreCase(name) && value.isNumber()) {\n                    properties.put(name, value.asInt());\n                } else if (OUTPUT_PORT_COUNT_KEY.equalsIgnoreCase(name) && value.isNumber()) {\n                    properties.put(name, value.asInt());\n                } else if (RENDERING_PROPERTIES_KEY.equalsIgnoreCase(name) && value.isObject()) {\n                    Map<String, Object> renderingProperties = unmarshalRenderingProperties(value.asObject());\n                    properties.putAll(renderingProperties);\n                } else if (PID_KEY.equalsIgnoreCase(name) && value.isString()) {\n                    componentPid = value.asString();\n                }\n            }\n\n            if (componentPid != null) {\n                ComponentConfiguration componentConfiguration = new ComponentConfigurationImpl(componentPid, null,\n                        null);\n\n                WireComponentConfiguration wireComponentConfiguration = new WireComponentConfiguration(\n                        componentConfiguration, properties);\n                wireComponentConfigurationList.add(wireComponentConfiguration);\n            }\n        }\n\n        return wireComponentConfigurationList;\n    }\n\n    private static Map<String, Object> unmarshalRenderingProperties(JsonObject jsonRenderingProps) {\n        Map<String, Object> renderingProps = new HashMap<>();\n\n        for (JsonObject.Member member : jsonRenderingProps) {\n            String name = member.getName();\n            JsonValue value = member.getValue();\n            if (POSITION_KEY.equalsIgnoreCase(name) && value.isObject()) {\n                Map<String, Object> positionMap = unmarshalPosition(value.asObject());\n                renderingProps.putAll(positionMap);\n            } else if (INPUT_PORT_NAMES_KEY.equalsIgnoreCase(name) && value.isObject()) {\n                Map<String, Object> inputPortNamesMap = unmarshalInputPortNames(value.asObject());\n                renderingProps.putAll(inputPortNamesMap);\n            } else if (OUTPUT_PORT_NAMES_KEY.equalsIgnoreCase(name) && value.isObject()) {\n                Map<String, Object> outputPortNamesMap = unmarshalOutputPortNames(value.asObject());\n                renderingProps.putAll(outputPortNamesMap);\n            }\n        }\n\n        return renderingProps;\n    }\n\n    private static Map<String, Object> unmarshalInputPortNames(JsonObject jsonInputPortNames) {\n        Map<String, Object> inputPortNamesMap = new HashMap<>();\n\n        for (JsonObject.Member member : jsonInputPortNames) {\n            String name = member.getName();\n            JsonValue value = member.getValue();\n            if (value.isString()) {\n                inputPortNamesMap.put(INPUT_PORT_NAMES_KEY + \".\" + name, value.asString());\n            }\n        }\n\n        return inputPortNamesMap;\n    }\n\n    private static Map<String, Object> unmarshalOutputPortNames(JsonObject jsonOutputPortNames) {\n        Map<String, Object> outputPortNamesMap = new HashMap<>();\n\n        for (JsonObject.Member member : jsonOutputPortNames) {\n            String name = member.getName();\n            JsonValue value = member.getValue();\n            if (value.isString()) {\n                outputPortNamesMap.put(OUTPUT_PORT_NAMES_KEY + \".\" + name, value.asString());\n            }\n        }\n\n        return outputPortNamesMap;\n    }\n\n    private static Map<String, Object> unmarshalPosition(JsonObject jsonPositionPros) {\n        Map<String, Object> positionMap = new HashMap<>();\n\n        for (JsonObject.Member member : jsonPositionPros) {\n            String name = member.getName();\n            JsonValue value = member.getValue();\n            if (\"x\".equalsIgnoreCase(name) && value.isNumber()) {\n                positionMap.put(\"position.x\", value.asFloat());\n            } else if (\"y\".equalsIgnoreCase(name) && value.isNumber()) {\n                positionMap.put(\"position.y\", value.asFloat());\n            }\n        }\n\n        return positionMap;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static <T> void addPropertyChecked(final Map<String, Object> componentProperties,\n            final String jsonPropertyKey, final String componentPropertyKey, final Class<T> expectedClass,\n            final BiConsumer<String, T> adder) {\n        final Object property = componentProperties.get(componentPropertyKey);\n\n        if (!(expectedClass.isInstance(property))) {\n            return;\n        }\n\n        adder.accept(jsonPropertyKey, (T) property);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.jul.to.slf4j.configuration/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Kura Configurator for jul-to-slf4j\nBundle-SymbolicName: org.eclipse.kura.jul.to.slf4j.configuration;singleton:=true\nBundle-Version: 1.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nBundle-Activator: org.eclipse.kura.jul.to.slf4j.configuration.Activator\nImport-Package: org.osgi.framework;version=\"1.10.0\",\n org.slf4j.bridge;version=\"1.7.21\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.jul.to.slf4j.configuration/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.jul.to.slf4j.configuration/build.properties",
    "content": "#\n#  Copyright (c) 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .\n"
  },
  {
    "path": "kura/org.eclipse.kura.jul.to.slf4j.configuration/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.jul.to.slf4j.configuration</artifactId>\n    <version>1.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.jul.to.slf4j.configuration/src/main/java/org/eclipse/kura/jul/to/slf4j/configuration/Activator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.jul.to.slf4j.configuration;\n\nimport org.osgi.framework.BundleActivator;\nimport org.osgi.framework.BundleContext;\nimport org.slf4j.bridge.SLF4JBridgeHandler;\n\npublic class Activator implements BundleActivator {\n\n    @Override\n    public void start(BundleContext context) throws Exception {\n        SLF4JBridgeHandler.removeHandlersForRootLogger();\n        SLF4JBridgeHandler.install();\n    }\n\n    @Override\n    public void stop(BundleContext context) throws Exception {\n        SLF4JBridgeHandler.uninstall();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/.gitignore",
    "content": "/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.linux.clock\nBundle-SymbolicName: org.eclipse.kura.linux.clock;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: com.google.gson;version=\"2.7.0\",\n com.google.gson.annotations;version=\"2.7.0\",\n org.apache.commons.net;version=\"3.1.0\",\n org.apache.commons.net.ntp;version=\"3.1.0\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.clock;version=\"[1.0,1.1)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.linux.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.position;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.event;version=\"1.3.0\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/OSGI-INF/clock.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.clock.ClockService\">\n   <implementation class=\"org.eclipse.kura.linux.clock.ClockServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.clock.ClockService\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.clock.ClockService\"/>\n   <reference name=\"EventAdmin\" \n              cardinality=\"1..1\" \n              policy=\"static\"\n              bind=\"setEventAdmin\"\n              unbind=\"unsetEventAdmin\"\n              interface=\"org.osgi.service.event.EventAdmin\"/>\n   <reference bind=\"setExecutorService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.executor.PrivilegedExecutorService\" name=\"PrivilegedExecutorService\" policy=\"static\" unbind=\"unsetExecutorService\"/>\n   <reference bind=\"setCryptoService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.crypto.CryptoService\" name=\"CryptoService\" policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/OSGI-INF/metatype/org.eclipse.kura.clock.ClockService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.clock.ClockService\"\n         name=\"ClockService\"\n         description=\"ClockService Configuration\">\n\n        <Icon resource=\"ClockService\" size=\"32\"/>\n\n        <AD id=\"enabled\"\n            name=\"enabled\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"Whether or not to enable the ClockService\"/>\n\n        <AD id=\"clock.set.hwclock\"\n            name=\"clock.set.hwclock\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"true\"\n            description=\"Whether or not to sync the system hardware clock after the system time gets set\"/>\n\n        <AD id=\"clock.provider\"\n            name=\"clock.provider\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"java-ntp\"\n            description=\"Source for setting the system clock. Verify the availabiliy of the selected provider before activate it. Using chrony-advanced causes all fields, except Chrony Configuration, to be ignored.\">\n\n               <Option label=\"java-ntp\" value=\"java-ntp\"/>\n               <Option label=\"chrony-advanced\" value=\"chrony-advanced\"/>\n        </AD>\n\n        <AD id=\"clock.ntp.host\"\n            name=\"clock.ntp.host\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0.pool.ntp.org\"\n            description=\"The hostname that provides the system time via NTP\"/>\n\n        <AD id=\"clock.ntp.port\"\n            name=\"clock.ntp.port\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            min=\"1\"\n            max=\"65535\"\n            default=\"123\"\n            description=\"The port number that provides the system time via NTP\"/>\n\n        <AD id=\"clock.ntp.timeout\"\n            name=\"clock.ntp.timeout\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            min=\"1000\"\n            default=\"10000\"\n            description=\"The NTP timeout in milliseconds\"/>\n\n        <AD id=\"clock.ntp.max-retry\"\n            name=\"clock.ntp.max-retry\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            min=\"0\"\n            default=\"0\"\n            description=\"The maximum number of retries for the initial synchronization (with interval clock.ntp.retry.interval). If set to 0 the service will retry forever.\"/>\n\n        <AD id=\"clock.ntp.retry.interval\"\n            name=\"clock.ntp.retry.interval\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            min=\"1\"\n            default=\"5\"\n            description=\"When sync fails, interval in seconds between each retry.\"/>\n\n        <AD id=\"clock.ntp.refresh-interval\"\n            name=\"clock.ntp.refresh-interval\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"3600\"\n            description=\"Whether or not to sync the clock and if so, the frequency in seconds.  If less than zero - no update, if equal to zero - sync once at startup, if greater than zero - the frequency in seconds to perform a new clock sync\"/>\n\n        <AD id=\"rtc.filename\"\n            name=\"RTC File Name\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"/dev/rtc0\"\n            description=\"The RTC File Name. It defaults to /dev/rtc0. This option is not used if chrony-advanced option is selected in clock.provider.\"/>\n\n        <AD id=\"chrony.advanced.config\"\n            name=\"Chrony Configuration\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            description=\"Chrony configuration file. All fields above will be ignored.|TextArea\" />\n\n    </OCD>\n    <Designate pid=\"org.eclipse.kura.clock.ClockService\">\n        <Object ocdref=\"org.eclipse.kura.clock.ClockService\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.eclipse.osgi,\\\n                     org.eclipse.kura.core\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n     Red Hat Inc - fix issue #603\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.linux.clock</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.linux.clock.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/src/main/java/org/eclipse/kura/linux/clock/AbstractNtpClockSyncProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport java.util.Date;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class AbstractNtpClockSyncProvider implements ClockSyncProvider {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractNtpClockSyncProvider.class);\n\n    protected ClockSyncListener listener;\n\n    protected String ntpHost;\n    protected int ntpPort;\n    protected int ntpTimeout;\n    protected int retryInterval;\n    protected int refreshInterval;\n    protected Date lastSync;\n    protected ScheduledExecutorService scheduler;\n    protected int maxRetry;\n    protected int numRetry;\n    protected boolean isSynced;\n    protected int syncCount;\n\n    private ScheduledFuture<?> future;\n\n    @Override\n    public void init(ClockServiceConfig clockServiceConfig, ScheduledExecutorService scheduler,\n            ClockSyncListener listener) throws KuraException {\n        this.scheduler = scheduler;\n        this.listener = listener;\n        this.ntpHost = clockServiceConfig.getNtpHost();\n        this.ntpPort = clockServiceConfig.getNtpPort();\n        this.ntpTimeout = clockServiceConfig.getNtpTimeout();\n        this.retryInterval = clockServiceConfig.getNtpRetryInterval();\n        this.refreshInterval = clockServiceConfig.getNtpRefreshInterval();\n        this.maxRetry = clockServiceConfig.getNtpMaxRetries();\n    }\n\n    @Override\n    public void start() throws KuraException {\n        this.isSynced = false;\n        this.numRetry = 0;\n        if (this.refreshInterval < 0) {\n            // Never do any update. So Nothing to do.\n            logger.info(\"No clock update required\");\n            stop();\n        } else if (this.refreshInterval == 0) {\n            // Perform one clock update - but in a thread.\n            logger.info(\"Perform clock update just once\");\n            stop();\n\n            // call recursive retry method for setting the clock\n            scheduleOnce();\n        } else {\n            final int retryInt;\n            if (this.retryInterval <= 0) {\n                retryInt = 1;\n            } else {\n                retryInt = this.retryInterval;\n            }\n            // Perform periodic clock updates.\n            logger.info(\"Perform periodic clock updates every {} sec\", this.refreshInterval);\n            stop();\n\n            this.future = this.scheduler.scheduleAtFixedRate(() -> {\n                Thread.currentThread().setName(\"AbstractNtpClockSyncProvider:schedule\");\n                if (!AbstractNtpClockSyncProvider.this.isSynced) {\n                    AbstractNtpClockSyncProvider.this.syncCount = 0;\n                    try {\n                        logger.info(\"Try to sync clock ({})\", AbstractNtpClockSyncProvider.this.numRetry);\n                        if (syncClock()) {\n                            logger.info(\"Clock synced\");\n                            AbstractNtpClockSyncProvider.this.isSynced = true;\n                            AbstractNtpClockSyncProvider.this.numRetry = 0;\n                        } else {\n                            AbstractNtpClockSyncProvider.this.numRetry++;\n                            if (AbstractNtpClockSyncProvider.this.maxRetry > 0\n                                    && AbstractNtpClockSyncProvider.this.numRetry >= AbstractNtpClockSyncProvider.this.maxRetry) {\n                                logger.error(\"Failed to synchronize System Clock. Exhausted retry attempts, giving up\");\n                                AbstractNtpClockSyncProvider.this.isSynced = true;\n                            }\n                        }\n                    } catch (KuraException e) {\n                        AbstractNtpClockSyncProvider.this.numRetry++;\n                        logger.error(\"Error Synchronizing Clock\", e);\n                        if (AbstractNtpClockSyncProvider.this.maxRetry > 0\n                                && AbstractNtpClockSyncProvider.this.numRetry >= AbstractNtpClockSyncProvider.this.maxRetry) {\n                            logger.error(\"Failed to synchronize System Clock. Exhausted retry attempts, giving up\");\n                            AbstractNtpClockSyncProvider.this.isSynced = true;\n                        }\n                    }\n                } else {\n                    AbstractNtpClockSyncProvider.this.syncCount++;\n                    if (AbstractNtpClockSyncProvider.this.syncCount\n                            * retryInt >= AbstractNtpClockSyncProvider.this.refreshInterval - 1) {\n                        AbstractNtpClockSyncProvider.this.isSynced = false;\n                        AbstractNtpClockSyncProvider.this.numRetry = 0;\n                    }\n                }\n            }, 0, retryInt, TimeUnit.SECONDS);\n        }\n    }\n\n    private void scheduleOnce() {\n        this.future = this.scheduler.schedule(() -> {\n            Thread.currentThread().setName(\"AbstractNtpClockSyncProvider:scheduleOnce\");\n            try {\n                syncClock();\n            } catch (KuraException e) {\n                logger.error(\"Error Synchronizing Clock - retrying\", e);\n                scheduleOnce();\n            }\n        }, 1, TimeUnit.SECONDS);\n    }\n\n    @Override\n    public void stop() throws KuraException {\n        if (this.future != null) {\n            this.future.cancel(true);\n        }\n    }\n\n    @Override\n    public Date getLastSync() {\n        return this.lastSync;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private/Protected Methods\n    //\n    // ----------------------------------------------------------------\n    protected abstract boolean syncClock() throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/src/main/java/org/eclipse/kura/linux/clock/ChronyClockSyncProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardCopyOption;\nimport java.security.NoSuchAlgorithmException;\nimport java.time.Instant;\nimport java.time.temporal.ChronoUnit;\nimport java.util.Date;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.gson.Gson;\nimport com.google.gson.annotations.SerializedName;\n\npublic class ChronyClockSyncProvider implements ClockSyncProvider {\n\n    private static final String[] CHRONY_SERVICE_NAMES = new String[] { \"chrony\", \"chronyd\" };\n\n    private static final String SERVICE_MANAGER = \"systemctl\";\n\n    private static final Logger logger = LoggerFactory.getLogger(ChronyClockSyncProvider.class);\n\n    private static final int SERVICE_STATUS_UNKNOWN = 4;\n\n    private final CommandExecutorService executorService;\n    private ScheduledExecutorService schedulerExecutor;\n    private ScheduledFuture<?> future;\n\n    private ClockSyncListener listener;\n\n    private String chronyConfig;\n\n    private String chronyServiceName;\n\n    private Date lastSyncValue;\n\n    private Gson gson;\n\n    private long lastSyncTime;\n\n    private final Path[] chronyConfigLocations = new Path[] { Paths.get(\"/etc/chrony.conf\"),\n            Paths.get(\"/etc/chrony/chrony.conf\") };\n\n    private final CryptoService cryptoService;\n\n    public ChronyClockSyncProvider(CommandExecutorService commandExecutorService, CryptoService cryptoService) {\n        this.executorService = commandExecutorService;\n        this.cryptoService = cryptoService;\n    }\n\n    @Override\n    public void init(ClockServiceConfig clockServiceConfig, ScheduledExecutorService scheduler,\n            ClockSyncListener listener) throws KuraException {\n        this.listener = listener;\n        this.schedulerExecutor = scheduler;\n\n        this.gson = new Gson();\n        this.chronyConfig = clockServiceConfig.getChronyAdvancedConfig();\n\n        this.chronyServiceName = findChronyService();\n\n        writeConfiguration();\n    }\n\n    private void writeConfiguration() throws KuraException {\n\n        if (this.chronyConfig != null && !this.chronyConfig.isEmpty()) {\n\n            Path chronyConfigLocation = null;\n\n            for (Path loc : this.chronyConfigLocations) {\n                if (Files.exists(loc)) {\n                    chronyConfigLocation = loc;\n                    break;\n                }\n            }\n\n            if (chronyConfigLocation == null) {\n                throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, \"chrony configuration\", \"....\");\n            }\n\n            try {\n                String chronyConfigLocationContent = new String(Files.readAllBytes(chronyConfigLocation),\n                        StandardCharsets.UTF_8);\n\n                if (this.cryptoService.sha256Hash(this.chronyConfig)\n                        .equals(this.cryptoService.sha256Hash(chronyConfigLocationContent))) {\n\n                    logger.debug(\"chrony configuration not changed\");\n                    return;\n                }\n\n                String chronyConfigLocationBackup = chronyConfigLocation.toString() + \".bak\";\n\n                logger.info(\"Saving previous chrony configuration file at {}\", chronyConfigLocationBackup);\n                Files.copy(chronyConfigLocation, Paths.get(chronyConfigLocationBackup),\n                        StandardCopyOption.REPLACE_EXISTING);\n                Files.write(chronyConfigLocation, this.chronyConfig.getBytes());\n            } catch (IOException e) {\n                logger.error(\"Unable to write chrony configuration file at {}\", chronyConfigLocation, e);\n            } catch (NoSuchAlgorithmException e) {\n                logger.error(\"Unable to get files hash\", e);\n            }\n        }\n\n    }\n\n    @Override\n    public void start() throws KuraException {\n\n        if (!isChronydRunning()) {\n            logger.info(\"chrony service down, trying to start...\");\n\n            boolean startChronyd = controlChronyd(\"start\");\n            if (!startChronyd) {\n                logger.error(\"Unable to start chrony service.\");\n                throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR, \"Unable to start chrony service.\");\n            }\n        } else {\n            logger.info(\"chrony service is up.\");\n        }\n\n        if (syncClock()) {\n            logger.info(\"Clock synced\");\n        } else {\n            logger.info(\"Clock not synced\");\n        }\n\n        this.future = this.schedulerExecutor.scheduleAtFixedRate(this::readAndUpdateSyncInfo, 0, 60, TimeUnit.SECONDS);\n\n    }\n\n    protected boolean syncClock() {\n\n        logger.info(\"Forcing clock synchronization...\");\n\n        Command chronycMakeStep = new Command(new String[] { \"chronyc\", \"makestep\" });\n        CommandStatus chronycMakeStepStatus = this.executorService.execute(chronycMakeStep);\n\n        boolean clockSynced = chronycMakeStepStatus.getExitStatus().isSuccessful();\n\n        if (clockSynced) {\n            readAndUpdateSyncInfo();\n        }\n\n        return clockSynced;\n    }\n\n    private void readAndUpdateSyncInfo() {\n\n        logger.debug(\"Start reading the journal for clock updates...\");\n\n        // check either chronyd or chrony unit because both are used in journal alternatively\n        Command journalClockUpdateRead = new Command(new String[] { \"journalctl\", \"-r\", \"-u\", chronyServiceName, \"-u\",\n                \"chrony\", \"-b\", \"-o\", \"json\", \"-S\", \"today\", \"--output-fields\", \"MESSAGE\", \"|\", \"grep\",\n                \"'System clock was stepped by'\", \"-m\", \"1\" });\n\n        journalClockUpdateRead.setExecuteInAShell(true);\n        journalClockUpdateRead.setErrorStream(new ByteArrayOutputStream());\n        journalClockUpdateRead.setOutputStream(new ByteArrayOutputStream());\n        CommandStatus journalClockUpdateReadStatus = this.executorService.execute(journalClockUpdateRead);\n\n        if (journalClockUpdateReadStatus.getExitStatus().isSuccessful()\n                && journalClockUpdateReadStatus.getOutputStream() instanceof ByteArrayOutputStream) {\n            ByteArrayOutputStream journalClockUpdateReadStatusStream = (ByteArrayOutputStream) journalClockUpdateReadStatus\n                    .getOutputStream();\n\n            if (journalClockUpdateReadStatusStream.size() > 0) {\n\n                JournalChronyEntry journalEntry = this.gson.fromJson(\n                        new String(journalClockUpdateReadStatusStream.toByteArray(), StandardCharsets.UTF_8),\n                        JournalChronyEntry.class);\n\n                if (journalEntry.getTime() > this.lastSyncTime) {\n\n                    logger.info(\"Journal successfully readed. Last clock stepping event was at: {}\",\n                            Instant.EPOCH.plus(journalEntry.getTime(), ChronoUnit.MICROS));\n\n                    this.lastSyncTime = journalEntry.getTime();\n                    this.lastSyncValue = new Date(\n                            TimeUnit.MILLISECONDS.convert(journalEntry.getTime(), TimeUnit.MICROSECONDS));\n\n                    this.listener.onClockUpdate(0, false);\n                }\n            } else {\n                logger.debug(\"No new clock stepping event\");\n            }\n        } else {\n            logger.debug(\"Chrony stepping not found in system journal (may be not requested). {}\",\n                    journalClockUpdateRead.getErrorStream());\n        }\n\n    }\n\n    @Override\n    public void stop() throws KuraException {\n        logger.info(\"Stopping chrony service...\");\n\n        if (controlChronyd(\"stop\")) {\n            logger.info(\"chrony service stopped\");\n        } else {\n            logger.warn(\"Unable to stop chrony service\");\n        }\n\n        if (this.future != null) {\n            this.future.cancel(true);\n        }\n    }\n\n    @Override\n    public Date getLastSync() {\n        return this.lastSyncValue;\n    }\n\n    private boolean isChronydRunning() {\n\n        logger.info(\"Checking chrony service status...\");\n\n        Command checkChronyStatus = new Command(new String[] { SERVICE_MANAGER, \"is-active\", chronyServiceName });\n        CommandStatus chronyStatus = this.executorService.execute(checkChronyStatus);\n\n        return chronyStatus.getExitStatus().isSuccessful();\n    }\n\n    private boolean controlChronyd(String command) {\n        Command startChronyStatus = new Command(new String[] { SERVICE_MANAGER, command, chronyServiceName });\n        CommandStatus chronyStatus = this.executorService.execute(startChronyStatus);\n\n        return chronyStatus.getExitStatus().isSuccessful();\n    }\n\n    private String findChronyService() throws KuraException {\n\n        String foundChronyDaemon = \"\";\n\n        for (String chronyServiceNameItem : CHRONY_SERVICE_NAMES) {\n            if (findWithSystemd(chronyServiceNameItem)) {\n                foundChronyDaemon = chronyServiceNameItem;\n                break;\n            }\n        }\n\n        if (foundChronyDaemon.isEmpty()) {\n            throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR);\n        }\n\n        return foundChronyDaemon;\n    }\n\n    private boolean findWithSystemd(String serviceName) {\n        Command chronyStatusCommand = new Command(new String[] { SERVICE_MANAGER, \"status\", serviceName });\n        chronyStatusCommand.setExecuteInAShell(true);\n        int exitCode = this.executorService.execute(chronyStatusCommand).getExitStatus().getExitCode();\n\n        return (exitCode >= 0 && exitCode != SERVICE_STATUS_UNKNOWN);\n\n    }\n\n    private class JournalChronyEntry {\n\n        @SerializedName(\"__REALTIME_TIMESTAMP\")\n        private final long time;\n\n        @SuppressWarnings(\"unused\")\n        public JournalChronyEntry(long time) {\n            super();\n            this.time = time;\n        }\n\n        public long getTime() {\n            return this.time;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/src/main/java/org/eclipse/kura/linux/clock/ClockProviderType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic enum ClockProviderType {\n\n    JAVA_NTP(\"java-ntp\"),\n    NTPD(\"ntpd\"),\n    CHRONY_ADVANCED(\"chrony-advanced\");\n\n    private static Map<String, ClockProviderType> valuesMap = new HashMap<>();\n\n    static {\n        for (ClockProviderType type : ClockProviderType.values()) {\n            valuesMap.put(type.getValue(), type);\n        }\n    }\n\n    private String value;\n\n    public String getValue() {\n        return this.value;\n    }\n\n    ClockProviderType(String value) {\n        this.value = value;\n    }\n\n    public static ClockProviderType fromValue(String value) {\n        return valuesMap.get(value);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/src/main/java/org/eclipse/kura/linux/clock/ClockServiceConfig.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class ClockServiceConfig {\n\n    private static final Property<Boolean> PROPERTY_ENABLE = new Property<>(\"enabled\", true);\n\n    private static final Property<Boolean> PROPERTY_HW_CLOCK_ENABLED = new Property<>(\"clock.set.hwclock\", true);\n    private static final Property<String> PROPERTY_CLOCK_PROVIDER = new Property<>(\"clock.provider\", \"java-ntp\");\n    private static final Property<String> PROPERTY_NTP_HOST = new Property<>(\"clock.ntp.host\", \"0.pool.ntp.org\");\n    private static final Property<Integer> PROPERTY_NTP_PORT = new Property<>(\"clock.ntp.port\", 123);\n    private static final Property<Integer> PROPERTY_NTP_TIMEOUT = new Property<>(\"clock.ntp.timeout\", 10000);\n    private static final Property<Integer> PROPERTY_NTP_MAX_RETRIES = new Property<>(\"clock.ntp.max-retry\", 0);\n    private static final Property<Integer> PROPERTY_NTP_RETRY_INTERVAL = new Property<>(\"clock.ntp.max-retry\", 5);\n    private static final Property<Integer> PROPERTY_NTP_REFRESH_INTERVAL = new Property<>(\"clock.ntp.refresh-interval\",\n            3600);\n    private static final Property<String> PROPERTY_RTC_FILENAME = new Property<>(\"rtc.filename\", \"/dev/rtc0\");\n    private static final Property<String> PROPERTY_CHRONY_ADVANCED_CONFIG = new Property<>(\"chrony.advanced.config\",\n            \"\");\n\n    private final boolean enabled;\n    private final boolean hwclockEnabled;\n    private final String clockProvider;\n    private final String ntpHost;\n    private final int ntpPort;\n    private final int ntpTimeout;\n    private final int ntpMaxRetries;\n    private final int ntpRetryInterval;\n    private final int ntpRefreshInterval;\n    private final String rtcFilename;\n    private final String chronyAdvancedConfig;\n\n    public ClockServiceConfig(Map<String, Object> properties) {\n        this.enabled = PROPERTY_ENABLE.get(properties);\n        this.hwclockEnabled = PROPERTY_HW_CLOCK_ENABLED.get(properties);\n        this.clockProvider = PROPERTY_CLOCK_PROVIDER.get(properties);\n        this.ntpHost = PROPERTY_NTP_HOST.get(properties);\n        this.ntpPort = PROPERTY_NTP_PORT.get(properties);\n        this.ntpTimeout = PROPERTY_NTP_TIMEOUT.get(properties);\n        this.ntpMaxRetries = PROPERTY_NTP_MAX_RETRIES.get(properties);\n        this.ntpRetryInterval = PROPERTY_NTP_RETRY_INTERVAL.get(properties);\n        this.ntpRefreshInterval = PROPERTY_NTP_REFRESH_INTERVAL.get(properties);\n        this.rtcFilename = PROPERTY_RTC_FILENAME.get(properties);\n        this.chronyAdvancedConfig = PROPERTY_CHRONY_ADVANCED_CONFIG.get(properties);\n    }\n\n    public boolean isEnabled() {\n        return this.enabled;\n    }\n\n    public boolean isHwclockEnabled() {\n        return this.hwclockEnabled;\n    }\n\n    public String getClockProvider() {\n        return this.clockProvider;\n    }\n\n    public String getNtpHost() {\n        return this.ntpHost;\n    }\n\n    public int getNtpPort() {\n        return this.ntpPort;\n    }\n\n    public int getNtpTimeout() {\n        return this.ntpTimeout;\n    }\n\n    public int getNtpMaxRetries() {\n        return this.ntpMaxRetries;\n    }\n\n    public int getNtpRetryInterval() {\n        return this.ntpRetryInterval;\n    }\n\n    public int getNtpRefreshInterval() {\n        return this.ntpRefreshInterval;\n    }\n\n    public String getRtcFilename() {\n        return this.rtcFilename;\n    }\n\n    public String getChronyAdvancedConfig() {\n        return this.chronyAdvancedConfig;\n    }\n\n    @Override\n    public int hashCode() {\n        final int prime = 31;\n        int result = 1;\n        result = prime * result + (this.chronyAdvancedConfig == null ? 0 : this.chronyAdvancedConfig.hashCode());\n        result = prime * result + (this.clockProvider == null ? 0 : this.clockProvider.hashCode());\n        result = prime * result + (this.enabled ? 1231 : 1237);\n        result = prime * result + (this.hwclockEnabled ? 1231 : 1237);\n        result = prime * result + (this.ntpHost == null ? 0 : this.ntpHost.hashCode());\n        result = prime * result + this.ntpMaxRetries;\n        result = prime * result + this.ntpPort;\n        result = prime * result + this.ntpRefreshInterval;\n        result = prime * result + this.ntpRetryInterval;\n        result = prime * result + this.ntpTimeout;\n        result = prime * result + (this.rtcFilename == null ? 0 : this.rtcFilename.hashCode());\n        return result;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        ClockServiceConfig other = (ClockServiceConfig) obj;\n        if (this.chronyAdvancedConfig == null) {\n            if (other.chronyAdvancedConfig != null) {\n                return false;\n            }\n        } else if (!this.chronyAdvancedConfig.equals(other.chronyAdvancedConfig)) {\n            return false;\n        }\n        if (this.clockProvider == null) {\n            if (other.clockProvider != null) {\n                return false;\n            }\n        } else if (!this.clockProvider.equals(other.clockProvider)) {\n            return false;\n        }\n        if (this.enabled != other.enabled) {\n            return false;\n        }\n        if (this.hwclockEnabled != other.hwclockEnabled) {\n            return false;\n        }\n        if (this.ntpHost == null) {\n            if (other.ntpHost != null) {\n                return false;\n            }\n        } else if (!this.ntpHost.equals(other.ntpHost)) {\n            return false;\n        }\n        if (this.ntpMaxRetries != other.ntpMaxRetries) {\n            return false;\n        }\n        if (this.ntpPort != other.ntpPort) {\n            return false;\n        }\n        if (this.ntpRefreshInterval != other.ntpRefreshInterval) {\n            return false;\n        }\n        if (this.ntpRetryInterval != other.ntpRetryInterval) {\n            return false;\n        }\n        if (this.ntpTimeout != other.ntpTimeout) {\n            return false;\n        }\n        if (this.rtcFilename == null) {\n            if (other.rtcFilename != null) {\n                return false;\n            }\n        } else if (!this.rtcFilename.equals(other.rtcFilename)) {\n            return false;\n        }\n        return true;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/src/main/java/org/eclipse/kura/linux/clock/ClockServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.clock.ClockEvent;\nimport org.eclipse.kura.clock.ClockService;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.osgi.service.event.EventAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ClockServiceImpl implements ConfigurableComponent, ClockService, ClockSyncListener {\n\n    private static final ClockEvent EMPTY_EVENT = new ClockEvent(Collections.<String, Object>emptyMap());\n\n    private static final Logger logger = LoggerFactory.getLogger(ClockServiceImpl.class);\n\n    private EventAdmin eventAdmin;\n    private CommandExecutorService executorService;\n    private CryptoService cryptoService;\n    private ClockSyncProvider provider;\n\n    private ClockServiceConfig clockServiceConfig;\n    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public void setEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    public void unsetEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = null;\n    }\n\n    public void setExecutorService(CommandExecutorService executorService) {\n        this.executorService = executorService;\n    }\n\n    public void unsetExecutorService(CommandExecutorService executorService) {\n        this.executorService = null;\n    }\n\n    public void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(Map<String, Object> properties) {\n        logger.info(\"Activate. Current Time: {}\", new Date());\n\n        // save the properties\n        this.clockServiceConfig = new ClockServiceConfig(properties);\n\n        if (this.clockServiceConfig.isEnabled()) {\n            // start the provider\n            try {\n                startClockSyncProvider();\n            } catch (KuraException t) {\n                logger.error(\"Error updating ClockService Configuration\", t);\n            }\n        }\n    }\n\n    protected void deactivate() {\n        logger.info(\"Deactivate...\");\n        try {\n            stopClockSyncProvider();\n        } catch (KuraException t) {\n            logger.error(\"Error deactivating ClockSyncProvider\", t);\n        }\n        this.scheduler.shutdown();\n        try {\n            if (!this.scheduler.awaitTermination(1, TimeUnit.SECONDS)) {\n                this.scheduler.shutdownNow();\n            }\n        } catch (InterruptedException e) {\n            logger.warn(\"Interrupted clock service scheduler shutdown!\", e);\n            this.scheduler.shutdownNow();\n            Thread.currentThread().interrupt();\n        }\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"Updated...\");\n\n        // save the properties\n        ClockServiceConfig newClockServiceConfig = new ClockServiceConfig(properties);\n        if (newClockServiceConfig.equals(this.clockServiceConfig)) {\n            return;\n        }\n        logger.info(\"New configuration for Clock Service\");\n        this.clockServiceConfig = newClockServiceConfig;\n\n        if (this.clockServiceConfig.isEnabled()) {\n            try {\n                // start the provider\n                startClockSyncProvider();\n            } catch (KuraException t) {\n                logger.error(\"Error updating ClockService Configuration\", t);\n            }\n        } else {\n            // stop the provider if it was running\n            try {\n                stopClockSyncProvider();\n            } catch (KuraException t) {\n                logger.error(\"Error deactivate ClockService\", t);\n            }\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Master Client Management APIs\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public Date getLastSync() throws KuraException {\n        if (this.provider != null) {\n            return this.provider.getLastSync();\n        } else {\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, \"Clock service not configured yet\");\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private Methods\n    //\n    // ----------------------------------------------------------------\n\n    private void startClockSyncProvider() throws KuraException {\n        stopClockSyncProvider();\n        String sprovider = this.clockServiceConfig.getClockProvider();\n\n        switch (ClockProviderType.fromValue(sprovider)) {\n        case JAVA_NTP:\n            this.provider = new JavaNtpClockSyncProvider();\n            break;\n        case NTPD:\n            logger.error(\"NTPD clock provider is not supported anymore. Use JAVA_NTP or CHRONY_ADVANCED instead.\");\n            return;\n        case CHRONY_ADVANCED:\n            this.provider = new ChronyClockSyncProvider(this.executorService, this.cryptoService);\n            break;\n\n        default:\n            throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID);\n        }\n\n        this.provider.init(this.clockServiceConfig, this.scheduler, this);\n        this.provider.start();\n    }\n\n    private void stopClockSyncProvider() throws KuraException {\n        if (this.provider != null) {\n            this.provider.stop();\n            this.provider = null;\n        }\n    }\n\n    /**\n     * Called by the current ClockSyncProvider after each Clock synchronization\n     */\n    @Override\n    public void onClockUpdate(long offset, boolean changeSystemClock) {\n\n        logger.info(\"Clock update. Offset: {}\", offset);\n\n        // set system clock if necessary\n        boolean bClockUpToDate = false;\n        if (offset != 0 && changeSystemClock) {\n            long time = System.currentTimeMillis() + offset;\n            Command command = new Command(new String[] { \"date\", \"-s\", \"@\" + Long.toString(time / 1000) });\n            command.setTimeout(60);\n            CommandStatus status = this.executorService.execute(command);\n            if (status.getExitStatus().isSuccessful()) {\n                bClockUpToDate = true;\n                logger.info(\"System Clock Updated to {}\", new Date());\n            } else {\n                logger.error(\n                        \"Unexpected error while updating System Clock - rc = {}, CommandLine:{}, it should've been {}\",\n                        status.getExitStatus().getExitCode(), command.getCommandLine(), new Date());\n            }\n        } else {\n            bClockUpToDate = true;\n        }\n\n        if (this.clockServiceConfig.isHwclockEnabled() && changeSystemClock) {\n            Command command = new Command(\n                    new String[] { \"hwclock\", \"--utc\", \"--systohc\", \"-f\", this.clockServiceConfig.getRtcFilename() });\n            command.setTimeout(60);\n            CommandStatus status = this.executorService.execute(command);\n            if (status.getExitStatus().isSuccessful()) {\n                logger.info(\"Hardware Clock Updated\");\n            } else {\n                logger.error(\"Unexpected error while updating Hardware Clock - rc = {}\",\n                        status.getExitStatus().getExitCode());\n            }\n        }\n\n        // Raise the event\n        if (bClockUpToDate) {\n            this.eventAdmin.postEvent(EMPTY_EVENT);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/src/main/java/org/eclipse/kura/linux/clock/ClockSyncListener.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\npublic interface ClockSyncListener {\n\n    public void onClockUpdate(long offset, boolean changeSystemClock);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/src/main/java/org/eclipse/kura/linux/clock/ClockSyncProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport java.util.Date;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport org.eclipse.kura.KuraException;\n\npublic interface ClockSyncProvider {\n\n    public void init(ClockServiceConfig clockServiceConfig, ScheduledExecutorService scheduler,\n            ClockSyncListener listener) throws KuraException;\n\n    public void start() throws KuraException;\n\n    public void stop() throws KuraException;\n\n    public Date getLastSync();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.clock/src/main/java/org/eclipse/kura/linux/clock/JavaNtpClockSyncProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.apache.commons.net.ntp.NTPUDPClient;\nimport org.apache.commons.net.ntp.TimeInfo;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class JavaNtpClockSyncProvider extends AbstractNtpClockSyncProvider {\n\n    private static final Logger logger = LoggerFactory.getLogger(JavaNtpClockSyncProvider.class);\n\n    // ----------------------------------------------------------------\n    //\n    // Concrete Methods\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    protected boolean syncClock() throws KuraException {\n        boolean ret = false;\n        // connect and get the delta\n        NTPUDPClient ntpClient = new NTPUDPClient();\n        ntpClient.setDefaultTimeout(this.ntpTimeout);\n        try {\n            ntpClient.open();\n            InetAddress ntpHostAddr = InetAddress.getByName(this.ntpHost);\n            TimeInfo info = ntpClient.getTime(ntpHostAddr, this.ntpPort);\n            this.lastSync = new Date();\n            info.computeDetails();\n            info.getComments().forEach(comment -> logger.debug(\"Clock sync compute comment: {}\", comment));\n            List<String> computeErrors = info.getComments().stream().filter(comment -> comment.contains(\"Error:\"))\n                    .collect(Collectors.toList());\n            Long delayValue = info.getDelay();\n            if (delayValue != null && delayValue.longValue() < 1000 && computeErrors.isEmpty()) {\n                this.listener.onClockUpdate(info.getOffset(), true);\n                ret = true;\n            } else {\n                logger.error(\"Incorrect clock sync. Delay value({}), clock will not be updated\", info.getDelay());\n            }\n        } catch (IOException e) {\n            logger.warn(\n                    \"Error while synchronizing System Clock with NTP host {}. Please verify network connectivity ...\",\n                    this.ntpHost);\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.CONNECTION_FAILED, e);\n        } finally {\n            ntpClient.close();\n        }\n        return ret;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/.gitignore",
    "content": "/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.linux.usb\nBundle-SymbolicName: org.eclipse.kura.linux.usb;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: javax.usb;version=\"1.0.2\",\n javax.usb.event;version=\"1.0.2\",\n javax.usb.util;version=\"1.0.2\",\n org.apache.commons.exec;version=\"1.3.0\",\n org.apache.commons.io;version=\"1.4.9999\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.linux.udev;version=\"[1.0,1.1)\",\n org.eclipse.kura.usb;version=\"[1.3,1.4)\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.event;version=\"1.3.0\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/OSGI-INF/usb.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" immediate=\"true\" name=\"org.eclipse.kura.usb.UsbService\">\n   <implementation class=\"org.eclipse.kura.linux.usb.UsbServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.usb.UsbService\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.usb.UsbService\"/>\n   <reference bind=\"setEventAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.event.EventAdmin\" name=\"EventAdmin\" policy=\"dynamic\" unbind=\"unsetEventAdmin\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.eclipse.osgi,\\\n                     org.eclipse.equinox.io,\\\n                     org.eclipse.kura.core\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n     Red Hat Inc\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.linux.usb</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.linux.usb.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/.gitignore",
    "content": "*.so\n*.o"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/LinuxUdev.c",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n *\n *  This program and the accompanying materials are made\n *  available under the terms of the Eclipse Public License 2.0\n *  which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n *  SPDX-License-Identifier: EPL-2.0\n *\n *  Contributors:\n *   Eurotech\n *   Red Hat Inc\n *******************************************************************************/\n/*******************************************\n This code is meant to be a teaching\n resource. It can be used for anyone for\n any reason, including embedding into\n a commercial product.\n\n The document describing this file, and\n updated versions can be found at:\n    http://www.signal11.us/oss/udev/\n\n Alan Ott\n Signal 11 Software\n *******************************************/\n\n#include \"LinuxUdev.h\"\n\njobject get_interface_number(JNIEnv *env, struct udev_device *dev_interface) {\n\tjclass integerClass;\n\tjmethodID integerConstructorID;\n\tjobject interfaceNumber = NULL;\n\tint interfaceNumberInt;\n\n\tintegerClass = (*env)->FindClass(env, \"java/lang/Integer\");\n\tif (integerClass == NULL) return NULL;\n\tintegerConstructorID = (*env)->GetMethodID(env, integerClass, \"<init>\", \"(I)V\");\n\tif (integerConstructorID == NULL) return NULL;\n\n\tconst char* interfaceNumberString = udev_device_get_sysattr_value(dev_interface, \"bInterfaceNumber\");\n\tif (interfaceNumberString) {\n\t\tinterfaceNumberInt = (int) strtol(interfaceNumberString,NULL,16);\n\t\tinterfaceNumber = (*env)->NewObject(env, integerClass, integerConstructorID, interfaceNumberInt);\n\t}\n\n\treturn interfaceNumber;\n\n}\n\nJNIEXPORT jobject JNICALL Java_org_eclipse_kura_linux_usb_LinuxUdevNative_getUsbDevices(JNIEnv *env, jclass LinuxUdevNative, jstring deviceClass) {\n\tstruct udev *udev;\n\tstruct udev_enumerate *enumerate;\n\tstruct udev_list_entry *devices, *dev_list_entry;\n\tstruct udev_device *dev, *dev_parent;\n\n\tconst char *nativeDeviceClass = (*env)->GetStringUTFChars(env, deviceClass, 0);\n\tjclass UsbDeviceClass = NULL;\n\tjmethodID UsbDeviceConstructor = NULL;\n\tjobject UsbDeviceObject = NULL;\n\n\t//specifics for BLOCK devices\n\tjstring blockDeviceNode = NULL;\n\n\t//specifics for NET devices\n\tjstring interfaceName = NULL;\n\n\t//specifics for TTY devices\n\tjstring ttyDeviceNode = NULL;\n\n\t//initialize the ArrayList for the return\n\tjclass arrayClass = (*env)->FindClass(env, \"java/util/ArrayList\");\n\tif (arrayClass == NULL) return NULL;\n\tjmethodID mid_init =  (*env)->GetMethodID(env, arrayClass, \"<init>\", \"()V\");\n\tif (mid_init == NULL) return NULL;\n\tjobject objArr = (*env)->NewObject(env, arrayClass, mid_init);\n\tif (objArr == NULL) return NULL;\n\tjmethodID mid_add = (*env)->GetMethodID(env, arrayClass, \"add\", \"(Ljava/lang/Object;)Z\");\n\tif (mid_add == NULL) return NULL;\n\n\t//set up our specific device type constructor\n\tif(strcmp(nativeDeviceClass,\"block\")==0) {\n\t\tUsbDeviceClass = (*env)->FindClass(env, \"org/eclipse/kura/usb/UsbBlockDevice\");\n\t\tif (UsbDeviceClass == NULL) return NULL;\n\t\tUsbDeviceConstructor = (*env)->GetMethodID(env, UsbDeviceClass, \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\");\n\t\tif (UsbDeviceConstructor == NULL) return NULL;\n\t} else if(strcmp(nativeDeviceClass,\"net\")==0) {\n\t\tUsbDeviceClass = (*env)->FindClass(env, \"org/eclipse/kura/usb/UsbNetDevice\");\n\t\tif (UsbDeviceClass == NULL) return NULL;\n\t\tUsbDeviceConstructor = (*env)->GetMethodID(env, UsbDeviceClass, \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\");\n\t\tif (UsbDeviceConstructor == NULL) return NULL;\n\t} else if(strcmp(nativeDeviceClass,\"tty\")==0) {\n\t\tUsbDeviceClass = (*env)->FindClass(env, \"org/eclipse/kura/usb/UsbTtyDevice\");\n\t\tif (UsbDeviceClass == NULL) return NULL;\n\t\tUsbDeviceConstructor = (*env)->GetMethodID(env, UsbDeviceClass, \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V\");\n\t\tif (UsbDeviceConstructor == NULL) return NULL;\n\t}\n\n\t/* Create the udev object */\n\tudev = udev_new();\n\tif (!udev) {\n\t\tprintf(\"Can't create udev\\n\");\n\t\tjclass Exception = (*env)->FindClass(env, \"java/lang/IOException\");\n\t\t(*env)->ThrowNew(env, Exception,\"Can't create udev object.\");\n\t}\n\n\t/* Create a list of the devices in the '/sys/class/' subsystem. */\n\tenumerate = udev_enumerate_new(udev);\n\tudev_enumerate_add_match_subsystem(enumerate, nativeDeviceClass);\n\n\tudev_enumerate_scan_devices(enumerate);\n\tdevices = udev_enumerate_get_list_entry(enumerate);\n\n\t//loop through what we've found\n\tudev_list_entry_foreach(dev_list_entry, devices) {\n\t\tconst char *path;\n\n\t\t/* Get the filename of the /sys entry for the device\n\t\t   and create a udev_device object (dev) representing it */\n\t\tpath = udev_list_entry_get_name(dev_list_entry);\n\t\tdev = udev_device_new_from_syspath(udev, path);\n\n\t\t/* usb_device_get_devnode() returns the path to the device node\n\t\t   itself in /dev - save this for TTY devices */\n\t\tif(strcmp(nativeDeviceClass,\"block\")==0) {\n\t\t\tblockDeviceNode = (*env)->NewStringUTF(env, udev_device_get_devnode(dev));\n\t\t} else if(strcmp(nativeDeviceClass,\"net\")==0) {\n\t\t\tinterfaceName = (*env)->NewStringUTF(env, udev_device_get_sysname(dev));\n\t\t} else if(strcmp(nativeDeviceClass,\"tty\")==0) {\n\t\t\tttyDeviceNode = (*env)->NewStringUTF(env, udev_device_get_devnode(dev));\n\t\t}\n\n\t\t/* The device pointed to by dev contains information about\n\t\t   the /sys/class/ device. In order to get information about the\n\t\t   USB device, get the parent device with the\n\t\t   subsystem/devtype pair of \"usb\"/\"usb_device\". This will\n\t\t   be several levels up the tree, but the function will find\n\t\t   it.*/\n\t\tdev_parent = udev_device_get_parent_with_subsystem_devtype(\n\t\t\t\tdev,\n\t\t\t\t\"usb\",\n\t\t\t\t\"usb_device\");\n\n\t\tif (dev_parent) {\n\t\t\tif(strcmp(nativeDeviceClass,\"block\")==0) {\n\t\t\t\tUsbDeviceObject = (*env)->NewObject(env, UsbDeviceClass, UsbDeviceConstructor,\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idVendor\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idProduct\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"manufacturer\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"product\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"busnum\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"devpath\")),\n\t\t\t\t\t\tblockDeviceNode);\n\t\t\t} else if(strcmp(nativeDeviceClass,\"net\")==0) {\n\t\t\t\tUsbDeviceObject = (*env)->NewObject(env, UsbDeviceClass, UsbDeviceConstructor,\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idVendor\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idProduct\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"manufacturer\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"product\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"busnum\")),\n\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"devpath\")),\n\t\t\t\t\t\tinterfaceName);\n\t\t\t} else if(strcmp(nativeDeviceClass,\"tty\")==0) {\n\n\t\t\t\t/* Get the parent with usb_interface devtype to retrieve the tty interface number */\n\t\t\t\tstruct udev_device *dev_interface = udev_device_get_parent_with_subsystem_devtype(\n\t\t\t\t\t\tdev,\n\t\t\t\t\t\t\"usb\",\n\t\t\t\t\t\t\"usb_interface\");\n\n\t\t\t\tif (dev_interface) {\n\t\t\t\t\tconst jobject interfaceNumber = get_interface_number(env, dev_interface);\n\t\t\t\t\tif (interfaceNumber == NULL) {\n\t\t\t\t\t\tudev_device_unref(dev);\n\t\t\t\t\t\tudev_enumerate_unref(enumerate);\n\t\t\t\t\t\tudev_unref(udev);\n\t\t\t\t\t\t(*env)->ReleaseStringUTFChars(env, deviceClass, nativeDeviceClass);\n\n\t\t\t\t\t\treturn NULL;\n\t\t\t\t\t}\n\t\t\t\t\tUsbDeviceObject = (*env)->NewObject(env, UsbDeviceClass, UsbDeviceConstructor,\n\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idVendor\")),\n\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idProduct\")),\n\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"manufacturer\")),\n\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"product\")),\n\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"busnum\")),\n\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"devpath\")),\n\t\t\t\t\t\t\tttyDeviceNode,\n\t\t\t\t\t\t\tinterfaceNumber);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t//add it to the ArrayList\n\t\t\tconst jboolean jbool = (*env)->CallBooleanMethod(env, objArr, mid_add, UsbDeviceObject);\n\n\t\t\tif ( JNI_FALSE == jbool ) {\n\t\t\t\t/* early clean up */\n\n\t\t\t\tudev_device_unref(dev);\n\t\t\t\tudev_enumerate_unref(enumerate);\n\t\t\t\tudev_unref(udev);\n\t\t\t\t(*env)->ReleaseStringUTFChars(env, deviceClass, nativeDeviceClass);\n\n\t\t\t\treturn objArr;\n\t\t\t}\n\n\t\t\tudev_device_unref(dev);\n\t\t}\n\t}\n\n\t/* Free the enumerator object */\n\tudev_enumerate_unref(enumerate);\n\tudev_unref(udev);\n\n\t/* release the nativeDeviceClass */\n\t(*env)->ReleaseStringUTFChars(env, deviceClass, nativeDeviceClass);\n\n\treturn objArr;\n}\n\nJNIEXPORT void JNICALL Java_org_eclipse_kura_linux_usb_LinuxUdevNative_nativeHotplugThread(JNIEnv *env, jclass LinuxUdevNative, jobject linuxUdevNative) {\n\n\tjclass UsbDeviceClass = NULL;\n\tjmethodID UsbDeviceConstructor = NULL;\n\tjobject UsbDeviceObject = NULL;\n\n\t//event type enum for return\n\tjstring eventType = NULL;\n\n\t//specifics for BLOCK devices\n\tjstring blockDeviceNode = NULL;\n\n\t//specifics for NET devices\n\tjstring interfaceName = NULL;\n\n\t//specifics for TTY devices\n\tjstring ttyDeviceNode = NULL;\n\n\tstruct udev *udev;\n\n\t/* Create the udev object */\n\tudev = udev_new();\n\tif (!udev) {\n\t\tprintf(\"Can't create udev\\n\");\n\t\tjclass Exception = (*env)->FindClass(env, \"java/lang/IOException\");\n\t\t(*env)->ThrowNew(env, Exception,\"Can't create udev object.\");\n\t}\n\n\t/* Set up a monitor to monitor selected USB devices */\n\tstruct udev_monitor *mon = udev_monitor_new_from_netlink(udev, \"udev\");\n\tudev_monitor_filter_add_match_subsystem_devtype(mon, \"block\", NULL);\n\tudev_monitor_filter_add_match_subsystem_devtype(mon, \"net\", NULL);\n\tudev_monitor_filter_add_match_subsystem_devtype(mon, \"tty\", NULL);\n\tudev_monitor_enable_receiving(mon);\n\t/* Get the file descriptor (fd) for the monitor.\n\t   This fd will get passed to select() */\n\tint fd = udev_monitor_get_fd(mon);\n\n\t/* This section will run continuously, calling usleep() at\n\t   the end of each pass. This is to demonstrate how to use\n\t   a udev_monitor in a non-blocking way. */\n\twhile (1) {\n\t\t/* Set up the call to select(). In this case, select() will\n\t\t   only operate on a single file descriptor, the one\n\t\t   associated with our udev_monitor. Note that the timeval\n\t\t   object is set to 0, which will cause select() to not\n\t\t   block. */\n\t\tfd_set fds;\n\t\tstruct timeval tv;\n\t\tint ret;\n\n\t\tFD_ZERO(&fds);\n\t\tFD_SET(fd, &fds);\n\t\ttv.tv_sec = 0;\n\t\ttv.tv_usec = 0;\n\n\t\tret = select(fd+1, &fds, NULL, NULL, &tv);\n\n\t\t/* Check if our file descriptor has received data. */\n\t\tif (ret > 0 && FD_ISSET(fd, &fds)) {\n\n\t\t\t/* Make the call to receive the device.\n\t\t\t   select() ensured that this will not block. */\n\t\t\tstruct udev_device *dev = udev_monitor_receive_device(mon);\n\t\t\tif (dev) {\n\t\t\t\tconst char *subsystem = udev_device_get_subsystem(dev);\n\n\t\t\t\tif(strcmp(subsystem,\"block\")==0) {\n\t\t\t\t\tblockDeviceNode = (*env)->NewStringUTF(env, udev_device_get_devnode(dev));\n\t\t\t\t} else if(strcmp(subsystem,\"net\")==0) {\n\t\t\t\t\tinterfaceName = (*env)->NewStringUTF(env, udev_device_get_sysname(dev));\n\t\t\t\t} else if(strcmp(subsystem,\"tty\")==0) {\n\t\t\t\t\tttyDeviceNode = (*env)->NewStringUTF(env, udev_device_get_devnode(dev));\n\t\t\t\t}\n\n\t\t\t\t//get the event type\n\t\t\t\tconst char *action = udev_device_get_action(dev);\n\t\t\t\tif(strcmp(\"add\",action)==0) {\n\t\t\t\t\teventType = (*env)->NewStringUTF(env, \"ATTACHED\");\n\t\t\t\t} else if(strcmp(\"remove\",action)==0) {\n\t\t\t\t\teventType = (*env)->NewStringUTF(env, \"DETACHED\");\n\t\t\t\t}\n\n\t\t\t\tstruct udev_device *dev_parent = udev_device_get_parent_with_subsystem_devtype(\n\t\t\t\t\t\tdev,\n\t\t\t\t\t\t\"usb\",\n\t\t\t\t\t\t\"usb_device\");\n\n\t\t\t\tif (dev_parent) {\n\t\t\t\t\tif(strcmp(subsystem,\"block\")==0) {\n\t\t\t\t\t\tUsbDeviceClass = (*env)->FindClass(env, \"org/eclipse/kura/usb/UsbBlockDevice\");\n\t\t\t\t\t\tif (UsbDeviceClass == NULL) {\n\t\t\t\t\t\t\tudev_device_unref(dev);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tUsbDeviceConstructor = (*env)->GetMethodID(env, UsbDeviceClass, \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\");\n\t\t\t\t\t\tif (UsbDeviceConstructor == NULL) {\n\t\t\t\t\t\t\tudev_device_unref(dev);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tUsbDeviceObject = (*env)->NewObject(env, UsbDeviceClass, UsbDeviceConstructor,\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idVendor\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idProduct\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"manufacturer\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"product\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"busnum\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"devpath\")),\n\t\t\t\t\t\t\t\tblockDeviceNode);\n\n\t\t\t\t\t\tjmethodID LinuxUdevNativeCallback = (*env)->GetMethodID(env, LinuxUdevNative, \"callback\", \"(Ljava/lang/String;Lorg/eclipse/kura/usb/UsbDevice;)V\");\n\t\t\t\t\t\t(*env)->CallVoidMethod(env, linuxUdevNative, LinuxUdevNativeCallback, eventType, UsbDeviceObject);\n\t\t\t\t\t} else if(strcmp(subsystem,\"net\")==0) {\n\t\t\t\t\t\tUsbDeviceClass = (*env)->FindClass(env, \"org/eclipse/kura/usb/UsbNetDevice\");\n\t\t\t\t\t\tif (UsbDeviceClass == NULL) {\n\t\t\t\t\t\t\tudev_device_unref(dev);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tUsbDeviceConstructor = (*env)->GetMethodID(env, UsbDeviceClass, \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\");\n\t\t\t\t\t\tif (UsbDeviceConstructor == NULL) {\n\t\t\t\t\t\t\tudev_device_unref(dev);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tUsbDeviceObject = (*env)->NewObject(env, UsbDeviceClass, UsbDeviceConstructor,\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idVendor\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idProduct\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"manufacturer\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"product\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"busnum\")),\n\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"devpath\")),\n\t\t\t\t\t\t\t\tinterfaceName);\n\n\t\t\t\t\t\tjmethodID LinuxUdevNativeCallback = (*env)->GetMethodID(env, LinuxUdevNative, \"callback\", \"(Ljava/lang/String;Lorg/eclipse/kura/usb/UsbDevice;)V\");\n\t\t\t\t\t\t(*env)->CallVoidMethod(env, linuxUdevNative, LinuxUdevNativeCallback, eventType, UsbDeviceObject);\n\t\t\t\t\t} else if(strcmp(subsystem,\"tty\")==0) {\n\t\t\t\t\t\tUsbDeviceClass = (*env)->FindClass(env, \"org/eclipse/kura/usb/UsbTtyDevice\");\n\t\t\t\t\t\tif (UsbDeviceClass == NULL) {\n\t\t\t\t\t\t\tudev_device_unref(dev);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/* Get the parent with usb_interface devtype to retrieve the tty interface number */\n\t\t\t\t\t\tstruct udev_device *dev_interface = udev_device_get_parent_with_subsystem_devtype(\n\t\t\t\t\t\t\t\tdev,\n\t\t\t\t\t\t\t\t\"usb\",\n\t\t\t\t\t\t\t\t\"usb_interface\");\n\n\t\t\t\t\t\tif (dev_interface) {\n\t\t\t\t\t\t\tUsbDeviceConstructor = (*env)->GetMethodID(env, UsbDeviceClass, \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V\");\n\t\t\t\t\t\t\tif (UsbDeviceConstructor == NULL) {\n\t\t\t\t\t\t\t\tudev_device_unref(dev);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst jobject interfaceNumber = get_interface_number(env, dev_interface);\n\t\t\t\t\t\t\tif (interfaceNumber == NULL) {\n\t\t\t\t\t\t\t\tudev_device_unref(dev);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tUsbDeviceObject = (*env)->NewObject(env, UsbDeviceClass, UsbDeviceConstructor,\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idVendor\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idProduct\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"manufacturer\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"product\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"busnum\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"devpath\")),\n\t\t\t\t\t\t\t\t\tttyDeviceNode,\n\t\t\t\t\t\t\t\t\tinterfaceNumber);\n\n\t\t\t\t\t\t\tjmethodID LinuxUdevNativeCallback = (*env)->GetMethodID(env, LinuxUdevNative, \"callback\", \"(Ljava/lang/String;Lorg/eclipse/kura/usb/UsbDevice;)V\");\n\t\t\t\t\t\t\t(*env)->CallVoidMethod(env, linuxUdevNative, LinuxUdevNativeCallback, eventType, UsbDeviceObject);\n\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t/* During detaching the usb_interface dev does not exists...*/\n\t\t\t\t\t\t\tUsbDeviceConstructor = (*env)->GetMethodID(env, UsbDeviceClass, \"<init>\", \"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V\");\n\t\t\t\t\t\t\tif (UsbDeviceConstructor == NULL) {\n\t\t\t\t\t\t\t\tudev_device_unref(dev);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tUsbDeviceObject = (*env)->NewObject(env, UsbDeviceClass, UsbDeviceConstructor,\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idVendor\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"idProduct\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"manufacturer\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"product\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"busnum\")),\n\t\t\t\t\t\t\t\t\t(*env)->NewStringUTF(env, udev_device_get_sysattr_value(dev_parent, \"devpath\")),\n\t\t\t\t\t\t\t\t\tttyDeviceNode);\n\n\t\t\t\t\t\t\tjmethodID LinuxUdevNativeCallback = (*env)->GetMethodID(env, LinuxUdevNative, \"callback\", \"(Ljava/lang/String;Lorg/eclipse/kura/usb/UsbDevice;)V\");\n\t\t\t\t\t\t\t(*env)->CallVoidMethod(env, linuxUdevNative, LinuxUdevNativeCallback, eventType, UsbDeviceObject);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tudev_device_unref(dev);\n\t\t\t} else {\n\t\t\t\tprintf(\"No Device from receive_device(). An error occured.\\n\");\n\t\t\t}\n\t\t}\n\t\tusleep(250*1000);\n\t}\n\n\tudev_unref(udev);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/LinuxUdev.h",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n *\n *  This program and the accompanying materials are made\n *  available under the terms of the Eclipse Public License 2.0\n *  which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n *  SPDX-License-Identifier: EPL-2.0\n *\n *  Contributors:\n *   Eurotech\n *******************************************************************************/\n\n#include \"org_eclipse_kura_linux_usb_LinuxUdevNative.h\"\n\n#include <libudev.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <locale.h>\n#include <unistd.h>\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/Makefile",
    "content": "\n# Copyright (c) 1999 - 2001, International Business Machines Corporation.\n# All Rights Reserved.\n#\n# This software is provided and licensed under the terms and conditions\n# of the Common Public License:\n# http://oss.software.ibm.com/developerworks/opensource/license-cpl.html\n\n# Makefile for Linux Ext Java Usb\n#\n# Dan Streetman\n#\n\n# Object and header dependencies - these are removed by 'make clean'\nOBJECTS = \\\n\tLinuxUdev.o\nHEADER = org_eclipse_kura_linux_usb_LinuxUdevNative.h\n\nCC = gcc\nCCLD = $(CC)\n\n#INCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux $(CINCLUDES)\nINCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I../java_home/include/ $(CINCLUDES)\n\nCFLAGS = -Wall -fPIC $(JUSB_FLAGS)\nSOFLAGS = -shared\n\nCOMPILE = $(CC) $(INCLUDES) $(CFLAGS)\nLINK = $(CCLD) $(CFLAGS) -ludev -o $@\n\n# This is the final shared library\nall: libEurotechLinuxUdev.so\n\n.SUFFIXES:\n.SUFFIXES: .c .o\n\n.c.o:\n\t$(COMPILE) -c $<\n\n# Build the shared library\nlibEurotechLinuxUdev.so: $(OBJECTS)\n\t@[ -n \"${JAVA_HOME}\" ] || (echo \"\";echo \"*** Please set your JAVA_HOME variable (I need the JNI headers!) ***\";echo \"\";exit 1)\n\t@[ -f ${HEADER} ] || (echo \"Could not find ${HEADER} header file!\";exit 1)\n\t@rm -f libEurotechLinuxUdev.so\n\t$(LINK) $(SOFLAGS) $(OBJECTS) -ludev\n\n# Cleanup all object and shared files and JAVAH-generated headers (not all headers!!)\nclean:\n\trm -f libEurotechLinuxUdev.so $(OBJECTS) *.o *.so\n#\trm -f libEurotechLinuxUdev.so $(OBJECTS) $(HEADER) *.o *.so\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/Makefile.aarch64",
    "content": "\n# Copyright (c) 1999 - 2001, International Business Machines Corporation.\n# All Rights Reserved.\n#\n# This software is provided and licensed under the terms and conditions\n# of the Common Public License:\n# http://oss.software.ibm.com/developerworks/opensource/license-cpl.html\n\n# Makefile for Linux Ext Java Usb\n#\n# Dan Streetman\n#\n\n# After libudev1 and libudev-dev installation, please move the libudev.h file in $(SYSROOT)/usr/include\nSYSROOT = /usr/bin/aarch64-unknown-linux-gnueabi/aarch64-unknown-linux-gnueabi/sysroot\n\n# Object and header dependencies - these are removed by 'make clean'\nOBJECTS = \\\n\tLinuxUdev.o\nHEADER = org_eclipse_kura_linux_usb_LinuxUdevNative.h\n\n#CC = gcc\nCCLD = $(CC)\n\n#INCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux $(CINCLUDES)\nINCLUDES = -I$(SYSROOT)/usr/include -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I../java_home/include/ $(CINCLUDES)\n\nCFLAGS = -Wall -fPIC $(JUSB_FLAGS)\nSOFLAGS = -shared\n\nCOMPILE = $(CC) --sysroot=$(SYSROOT) $(INCLUDES) $(CFLAGS)\nLINK = $(CCLD) -L/usr/lib/aarch64-linux-gnu $(CFLAGS) -ludev -o $@\n\n# This is the final shared library\nall: libEurotechLinuxUdev.so\n\n.SUFFIXES:\n.SUFFIXES: .c .o\n\n.c.o:\n\t$(COMPILE) -c $<\n\n# Build the shared library\nlibEurotechLinuxUdev.so: $(OBJECTS)\n\t@[ -n \"${JAVA_HOME}\" ] || (echo \"\";echo \"*** Please set your JAVA_HOME variable (I need the JNI headers!) ***\";echo \"\";exit 1)\n\t@[ -f ${HEADER} ] || (echo \"Could not find ${HEADER} header file!\";exit 1)\n\t@rm -f libEurotechLinuxUdev.so\n\t$(LINK) $(SOFLAGS) $(OBJECTS) -ludev\n\n# Cleanup all object and shared files and JAVAH-generated headers (not all headers!!)\nclean:\n\trm -f libEurotechLinuxUdev.so $(OBJECTS) *.o *.so\n#\trm -f libEurotechLinuxUdev.so $(OBJECTS) $(HEADER) *.o *.so\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/Makefile.poky.arm_hf",
    "content": "\n# Copyright (c) 1999 - 2001, International Business Machines Corporation.\n# All Rights Reserved.\n#\n# This software is provided and licensed under the terms and conditions\n# of the Common Public License:\n# http://oss.software.ibm.com/developerworks/opensource/license-cpl.html\n\n# Makefile for Linux Ext Java Usb\n#\n# Dan Streetman\n#\n\n# Object and header dependencies - these are removed by 'make clean'\nOBJECTS = \\\n\tLinuxUdev.o\nHEADER = org_eclipse_kura_linux_usb_LinuxUdevNative.h\n\n#CC = gcc\nCCLD = $(CC)\n\nINCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux $(CINCLUDES)\n\nCFLAGS += -Wall -fPIC $(JUSB_FLAGS)\nSOFLAGS = -shared\n\nCOMPILE = $(CC) $(INCLUDES) $(CFLAGS)\nLINK = $(CCLD) $(CFLAGS) -ludev -o $@\n\n# This is the final shared library\nall: libEurotechLinuxUdev.so\n\n.SUFFIXES:\n.SUFFIXES: .c .o\n\n.c.o:\n\t$(COMPILE) -c $<\n\n# Build the shared library\nlibEurotechLinuxUdev.so: $(OBJECTS)\n\t@[ -n \"${JAVA_HOME}\" ] || (echo \"\";echo \"*** Please set your JAVA_HOME variable (I need the JNI headers!) ***\";echo \"\";exit 1)\n\t@[ -f ${HEADER} ] || (echo \"Could not find ${HEADER} header file!\";exit 1)\n\t@rm -f libEurotechLinuxUdev.so\n\t$(LINK) $(SOFLAGS) $(OBJECTS) -ludev\n\n# Cleanup all object and shared files and JAVAH-generated headers (not all headers!!)\nclean:\n\trm -f libEurotechLinuxUdev.so $(OBJECTS) *.o *.so\n#\trm -f libEurotechLinuxUdev.so $(OBJECTS) $(HEADER) *.o *.so\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/Makefile.poky.arm_sf",
    "content": "\n# Copyright (c) 1999 - 2001, International Business Machines Corporation.\n# All Rights Reserved.\n#\n# This software is provided and licensed under the terms and conditions\n# of the Common Public License:\n# http://oss.software.ibm.com/developerworks/opensource/license-cpl.html\n\n# Makefile for Linux Ext Java Usb\n#\n# Dan Streetman\n#\n\n# Object and header dependencies - these are removed by 'make clean'\nOBJECTS = \\\n\tLinuxUdev.o\nHEADER = org_eclipse_kura_linux_usb_LinuxUdevNative.h\n\n#CC = gcc\nCCLD = $(CC)\n\nINCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux $(CINCLUDES)\n\nCFLAGS += -msoft-float -Wall -fPIC $(JUSB_FLAGS)\nSOFLAGS = -shared\n\nCOMPILE = $(CC) $(INCLUDES) $(CFLAGS)\nLINK = $(CCLD) $(CFLAGS) -ludev -o $@\n\n# This is the final shared library\nall: libEurotechLinuxUdev.so\n\n.SUFFIXES:\n.SUFFIXES: .c .o\n\n.c.o:\n\t$(COMPILE) -c $<\n\n# Build the shared library\nlibEurotechLinuxUdev.so: $(OBJECTS)\n\t@[ -n \"${JAVA_HOME}\" ] || (echo \"\";echo \"*** Please set your JAVA_HOME variable (I need the JNI headers!) ***\";echo \"\";exit 1)\n\t@[ -f ${HEADER} ] || (echo \"Could not find ${HEADER} header file!\";exit 1)\n\t@rm -f libEurotechLinuxUdev.so\n\t$(LINK) $(SOFLAGS) $(OBJECTS) -ludev\n\n# Cleanup all object and shared files and JAVAH-generated headers (not all headers!!)\nclean:\n\trm -f libEurotechLinuxUdev.so $(OBJECTS) *.o *.so\n#\trm -f libEurotechLinuxUdev.so $(OBJECTS) $(HEADER) *.o *.so\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/Makefile.poky.i586",
    "content": "\n# Copyright (c) 1999 - 2001, International Business Machines Corporation.\n# All Rights Reserved.\n#\n# This software is provided and licensed under the terms and conditions\n# of the Common Public License:\n# http://oss.software.ibm.com/developerworks/opensource/license-cpl.html\n\n# Makefile for Linux Ext Java Usb\n#\n# Dan Streetman\n#\n\n# Object and header dependencies - these are removed by 'make clean'\nOBJECTS = \\\n\tLinuxUdev.o\nHEADER = org_eclipse_kura_linux_usb_LinuxUdevNative.h\n\n#CC = gcc\nCCLD = $(CC)\n\nINCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux $(CINCLUDES)\n\nCFLAGS += -Wall -fPIC $(JUSB_FLAGS)\nSOFLAGS = -shared\n\nCOMPILE = $(CC) $(INCLUDES) $(CFLAGS)\nLINK = $(CCLD) $(CFLAGS) -ludev -o $@\n\n# This is the final shared library\nall: libEurotechLinuxUdev.so\n\n.SUFFIXES:\n.SUFFIXES: .c .o\n\n.c.o:\n\t$(COMPILE) -c $<\n\n# Build the shared library\nlibEurotechLinuxUdev.so: $(OBJECTS)\n\t@[ -n \"${JAVA_HOME}\" ] || (echo \"\";echo \"*** Please set your JAVA_HOME variable (I need the JNI headers!) ***\";echo \"\";exit 1)\n\t@[ -f ${HEADER} ] || (echo \"Could not find ${HEADER} header file!\";exit 1)\n\t@rm -f libEurotechLinuxUdev.so\n\t$(LINK) $(SOFLAGS) $(OBJECTS) -ludev\n\n# Cleanup all object and shared files and JAVAH-generated headers (not all headers!!)\nclean:\n\trm -f libEurotechLinuxUdev.so $(OBJECTS) *.o *.so\n#\trm -f libEurotechLinuxUdev.so $(OBJECTS) $(HEADER) *.o *.so\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/Makefile.poky.x86_64",
    "content": "\n# Copyright (c) 1999 - 2001, International Business Machines Corporation.\n# All Rights Reserved.\n#\n# This software is provided and licensed under the terms and conditions\n# of the Common Public License:\n# http://oss.software.ibm.com/developerworks/opensource/license-cpl.html\n\n# Makefile for Linux Ext Java Usb\n#\n# Dan Streetman\n#\n\n# Object and header dependencies - these are removed by 'make clean'\nOBJECTS = \\\n\tLinuxUdev.o\nHEADER = org_eclipse_kura_linux_usb_LinuxUdevNative.h\n\n#CC = gcc\nCCLD = $(CC)\n\nINCLUDES = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux $(CINCLUDES)\n\nCFLAGS += -Wall -fPIC $(JUSB_FLAGS)\nSOFLAGS = -shared\n\nCOMPILE = $(CC) $(INCLUDES) $(CFLAGS)\nLINK = $(CCLD) $(CFLAGS) -ludev -o $@\n\n# This is the final shared library\nall: libEurotechLinuxUdev.so\n\n.SUFFIXES:\n.SUFFIXES: .c .o\n\n.c.o:\n\t$(COMPILE) -c $<\n\n# Build the shared library\nlibEurotechLinuxUdev.so: $(OBJECTS)\n\t@[ -n \"${JAVA_HOME}\" ] || (echo \"\";echo \"*** Please set your JAVA_HOME variable (I need the JNI headers!) ***\";echo \"\";exit 1)\n\t@[ -f ${HEADER} ] || (echo \"Could not find ${HEADER} header file!\";exit 1)\n\t@rm -f libEurotechLinuxUdev.so\n\t$(LINK) $(SOFLAGS) $(OBJECTS) -ludev\n\n# Cleanup all object and shared files and JAVAH-generated headers (not all headers!!)\nclean:\n\trm -f libEurotechLinuxUdev.so $(OBJECTS) *.o *.so\n#\trm -f libEurotechLinuxUdev.so $(OBJECTS) $(HEADER) *.o *.so\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/c/udev/org_eclipse_kura_linux_usb_LinuxUdevNative.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n/* Header for class org_eclipse_kura_linux_usb_LinuxUdevNative */\n\n#ifndef _Included_org_eclipse_kura_linux_usb_LinuxUdevNative\n#define _Included_org_eclipse_kura_linux_usb_LinuxUdevNative\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     org_eclipse_kura_linux_usb_LinuxUdevNative\n * Method:    nativeHotplugThread\n * Signature: (Lorg/eclipse/kura/linux/usb/LinuxUdevNative;)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_kura_linux_usb_LinuxUdevNative_nativeHotplugThread\n  (JNIEnv *, jclass, jobject);\n\n/*\n * Class:     org_eclipse_kura_linux_usb_LinuxUdevNative\n * Method:    getUsbDevices\n * Signature: (Ljava/lang/String;)Ljava/util/ArrayList;\n */\nJNIEXPORT jobject JNICALL Java_org_eclipse_kura_linux_usb_LinuxUdevNative_getUsbDevices\n  (JNIEnv *, jclass, jstring);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/java/org/eclipse/kura/linux/usb/LinuxUdevNative.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.usb;\n\nimport java.io.IOException;\nimport java.security.AccessController;\nimport java.security.PrivilegedAction;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.linux.udev.LinuxUdevListener;\nimport org.eclipse.kura.linux.udev.UdevEventType;\nimport org.eclipse.kura.usb.UsbBlockDevice;\nimport org.eclipse.kura.usb.UsbDevice;\nimport org.eclipse.kura.usb.UsbNetDevice;\nimport org.eclipse.kura.usb.UsbTtyDevice;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@SuppressWarnings({ \"unchecked\", \"rawtypes\" })\npublic class LinuxUdevNative {\n\n    private static final Logger logger = LoggerFactory.getLogger(LinuxUdevNative.class);\n\n    private static final String LIBRARY_NAME = \"EurotechLinuxUdev\";\n    private static final long THREAD_TERMINATION_TOUT = 1; // in seconds\n    private static final String UNABLE_TO_LOAD_ERROR = \"Unable to load: \";\n    private static final String UNKNOWN_UDEV_EVENT = \"Unknown udev event: {}\";\n\n    static {\n        try {\n            AccessController.doPrivileged((PrivilegedAction) LinuxUdevNative::loadUdevLibrary);\n        } catch (Exception e) {\n            logger.error(UNABLE_TO_LOAD_ERROR + LIBRARY_NAME);\n        }\n    }\n\n    private static Object loadUdevLibrary() {\n        try {\n            System.loadLibrary(LIBRARY_NAME);\n        } catch (Exception e) {\n            logger.error(UNABLE_TO_LOAD_ERROR + LIBRARY_NAME);\n        }\n        return null;\n    }\n\n    private boolean started;\n    private Future<?> task;\n    private ScheduledExecutorService executor;\n\n    private LinuxUdevListener linuxUdevListener;\n    private LinuxUdevNative linuxUdevNativeInstance;\n\n    /*\n     * Devices by their device node (e.g. ttyACM3 or sdb1) or interface name (e.g. usb1).\n     */\n    private static HashMap<String, UsbBlockDevice> blockDevices = new HashMap<>();\n    private static HashMap<String, UsbNetDevice> netDevices = new HashMap<>();\n    private static HashMap<String, UsbTtyDevice> ttyDevices = new HashMap<>();\n\n    public LinuxUdevNative(LinuxUdevListener linuxUdevListener) throws IOException {\n        if (!this.started) {\n            this.linuxUdevNativeInstance = this;\n            this.linuxUdevListener = linuxUdevListener;\n\n            /* Assume we get some \"good\" devices here */\n            List<UsbBlockDevice> usbBlockDevices = (List<UsbBlockDevice>) LinuxUdevNative.getUsbDevices(\"block\");\n            if (usbBlockDevices != null) {\n                for (UsbBlockDevice blockDevice : usbBlockDevices) {\n                    blockDevices.put(blockDevice.getDeviceNode(), blockDevice);\n                }\n            }\n\n            List<UsbNetDevice> usbNetDevices = (List<UsbNetDevice>) LinuxUdevNative.getUsbDevices(\"net\");\n            if (usbNetDevices != null) {\n                for (UsbNetDevice netDevice : usbNetDevices) {\n                    netDevices.put(netDevice.getInterfaceName(), netDevice);\n                }\n            }\n\n            List<UsbTtyDevice> usbTtyDevices = (List<UsbTtyDevice>) LinuxUdevNative.getUsbDevices(\"tty\");\n            if (usbTtyDevices != null) {\n                for (UsbTtyDevice ttyDevice : usbTtyDevices) {\n                    ttyDevices.put(ttyDevice.getDeviceNode(), ttyDevice);\n                }\n            }\n\n            start();\n            this.started = true;\n        }\n    }\n\n    public void unbind() {\n        if (this.task != null && !this.task.isDone()) {\n            logger.debug(\"Cancelling LinuxUdevNative task ...\");\n            this.task.cancel(true);\n            logger.info(\"LinuxUdevNative task cancelled? = {}\", this.task.isDone());\n            this.task = null;\n        }\n        if (this.executor != null) {\n            logger.debug(\"Terminating LinuxUdevNative Thread ...\");\n            this.executor.shutdownNow();\n            try {\n                this.executor.awaitTermination(THREAD_TERMINATION_TOUT, TimeUnit.SECONDS);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                logger.warn(\"Interrupted\", e);\n            }\n            logger.info(\"LinuxUdevNative Thread terminated? - {}\", this.executor.isTerminated());\n            this.executor = null;\n        }\n        this.started = false;\n    }\n\n    public static List<UsbBlockDevice> getUsbBlockDevices() {\n        return new ArrayList<>(blockDevices.values());\n    }\n\n    public static List<UsbNetDevice> getUsbNetDevices() {\n        return new ArrayList<>(netDevices.values());\n    }\n\n    public static List<UsbTtyDevice> getUsbTtyDevices() {\n        return new ArrayList<>(ttyDevices.values());\n    }\n\n    private static native void nativeHotplugThread(LinuxUdevNative linuxUdevNative) throws IOException;\n\n    private static native ArrayList<? extends UsbDevice> getUsbDevices(String deviceClass) throws IOException;\n\n    /*\n     * WARNING\n     *\n     * The callback does not fire for devices open by a process\n     * when the device is unplugged from the USB.\n     * Note that `udevadm monitor' correctly reports removal of these devices so there\n     * must be something wrong with our native code using libudev.\n     *\n     * On top of that information for detached (UdevEventType.DETACHED) devices is completely unreliable:\n     * missing manufacturer and product names, wrong VID&PID (often the one of the\n     * USB hub the device was attached to), wrong USB path (often the path of the USB hub\n     * the device was attached to).\n     * The only reliable information seems to be the device node name, e.g. ttyACM0.\n     *\n     * Information for devices being attached (UdevEventType.ATTACHED) seems to work more reliably.\n     * The callback might still fire with wrong/incomplete information but EVENTUALLY\n     * we get all the devices with the right information.\n     *\n     */\n    private void callback(String type, UsbDevice usbDevice) {\n\n        logger.debug(\"TYPE: {}\", usbDevice.getClass());\n        logger.debug(\"\\tmanfufacturer name: {}\", usbDevice.getManufacturerName());\n        logger.debug(\"\\tproduct name: {}\", usbDevice.getProductName());\n        logger.debug(\"\\tvendor ID: {}\", usbDevice.getVendorId());\n        logger.debug(\"\\tproduct ID: {}\", usbDevice.getProductId());\n        logger.debug(\"\\tUSB Bus Number: {}\", usbDevice.getUsbBusNumber());\n\n        if (usbDevice instanceof UsbBlockDevice) {\n            manageUsbBlockDevice(type, usbDevice);\n        } else if (usbDevice instanceof UsbNetDevice) {\n            manageUsbNetDevice(type, usbDevice);\n        } else if (usbDevice instanceof UsbTtyDevice) {\n            manageUsbTtyDevice(type, usbDevice);\n        }\n    }\n\n    private void manageUsbTtyDevice(String type, UsbDevice usbDevice) {\n        String name = ((UsbTtyDevice) usbDevice).getDeviceNode();\n        if (name != null) {\n            if (type.compareTo(UdevEventType.ATTACHED.name()) == 0) {\n                UsbTtyDevice ttyDevice = (UsbTtyDevice) usbDevice;\n                ttyDevices.put(name, ttyDevice);\n                this.linuxUdevListener.attached(ttyDevice);\n            } else if (type.compareTo(UdevEventType.DETACHED.name()) == 0) {\n                UsbTtyDevice removedDevice = ttyDevices.remove(name);\n                if (removedDevice != null) {\n                    this.linuxUdevListener.detached(removedDevice);\n                }\n            } else {\n                logger.debug(UNKNOWN_UDEV_EVENT, type);\n            }\n        }\n    }\n\n    private void manageUsbNetDevice(String type, UsbDevice usbDevice) {\n        String name = ((UsbNetDevice) usbDevice).getInterfaceName();\n        if (name != null) {\n            if (type.compareTo(UdevEventType.ATTACHED.name()) == 0) {\n                netDevices.put(name, (UsbNetDevice) usbDevice);\n                this.linuxUdevListener.attached(usbDevice);\n            } else if (type.compareTo(UdevEventType.DETACHED.name()) == 0) {\n                UsbNetDevice removedDevice = netDevices.remove(name);\n                if (removedDevice != null) {\n                    this.linuxUdevListener.detached(removedDevice);\n                }\n            } else {\n                logger.debug(UNKNOWN_UDEV_EVENT, type);\n            }\n        }\n    }\n\n    private void manageUsbBlockDevice(String type, UsbDevice usbDevice) {\n        String name = ((UsbBlockDevice) usbDevice).getDeviceNode();\n        if (name != null) {\n            if (type.compareTo(UdevEventType.ATTACHED.name()) == 0) {\n                /*\n                 * FIXME: does an already existing device, with the same name,\n                 * need to be removed first?\n                 */\n                blockDevices.put(name, (UsbBlockDevice) usbDevice);\n                this.linuxUdevListener.attached(usbDevice);\n            } else if (type.compareTo(UdevEventType.DETACHED.name()) == 0) {\n                /*\n                 * Due to the above limitations,\n                 * the best we can do is to remove the device from the\n                 * map of already known devices by its name.\n                 */\n                UsbBlockDevice removedDevice = blockDevices.remove(name);\n                if (removedDevice != null) {\n                    this.linuxUdevListener.detached(removedDevice);\n                }\n            } else {\n                logger.debug(UNKNOWN_UDEV_EVENT, type);\n            }\n        }\n    }\n\n    /** Start this Hotplug Thread. */\n    private void start() {\n\n        this.executor = Executors.newSingleThreadScheduledExecutor(r -> {\n            Thread thread = new Thread(r, \"UdevHotplugThread\");\n            thread.setDaemon(true);\n            return thread;\n        });\n\n        this.task = this.executor.submit(() -> {\n            logger.info(\"Starting LinuxUdevNative Thread ...\");\n            Thread.currentThread().setName(\"LinuxUdevNative\");\n            try {\n                LinuxUdevNative.nativeHotplugThread(LinuxUdevNative.this.linuxUdevNativeInstance);\n            } catch (Exception e) {\n                logger.error(\"Starting LinuxUdevNative failed\", e);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/java/org/eclipse/kura/linux/usb/UsbSerial.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.usb;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.StringTokenizer;\n\npublic class UsbSerial {\n\n    private static final String FILENAME = \"/proc/tty/driver/usbserial\";\n\n    private static ArrayList<UsbSerialEntry> entries = null;\n\n    private UsbSerial() {\n\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see org.eclipse.kura.device.usb.usbmanager.usbserial.service.IUsbSerialService#getInfo()\n     */\n    private static void getInfo() throws IOException {\n\n        try (FileReader fr = new FileReader(FILENAME);\n                BufferedReader in = new BufferedReader(fr);) {\n            entries = new ArrayList<>();\n\n            int ttyUsbNo = 0;\n            String vendor = null;\n            String product = null;\n            int numPorts = 0;\n            int portEnum = 0;\n            String path = null;\n\n            String line = in.readLine(); // read first line (do not need to parse it)\n            while ((line = in.readLine()) != null) {\n\n                ttyUsbNo = Integer.parseInt(line.substring(0, line.indexOf(':')));\n                line = line.substring(line.indexOf(\"vendor:\"));\n                StringTokenizer st = new StringTokenizer(line, \" \");\n                while (st.hasMoreTokens()) {\n                    String token = st.nextToken();\n                    if (token.startsWith(\"vendor:\")) {\n                        vendor = token.substring(token.indexOf(':') + 1).trim();\n                    }\n                    if (token.startsWith(\"product:\")) {\n                        product = token.substring(token.indexOf(':') + 1).trim();\n                    }\n                    if (token.startsWith(\"num_ports:\")) {\n                        numPorts = Integer.parseInt(token.substring(token.indexOf(':') + 1).trim());\n                    }\n                    if (token.startsWith(\"port:\")) {\n                        portEnum = Integer.parseInt(token.substring(token.indexOf(':') + 1).trim());\n                    }\n                    if (token.startsWith(\"path:\")) {\n                        path = token.substring(token.indexOf(':') + 1).trim();\n                    }\n                }\n                entries.add(new UsbSerialEntry(ttyUsbNo, vendor, product, numPorts, portEnum, path));\n            }\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see\n     * org.eclipse.kura.device.usb.usbmanager.usbserial.service.IUsbSerialService#getUsbSerialEntries(java.lang.String,\n     * java.lang.String)\n     */\n    public static ArrayList<UsbSerialEntry> getUsbSerialEntries(String vendor, String product) throws Exception {\n\n        getInfo();\n\n        UsbSerialEntry entry = null;\n        ArrayList<UsbSerialEntry> matches = new ArrayList<>();\n\n        for (int i = 0; i < entries.size(); i++) {\n            entry = entries.get(i);\n            if (entry.getVendorID().compareTo(vendor) == 0 && entry.getProductID().compareTo(product) == 0) {\n                matches.add(entry);\n            }\n        }\n\n        return matches;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/java/org/eclipse/kura/linux/usb/UsbSerialEntry.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.usb;\n\npublic class UsbSerialEntry {\n\n    private int ttyUsbPortNo = 0;\n    private String vendorID = null;\n    private String productID = null;\n    private int numberOfPorts = 0;\n    private int portEnumeration = 0;\n    private String path2usbDevice = null;\n\n    /**\n     * UsbSerialEntry constructor\n     *\n     * @param ttyUsbPortNo\n     *            - ttyUSB port number\n     * @param vendor\n     *            - vendor ID\n     * @param product\n     *            - product ID\n     * @param portEnum\n     *            - port enumeration\n     * @param path\n     *            - path to USB device\n     */\n    public UsbSerialEntry(int ttyUsbPortNo, String vendor, String product, int numPorts, int portEnum, String path) {\n\n        this.ttyUsbPortNo = ttyUsbPortNo;\n        this.vendorID = vendor;\n        this.productID = product;\n        this.numberOfPorts = numPorts;\n        this.portEnumeration = portEnum;\n        this.path2usbDevice = path;\n    }\n\n    /**\n     * Reports ttyUSB port number\n     *\n     * @return ttyUSB port number as <code>int</code>\n     */\n    public int getTtyUsbPortNo() {\n        return this.ttyUsbPortNo;\n    }\n\n    /**\n     * Reports vendor ID\n     *\n     * @return vendor ID as <code>String</code>\n     */\n    public String getVendorID() {\n        return this.vendorID;\n    }\n\n    /**\n     * Reports product ID\n     *\n     * @return product ID as <code>String</code>\n     */\n    public String getProductID() {\n        return this.productID;\n    }\n\n    /**\n     * Reports total number of ports.\n     *\n     * @return number of ports as <code>int</code>\n     */\n    public int getNumberOfPorts() {\n        return this.numberOfPorts;\n    }\n\n    /**\n     * Reports port enumeration\n     *\n     * @return port enumeration as <code>int</code>\n     */\n    public int getPortEnumeration() {\n        return this.portEnumeration;\n    }\n\n    /**\n     * Reports path to USB device\n     *\n     * @return path to USB device as <code>String</code>\n     */\n    public String getPath2usbDevice() {\n        return this.path2usbDevice;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb/src/main/java/org/eclipse/kura/linux/usb/UsbServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.usb;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.usb.UsbException;\nimport javax.usb.UsbHostManager;\nimport javax.usb.UsbServices;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.linux.udev.LinuxUdevListener;\nimport org.eclipse.kura.usb.UsbBlockDevice;\nimport org.eclipse.kura.usb.UsbDevice;\nimport org.eclipse.kura.usb.UsbDeviceAddedEvent;\nimport org.eclipse.kura.usb.UsbDeviceEvent;\nimport org.eclipse.kura.usb.UsbDeviceRemovedEvent;\nimport org.eclipse.kura.usb.UsbDeviceType;\nimport org.eclipse.kura.usb.UsbNetDevice;\nimport org.eclipse.kura.usb.UsbService;\nimport org.eclipse.kura.usb.UsbTtyDevice;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.component.ComponentException;\nimport org.osgi.service.event.EventAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class UsbServiceImpl implements UsbService, LinuxUdevListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(UsbServiceImpl.class);\n\n    private LinuxUdevNative linuxUdevNative;\n    private EventAdmin eventAdmin;\n\n    protected void activate(ComponentContext componentContext) {\n        // only support Linux\n        String osName = System.getProperty(\"os.name\");\n        String osVersion = System.getProperty(\"os.version\");\n        if (osName.equals(\"Linux\")) {\n            try {\n                this.linuxUdevNative = new LinuxUdevNative(this);\n            } catch (IOException e) {\n                logger.error(\"Udev native can't be instantiated\");\n            }\n        } else {\n            logger.error(\"This is not Linux! - can not start the USB service.  This is {}\", osVersion);\n            throw new ComponentException(\"This is not Linux! - can not start the USB service.  This is \" + osVersion);\n        }\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        this.linuxUdevNative.unbind();\n        this.linuxUdevNative = null;\n    }\n\n    public void setEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = eventAdmin;\n    }\n\n    public void unsetEventAdmin(EventAdmin eventAdmin) {\n        this.eventAdmin = null;\n    }\n\n    @Override\n    public UsbServices getUsbServices() throws KuraException {\n        try {\n            return UsbHostManager.getUsbServices();\n        } catch (SecurityException e) {\n            throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION, e, (Object[]) null);\n        } catch (UsbException e) {\n            throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e, (Object[]) null);\n        }\n    }\n\n    @Override\n    public synchronized List<? extends UsbDevice> getUsbDevices() {\n        List<UsbDevice> usbDevices = new ArrayList<>();\n        usbDevices.addAll(getUsbBlockDevices());\n        usbDevices.addAll(getUsbNetDevices());\n        usbDevices.addAll(getUsbTtyDevices());\n\n        return usbDevices;\n    }\n\n    @Override\n    public synchronized List<UsbBlockDevice> getUsbBlockDevices() {\n        return LinuxUdevNative.getUsbBlockDevices();\n    }\n\n    @Override\n    public synchronized List<UsbNetDevice> getUsbNetDevices() {\n        return LinuxUdevNative.getUsbNetDevices();\n    }\n\n    @Override\n    public synchronized List<UsbTtyDevice> getUsbTtyDevices() {\n        return LinuxUdevNative.getUsbTtyDevices();\n    }\n\n    @Override\n    public synchronized void attached(UsbDevice device) {\n        logger.debug(\"firing UsbDeviceAddedEvent for: {}\", device);\n        Map<String, Object> map = new HashMap<>();\n        map.put(UsbDeviceEvent.USB_EVENT_USB_PORT_PROPERTY, device.getUsbPort());\n        map.put(UsbDeviceEvent.USB_EVENT_VENDOR_ID_PROPERTY, device.getVendorId());\n        map.put(UsbDeviceEvent.USB_EVENT_PRODUCT_ID_PROPERTY, device.getProductId());\n        map.put(UsbDeviceEvent.USB_EVENT_MANUFACTURER_NAME_PROPERTY, device.getManufacturerName());\n        map.put(UsbDeviceEvent.USB_EVENT_PRODUCT_NAME_PROPERTY, device.getProductName());\n        map.put(UsbDeviceEvent.USB_EVENT_BUS_NUMBER_PROPERTY, device.getUsbBusNumber());\n        map.put(UsbDeviceEvent.USB_EVENT_DEVICE_PATH_PROPERTY, device.getUsbDevicePath());\n\n        if (device instanceof UsbBlockDevice) {\n            map.put(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY, ((UsbBlockDevice) device).getDeviceNode());\n            map.put(UsbDeviceEvent.USB_EVENT_DEVICE_TYPE_PROPERTY, UsbDeviceType.USB_BLOCK_DEVICE);\n        } else if (device instanceof UsbNetDevice) {\n            map.put(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY, ((UsbNetDevice) device).getInterfaceName());\n            map.put(UsbDeviceEvent.USB_EVENT_DEVICE_TYPE_PROPERTY, UsbDeviceType.USB_NET_DEVICE);\n        } else if (device instanceof UsbTtyDevice) {\n            map.put(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY, ((UsbTtyDevice) device).getDeviceNode());\n            map.put(UsbDeviceEvent.USB_EVENT_USB_INTERFACE_NUMBER, ((UsbTtyDevice) device).getInterfaceNumber());\n            map.put(UsbDeviceEvent.USB_EVENT_DEVICE_TYPE_PROPERTY, UsbDeviceType.USB_TTY_DEVICE);\n        }\n\n        this.eventAdmin.postEvent(new UsbDeviceAddedEvent(map));\n    }\n\n    @Override\n    public synchronized void detached(UsbDevice device) {\n        logger.debug(\"firing UsbDeviceRemovedEvent for: {}\", device);\n        Map<String, Object> map = new HashMap<>();\n        map.put(UsbDeviceEvent.USB_EVENT_USB_PORT_PROPERTY, device.getUsbPort());\n        map.put(UsbDeviceEvent.USB_EVENT_VENDOR_ID_PROPERTY, device.getVendorId());\n        map.put(UsbDeviceEvent.USB_EVENT_PRODUCT_ID_PROPERTY, device.getProductId());\n        map.put(UsbDeviceEvent.USB_EVENT_MANUFACTURER_NAME_PROPERTY, device.getManufacturerName());\n        map.put(UsbDeviceEvent.USB_EVENT_PRODUCT_NAME_PROPERTY, device.getProductName());\n        map.put(UsbDeviceEvent.USB_EVENT_BUS_NUMBER_PROPERTY, device.getUsbBusNumber());\n        map.put(UsbDeviceEvent.USB_EVENT_DEVICE_PATH_PROPERTY, device.getUsbDevicePath());\n\n        if (device instanceof UsbBlockDevice) {\n            map.put(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY, ((UsbBlockDevice) device).getDeviceNode());\n            map.put(UsbDeviceEvent.USB_EVENT_DEVICE_TYPE_PROPERTY, UsbDeviceType.USB_BLOCK_DEVICE);\n        } else if (device instanceof UsbNetDevice) {\n            map.put(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY, ((UsbNetDevice) device).getInterfaceName());\n            map.put(UsbDeviceEvent.USB_EVENT_DEVICE_TYPE_PROPERTY, UsbDeviceType.USB_NET_DEVICE);\n        } else if (device instanceof UsbTtyDevice) {\n            map.put(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY, ((UsbTtyDevice) device).getDeviceNode());\n            map.put(UsbDeviceEvent.USB_EVENT_DEVICE_TYPE_PROPERTY, UsbDeviceType.USB_TTY_DEVICE);\n        }\n\n        this.eventAdmin.postEvent(new UsbDeviceRemovedEvent(map));\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.aarch64/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.aarch64/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Native libraries for 'org.eclipse.kura.linux.usb' on ARM 64\nBundle-SymbolicName: org.eclipse.kura.linux.usb.aarch64\nBundle-Version: 2.0.0.qualifier\nFragment-Host: org.eclipse.kura.linux.usb;bundle-version=\"[2.0.0,3.0.0)\"\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-NativeCode: lib/linux/libEurotechLinuxUdev.so; osname=Linux; processor=aarch64\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.aarch64/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.aarch64/build.properties",
    "content": "bin.includes = META-INF/,\\\n               .,\\\n               about.html,\\\n               lib/\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.aarch64/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2016, 2024 Red Hat Inc and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Red Hat Inc - Initial API and implementation\n     Cavium\n     \n-->\n<project\n    xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.linux.usb.aarch64</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t</properties>\n\t\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n                <configuration>\n                    <environments>\n                        <environment>\n                            <os>linux</os>\n                            <ws>gtk</ws>\n                            <arch>aarch64</arch>\n                        </environment>\n                    </environments>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.x86_64/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.x86_64/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Native libraries for 'org.eclipse.kura.linux.usb' on x86_64\nBundle-SymbolicName: org.eclipse.kura.linux.usb.x86_64\nBundle-Version: 2.0.0.qualifier\nFragment-Host: org.eclipse.kura.linux.usb;bundle-version=\"[2.0.0,3.0.0)\"\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-NativeCode: lib/linux/libEurotechLinuxUdev.so; osname=Linux; processor=x86-64\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.x86_64/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.x86_64/build.properties",
    "content": "bin.includes = META-INF/,\\\n               .,\\\n               about.html,\\\n               lib/\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.usb.x86_64/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2016, 2024 Red Hat Inc and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Red Hat Inc\n\n-->\n<project\n    xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.linux.usb.x86_64</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t</properties>\n\t\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n                <configuration>\n                    <environments>\n                        <environment>\n                            <os>linux</os>\n                            <ws>gtk</ws>\n                            <arch>x86_64</arch>\n                        </environment>\n                    </environments>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/.gitignore",
    "content": "/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.linux.watchdog\nBundle-SymbolicName: org.eclipse.kura.linux.watchdog;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.watchdog;version=\"[1.0,1.1)\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/OSGI-INF/metatype/org.eclipse.kura.watchdog.WatchdogService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.watchdog.WatchdogService\"\n         name=\"WatchdogService\" \n         description=\"The WatchdogService handles the hardware watchdog of the platform.  The parameter define the ping periodicity of the hardware watchdog to ensure it does not reboot. The WatchdogService will reset the watchdog timeout, can disable it (where supported) with the Magic Character, but cannot set the refresh rate of a watchdog device.\">\n        \n        <Icon resource=\"WatchdogService\" size=\"32\"/>\n        \n        <AD id=\"enabled\"  \n            name=\"Watchdog enable\"\n            type=\"Boolean\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"false\" \n            description=\"The WatchdogService monitors CriticalComponents and reboots the system if one of them hangs. Once enabled the WatchdogService starts refreshing the watchdog device, which will reset the system if WatchdogService hangs.\"/>\n        \n        <AD id=\"pingInterval\"\n            name=\"Watchdog refresh interval\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"10000\"\n            max=\"60000\"\n            description=\"WatchdogService's refresh interval in ms of the Watchdog device. The value can be set between 1 and 60 seconds and should not be set to a value greater or equal to the Watchdog device's timeout value\"/>\n\n        <AD id=\"watchdogDevice\"\n            name=\"Watchdog device path\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"/dev/watchdog\"\n            description=\"Watchdog device path e.g. /dev/watchdog.\"/>\n            \n        <AD id=\"rebootCauseFilePath\"\n            name=\"Reboot Cause File Path\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"/opt/eclipse/kura/data/kura-reboot-cause\"\n            description=\"The path for the file that will contain the reboot cause information.\"/>\n            \n    </OCD>\n    <Designate pid=\"org.eclipse.kura.watchdog.WatchdogService\">\n        <Object ocdref=\"org.eclipse.kura.watchdog.WatchdogService\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/OSGI-INF/watchdog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.watchdog.WatchdogService\">\n   <implementation class=\"org.eclipse.kura.linux.watchdog.WatchdogServiceImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.watchdog.WatchdogService\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.watchdog.WatchdogService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.eclipse.osgi\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n     Red Hat Inc\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.linux.watchdog</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.linux.watchdog.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/src/main/java/org/eclipse/kura/linux/watchdog/CriticalComponentRegistration.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.watchdog;\n\nimport org.eclipse.kura.watchdog.CriticalComponent;\n\npublic class CriticalComponentRegistration {\n\n    private final CriticalComponent criticalComponent;\n    private long updated;\n\n    public CriticalComponentRegistration(CriticalComponent criticalComponent) {\n        this.criticalComponent = criticalComponent;\n        this.updated = System.nanoTime();\n    }\n\n    public boolean isTimedOut() {\n        long now = System.nanoTime();\n        return this.criticalComponent.getCriticalComponentTimeout() * 1000000L < now - this.updated;\n    }\n\n    public void update() {\n        this.updated = System.nanoTime();\n    }\n\n    public String getCriticalComponentName() {\n        return this.criticalComponent.getCriticalComponentName();\n    }\n\n    public int getCriticalComponentTimeout() {\n        return this.criticalComponent.getCriticalComponentTimeout();\n    }\n\n    public CriticalComponent getCriticalComponent() {\n        return this.criticalComponent;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/src/main/java/org/eclipse/kura/linux/watchdog/RebootCauseFileWriter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.watchdog;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.nio.file.Files;\nimport java.nio.file.StandardCopyOption;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class RebootCauseFileWriter {\n\n    private static final Logger logger = LoggerFactory.getLogger(RebootCauseFileWriter.class);\n\n    private final File rebootCauseFile;\n\n    public RebootCauseFileWriter(String rebootCauseFilePath) {\n        this.rebootCauseFile = new File(rebootCauseFilePath).getAbsoluteFile();\n    }\n\n    public void writeRebootCause(String cause) {\n        final File rebootCauseFileDir = this.rebootCauseFile.getParentFile();\n\n        if (this.rebootCauseFile.exists()) {\n            logger.info(\"Reboot cause file {} already exists, not updating..\", this.rebootCauseFile);\n            return;\n        }\n        if (rebootCauseFileDir == null) {\n            logger.warn(\"failed to determine reboot cause file parent directory\", rebootCauseFileDir);\n            return;\n        }\n        rebootCauseFileDir.mkdirs();\n        if (!rebootCauseFileDir.isDirectory()) {\n            logger.warn(\"failed to create reboot cause file parent directory\", rebootCauseFileDir);\n            return;\n        }\n\n        final long timestamp = System.currentTimeMillis();\n        final File tmpFile = new File(this.rebootCauseFile.getPath() + '.' + timestamp);\n\n        try {\n            logger.info(\"Writing reboot cause file...\");\n            writeFile(tmpFile, timestamp, cause);\n            Files.move(tmpFile.toPath(), this.rebootCauseFile.toPath(), StandardCopyOption.ATOMIC_MOVE);\n            logger.info(\"Writing reboot cause file...done\");\n        } catch (Exception e) {\n            logger.warn(\"failed to write reboot cause file\", e);\n        } finally {\n            tmpFile.delete();\n        }\n    }\n\n    private void writeFile(File file, long timestamp, String rebootCause) throws IOException {\n        try (FileOutputStream out = new FileOutputStream(file); PrintStream writer = new PrintStream(out)) {\n            writer.println(timestamp);\n            writer.println(rebootCause);\n            writer.flush();\n            out.getFD().sync();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/src/main/java/org/eclipse/kura/linux/watchdog/WatchdogServiceImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.watchdog;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.Writer;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.watchdog.CriticalComponent;\nimport org.eclipse.kura.watchdog.WatchdogService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class WatchdogServiceImpl implements WatchdogService, ConfigurableComponent {\n\n    private static final String[] STOP_WATCHDOGD_COMMANDS = { \"systemctl stop watchdog\", \"service watchdog stop\",\n            \"/etc/init.d/watchdog stop\", \"/etc/init.d/watchdog.sh stop\" };\n\n    private static final Logger logger = LoggerFactory.getLogger(WatchdogServiceImpl.class);\n\n    private static final long GRACE_PERIOD = Duration.ofMinutes(5).toNanos();\n\n    private Long timedOutOn;\n    private List<CriticalComponentRegistration> criticalComponentRegistrations;\n    private ScheduledExecutorService pollExecutor;\n    private ScheduledFuture<?> pollTask;\n    private Writer watchdogFileWriter;\n    private WatchdogServiceOptions options;\n\n    protected void activate(Map<String, Object> properties) {\n        this.criticalComponentRegistrations = new CopyOnWriteArrayList<>();\n        this.pollExecutor = Executors.newSingleThreadScheduledExecutor();\n\n        updated(properties);\n    }\n\n    protected void deactivate() {\n        cancelPollTask();\n        shutdownPollExecutor();\n        if (this.watchdogFileWriter != null) {\n            refreshWatchdog();\n            closeWatchdogFileWriter();\n        }\n    }\n\n    public void updated(Map<String, Object> properties) {\n        WatchdogServiceOptions newOptions = new WatchdogServiceOptions(properties);\n\n        this.pollExecutor.submit(() -> {\n            Thread.currentThread().setName(\"WatchdogServiceImpl\");\n            cancelPollTask();\n            if (this.watchdogFileWriter != null) {\n                disableWatchdog();\n            }\n            doUpdate(newOptions);\n        });\n    }\n\n    private void stopWatchdogd() {\n        for (final String stopCommand : STOP_WATCHDOGD_COMMANDS) {\n            try {\n                runCommand(stopCommand);\n                Thread.sleep(5000);\n                return;\n            } catch (Exception e) {\n                logger.debug(\"Command failed: {}\", stopCommand, e);\n            }\n        }\n    }\n\n    private void openWatchdog(final String watchdogDevice, final boolean tryStopWatchdogd) throws IOException {\n        try {\n            this.watchdogFileWriter = getWatchdogDeviceWriter(watchdogDevice);\n        } catch (IOException e) {\n            if (tryStopWatchdogd) {\n                stopWatchdogd();\n                openWatchdog(watchdogDevice, false);\n            } else {\n                throw e;\n            }\n        }\n    }\n\n    private void doUpdate(WatchdogServiceOptions newOptions) {\n        if (!newOptions.isEnabled()) {\n            return;\n        }\n\n        this.timedOutOn = null;\n        this.watchdogFileWriter = null;\n\n        String watchdogDevice = newOptions.getWatchdogDevice();\n\n        if (!isWatchdogDeviceAvailable(watchdogDevice)) {\n            logger.error(\"Watchdog device '{}' does not exist\", watchdogDevice);\n            return;\n        }\n\n        try {\n            openWatchdog(watchdogDevice, true);\n        } catch (IOException e) {\n            logger.error(\"Failed to open watchdog device\", e);\n            return;\n        }\n\n        try (PrintWriter wdWriter = new PrintWriter(newOptions.getWatchdogEnabledTemporaryFilePath())) {\n            wdWriter.write(watchdogDevice);\n        } catch (IOException e) {\n            logger.warn(\"Unable to write watchdog enabled temporary file. Continuing anyway\", e);\n        }\n\n        this.options = newOptions;\n\n        this.pollTask = this.pollExecutor.scheduleAtFixedRate(() -> {\n            Thread.currentThread().setName(\"WatchdogServiceImpl\");\n            checkCriticalComponents();\n        }, 0, this.options.getPingInterval(), TimeUnit.MILLISECONDS);\n    }\n\n    protected Writer getWatchdogDeviceWriter(String watchdogDevice) throws IOException {\n        return new FileWriter(new File(watchdogDevice));\n    }\n\n    protected boolean isWatchdogDeviceAvailable(String watchdogDevice) {\n        return new File(watchdogDevice).exists();\n    }\n\n    @Override\n    @Deprecated\n    public void startWatchdog() {\n    }\n\n    @Override\n    @Deprecated\n    public void stopWatchdog() {\n    }\n\n    @Override\n    public int getHardwareTimeout() {\n        return 0;\n    }\n\n    @Override\n    public void registerCriticalComponent(CriticalComponent criticalComponent) {\n        boolean found = this.criticalComponentRegistrations.stream()\n                .anyMatch(ccr -> ccr.getCriticalComponent() == criticalComponent);\n        if (found) {\n            logger.warn(\"Critical component '{}' already registered\", criticalComponent.getCriticalComponentName());\n            return;\n        }\n        CriticalComponentRegistration ccr = new CriticalComponentRegistration(criticalComponent);\n        this.criticalComponentRegistrations.add(ccr);\n    }\n\n    @Override\n    @Deprecated\n    public void registerCriticalService(CriticalComponent criticalComponent) {\n        registerCriticalComponent(criticalComponent);\n    }\n\n    @Override\n    public void unregisterCriticalComponent(CriticalComponent criticalComponent) {\n        this.criticalComponentRegistrations.removeIf(ccr -> ccr.getCriticalComponent() == criticalComponent);\n    }\n\n    @Override\n    @Deprecated\n    public void unregisterCriticalService(CriticalComponent criticalComponent) {\n        unregisterCriticalComponent(criticalComponent);\n    }\n\n    @Override\n    public List<CriticalComponent> getCriticalComponents() {\n        List<CriticalComponent> result = new ArrayList<>();\n        for (CriticalComponentRegistration ccr : this.criticalComponentRegistrations) {\n            result.add(ccr.getCriticalComponent());\n        }\n        return Collections.unmodifiableList(result);\n    }\n\n    @Override\n    public void checkin(CriticalComponent criticalComponent) {\n        for (CriticalComponentRegistration ccr : this.criticalComponentRegistrations) {\n            if (ccr.getCriticalComponent() == criticalComponent) {\n                ccr.update();\n                break;\n            }\n        }\n    }\n\n    protected void checkCriticalComponents() {\n        logger.debug(\"Starting critical components check...\");\n        if (this.timedOutOn == null) {\n            CriticalComponentRegistration ccr = getAnyTimedOutRegistration();\n            if (ccr != null) {\n                this.timedOutOn = System.nanoTime();\n                logger.warn(\"Critical component '{}' timed out. System will reboot\", ccr.getCriticalComponentName());\n\n                RebootCauseFileWriter rebootCauseWriter = new RebootCauseFileWriter(\n                        this.options.getRebootCauseFilePath());\n                rebootCauseWriter.writeRebootCause(ccr.getCriticalComponentName());\n\n                try {\n                    logger.debug(\"Requesting debug.\");\n                    rebootSystem();\n                } catch (KuraException e) {\n                    logger.error(\"System reboot failed. Watchdog will not be refreshed\", e);\n                    this.timedOutOn -= GRACE_PERIOD;\n                }\n            }\n        }\n\n        if (this.timedOutOn == null || System.nanoTime() - this.timedOutOn < GRACE_PERIOD) {\n            logger.debug(\"Refreshing watchdog.\");\n            refreshWatchdog();\n        }\n    }\n\n    private CriticalComponentRegistration getAnyTimedOutRegistration() {\n        CriticalComponentRegistration result = null;\n\n        for (CriticalComponentRegistration ccr : this.criticalComponentRegistrations) {\n            if (ccr.isTimedOut()) {\n                result = ccr;\n                break;\n            }\n        }\n\n        return result;\n    }\n\n    private synchronized void rebootSystem() throws KuraException {\n        try {\n            runCommand(\"sync\");\n        } catch (KuraException e) {\n            logger.error(\"Filesystem sync failed. Continuing\", e);\n        }\n\n        runCommand(\"reboot\");\n    }\n\n    private void runCommand(String command) throws KuraException {\n        try {\n            int exitCode = 0;\n            Process proc = Runtime.getRuntime().exec(command);\n            exitCode = proc.waitFor();\n            if (exitCode != 0) {\n                throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR, command, exitCode);\n            }\n        } catch (IOException e) {\n            throw new KuraException(KuraErrorCode.PROCESS_EXECUTION_ERROR, e);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new KuraException(KuraErrorCode.PROCESS_EXECUTION_ERROR, e);\n        }\n    }\n\n    private void refreshWatchdog() {\n        try {\n            writeWatchdogDevice(\"w\");\n        } catch (IOException e) {\n            logger.error(\"Failed to refresh watchdog device '{}'\", this.options.getWatchdogDevice(), e);\n        }\n    }\n\n    private void disableWatchdog() {\n        try {\n            writeWatchdogDevice(\"V\");\n        } catch (IOException e) {\n            logger.error(\"Failed to write magic character to watchdog device '{}'\", this.options.getWatchdogDevice(),\n                    e);\n        }\n        closeWatchdogFileWriter();\n    }\n\n    private void closeWatchdogFileWriter() {\n        try {\n            this.watchdogFileWriter.close();\n            this.watchdogFileWriter = null;\n        } catch (IOException e) {\n            logger.error(\"Failed to close watchdog device '{}'\", this.options.getWatchdogDevice(), e);\n        }\n    }\n\n    private synchronized void writeWatchdogDevice(String value) throws IOException {\n        this.watchdogFileWriter.write(value);\n        this.watchdogFileWriter.flush();\n    }\n\n    private void cancelPollTask() {\n        if (this.pollTask != null && !this.pollTask.isCancelled()) {\n            logger.debug(\"Cancelling watchdog task...\");\n            this.pollTask.cancel(false);\n            logger.debug(\"Watchdog task cancelled? = {}\", this.pollTask.isCancelled());\n            this.pollTask = null;\n        }\n    }\n\n    private void shutdownPollExecutor() {\n        if (this.pollExecutor != null) {\n            logger.debug(\"Terminating watchdog executor...\");\n            this.pollExecutor.shutdown();\n            logger.debug(\"Watchdog executor terminated? - {}\", this.pollExecutor.isTerminated());\n            this.pollExecutor = null;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.linux.watchdog/src/main/java/org/eclipse/kura/linux/watchdog/WatchdogServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.linux.watchdog;\n\nimport java.util.Map;\n\npublic class WatchdogServiceOptions {\n\n    private static final ConfigurationProperty<Boolean> PROPERTY_ENABLED = new ConfigurationProperty<>(\"enabled\",\n            false);\n    private static final ConfigurationProperty<Integer> PROPERTY_PING_INTERVAL = new ConfigurationProperty<>(\n            \"pingInterval\", 10000);\n    private static final ConfigurationProperty<String> PROPERTY_WD_DEVICE = new ConfigurationProperty<>(\n            \"watchdogDevice\", \"/dev/watchdog\");\n    private static final ConfigurationProperty<String> PROPERTY_REBOOT_CAUSE_FILE_PATH = new ConfigurationProperty<>(\n            \"rebootCauseFilePath\", \"/opt/eclipse/kura/data/kura-reboot-cause\");\n\n    private static final String WD_ENABLED_TEMPORARY_FILE_PATH = \"/tmp/watchdog\";\n\n    private final Map<String, Object> properties;\n\n    public WatchdogServiceOptions(Map<String, Object> properties) {\n        this.properties = properties;\n    }\n\n    public boolean isEnabled() {\n        return PROPERTY_ENABLED.get(this.properties);\n    }\n\n    public Integer getPingInterval() {\n        return PROPERTY_PING_INTERVAL.get(this.properties);\n    }\n\n    public String getWatchdogDevice() {\n        return PROPERTY_WD_DEVICE.get(this.properties);\n    }\n\n    public String getRebootCauseFilePath() {\n        return PROPERTY_REBOOT_CAUSE_FILE_PATH.get(this.properties);\n    }\n\n    public String getWatchdogEnabledTemporaryFilePath() {\n        return WD_ENABLED_TEMPORARY_FILE_PATH;\n    }\n\n    private static class ConfigurationProperty<T> {\n\n        private final String key;\n        private final T defaultValue;\n\n        public ConfigurationProperty(String key, T defaultValue) {\n            this.key = key;\n            this.defaultValue = defaultValue;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public T get(Map<String, Object> properties) {\n            final Object value = properties.get(this.key);\n            if (this.defaultValue.getClass().isInstance(value)) {\n                return (T) value;\n            }\n            return this.defaultValue;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.log.filesystem.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.log.filesystem.provider\nBundle-SymbolicName: org.eclipse.kura.log.filesystem.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.log;version=\"[1.1,1.2)\",\n org.eclipse.kura.log.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.util.tracker;version=\"1.5.1\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/org.eclipse.kura.log.filesystem.provider/OSGI-INF/FilesystemLogProvider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.2.0\"\n    name=\"org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider\"\n    activate=\"activate\"\n    deactivate=\"deactivate\"\n    modified=\"updated\"\n    enabled=\"true\"\n    immediate=\"true\"\n    configuration-policy=\"require\">\n\t<implementation class=\"org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider\"/>\n\n    <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider\"/>\n    <service>\n        <provide interface=\"org.eclipse.kura.log.LogProvider\"/>\n    </service>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.log.filesystem.provider/OSGI-INF/metatype/org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider\"\n         name=\"FilesystemLogProvider\"\n         description=\"Implementation of a log provider that reads entries from the specified log file path.\">\n         \n        <AD id=\"logFilePath\"\n            name=\"Log file path\"\n            type=\"String\"\n            cardinality=\"1\"\n            required=\"true\"\n            default=\"/var/log/kura.log\"\n            description=\"Specifies the file path from which the logs are fetched.\">\n        </AD>\n\n    </OCD>\n    <Designate pid=\"org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider\" factoryPid=\"org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider\">\n        <Object ocdref=\"org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.log.filesystem.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.log.filesystem.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.log.filesystem.provider/build.properties",
    "content": "#\n#  Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.log.filesystem.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.log.filesystem.provider</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.log.filesystem.provider.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.log.filesystem.provider/src/main/java/org/eclipse/kura/log/filesystem/provider/FilesystemLogProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.log.filesystem.provider;\n\nimport java.io.EOFException;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.log.LogEntry;\nimport org.eclipse.kura.log.LogProvider;\nimport org.eclipse.kura.log.listener.LogListener;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FilesystemLogProvider implements ConfigurableComponent, LogProvider {\n\n    private static final Logger logger = LoggerFactory.getLogger(FilesystemLogProvider.class);\n    public static final String LOG_FILEPATH_PROP_KEY = \"logFilePath\";\n\n    private final List<LogListener> registeredListeners = new LinkedList<>();\n    private FileLogReader readerThread;\n    private String filePath;\n\n    protected void activate(Map<String, Object> properties) {\n        logger.info(\"Activating FilesystemLogProvider...\");\n        updated(properties);\n        logger.info(\"Activating FilesystemLogProvider... Done.\");\n    }\n\n    protected void deactivate() {\n        logger.info(\"Deactivating FilesystemLogProvider...\");\n        if (this.readerThread != null) {\n            this.readerThread.interrupt();\n        }\n        logger.info(\"Deactivating FilesystemLogProvider... Done.\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"Updated FilesystemLogProvider...\");\n        if (this.readerThread != null) {\n            this.readerThread.interrupt();\n        }\n        this.filePath = (String) properties.get(LOG_FILEPATH_PROP_KEY);\n        this.readerThread = new FileLogReader(this.filePath);\n        this.readerThread.start();\n        logger.info(\"Updated FilesystemLogProvider... Done.\");\n    }\n\n    @Override\n    public void registerLogListener(LogListener listener) {\n        this.registeredListeners.add(listener);\n    }\n\n    @Override\n    public void unregisterLogListener(LogListener listener) {\n        this.registeredListeners.remove(listener);\n    }\n\n    class FileLogReader extends Thread {\n\n        private static final long SAMPLE_INTERVAL = 100;\n        private final File logFile;\n        private boolean follow = true;\n\n        public FileLogReader(String filePath) {\n            this.logFile = new File(filePath);\n            this.follow = true;\n        }\n\n        @Override\n        public void run() {\n            try (RandomAccessFile file = new RandomAccessFile(this.logFile, \"r\")) {\n                while (this.follow) {\n                    readLinesAndNotifyListeners(file);\n                    sleep(SAMPLE_INTERVAL);\n                }\n            } catch (FileNotFoundException fnf) {\n                logger.error(\"File '{}' not found.\", this.logFile.getPath());\n            } catch (InterruptedException ie) {\n                // nothing to do\n            } catch (Exception e) {\n                logger.error(\"Unexpected exception in FilesystemLogProvider.\", e);\n            } finally {\n                Thread.currentThread().interrupt();\n            }\n        }\n\n        private void readLinesAndNotifyListeners(RandomAccessFile file) throws IOException {\n            Optional<String> line = readUntilNewLine(file);\n\n            if (line.isPresent()) {\n                String stacktrace = readStacktrace(file);\n                notifyListeners(line.get(), stacktrace);\n            }\n        }\n\n        private Optional<String> readUntilNewLine(RandomAccessFile file) throws IOException {\n            StringBuilder resultLine = new StringBuilder();\n            long pointerToLastSuccessfulRead = file.getFilePointer();\n\n            if (pointerToLastSuccessfulRead < file.length()) {\n                char newChar = 0;\n\n                do {\n                    try {\n                        newChar = (char) file.readByte();\n                        resultLine.append(newChar);\n                        pointerToLastSuccessfulRead = file.getFilePointer();\n                    } catch (EOFException eof) {\n                        file.seek(pointerToLastSuccessfulRead);\n                    }\n                } while (newChar != '\\n');\n\n                return Optional.of(resultLine.toString());\n            } else {\n                return Optional.empty();\n            }\n        }\n\n        private String readStacktrace(RandomAccessFile file) throws IOException {\n            StringBuilder stacktrace = new StringBuilder();\n            long lastReadPosition = file.getFilePointer();\n\n            Optional<String> maybeStacktrace = readUntilNewLine(file);\n\n            while (maybeStacktrace.isPresent() && isStacktrace(maybeStacktrace.get())) {\n                stacktrace.append(maybeStacktrace.get());\n                stacktrace.append(\"\\n\");\n                lastReadPosition = file.getFilePointer();\n                maybeStacktrace = readUntilNewLine(file);\n            }\n\n            file.seek(lastReadPosition);\n\n            return stacktrace.toString().trim();\n        }\n\n        private boolean isStacktrace(String line) {\n            /*\n             * stacktrace lines do not start with a timestamp\n             * \n             * in kura-audit log file the lines start with a '<'\n             */\n            return line.length() > 4 && !line.substring(0, 4).matches(\"\\\\d{4}\") && !line.startsWith(\"<\");\n        }\n\n        private synchronized void notifyListeners(String message, String stacktrace) {\n            if (message != null) {\n                for (LogListener listener : FilesystemLogProvider.this.registeredListeners) {\n                    LogEntry entry = new KuraLogLineParser(message, FilesystemLogProvider.this.filePath, stacktrace)\n                            .createLogEntry();\n                    listener.newLogEntry(entry);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.log.filesystem.provider/src/main/java/org/eclipse/kura/log/filesystem/provider/KuraLogLineParser.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.log.filesystem.provider;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.log.LogEntry;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic final class KuraLogLineParser {\n\n    private static final Logger logger = LoggerFactory.getLogger(KuraLogLineParser.class);\n\n    public static final long DEFAULT_TIMESTAMP = new Date(0).getTime();\n    public static final String DEFAULT_PID = \"undefined\";\n    public static final String DEFAULT_PRIORITY = \"INFO\";\n    public static final String DEFAULT_SYSLOG_IDENTIFIER = \"Kura\";\n    public static final String DEFAULT_STACKTRACE = \"\";\n\n    private static final Pattern PID_PATTERN = Pattern.compile(\"\\\\[[A-Za-z0-9 ]*\\\\]\");\n\n    private long timestamp;\n    private String pid;\n    private String priority;\n    private String message;\n    private final String filepath;\n    private String syslogIdentifier;\n    private String stacktrace;\n    private boolean pidWhitespaceReplaced;\n\n    public KuraLogLineParser(String message, String filepath, String stacktrace) {\n        this.timestamp = DEFAULT_TIMESTAMP;\n        this.pid = DEFAULT_PID;\n        this.priority = DEFAULT_PRIORITY;\n        this.message = message;\n        this.filepath = filepath;\n        this.syslogIdentifier = DEFAULT_SYSLOG_IDENTIFIER;\n        this.stacktrace = stacktrace;\n    }\n\n    public LogEntry createLogEntry() {\n        if (this.filepath.contains(\"kura.log\")) {\n            parseKuraLog();\n        }\n\n        if (this.filepath.contains(\"kura-audit.log\")) {\n            parseKuraAuditLog();\n        }\n\n        return generateLogEntry();\n    }\n\n    /*\n     * kura.log message format:\n     *\n     * _SOURCE_REALTIME_TIMESTAMP [PID] PRIORITY MESSAGE_WITH_POSSIBLE_SPACES\n     */\n    private void parseKuraLog() {\n        String[] splits = innerTrimPid(this.message).split(\" \");\n        if (splits.length >= 3) {\n            this.timestamp = parseStringToEpoch(\"yyyy-MM-dd'T'hh:mm:ss,S\", splits[0]);\n\n            this.pid = splits[1];\n            this.pid = this.pid.replace(\"[\", \"\");\n            this.pid = this.pid.replace(\"]\", \"\");\n\n            this.pid = this.pidWhitespaceReplaced ? this.pid.replace(\"-\", \" \") : this.pid;\n\n            this.priority = splits[2];\n            StringBuilder sb = new StringBuilder();\n            for (int i = 3; i < splits.length; i++) {\n                sb.append(splits[i]);\n                sb.append(\" \");\n            }\n            this.message = sb.toString().trim();\n        }\n    }\n\n    private String innerTrimPid(String message) {\n\n        String trimmedMessage = message;\n\n        Matcher pidMatcher = PID_PATTERN.matcher(message);\n\n        if (pidMatcher.find()) {\n            String foundPid = pidMatcher.group();\n            trimmedMessage = trimmedMessage.replace(foundPid, foundPid.replace(\" \", \"-\"));\n            this.pidWhitespaceReplaced = true;\n        }\n\n        return trimmedMessage;\n    }\n\n    private long parseStringToEpoch(String format, String date) {\n        try {\n            Date parsedDate = new SimpleDateFormat(format).parse(date);\n            return parsedDate.toInstant().getEpochSecond();\n        } catch (ParseException e) {\n            logger.error(\"Error parsing Kura log timestamp.\", e);\n        }\n        return 0;\n    }\n\n    /*\n     * kura-audit.log message format:\n     *\n     * <ID>NUMBER TIMESTAMP DEVICE SYSLOG_IDENTIFIER - - [RequestContext@28392 category=\"AuditLogger\"\n     * exception=\"STACKTRACE\" priority=\"PRIORITY\" thread=\"PID\"] MESSAGE_WITH_POSSIBLE_SPACES\n     */\n    private void parseKuraAuditLog() {\n        String[] splits = this.message.split(\" \");\n        if (splits.length >= 11) {\n            this.timestamp = parseStringToEpoch(\"yyyy-MM-dd'T'hh:mm:ss.SSSXXX\", splits[1]);\n\n            this.syslogIdentifier = splits[3];\n            this.stacktrace += splits[8].replace(\"exception=\", \"\").replace(\"\\\"\", \"\");\n            this.priority = splits[9].replace(\"priority=\", \"\").replace(\"\\\"\", \"\");\n            this.pid = splits[10].replace(\"thread=\", \"\").replace(\"\\\"\", \"\").replace(\"]\", \"\");\n            StringBuilder sb = new StringBuilder();\n            for (int i = 11; i < splits.length; i++) {\n                sb.append(splits[i]);\n                sb.append(\" \");\n            }\n            this.message = sb.toString().trim();\n        }\n    }\n\n    private LogEntry generateLogEntry() {\n        Map<String, Object> entryProperties = new HashMap<>();\n        entryProperties.put(\"_PID\", this.pid);\n        entryProperties.put(\"MESSAGE\", this.message);\n        entryProperties.put(\"PRIORITY\", this.priority);\n        entryProperties.put(\"SYSLOG_IDENTIFIER\", this.syslogIdentifier);\n        entryProperties.put(\"_TRANSPORT\", this.filepath);\n        entryProperties.put(\"STACKTRACE\", this.stacktrace);\n\n        return new LogEntry(entryProperties, this.timestamp);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: CloudService Relay (CloudService CAT)\nBundle-SymbolicName: org.eclipse.kura.misc.cloudcat;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nBundle-Category: Miscellaneous Applications and Services\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.cloud;version=\"[1.1,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.util.tracker;version=\"1.5.0\",\n org.slf4j;version=\"1.6.4\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/OSGI-INF/CloudCat.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    \n   Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n    Eurotech\n    \n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" modified=\"updated\" name=\"org.eclipse.kura.misc.cloudcat.CloudCat\">\n   <implementation class=\"org.eclipse.kura.internal.misc.cloudcat.CloudCat\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.misc.cloudcat.CloudCat\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/OSGI-INF/metatype/org.eclipse.kura.misc.cloudcat.CloudCat.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.misc.cloudcat.CloudCat\"\n         name=\"CloudCat\" \n         description=\"Creates a pair of CloudClient instances and copies messages between them.\n         In a typical scenario, the first client connects to the cloud platform broker via the default CloudService.\n         The second client connects to the embedded broker via a second CloudService instance.\n         An external process, connected to the embedded broker, can optionally subscribe to the topic namespace of the second client i.e.\n         second-account-name/second-device-id/second.cloud.client.app.id/# to receive data messages and $EDC/second-account-name/second-device-id/second.cloud.client.app.id/#\n         to receive control messages where the account name and devide ID are configured in the DataTransportService layer of the CloudClient's CloudService.\n         Messages will be relayed between the first and second client preserving the application topic and the QoS of the incoming meessage:\n         [$EDC/]first-account-name/first-device-id/first.cloud.client.app.id/app-topic &lt;-&gt; [$EDC/]second-account-name/second-device-id/second.cloud.client.app.id/app-topic.\">\n        \n        <AD id=\"relay.enable\"\n            name=\"Relay Enable\"\n            type=\"Boolean\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"false\" \n            description=\"Enable relaying messages between CloudClient instances.\"/>\n        \n        <AD id=\"first.cloud.service.pid\"\n            name=\"First CloudService PID\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"org.eclipse.kura.cloud.CloudService\"\n            description=\"The PID of the CloudService used by the first CloudClient, e.g. org.eclipse.kura.cloud.CloudService.\">\n        </AD>\n        \n        <AD id=\"second.cloud.service.pid\"\n            name=\"Second CloudService PID\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"org.eclipse.kura.cloud.CloudService-2\"\n            description=\"The PID of the CloudService used by the first CloudClient, e.g. org.eclipse.kura.cloud.CloudService-2.\">\n        </AD>\n        \n        <AD id=\"first.cloud.client.app.id\"\n            name=\"First CloudClient App ID\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"CLOUDCAT1\"\n            description=\"The application identifier of the first CloudClient.\">\n        </AD>\n\n        <AD id=\"second.cloud.client.app.id\"\n            name=\"Second CloudClient App ID\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"CLOUDCAT2\"\n            description=\"The application identifier of the second CloudClient.\">\n        </AD>\n            \n        <AD id=\"first.cloud.client.control.subscriptions\"\n            name=\"First CloudClient Control Subscriptions\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"\"\n            description=\"Comma-separated list of control subscriptions, each in the form control-app-topic;Qos. Usually not needed in virtue of the CloudService default subscription.\">\n        </AD>\n        \n        <AD id=\"second.cloud.client.control.subscriptions\"\n            name=\"Second CloudClient Control Subscriptions\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"\"\n            description=\"Comma-separated list of control subscriptions, each in the form control-app-topic;Qos. Usually not needed in virtue of the CloudService default subscription.\">       \n        </AD>\n        \n        <AD id=\"first.cloud.client.data.subscriptions\"\n            name=\"First CloudClient Data Subscriptions\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"\"\n            description=\"Comma-separated list of data subscriptions, each in the form data-app-topic;Qos. Usually not needed.\">\n        </AD>\n        \n        <AD id=\"second.cloud.client.data.subscriptions\"\n            name=\"Second CloudClient Data Subscriptions\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"false\"\n            default=\"#;0\"\n            description=\"Comma-separated list of data subscriptions, each in the form data-app-topic;Qos.\">\n        </AD>\n        \n    </OCD>\n    <Designate pid=\"org.eclipse.kura.misc.cloudcat.CloudCat\" factoryPid=\"org.eclipse.kura.misc.cloudcat.CloudCat\">\n        <Object ocdref=\"org.eclipse.kura.misc.cloudcat.CloudCat\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/build.properties",
    "content": "output.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               OSGI-INF/CloudCat.xml\nsrc.includes = about.html\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.misc.cloudcat</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/src/main/java/org/eclipse/kura/internal/misc/cloudcat/CloudCat.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.misc.cloudcat;\n\nimport static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudCat implements ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudCat.class);\n\n    private CloudCatOptions options;\n    private CloudService firstCloudService;\n    private CloudService secondCloudService;\n    private CloudClient firstCloudClient;\n    private CloudClient secondCloudClient;\n    private CloudClientRelay firstCloudClientRelay;\n    private CloudClientRelay secondCloudClientRelay;\n\n    private ServiceTracker<CloudService, CloudService> firstCloudServiceTracker;\n    private ServiceTracker<CloudService, CloudService> secondCloudServiceTracker;\n\n    private ComponentContext componentContext;\n\n    private void bindFirstCloudService(CloudService firstCloudService) {\n        this.firstCloudService = firstCloudService;\n\n        try {\n            this.firstCloudClient = this.firstCloudService.newCloudClient(this.options.getFirstCloudClientAppId());\n            initClients();\n        } catch (KuraException e) {\n            logger.error(\"CloudClient: {} instantiation failed\", this.options.getFirstCloudClientAppId(), e);\n        }\n    }\n\n    private void bindSecondCloudService(CloudService secondCloudService) {\n        this.secondCloudService = secondCloudService;\n\n        try {\n            this.secondCloudClient = this.secondCloudService.newCloudClient(this.options.getSecondCloudClientAppId());\n            initClients();\n        } catch (KuraException e) {\n            logger.error(\"CloudClient: {} instantiation failed\", this.options.getSecondCloudClientAppId(), e);\n        }\n    }\n\n    private void unbindFirstCloudService(CloudService firstCloudService) {\n        cleanupClients();\n        this.firstCloudService = null;\n    }\n\n    private void unbindSecondCloudService(CloudService firstCloudService) {\n        cleanupClients();\n        this.secondCloudService = null;\n    }\n\n    protected void activate(ComponentContext ctx, Map<String, Object> properties) {\n        logger.info(\"Activating {}\", ctx.getProperties().get(KURA_SERVICE_PID));\n        this.componentContext = ctx;\n        init(properties);\n    }\n\n    protected void updated(ComponentContext ctx, Map<String, Object> properties) {\n        logger.info(\"Updating {}\", ctx.getProperties().get(KURA_SERVICE_PID));\n        cleanup();\n        init(properties);\n    }\n\n    protected void deactivate(ComponentContext ctx) {\n        logger.info(\"Deactivating {}\", ctx.getProperties().get(KURA_SERVICE_PID));\n        cleanup();\n    }\n\n    private void init(Map<String, Object> properties) {\n        try {\n            this.options = CloudCatOptions.parseOptions(properties);\n        } catch (NullPointerException | IllegalArgumentException e) {\n            logger.error(\"Invalid configuration\", e);\n            return;\n        }\n\n        if (!this.options.isRelayEnabled()) {\n            logger.info(\"Relay is disabled\");\n            return;\n        }\n\n        // Start trackers\n        try {\n            Filter filter = this.componentContext.getBundleContext()\n                    .createFilter(\"(\" + KURA_SERVICE_PID + \"=\" + this.options.getFirstCloudServicePid() + \")\");\n            this.firstCloudServiceTracker = new ServiceTracker<>(this.componentContext.getBundleContext(), filter,\n                    new ServiceTrackerCustomizer<CloudService, CloudService>() {\n\n                        @Override\n                        public CloudService addingService(ServiceReference<CloudService> reference) {\n                            CloudService cloudService = CloudCat.this.componentContext.getBundleContext()\n                                    .getService(reference);\n                            bindFirstCloudService(cloudService);\n                            return cloudService;\n                        }\n\n                        @Override\n                        public void modifiedService(ServiceReference<CloudService> reference, CloudService service) {\n                            // Ignore\n                        }\n\n                        @Override\n                        public void removedService(ServiceReference<CloudService> reference, CloudService service) {\n                            unbindFirstCloudService(service);\n                        }\n\n                    });\n            this.firstCloudServiceTracker.open();\n        } catch (InvalidSyntaxException e) {\n            logger.error(\"Invalid filter\", e);\n            return;\n        }\n\n        try {\n            Filter filter = this.componentContext.getBundleContext()\n                    .createFilter(\"(\" + KURA_SERVICE_PID + \"=\" + this.options.getSecondCloudServicePid() + \")\");\n            this.secondCloudServiceTracker = new ServiceTracker<>(this.componentContext.getBundleContext(), filter,\n                    new ServiceTrackerCustomizer<CloudService, CloudService>() {\n\n                        @Override\n                        public CloudService addingService(ServiceReference<CloudService> reference) {\n                            CloudService cloudService = CloudCat.this.componentContext.getBundleContext()\n                                    .getService(reference);\n                            bindSecondCloudService(cloudService);\n                            return cloudService;\n                        }\n\n                        @Override\n                        public void modifiedService(ServiceReference<CloudService> reference, CloudService service) {\n                            // Ignore\n                        }\n\n                        @Override\n                        public void removedService(ServiceReference<CloudService> reference, CloudService service) {\n                            unbindSecondCloudService(service);\n                        }\n\n                    });\n            this.secondCloudServiceTracker.open();\n        } catch (InvalidSyntaxException e) {\n            logger.error(\"Invalid filter\", e);\n            return;\n        }\n    }\n\n    private void initClients() {\n        if (this.firstCloudClient != null && this.secondCloudClient != null && this.firstCloudClientRelay == null\n                && this.secondCloudClientRelay == null) {\n            logger.info(\"Initializing relay\");\n\n            this.firstCloudClientRelay = new CloudClientRelay(this.firstCloudClient, this.secondCloudClient,\n                    this.options.getFirstCloudClientDataSubscriptions(),\n                    this.options.getFirstCloudClientControlSubscriptions());\n\n            this.secondCloudClientRelay = new CloudClientRelay(this.secondCloudClient, this.firstCloudClient,\n                    this.options.getSecondCloudClientDataSubscriptions(),\n                    this.options.getSecondCloudClientControlSubscriptions());\n\n            this.firstCloudClientRelay.listen();\n            this.secondCloudClientRelay.listen();\n\n            if (this.firstCloudClientRelay.isConnected()) {\n                this.firstCloudClientRelay.subscribe();\n            }\n            if (this.secondCloudClientRelay.isConnected()) {\n                this.secondCloudClientRelay.subscribe();\n            }\n        }\n    }\n\n    private void cleanup() {\n        if (this.firstCloudServiceTracker != null) {\n            this.firstCloudServiceTracker.close();\n            this.firstCloudServiceTracker = null;\n        }\n        if (this.secondCloudServiceTracker != null) {\n            this.secondCloudServiceTracker.close();\n            this.secondCloudServiceTracker = null;\n        }\n        cleanupClients();\n    }\n\n    private void cleanupClients() {\n        if (this.firstCloudClientRelay != null) {\n            this.firstCloudClientRelay.unlisten();\n            if (this.firstCloudClientRelay.isConnected()) {\n                this.firstCloudClientRelay.unsubscribe();\n            }\n            this.firstCloudClientRelay = null;\n        }\n        if (this.secondCloudClientRelay != null) {\n            this.secondCloudClientRelay.unlisten();\n            if (this.secondCloudClientRelay.isConnected()) {\n                this.secondCloudClientRelay.unsubscribe();\n            }\n            this.secondCloudClientRelay = null;\n        }\n\n        if (this.firstCloudClient != null) {\n            this.firstCloudClient.release();\n            this.firstCloudClient = null;\n        }\n        if (this.secondCloudClient != null) {\n            this.secondCloudClient.release();\n            this.secondCloudClient = null;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/src/main/java/org/eclipse/kura/internal/misc/cloudcat/CloudCatOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.misc.cloudcat;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\npublic class CloudCatOptions {\n\n    private static final String RELAY_ENABLE = \"relay.enable\";\n    private static final String FIRST_CLOUD_SERVICE_PID = \"first.cloud.service.pid\";\n    private static final String SECOND_CLOUD_SERVICE_PID = \"second.cloud.service.pid\";\n    private static final String FIRST_CLOUD_CLIENT_APP_ID = \"first.cloud.client.app.id\";\n    private static final String SECOND_CLOUD_CLIENT_APP_ID = \"second.cloud.client.app.id\";\n    private static final String FIRST_CLOUD_CLIENT_CONTROL_SUBSCRPTIONS = \"first.cloud.client.control.subscriptions\";\n    private static final String FIRST_CLOUD_CLIENT_DATA_SUBSCRPTIONS = \"first.cloud.client.data.subscriptions\";\n    private static final String SECOND_CLOUD_CLIENT_CONTROL_SUBSCRPTIONS = \"second.cloud.client.control.subscriptions\";\n    private static final String SECOND_CLOUD_CLIENT_DATA_SUBSCRPTIONS = \"second.cloud.client.data.subscriptions\";\n\n    private Map<String, Object> effectiveProperties;\n\n    private boolean relayEnabled;\n    private String firstCloudServicePid;\n    private String secondCloudServicePid;\n    private String firstCloudClientAppId;\n    private String secondCloudClientAppId;\n    private List<CloudCatSubscription> firstCloudClientControlSubscriptions;\n    private List<CloudCatSubscription> firstCloudClientDataSubscriptions;\n    private List<CloudCatSubscription> secondCloudClientControlSubscriptions;\n    private List<CloudCatSubscription> secondCloudClientDataSubscriptions;\n\n    private static CloudCatOptions defaultOptions;\n    private static Map<String, Object> defaultProperties;\n\n    public boolean isRelayEnabled() {\n        return this.relayEnabled;\n    }\n\n    public String getFirstCloudServicePid() {\n        return this.firstCloudServicePid;\n    }\n\n    public String getSecondCloudServicePid() {\n        return this.secondCloudServicePid;\n    }\n\n    public String getFirstCloudClientAppId() {\n        return this.firstCloudClientAppId;\n    }\n\n    public String getSecondCloudClientAppId() {\n        return this.secondCloudClientAppId;\n    }\n\n    public List<CloudCatSubscription> getFirstCloudClientControlSubscriptions() {\n        return this.firstCloudClientControlSubscriptions;\n    }\n\n    public List<CloudCatSubscription> getFirstCloudClientDataSubscriptions() {\n        return this.firstCloudClientDataSubscriptions;\n    }\n\n    public List<CloudCatSubscription> getSecondCloudClientControlSubscriptions() {\n        return this.secondCloudClientControlSubscriptions;\n    }\n\n    public List<CloudCatSubscription> getSecondCloudClientDataSubscriptions() {\n        return this.secondCloudClientDataSubscriptions;\n    }\n\n    public static synchronized CloudCatOptions getDefaultOptions() {\n        if (defaultOptions == null) {\n            defaultOptions = parseOptions(getDefaultProperties());\n        }\n        return defaultOptions;\n    }\n\n    public static CloudCatOptions parseOptions(Map<String, Object> properties) {\n        requireNonNull(properties);\n\n        CloudCatOptions options = new CloudCatOptions();\n        options.effectiveProperties = new HashMap<>(getDefaultProperties());\n\n        for (Entry<String, Object> entry : properties.entrySet()) {\n            String key = entry.getKey();\n            Object value = properties.get(key);\n            if (value != null) {\n                options.effectiveProperties.put(key, value);\n            }\n        }\n\n        options.relayEnabled = (Boolean) options.effectiveProperties.get(RELAY_ENABLE);\n        options.firstCloudServicePid = (String) options.effectiveProperties.get(FIRST_CLOUD_SERVICE_PID);\n        options.secondCloudServicePid = (String) options.effectiveProperties.get(SECOND_CLOUD_SERVICE_PID);\n        options.firstCloudClientAppId = (String) options.effectiveProperties.get(FIRST_CLOUD_CLIENT_APP_ID);\n        options.secondCloudClientAppId = (String) options.effectiveProperties.get(SECOND_CLOUD_CLIENT_APP_ID);\n\n        options.firstCloudClientControlSubscriptions = parseSubscriptions(\n                (String) options.effectiveProperties.get(FIRST_CLOUD_CLIENT_CONTROL_SUBSCRPTIONS));\n        options.firstCloudClientDataSubscriptions = parseSubscriptions(\n                (String) options.effectiveProperties.get(FIRST_CLOUD_CLIENT_DATA_SUBSCRPTIONS));\n        options.secondCloudClientControlSubscriptions = parseSubscriptions(\n                (String) options.effectiveProperties.get(SECOND_CLOUD_CLIENT_CONTROL_SUBSCRPTIONS));\n        options.secondCloudClientDataSubscriptions = parseSubscriptions(\n                (String) options.effectiveProperties.get(SECOND_CLOUD_CLIENT_DATA_SUBSCRPTIONS));\n\n        return options;\n    }\n\n    private static List<CloudCatSubscription> parseSubscriptions(String subscriptions) {\n        List<CloudCatSubscription> result = new ArrayList<>();\n        String[] parts = subscriptions.split(\",\");\n\n        if (parts != null) {\n            for (String part : parts) {\n                if (!part.isEmpty()) {\n                    CloudCatSubscription subscription = CloudCatSubscription.parseSubscription(part);\n                    result.add(subscription);\n                }\n            }\n        }\n\n        return result;\n    }\n\n    private static synchronized Map<String, Object> getDefaultProperties() {\n        if (defaultProperties == null) {\n            Map<String, Object> properties = new HashMap<>();\n            properties.put(RELAY_ENABLE, false);\n            properties.put(FIRST_CLOUD_SERVICE_PID, \"org.eclipse.kura.cloud.CloudService\");\n            properties.put(SECOND_CLOUD_SERVICE_PID, \"org.eclipse.kura.cloud.CloudService-2\");\n            properties.put(FIRST_CLOUD_CLIENT_APP_ID, \"CLOUDCAT1\");\n            properties.put(SECOND_CLOUD_CLIENT_APP_ID, \"CLOUDCAT2\");\n            properties.put(FIRST_CLOUD_CLIENT_CONTROL_SUBSCRPTIONS, \"\");\n            properties.put(FIRST_CLOUD_CLIENT_DATA_SUBSCRPTIONS, \"\");\n            properties.put(SECOND_CLOUD_CLIENT_CONTROL_SUBSCRPTIONS, \"\");\n            properties.put(SECOND_CLOUD_CLIENT_DATA_SUBSCRPTIONS, \"#;0\");\n\n            defaultProperties = properties;\n        }\n        return defaultProperties;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/src/main/java/org/eclipse/kura/internal/misc/cloudcat/CloudCatSubscription.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.misc.cloudcat;\n\npublic class CloudCatSubscription {\n\n    private final String topic;\n    private final int qos;\n\n    public CloudCatSubscription(String topic, int qos) {\n        this.topic = topic;\n        this.qos = qos;\n    }\n\n    public String getTopic() {\n        return this.topic;\n    }\n\n    public int getQos() {\n        return this.qos;\n    }\n\n    static CloudCatSubscription parseSubscription(String subscription) {\n        int index = subscription.lastIndexOf(';');\n        if (index == -1) {\n            throw new IllegalArgumentException(\"QoS separator missing in: '\" + subscription + \"'\");\n        } else if (index == 0) {\n            throw new IllegalArgumentException(\"topic token missing in: '\" + subscription + \"'\");\n        } else if (index == subscription.length() - 1) {\n            throw new IllegalArgumentException(\"QoS token missing in: '\" + subscription + \"'\");\n        }\n        String topic = subscription.substring(0, index).trim();\n        int qos = Integer.parseInt(subscription.substring(index + 1).trim());\n        if (qos < 0 || qos > 2) {\n            throw new IllegalArgumentException(\"Invalid QoS in '\" + subscription + \"'\");\n        }\n        return new CloudCatSubscription(topic, qos);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.misc.cloudcat/src/main/java/org/eclipse/kura/internal/misc/cloudcat/CloudClientRelay.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.misc.cloudcat;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloud.CloudClientListener;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CloudClientRelay implements CloudClientListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudClientRelay.class);\n\n    private static final int DFLT_PRIORITY = 5;\n\n    private static final String FORWARDED_MESSAGE_METRIC_NAME = \"_fwd\";\n\n    private final CloudClient thisCloudClient;\n    private final CloudClient otherCloudClient;\n    private final List<CloudCatSubscription> dataSubscriptions;\n    private final List<CloudCatSubscription> controlSubscriptions;\n\n    public CloudClientRelay(CloudClient thisCloudClient, CloudClient otherCloudClient,\n            List<CloudCatSubscription> dataSubscriptions, List<CloudCatSubscription> controlSubscriptions) {\n        super();\n        this.thisCloudClient = thisCloudClient;\n        this.otherCloudClient = otherCloudClient;\n        this.dataSubscriptions = dataSubscriptions;\n        this.controlSubscriptions = controlSubscriptions;\n    }\n\n    private boolean isForwardedMessage(KuraPayload msg) {\n        final Object isForwardedMessage = msg.getMetric(FORWARDED_MESSAGE_METRIC_NAME);\n        return isForwardedMessage != null && isForwardedMessage instanceof Boolean && (Boolean) isForwardedMessage;\n    }\n\n    @Override\n    public void onControlMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) {\n        try {\n            if (isForwardedMessage(msg)) {\n                logger.debug(\"Received already forwarded message, discarding\");\n                return;\n            }\n\n            msg.addMetric(FORWARDED_MESSAGE_METRIC_NAME, true);\n            this.otherCloudClient.controlPublish(appTopic, msg, qos, retain, DFLT_PRIORITY);\n        } catch (KuraException e) {\n            logger.warn(\"Failed to relay incoming control message from: {} to: {}\", appTopic,\n                    this.thisCloudClient.getApplicationId(), this.otherCloudClient.getApplicationId());\n        }\n    }\n\n    @Override\n    public void onMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) {\n        try {\n            if (isForwardedMessage(msg)) {\n                logger.debug(\"Received already forwarded message, discarding\");\n                return;\n            }\n\n            msg.addMetric(FORWARDED_MESSAGE_METRIC_NAME, true);\n            this.otherCloudClient.publish(appTopic, msg, qos, retain, DFLT_PRIORITY);\n        } catch (KuraException e) {\n            logger.warn(\"Failed to relay incoming data message from: {} to: {}\", appTopic,\n                    this.thisCloudClient.getApplicationId(), this.otherCloudClient.getApplicationId());\n        }\n    }\n\n    @Override\n    public void onConnectionLost() {\n        // Ignore\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        // Assuming clean session\n        subscribe();\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String appTopic) {\n        // Ignore\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String appTopic) {\n        // Ignore\n    }\n\n    public void subscribe() {\n        for (CloudCatSubscription subscription : this.dataSubscriptions) {\n            String topic = subscription.getTopic();\n            int qos = subscription.getQos();\n\n            try {\n                this.thisCloudClient.subscribe(topic, qos);\n            } catch (KuraException e) {\n                logger.error(\"Failed to subscribe client: {} to data topic: '{}'\",\n                        this.thisCloudClient.getApplicationId(), topic, e);\n            }\n        }\n\n        for (CloudCatSubscription subscription : this.controlSubscriptions) {\n            String topic = subscription.getTopic();\n            int qos = subscription.getQos();\n\n            try {\n                this.thisCloudClient.controlSubscribe(topic, qos);\n            } catch (KuraException e) {\n                logger.error(\"Failed to subscribe client: {} to control topic: '{}'\",\n                        this.thisCloudClient.getApplicationId(), topic, e);\n            }\n        }\n    }\n\n    public void unsubscribe() {\n        for (CloudCatSubscription subscription : this.dataSubscriptions) {\n            String topic = subscription.getTopic();\n\n            try {\n                this.thisCloudClient.unsubscribe(topic);\n            } catch (KuraException e) {\n                logger.error(\"Failed to unsubscribe client: {} from data topic: '{}'\",\n                        this.thisCloudClient.getApplicationId(), topic, e);\n            }\n        }\n\n        for (CloudCatSubscription subscription : this.controlSubscriptions) {\n            String topic = subscription.getTopic();\n\n            try {\n                this.thisCloudClient.controlUnsubscribe(topic);\n            } catch (KuraException e) {\n                logger.error(\"Failed to unsubscribe client: {} from control topic: '{}'\",\n                        this.thisCloudClient.getApplicationId(), topic, e);\n            }\n        }\n    }\n\n    public boolean isConnected() {\n        return this.thisCloudClient.isConnected();\n    }\n\n    public void listen() {\n        this.thisCloudClient.addCloudClientListener(this);\n    }\n\n    public void unlisten() {\n        this.thisCloudClient.removeCloudClientListener(this);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/.gitignore",
    "content": "/target\n/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.protocol.modbus\nBundle-SymbolicName: org.eclipse.kura.protocol.modbus;singleton:=true\nBundle-Version: 3.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.comm;version=\"[1.0,2.0)\",\n org.eclipse.kura.usb;version=\"[1.0,2.0)\",\n javax.microedition.io;resolution:=optional,\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.io,\n org.slf4j;version=\"1.6.4\"\nExport-Package: org.eclipse.kura.protocol.modbus;version=\"1.0.1\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nBundle-Classpath: .,\n ../target-definition/equinox_3.8.1/repository/plugins/org.eclipse.equinox.io_1.0.400.v20120522-2049.jar\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/OSGI-INF/modbusProtocolDevice.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" name=\"org.eclipse.kura.protocol.modbus.ModbusProtocolDevice\">\n   <implementation class=\"org.eclipse.kura.protocol.modbus.ModbusProtocolDevice\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.protocol.modbus.ModbusProtocolDeviceService\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.protocol.modbus.ModbusProtocolDeviceService\"/>\n   \n   <reference bind=\"setConnectionFactory\" \n   \t\t\t  cardinality=\"1..1\" \n   \t\t\t  interface=\"org.osgi.service.io.ConnectionFactory\" \n   \t\t\t  name=\"ConnectionFactory\" \n   \t\t\t  policy=\"static\" \n   \t\t\t  unbind=\"unsetConnectionFactory\"/>\n   \t\t\t  \n   <reference name=\"UsbService\"\n              bind=\"setUsbService\"\n              unbind=\"unsetUsbService\"\n              cardinality=\"1..1\"\n              policy=\"static\"\n              interface=\"org.eclipse.kura.usb.UsbService\"/>              \n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nadditional.bundles = slf4j.api,\\\n                     org.eclipse.equinox.io\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.protocol.modbus</artifactId>\n\t<version>3.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.protocol.modbus.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\t\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>de.dentrassi.maven</groupId>\n\t\t\t\t<artifactId>osgi-dp</artifactId>\n\t\t\t\t<version>${osgi-dp-plugin-version}</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>build</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n        \t\t<groupId>org.apache.maven.plugins</groupId>\n        \t\t<artifactId>maven-checkstyle-plugin</artifactId>\n        \t\t<configuration>\n        \t\t\t<skip>true</skip>\n        \t\t</configuration>\n        \t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/Crc16.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\n/**\n * Used to calculate the CRC-16 (cyclical redundancy check) for an array of bytes.\n */\npublic class Crc16 {\n\n    private Crc16() {\n    }\n\n    /**\n     * calculate the crc for the passed buffer\n     *\n     * @param buff\n     *            byte array to calculate CRC of\n     * @param buffLen\n     *            number of bytes in array to calculate against\n     * @param crcSeed\n     *            starting seed for CRC calculation\n     * @return CRC16 as calculated for buff\n     */\n    public static int getCrc16(byte[] buff, int buffLen, int crcSeed) {\n        int hi, lo, tmp;\n\n        lo = crcSeed & 0x0ff;\n        hi = crcSeed >> 8 & 0x0ff;\n\n        for (int i = 0; i < buffLen; i++) {\n            tmp = (lo ^ buff[i]) & 0x0ff;\n            lo = hi ^ abCrcTbl2[tmp];\n            hi = abCrcTbl1[tmp];\n        }\n        return lo + (hi << 8);\n    }\n\n    private final static int[] abCrcTbl1 = { 0x000, 0x0C0, 0x0C1, 0x001, 0x0C3, 0x003, 0x002, 0x0C2, 0x0C6, 0x006,\n            0x007, 0x0C7, 0x005, 0x0C5, 0x0C4, 0x004, 0x0CC, 0x00C, 0x00D, 0x0CD, 0x00F, 0x0CF, 0x0CE, 0x00E, 0x00A,\n            0x0CA, 0x0CB, 0x00B, 0x0C9, 0x009, 0x008, 0x0C8, 0x0D8, 0x018, 0x019, 0x0D9, 0x01B, 0x0DB, 0x0DA, 0x01A,\n            0x01E, 0x0DE, 0x0DF, 0x01F, 0x0DD, 0x01D, 0x01C, 0x0DC, 0x014, 0x0D4, 0x0D5, 0x015, 0x0D7, 0x017, 0x016,\n            0x0D6, 0x0D2, 0x012, 0x013, 0x0D3, 0x011, 0x0D1, 0x0D0, 0x010, 0x0F0, 0x030, 0x031, 0x0F1, 0x033, 0x0F3,\n            0x0F2, 0x032, 0x036, 0x0F6, 0x0F7, 0x037, 0x0F5, 0x035, 0x034, 0x0F4, 0x03C, 0x0FC, 0x0FD, 0x03D, 0x0FF,\n            0x03F, 0x03E, 0x0FE, 0x0FA, 0x03A, 0x03B, 0x0FB, 0x039, 0x0F9, 0x0F8, 0x038, 0x028, 0x0E8, 0x0E9, 0x029,\n            0x0EB, 0x02B, 0x02A, 0x0EA, 0x0EE, 0x02E, 0x02F, 0x0EF, 0x02D, 0x0ED, 0x0EC, 0x02C, 0x0E4, 0x024, 0x025,\n            0x0E5, 0x027, 0x0E7, 0x0E6, 0x026, 0x022, 0x0E2, 0x0E3, 0x023, 0x0E1, 0x021, 0x020, 0x0E0, 0x0A0, 0x060,\n            0x061, 0x0A1, 0x063, 0x0A3, 0x0A2, 0x062, 0x066, 0x0A6, 0x0A7, 0x067, 0x0A5, 0x065, 0x064, 0x0A4, 0x06C,\n            0x0AC, 0x0AD, 0x06D, 0x0AF, 0x06F, 0x06E, 0x0AE, 0x0AA, 0x06A, 0x06B, 0x0AB, 0x069, 0x0A9, 0x0A8, 0x068,\n            0x078, 0x0B8, 0x0B9, 0x079, 0x0BB, 0x07B, 0x07A, 0x0BA, 0x0BE, 0x07E, 0x07F, 0x0BF, 0x07D, 0x0BD, 0x0BC,\n            0x07C, 0x0B4, 0x074, 0x075, 0x0B5, 0x077, 0x0B7, 0x0B6, 0x076, 0x072, 0x0B2, 0x0B3, 0x073, 0x0B1, 0x071,\n            0x070, 0x0B0, 0x050, 0x090, 0x091, 0x051, 0x093, 0x053, 0x052, 0x092, 0x096, 0x056, 0x057, 0x097, 0x055,\n            0x095, 0x094, 0x054, 0x09C, 0x05C, 0x05D, 0x09D, 0x05F, 0x09F, 0x09E, 0x05E, 0x05A, 0x09A, 0x09B, 0x05B,\n            0x099, 0x059, 0x058, 0x098, 0x088, 0x048, 0x049, 0x089, 0x04B, 0x08B, 0x08A, 0x04A, 0x04E, 0x08E, 0x08F,\n            0x04F, 0x08D, 0x04D, 0x04C, 0x08C, 0x044, 0x084, 0x085, 0x045, 0x087, 0x047, 0x046, 0x086, 0x082, 0x042,\n            0x043, 0x083, 0x041, 0x081, 0x080, 0x040 };\n\n    private final static int[] abCrcTbl2 = { 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080,\n            0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081,\n            0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081,\n            0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080,\n            0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081,\n            0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080,\n            0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080,\n            0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081,\n            0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081,\n            0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080,\n            0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080,\n            0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081,\n            0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080,\n            0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081,\n            0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x00, 0x0C1, 0x081,\n            0x40, 0x01, 0x0C0, 0x080, 0x41, 0x00, 0x0C1, 0x081, 0x40, 0x01, 0x0C0, 0x080, 0x41, 0x01, 0x0C0, 0x080,\n            0x41, 0x00, 0x0C1, 0x081, 0x40 };\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/ModbusCommEvent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\n/**\n * The ModbusCommEvent class contains the values returned by Modbus functions 11(0x0B)\n * and 12(0x0C).\n * <ul>\n * <li>status : two-bytes status word, 0xFFFF if a busy condition exists, 0 otherwise\n * <li>eventCount : event counter incremented for each successful message completion\n * <li>messageCount : quantity of messages processed since last restart\n * <li>events[] : 0 to 64 bytes, each byte corresponding to the status of one Modbus\n * </ul>\n * send or receive operation, byte 0 is the most recent event.\n */\npublic class ModbusCommEvent {\n\n    private int status;\n    private int eventCount;\n    private int messageCount;\n    private int[] events;\n\n    public ModbusCommEvent() {\n        this.status = 0;\n        this.eventCount = 0;\n        this.messageCount = 0;\n        this.events = null;\n    }\n\n    public int getStatus() {\n        return this.status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public int getEventCount() {\n        return this.eventCount;\n    }\n\n    public void setEventCount(int eventCount) {\n        this.eventCount = eventCount;\n    }\n\n    public int getMessageCount() {\n        return this.messageCount;\n    }\n\n    public void setMessageCount(int messageCount) {\n        this.messageCount = messageCount;\n    }\n\n    public int[] getEvents() {\n        return this.events;\n    }\n\n    public void setEvents(int[] events) {\n        this.events = events;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/ModbusDataOrder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\n/**\n * This static class defines the possible byte organization in\n * the data stream sent and received. The Modbus protocol only\n * defines one analog data type (16 bit) and only one format\n * for that data in the stream (big endian). Manufactures of\n * various \"Modbus compatible\" field devices have extend and\n * modified the size and arrangementof the data in the stream. Data units may now be 16 or\n * 32 bit sized and may be in a variety of byte arrangements.\n * <p>\n * In the definitions below, the character arrangement making up the definition\n * field value actually represent the ordering of the bytes in the\n * stream. For a hexadecimal number 0x01020304, the '1' is the 0x01\n * byte, '2' is the 0x02 byte, '3' is the 0x03 byte and '4' is the 0x04.\n * <p>\n * The Field values, not the field names should be used in configuration files.\n *\n * @author matt.demaree\n *\n */\npublic class ModbusDataOrder {\n\n    /**\n     *\n     */\n    private ModbusDataOrder() {\n    }\n\n    /**\n     * booleans do not have a specified data order\n     */\n    public static final String MODBUS_BOOLEAN_ORDER = \"none\";\n    /**\n     * this is the Modbus default (note only 16 bit or 2 byte data)\n     */\n    public static final String MODBUS_WORD_ORDER_BIG_ENDIAN = \"12\";\n    public static final String MODBUS_WORD_ORDER_LITTLE_ENDIAN = \"21\";\n    /**\n     * this is the most common 32 bit arrangement used by many devices\n     */\n    public static final String MODBUS_LONG_ORDER_BIG_BIG_ENDIAN = \"1234\";\n    public static final String MODBUS_LONG_ORDER_BIG_LITTLE_ENDIAN = \"2143\";\n    public static final String MODBUS_LONG_ORDER_LITTLE_BIG_ENDIAN = \"3412\";\n    public static final String MODBUS_LONG_ORDER_LITTLE_LITTLE_ENDIAN = \"4321\";\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/ModbusFunctionCodes.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\n/**\n * supported modbus commands\n *\n * @author matt.demaree\n *\n */\npublic class ModbusFunctionCodes {\n\n    /**\n     *\n     */\n    private ModbusFunctionCodes() {\n    }\n\n    public static final int READ_COIL_STATUS = 1;\n    public static final int READ_INPUT_STATUS = 2;\n    public static final int READ_HOLDING_REGS = 3;\n    public static final int READ_INPUT_REGS = 4;\n    public static final int FORCE_SINGLE_COIL = 5;\n    public static final int PRESET_SINGLE_REG = 6;\n    public static final int READ_EXCEPTION_STATUS = 7;\n    public static final int GET_COMM_EVENT_COUNTER = 11;\n    public static final int GET_COMM_EVENT_LOG = 12;\n    public static final int FORCE_MULTIPLE_COILS = 15;\n    public static final int PRESET_MULTIPLE_REGS = 16;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/ModbusProtocolDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketTimeoutException;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.eclipse.kura.KuraConnectionStatus;\nimport org.eclipse.kura.comm.CommConnection;\nimport org.eclipse.kura.comm.CommURI;\nimport org.eclipse.kura.usb.UsbService;\nimport org.eclipse.kura.usb.UsbTtyDevice;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.io.ConnectionFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * The Modbus protocol implements a subset of the Modbus standard command set.\n * It also provides for the extension of some data typing to allow register\n * pairings to hold 32 bit data (see the configureDataMap for more detail).\n * <p>\n * The protocol supports RTU and ASCII mode operation.\n *\n */\npublic class ModbusProtocolDevice implements ModbusProtocolDeviceService {\n\n    private static final Logger logger = LoggerFactory.getLogger(ModbusProtocolDevice.class);\n\n    private ConnectionFactory connectionFactory;\n    private UsbService usbService;\n\n    static final String PROTOCOL_NAME = \"modbus\";\n    public static final String PROTOCOL_CONNECTION_TYPE_SERIAL = \"RS232\";\n    public static final String PROTOCOL_CONNECTION_TYPE_ETHER_RTU = \"TCP-RTU\";\n    public static final String PROTOCOL_CONNECTION_TYPE_ETHER_TCP = \"TCP/IP\";\n    private int respTout;\n    private int txMode;\n    private boolean connConfigd = false;\n    private boolean protConfigd = false;\n    private String connType = null;\n    private Communicate comm;\n    private Properties modbusProperties = null;\n    private static int transactionIndex = 0;\n\n    public void setConnectionFactory(ConnectionFactory connectionFactory) {\n        this.connectionFactory = connectionFactory;\n    }\n\n    public void unsetConnectionFactory(ConnectionFactory connectionFactory) {\n        this.connectionFactory = null;\n    }\n\n    public void setUsbService(UsbService usbService) {\n        this.usbService = usbService;\n    }\n\n    public void unsetUsbService(UsbService usbService) {\n        this.usbService = null;\n    }\n\n    private boolean serialPortExists() {\n        if (this.modbusProperties == null) {\n            return false;\n        }\n\n        String portName = this.modbusProperties.getProperty(\"port\");\n        if (portName != null) {\n            if (portName.contains(\"/dev/\")) {\n                File f = new File(portName);\n                if (f.exists()) {\n                    return true;\n                }\n            } else {\n                List<UsbTtyDevice> utd = this.usbService.getUsbTtyDevices();\n                if (utd != null) {\n                    for (UsbTtyDevice u : utd) {\n                        if (portName.equals(u.getUsbPort())) {\n                            // replace device number with tty\n                            portName = u.getDeviceNode();\n                            this.modbusProperties.setProperty(\"port\", portName);\n                            return true;\n                        }\n                    }\n                }\n            }\n        }\n        return false;\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n    protected void activate(ComponentContext componentContext) {\n        logger.info(\"activate...\");\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.info(\"deactivate...\");\n        try {\n            disconnect();\n        } catch (ModbusProtocolException e) {\n            logger.error(\"ModbusProtocolException :  {}\", e.getCode());\n        }\n    }\n\n    /**\n     * two connection types are available:\n     * <ul>\n     * <li>serial mode (PROTOCOL_CONNECTION_TYPE_SERIAL)\n     *\n     * <li>Ethernet with 2 possible modes : RTU over TCP/IP (PROTOCOL_CONNECTION_TYPE_ETHER_RTU) or real MODBUS-TCP/IP\n     * (PROTOCOL_CONNECTION_TYPE_ETHER_TCP).\n     * <ul>\n     * <p>\n     * <h4>PROTOCOL_CONNECTION_TYPE_SERIAL</h4>\n     * see {@link org.eclipse.kura.comm.CommConnection CommConnection} package for more detail.\n     * <table border=\"1\">\n     * <tr>\n     * <th>Key</th>\n     * <th>Description</th>\n     * </tr>\n     * <tr>\n     * <td>connectionType</td>\n     * <td>\"RS232\" (from PROTOCOL_CONNECTION_TYPE_SERIAL). This parameter indicates the connection type for the\n     * configuration. See {@link org.eclipse.kura.comm.CommConnection CommConnection} for more details on serial port\n     * configuration.\n     * </tr>\n     * <tr>\n     * <td>port</td>\n     * <td>the actual device port, such as \"/dev/ttyUSB0\" in linux</td>\n     * </tr>\n     * <tr>\n     * <td>baudRate</td>\n     * <td>baud rate to be configured for the port</td>\n     * </tr>\n     * <tr>\n     * <td>stopBits</td>\n     * <td>number of stop bits to be configured for the port</td>\n     * </tr>\n     * <tr>\n     * <td>parity</td>\n     * <td>parity mode to be configured for the port</td>\n     * </tr>\n     * <tr>\n     * <td>bitsPerWord</td>\n     * <td>only RTU mode supported, bitsPerWord must be 8</td>\n     * </tr>\n     * </table>\n     * <p>\n     * <h4>PROTOCOL_CONNECTION_TYPE_ETHER_TCP</h4>\n     * The Ethernet mode merely opens a socket and sends the full RTU mode Modbus packet over that socket connection and\n     * expects to receive a full RTU mode Modbus response, including the CRC bytes.\n     * <table border=\"1\">\n     * <tr>\n     * <th>Key</th>\n     * <th>Description</th>\n     * </tr>\n     * <tr>\n     * <td>connectionType</td>\n     * <td>\"ETHERTCP\" (from PROTOCOL_CONNECTION_TYPE_ETHER_TCP). This parameter indicates the connection type for the\n     * configurator.\n     * </tr>\n     * <tr>\n     * <td>ipAddress</td>\n     * <td>the 4 octet IP address of the field device (xxx.xxx.xxx.xxx)</td>\n     * </tr>\n     * <tr>\n     * <td>port</td>\n     * <td>port on the field device to connect to</td>\n     * </tr>\n     * </table>\n     */\n    @Override\n    public void configureConnection(Properties connectionConfig) throws ModbusProtocolException {\n        if ((this.connType = connectionConfig.getProperty(\"connectionType\")) == null) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_CONFIGURATION);\n        }\n\n        this.modbusProperties = connectionConfig;\n\n        String txMode;\n        String respTimeout;\n        if (this.protConfigd || (txMode = connectionConfig.getProperty(\"transmissionMode\")) == null\n                || (respTimeout = connectionConfig.getProperty(\"respTimeout\")) == null) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_CONFIGURATION);\n        }\n        if (txMode.equals(ModbusTransmissionMode.RTU)) {\n            this.txMode = ModbusTransmissionMode.RTU_MODE;\n        } else if (txMode.equals(ModbusTransmissionMode.ASCII)) {\n            this.txMode = ModbusTransmissionMode.ASCII_MODE;\n        } else {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_CONFIGURATION);\n        }\n        this.respTout = Integer.parseInt(respTimeout);\n        if (this.respTout < 0) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_CONFIGURATION);\n        }\n        this.protConfigd = true;\n\n        if (this.connConfigd) {\n            this.comm.disconnect();\n            this.comm = null;\n            this.connConfigd = false;\n        }\n\n        if (PROTOCOL_CONNECTION_TYPE_SERIAL.equals(this.connType)) {\n            if (!serialPortExists()) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_AVAILABLE);\n            }\n            this.comm = new SerialCommunicate(this.connectionFactory, connectionConfig);\n        } else if (PROTOCOL_CONNECTION_TYPE_ETHER_TCP.equals(this.connType)\n                || PROTOCOL_CONNECTION_TYPE_ETHER_RTU.equals(this.connType)) {\n            this.comm = new EthernetCommunicate(this.connectionFactory, connectionConfig);\n        } else {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_CONFIGURATION);\n        }\n\n        this.connConfigd = true;\n    }\n\n    /**\n     * get the name \"modbus\" for this protocol\n     *\n     * @return \"modbus\"\n     */\n    @Override\n    public String getProtocolName() {\n        return \"modbus\";\n    }\n\n    @Override\n    public void connect() throws ModbusProtocolException {\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_CONFIGURATION);\n        }\n        this.comm.connect();\n    }\n\n    @Override\n    public void disconnect() throws ModbusProtocolException {\n        if (this.connConfigd) {\n            this.comm.disconnect();\n            this.comm = null;\n            this.connConfigd = false;\n            logger.info(\"Serial comm disconnected\");\n        }\n        this.protConfigd = false;\n    }\n\n    @Override\n    public int getConnectStatus() {\n        if (!this.connConfigd) {\n            return KuraConnectionStatus.NEVERCONNECTED;\n        }\n        return this.comm.getConnectStatus();\n    }\n\n    /**\n     * The only constructor must be the configuration mechanism\n     */\n    abstract private class Communicate {\n\n        abstract public void connect();\n\n        abstract public void disconnect() throws ModbusProtocolException;\n\n        abstract public int getConnectStatus();\n\n        abstract public byte[] msgTransaction(byte[] msg) throws ModbusProtocolException;\n    }\n\n    /**\n     * Installation of a serial connection to communicate, using javax.comm.SerialPort\n     * <p>\n     * <table border=\"1\">\n     * <tr>\n     * <th>Key</th>\n     * <th>Description</th>\n     * </tr>\n     * <tr>\n     * <td>port</td>\n     * <td>the actual device port, such as \"/dev/ttyUSB0\" in linux</td>\n     * </tr>\n     * <tr>\n     * <td>serialMode</td>\n     * <td>SERIAL_232 or SERIAL_485</td>\n     * </tr>\n     * <tr>\n     * <td>baudRate</td>\n     * <td>baud rate to be configured for the port</td>\n     * </tr>\n     * <tr>\n     * <td>stopBits</td>\n     * <td>number of stop bits to be configured for the port</td>\n     * </tr>\n     * <tr>\n     * <td>parity</td>\n     * <td>parity mode to be configured for the port</td>\n     * </tr>\n     * <tr>\n     * <td>bitsPerWord</td>\n     * <td>only RTU mode supported, bitsPerWord must be 8</td>\n     * </tr>\n     * </table>\n     * see {@link org.eclipse.kura.comm.CommConnection CommConnection} package for more detail.\n     */\n    private final class SerialCommunicate extends Communicate {\n\n        InputStream in;\n        OutputStream out;\n        CommConnection conn = null;\n\n        public SerialCommunicate(ConnectionFactory connFactory, Properties connectionConfig)\n                throws ModbusProtocolException {\n            logger.info(\"Configure serial connection\");\n\n            String sPort;\n            String sBaud;\n            String sStop;\n            String sParity;\n            String sBits;\n\n            if ((sPort = connectionConfig.getProperty(\"port\")) == null\n                    || (sBaud = connectionConfig.getProperty(\"baudRate\")) == null\n                    || (sStop = connectionConfig.getProperty(\"stopBits\")) == null\n                    || (sParity = connectionConfig.getProperty(\"parity\")) == null\n                    || (sBits = connectionConfig.getProperty(\"bitsPerWord\")) == null) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_CONFIGURATION);\n            }\n\n            int baud = Integer.valueOf(sBaud).intValue();\n            int stop = Integer.valueOf(sStop).intValue();\n            int parity = Integer.valueOf(sParity).intValue();\n            int bits = Integer.valueOf(sBits).intValue();\n\n            String uri = new CommURI.Builder(sPort).withBaudRate(baud).withDataBits(bits).withStopBits(stop)\n                    .withParity(parity).withTimeout(2000).build().toString();\n\n            try {\n                this.conn = (CommConnection) connFactory.createConnection(uri, 1, false);\n            } catch (IOException e1) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.CONNECTION_FAILURE, e1.getMessage());\n            }\n\n            // get the streams\n            try {\n                this.in = this.conn.openInputStream();\n                this.out = this.conn.openOutputStream();\n            } catch (Exception e) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.CONNECTION_FAILURE, e);\n            }\n            logger.info(\"Serial connection connected\");\n        }\n\n        @Override\n        public void connect() {\n            /*\n             * always connected\n             */\n        }\n\n        @Override\n        public void disconnect() throws ModbusProtocolException {\n            if (this.conn != null) {\n                try {\n                    this.conn.close();\n                    logger.debug(\"Serial connection closed\");\n                } catch (IOException e) {\n                    throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE, e.getMessage());\n                }\n                this.conn = null;\n            }\n        }\n\n        @Override\n        public int getConnectStatus() {\n            return KuraConnectionStatus.CONNECTED;\n        }\n\n        private byte asciiLrcCalc(byte[] msg, int len) {\n            char[] ac = new char[2];\n            ac[0] = (char) msg[len - 4];\n            ac[1] = (char) msg[len - 3];\n            String s = new String(ac);\n            byte lrc = (byte) Integer.parseInt(s, 16);\n            return lrc;\n        }\n\n        private int binLrcCalc(byte[] msg) {\n            int llrc = 0;\n            for (byte element : msg) {\n                llrc += element & 0xff;\n            }\n            llrc = (llrc ^ 0xff) + 1;\n            // byte lrc=(byte)(llrc & 0x0ff);\n            return llrc;\n        }\n\n        /**\n         * convertCommandToAscii: convert a binary command into a standard Modbus\n         * ASCII frame\n         */\n        private byte[] convertCommandToAscii(byte[] msg) {\n            int lrc = binLrcCalc(msg);\n\n            char[] hexArray = \"0123456789ABCDEF\".toCharArray();\n            byte[] ab = new byte[msg.length * 2 + 5];\n            ab[0] = ':';\n            int v;\n            for (int i = 0; i < msg.length; i++) {\n                v = msg[i] & 0xff;\n                ab[i * 2 + 1] = (byte) hexArray[v >>> 4];\n                ab[i * 2 + 2] = (byte) hexArray[v & 0x0f];\n            }\n            v = lrc & 0x0ff;\n            ab[ab.length - 4] = (byte) hexArray[v >>> 4];\n            ab[ab.length - 3] = (byte) hexArray[v & 0x0f];\n            ab[ab.length - 2] = 13;\n            ab[ab.length - 1] = 10;\n            return ab;\n        }\n\n        /**\n         * convertAsciiResponseToBin: convert a standard Modbus frame to\n         * byte array\n         */\n        private byte[] convertAsciiResponseToBin(byte[] msg, int len) {\n            int l = (len - 5) / 2;\n            byte[] ab = new byte[l];\n            char[] ac = new char[2];\n            // String s=new String(msg);\n            for (int i = 0; i < l; i++) {\n                ac[0] = (char) msg[i * 2 + 1];\n                ac[1] = (char) msg[i * 2 + 2];\n                // String s=new String(ac);\n                ab[i] = (byte) Integer.parseInt(new String(ac), 16);\n            }\n            return ab;\n        }\n\n        /**\n         * msgTransaction must be called with a byte array having two extra\n         * bytes for the CRC. It will return a byte array of the response to the\n         * message. Validation will include checking the CRC and verifying the\n         * command matches.\n         */\n        @Override\n        public byte[] msgTransaction(byte[] msg) throws ModbusProtocolException {\n\n            byte[] cmd = null;\n\n            if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.RTU_MODE) {\n                cmd = new byte[msg.length + 2];\n                for (int i = 0; i < msg.length; i++) {\n                    cmd[i] = msg[i];\n                }\n                // Add crc calculation to end of message\n                int crc = Crc16.getCrc16(msg, msg.length, 0x0ffff);\n                cmd[msg.length] = (byte) crc;\n                cmd[msg.length + 1] = (byte) (crc >> 8);\n            } else if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.ASCII_MODE) {\n                cmd = convertCommandToAscii(msg);\n            }\n\n            // Send the message\n            try {\n                synchronized (this.out) {\n                    synchronized (this.in) {\n                        // flush input\n                        while (this.in.available() > 0) {\n                            this.in.read();\n                        }\n                        // send all data\n                        this.out.write(cmd, 0, cmd.length);\n                        this.out.flush();\n                        // outputStream.waitAllSent(respTout);\n\n                        // wait for and process response\n                        byte[] response = new byte[262]; // response buffer\n                        int respIndex = 0;\n                        int minimumLength = 5; // default minimum message length\n                        if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.ASCII_MODE) {\n                            minimumLength = 11;\n                        }\n                        int timeOut = ModbusProtocolDevice.this.respTout;\n                        for (int maxLoop = 0; maxLoop < 1000; maxLoop++) {\n                            boolean endFrame = false;\n                            // while (respIndex < minimumLength) {\n                            while (!endFrame) {\n                                long start = System.currentTimeMillis();\n                                while (this.in.available() == 0) {\n                                    try {\n                                        Thread.sleep(5);\t// avoid a high cpu load\n                                    } catch (InterruptedException e) {\n                                        throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE,\n                                                \"Thread interrupted\");\n                                    }\n\n                                    long elapsed = System.currentTimeMillis() - start;\n                                    if (elapsed > timeOut) {\n                                        String failMsg = \"Recv timeout\";\n                                        logger.warn(failMsg + \" : \" + elapsed + \" minimumLength=\" + minimumLength\n                                                + \" respIndex=\" + respIndex);\n                                        throw new ModbusProtocolException(ModbusProtocolErrorCode.RESPONSE_TIMEOUT,\n                                                failMsg);\n                                    }\n                                }\n                                // address byte must match first\n                                if (respIndex == 0) {\n                                    if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.ASCII_MODE) {\n                                        if ((response[0] = (byte) this.in.read()) == ':') {\n                                            respIndex++;\n                                        }\n                                    } else {\n                                        if ((response[0] = (byte) this.in.read()) == msg[0]) {\n                                            respIndex++;\n                                        }\n                                    }\n                                } else {\n                                    response[respIndex++] = (byte) this.in.read();\n                                }\n\n                                if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.RTU_MODE) {\n                                    timeOut = 100; // move to character timeout\n                                    if (respIndex >= minimumLength) {\n                                        endFrame = true;\n                                    }\n                                } else {\n                                    if (response[respIndex - 1] == 10 && response[respIndex - 2] == 13) {\n                                        endFrame = true;\n                                    }\n                                }\n                            }\n                            // if ASCII mode convert response\n                            if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.ASCII_MODE) {\n                                byte lrcRec = asciiLrcCalc(response, respIndex);\n                                response = convertAsciiResponseToBin(response, respIndex);\n                                byte lrcCalc = (byte) binLrcCalc(response);\n                                if (lrcRec != lrcCalc) {\n                                    throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE,\n                                            \"Bad LRC\");\n                                }\n                            }\n\n                            // Check first for an Exception response\n                            if ((response[1] & 0x80) == 0x80) {\n                                if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.ASCII_MODE\n                                        || Crc16.getCrc16(response, 5, 0xffff) == 0) {\n                                    throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE,\n                                            \"Exception response = \" + Byte.toString(response[2]));\n                                }\n                            } else {\n                                // then check for a valid message\n                                switch (response[1]) {\n                                case ModbusFunctionCodes.FORCE_SINGLE_COIL:\n                                case ModbusFunctionCodes.PRESET_SINGLE_REG:\n                                case ModbusFunctionCodes.FORCE_MULTIPLE_COILS:\n                                case ModbusFunctionCodes.PRESET_MULTIPLE_REGS:\n                                    if (respIndex < 8) {\n                                        // wait for more data\n                                        minimumLength = 8;\n                                    } else if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.ASCII_MODE\n                                            || Crc16.getCrc16(response, 8, 0xffff) == 0) {\n                                        byte[] ret = new byte[6];\n                                        for (int i = 0; i < 6; i++) {\n                                            ret[i] = response[i];\n                                        }\n                                        return ret;\n                                    }\n                                    break;\n                                case ModbusFunctionCodes.READ_COIL_STATUS:\n                                case ModbusFunctionCodes.READ_INPUT_STATUS:\n                                case ModbusFunctionCodes.READ_INPUT_REGS:\n                                case ModbusFunctionCodes.READ_HOLDING_REGS:\n                                    int byteCnt;\n                                    if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.ASCII_MODE) {\n                                        byteCnt = (response[2] & 0xff) + 3;\n                                    } else {\n                                        byteCnt = (response[2] & 0xff) + 5;\n                                    }\n                                    if (respIndex < byteCnt) {\n                                        // wait for more data\n                                        minimumLength = byteCnt;\n                                    } else if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.ASCII_MODE\n                                            || Crc16.getCrc16(response, byteCnt, 0xffff) == 0) {\n                                        byte[] ret = new byte[byteCnt];\n                                        for (int i = 0; i < byteCnt; i++) {\n                                            ret[i] = response[i];\n                                        }\n                                        return ret;\n                                    }\n                                }\n                            }\n\n                            /*\n                             * if required length then must have failed, drop\n                             * first byte and try again\n                             */\n                            if (respIndex >= minimumLength) {\n                                respIndex--;\n                                for (int i = 0; i < respIndex; i++) {\n                                    response[i] = response[i + 1];\n                                }\n                                minimumLength = 5; // reset minimum length\n                            }\n                        }\n                    }\n                }\n            } catch (IOException e) {\n                // e.printStackTrace();\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE, e.getMessage());\n            }\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE,\n                    \"Too much activity on recv line\");\n        }\n    }\n\n    /**\n     * Installation of an ethernet connection to communicate\n     */\n    private final class EthernetCommunicate extends Communicate {\n\n        InputStream inputStream;\n        OutputStream outputStream;\n        Socket socket;\n        int port;\n        String ipAddress;\n        String connType;\n        boolean connected = false;\n\n        public EthernetCommunicate(ConnectionFactory connFactory, Properties connectionConfig)\n                throws ModbusProtocolException {\n            logger.debug(\"Configure TCP connection\");\n            String sPort;\n            this.connType = connectionConfig.getProperty(\"connectionType\");\n\n            if ((sPort = connectionConfig.getProperty(\"ethport\")) == null\n                    || (this.ipAddress = connectionConfig.getProperty(\"ipAddress\")) == null) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_CONFIGURATION);\n            }\n            this.port = Integer.valueOf(sPort).intValue();\n            ModbusProtocolDevice.this.connConfigd = true;\n            this.socket = new Socket();\n        }\n\n        @Override\n        public void connect() {\n            if (!ModbusProtocolDevice.this.connConfigd) {\n                logger.error(\"Can't connect, port not configured\");\n            } else {\n                if (!this.connected) {\n                    try {\n                        this.socket = new Socket();\n                        this.socket.connect(new InetSocketAddress(this.ipAddress, this.port),\n                                ModbusProtocolDevice.this.respTout);\n                        try {\n                            this.inputStream = this.socket.getInputStream();\n                            this.outputStream = this.socket.getOutputStream();\n                            this.connected = true;\n                            logger.info(\"TCP connected\");\n                        } catch (IOException e) {\n                            disconnect();\n                            logger.error(\"Failed to get socket streams: \" + e);\n                        }\n                    } catch (IOException e) {\n                        this.socket = null;\n                        logger.error(\"Failed to connect to remote: \" + e);\n                    }\n                }\n            }\n        }\n\n        @Override\n        public void disconnect() {\n            if (this.socket == null) {\n                return;\n            }\n            if (ModbusProtocolDevice.this.connConfigd) {\n                if (this.connected) {\n                    try {\n                        if (!this.socket.isInputShutdown()) {\n                            this.socket.shutdownInput();\n                        }\n                        if (!this.socket.isOutputShutdown()) {\n                            this.socket.shutdownOutput();\n                        }\n                        this.socket.close();\n                    } catch (IOException eClose) {\n                        logger.error(\"Error closing TCP: \" + eClose);\n                    }\n                    this.inputStream = null;\n                    this.outputStream = null;\n                    this.connected = false;\n                    this.socket = null;\n                }\n            }\n        }\n\n        @Override\n        public int getConnectStatus() {\n            if (this.connected) {\n                return KuraConnectionStatus.CONNECTED;\n            } else if (ModbusProtocolDevice.this.connConfigd) {\n                return KuraConnectionStatus.DISCONNECTED;\n            } else {\n                return KuraConnectionStatus.NEVERCONNECTED;\n            }\n        }\n\n        @Override\n        public byte[] msgTransaction(byte[] msg) throws ModbusProtocolException {\n            byte[] cmd = null;\n\n            // ---------------------------------------------- Send Message\n            // ---------------------------------------------------\n            if (ModbusProtocolDevice.this.txMode == ModbusTransmissionMode.RTU_MODE) {\n                if (PROTOCOL_CONNECTION_TYPE_ETHER_TCP.equals(this.connType)) {\n                    cmd = new byte[msg.length + 6];\n                    // build MBAP header\n                    int index = getNextTransactionIndex();\n                    cmd[0] = (byte) (index >> 8);\n                    cmd[1] = (byte) index;\n                    cmd[2] = 0;\n                    cmd[3] = 0;\n                    // length\n                    int len = msg.length;\n                    cmd[4] = (byte) (len >> 8);\n                    cmd[5] = (byte) len;\n                    for (int i = 0; i < msg.length; i++) {\n                        cmd[i + 6] = msg[i];\n                    }\n                    // No crc in Modbus TCP\n                } else {\n                    cmd = new byte[msg.length + 2];\n                    for (int i = 0; i < msg.length; i++) {\n                        cmd[i] = msg[i];\n                    }\n                    // Add crc calculation to end of message\n                    int crc = Crc16.getCrc16(msg, msg.length, 0x0ffff);\n                    cmd[msg.length] = (byte) crc;\n                    cmd[msg.length + 1] = (byte) (crc >> 8);\n                }\n            } else {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.METHOD_NOT_SUPPORTED,\n                        \"Only RTU over TCP/IP supported\");\n            }\n\n            // Check connection status and connect\n            connect();\n            if (!this.connected) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE,\n                        \"Cannot transact on closed socket\");\n            }\n\n            // Send the message\n            try {\n                // flush input\n                while (this.inputStream.available() > 0) {\n                    this.inputStream.read();\n                }\n                // send all data\n                this.outputStream.write(cmd, 0, cmd.length);\n                this.outputStream.flush();\n            } catch (IOException e) {\n                // Assume this means the socket is closed...make sure it is\n                logger.error(\"Socket disconnect in send: \" + e);\n                disconnect();\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE,\n                        \"Send failure: \" + e.getMessage());\n            }\n\n            // ---------------------------------------------- Receive response\n            // ---------------------------------------------------\n            // wait for and process response\n\n            boolean endFrame = false;\n            byte[] response = new byte[262]; // response buffer\n            int respIndex = 0;\n            int minimumLength = 5; // default minimum message length\n            if (PROTOCOL_CONNECTION_TYPE_ETHER_TCP.equals(this.connType)) {\n                minimumLength += 6;\n            }\n            while (!endFrame) {\n                try {\n                    this.socket.setSoTimeout(ModbusProtocolDevice.this.respTout);\n                    int resp = this.inputStream.read(response, respIndex, 1);\n                    if (resp > 0) {\n                        respIndex += resp;\n                        if (PROTOCOL_CONNECTION_TYPE_ETHER_TCP.equals(this.connType)) {\n                            if (respIndex == 7) {\n                                // test modbus id\n                                if (response[6] != msg[0]) {\n                                    throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE,\n                                            \"incorrect modbus id \" + String.format(\"%02X\", response[6]));\n                                }\n                            } else if (respIndex == 8) {\n                                // test function number\n                                if ((response[7] & 0x7f) != msg[1]) {\n                                    throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE,\n                                            \"incorrect function number \" + String.format(\"%02X\", response[7]));\n                                }\n                            } else if (respIndex == 9) {\n                                // Check first for an Exception response\n                                if ((response[7] & 0x80) == 0x80) {\n                                    throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE,\n                                            \"Modbus responds an error = \" + String.format(\"%02X\", response[8]));\n                                } else {\n                                    if (response[7] == ModbusFunctionCodes.FORCE_SINGLE_COIL\n                                            || response[7] == ModbusFunctionCodes.PRESET_SINGLE_REG\n                                            || response[7] == ModbusFunctionCodes.FORCE_MULTIPLE_COILS\n                                            || response[7] == ModbusFunctionCodes.PRESET_MULTIPLE_REGS) {\n                                        minimumLength = 12;\n                                    } else {\n                                        // bytes count\n                                        minimumLength = (response[8] & 0xff) + 9;\n                                    }\n                                }\n                            } else if (respIndex == minimumLength) {\n                                endFrame = true;\n                            }\n                        } else {\n\n                        }\n                    } else {\n                        logger.error(\"Socket disconnect in recv\");\n                        throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE, \"Recv failure\");\n                    }\n                } catch (SocketTimeoutException e) {\n                    String failMsg = \"Recv timeout\";\n                    logger.warn(failMsg);\n                    throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE, failMsg);\n                } catch (IOException e) {\n                    logger.error(\"Socket disconnect in recv: \" + e);\n                    throw new ModbusProtocolException(ModbusProtocolErrorCode.TRANSACTION_FAILURE, \"Recv failure\");\n                }\n\n            }\n\n            // then check for a valid message\n            switch (response[7]) {\n            case ModbusFunctionCodes.FORCE_SINGLE_COIL:\n            case ModbusFunctionCodes.PRESET_SINGLE_REG:\n            case ModbusFunctionCodes.FORCE_MULTIPLE_COILS:\n            case ModbusFunctionCodes.PRESET_MULTIPLE_REGS:\n                byte[] ret = new byte[8];\n                for (int i = 6; i < 12; i++) {\n                    ret[i - 6] = response[i];\n                }\n                return ret;\n            case ModbusFunctionCodes.READ_COIL_STATUS:\n            case ModbusFunctionCodes.READ_INPUT_STATUS:\n            case ModbusFunctionCodes.READ_INPUT_REGS:\n            case ModbusFunctionCodes.READ_HOLDING_REGS:\n                int byteCnt = (response[8] & 0xff) + 3 + 6;\n                ret = new byte[byteCnt - 6];\n                for (int i = 6; i < byteCnt; i++) {\n                    ret[i - 6] = response[i];\n                }\n                return ret;\n            }\n            return null;\n        }\n    }\n\n    @Override\n    public boolean[] readCoils(int unitAddr, int dataAddress, int count) throws ModbusProtocolException {\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        boolean[] ret = new boolean[count];\n        int index = 0;\n\n        byte[] resp;\n        /*\n         * construct the command issue and get results\n         */\n        byte[] cmd = new byte[6];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = (byte) ModbusFunctionCodes.READ_COIL_STATUS;\n        cmd[2] = (byte) (dataAddress / 256);\n        cmd[3] = (byte) (dataAddress % 256);\n        cmd[4] = (byte) (count / 256);\n        cmd[5] = (byte) (count % 256);\n\n        /*\n         * send the message and get the response\n         */\n        resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response (address & CRC already confirmed)\n         */\n        if (resp.length < 3 || resp.length < (resp[2] & 0xff) + 3) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        if ((resp[2] & 0xff) == (count + 7) / 8) {\n            byte mask = 1;\n            int byteOffset = 3;\n            for (int j = 0; j < count; j++, index++) {\n                // get this point's value\n                if ((resp[byteOffset] & mask) == mask) {\n                    ret[index] = true;\n                } else {\n                    ret[index] = false;\n                }\n                // advance the mask and offset index\n                if ((mask <<= 1) == 0) {\n                    mask = 1;\n                    byteOffset++;\n                }\n            }\n        } else {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_ADDRESS);\n        }\n\n        return ret;\n    }\n\n    @Override\n    public boolean[] readDiscreteInputs(int unitAddr, int dataAddress, int count) throws ModbusProtocolException {\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        boolean[] ret = new boolean[count];\n        int index = 0;\n\n        byte[] resp;\n        /*\n         * construct the command issue and get results\n         */\n        byte[] cmd = new byte[6];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = (byte) ModbusFunctionCodes.READ_INPUT_STATUS;\n        cmd[2] = (byte) (dataAddress / 256);\n        cmd[3] = (byte) (dataAddress % 256);\n        cmd[4] = (byte) (count / 256);\n        cmd[5] = (byte) (count % 256);\n\n        /*\n         * send the message and get the response\n         */\n        resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response (address & CRC already confirmed)\n         */\n        if (resp.length < 3 || resp.length < (resp[2] & 0xff) + 3) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        if ((resp[2] & 0xff) == (count + 7) / 8) {\n            byte mask = 1;\n            int byteOffset = 3;\n            for (int j = 0; j < count; j++, index++) {\n                // get this point's value\n                if ((resp[byteOffset] & mask) == mask) {\n                    ret[index] = true;\n                } else {\n                    ret[index] = false;\n                }\n                // advance the mask and offset index\n                if ((mask <<= 1) == 0) {\n                    mask = 1;\n                    byteOffset++;\n                }\n            }\n        } else {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_ADDRESS);\n        }\n\n        return ret;\n    }\n\n    @Override\n    public void writeSingleCoil(int unitAddr, int dataAddress, boolean data) throws ModbusProtocolException {\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        byte[] resp;\n\n        byte[] cmd = new byte[6];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = ModbusFunctionCodes.FORCE_SINGLE_COIL;\n        cmd[2] = (byte) (dataAddress / 256);\n        cmd[3] = (byte) (dataAddress % 256);\n        cmd[4] = data == true ? (byte) 0xff : (byte) 0;\n        cmd[5] = 0;\n\n        /*\n         * send the message and get the response\n         */\n        resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response\n         */\n        if (resp.length < 6) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        for (int i = 0; i < 6; i++) {\n            if (cmd[i] != resp[i]) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n            }\n        }\n\n    }\n\n    @Override\n    public void writeMultipleCoils(int unitAddr, int dataAddress, boolean[] data) throws ModbusProtocolException {\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        /*\n         * write multiple boolean values\n         */\n        int localCnt = data.length;\n        int index = 0;\n        byte[] resp;\n        /*\n         * construct the command, issue and verify response\n         */\n        int dataLength = (localCnt + 7) / 8;\n        byte[] cmd = new byte[dataLength + 7];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = ModbusFunctionCodes.FORCE_MULTIPLE_COILS;\n        cmd[2] = (byte) (dataAddress / 256);\n        cmd[3] = (byte) (dataAddress % 256);\n        cmd[4] = (byte) (localCnt / 256);\n        cmd[5] = (byte) (localCnt % 256);\n        cmd[6] = (byte) dataLength;\n\n        // put the data on the command\n        byte mask = 1;\n        int byteOffset = 7;\n        cmd[byteOffset] = 0;\n        for (int j = 0; j < localCnt; j++, index++) {\n            // get this point's value\n            if (data[index]) {\n                cmd[byteOffset] += mask;\n            }\n            // advance the mask and offset index\n            if ((mask <<= 1) == 0) {\n                mask = 1;\n                byteOffset++;\n                cmd[byteOffset] = 0;\n            }\n        }\n\n        /*\n         * send the message and get the response\n         */\n        resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response\n         */\n        if (resp.length < 6) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        for (int j = 0; j < 6; j++) {\n            if (cmd[j] != resp[j]) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n            }\n        }\n    }\n\n    @Override\n    public int[] readHoldingRegisters(int unitAddr, int dataAddress, int count) throws ModbusProtocolException {\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        int[] ret = new int[count];\n        int index = 0;\n\n        byte[] resp;\n        /*\n         * construct the command issue and get results, putting the results\n         * away at index and then incrementing index for the next command\n         */\n        byte[] cmd = new byte[6];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = (byte) ModbusFunctionCodes.READ_HOLDING_REGS;\n        cmd[2] = (byte) (dataAddress / 256);\n        cmd[3] = (byte) (dataAddress % 256);\n        cmd[4] = 0;\n        cmd[5] = (byte) count;\n\n        /*\n         * send the message and get the response\n         */\n        resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response (address & CRC already confirmed)\n         */\n        if (resp.length < 3 || resp.length < (resp[2] & 0xff) + 3) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        if ((resp[2] & 0xff) == count * 2) {\n            int byteOffset = 3;\n            for (int j = 0; j < count; j++, index++) {\n                int val = resp[byteOffset + ModbusDataOrder.MODBUS_WORD_ORDER_BIG_ENDIAN.charAt(0) - '1'] & 0xff;\n                val <<= 8;\n                val += resp[byteOffset + ModbusDataOrder.MODBUS_WORD_ORDER_BIG_ENDIAN.charAt(1) - '1'] & 0xff;\n\n                ret[index] = val;\n\n                byteOffset += 2;\n            }\n        } else {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_ADDRESS);\n        }\n        return ret;\n    }\n\n    @Override\n    public int[] readInputRegisters(int unitAddr, int dataAddress, int count) throws ModbusProtocolException {\n\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        int[] ret = new int[count];\n        int index = 0;\n\n        byte[] resp;\n        /*\n         * construct the command issue and get results, putting the results\n         * away at index and then incrementing index for the next command\n         */\n        byte[] cmd = new byte[6];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = (byte) ModbusFunctionCodes.READ_INPUT_REGS;\n        cmd[2] = (byte) (dataAddress / 256);\n        cmd[3] = (byte) (dataAddress % 256);\n        cmd[4] = 0;\n        cmd[5] = (byte) count;\n\n        /*\n         * send the message and get the response\n         */\n        resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response (address & CRC already confirmed)\n         */\n        if (resp.length < 3 || resp.length < (resp[2] & 0xff) + 3) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        if ((resp[2] & 0xff) == count * 2) {\n            int byteOffset = 3;\n            for (int j = 0; j < count; j++, index++) {\n                int val = resp[byteOffset + ModbusDataOrder.MODBUS_WORD_ORDER_BIG_ENDIAN.charAt(0) - '1'] & 0xff;\n                val <<= 8;\n                val += resp[byteOffset + ModbusDataOrder.MODBUS_WORD_ORDER_BIG_ENDIAN.charAt(1) - '1'] & 0xff;\n\n                ret[index] = val;\n\n                byteOffset += 2;\n            }\n        } else {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_ADDRESS);\n        }\n        return ret;\n    }\n\n    @Override\n    public void writeSingleRegister(int unitAddr, int dataAddress, int data) throws ModbusProtocolException {\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        byte[] cmd = new byte[6];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = ModbusFunctionCodes.PRESET_SINGLE_REG;\n        cmd[2] = (byte) (dataAddress / 256);\n        cmd[3] = (byte) (dataAddress % 256);\n        cmd[4] = (byte) (data >> 8);\n        cmd[5] = (byte) data;\n\n        /*\n         * send the message and get the response\n         */\n        byte[] resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response\n         */\n        if (resp.length < 6) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        for (int i = 0; i < 6; i++) {\n            if (cmd[i] != resp[i]) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n            }\n        }\n    }\n\n    @Override\n    public void writeMultipleRegister(int unitAddr, int dataAddress, int[] data) throws ModbusProtocolException {\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        int localCnt = data.length;\n        /*\n         * construct the command, issue and verify response\n         */\n        int dataLength = localCnt * 2;\n        byte[] cmd = new byte[dataLength + 7];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = ModbusFunctionCodes.PRESET_MULTIPLE_REGS;\n        cmd[2] = (byte) (dataAddress / 256);\n        cmd[3] = (byte) (dataAddress % 256);\n        cmd[4] = (byte) (localCnt / 256);\n        cmd[5] = (byte) (localCnt % 256);\n        cmd[6] = (byte) dataLength;\n\n        // put the data on the command\n        int byteOffset = 7;\n        int index = 0;\n        for (int j = 0; j < localCnt; j++, index++) {\n            cmd[byteOffset + ModbusDataOrder.MODBUS_WORD_ORDER_BIG_ENDIAN.charAt(0) - '1'] = (byte) (data[index] >> 8);\n            cmd[byteOffset + ModbusDataOrder.MODBUS_WORD_ORDER_BIG_ENDIAN.charAt(1) - '1'] = (byte) data[index];\n\n            byteOffset += 2;\n        }\n\n        /*\n         * send the message and get the response\n         */\n        byte[] resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response\n         */\n        if (resp.length < 6) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        for (int j = 0; j < 6; j++) {\n            if (cmd[j] != resp[j]) {\n                throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n            }\n        }\n    }\n\n    @Override\n    public boolean[] readExceptionStatus(int unitAddr) throws ModbusProtocolException {\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        boolean[] ret = new boolean[8];\n        int index = 0;\n\n        byte[] resp;\n        /*\n         * construct the command issue and get results\n         */\n        byte[] cmd = new byte[2];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = (byte) ModbusFunctionCodes.READ_EXCEPTION_STATUS;\n\n        /*\n         * send the message and get the response\n         */\n        resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response (address & CRC already confirmed)\n         */\n        if (resp.length < 3) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        byte mask = 1;\n        for (int j = 0; j < 8; j++, index++) {\n            // get this point's value\n            if ((resp[2] & mask) == mask) {\n                ret[index] = true;\n            } else {\n                ret[index] = false;\n            }\n            // advance the mask and offset index\n            if ((mask <<= 1) == 0) {\n                mask = 1;\n            }\n        }\n\n        return ret;\n    }\n\n    @Override\n    public ModbusCommEvent getCommEventCounter(int unitAddr) throws ModbusProtocolException {\n        ModbusCommEvent mce = new ModbusCommEvent();\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        /*\n         * construct the command issue and get results\n         */\n        byte[] cmd = new byte[2];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = (byte) ModbusFunctionCodes.GET_COMM_EVENT_COUNTER;\n\n        /*\n         * send the message and get the response\n         */\n        byte[] resp;\n        resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response (address & CRC already confirmed)\n         */\n        if (resp.length < 6) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        int val = resp[2] & 0xff;\n        val <<= 8;\n        val += resp[3] & 0xff;\n        mce.setStatus(val);\n        val = resp[4] & 0xff;\n        val <<= 8;\n        val += resp[5] & 0xff;\n        mce.setEventCount(val);\n\n        return mce;\n    }\n\n    @Override\n    public ModbusCommEvent getCommEventLog(int unitAddr) throws ModbusProtocolException {\n        ModbusCommEvent mce = new ModbusCommEvent();\n        if (!this.connConfigd) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.NOT_CONNECTED);\n        }\n\n        /*\n         * construct the command issue and get results\n         */\n        byte[] cmd = new byte[2];\n        cmd[0] = (byte) unitAddr;\n        cmd[1] = (byte) ModbusFunctionCodes.GET_COMM_EVENT_LOG;\n\n        /*\n         * send the message and get the response\n         */\n        byte[] resp;\n        resp = this.comm.msgTransaction(cmd);\n\n        /*\n         * process the response (address & CRC already confirmed)\n         */\n        if (resp.length < (resp[2] & 0xff) + 3 || (resp[2] & 0xff) > 64 + 7) {\n            throw new ModbusProtocolException(ModbusProtocolErrorCode.INVALID_DATA_TYPE);\n        }\n        int val = resp[3] & 0xff;\n        val <<= 8;\n        val += resp[4] & 0xff;\n        mce.setStatus(val);\n\n        val = resp[5] & 0xff;\n        val <<= 8;\n        val += resp[6] & 0xff;\n        mce.setEventCount(val);\n\n        val = resp[7] & 0xff;\n        val <<= 8;\n        val += resp[8] & 0xff;\n        mce.setMessageCount(val);\n\n        int count = (resp[2] & 0xff) - 4;\n        int[] events = new int[count];\n        for (int j = 0; j < count; j++) {\n            int bval = resp[9 + j] & 0xff;\n            events[j] = bval;\n        }\n        mce.setEvents(events);\n\n        return mce;\n    }\n\n    /**\n     * Calculates and returns the next transaction index for Modbus TCP.\n     *\n     * @return the next transaction index.\n     */\n    private int getNextTransactionIndex() {\n        transactionIndex++;\n        if (transactionIndex > 0xffff) {\n            transactionIndex = 0;\n        }\n        return transactionIndex;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/ModbusProtocolDeviceService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\nimport java.util.Properties;\n\nimport org.eclipse.kura.KuraConnectionStatus;\n\n/**\n * OSGI service providing a connection to a device via Serial link (RS232/RS485) or Ethernet using Modbus protocol.\n * This service implements a subset of Modbus Application Protocol as defined by Modbus Organization :\n * http://www.modbus.org/specs.php.<br>\n * For the moment in Ethernet mode, only RTU over TCP/IP is supported\n * <p>\n * Function codes implemented are :\n * <ul>\n * <li>01 (0x01) readCoils(int dataAddress, int count) : Read 1 to 2000 max contiguous status of coils from the attached\n * field device.\n * It returns an array of booleans representing the requested data points.\n * <li>02 (0x02) readDiscreteInputs(int dataAddress, int count) : Read 1 to 2000 max contiguous status of discrete\n * inputs\n * from the attached field device. It returns an array of booleans representing the requested data points.\n * <li>03 (0x03) readHoldingRegisters(int dataAddress, int count) : Read contents of 1 to 125 max contiguous block of\n * holding\n * registers from the attached field device. It returns an array of int representing the requested data points\n * (data registers on 2 bytes).\n * <li>04 (0x04) readInputRegisters(int dataAddress, int count) : Read contents of 1 to 125 max contiguous block of\n * input registers\n * from the attached field device. It returns an array of int representing the requested data points (data registers on\n * 2 bytes).\n * <li>05 (0x05) writeSingleCoil(int dataAddress, boolean data) : Write a single output to either ON or OFF in the\n * attached field\n * device.\n * <li>06 (0x06) writeSingleRegister(int dataAddress, int data) : write a single holding register in the attached field\n * device.\n * <li>07 (0x07) readExceptionStatus() : read the content of 8 Exception Status outputs in the field\n * device.\n * <li>11 (0x0B) getCommEventCounter() : Get a status word and an event count from the field\n * device.\n * <li>12 (0x0C) getCommEventLog() : Get a status word, an event count, a message count and a list of event bytes from\n * the field\n * device.\n * <li>15 (0x0F) writeMultipleCoils(int dataAddress, boolean[] data) : Write multiple coils in a sequence of coils to\n * either\n * ON or OFF in the attached field device.\n * <li>16 (0x10) writeMultipleRegister(int dataAddress, int[] data) : write a block of contiguous registers (1 to 123)\n * in the attached\n * field device.\n * </ul>\n */\n\npublic interface ModbusProtocolDeviceService {\n\n    /**\n     * name of this service\n     */\n    public static final String SERVICE_NAME = ModbusProtocolDeviceService.class.getName();\n\n    /**\n     * returns the unit name given in the configureProtocol call. Prior to\n     * configuration, this method will return the built-in name of the protocol,\n     * the same as returned by getProtocolName.\n     *\n     * @return assigned unit name\n     *\n     * @see java.lang.Object#toString()\n     */\n    @Override\n    public String toString();\n\n    /**\n     * returns the protocol name for the specific protocol implemented. This\n     * name should follow Java member naming conventions, so the first (or only)\n     * part of the name should be all lower case, all subsequent parts to the\n     * name should begin with an upper case and continue with lower case.\n     *\n     * @return name following the above rules\n     */\n    public String getProtocolName();\n\n    /**\n     * Configure access to the physical device.\n     *\n     * @param connectionConfig\n     *            (key/value pairing directly from configuration file)\n     *            <ul>\n     *            <li>connectionType : serial = \"RS232\" or Ethernet = \"TCP-RTU\" = RTU over TCP/IP or\n     *            \"TCP/IP\" = real MODBUS-TCP/IP\n     *            </ul>\n     *            <br>\n     *            for SERIAL mode :\n     *            <ul>\n     *            <li>port : Name of the port (\"/dev/ttyUSB0\")\n     *            <li>baudRate : baudrate\n     *            <li>stopBits : number of stopbits\n     *            <li>parity : parity mode (0=none, 1=odd, 2=even)\n     *            <li>bitsPerWord : number of bits per word\n     *            </ul>\n     *            <br>\n     *            for ETHERNET mode :\n     *            <ul>\n     *            <li>port : TCP port to be used\n     *            <li>ipAddress : the 4 bytes IP address of the field device (xxx.xxx.xxx.xxx)\n     *            </ul>\n     *            <br>\n     *            Modbus properties :\n     *            <ul>\n     *            <li>transmissionMode : modbus transmission mode, can be RTU or ASCII, in Ethernet mode only RTU is\n     *            supported\n     *            <li>respTimeout : Timeout in milliseconds on a question/response request.\n     *            </ul>\n     * \n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#INVALID_CONFIGURATION}\n     *             unspecified problem with the configuration\n     */\n    public void configureConnection(Properties connectionConfig) throws ModbusProtocolException;\n\n    /**\n     * for expedience, can test the status of the connection prior to attempting\n     * a command. A connection status of <b>CONNECTED</b> does not assure that a\n     * subsequent command will succeed.\n     * <p>\n     * All protocols must implement this method.\n     *\n     * @return current connection status as defined in\n     *         {@link KuraConnectionStatus KuraConnectionStatus}.\n     */\n    public int getConnectStatus();\n\n    /**\n     * attempt to connect to the field device using the provided configuration.\n     * Attempts to connect before configuring the connection or any issues with\n     * connecting to the field device will result in an exception being thrown.\n     * This includes things like a networking failure in the case of a protocol\n     * configured to access the field device of a network.\n     * <p>\n     * Refer to {@link #getConnectStatus() getConnectStatus} to determine if the\n     * connection is completed.\n     * <p>\n     * All protocols must implement this method.\n     *\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#INVALID_CONFIGURATION}\n     *             this operates on the basic assumption that access to a device\n     *             should exist, if the device is unreachable, it is interpreted\n     *             as a failure of the configuration.\n     */\n    public void connect() throws ModbusProtocolException;\n\n    /**\n     * attempt to disconnect from the field device. This should close any port\n     * used exclusively for this protocol to talk with its attached device.\n     * Attempting to close an already closed connection is not invalid.\n     * <p>\n     * All protocols must implement this method.\n     *\n     * @throws ModbusProtocolException\n     *\n     * @see #getConnectStatus()\n     */\n    public void disconnect() throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 01</b><br>\n     * Read 1 to 2000 contiguous status of coils from the attached field device.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @param dataAddress\n     *            starting address\n     * @param count\n     *            quantity of coils\n     * @return an array of booleans representing the requested data points.\n     *         <b>true</b> for a given point if the point is set, <b>false</b>\n     *         otherwise.\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     */\n    public boolean[] readCoils(int unitAddr, int dataAddress, int count) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 02</b><br>\n     * Read 1 to 2000 contiguous status of discrete inputs from the attached field device.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @param dataAddress\n     *            starting address\n     * @param count\n     *            quantity of inputs\n     * @return an array of booleans representing the requested data points.\n     *         <b>true</b> for a given point if the point is set, <b>false</b>\n     *         otherwise.\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     */\n    public boolean[] readDiscreteInputs(int unitAddr, int dataAddress, int count) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 05</b><br>\n     * write a single output to either ON or OFF in the attached field device.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @param dataAddress\n     *            Output address.\n     * @param data\n     *            Output value (boolean) to write.\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     */\n    public void writeSingleCoil(int unitAddr, int dataAddress, boolean data) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 15 (0x0F)</b><br>\n     * write multiple coils in a sequence of coils to either ON or OFF in the attached field device.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @param dataAddress\n     *            Starting Output address.\n     * @param data\n     *            Outputs value (array of boolean) to write.\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     */\n    public void writeMultipleCoils(int unitAddr, int dataAddress, boolean[] data) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 03</b><br>\n     * Read contents of 1 to 125 contiguous block of holding registers from the attached field device.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @param dataAddress\n     *            starting address\n     * @param count\n     *            quantity of registers (maximum 0x7D)\n     * @return an array of int representing the requested data points (data registers on 2 bytes).\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     */\n    public int[] readHoldingRegisters(int unitAddr, int dataAddress, int count) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 04</b><br>\n     * Read contents of 1 to 125 contiguous block of input registers from the attached field device.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @param dataAddress\n     *            starting address\n     * @param count\n     *            quantity of registers (maximum 0x7D)\n     * @return an array of int representing the requested data points (data registers on 2 bytes).\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     */\n    public int[] readInputRegisters(int unitAddr, int dataAddress, int count) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 06</b><br>\n     * write a single holding register in the attached field device.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @param dataAddress\n     *            Output address.\n     * @param data\n     *            Output value (2 bytes) to write.\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     */\n    public void writeSingleRegister(int unitAddr, int dataAddress, int data) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 07</b><br>\n     * read the content of 8 Exception Status outputs in the field device.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     */\n    public boolean[] readExceptionStatus(int unitAddr) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 11 (0x0B)</b><br>\n     * Get a status word and an event count from the device.<br>\n     * Return values in a ModbusCommEvent.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     * @see ModbusCommEvent\n     */\n    public ModbusCommEvent getCommEventCounter(int unitAddr) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 12 (0x0C)</b><br>\n     * Get a status word, an event count, a message count and a list of event bytes\n     * from the device.<br>\n     * Return values in a ModbusCommEvent.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     * @see ModbusCommEvent\n     */\n    public ModbusCommEvent getCommEventLog(int unitAddr) throws ModbusProtocolException;\n\n    /**\n     * <b>Modbus function 16 (0x10)</b><br>\n     * write a block of contiguous registers (1 to 123) in the attached field device.\n     * <p>\n     *\n     * @param unitAddr\n     *            modbus slave address (must be unique in the range 1 - 247)\n     * @param dataAddress\n     *            Output address.\n     * @param data\n     *            Registers value (array of int converted in 2 bytes values) to write.\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#NOT_CONNECTED}\n     *             current connection is in a status other than <b>CONNECTED</b>\n     * @throws ModbusProtocolException\n     *             with a {@link ModbusProtocolErrorCode#TRANSACTION_FAILURE}\n     *             should include a protocol specific message to help clarify\n     *             the cause of the exception\n     */\n    public void writeMultipleRegister(int unitAddr, int dataAddress, int[] data) throws ModbusProtocolException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/ModbusProtocolErrorCode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\n/**\n * ProtocolErrorCode holds the enumeration of valid error codes for the exception message. For each defined enum value,\n * a corresponding message should be defined in the properties bundle named:\n * ProtocolExceptionMessagesBundle.properties.\n *\n *\n */\npublic enum ModbusProtocolErrorCode {\n\n    INVALID_CONFIGURATION,\n    INVALID_DATA_ADDRESS,\n    INVALID_DATA_TYPE,\n    INVALID_DATA_LENGTH,\n    METHOD_NOT_SUPPORTED,\n    NOT_AVAILABLE,\n    NOT_CONNECTED,\n    CONNECTION_FAILURE,\n    TRANSACTION_FAILURE,\n    RESPONSE_TIMEOUT;\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/ModbusProtocolException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\nimport java.text.MessageFormat;\nimport java.util.Locale;\nimport java.util.MissingResourceException;\nimport java.util.ResourceBundle;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * The ProtocolException class is the superclass of all errors and exceptions in the Kura Protocol project. It extends\n * the JDK Exception class by requesting its invokers to provide an error code when\n * building its instances. The code is one value of ProtocolErrorCode enum; the code is used to document the possible\n * error conditions generated by the platform as well as to identify the localized\n * exception messages to be reported. Exceptions messages are stored in the ProtocolExceptionMessagesBundle Properties\n * Bundle and they are keyed on the exception code.\n *\n *\n */\npublic class ModbusProtocolException extends Exception {\n\n    private static final long serialVersionUID = -6155136065068974723L;\n\n    private static final String PROTOCOL_GENERIC_MESSAGES_PATTERN = \"Generic Error - {0}: {1} {2} {3} {4} {5}\";\n    private static final String PROTOCOL_EXCEPTION_MESSAGES_BUNDLE = \"org.eclipse.kura.protocol.messages.ProtocolExceptionMessagesBundle\";\n\n    private static final Logger s_logger = LoggerFactory.getLogger(ModbusProtocolException.class);\n\n    protected ModbusProtocolErrorCode m_code;\n    private Object[] m_arguments;\n    private String m_complement;\n\n    @SuppressWarnings(\"unused\")\n    private ModbusProtocolException() {\n        super();\n    }\n\n    @SuppressWarnings(\"unused\")\n    private ModbusProtocolException(String message) {\n        super(message);\n    }\n\n    @SuppressWarnings(\"unused\")\n    private ModbusProtocolException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    @SuppressWarnings(\"unused\")\n    private ModbusProtocolException(Throwable t) {\n        super(t);\n    }\n\n    /**\n     * Builds a new EdcException instance based on the supplied EdcErrorCode.\n     *\n     * @param code\n     */\n    public ModbusProtocolException(ModbusProtocolErrorCode code) {\n        this.m_code = code;\n    }\n\n    /**\n     * Builds a new EdcException instance based on the supplied EdcErrorCode and an optional complement string\n     *\n     * @param code\n     * @param complement\n     */\n    public ModbusProtocolException(ModbusProtocolErrorCode code, String complement) {\n        this.m_code = code;\n        this.m_complement = complement;\n    }\n\n    /**\n     * Builds a new EdcException instance based on the supplied EdcErrorCode, an optional Throwable cause, and optional\n     * arguments for the associated exception message.\n     *\n     * @param code\n     * @param arguments\n     */\n    public ModbusProtocolException(ModbusProtocolErrorCode code, Throwable cause, Object... arguments) {\n        super(cause);\n\n        this.m_code = code;\n        this.m_arguments = arguments;\n    }\n\n    public ModbusProtocolErrorCode getCode() {\n        return this.m_code;\n    }\n\n    @Override\n    public String getMessage() {\n        return getLocalizedMessage(Locale.US);\n    }\n\n    @Override\n    public String getLocalizedMessage() {\n        return getLocalizedMessage(Locale.getDefault());\n    }\n\n    private String getLocalizedMessage(Locale locale) {\n\n        String pattern = getMessagePattern(locale, this.m_code);\n        String message = MessageFormat.format(pattern, this.m_arguments) + \" \" + this.m_complement;\n        return message;\n    }\n\n    private String getMessagePattern(Locale locale, ModbusProtocolErrorCode code) {\n\n        //\n        // Load the message pattern from the bundle\n        String messagePattern = null;\n        ResourceBundle resourceBundle = null;\n        try {\n\n            resourceBundle = ResourceBundle.getBundle(PROTOCOL_EXCEPTION_MESSAGES_BUNDLE, locale);\n            messagePattern = resourceBundle.getString(code.name());\n            if (messagePattern == null) {\n                s_logger.warn(\"Could not find Exception Messages for Locale {} and code {}\", locale, code);\n            }\n        } catch (MissingResourceException mre) {\n            // log the failure to load a message bundle\n            s_logger.warn(\"Could not load Exception Messages Bundle for Locale {}\", locale);\n        }\n\n        //\n        // If no bundle or code in the bundle is found, use a generic message\n        if (messagePattern == null) {\n            // build a generic message format\n            messagePattern = MessageFormat.format(PROTOCOL_GENERIC_MESSAGES_PATTERN, code.name());\n        }\n\n        return messagePattern;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/ModbusTransmissionMode.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\n/**\n * This static class is provided only for completeness. Currently the\n * Modbus protocol only supports RTU mode communications.\n * <p>\n * The Field values, not the field names should be used in configuration files.\n *\n *\n */\npublic class ModbusTransmissionMode {\n\n    /**\n     *\n     */\n    private ModbusTransmissionMode() {\n    }\n\n    public static final String RTU = \"RTU\";\n    public static final String ASCII = \"ASCII\";\n    public static final int RTU_MODE = 0;\n    public static final int ASCII_MODE = 1;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/java/org/eclipse/kura/protocol/modbus/ProtocolPrimitiveDataTypes.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.protocol.modbus;\n\n/**\n * This class is used to enumerate the Java primitive data types.\n *\n * @author matt.demaree\n *\n */\npublic class ProtocolPrimitiveDataTypes {\n\n    /**\n     *\n     */\n    private ProtocolPrimitiveDataTypes() {\n    }\n\n    /**\n     * defined for completeness, typically never used\n     */\n    public static final String TYPE_VOID = \"VOID\";\n    /**\n     * a primitive data type of boolean (1 bit)\n     */\n    public static final String TYPE_BOOLEAN = \"BOOL\";\n    /**\n     * a primitive data type of character (8 bits)\n     */\n    public static final String TYPE_CHAR = \"CHAR\";\n    /**\n     * a primitive data type of byte (8 bits)\n     */\n    public static final String TYPE_BYTE = \"BYTE\";\n    /**\n     * a primitive data type of short int (16 bits)\n     */\n    public static final String TYPE_SHORT = \"SHORT\";\n    /**\n     * a primitive data type of int, limited to the range 0 to 65535 inclusive\n     */\n    public static final String TYPE_UNSIGNED_SHORT = \"USHORT\";\n    /**\n     * a primitive data type of int (32 bits)\n     */\n    public static final String TYPE_INT = \"INT\";\n    /**\n     * a primitive data type of long, limited to the range 0 to 4294967295 inclusive\n     */\n    public static final String TYPE_UNSIGNED_INT = \"UINT\";\n    /**\n     * a primitive data type of long (64 bits)\n     */\n    public static final String TYPE_LONG = \"LONG\";\n    /**\n     * a primitive data type of 32 bit floating point\n     */\n    public static final String TYPE_FLOAT = \"FLOAT\";\n    /**\n     * a primitive data type of 64 bit floating point\n     */\n    public static final String TYPE_DOUBLE = \"DOUBLE\";\n    /**\n     * something other than one of the primitive data types\n     */\n    public static final String TYPE_CLASS = \"CLASS\";\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.protocol.modbus/src/main/resources/org.eclipse.kura.protocol.modbus.dpp",
    "content": "#Deployment Plugin Project File\n#Wed Mar 12 13:49:19 CDT 2014\nbuild.ant.name=<.>/src/main/resources/org.eclipse.kura.protocol.modbus_build.xml\nbuild.dp.file=<.>/target/org.eclipse.kura.protocol.modbus.dp\nbuild.location=\nbundles.0.bundle_path=<.>/target/org.eclipse.kura.protocol.modbus-1.0.2-SNAPSHOT.jar\nbundles.0.customizer=false\nbundles.0.headers.count=0\nbundles.0.missing=false\nbundles.0.name=bundles/org.eclipse.kura.protocol.modbus-1.0.2-SNAPSHOT.jar\nbundles.0.symbolic_name=org.eclipse.kura.protocol.modbus;singleton\\:\\=true\nbundles.0.version=1.0.2.201412211043\nbundles.count=1\ncertificates.count=0\ngeneral.signbundles=false\nheaders.other.headers=\nheaders.symbolic.name=org.eclipse.kura.protocol.modbus\nheaders.version=1.0.0\nresources.count=0\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.request.handler.jaxrs\nBundle-SymbolicName: org.eclipse.kura.request.handler.jaxrs;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: com.google.gson,\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.apache.commons.io;version=\"2.4.0\",\n org.eclipse.kura;version=\"[1.6,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.4,2.0)\",\n org.slf4j;version=\"1.7.25\"\nExport-Package: org.eclipse.kura.request.handler.jaxrs;version=\"2.0.0\",\n org.eclipse.kura.request.handler.jaxrs.annotation;version=\"1.0.0\",\n org.eclipse.kura.request.handler.jaxrs.consumer;version=\"1.1.0\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/build.properties",
    "content": "#\n#  Copyright (c) 2021 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes\nbin.includes = .,\\\n               META-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<artifactId>org.eclipse.kura.request.handler.jaxrs</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/src/main/java/org/eclipse/kura/request/handler/jaxrs/DefaultExceptionHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.request.handler.jaxrs;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.Optional;\n\nimport jakarta.ws.rs.WebApplicationException;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.gson.Gson;\n\npublic class DefaultExceptionHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(DefaultExceptionHandler.class);\n\n    private DefaultExceptionHandler() {\n    }\n\n    public static WebApplicationException toWebApplicationException(final Throwable e) {\n        if (e instanceof KuraException) {\n            return toWebApplicationException((KuraException) e);\n        } else if (e instanceof WebApplicationException) {\n            return (WebApplicationException) e;\n        } else if (e instanceof InvocationTargetException && e.getCause() != null) {\n            return toWebApplicationException(e.getCause());\n        } else {\n            return buildWebApplicationException(Status.INTERNAL_SERVER_ERROR, e.getMessage());\n        }\n    }\n\n    public static WebApplicationException toWebApplicationException(final KuraException e) {\n        if (e.getCode() == KuraErrorCode.NOT_FOUND) {\n            return buildWebApplicationException(Status.NOT_FOUND, e.getMessage());\n        } else if (e.getCode() == KuraErrorCode.BAD_REQUEST || e.getCode() == KuraErrorCode.CONFIGURATION_ERROR) {\n            return buildWebApplicationException(Status.BAD_REQUEST, e.getMessage());\n        } else {\n            return buildWebApplicationException(Status.INTERNAL_SERVER_ERROR, e.getMessage());\n        }\n    }\n\n    public static KuraMessage toKuraMessage(final WebApplicationException e, final Optional<Gson> gson) {\n        final Response response = e.getResponse();\n\n        final KuraPayload responsePayload = new KuraResponsePayload(response.getStatus());\n\n        try {\n            ResponseBodyHandlers.responseHandler(gson.orElseGet(Gson::new)).buildBody(response)\n                    .ifPresent(responsePayload::setBody);\n        } catch (final Exception ex) {\n            logger.warn(\"failed to serialize WebApplicationException entity\", ex);\n        }\n\n        return new KuraMessage(responsePayload);\n    }\n\n    public static WebApplicationException buildWebApplicationException(final Status status, final String message) {\n\n        final String actualMessage = message != null ? message : \"An internal error occurred\";\n\n        return new WebApplicationException(\n                Response.status(status).type(MediaType.APPLICATION_JSON).entity(new Failure(actualMessage)).build());\n    }\n\n    private static class Failure {\n\n        private final String message;\n\n        public Failure(String message) {\n            this.message = message;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public String getMessage() {\n            return this.message;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/src/main/java/org/eclipse/kura/request/handler/jaxrs/JaxRsRequestHandlerProxy.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.request.handler.jaxrs;\n\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\n\nimport java.io.InputStream;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Parameter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerContext;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.eclipse.kura.request.handler.jaxrs.annotation.EXEC;\nimport org.eclipse.kura.request.handler.jaxrs.consumer.RequestArgumentHandler;\nimport org.eclipse.kura.request.handler.jaxrs.consumer.RequestParameterHandler;\nimport org.eclipse.kura.request.handler.jaxrs.consumer.ResponseBodyHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.gson.Gson;\n\nimport jakarta.ws.rs.DELETE;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.PUT;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.core.Context;\nimport jakarta.ws.rs.core.Response;\n\npublic class JaxRsRequestHandlerProxy implements RequestHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(JaxRsRequestHandlerProxy.class);\n\n    private final Object target;\n    private final Map<Endpoint, MethodProxy> endpoints;\n    private final Gson gson;\n\n    public JaxRsRequestHandlerProxy(final Object target) {\n        this.gson = buildGson();\n        this.target = target;\n        this.endpoints = probeRequestMethods(target);\n    }\n\n    @Override\n    public KuraMessage doGet(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        return dispatch(RequestHandlerMethod.GET, reqMessage);\n    }\n\n    @Override\n    public KuraMessage doPost(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        return dispatch(RequestHandlerMethod.POST, reqMessage);\n    }\n\n    @Override\n    public KuraMessage doPut(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        return dispatch(RequestHandlerMethod.PUT, reqMessage);\n    }\n\n    @Override\n    public KuraMessage doExec(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        return dispatch(RequestHandlerMethod.EXEC, reqMessage);\n    }\n\n    @Override\n    public KuraMessage doDel(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        return dispatch(RequestHandlerMethod.DELETE, reqMessage);\n    }\n\n    protected Gson buildGson() {\n        return new Gson();\n    }\n\n    protected Map<Endpoint, MethodProxy> probeRequestMethods(final Object object) {\n\n        final Map<Endpoint, MethodProxy> result = new HashMap<>();\n        final Method[] methods = object.getClass().getMethods();\n\n        for (final Method method : methods) {\n            final Optional<Endpoint> endpoint = probeEndpoint(method);\n\n            if (!endpoint.isPresent()) {\n                continue;\n            }\n\n            buildMethodProxy(method).ifPresent(s -> result.put(endpoint.get(), s));\n        }\n\n        return result;\n    }\n\n    protected String resourcesToPath(final List<String> resources) {\n        return \"/\" + resources.stream().collect(Collectors.joining(\"/\"));\n    }\n\n    protected Optional<Endpoint> probeEndpoint(final Method method) {\n        final RequestHandlerMethod requestHandlerMethod;\n\n        final Path path = method.getAnnotation(Path.class);\n\n        if (path == null) {\n            logger.debug(\"{} does not specify the Path annotation, ignoring\", method);\n            return Optional.empty();\n        }\n\n        if (method.isAnnotationPresent(EXEC.class)) {\n            logger.debug(\"found EXEC method: {}\", method);\n            requestHandlerMethod = RequestHandlerMethod.EXEC;\n        } else if (method.isAnnotationPresent(GET.class)) {\n            logger.debug(\"found GET method: {}\", method);\n            requestHandlerMethod = RequestHandlerMethod.GET;\n        } else if (method.isAnnotationPresent(POST.class)) {\n            logger.debug(\"found POST method: {}\", method);\n            requestHandlerMethod = RequestHandlerMethod.POST;\n        } else if (method.isAnnotationPresent(PUT.class)) {\n            logger.debug(\"found PUT method: {}\", method);\n            requestHandlerMethod = RequestHandlerMethod.PUT;\n        } else if (method.isAnnotationPresent(DELETE.class)) {\n            logger.debug(\"found DELETE method: {}\", method);\n            requestHandlerMethod = RequestHandlerMethod.DELETE;\n        } else {\n            logger.debug(\"{} is not a supported REST method, ignoring\", method);\n            return Optional.empty();\n        }\n\n        logger.debug(\"found method {}, path: {}, rest method: {}\", method, path, requestHandlerMethod);\n\n        return Optional.of(new Endpoint(requestHandlerMethod, path.value()));\n    }\n\n    protected Optional<MethodProxy> buildMethodProxy(final Method method) {\n\n        final Parameter[] parameters = method.getParameters();\n\n        final List<RequestArgumentHandler<?>> handlers = new ArrayList<>();\n\n        for (final Parameter parameter : parameters) {\n\n            final Class<?> type = parameter.getType();\n\n            if (Arrays.asList(parameter.getAnnotations()).stream().map(a -> a.annotationType())\n                    .anyMatch(Context.class::equals)) {\n                handlers.add(RequestParameterHandlers.nullArgumentHandler());\n            } else if (type == InputStream.class) {\n                handlers.add(RequestParameterHandlers.inputStreamArgumentHandler());\n            } else {\n                handlers.add(RequestParameterHandlers.gsonArgumentHandler(type, gson));\n            }\n\n        }\n\n        final RequestParameterHandler parameterHandler = RequestParameterHandlers.fromArgumentHandlers(handlers);\n\n        final ResponseBodyHandler bodyHandler;\n\n        final Class<?> returnType = method.getReturnType();\n\n        if (returnType == Void.class) {\n            bodyHandler = ResponseBodyHandlers.voidHandler();\n        } else if (returnType == Response.class) {\n            bodyHandler = ResponseBodyHandlers.responseHandler(gson);\n        } else {\n            bodyHandler = ResponseBodyHandlers.gsonHandler(gson);\n        }\n\n        return Optional.of(new MethodProxy(method, parameterHandler, bodyHandler));\n    }\n\n    protected KuraMessage dispatch(final RequestHandlerMethod restMethod, final KuraMessage request) {\n\n        try {\n            final List<String> resources = extractResources(request);\n\n            final String path = resourcesToPath(resources);\n\n            final MethodProxy proxy = Optional.ofNullable(this.endpoints.get(new Endpoint(restMethod, path)))\n                    .orElseThrow(() -> new KuraException(KuraErrorCode.NOT_FOUND));\n\n            return invoke(proxy, target, request);\n        } catch (final Exception e) {\n            return handleException(e);\n        }\n    }\n\n    protected KuraMessage invoke(final MethodProxy proxy, final Object target, final KuraMessage request)\n            throws KuraException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {\n\n        final Object[] parameters = proxy.parameterHandler.buildParameters(request);\n\n        final Object result = proxy.method.invoke(target, parameters);\n\n        final KuraPayload resultPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n\n        proxy.bodyHandler.buildBody(result).ifPresent(resultPayload::setBody);\n\n        return new KuraMessage(resultPayload);\n    }\n\n    protected KuraMessage handleException(final Throwable e) {\n\n        return DefaultExceptionHandler.toKuraMessage(DefaultExceptionHandler.toWebApplicationException(e),\n                Optional.of(gson));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static List<String> extractResources(final KuraMessage request) throws KuraException {\n\n        try {\n            return java.util.Objects.requireNonNull((List<String>) request.getProperties().get(ARGS_KEY.value()));\n        } catch (final Exception e) {\n            logger.warn(\"failed to get resources from request\");\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n    }\n\n    public static class Endpoint {\n\n        private final RequestHandlerMethod method;\n        private final String relativePath;\n\n        public Endpoint(RequestHandlerMethod method, String relativePath) {\n            this.method = method;\n            this.relativePath = relativePath;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(method, relativePath);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (obj == null) {\n                return false;\n            }\n            if (getClass() != obj.getClass()) {\n                return false;\n            }\n            Endpoint other = (Endpoint) obj;\n            return method == other.method && Objects.equals(relativePath, other.relativePath);\n        }\n\n    }\n\n    public static class MethodProxy {\n\n        private Method method;\n        private RequestParameterHandler parameterHandler;\n        private ResponseBodyHandler bodyHandler;\n\n        public MethodProxy(Method method, RequestParameterHandler parameterHandler, ResponseBodyHandler bodyHandler) {\n            this.method = method;\n            this.parameterHandler = parameterHandler;\n            this.bodyHandler = bodyHandler;\n        }\n    }\n\n    public enum RequestHandlerMethod {\n        GET,\n        POST,\n        PUT,\n        DELETE,\n        EXEC\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/src/main/java/org/eclipse/kura/request/handler/jaxrs/RequestParameterHandlers.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.request.handler.jaxrs;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.CodingErrorAction;\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.request.handler.jaxrs.consumer.RequestArgumentHandler;\nimport org.eclipse.kura.request.handler.jaxrs.consumer.RequestParameterHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.gson.Gson;\n\npublic final class RequestParameterHandlers {\n\n    private static final Logger logger = LoggerFactory.getLogger(RequestParameterHandlers.class);\n\n    private static final Object[] EMPTY_PARAMETERS = new Object[0];\n\n    private RequestParameterHandlers() {\n    }\n\n    public static RequestParameterHandler noArgsHandler() {\n        return m -> EMPTY_PARAMETERS;\n    }\n\n    public static RequestParameterHandler fromArgumentHandlers(final List<RequestArgumentHandler<?>> handlers) {\n        return m -> {\n            final Object[] result = new Object[handlers.size()];\n\n            for (int i = 0; i < handlers.size(); i++) {\n                result[i] = handlers.get(i).buildParameter(m);\n            }\n            return result;\n        };\n    }\n\n    public static <T> RequestArgumentHandler<T> nullArgumentHandler() {\n        return m -> null;\n    }\n\n    public static RequestArgumentHandler<InputStream> inputStreamArgumentHandler() {\n        return m -> {\n            final KuraPayload payload = m.getPayload();\n            final byte[] body = payload.getBody();\n\n            if (body == null || body.length == 0) {\n                return null;\n            }\n\n            return new ByteArrayInputStream(body);\n        };\n    }\n\n    public static RequestParameterHandler inputStreamHandler() {\n        return m -> {\n            final RequestArgumentHandler<InputStream> handler = inputStreamArgumentHandler();\n\n            return new Object[] { handler.buildParameter(m) };\n        };\n    }\n\n    public static <T> RequestArgumentHandler<T> gsonArgumentHandler(final Class<T> type, final Gson gson) {\n        return m -> {\n            final KuraPayload payload = m.getPayload();\n            final byte[] body = payload.getBody();\n\n            if (body == null || body.length == 0) {\n                return null;\n            }\n\n            final String asString;\n\n            try {\n\n                asString = StandardCharsets.UTF_8.newDecoder().onMalformedInput(CodingErrorAction.REPORT)\n                        .decode(ByteBuffer.wrap(body)).toString();\n            } catch (final Exception e) {\n                logger.warn(\"request body is not valid UTF8\", e);\n                throw new KuraException(KuraErrorCode.BAD_REQUEST);\n            }\n\n            final T result;\n\n            try {\n                result = gson.fromJson(asString, type);\n            } catch (final Exception e) {\n                logger.warn(\"malformed JSON request\", e);\n                throw new KuraException(KuraErrorCode.BAD_REQUEST);\n            }\n\n            return result;\n        };\n    }\n\n    public static RequestParameterHandler gsonHandler(final Class<?> type, final Gson gson) {\n\n        return m -> {\n\n            final RequestArgumentHandler<?> handler = gsonArgumentHandler(type, gson);\n\n            return new Object[] { handler.buildParameter(m) };\n        };\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/src/main/java/org/eclipse/kura/request/handler/jaxrs/ResponseBodyHandlers.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.request.handler.jaxrs;\n\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Optional;\n\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.request.handler.jaxrs.consumer.ResponseBodyHandler;\n\nimport com.google.gson.Gson;\n\nimport jakarta.ws.rs.core.Response;\n\npublic final class ResponseBodyHandlers {\n\n    private ResponseBodyHandlers() {\n    }\n\n    public static ResponseBodyHandler voidHandler() {\n        return r -> Optional.empty();\n    }\n\n    public static ResponseBodyHandler responseHandler(final Gson gson) {\n        return r -> {\n            final Response response = (Response) r;\n\n            if (response == null) {\n                return Optional.empty();\n            }\n\n            final Object entity = response.getEntity();\n\n            if (entity == null) {\n                return Optional.empty();\n            } else if (entity instanceof String) {\n                return Optional.of(((String) entity).getBytes(StandardCharsets.UTF_8));\n            } else if (entity instanceof byte[]) {\n                return Optional.of((byte[]) entity);\n            } else if (entity instanceof InputStream) {\n                try {\n                    return Optional.of(IOUtils.toByteArray((InputStream) entity));\n                } catch (final Exception e) {\n                    throw KuraException.internalError(e);\n                }\n            } else {\n                final String asJson = gson.toJson(entity);\n                return Optional.of(asJson.getBytes(StandardCharsets.UTF_8));\n            }\n        };\n    }\n\n    public static ResponseBodyHandler gsonHandler(final Gson gson) {\n        return r -> {\n            if (r == null) {\n                return Optional.empty();\n            }\n\n            return Optional.of(gson.toJson(r).getBytes(StandardCharsets.UTF_8));\n        };\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/src/main/java/org/eclipse/kura/request/handler/jaxrs/annotation/EXEC.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.request.handler.jaxrs.annotation;\n\nimport static java.lang.annotation.ElementType.METHOD;\nimport static java.lang.annotation.RetentionPolicy.RUNTIME;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\n@Retention(RUNTIME)\n@Target(METHOD)\npublic @interface EXEC {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/src/main/java/org/eclipse/kura/request/handler/jaxrs/consumer/RequestArgumentHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.request.handler.jaxrs.consumer;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\n\npublic interface RequestArgumentHandler<T> {\n\n    T buildParameter(final KuraMessage request) throws KuraException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/src/main/java/org/eclipse/kura/request/handler/jaxrs/consumer/RequestParameterHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.request.handler.jaxrs.consumer;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\n\n@FunctionalInterface\npublic interface RequestParameterHandler {\n\n    Object[] buildParameters(final KuraMessage request) throws KuraException;\n}"
  },
  {
    "path": "kura/org.eclipse.kura.request.handler.jaxrs/src/main/java/org/eclipse/kura/request/handler/jaxrs/consumer/ResponseBodyHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.request.handler.jaxrs.consumer;\n\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\n\n@FunctionalInterface\npublic interface ResponseBodyHandler {\n\n    Optional<byte[]> buildBody(final Object o) throws KuraException;\n}"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: CloudConnection REST Service\nBundle-SymbolicName: org.eclipse.kura.rest.cloudconnection.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nImport-Package: jakarta.annotation.security;version=\"2.1.1\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.apache.commons.io;version=\"2.4.0\",\n org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.cloud;version=\"[1.1,2.0)\",\n org.eclipse.kura.cloud.factory;version=\"[1.1.1,2.0)\",\n org.eclipse.kura.cloudconnection;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.factory;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.publisher;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.subscriber;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.configuration;version=\"[2.0,3.0)\",\n org.eclipse.kura.crypto;version=\"1.3.0\",\n org.eclipse.kura.data;version=\"[1.1.2,2.0)\",\n org.eclipse.kura.request.handler.jaxrs;version=\"[2.0,3.0)\",\n org.eclipse.kura.request.handler.jaxrs.annotation;version=\"[1.0,2.0)\",\n org.eclipse.kura.rest.configuration.api;version=\"[1.1,2.0)\",\n org.eclipse.kura.util.service;version=\"[1.2,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.component;version=\"[1.3,2.0)\",\n org.osgi.service.component.runtime;version=\"1.4.0\",\n org.osgi.service.component.runtime.dto;version=\"1.4.0\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.slf4j;version=\"1.7.25\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/OSGI-INF/CloudConnectionRestService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" immediate=\"true\" name=\"org.eclipse.kura.internal.rest.cloudconnection.provider.CloudConnectionRestService\">\n    <implementation class=\"org.eclipse.kura.internal.rest.cloudconnection.provider.CloudConnectionRestService\"/>\n\n    <property name=\"kura.service.pid\" \n              type=\"String\" \n              value=\"org.eclipse.kura.internal.rest.cloudconnection.provider.CloudConnectionRestService\" />\n              \n    <reference interface=\"org.eclipse.kura.crypto.CryptoService\" \n               bind=\"bindCryptoService\" \n               cardinality=\"1..1\" \n               name=\"CryptoService\" \n               policy=\"static\" />\n\n    <reference interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\"\n               bind=\"bindRequestHandlerRegistry\"\n               unbind=\"unbindRequestHandlerRegistry\"\n               cardinality=\"0..n\"\n               name=\"RequestHandlerRegistry\"\n               policy=\"dynamic\" />\n\n    <reference interface=\"org.osgi.service.useradmin.UserAdmin\"\n               bind=\"bindUserAdmin\"\n               cardinality=\"1..1\"\n               name=\"UserAdmin\"\n               policy=\"static\" />\n               \n    <reference interface=\"org.eclipse.kura.configuration.ConfigurationService\" \n               bind=\"bindConfigurationService\" \n               cardinality=\"1..1\"  \n               name=\"ConfigurationService\" \n               policy=\"static\" />\n\n    <service>\n        <provide interface=\"org.eclipse.kura.internal.rest.cloudconnection.provider.CloudConnectionRestService\" />\n    </service>\n\n    <property name=\"service.pid\"\n              type=\"String\"\n              value=\"org.eclipse.kura.internal.rest.cloudconnection.provider.CloudConnectionRestService\" />\n    <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <artifactId>org.eclipse.kura.rest.cloudconnection.provider</artifactId>\n    <packaging>eclipse-plugin</packaging>\n    <version>2.0.0-SNAPSHOT</version>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionManagerBridge.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider;\n\nimport static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID;\n\nimport java.util.Collection;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraDisconnectException;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraRuntimeException;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentConstants;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@SuppressWarnings(\"deprecation\")\npublic class CloudConnectionManagerBridge {\n\n    private static final String CONNECTION_ERROR_MESSAGE = \"Error connecting. Please review your configuration.\";\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudConnectionManagerBridge.class);\n\n    private static final String DATA_SERVICE_REFERENCE_NAME = \"DataService\";\n\n    private final BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();\n\n    public void connectCloudEndpoint(String connectionId) throws KuraException {\n\n        boolean ran = false;\n\n        ran = runOnDataService(connectionId, dataService -> {\n            int counter = 10;\n\n            dataService.connect();\n            while (!dataService.isConnected() && counter > 0) {\n                Thread.sleep(1000);\n                counter--;\n            }\n\n        });\n\n        ran = ran || runOnCloudConnectionManager(connectionId, cloudConnectionManager -> {\n            try {\n                cloudConnectionManager.connect();\n            } catch (KuraConnectException e) {\n                throw new KuraRuntimeException(KuraErrorCode.CONNECTION_FAILED, e, CONNECTION_ERROR_MESSAGE);\n            }\n        });\n\n        if (!ran) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n    }\n\n    public void disconnectCloudEndpoint(String connectionId) throws KuraException {\n\n        boolean ran = false;\n\n        ran = runOnDataService(connectionId, dataService -> dataService.disconnect(10));\n\n        ran = ran || runOnCloudConnectionManager(connectionId, CloudConnectionManager::disconnect);\n\n        if (!ran) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n\n    }\n\n    public boolean isConnectedCloudEndpoint(String connectionId) throws KuraException {\n\n        boolean ran = false;\n\n        AtomicReference<Boolean> connectionStatusHolder = new AtomicReference<>(false);\n\n        ran = runOnDataService(connectionId, dataService -> connectionStatusHolder.set(dataService.isConnected()));\n\n        ran = ran || runOnCloudConnectionManager(connectionId,\n                cloudConnectionManager -> connectionStatusHolder.set(cloudConnectionManager.isConnected()));\n\n        if (!ran) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n\n        return connectionStatusHolder.get();\n\n    }\n\n    private boolean runOnDataService(String connectionId, InterruptableConsumer<DataService> dataServiceConsumer)\n            throws KuraException {\n        Collection<ServiceReference<CloudService>> cloudServiceReferences = ServiceUtil\n                .getServiceReferencesAsCollection(this.bundleContext, CloudService.class, null);\n\n        for (ServiceReference<CloudService> cloudServiceReference : cloudServiceReferences) {\n            String cloudServicePid = (String) cloudServiceReference.getProperty(KURA_SERVICE_PID);\n            if (cloudServicePid.endsWith(connectionId)) {\n                String dataServiceRef = (String) cloudServiceReference\n                        .getProperty(DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX);\n                Collection<ServiceReference<DataService>> dataServiceReferences = ServiceUtil\n                        .getServiceReferencesAsCollection(this.bundleContext, DataService.class, dataServiceRef);\n\n                for (ServiceReference<DataService> dataServiceReference : dataServiceReferences) {\n                    DataService dataService = ServiceUtil.getService(this.bundleContext, dataServiceReference);\n                    if (dataService != null) {\n\n                        invokeAndHandleExceptions(dataServiceConsumer, dataService);\n                        return true;\n                    }\n                    ServiceUtil.ungetService(this.bundleContext, dataServiceReference);\n                }\n            }\n            ServiceUtil.ungetService(this.bundleContext, cloudServiceReference);\n        }\n\n        return false;\n    }\n\n    private boolean runOnCloudConnectionManager(String connectionId,\n            InterruptableConsumer<CloudConnectionManager> cloudConnectionManagerConsumer) throws KuraException {\n        Collection<ServiceReference<CloudConnectionManager>> cloudConnectionManagerReferences = ServiceUtil\n                .getServiceReferencesAsCollection(this.bundleContext, CloudConnectionManager.class, null);\n\n        for (ServiceReference<CloudConnectionManager> cloudConnectionManagerReference : cloudConnectionManagerReferences) {\n            String cloudConnectionManagerPid = (String) cloudConnectionManagerReference.getProperty(KURA_SERVICE_PID);\n            if (cloudConnectionManagerPid.endsWith(connectionId)) {\n                CloudConnectionManager cloudConnectionManager = ServiceUtil.getService(this.bundleContext,\n                        cloudConnectionManagerReference);\n\n                invokeAndHandleExceptions(cloudConnectionManagerConsumer, cloudConnectionManager);\n\n                return true;\n            }\n            ServiceUtil.ungetService(this.bundleContext, cloudConnectionManagerReference);\n        }\n\n        return false;\n    }\n\n    private <T> void invokeAndHandleExceptions(InterruptableConsumer<T> consumer, T service) throws KuraException {\n        try {\n            consumer.accept(service);\n        } catch (KuraConnectException e) {\n            throw new KuraException(KuraErrorCode.CONNECTION_FAILED, e, CONNECTION_ERROR_MESSAGE);\n        } catch (IllegalStateException e) {\n            throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e, \"Illegal client state\");\n        } catch (InterruptedException e) {\n            logger.warn(\"Interrupt Exception\");\n            Thread.currentThread().interrupt();\n        }\n    }\n\n    public interface InterruptableConsumer<T> {\n\n        void accept(T t)\n                throws InterruptedException, KuraConnectException, KuraDisconnectException, IllegalStateException;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionRestService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider;\n\nimport java.util.List;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudComponentFactories;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudComponentInstances;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudConnectionFactoryPidAndCloudEndpointPid;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudEndpointPidRequest;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.ConnectedStatus;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.PidAndFactoryPidAndCloudEndpointPid;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.eclipse.kura.request.handler.jaxrs.JaxRsRequestHandlerProxy;\nimport org.eclipse.kura.rest.configuration.api.ComponentConfigurationList;\nimport org.eclipse.kura.rest.configuration.api.DTOUtil;\nimport org.eclipse.kura.rest.configuration.api.PidAndFactoryPid;\nimport org.eclipse.kura.rest.configuration.api.PidSet;\nimport org.eclipse.kura.rest.configuration.api.UpdateComponentConfigurationRequest;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.DELETE;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.PUT;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\n\n@Path(\"cloudconnection/v1\")\npublic class CloudConnectionRestService {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudConnectionRestService.class);\n\n    private static final String MQTT_APP_ID = \"CLD-V1\";\n    private static final String REST_ROLE_NAME = \"cloudconnection\";\n    private static final String KURA_PERMISSION_REST_ROLE = \"kura.permission.rest.\" + REST_ROLE_NAME;\n\n    private final RequestHandler requestHandler = new JaxRsRequestHandlerProxy(this);\n\n    private CloudConnectionService cloudConnectionService;\n    private CloudConnectionManagerBridge cloudConnectionManagerBridge;\n    private ConfigurationService configurationService;\n    private CryptoService cryptoService;\n\n    public void bindUserAdmin(UserAdmin userAdmin) {\n        userAdmin.createRole(KURA_PERMISSION_REST_ROLE, Role.GROUP);\n    }\n\n    public void bindCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void bindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.registerRequestHandler(MQTT_APP_ID, this.requestHandler);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to register {} request handler\", MQTT_APP_ID, e);\n        }\n    }\n\n    public void bindConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    public void unbindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.unregister(MQTT_APP_ID);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to unregister {} request handler\", MQTT_APP_ID, e);\n        }\n    }\n\n    public void activate() {\n        this.cloudConnectionService = new CloudConnectionService(this.configurationService);\n        this.cloudConnectionManagerBridge = new CloudConnectionManagerBridge();\n    }\n\n    @GET\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/instances\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public CloudComponentInstances findCloudComponentInstances() {\n        try {\n            return new CloudComponentInstances(this.cloudConnectionService.findCloudEndpointInstances(),\n                    this.cloudConnectionService.findPubsubInstances());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/cloudEndpoint/stackComponentPids\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    @Produces(MediaType.APPLICATION_JSON)\n    public PidSet getStackComponentsPids(\n            final CloudConnectionFactoryPidAndCloudEndpointPid cloudConnectionFactoryPidAndCloudEndpointPid) {\n        try {\n            Set<String> pidSet = this.cloudConnectionService.getStackComponentsPids(\n                    cloudConnectionFactoryPidAndCloudEndpointPid.getCloudConnectionFactoryPid(),\n                    cloudConnectionFactoryPidAndCloudEndpointPid.getCloudEndpointPid());\n\n            return new PidSet(pidSet);\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/cloudEndpoint\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response createCloudEndpoint(\n            final CloudConnectionFactoryPidAndCloudEndpointPid cloudConnectionFactoryPidAndCloudEndpointPid) {\n        try {\n            this.cloudConnectionService.createCloudEndpointFromFactory(\n                    cloudConnectionFactoryPidAndCloudEndpointPid.getCloudConnectionFactoryPid(),\n                    cloudConnectionFactoryPidAndCloudEndpointPid.getCloudEndpointPid());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @DELETE\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/cloudEndpoint\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response deleteCloudEndpoint(\n            final CloudConnectionFactoryPidAndCloudEndpointPid cloudConnectionFactoryPidAndCloudEndpointPid) {\n        try {\n            this.cloudConnectionService.deleteCloudEndpointFromFactory(\n                    cloudConnectionFactoryPidAndCloudEndpointPid.getCloudConnectionFactoryPid(),\n                    cloudConnectionFactoryPidAndCloudEndpointPid.getCloudEndpointPid());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @GET\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/factories\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public CloudComponentFactories getCloudComponentFactories() {\n        try {\n            return this.cloudConnectionService.getCloudComponentFactories();\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/pubSub\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response createPubSubInstance(\n            final PidAndFactoryPidAndCloudEndpointPid pidAndFactoryPidAndCloudEndpointPid) {\n        try {\n            this.cloudConnectionService.createPubSubInstance(pidAndFactoryPidAndCloudEndpointPid.getPid(),\n                    pidAndFactoryPidAndCloudEndpointPid.getFactoryPid(),\n                    pidAndFactoryPidAndCloudEndpointPid.getCloudEndpointPid());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @DELETE\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/pubSub\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response deletePubSubInstance(final PidAndFactoryPid pidAndFactoryPid) {\n        try {\n            this.cloudConnectionService.deletePubSubInstance(pidAndFactoryPid.getPid());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/configurations\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public ComponentConfigurationList getConfigurations(final PidSet pidSet) {\n        try {\n            List<ComponentConfiguration> result = this.cloudConnectionService.getPubSubConfiguration(pidSet.getPids());\n\n            result.addAll(this.cloudConnectionService.getStackConfigurationsByPid(pidSet.getPids()));\n\n            return new ComponentConfigurationList(\n                    result.stream().map(c -> DTOUtil.toComponentConfigurationDTO(c, this.cryptoService, false)\n                            .replacePasswordsWithPlaceholder()).collect(Collectors.toList()));\n\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @PUT\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/configurations\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response updateStackComponentConfigurations(\n            UpdateComponentConfigurationRequest updateComponentConfigurationRequest) {\n        try {\n            this.cloudConnectionService.updateStackComponentConfiguration(\n                    updateComponentConfigurationRequest.getComponentConfigurations(),\n                    updateComponentConfigurationRequest.isTakeSnapshot());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/cloudEndpoint/connect\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response connectCloudEndpoint(CloudEndpointPidRequest cloudEndpointPid) {\n        try {\n            this.cloudConnectionManagerBridge.connectCloudEndpoint(cloudEndpointPid.getCloudEndpointPid());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/cloudEndpoint/disconnect\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response disconnectCloudEndpoint(CloudEndpointPidRequest cloudEndpointPid) {\n        try {\n            this.cloudConnectionManagerBridge.disconnectCloudEndpoint(cloudEndpointPid.getCloudEndpointPid());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/cloudEndpoint/isConnected\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    @Produces(MediaType.APPLICATION_JSON)\n    public ConnectedStatus isConnectedCloudEndpoint(CloudEndpointPidRequest cloudEndpointPid) {\n        try {\n            return new ConnectedStatus(\n                    this.cloudConnectionManagerBridge.isConnectedCloudEndpoint(cloudEndpointPid.getCloudEndpointPid()));\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider;\n\nimport static java.lang.String.format;\nimport static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.cloud.factory.CloudServiceFactory;\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.configuration.ComponentConfigurationImpl;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudComponentFactories;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudConnectionFactoryInfo;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudConnectionState;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudEndpointInstance;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudEndpointType;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudPubSubType;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.PubSubFactoryInfo;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.PubSubInstance;\nimport org.eclipse.kura.rest.configuration.api.ComponentConfigurationDTO;\nimport org.eclipse.kura.rest.configuration.api.DTOUtil;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.eclipse.kura.util.service.ServiceUtil.ServiceConsumer;\nimport org.eclipse.kura.util.service.ServiceUtil.ServiceReferenceConsumer;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.component.runtime.ServiceComponentRuntime;\nimport org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@SuppressWarnings(\"deprecation\")\npublic class CloudConnectionService {\n\n    private static final Logger logger = LoggerFactory.getLogger(CloudConnectionService.class);\n\n    private static final String CLOUD_CONNECTION_FACTORY_FILTER = \"(\" + \"|\"\n            + \"(objectClass=org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory)\"\n            + \"(objectClass=org.eclipse.kura.cloud.factory.CloudServiceFactory)\" + \")\";\n\n    private static final String KURA_UI_CSF_PID_DEFAULT = \"kura.ui.csf.pid.default\";\n    private static final String KURA_UI_CSF_PID_REGEX = \"kura.ui.csf.pid.regex\";\n\n    private static final String CLOUD_PUBLISHER = CloudPublisher.class.getName();\n    private static final String CLOUD_SUBSCRIBER = CloudSubscriber.class.getName();\n\n    private final BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();\n\n    private final ConfigurationService configurationService;\n\n    public CloudConnectionService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    public List<CloudEndpointInstance> findCloudEndpointInstances() throws KuraException {\n\n        final List<CloudEndpointInstance> result = new ArrayList<>();\n\n        withAllCloudConnectionFactories(service -> {\n\n            final String factoryPid = service.getFactoryPid();\n            if (factoryPid == null) {\n                return;\n            }\n\n            for (final String pid : service.getManagedCloudConnectionPids()) {\n                if (pid == null) {\n                    continue;\n                }\n\n                final CloudEndpointInstance cloudConnectionEntry = new CloudEndpointInstance(factoryPid, pid);\n\n                fillState(cloudConnectionEntry);\n\n                result.add(cloudConnectionEntry);\n            }\n\n        });\n\n        return result;\n    }\n\n    public List<PubSubInstance> findPubsubInstances() throws KuraException {\n        final List<PubSubInstance> result = new ArrayList<>();\n\n        result.addAll(getPubSubInstances(CloudPubSubType.PUBLISHER));\n        result.addAll(getPubSubInstances(CloudPubSubType.SUBSCRIBER));\n\n        return result;\n    }\n\n    public Set<String> getStackComponentsPids(final String factoryPid, final String cloudEndpointPid)\n            throws KuraException {\n\n        final Set<String> result = new HashSet<>();\n\n        withAllCloudConnectionFactories(factory -> {\n            if (factoryPid.equals(factory.getFactoryPid())) {\n                if (!factory.getManagedCloudConnectionPids().contains(cloudEndpointPid)) {\n                    throw new KuraException(KuraErrorCode.NOT_FOUND);\n                }\n                result.addAll(getStackComponentPids(factory, cloudEndpointPid));\n            }\n        });\n\n        return result;\n    }\n\n    private List<String> getStackComponentPids(CloudConnectionFactory factory, String pid) {\n\n        List<String> result = new ArrayList<>();\n\n        try {\n            result = factory.getStackComponentsPids(pid);\n        } catch (Exception e) {\n            // nothing to do, just return an empty list\n        }\n\n        return result;\n    }\n\n    public Set<ComponentConfiguration> getStackConfigurationsByPid(final Set<String> pids) throws KuraException {\n\n        List<String> result = new ArrayList<>();\n\n        Set<ComponentConfiguration> resultSet = new HashSet<>();\n\n        withAllCloudConnectionFactories(factory -> {\n\n            Set<String> managedCloudConnectionPids = factory.getManagedCloudConnectionPids();\n\n            for (String cloudConnectionPid : managedCloudConnectionPids) {\n                List<String> stackComponentsPids = getStackComponentPids(factory, cloudConnectionPid);\n\n                pids.stream().filter(stackComponentsPids::contains).forEach(result::add);\n            }\n\n        });\n\n        for (String stackConfigurationPid : result) {\n            ComponentConfiguration componetConfiguration = this.configurationService\n                    .getComponentConfiguration(stackConfigurationPid);\n            if (componetConfiguration != null) {\n                resultSet.add(componetConfiguration);\n            }\n        }\n\n        return resultSet;\n    }\n\n    public void createCloudEndpointFromFactory(String factoryPid, String cloudServicePid) throws KuraException {\n        if (factoryPid == null || factoryPid.trim().isEmpty() || cloudServicePid == null\n                || cloudServicePid.trim().isEmpty()) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        AtomicReference<Boolean> found = new AtomicReference<>(false);\n\n        withAllCloudConnectionFactories(service -> {\n            if (service.getFactoryPid().equals(factoryPid)) {\n                found.set(true);\n                service.createConfiguration(cloudServicePid);\n            }\n        });\n\n        if (Boolean.FALSE.equals(found.get())) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n    }\n\n    public void deleteCloudEndpointFromFactory(String factoryPid, String cloudEndpointPid) throws KuraException {\n        if (factoryPid == null || factoryPid.trim().isEmpty() || cloudEndpointPid == null\n                || cloudEndpointPid.trim().isEmpty()) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        AtomicReference<Boolean> found = new AtomicReference<>(false);\n\n        withAllCloudConnectionFactories(factory -> {\n            if (factory.getFactoryPid().equals(factoryPid)\n                    && factory.getManagedCloudConnectionPids().contains(cloudEndpointPid)) {\n\n                factory.deleteConfiguration(cloudEndpointPid);\n                found.set(true);\n            }\n        });\n\n        if (Boolean.FALSE.equals(found.get())) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n    }\n\n    public CloudComponentFactories getCloudComponentFactories() throws KuraException {\n        final List<CloudConnectionFactoryInfo> cloudConnectionFactoryPids = new ArrayList<>();\n\n        withAllCloudConnectionFactoryRefs((ref, ctx) -> {\n\n            try {\n                final CloudConnectionFactory service = wrap(ctx.getService(ref));\n                String defaultPid = (String) ref.getProperty(KURA_UI_CSF_PID_DEFAULT);\n                String pidRegex = (String) ref.getProperty(KURA_UI_CSF_PID_REGEX);\n\n                CloudConnectionFactoryInfo cloudConnectionFactoryInfoDTO = new CloudConnectionFactoryInfo(\n                        service.getFactoryPid(), defaultPid, pidRegex);\n\n                cloudConnectionFactoryPids.add(cloudConnectionFactoryInfoDTO);\n            } finally {\n                ctx.ungetService(ref);\n            }\n\n        });\n\n        final List<PubSubFactoryInfo> pubSubFactories = getPubSubFactories();\n\n        return new CloudComponentFactories(cloudConnectionFactoryPids, pubSubFactories);\n    }\n\n    public void createPubSubInstance(final String pid, final String factoryPid, final String cloudEndpointPid)\n            throws KuraException {\n\n        if (pid == null || pid.trim().isEmpty() || //\n                factoryPid == null || factoryPid.trim().isEmpty() //\n                || cloudEndpointPid == null || cloudEndpointPid.trim().isEmpty()) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        requireIsPubSubFactory(factoryPid);\n\n        ServiceUtil.applyToServiceOptionally(this.bundleContext, ConfigurationService.class, cs -> {\n            cs.createFactoryConfiguration(factoryPid, pid, Collections.singletonMap(\n                    CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), cloudEndpointPid), true);\n\n            return null;\n        });\n    }\n\n    public void deletePubSubInstance(final String pid) throws KuraException {\n\n        requireIsPubSub(pid);\n\n        ServiceUtil.applyToServiceOptionally(this.bundleContext, ConfigurationService.class, cs -> {\n            cs.deleteFactoryConfiguration(pid, true);\n\n            return null;\n        });\n    }\n\n    public List<ComponentConfiguration> getPubSubConfiguration(Set<String> pids) throws KuraException {\n\n        List<ComponentConfiguration> result = new ArrayList<>();\n\n        for (String pid : pids) {\n            if (isPubSub(pid)) {\n                ComponentConfiguration configuration = this.configurationService.getComponentConfiguration(pid);\n                if (configuration != null) {\n                    result.add(configuration);\n                }\n            }\n        }\n\n        return result;\n    }\n\n    public void updateStackComponentConfiguration(List<ComponentConfigurationDTO> componentConfigurations,\n            boolean takeSnapshot) throws KuraException {\n\n        for (ComponentConfigurationDTO componentConfig : componentConfigurations) {\n            if (!(isPubSub(componentConfig.getPid()) || isComponentManagedByFactory(componentConfig.getPid()))) {\n                throw new KuraException(KuraErrorCode.BAD_REQUEST);\n            }\n        }\n\n        updateComponentConfigurations(componentConfigurations, takeSnapshot);\n\n    }\n\n    private void updateComponentConfigurations(List<ComponentConfigurationDTO> componentConfigurations,\n            boolean takeSnapshot) throws KuraException {\n\n        List<ComponentConfiguration> configs = componentConfigurations.stream()\n                .map(cc -> new ComponentConfigurationImpl(cc.getPid(), null,\n                        DTOUtil.dtosToConfigurationProperties(cc.getProperties())))\n                .collect(Collectors.toList());\n\n        this.configurationService.updateConfigurations(configs, takeSnapshot);\n    }\n\n    private boolean isComponentManagedByFactory(final String pid) {\n        final AtomicBoolean result = new AtomicBoolean(false);\n\n        try {\n            withAllCloudConnectionFactories(f -> {\n                for (final String stackPid : f.getManagedCloudConnectionPids()) {\n                    if (f.getStackComponentsPids(stackPid).contains(pid)) {\n                        result.set(true);\n                        return;\n                    }\n                }\n            });\n        } catch (final Exception e) {\n            return false;\n        }\n\n        return result.get();\n    }\n\n    private void requireIsPubSub(final String pid) throws KuraException {\n        if (!isPubSub(pid)) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n    }\n\n    private boolean isPubSub(final String pid) {\n        return ServiceUtil.providesService(this.bundleContext, pid, CloudPublisher.class)\n                || ServiceUtil.providesService(this.bundleContext, pid, CloudSubscriber.class);\n    }\n\n    private List<PubSubFactoryInfo> getPubSubFactories() throws KuraException {\n\n        return ServiceUtil.applyToServiceOptionally(this.bundleContext, ServiceComponentRuntime.class, scr ->\n\n        scr.getComponentDescriptionDTOs().stream().map(this::pubSubFactoryToInfo).filter(Objects::nonNull)\n                .collect(Collectors.toList()));\n    }\n\n    private void requireIsPubSubFactory(final String factoryPid) throws KuraException {\n        final boolean isPubSub = ServiceUtil.applyToServiceOptionally(this.bundleContext, ServiceComponentRuntime.class,\n                scr -> scr.getComponentDescriptionDTOs().stream().anyMatch(c -> {\n                    final Map<String, Object> properties = c.properties;\n\n                    if (properties == null) {\n                        return false;\n                    }\n\n                    return Objects.equals(factoryPid, properties.get(\"service.pid\")) && pubSubFactoryToInfo(c) != null;\n                }));\n\n        if (!isPubSub) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n    }\n\n    private PubSubFactoryInfo pubSubFactoryToInfo(final ComponentDescriptionDTO component) {\n\n        if (Arrays.stream(component.serviceInterfaces)\n                .noneMatch(intf -> CLOUD_PUBLISHER.equals(intf) || CLOUD_SUBSCRIBER.equals(intf))) {\n            return null;\n        }\n\n        final String ccsfFactoryPidPropName = CloudConnectionConstants.CLOUD_CONNECTION_FACTORY_PID_PROP_NAME.value();\n\n        final Object ccsfFactoryPid = component.properties.get(ccsfFactoryPidPropName);\n        final Object factoryPid = component.properties.get(\"service.pid\");\n        final Object defaultFactoryPid = component.properties.get(KURA_UI_CSF_PID_DEFAULT);\n        final Object defaultFactoryPidRegex = component.properties.get(KURA_UI_CSF_PID_REGEX);\n\n        if (!(factoryPid instanceof String)) {\n            logger.warn(\n                    \"component {} defines a CloudPublisher or CloudSubscriber but does not specify the service.pid property, ignoring it\",\n                    component.name);\n            return null;\n        }\n\n        if (!(ccsfFactoryPid instanceof String)) {\n            logger.warn(\n                    \"component {} defines a CloudPublisher or CloudSubscriber but does not specify the {} property, ignoring it\",\n                    component.name, ccsfFactoryPidPropName);\n            return null;\n        }\n\n        return new PubSubFactoryInfo((String) factoryPid, (String) ccsfFactoryPid, (String) defaultFactoryPid,\n                (String) defaultFactoryPidRegex);\n    }\n\n    private void fillState(final CloudEndpointInstance cloudEndpointInstance) throws KuraException {\n\n        cloudEndpointInstance.setState(CloudConnectionState.UNREGISTERED);\n\n        final String filter = format(\"(%s=%s)\", KURA_SERVICE_PID, cloudEndpointInstance.getCloudEndpointPid());\n\n        ServiceUtil.withAllServices(this.bundleContext, null, filter, service -> {\n            if (service instanceof CloudConnectionManager) {\n                cloudEndpointInstance\n                        .setState(((CloudConnectionManager) service).isConnected() ? CloudConnectionState.CONNECTED\n                                : CloudConnectionState.DISCONNECTED);\n                cloudEndpointInstance.setConnectionType(CloudEndpointType.CLOUD_CONNECTION_MANAGER);\n            } else if (service instanceof CloudEndpoint) {\n                cloudEndpointInstance.setConnectionType(CloudEndpointType.CLOUD_ENDPOINT);\n            } else if (service instanceof CloudService) {\n                cloudEndpointInstance.setState(((CloudService) service).isConnected() ? CloudConnectionState.CONNECTED\n                        : CloudConnectionState.DISCONNECTED);\n                cloudEndpointInstance.setConnectionType(CloudEndpointType.CLOUD_CONNECTION_MANAGER);\n            }\n        });\n    }\n\n    private void withAllCloudConnectionFactoryRefs(final ServiceReferenceConsumer<Object> consumer)\n            throws KuraException {\n        ServiceUtil.withAllServiceReferences(this.bundleContext, CLOUD_CONNECTION_FACTORY_FILTER, consumer);\n    }\n\n    private void withAllCloudConnectionFactories(final ServiceConsumer<CloudConnectionFactory> consumer)\n            throws KuraException {\n        ServiceUtil.withAllServices(this.bundleContext, CLOUD_CONNECTION_FACTORY_FILTER,\n                o -> consumer.consume(wrap(o)));\n    }\n\n    private CloudConnectionFactory wrap(final Object o) {\n        if (o instanceof CloudConnectionFactory) {\n            return (CloudConnectionFactory) o;\n        } else if (o instanceof CloudServiceFactory) {\n            final CloudServiceFactory f = (CloudServiceFactory) o;\n\n            return new CloudConnectionFactory() {\n\n                @Override\n                public List<String> getStackComponentsPids(String pid) throws KuraException {\n                    return f.getStackComponentsPids(pid);\n                }\n\n                @Override\n                public Set<String> getManagedCloudConnectionPids() throws KuraException {\n                    return f.getManagedCloudServicePids();\n                }\n\n                @Override\n                public String getFactoryPid() {\n                    return f.getFactoryPid();\n                }\n\n                @Override\n                public void deleteConfiguration(String pid) throws KuraException {\n                    f.deleteConfiguration(pid);\n                }\n\n                @Override\n                public void createConfiguration(String pid) throws KuraException {\n                    f.createConfiguration(pid);\n                }\n            };\n        }\n        return null;\n    }\n\n    private Set<PubSubInstance> getPubSubInstances(CloudPubSubType type) throws KuraException {\n\n        final Set<PubSubInstance> result = new HashSet<>();\n\n        Class<?> clazz = (type == CloudPubSubType.PUBLISHER) ? CloudPublisher.class : CloudSubscriber.class;\n\n        try {\n            this.bundleContext.getServiceReferences(clazz, null).stream().map(ref -> pubSubRefToDTO(ref, type))\n                    .filter(Objects::nonNull).forEach(result::add);\n\n            return result;\n        } catch (InvalidSyntaxException e) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER, \"Unexpected error\");\n        }\n    }\n\n    private static PubSubInstance pubSubRefToDTO(final ServiceReference<?> ref, final CloudPubSubType type) {\n        final Object ccsPid = ref.getProperty(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value());\n        final Object factoryPid = ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID);\n\n        if (!(ccsPid instanceof String && factoryPid instanceof String)) {\n            return null;\n        }\n\n        final String kuraServicePid = (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID);\n\n        return new PubSubInstance((String) ccsPid, kuraServicePid, (String) factoryPid, type);\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudComponentFactories.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\nimport java.util.List;\n\npublic class CloudComponentFactories {\n\n    private final List<CloudConnectionFactoryInfo> cloudConnectionFactories;\n    private final List<PubSubFactoryInfo> pubSubFactories;\n\n    public CloudComponentFactories(List<CloudConnectionFactoryInfo> cloudConnectionFactories,\n            List<PubSubFactoryInfo> pubSubFactories) {\n\n        this.cloudConnectionFactories = cloudConnectionFactories;\n        this.pubSubFactories = pubSubFactories;\n    }\n\n    public List<CloudConnectionFactoryInfo> getCloudConnectionFactories() {\n        return this.cloudConnectionFactories;\n    }\n\n    public List<PubSubFactoryInfo> getPubSubFactories() {\n        return this.pubSubFactories;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudComponentInstances.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class CloudComponentInstances {\n\n    private List<CloudEndpointInstance> cloudEndpointInstances = new ArrayList<>();\n    private List<PubSubInstance> pubsubInstances = new ArrayList<>();\n\n    public CloudComponentInstances(List<CloudEndpointInstance> cloudEndpointInstances,\n            List<PubSubInstance> pubsubInstances) {\n        super();\n        this.cloudEndpointInstances = cloudEndpointInstances;\n        this.pubsubInstances = pubsubInstances;\n    }\n\n    public List<CloudEndpointInstance> getCloudEndpointInstances() {\n        return this.cloudEndpointInstances;\n    }\n\n    public List<PubSubInstance> getPubsubInstances() {\n        return this.pubsubInstances;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionFactoryInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic class CloudConnectionFactoryInfo {\n\n    private final String cloudConnectionFactoryPid;\n    private final String defaultCloudEndpointPid;\n    private final String cloudEndpointPidRegex;\n\n    public CloudConnectionFactoryInfo(String cloudConnectionFactoryPid, String defaultCloudEndpointPid,\n            String cloudEndpointPidRegex) {\n\n        this.cloudConnectionFactoryPid = cloudConnectionFactoryPid;\n        this.defaultCloudEndpointPid = defaultCloudEndpointPid;\n        this.cloudEndpointPidRegex = cloudEndpointPidRegex;\n    }\n\n    public String getCloudConnectionFactoryPid() {\n        return this.cloudConnectionFactoryPid;\n    }\n\n    public String getDefaultCloudEndpointPid() {\n        return this.defaultCloudEndpointPid;\n    }\n\n    public String getCloudEndpointPidRegex() {\n        return this.cloudEndpointPidRegex;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionFactoryPidAndCloudEndpointPid.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic class CloudConnectionFactoryPidAndCloudEndpointPid {\n\n    private final String cloudConnectionFactoryPid;\n    private final String cloudEndpointPid;\n\n    public CloudConnectionFactoryPidAndCloudEndpointPid(String cloudConnectionFactoryPid, String cloudEndpointPid) {\n        super();\n        this.cloudConnectionFactoryPid = cloudConnectionFactoryPid;\n        this.cloudEndpointPid = cloudEndpointPid;\n    }\n\n    public String getCloudConnectionFactoryPid() {\n        return this.cloudConnectionFactoryPid;\n    }\n\n    public String getCloudEndpointPid() {\n        return this.cloudEndpointPid;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionState.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic enum CloudConnectionState {\n    UNREGISTERED,\n    DISCONNECTED,\n    CONNECTED;\n}"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointInstance.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic class CloudEndpointInstance {\n\n    private final String cloudConnectionFactoryPid;\n    private final String cloudEndpointPid;\n    private CloudConnectionState state;\n    private CloudEndpointType cloudEndpointType;\n\n    public CloudEndpointInstance(String cloudConnectionFactoryPid, String cloudEndpointPid) {\n        super();\n        this.cloudConnectionFactoryPid = cloudConnectionFactoryPid;\n        this.cloudEndpointPid = cloudEndpointPid;\n    }\n\n    public String getCloudConnectionFactoryPid() {\n        return this.cloudConnectionFactoryPid;\n    }\n\n    public String getCloudEndpointPid() {\n        return this.cloudEndpointPid;\n    }\n\n    public CloudConnectionState getState() {\n        return this.state;\n    }\n\n    public void setState(CloudConnectionState state) {\n        this.state = state;\n    }\n\n    public CloudEndpointType getCloudEndpointType() {\n        return this.cloudEndpointType;\n    }\n\n    public void setConnectionType(CloudEndpointType connectionType) {\n        this.cloudEndpointType = connectionType;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointPidRequest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic class CloudEndpointPidRequest {\n\n    private final String cloudEndpointPid;\n\n    public CloudEndpointPidRequest(String cloudEndpointPid) {\n\n        this.cloudEndpointPid = cloudEndpointPid;\n    }\n\n    public String getCloudEndpointPid() {\n        return this.cloudEndpointPid;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic enum CloudEndpointType {\n    CLOUD_ENDPOINT,\n    CLOUD_CONNECTION_MANAGER;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudPubSubType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic enum CloudPubSubType {\n    PUBLISHER,\n    SUBSCRIBER\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/ConnectedStatus.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic class ConnectedStatus {\n\n    private final boolean connected;\n\n    public ConnectedStatus(boolean connected) {\n        this.connected = connected;\n    }\n\n    public boolean isConnected() {\n        return this.connected;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PidAndFactoryPidAndCloudEndpointPid.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic class PidAndFactoryPidAndCloudEndpointPid {\n\n    private final String pid;\n    private final String factoryPid;\n    private final String cloudEndpointPid;\n\n    public PidAndFactoryPidAndCloudEndpointPid(String pid, String factoryPid, String cloudEndpointPid) {\n\n        this.pid = pid;\n        this.factoryPid = factoryPid;\n        this.cloudEndpointPid = cloudEndpointPid;\n    }\n\n    public String getPid() {\n        return this.pid;\n    }\n\n    public String getFactoryPid() {\n        return this.factoryPid;\n    }\n\n    public String getCloudEndpointPid() {\n        return this.cloudEndpointPid;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PubSubFactoryInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic class PubSubFactoryInfo {\n\n    private final String factoryPid;\n    private final String cloudConnectionFactoryPid;\n    private final String defaultPid;\n    private final String defaultPidRegex;\n\n    public PubSubFactoryInfo(String factoryPid, String cloudConnectionFactoryPid, String defaultPid,\n            String defaultPidRegex) {\n\n        this.factoryPid = factoryPid;\n        this.cloudConnectionFactoryPid = cloudConnectionFactoryPid;\n        this.defaultPid = defaultPid;\n        this.defaultPidRegex = defaultPidRegex;\n    }\n\n    public String getFactoryPid() {\n        return this.factoryPid;\n    }\n\n    public String getCloudConnectionFactoryPid() {\n        return this.cloudConnectionFactoryPid;\n    }\n\n    public String getDefaultPid() {\n        return this.defaultPid;\n    }\n\n    public String getDefaultPidRegex() {\n        return this.defaultPidRegex;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PubSubInstance.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.dto;\n\npublic class PubSubInstance {\n\n    private final String cloudEndpointPid;\n    private final String pid;\n    private final String factoryPid;\n    private final CloudPubSubType type;\n\n    public PubSubInstance(String cloudEndpointPid, String pid, String factoryPid, CloudPubSubType type) {\n        this.cloudEndpointPid = cloudEndpointPid;\n        this.pid = pid;\n        this.factoryPid = factoryPid;\n        this.type = type;\n    }\n\n    public String getCloudEndpointPid() {\n        return this.cloudEndpointPid;\n    }\n\n    public String getPid() {\n        return this.pid;\n    }\n\n    public String getFactoryPid() {\n        return this.factoryPid;\n    }\n\n    public CloudPubSubType getType() {\n        return this.type;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/util/PidUtils.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.util;\n\nimport java.util.Iterator;\n\npublic class PidUtils {\n\n    private PidUtils() {\n\n    }\n\n    public static String getPidFilter(final Iterator<String> pids) {\n        if (!pids.hasNext()) {\n            throw new IllegalArgumentException(\"pids list must be non empty\");\n        }\n        final StringBuilder builder = new StringBuilder();\n        builder.append(\"(|\");\n        while (pids.hasNext()) {\n            final String pid = pids.next();\n            builder.append(\"(kura.service.pid=\");\n            builder.append(pid);\n            builder.append(\")\");\n        }\n        builder.append(\")\");\n        return builder.toString();\n    }\n\n    public static String stripPidPrefix(String pid) {\n        int start = pid.lastIndexOf('.');\n        if (start < 0) {\n            return pid;\n        } else {\n            int begin = start + 1;\n            if (begin < pid.length()) {\n                return pid.substring(begin);\n            } else {\n                return pid;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.configuration.provider\nBundle-SymbolicName: org.eclipse.kura.rest.configuration.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nImport-Package: jakarta.annotation.security;version=\"2.1.1\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.apache.commons.io;version=\"2.4.0\",\n org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.configuration;version=\"[2.0,3.0)\",\n org.eclipse.kura.core.configuration.metatype;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.request.handler.jaxrs;version=\"[2.0,3.0)\",\n org.eclipse.kura.request.handler.jaxrs.annotation;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.component;version=\"1.3.0\",\n org.osgi.service.useradmin;version=\"1.1.0\";resolution:=optional,\n org.slf4j;version=\"1.7.25\"\nExport-Package: org.eclipse.kura.rest.configuration.api;version=\"1.1.0\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/OSGI-INF/configuration_rest_service.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.internal.rest.configuration.ConfigurationRestService\">\n   <implementation class=\"org.eclipse.kura.internal.rest.configuration.ConfigurationRestService\"/>\n   \n   <property name=\"kura.service.pid\" type=\"String\" value=\"org.eclipse.kura.internal.rest.configuration.ConfigurationRestService\"/>\n   \n   <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\"/>\n   <reference bind=\"setOCDService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.metatype.OCDService\" name=\"OCDService\" policy=\"static\"/>\n   <reference bind=\"setUserAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.useradmin.UserAdmin\" name=\"UserAdmin\" policy=\"static\"/>\n   <reference bind=\"setRequestHandlerRegistry\" cardinality=\"0..n\" interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\" name=\"RequestHandlerRegistry\" policy=\"dynamic\" unbind=\"unsetRequestHandlerRegistry\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.internal.rest.configuration.ConfigurationRestService\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.internal.rest.configuration.ConfigurationRestService\"/>\n   <reference bind=\"setCryptoService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.crypto.CryptoService\" name=\"CryptoService\" policy=\"static\"/>\n   <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/build.properties",
    "content": "#\n#  Copyright (c) 2021 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<artifactId>org.eclipse.kura.rest.configuration.provider</artifactId>\n\t<packaging>eclipse-plugin</packaging>\n\t<version>2.0.0-SNAPSHOT</version>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/internal/rest/configuration/ConfigurationRestService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.configuration;\n\nimport static java.util.Objects.isNull;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.metatype.OCDService;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.eclipse.kura.request.handler.jaxrs.JaxRsRequestHandlerProxy;\nimport org.eclipse.kura.request.handler.jaxrs.annotation.EXEC;\nimport org.eclipse.kura.rest.configuration.api.ComponentConfigurationDTO;\nimport org.eclipse.kura.rest.configuration.api.ComponentConfigurationList;\nimport org.eclipse.kura.rest.configuration.api.CreateFactoryComponentConfigurationsRequest;\nimport org.eclipse.kura.rest.configuration.api.DTOUtil;\nimport org.eclipse.kura.rest.configuration.api.DeleteFactoryComponentRequest;\nimport org.eclipse.kura.rest.configuration.api.FactoryComponentConfigurationDTO;\nimport org.eclipse.kura.rest.configuration.api.FailureHandler;\nimport org.eclipse.kura.rest.configuration.api.PidAndFactoryPid;\nimport org.eclipse.kura.rest.configuration.api.PidAndFactoryPidSet;\nimport org.eclipse.kura.rest.configuration.api.PidSet;\nimport org.eclipse.kura.rest.configuration.api.SnapshotId;\nimport org.eclipse.kura.rest.configuration.api.SnapshotIdSet;\nimport org.eclipse.kura.rest.configuration.api.UpdateComponentConfigurationRequest;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.DELETE;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.PUT;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.core.Response.Status;\n\n@Path(\"/configuration/v2\")\npublic class ConfigurationRestService {\n\n    private static final Logger logger = LoggerFactory.getLogger(ConfigurationRestService.class);\n\n    private static final String APP_ID = \"CONF-V2\";\n\n    private static final String KURA_PERMISSION_REST_CONFIGURATION_ROLE = \"kura.permission.rest.configuration\";\n    private static final String SNAPSHOT_SUBTASK_ID = \"snapshot\";\n\n    private final RequestHandler requestHandler = new JaxRsRequestHandlerProxy(this);\n\n    private ConfigurationService configurationService;\n    private OCDService ocdService;\n    private CryptoService cryptoService;\n\n    public void setUserAdmin(UserAdmin userAdmin) {\n        userAdmin.createRole(KURA_PERMISSION_REST_CONFIGURATION_ROLE, Role.GROUP);\n    }\n\n    public void setConfigurationService(ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    public void setOCDService(OCDService ocdService) {\n        this.ocdService = ocdService;\n    }\n\n    public void setCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    public void setRequestHandlerRegistry(final RequestHandlerRegistry registry) {\n        try {\n            registry.registerRequestHandler(APP_ID, this.requestHandler);\n        } catch (final Exception e) {\n            logger.warn(\"failed to register request handler\", e);\n        }\n    }\n\n    public void unsetRequestHandlerRegistry(final RequestHandlerRegistry registry) {\n        try {\n            registry.unregister(APP_ID);\n        } catch (KuraException e) {\n            logger.warn(\"failed to unregister request handler\", e);\n        }\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists all the available snapshots in the framework\n     *\n     * @return a list of long that represents the list of snapshots managed by the\n     *         framework.\n     */\n    @GET\n    @RolesAllowed(\"configuration\")\n    @Path(\"/snapshots\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public SnapshotIdSet listSnapshots() {\n        try {\n            return new SnapshotIdSet(\n                    this.configurationService.getSnapshots().stream().collect(Collectors.toCollection(TreeSet::new)));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * GET method.\n     *\n     * The method lists all the FactoryComponents Pids tracked by\n     * {@link ConfigurationService}\n     *\n     * @return a list of String representing the tracked FactoryComponents\n     */\n    @GET\n    @RolesAllowed(\"configuration\")\n    @Path(\"/factoryComponents\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public PidSet listFactoryComponentsPids() {\n        return new PidSet(this.configurationService.getFactoryComponentPids().stream().collect(Collectors.toSet()));\n    }\n\n    /**\n     * POST method.\n     *\n     * Creates a new ConfigurableComponent instance by creating a new configuration\n     * from a\n     * Configuration Admin factory.\n     * The {@link FactoryComponentConfigurationDTO} will provide all the information\n     * needed to generate the instance: it\n     * links the factory Pid to be used, the target instance Pid, the properties to\n     * be used when creating the instance\n     * and if the request should be persisted with a snapshot.\n     * In case of a request error, an exception is thrown.\n     *\n     * @param factoryComponentConfiguration\n     *            provides all the parameters needed to\n     *            generate a new instance from a Factory\n     *            Component\n     *\n     */\n    @POST\n    @RolesAllowed(\"configuration\")\n    @Path(\"/factoryComponents\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response createFactoryComponents(CreateFactoryComponentConfigurationsRequest configs) {\n        configs.validate();\n\n        final FailureHandler handler = new FailureHandler();\n\n        for (final FactoryComponentConfigurationDTO config : configs.getConfigs()) {\n            handler.runFallibleSubtask(\"create:\" + config.getPid(), () -> {\n                final Map<String, Object> castedProperties = DTOUtil\n                        .dtosToConfigurationProperties(config.getProperties());\n\n                this.configurationService.createFactoryConfiguration(config.getFactoryPid(), config.getPid(),\n                        castedProperties, false);\n\n            });\n        }\n\n        if (configs.isTakeSnapshot()) {\n            handler.runFallibleSubtask(SNAPSHOT_SUBTASK_ID, () -> this.configurationService.snapshot());\n        }\n\n        handler.checkStatus();\n        return Response.ok().build();\n    }\n\n    /**\n     * DELETE method.\n     *\n     * For the specified Pid and {@link FactoryComponentDeleteRequest}, the\n     * {@link ConfigurationService} instance\n     * deletes the corresponding ConfigurableComponent instance.\n     *\n     * @param pid\n     *            A String representing the pid of the\n     *            instance generated by a Factory\n     *            Component that needs to be\n     *            deleted\n     * @param factoryComponentDeleteRequest\n     *            A {@link FactoryComponentDeleteRequest}\n     *            containing additional information to\n     *            ease the process of\n     *            instance delete\n     */\n    @DELETE\n    @RolesAllowed(\"configuration\")\n    @Path(\"/factoryComponents/byPid\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response deleteFactoryConfigurations(final DeleteFactoryComponentRequest request) {\n        request.validate();\n\n        final FailureHandler handler = new FailureHandler();\n\n        for (final String pid : request.getPids()) {\n            handler.runFallibleSubtask(\"delete:\" + pid,\n                    () -> this.configurationService.deleteFactoryConfiguration(pid, false));\n        }\n\n        if (request.isTakeSnapshot()) {\n            handler.runFallibleSubtask(SNAPSHOT_SUBTASK_ID, () -> this.configurationService.snapshot());\n        }\n\n        handler.checkStatus();\n        return Response.ok().build();\n    }\n\n    @GET\n    @RolesAllowed(\"configuration\")\n    @Path(\"/factoryComponents/ocd\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public ComponentConfigurationList getFactoryComponentOcds() {\n        final List<ComponentConfiguration> ocds;\n\n        try {\n            ocds = this.ocdService.getFactoryComponentOCDs();\n        } catch (final Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return DTOUtil.toComponentConfigurationList(ocds, this.cryptoService, false);\n    }\n\n    @POST\n    @RolesAllowed(\"configuration\")\n    @Path(\"/factoryComponents/ocd/byFactoryPid\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public ComponentConfigurationList getFactoryComponentOcdsByPid(final PidSet factoryPids) {\n        factoryPids.validate();\n\n        final List<ComponentConfiguration> ocds;\n\n        try {\n            ocds = this.ocdService.getFactoryComponentOCDs().stream()\n                    .filter(c -> factoryPids.getPids().contains(c.getPid())).collect(Collectors.toList());\n        } catch (final Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return DTOUtil.toComponentConfigurationList(ocds, this.cryptoService, false);\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists the tracked configurable component Pids\n     *\n     * @return a List of String objects representing the Pids of factory components\n     *         tracked by the\n     *         {@link ConfigurationService}\n     */\n    @GET\n    @RolesAllowed(\"configuration\")\n    @Path(\"/configurableComponents/pidsWithFactory\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public PidAndFactoryPidSet listConfigurableComponentsPidAndFactoryPid() {\n\n        final List<ComponentConfiguration> ccs;\n\n        try {\n            ccs = this.configurationService.getComponentConfigurations();\n        } catch (final Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        final Set<PidAndFactoryPid> result = ccs.stream().map(c -> {\n            final String pid = c.getPid();\n\n            final Optional<String> factoryPid = Optional.ofNullable(c.getConfigurationProperties())\n                    .map(p -> p.get(ConfigurationAdmin.SERVICE_FACTORYPID)).flatMap(o -> {\n                        if (o instanceof String) {\n                            return Optional.of((String) o);\n                        } else {\n                            return Optional.empty();\n                        }\n                    });\n\n            if (factoryPid.isPresent()) {\n                return new PidAndFactoryPid(pid, factoryPid.get());\n            } else {\n                return new PidAndFactoryPid(pid);\n            }\n\n        }).collect(Collectors.toSet());\n\n        return new PidAndFactoryPidSet(result);\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists the tracked configurable component Pids\n     *\n     * @return a List of String objects representing the Pids of factory components\n     *         tracked by the\n     *         {@link ConfigurationService}\n     */\n    @GET\n    @RolesAllowed(\"configuration\")\n    @Path(\"/configurableComponents\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public PidSet listConfigurableComponentsPids() {\n        return new PidSet(\n                this.configurationService.getConfigurableComponentPids().stream().collect(Collectors.toSet()));\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists all the component configurations of all the ConfigurableComponents\n     * tracked by the\n     * {@link ConfigurationService}\n     *\n     * @return a list of {@link ComponentConfigurationDTO} that map all the\n     *         configuration parameters tracked for the\n     *         configurable components tracked.\n     */\n    @GET\n    @RolesAllowed(\"configuration\")\n    @Path(\"/configurableComponents/configurations\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public ComponentConfigurationList listComponentConfigurations() {\n\n        final List<ComponentConfiguration> ccs;\n\n        try {\n            ccs = this.configurationService.getComponentConfigurations();\n        } catch (final Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return DTOUtil.toComponentConfigurationList(ccs, this.cryptoService, false).replacePasswordsWithPlaceholder();\n\n    }\n\n    /**\n     * POST method.\n     *\n     * Lists the component configurations of all the ConfigurableComponents tracked\n     * by the\n     * {@link ConfigurationService} that match the filter specified\n     *\n     * @param filter\n     *            A String representing an OSGi filter\n     * @return a list of {@link ComponentConfigurationDTO}s for the components that\n     *         match the specified filter\n     */\n    @POST\n    @RolesAllowed(\"configuration\")\n    @Path(\"/configurableComponents/configurations/byPid\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public ComponentConfigurationList listComponentConfigurations(final PidSet pids) {\n        pids.validate();\n\n        final List<ComponentConfiguration> configs = new ArrayList<>();\n\n        pids.getPids().forEach(pid -> {\n            try {\n                ComponentConfiguration config = this.configurationService.getComponentConfiguration(pid);\n                if (!isNull(config)) {\n                    configs.add(config);\n                }\n            } catch (Exception e) {\n                throw DefaultExceptionHandler.toWebApplicationException(e);\n            }\n        });\n\n        return DTOUtil.toComponentConfigurationList(configs, this.cryptoService, false)\n                .replacePasswordsWithPlaceholder();\n    }\n\n    /**\n     * POST method.\n     *\n     * Provides the default Component Configuration for the component identified by\n     * the specified PID\n     *\n     * @param componentPid\n     * @return The default {@link ComponentConfiguration} or a null object if the\n     *         component is not tracked\n     */\n    @POST\n    @RolesAllowed(\"configuration\")\n    @Path(\"/configurableComponents/configurations/byPid/_default\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    @Produces(MediaType.APPLICATION_JSON)\n    public ComponentConfigurationList listDefaultComponentConfiguration(final PidSet pids) {\n        pids.validate();\n\n        final List<ComponentConfigurationDTO> result = new ArrayList<>();\n\n        for (final String pid : pids.getPids()) {\n            try {\n                final ComponentConfiguration cc = this.configurationService.getDefaultComponentConfiguration(pid);\n\n                if (cc == null || cc.getDefinition() == null) {\n                    logger.warn(\"cannot find default configuration for {}\", pid);\n                    continue;\n                }\n\n                result.add(DTOUtil.toComponentConfigurationDTO(cc, this.cryptoService, false));\n            } catch (final Exception e) {\n                logger.warn(\"failed to get default configuration for {}\", pid, e);\n            }\n        }\n\n        return new ComponentConfigurationList(result);\n    }\n\n    /**\n     * POST method.\n     *\n     * Allows to update the configuration of multiple configurable components\n     *\n     * @param request\n     */\n    @PUT\n    @RolesAllowed(\"configuration\")\n    @Path(\"/configurableComponents/configurations/_update\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response updateComponentConfigurations(UpdateComponentConfigurationRequest request) {\n        request.validate();\n\n        final FailureHandler handler = new FailureHandler();\n\n        for (ComponentConfigurationDTO ccr : request.getComponentConfigurations()) {\n\n            handler.runFallibleSubtask(\"update:\" + ccr.getPid(), () -> {\n                final Map<String, Object> configurationProperties = DTOUtil\n                        .dtosToConfigurationProperties(ccr.getProperties());\n                this.configurationService.updateConfiguration(ccr.getPid(), configurationProperties, false);\n            });\n        }\n\n        if (request.isTakeSnapshot()) {\n            handler.runFallibleSubtask(SNAPSHOT_SUBTASK_ID, () -> this.configurationService.snapshot());\n        }\n\n        handler.checkStatus();\n        return Response.ok().build();\n    }\n\n    /**\n     * POST method.\n     *\n     * Returns the content of a given snapshot tracked by the framework.\n     *\n     * @param snapshotId\n     * @return a List of {@link ComponentConfiguration}\n     */\n    @POST\n    @RolesAllowed(\"configuration\")\n    @Path(\"/snapshots/byId\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public ComponentConfigurationList getSnapshot(final SnapshotId id) {\n        id.validate();\n\n        try {\n            if (!this.configurationService.getSnapshots().contains(id.getId())) {\n                throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND);\n            }\n\n            List<ComponentConfiguration> configs = this.configurationService.getSnapshot(id.getId());\n\n            return DTOUtil.toComponentConfigurationList(configs, this.cryptoService, false);\n        } catch (KuraException e) {\n            if (e.getCode() == KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.NOT_FOUND,\n                        \"The requested snapshot cannot be found.\");\n            }\n\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * POST method.\n     *\n     * Triggers the framework to take and persist a snapshot.\n     *\n     * @return a long representing the id of the generated snapshot\n     */\n    @EXEC\n    @POST\n    @RolesAllowed(\"configuration\")\n    @Path(\"/snapshots/_write\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public SnapshotId takeSnapshot() {\n        try {\n            return new SnapshotId(this.configurationService.snapshot());\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * POST method\n     *\n     * Rollbacks the framework to the last saved snapshot if available.\n     *\n     * @return the ID of the snapshot it rolled back to\n     */\n    @EXEC\n    @POST\n    @RolesAllowed(\"configuration\")\n    @Path(\"/snapshots/_rollback\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public SnapshotId rollbackSnapshot() {\n        try {\n            return new SnapshotId(this.configurationService.rollback());\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * POST method.\n     *\n     * Rollbacks the framework to the snapshot identified by the provided ID\n     *\n     * @param snapshotId\n     */\n    @EXEC\n    @POST\n    @RolesAllowed(\"configuration\")\n    @Path(\"/snapshots/byId/_rollback\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response rollbackSnapshot(final SnapshotId id) {\n        id.validate();\n\n        try {\n            this.configurationService.rollback(id.getId());\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/AdDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.Option;\nimport org.eclipse.kura.configuration.metatype.Scalar;\n\npublic class AdDTO implements AD {\n\n    private final List<Option> option;\n    private final String name;\n    private final String description;\n    private final String id;\n    private final Scalar type;\n    private final int cardinality;\n    private final String min;\n    private final String max;\n    private final String defaultValue;\n    private final boolean isRequired;\n\n    public AdDTO(final AD ad) {\n        this.option = ad.getOption() == null || ad.getOption().isEmpty() ? null\n                : ad.getOption().stream().map(OptionDTO::new).collect(Collectors.toList());\n        this.name = ad.getName();\n        this.description = ad.getDescription();\n        this.id = ad.getId();\n        this.type = ad.getType();\n        this.cardinality = ad.getCardinality();\n        this.min = ad.getMin();\n        this.max = ad.getMax();\n        this.defaultValue = ad.getDefault();\n        this.isRequired = ad.isRequired();\n    }\n\n    @Override\n    public List<Option> getOption() {\n        return option;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public String getDescription() {\n        return description;\n    }\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n    @Override\n    public Scalar getType() {\n        return type;\n    }\n\n    @Override\n    public int getCardinality() {\n        return cardinality;\n    }\n\n    @Override\n    public String getMin() {\n        return min;\n    }\n\n    @Override\n    public String getMax() {\n        return max;\n    }\n\n    @Override\n    public String getDefault() {\n        return defaultValue;\n    }\n\n    @Override\n    public boolean isRequired() {\n        return isRequired;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/ComponentConfigurationDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\n\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.configuration.metatype.Scalar;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\n\npublic class ComponentConfigurationDTO implements Validable {\n\n    private final String pid;\n    private final OcdDTO definition;\n    private final Map<String, PropertyDTO> properties;\n\n    public ComponentConfigurationDTO(final String pid, final OcdDTO definition,\n            final Map<String, PropertyDTO> properties) {\n        this.pid = pid;\n        this.definition = definition;\n        this.properties = properties;\n    }\n\n    public String getPid() {\n        return this.pid;\n    }\n\n    public Optional<OCD> getDefinition() {\n        return Optional.ofNullable(this.definition);\n    }\n\n    public Map<String, PropertyDTO> getProperties() {\n        return this.properties;\n    }\n\n    public ComponentConfigurationDTO replacePasswordsWithPlaceholder() {\n\n        if (properties == null) {\n            return this;\n        }\n\n        final Map<String, PropertyDTO> result = new HashMap<>(this.properties);\n\n        for (final Entry<String, PropertyDTO> e : result.entrySet()) {\n            e.setValue(replacePasswordsWithPlaceholder(e.getValue()));\n        }\n\n        return new ComponentConfigurationDTO(pid, definition, result);\n    }\n\n    public PropertyDTO replacePasswordsWithPlaceholder(final PropertyDTO property) {\n\n        if (property == null || property.getType() != Scalar.PASSWORD) {\n            return property;\n        }\n\n        if (property.getValue() instanceof String[]) {\n            final String[] asStringArray = (String[]) property.getValue();\n            final String[] result = new String[asStringArray.length];\n\n            for (int i = 0; i < asStringArray.length; i++) {\n                if (asStringArray[i] != null) {\n                    result[i] = \"placeholder\";\n                }\n            }\n\n            return new PropertyDTO(result, Scalar.PASSWORD);\n        } else {\n            return new PropertyDTO(\"placeholder\", Scalar.PASSWORD);\n        }\n    }\n\n    @Override\n    public void validate() {\n        FailureHandler.requireParameter(this.pid, \"pid\");\n        FailureHandler.requireParameter(this.properties, \"properties\");\n\n        for (final PropertyDTO param : properties.values()) {\n            if (param == null) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                        \"propety values cannot be null\");\n            }\n\n            param.validate();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/ComponentConfigurationList.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\npublic class ComponentConfigurationList implements Validable {\n\n    private final List<ComponentConfigurationDTO> configs;\n\n    public ComponentConfigurationList(List<ComponentConfigurationDTO> configs) {\n        this.configs = configs;\n    }\n\n    public List<ComponentConfigurationDTO> getConfigs() {\n        return configs;\n    }\n\n    @Override\n    public void validate() {\n        FailureHandler.requireParameter(this.configs, \"configs\");\n    }\n\n    public ComponentConfigurationList replacePasswordsWithPlaceholder() {\n        if (configs == null) {\n            return this;\n        }\n\n        return new ComponentConfigurationList(\n                configs.stream().map(ComponentConfigurationDTO::replacePasswordsWithPlaceholder)\n                        .collect(Collectors.toList()));\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/CreateFactoryComponentConfigurationsRequest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.List;\n\npublic class CreateFactoryComponentConfigurationsRequest implements Validable {\n\n    private final List<FactoryComponentConfigurationDTO> configs;\n    private final Boolean takeSnapshot;\n\n    public CreateFactoryComponentConfigurationsRequest(List<FactoryComponentConfigurationDTO> configs,\n            boolean takeSnapshot) {\n        this.configs = configs;\n        this.takeSnapshot = takeSnapshot;\n    }\n\n    public List<FactoryComponentConfigurationDTO> getConfigs() {\n        return configs;\n    }\n\n    public boolean isTakeSnapshot() {\n        return this.takeSnapshot == null || this.takeSnapshot;\n    }\n\n    @Override\n    public void validate() {\n        FailureHandler.requireParameter(this.configs, \"configs\");\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/DTOUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class DTOUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(DTOUtil.class);\n\n    private DTOUtil() {\n    }\n\n    public static ComponentConfigurationDTO toComponentConfigurationDTO(final ComponentConfiguration config,\n            final CryptoService cryptoService, final boolean decryptPasswords) {\n\n        return new ComponentConfigurationDTO(config.getPid(), ocdToDto(config.getDefinition()),\n                configurationPropertiesToDtos(config.getConfigurationProperties(), cryptoService, decryptPasswords));\n    }\n\n    public static ComponentConfigurationList toComponentConfigurationList(final List<ComponentConfiguration> configs,\n            final CryptoService cryptoService, final boolean decryptPasswords) {\n        final List<ComponentConfigurationDTO> result = configs.stream()\n                .map(c -> toComponentConfigurationDTO(c, cryptoService, decryptPasswords)).collect(Collectors.toList());\n\n        return new ComponentConfigurationList(result);\n    }\n\n    public static Map<String, Object> dtosToConfigurationProperties(final Map<String, PropertyDTO> properties) {\n        if (properties == null) {\n            return null;\n        }\n\n        final Map<String, Object> result = new HashMap<>(properties.size());\n\n        for (final Entry<String, PropertyDTO> e : properties.entrySet()) {\n\n            if (e.getValue().getValue() == null) {\n                result.put(e.getKey(), null);\n            } else {\n                final Object propertyValue = e.getValue().toConfigurationProperty()\n                        .orElseThrow(() -> new IllegalArgumentException(\n                                \"Invalid property value for \" + e.getKey() + \" \" + e.getValue()));\n\n                result.put(e.getKey(), propertyValue);\n            }\n        }\n\n        return result;\n    }\n\n    public static OcdDTO ocdToDto(final OCD ocd) {\n        if (ocd == null) {\n            return null;\n        } else {\n            return new OcdDTO(ocd);\n        }\n    }\n\n    public static Map<String, PropertyDTO> configurationPropertiesToDtos(Map<String, Object> properties,\n            final CryptoService cryptoService, final boolean decryptPasswords) {\n        if (properties == null) {\n            return null;\n        }\n\n        final Map<String, PropertyDTO> result = new HashMap<>();\n\n        for (final Entry<String, Object> entry : properties.entrySet()) {\n\n            final Optional<Object> value;\n\n            if (entry.getValue() == null) {\n                continue;\n            }\n\n            if (decryptPasswords) {\n                value = decryptPassword(entry.getValue(), cryptoService);\n            } else {\n                value = Optional.ofNullable(entry.getValue());\n            }\n\n            final Optional<PropertyDTO> propertyDTO = value.flatMap(PropertyDTO::fromConfigurationProperty);\n\n            if (!propertyDTO.isPresent()) {\n                logger.warn(\"ignoring invalid configiration property for {}: {}\", entry.getKey(), entry.getValue());\n            } else {\n                result.put(entry.getKey(), propertyDTO.get());\n            }\n        }\n\n        return result;\n    }\n\n    public static Optional<Object> decryptPassword(final Object property, final CryptoService cryptoService) {\n        try {\n            final Object result;\n\n            if (property instanceof Password) {\n                result = new Password(cryptoService.decryptAes(((Password) property).getPassword()));\n            } else if (property instanceof Password[]) {\n                final Password[] asPasswords = (Password[]) property;\n                final Password[] resultPasswords = new Password[asPasswords.length];\n\n                for (int i = 0; i < asPasswords.length; i++) {\n                    resultPasswords[i] = new Password(cryptoService.decryptAes(asPasswords[i].getPassword()));\n                }\n\n                result = resultPasswords;\n            } else {\n                result = property;\n            }\n\n            return Optional.ofNullable(result);\n        } catch (final Exception e) {\n            return Optional.empty();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/DeleteFactoryComponentRequest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.Set;\n\npublic class DeleteFactoryComponentRequest implements Validable {\n\n    private final Set<String> pids;\n    private final Boolean takeSnapshot;\n\n    public DeleteFactoryComponentRequest(Set<String> pids, boolean takeSnapshot) {\n        this.pids = pids;\n        this.takeSnapshot = takeSnapshot;\n    }\n\n    public Set<String> getPids() {\n        return pids;\n    }\n\n    public boolean isTakeSnapshot() {\n        return this.takeSnapshot == null || this.takeSnapshot;\n    }\n\n    @Override\n    public void validate() {\n        FailureHandler.requireParameter(this.pids, \"pids\");\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/FactoryComponentConfigurationDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\n\npublic class FactoryComponentConfigurationDTO implements Validable {\n\n    private final String factoryPid;\n    private final String pid;\n    private final Map<String, PropertyDTO> properties;\n\n    public FactoryComponentConfigurationDTO(String factoryPid, String pid, Map<String, PropertyDTO> properties) {\n        this.factoryPid = factoryPid;\n        this.pid = pid;\n        this.properties = properties;\n    }\n\n    public String getFactoryPid() {\n        return this.factoryPid;\n    }\n\n    public String getPid() {\n        return this.pid;\n    }\n\n    public Map<String, PropertyDTO> getProperties() {\n        return this.properties != null ? this.properties : Collections.emptyMap();\n    }\n\n    @Override\n    public void validate() {\n        FailureHandler.requireParameter(this.factoryPid, \"factoryPid\");\n        FailureHandler.requireParameter(this.pid, \"pid\");\n\n        if (properties != null) {\n            for (final PropertyDTO param : properties.values()) {\n                if (param == null) {\n                    throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                            \"propety values cannot be null\");\n                }\n\n                param.validate();\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/Failure.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\npublic class Failure {\n\n    private final String message;\n\n    public Failure(String message) {\n        this.message = message;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/FailureHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport jakarta.ws.rs.WebApplicationException;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.KuraException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FailureHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(FailureHandler.class);\n\n    private final List<SubtaskFailure> failures = new ArrayList<>();\n\n    public void runFallibleSubtask(final String id, final FallibleTask fallibleTask) {\n        try {\n            fallibleTask.run();\n        } catch (final Exception e) {\n            processFailure(id, e);\n        }\n    }\n\n    public void processFailure(final String id, final Exception e) {\n        logger.warn(\"task failed {}\", id, e);\n        failures.add(new SubtaskFailure(id, e.getMessage() != null ? e.getMessage() : \"An internal error occurred\"));\n    }\n\n    public void checkStatus() {\n        if (!failures.isEmpty()) {\n            throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR)\n                    .type(MediaType.APPLICATION_JSON).entity(new SubtaskFailureList(failures)).build());\n        }\n    }\n\n    @FunctionalInterface\n    public interface FallibleTask {\n\n        public void run() throws KuraException;\n    }\n\n    public static WebApplicationException parameterRequired(final String parameter) {\n        final Response response = Response.status(Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON)\n                .entity(new Failure(\"parameter \\\"\" + parameter + \"\\\" is required\")).build();\n        return new WebApplicationException(response);\n    }\n\n    public static void requireParameter(final Object value, final String name) {\n        if (value == null) {\n            throw parameterRequired(name);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/IconDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.math.BigInteger;\n\nimport org.eclipse.kura.configuration.metatype.Icon;\n\npublic class IconDTO implements Icon {\n\n    private final String resource;\n    private final BigInteger size;\n\n    public IconDTO(final Icon icon) {\n        this.resource = icon.getResource();\n        this.size = icon.getSize();\n    }\n\n    @Override\n    public String getResource() {\n        return resource;\n    }\n\n    @Override\n    public BigInteger getSize() {\n        return size;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/OcdDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.Icon;\nimport org.eclipse.kura.configuration.metatype.OCD;\n\npublic class OcdDTO implements OCD {\n\n    private final List<AdDTO> ad;\n    private final List<IconDTO> icon;\n    private final String name;\n    private final String description;\n    private final String id;\n\n    public OcdDTO(final OCD ocd) {\n        this.name = ocd.getName();\n        this.description = ocd.getDescription();\n        this.id = ocd.getId();\n\n        final List<AD> ocdAD = ocd.getAD();\n\n        if (ocdAD == null || ocdAD.isEmpty()) {\n            this.ad = null;\n        } else {\n            this.ad = ocdAD.stream().map(AdDTO::new).collect(Collectors.toList());\n        }\n\n        final List<Icon> ocdIcon = ocd.getIcon();\n\n        if (ocdIcon == null || ocdIcon.isEmpty()) {\n            this.icon = null;\n        } else {\n            this.icon = ocdIcon.stream().map(IconDTO::new).collect(Collectors.toList());\n        }\n\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public List<AD> getAD() {\n        return (List<AD>) (Object) ad;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public List<Icon> getIcon() {\n        return (List<Icon>) (Object) icon;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public String getDescription() {\n        return description;\n    }\n\n    @Override\n    public String getId() {\n        return id;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/OptionDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport org.eclipse.kura.configuration.metatype.Option;\n\npublic class OptionDTO implements Option {\n\n    private final String label;\n    private final String value;\n\n    public OptionDTO(final Option other) {\n        this.label = other.getLabel();\n        this.value = other.getValue();\n    }\n\n    @Override\n    public String getLabel() {\n        return label;\n    }\n\n    @Override\n    public String getValue() {\n        return value;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/PidAndFactoryPid.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\npublic class PidAndFactoryPid {\n\n    private final String pid;\n    private final String factoryPid;\n\n    public PidAndFactoryPid(String pid) {\n        this(pid, null);\n    }\n\n    public PidAndFactoryPid(String pid, String factoryPid) {\n        this.pid = pid;\n        this.factoryPid = factoryPid;\n    }\n\n    public String getPid() {\n        return pid;\n    }\n\n    public String getFactoryPid() {\n        return factoryPid;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/PidAndFactoryPidSet.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.Set;\n\npublic class PidAndFactoryPidSet {\n\n    private final Set<PidAndFactoryPid> components;\n\n    public PidAndFactoryPidSet(final Set<PidAndFactoryPid> components) {\n        this.components = components;\n    }\n\n    public Set<PidAndFactoryPid> getComponents() {\n        return components;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/PidSet.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.Set;\n\npublic class PidSet implements Validable {\n\n    private final Set<String> pids;\n\n    public PidSet(Set<String> pids) {\n        this.pids = pids;\n    }\n\n    public Set<String> getPids() {\n        return pids;\n    }\n\n    @Override\n    public void validate() {\n        FailureHandler.requireParameter(this.pids, \"pids\");\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/PropertyDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.function.Function;\n\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.configuration.metatype.Scalar;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\n\npublic class PropertyDTO implements Validable {\n\n    private final Object value;\n    private final Scalar type;\n\n    public PropertyDTO(final Object value, final Scalar type) {\n        this.value = value;\n        this.type = type;\n    }\n\n    public Scalar getType() {\n        return this.type;\n    }\n\n    public Object getValue() {\n        return this.value;\n    }\n\n    @Override\n    public void validate() {\n        FailureHandler.requireParameter(this.type, \"type\");\n\n        if (this.value instanceof List<?>) {\n            validateArrayProperty(this.type, (List<?>) this.value);\n        } else {\n            validateSingletonProperty(this.type, this.value);\n        }\n    }\n\n    private static void validateArrayProperty(final Scalar type, final List<?> values) {\n        for (final Object singletonValue : values) {\n            validateSingletonProperty(type, singletonValue);\n        }\n    }\n\n    private static void validateSingletonProperty(final Scalar type, final Object value) {\n        if (value == null) {\n            return;\n        }\n\n        final boolean isValid;\n\n        switch (type) {\n        case BYTE:\n        case FLOAT:\n        case LONG:\n        case INTEGER:\n        case SHORT:\n        case DOUBLE:\n            isValid = value instanceof Number;\n            break;\n        case PASSWORD:\n        case STRING:\n            isValid = value instanceof String;\n            break;\n        case CHAR:\n            isValid = value instanceof String && ((String) value).length() == 1;\n            break;\n        case BOOLEAN:\n            isValid = value instanceof Boolean;\n            break;\n        default:\n            isValid = false;\n        }\n\n        if (!isValid) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                    \"Invalid property for type \" + type + \": \" + value);\n        }\n    }\n\n    public static Optional<PropertyDTO> fromConfigurationProperty(final Object property) {\n\n        return Optional.ofNullable(property).flatMap(PropertyDTO::getScalarFromObject)\n                .map(type -> new PropertyDTO(configurationPropertyToDTOProperty(property), type));\n    }\n\n    private static Optional<Scalar> getScalarFromObject(Object p) {\n        Class<?> clazz = p.getClass();\n        if (clazz.isArray()) {\n            Object[] tempArray = (Object[]) p;\n            if (tempArray.length > 0 && tempArray[0] != null) {\n                clazz = tempArray[0].getClass();\n            } else {\n                clazz = clazz.getComponentType();\n            }\n        }\n        return scalarFromSingletonClass(clazz);\n    }\n\n    public Optional<Object> toConfigurationProperty() {\n        if (this.value == null) {\n            return Optional.empty();\n        }\n\n        final Optional<Object> asSingleton = singletonToProperty(this.value, this.type);\n\n        if (asSingleton.isPresent()) {\n            return asSingleton;\n        }\n\n        return arrayToProperty(this.value, this.type);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static <T> T assertType(final Object value, final Class<T> clazz) {\n        if (value.getClass() == clazz) {\n            return (T) value;\n        } else {\n            throw new IllegalArgumentException();\n        }\n    }\n\n    private static <T> Function<Object, T> nullOrElse(final Function<Object, T> func) {\n        return v -> {\n            if (v == null) {\n                return null;\n            } else {\n                return func.apply(v);\n            }\n        };\n    }\n\n    private static Optional<Object> singletonToProperty(final Object value, final Scalar type) {\n        final Object result;\n\n        try {\n            switch (type) {\n            case BOOLEAN:\n                result = assertType(value, Boolean.class);\n                break;\n            case BYTE:\n                result = ((Number) value).byteValue();\n                break;\n            case CHAR:\n                result = ((String) value).charAt(0);\n                break;\n            case DOUBLE:\n                result = ((Number) value).doubleValue();\n                break;\n            case FLOAT:\n                result = ((Number) value).floatValue();\n                break;\n            case INTEGER:\n                result = ((Number) value).intValue();\n                break;\n            case LONG:\n                result = ((Number) value).longValue();\n                break;\n            case PASSWORD:\n                result = new Password(assertType(value, String.class));\n                break;\n            case SHORT:\n                result = ((Number) value).shortValue();\n                break;\n            case STRING:\n                result = assertType(value, String.class);\n                break;\n            default:\n                return Optional.empty();\n            }\n\n            return Optional.of(result);\n        } catch (Exception e) {\n            return Optional.empty();\n        }\n    }\n\n    private static Optional<Object> arrayToProperty(final Object propertyValue, final Scalar type) {\n        final Object result;\n\n        try {\n            switch (type) {\n            case BOOLEAN:\n                result = ((List<?>) propertyValue).stream().map(nullOrElse(v -> assertType(v, Boolean.class)))\n                        .toArray(Boolean[]::new);\n                break;\n            case BYTE:\n                result = ((List<?>) propertyValue).stream().map(nullOrElse(v -> ((Number) v).byteValue()))\n                        .toArray(Byte[]::new);\n                break;\n            case CHAR:\n                result = ((List<?>) propertyValue).stream().map(nullOrElse(v -> ((String) v).charAt(0)))\n                        .toArray(Character[]::new);\n                break;\n            case DOUBLE:\n                result = ((List<?>) propertyValue).stream().map(nullOrElse(v -> ((Number) v).doubleValue()))\n                        .toArray(Double[]::new);\n                break;\n            case FLOAT:\n                result = ((List<?>) propertyValue).stream().map(nullOrElse(v -> ((Number) v).floatValue()))\n                        .toArray(Float[]::new);\n                break;\n            case INTEGER:\n                result = ((List<?>) propertyValue).stream().map(nullOrElse(v -> ((Number) v).intValue()))\n                        .toArray(Integer[]::new);\n                break;\n            case LONG:\n                result = ((List<?>) propertyValue).stream().map(nullOrElse(v -> ((Number) v).longValue()))\n                        .toArray(Long[]::new);\n                break;\n            case PASSWORD:\n                result = ((List<?>) propertyValue).stream()\n                        .map(nullOrElse(v -> new Password(assertType(v, String.class)))).toArray(Password[]::new);\n                break;\n            case SHORT:\n                result = ((List<?>) propertyValue).stream().map(nullOrElse(v -> ((Number) v).shortValue()))\n                        .toArray(Short[]::new);\n                break;\n            case STRING:\n                result = ((List<?>) propertyValue).stream().map(nullOrElse(v -> assertType(v, String.class)))\n                        .toArray(String[]::new);\n                break;\n            default:\n                return Optional.empty();\n            }\n\n            return Optional.of(result);\n        } catch (ClassCastException e) {\n            return Optional.empty();\n        }\n    }\n\n    public static Optional<Scalar> scalarFromSingletonClass(final Class<?> clazz) {\n        final Scalar result;\n\n        if (clazz == Boolean.class) {\n            result = Scalar.BOOLEAN;\n        } else if (clazz == Byte.class) {\n            result = Scalar.BYTE;\n        } else if (clazz == Character.class) {\n            result = Scalar.CHAR;\n        } else if (clazz == Double.class) {\n            result = Scalar.DOUBLE;\n        } else if (clazz == Float.class) {\n            result = Scalar.FLOAT;\n        } else if (clazz == Integer.class) {\n            result = Scalar.INTEGER;\n        } else if (clazz == Long.class) {\n            result = Scalar.LONG;\n        } else if (clazz == Password.class) {\n            result = Scalar.PASSWORD;\n        } else if (clazz == Short.class) {\n            result = Scalar.SHORT;\n        } else if (clazz == String.class) {\n            result = Scalar.STRING;\n        } else {\n            return Optional.empty();\n        }\n\n        return Optional.of(result);\n    }\n\n    private static Object configurationPropertyToDTOProperty(final Object property) {\n        if (property instanceof Password) {\n            return new String(((Password) property).getPassword());\n        } else if (property instanceof Password[]) {\n            return Arrays.stream((Password[]) property).map(p -> p == null ? null : new String(p.getPassword()))\n                    .toArray(String[]::new);\n        } else {\n            return property;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/SnapshotId.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\npublic class SnapshotId implements Validable {\n\n    private final Long id;\n\n    public SnapshotId(long id) {\n        this.id = id;\n    }\n\n    public long getId() {\n        return id;\n    }\n\n    @Override\n    public void validate() {\n        FailureHandler.requireParameter(id, \"id\");\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/SnapshotIdSet.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.Set;\n\npublic class SnapshotIdSet {\n\n    private final Set<Long> ids;\n\n    public SnapshotIdSet(Set<Long> ids) {\n        this.ids = ids;\n    }\n\n    public Set<Long> getIds() {\n        return ids;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/SubtaskFailure.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\npublic class SubtaskFailure {\n\n    private final String id;\n    private final String message;\n\n    public SubtaskFailure(final String id, final String message) {\n        this.id = id;\n        this.message = message;\n    }\n\n    public String getId() {\n        return id;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/SubtaskFailureList.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.List;\n\npublic class SubtaskFailureList {\n\n    private final List<SubtaskFailure> failures;\n\n    public SubtaskFailureList(List<SubtaskFailure> failures) {\n        this.failures = failures;\n    }\n\n    public List<SubtaskFailure> getFailures() {\n        return failures;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/UpdateComponentConfigurationRequest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\nimport java.util.List;\n\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\n\npublic class UpdateComponentConfigurationRequest implements Validable {\n\n    private final List<ComponentConfigurationDTO> configs;\n    private Boolean takeSnapshot;\n\n    public UpdateComponentConfigurationRequest(List<ComponentConfigurationDTO> componentConfigurations,\n            boolean takeSnapshot) {\n        this.configs = componentConfigurations;\n        this.takeSnapshot = takeSnapshot;\n    }\n\n    public List<ComponentConfigurationDTO> getComponentConfigurations() {\n        return this.configs;\n    }\n\n    public boolean isTakeSnapshot() {\n        return this.takeSnapshot == null || this.takeSnapshot;\n    }\n\n    @Override\n    public void validate() {\n        FailureHandler.requireParameter(this.configs, \"configs\");\n\n        for (final ComponentConfigurationDTO config : this.configs) {\n            if (config == null) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                        \"component configuration objects cannot be null\");\n            }\n\n            config.validate();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.configuration.provider/src/main/java/org/eclipse/kura/rest/configuration/api/Validable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.configuration.api;\n\npublic interface Validable {\n\n    public void validate();\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Identity REST Service\nBundle-SymbolicName: org.eclipse.kura.rest.identity.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nImport-Package: jakarta.annotation.security;version=\"2.1.1\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.apache.commons.lang3;version=\"3.12.0\",\n org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.core.configuration;version=\"[2.0,3.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.identity;version=\"[1.1,2.0)\",\n org.eclipse.kura.request.handler.jaxrs;version=\"[2.0,3.0)\",\n org.eclipse.kura.request.handler.jaxrs.annotation;version=\"[1.0,2.0)\",\n org.eclipse.kura.rest.configuration.api;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.useradmin;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.validation;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.component;version=\"[1.3,2.0)\",\n org.osgi.service.useradmin;version=\"1.1.0\";resolution:=optional,\n org.slf4j;version=\"1.7.25\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/build.properties",
    "content": "#\n#  Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\nadditional.bundles = org.osgi.service.component.annotations,\\\n                     org.osgi.service.metatype.annotations"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <artifactId>org.eclipse.kura.rest.identity.provider</artifactId>\n    <packaging>eclipse-plugin</packaging>\n    <version>2.0.0-SNAPSHOT</version>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>biz.aQute.bnd</groupId>\n                <artifactId>bnd-maven-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/IdentityRestServiceV1.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.internal.rest.identity.provider.dto.PermissionDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.dto.UserConfigDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.dto.UserDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.dto.ValidatorOptionsDTO;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.eclipse.kura.request.handler.jaxrs.JaxRsRequestHandlerProxy;\nimport org.eclipse.kura.util.validation.ValidatorOptions;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.Reference;\nimport org.osgi.service.component.annotations.ReferenceCardinality;\nimport org.osgi.service.component.annotations.ReferencePolicy;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.DELETE;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.PUT;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.core.Response.Status;\n\n@SuppressWarnings(\"restriction\")\n@Path(\"identity/v1\")\n@Component(immediate = true, property = {\n        \"kura.service.pid=org.eclipse.kura.internal.rest.identity.provider.IdentityRestServiceV1\",\n        \"osgi.jakartars.resource=true\" }, service = IdentityRestServiceV1.class)\npublic class IdentityRestServiceV1 {\n\n    private static final Logger logger = LoggerFactory.getLogger(IdentityRestServiceV1.class);\n\n    private static final String MQTT_APP_ID = \"IDN-V1\";\n\n    private static final String DEBUG_MESSAGE = \"Processing request for method '{}'\";\n\n    private static final String REST_ROLE_NAME = \"identity\";\n    private static final String KURA_PERMISSION_REST_ROLE = \"kura.permission.rest.\" + REST_ROLE_NAME;\n\n    private final RequestHandler requestHandler = new JaxRsRequestHandlerProxy(this);\n\n    private LegacyIdentityService legacyIdentityService;\n\n    private CryptoService cryptoService;\n    private UserAdmin userAdmin;\n    private PasswordStrengthVerificationService passwordStrengthVerificationService;\n\n    @Reference\n    public void bindCryptoService(CryptoService cryptoService) {\n        this.cryptoService = cryptoService;\n    }\n\n    @Reference\n    public void bindPasswordStrengthVerificationService(\n            PasswordStrengthVerificationService passwordStrengthVerificationService) {\n        this.passwordStrengthVerificationService = passwordStrengthVerificationService;\n    }\n\n    @Reference\n    public void bindUserAdmin(UserAdmin userAdmin) {\n        this.userAdmin = userAdmin;\n        this.userAdmin.createRole(KURA_PERMISSION_REST_ROLE, Role.GROUP);\n    }\n\n    @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.MULTIPLE)\n    public void bindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.registerRequestHandler(MQTT_APP_ID, this.requestHandler);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to register {} request handler\", MQTT_APP_ID, e);\n        }\n    }\n\n    public void unbindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.unregister(MQTT_APP_ID);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to unregister {} request handler\", MQTT_APP_ID, e);\n        }\n    }\n\n    // Added mainly for testing purposes. Currently the service is created by activate()\n    @Reference(cardinality = ReferenceCardinality.OPTIONAL)\n    public void bindLegacyIdentityService(LegacyIdentityService legacyIdentityService) {\n        this.legacyIdentityService = legacyIdentityService;\n    }\n\n    @Activate\n    public void activate() {\n        // create only if not externally set. Added mainly for testing purposes.\n        if (this.legacyIdentityService == null) {\n            this.legacyIdentityService = new LegacyIdentityService(this.cryptoService, this.userAdmin,\n                    this.passwordStrengthVerificationService);\n        }\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response createUser(final UserDTO userName) {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"createUser\");\n            this.legacyIdentityService.createUser(userName);\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @PUT\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response updateUser(final UserDTO user) {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"updateUser\");\n            this.legacyIdentityService.updateUser(user);\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities/byName\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    @Produces(MediaType.APPLICATION_JSON)\n    public UserDTO getUser(final UserDTO userName) {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"getUser\");\n            return this.legacyIdentityService.getUser(userName.getUserName());\n        } catch (KuraException e) {\n            if (e.getCode().equals(KuraErrorCode.NOT_FOUND)) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.NOT_FOUND, \"Identity does not exist\");\n            } else {\n                throw DefaultExceptionHandler.toWebApplicationException(e);\n            }\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n    }\n\n    @DELETE\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response deleteUser(final UserDTO userName) {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"deleteUser\");\n            this.legacyIdentityService.deleteUser(userName.getUserName());\n        } catch (KuraException e) {\n            if (e.getCode().equals(KuraErrorCode.NOT_FOUND)) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.NOT_FOUND, \"Identity does not exist\");\n            } else {\n                throw DefaultExceptionHandler.toWebApplicationException(e);\n            }\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @GET\n    @Path(\"/definedPermissions\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public PermissionDTO getDefinedPermissions() {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"getDefinedPermissions\");\n            return new PermissionDTO(this.legacyIdentityService.getDefinedPermissions());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @GET\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public UserConfigDTO getUserConfig() {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"getUserConfig\");\n            UserConfigDTO userConfig = new UserConfigDTO();\n            userConfig.setUserConfig(this.legacyIdentityService.getUserConfig());\n            return userConfig;\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @GET\n    @Path(\"/passwordRequirements\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public ValidatorOptionsDTO getValidatorOptions() {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"getValidatorOptions\");\n            ValidatorOptions validatorOptions = this.legacyIdentityService.getValidatorOptions();\n            return new ValidatorOptionsDTO(//\n                    validatorOptions.isPasswordMinimumLength(), //\n                    validatorOptions.isPasswordRequireDigits(), //\n                    validatorOptions.isPasswordRequireBothCases(), //\n                    validatorOptions.isPasswordRequireSpecialChars());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/IdentityRestServiceV2.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.internal.rest.identity.provider;\n\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.identity.AdditionalConfigurations;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityConfigurationComponent;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.internal.rest.identity.provider.util.IdentityDTOUtils;\nimport org.eclipse.kura.internal.rest.identity.provider.util.StringUtils;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.IdentityConfigurationDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.IdentityConfigurationRequestDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.IdentityDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.PasswordStrenghtRequirementsDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.PermissionDTO;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.eclipse.kura.request.handler.jaxrs.JaxRsRequestHandlerProxy;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.Reference;\nimport org.osgi.service.component.annotations.ReferenceCardinality;\nimport org.osgi.service.component.annotations.ReferencePolicy;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.DELETE;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.PUT;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.WebApplicationException;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.core.Response.Status;\n\n@Path(\"identity/v2\")\n@Component(immediate = true, property = {\n        \"kura.service.pid=org.eclipse.kura.internal.rest.identity.provider.IdentityRestServiceV2\",\n        \"osgi.jakartars.resource=true\" }, service = IdentityRestServiceV2.class)\npublic class IdentityRestServiceV2 {\n\n    private static final String NAME_REQUEST_FIELD = \"name\";\n\n    private static final Logger logger = LoggerFactory.getLogger(IdentityRestServiceV2.class);\n\n    private static final String MQTT_APP_ID = \"IDN-V2\";\n\n    private static final String DEBUG_MESSAGE = \"Processing request for method '{}'\";\n\n    private static final String REST_ROLE_NAME = \"identity\";\n    private static final String KURA_PERMISSION_REST_ROLE = \"kura.permission.rest.\" + REST_ROLE_NAME;\n\n    private final RequestHandler requestHandler = new JaxRsRequestHandlerProxy(this);\n\n    private IdentityService identityService;\n    private PasswordStrengthVerificationService passwordStrengthVerificationService;\n\n    @Reference\n    public void bindUserAdmin(UserAdmin userAdmin) {\n        userAdmin.createRole(KURA_PERMISSION_REST_ROLE, Role.GROUP);\n    }\n\n    @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.MULTIPLE)\n    public void bindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.registerRequestHandler(MQTT_APP_ID, this.requestHandler);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to register {} request handler\", MQTT_APP_ID, e);\n        }\n    }\n\n    public void unbindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.unregister(MQTT_APP_ID);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to unregister {} request handler\", MQTT_APP_ID, e);\n        }\n    }\n\n    @Reference\n    public void bindIdentityService(IdentityService identityService) {\n        this.identityService = identityService;\n    }\n\n    @Reference\n    public void bindPasswordStrengthVerificationService(\n            PasswordStrengthVerificationService passwordStrengthVerificationService) {\n        this.passwordStrengthVerificationService = passwordStrengthVerificationService;\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response createIdentity(final IdentityDTO identity) {\n        logger.debug(DEBUG_MESSAGE, \"createIdentity\");\n\n        try {\n\n            StringUtils.validateField(NAME_REQUEST_FIELD, identity.getName());\n\n            boolean created = this.identityService\n                    .createIdentity(new IdentityConfiguration(identity.getName(), List.of()));\n            if (!created) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.CONFLICT, \"Identity already exists\");\n            }\n        } catch (Exception e) {\n            throw toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @PUT\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response updateIdentity(final IdentityConfigurationDTO identityConfigurationDTO) {\n        logger.debug(DEBUG_MESSAGE, \"updateIdentity\");\n        try {\n\n            StringUtils.validateField(NAME_REQUEST_FIELD, identityConfigurationDTO.getIdentity().getName());\n\n            this.identityService\n                    .updateIdentityConfiguration(IdentityDTOUtils.toIdentityConfiguration(identityConfigurationDTO));\n        } catch (Exception e) {\n            throw toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities/byName\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    @Produces(MediaType.APPLICATION_JSON)\n    public IdentityConfigurationDTO getIdentityByName(\n            final IdentityConfigurationRequestDTO identityConfigurationRequestDTO) {\n        logger.debug(DEBUG_MESSAGE, \"getIdentityByName\");\n        try {\n\n            StringUtils.validateField(NAME_REQUEST_FIELD, identityConfigurationRequestDTO.getIdentity().getName());\n\n            String identityName = identityConfigurationRequestDTO.getIdentity().getName();\n\n            Optional<IdentityConfiguration> identityConfiguration = this.identityService.getIdentityConfiguration(\n                    identityName, //\n                    IdentityDTOUtils.toIdentityConfigurationComponents(\n                            identityConfigurationRequestDTO.getConfigurationComponents()));\n            if (!identityConfiguration.isPresent()) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.NOT_FOUND, \"Identity does not exist\");\n            }\n\n            return IdentityDTOUtils.fromIdentityConfiguration(identityConfiguration.get());\n        } catch (Exception e) {\n            throw toWebApplicationException(e);\n        }\n\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities/default/byName\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    @Produces(MediaType.APPLICATION_JSON)\n    public IdentityConfigurationDTO getIdentityDefaultByName(\n            final IdentityConfigurationRequestDTO identityConfigurationRequestDTO) {\n        logger.debug(DEBUG_MESSAGE, \"getIdentityDefaultByName\");\n\n        String identityName = identityConfigurationRequestDTO.getIdentity().getName();\n\n        try {\n\n            StringUtils.validateField(NAME_REQUEST_FIELD, identityName);\n\n            IdentityConfiguration identityConfiguration = this.identityService.getIdentityDefaultConfiguration(\n                    identityName, //\n                    IdentityDTOUtils.toIdentityConfigurationComponents(\n                            identityConfigurationRequestDTO.getConfigurationComponents()));\n\n            return IdentityDTOUtils.fromIdentityConfiguration(identityConfiguration);\n        } catch (KuraException e) {\n            throw toWebApplicationException(e);\n        }\n\n    }\n\n    @DELETE\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response deleteIdentity(final IdentityDTO identity) {\n        logger.debug(DEBUG_MESSAGE, \"deleteIdentity\");\n        try {\n\n            StringUtils.validateField(NAME_REQUEST_FIELD, identity.getName());\n\n            boolean deleted = this.identityService.deleteIdentity(identity.getName());\n            if (!deleted) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.NOT_FOUND, \"Identity not found\");\n            }\n        } catch (Exception e) {\n            throw toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @GET\n    @Path(\"/definedPermissions\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public Set<PermissionDTO> getDefinedPermissions() {\n        logger.debug(DEBUG_MESSAGE, \"getDefinedPermissions\");\n        try {\n            return this.identityService.getPermissions().stream().map(IdentityDTOUtils::fromPermission)\n                    .collect(Collectors.toSet());\n        } catch (Exception e) {\n            throw toWebApplicationException(e);\n        }\n    }\n\n    @GET\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public List<IdentityConfigurationDTO> getIdentities() {\n        logger.debug(DEBUG_MESSAGE, \"getIdentities\");\n        try {\n            return this.identityService.getIdentitiesConfiguration(allIdentitiesConfiguration()).stream()\n                    .map(IdentityDTOUtils::fromIdentityConfiguration).collect(Collectors.toList());\n\n        } catch (Exception e) {\n            throw toWebApplicationException(e);\n        }\n    }\n\n    @GET\n    @Path(\"/passwordStrenghtRequirements\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public PasswordStrenghtRequirementsDTO getPasswordStrenghtRequirements() {\n        logger.debug(DEBUG_MESSAGE, \"getPasswordStrenghtRequirements\");\n        try {\n            return IdentityDTOUtils.fromPasswordStrengthRequirements(\n                    this.passwordStrengthVerificationService.getPasswordStrengthRequirements());\n        } catch (Exception e) {\n            throw toWebApplicationException(e);\n        }\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/permissions\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response createPermission(final PermissionDTO permissionDTO) {\n        logger.debug(DEBUG_MESSAGE, \"createPermission\");\n\n        try {\n\n            StringUtils.validateField(NAME_REQUEST_FIELD, permissionDTO.getName());\n\n            boolean created = this.identityService.createPermission(IdentityDTOUtils.toPermission(permissionDTO));\n            if (!created) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.CONFLICT,\n                        \"Permission already exists\");\n            }\n        } catch (KuraException e) {\n            throw toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @DELETE\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/permissions\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response deletePermission(final PermissionDTO permissionDTO) {\n        logger.debug(DEBUG_MESSAGE, \"deletePermission\");\n\n        StringUtils.validateField(NAME_REQUEST_FIELD, permissionDTO.getName());\n\n        boolean deleted = false;\n        try {\n            deleted = this.identityService.deletePermission(IdentityDTOUtils.toPermission(permissionDTO));\n            if (!deleted) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.NOT_FOUND, \"Permission not found\");\n            }\n\n        } catch (KuraException e) {\n            throw toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/identities/validate\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response validateIdentityConfiguration(final IdentityConfigurationDTO identityConfigurationDTO) {\n        try {\n\n            StringUtils.validateField(NAME_REQUEST_FIELD, identityConfigurationDTO.getIdentity().getName());\n\n            this.identityService\n                    .validateIdentityConfiguration(IdentityDTOUtils.toIdentityConfiguration(identityConfigurationDTO));\n        } catch (KuraException e) {\n            throw toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    private static Set<Class<? extends IdentityConfigurationComponent>> allIdentitiesConfiguration() {\n        return new HashSet<>(\n                Arrays.asList(AdditionalConfigurations.class, AssignedPermissions.class, PasswordConfiguration.class));\n    }\n\n    private WebApplicationException toWebApplicationException(final Exception e) {\n        if (e instanceof KuraException && ((KuraException) e).getCode() == KuraErrorCode.INVALID_PARAMETER) {\n            return DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST, e.getMessage());\n        } else {\n            return DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/LegacyIdentityService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.identity.PasswordStrengthRequirements;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.internal.rest.identity.provider.dto.UserDTO;\nimport org.eclipse.kura.util.useradmin.UserAdminHelper;\nimport org.eclipse.kura.util.useradmin.UserAdminHelper.FallibleConsumer;\nimport org.eclipse.kura.util.validation.PasswordStrengthValidators;\nimport org.eclipse.kura.util.validation.Validator;\nimport org.eclipse.kura.util.validation.ValidatorOptions;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\n\n@SuppressWarnings(\"restriction\")\npublic class LegacyIdentityService {\n\n    private static final String IDENTITY = \"Identity \";\n    private static final String PERMISSION_ROLE_NAME_PREFIX = \"kura.permission.\";\n    private static final String USER_ROLE_NAME_PREFIX = \"kura.user.\";\n\n    private static final String KURA_NEED_PASSWORD_CHANGE_PROPERTY = \"kura.need.password.change\";\n    private static final String PASSWORD_PROPERTY = \"kura.password\";\n\n    private final UserAdminHelper userAdminHelper;\n    private final PasswordStrengthVerificationService passwordStrengthVerificationService;\n    private final CryptoService cryptoService;\n\n    public LegacyIdentityService(CryptoService cryptoService, UserAdmin userAdmin,\n            PasswordStrengthVerificationService passwordStrengthVerificationService) {\n\n        this.passwordStrengthVerificationService = passwordStrengthVerificationService;\n        this.cryptoService = cryptoService;\n\n        this.userAdminHelper = new UserAdminHelper(userAdmin, cryptoService);\n    }\n\n    public void createUser(UserDTO user) throws KuraException {\n        if (!this.userAdminHelper.getUser(user.getUserName()).isPresent()) {\n\n            final String password = user.getPassword();\n            if (password != null) {\n                validateUserPassword(password);\n            }\n\n            this.userAdminHelper.createUser(user.getUserName());\n            updateUser(user);\n        } else {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, IDENTITY + user.getUserName() + \" already exists\");\n        }\n    }\n\n    public void deleteUser(String userName) throws KuraException {\n\n        if (this.userAdminHelper.getUser(userName).isPresent()) {\n            this.userAdminHelper.deleteUser(userName);\n        } else {\n            throw new KuraException(KuraErrorCode.NOT_FOUND, \"Identity does not exist\");\n        }\n\n    }\n\n    public UserDTO getUser(String userName) throws KuraException {\n        Optional<User> user = this.userAdminHelper.getUser(userName);\n        if (user.isPresent()) {\n            UserDTO userFound = initUserConfig(user.get());\n            fillPermissions(Collections.singletonMap(user.get().getName(), userFound));\n            return userFound;\n        } else {\n            throw new KuraException(KuraErrorCode.NOT_FOUND, \"Identity does not exist\");\n        }\n    }\n\n    public Set<String> getDefinedPermissions() {\n        return this.userAdminHelper.getDefinedPermissions();\n    }\n\n    public Set<UserDTO> getUserConfig() {\n        final Map<String, UserDTO> result = new HashMap<>();\n\n        this.userAdminHelper.foreachUser((name, user) -> {\n\n            final UserDTO userData = initUserConfig(user);\n\n            result.put(user.getName(), userData);\n        });\n\n        fillPermissions(result);\n\n        return new HashSet<>(result.values());\n    }\n\n    private UserDTO initUserConfig(final User user) {\n\n        final boolean isPasswordEnabled = user.getCredentials().get(PASSWORD_PROPERTY) instanceof String;\n        final boolean isPasswordChangeRequired = Objects.equals(\"true\",\n                user.getProperties().get(KURA_NEED_PASSWORD_CHANGE_PROPERTY));\n\n        return new UserDTO(getBaseName(user), new HashSet<>(), isPasswordEnabled, isPasswordChangeRequired);\n    }\n\n    private static boolean isKuraUser(final Role role) {\n        return role.getName().startsWith(USER_ROLE_NAME_PREFIX);\n    }\n\n    private static boolean isKuraPermission(final Role role) {\n        return role.getName().startsWith(PERMISSION_ROLE_NAME_PREFIX);\n    }\n\n    private static String getBaseName(final Role role) {\n        final String name = role.getName();\n\n        if (isKuraUser(role)) {\n            return name.substring(USER_ROLE_NAME_PREFIX.length());\n        } else if (isKuraPermission(role)) {\n            return name.substring(PERMISSION_ROLE_NAME_PREFIX.length());\n        } else {\n            throw new IllegalArgumentException(\"not a Kura role\");\n        }\n    }\n\n    private void fillPermissions(final Map<String, ? extends UserDTO> userData) {\n        this.userAdminHelper.foreachPermission((permission, group) ->\n\n        forEach(group.getMembers(), member -> {\n            final UserDTO data = userData.get(member.getName());\n\n            if (data != null) {\n                data.getPermissions().add(permission);\n            }\n        }));\n    }\n\n    private static <T, E extends Exception> void forEach(final T[] items, final FallibleConsumer<T, E> consumer)\n            throws E {\n        if (items != null) {\n            for (final T item : items) {\n                consumer.accept(item);\n            }\n        }\n    }\n\n    public void updateUser(UserDTO userDTOToUpdate) throws KuraException {\n\n        final Optional<User> user = this.userAdminHelper.getUser(userDTOToUpdate.getUserName());\n\n        if (user.isPresent()) {\n            final Set<String> permissions = userDTOToUpdate.getPermissions();\n\n            if (permissions != null) {\n\n                this.userAdminHelper.foreachPermission((permissionName, permissionGroup) -> {\n\n                    if (permissions.contains(permissionName)) {\n                        permissionGroup.addMember(user.get());\n                    } else {\n                        permissionGroup.removeMember(user.get());\n                    }\n                });\n\n            }\n\n            updatePasswordOptions(userDTOToUpdate, user.get().getCredentials(), user.get().getProperties());\n        } else {\n            throw new KuraException(KuraErrorCode.NOT_FOUND, IDENTITY + userDTOToUpdate.getUserName() + \" not found\");\n        }\n\n    }\n\n    private void updatePasswordOptions(UserDTO userDTO, final Dictionary<String, Object> credentials,\n            final Dictionary<String, Object> properties) throws KuraException {\n\n        final Optional<Boolean> isPasswordAuthEnabledParam = userDTO.isPasswordAuthEnabled();\n\n        if (isPasswordAuthEnabledParam.isPresent()) {\n\n            if (Boolean.TRUE.equals(isPasswordAuthEnabledParam.get())) {\n                final String password = userDTO.getPassword();\n\n                if (password != null) {\n                    validateUserPassword(password);\n                    try {\n                        credentials.put(PASSWORD_PROPERTY, this.cryptoService.sha256Hash(password));\n                    } catch (final Exception e) {\n                        throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, e);\n                    }\n                }\n            } else {\n                credentials.remove(PASSWORD_PROPERTY);\n            }\n        }\n\n        final Optional<Boolean> isPasswordChangeNeededParam = userDTO.isPasswordChangeNeeded();\n\n        if (isPasswordChangeNeededParam.isPresent()) {\n\n            if (Boolean.TRUE.equals(isPasswordChangeNeededParam.get())) {\n                properties.put(KURA_NEED_PASSWORD_CHANGE_PROPERTY, \"true\");\n            } else {\n                properties.remove(KURA_NEED_PASSWORD_CHANGE_PROPERTY);\n            }\n\n        }\n\n    }\n\n    public void validateUserPassword(String password) throws KuraException {\n\n        ValidatorOptions validatorOptions = getValidatorOptions();\n\n        final List<Validator<String>> validators = PasswordStrengthValidators.fromConfig(validatorOptions);\n\n        final List<String> errors = new ArrayList<>();\n\n        for (final Validator<String> validator : validators) {\n            validator.validate(password, errors::add);\n        }\n\n        if (!errors.isEmpty()) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"password strenght requirements not satisfied\", errors);\n        }\n    }\n\n    public ValidatorOptions getValidatorOptions() throws KuraException {\n\n        final PasswordStrengthRequirements requirements = this.passwordStrengthVerificationService\n                .getPasswordStrengthRequirements();\n\n        return new ValidatorOptions(requirements.getPasswordMinimumLength(), requirements.digitsRequired(),\n                requirements.bothCasesRequired(), requirements.specialCharactersRequired());\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/dto/PermissionDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.dto;\n\nimport java.util.Set;\n\npublic class PermissionDTO {\n\n    private final Set<String> permissions;\n\n    public PermissionDTO(Set<String> permissions) {\n        this.permissions = permissions;\n    }\n\n    public Set<String> getPermissions() {\n        return this.permissions;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/dto/UserConfigDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.dto;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class UserConfigDTO {\n\n    private Set<UserDTO> userConfig = new HashSet<>();\n\n    public Set<UserDTO> getUserConfig() {\n        return this.userConfig;\n    }\n\n    public void setUserConfig(Set<UserDTO> userConfig) {\n        this.userConfig = userConfig;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/dto/UserDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.dto;\n\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\n\npublic class UserDTO {\n\n    private String userName;\n    private Boolean passwordAuthEnabled;\n    private Boolean passwordChangeNeeded;\n    private Set<String> permissions;\n    private String password;\n\n    public UserDTO() {\n\n    }\n\n    public UserDTO(final String userName, final Set<String> permissions, final boolean passwordAuthEnabled,\n            final boolean passwordChangeNeeded, final String password) {\n\n        this.userName = userName;\n        this.passwordAuthEnabled = passwordAuthEnabled;\n        this.passwordChangeNeeded = passwordChangeNeeded;\n        this.permissions = permissions;\n        this.password = password;\n    }\n\n    public UserDTO(final String userName, final Set<String> permissions, final boolean passwordAuthEnabled,\n            final boolean passwordChangeNeeded) {\n\n        this(userName, permissions, passwordAuthEnabled, passwordChangeNeeded, null);\n\n    }\n\n    public String getUserName() {\n        return this.userName;\n    }\n\n    public void setUserName(String userName) {\n        this.userName = userName;\n    }\n\n    public Optional<Boolean> isPasswordAuthEnabled() {\n        return Optional.ofNullable(this.passwordAuthEnabled);\n    }\n\n    public void setPasswordAuthEnabled(boolean passwordAuthEnabled) {\n        this.passwordAuthEnabled = passwordAuthEnabled;\n    }\n\n    public Optional<Boolean> isPasswordChangeNeeded() {\n        return Optional.ofNullable(this.passwordChangeNeeded);\n    }\n\n    public void setPasswordChangeNeeded(boolean passwordChangeNeeded) {\n        this.passwordChangeNeeded = passwordChangeNeeded;\n    }\n\n    public Set<String> getPermissions() {\n        return this.permissions;\n    }\n\n    public void setPermissions(Set<String> permissions) {\n        this.permissions = permissions;\n    }\n\n    public String getPassword() {\n        return this.password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.userName);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null || getClass() != obj.getClass()) {\n            return false;\n        }\n        UserDTO other = (UserDTO) obj;\n        return Objects.equals(this.userName, other.userName);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/dto/ValidatorOptionsDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.dto;\n\npublic class ValidatorOptionsDTO {\n\n    private final int passwordMinimumLength;\n    private final boolean passwordRequireDigits;\n    private final boolean passwordRequireSpecialChars;\n    private final boolean passwordRequireBothCases;\n\n    public ValidatorOptionsDTO(int passwordMinimumLength, boolean passwordRequireDigits,\n            boolean passwordRequireBothCases, boolean passwordRequireSpecialChars) {\n\n        this.passwordMinimumLength = passwordMinimumLength;\n        this.passwordRequireDigits = passwordRequireDigits;\n        this.passwordRequireSpecialChars = passwordRequireSpecialChars;\n        this.passwordRequireBothCases = passwordRequireBothCases;\n    }\n\n    public int getPasswordMinimumLength() {\n        return this.passwordMinimumLength;\n    }\n\n    public boolean isPasswordRequireDigits() {\n        return this.passwordRequireDigits;\n    }\n\n    public boolean isPasswordRequireSpecialChars() {\n        return this.passwordRequireSpecialChars;\n    }\n\n    public boolean isPasswordRequireBothCases() {\n        return this.passwordRequireBothCases;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/util/IdentityDTOUtils.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.util;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.core.configuration.ComponentConfigurationImpl;\nimport org.eclipse.kura.identity.AdditionalConfigurations;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityConfigurationComponent;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.PasswordStrengthRequirements;\nimport org.eclipse.kura.identity.Permission;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.AdditionalConfigurationsDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.IdentityConfigurationDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.IdentityDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.PasswordConfigurationDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.PasswordStrenghtRequirementsDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.PermissionConfigurationDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.PermissionDTO;\nimport org.eclipse.kura.rest.configuration.api.ComponentConfigurationDTO;\nimport org.eclipse.kura.rest.configuration.api.DTOUtil;\n\npublic class IdentityDTOUtils {\n\n    private IdentityDTOUtils() {\n        throw new IllegalStateException(\"Utility class\");\n    }\n\n    public static Set<Class<? extends IdentityConfigurationComponent>> toIdentityConfigurationComponents(\n            Set<String> componentNames) {\n\n        return componentNames.stream().map(name -> {\n\n            switch (name) {\n            case \"AdditionalConfigurations\":\n                return AdditionalConfigurations.class;\n            case \"AssignedPermissions\":\n                return AssignedPermissions.class;\n            case \"PasswordConfiguration\":\n                return PasswordConfiguration.class;\n            default:\n                throw new IllegalArgumentException(\"Unknown component name: \" + name);\n            }\n\n        }).collect(Collectors.toSet());\n\n    }\n\n    public static IdentityConfigurationDTO fromIdentityConfiguration(IdentityConfiguration identityConfiguration) {\n\n        IdentityConfigurationDTO identityConfigurationDTO = new IdentityConfigurationDTO(\n                new IdentityDTO(identityConfiguration.getName()));\n\n        identityConfiguration.getComponent(AdditionalConfigurations.class)\n                .ifPresent(additionalConfigurations -> identityConfigurationDTO\n                        .setAdditionalConfigurations(fromAdditionalConfigurations(additionalConfigurations)));\n\n        identityConfiguration.getComponent(AssignedPermissions.class)\n                .ifPresent(assignedPermissions -> identityConfigurationDTO\n                        .setPermissionConfiguration(fromPermissionConfiguration(assignedPermissions)));\n\n        identityConfiguration.getComponent(PasswordConfiguration.class)\n                .ifPresent(passwordConfiguration -> identityConfigurationDTO\n                        .setPasswordConfiguration(fromPasswordConfiguration(passwordConfiguration)));\n\n        return identityConfigurationDTO;\n    }\n\n    public static ComponentConfigurationDTO fromComponentConfiguration(ComponentConfiguration componentConfiguration) {\n        return new ComponentConfigurationDTO(componentConfiguration.getPid(), null, DTOUtil\n                .configurationPropertiesToDtos(componentConfiguration.getConfigurationProperties(), null, false));\n    }\n\n    public static Permission toPermission(PermissionDTO permissionDTO) {\n        return new Permission(permissionDTO.getName());\n    }\n\n    public static PermissionDTO fromPermission(Permission permission) {\n        return new PermissionDTO(permission.getName());\n    }\n\n    public static ComponentConfiguration toComponentConfiguration(ComponentConfigurationDTO componentConfigurationDTO) {\n\n        ComponentConfigurationImpl componentConfiguration = new ComponentConfigurationImpl();\n        componentConfiguration.setPid(componentConfigurationDTO.getPid());\n        componentConfiguration\n                .setProperties(DTOUtil.dtosToConfigurationProperties(componentConfigurationDTO.getProperties()));\n\n        return componentConfiguration;\n    }\n\n    public static IdentityConfigurationComponent toPermissionConfiguration(\n            PermissionConfigurationDTO permissionConfigurationDTO) {\n        return new AssignedPermissions(permissionConfigurationDTO.getPermissions().stream() //\n                .map(IdentityDTOUtils::toPermission) //\n                .collect(Collectors.toSet()) //\n        );\n    }\n\n    public static PermissionConfigurationDTO fromPermissionConfiguration(AssignedPermissions assignedPermissions) {\n        PermissionConfigurationDTO permissionsConfigurationDTO = new PermissionConfigurationDTO();\n        permissionsConfigurationDTO.setPermissions(assignedPermissions.getPermissions().stream()\n                .map(IdentityDTOUtils::fromPermission).collect(Collectors.toSet()));\n\n        return permissionsConfigurationDTO;\n    }\n\n    public static PasswordConfigurationDTO fromPasswordConfiguration(PasswordConfiguration passwordConfiguration) {\n        PasswordConfigurationDTO passwordConfigurationDTO = new PasswordConfigurationDTO();\n\n        passwordConfigurationDTO.setPasswordChangeNeeded(passwordConfiguration.isPasswordChangeNeeded());\n        passwordConfigurationDTO.setPasswordAuthEnabled(passwordConfiguration.isPasswordAuthEnabled());\n\n        return passwordConfigurationDTO;\n    }\n\n    public static PasswordConfiguration toPasswordConfiguration(PasswordConfigurationDTO passwordConfigurationDTO) {\n\n        Optional<char[]> password = Optional.empty();\n\n        if (passwordConfigurationDTO.getPassword() != null) {\n\n            password = Optional.of(passwordConfigurationDTO.getPassword().toCharArray());\n        }\n\n        return new PasswordConfiguration(passwordConfigurationDTO.isPasswordChangeNeeded(),\n                passwordConfigurationDTO.isPasswordAuthEnabled(), password, Optional.empty());\n    }\n\n    public static IdentityConfigurationComponent toAdditionalConfigurations(\n            AdditionalConfigurationsDTO additionalConfigurationsDTO) {\n\n        List<ComponentConfiguration> configurations = additionalConfigurationsDTO.getConfigurations()//\n                .stream()//\n                .map(IdentityDTOUtils::toComponentConfiguration)//\n                .collect(Collectors.toList());\n\n        return new AdditionalConfigurations(configurations);\n    }\n\n    public static AdditionalConfigurationsDTO fromAdditionalConfigurations(\n            AdditionalConfigurations additionalConfigurations) {\n\n        AdditionalConfigurationsDTO additionalConfigurationsDTO = new AdditionalConfigurationsDTO();\n\n        Set<ComponentConfigurationDTO> configurations = additionalConfigurations.getConfigurations()//\n                .stream()//\n                .map(IdentityDTOUtils::fromComponentConfiguration)//\n                .collect(Collectors.toSet());\n\n        additionalConfigurationsDTO.setConfigurations(configurations);\n\n        return additionalConfigurationsDTO;\n    }\n\n    public static IdentityConfiguration toIdentityConfiguration(IdentityConfigurationDTO identityConfigurationDTO) {\n        List<IdentityConfigurationComponent> components = new ArrayList<>();\n\n        if (identityConfigurationDTO.getPermissionConfiguration() != null) {\n            components.add(toPermissionConfiguration(identityConfigurationDTO.getPermissionConfiguration()));\n        }\n\n        if (identityConfigurationDTO.getPasswordConfiguration() != null) {\n            components.add(toPasswordConfiguration(identityConfigurationDTO.getPasswordConfiguration()));\n        }\n\n        if (identityConfigurationDTO.getAdditionalConfigurations() != null) {\n            components.add(toAdditionalConfigurations(identityConfigurationDTO.getAdditionalConfigurations()));\n        }\n\n        return new IdentityConfiguration(identityConfigurationDTO.getIdentity().getName(), components);\n\n    }\n\n    public static PasswordStrenghtRequirementsDTO fromPasswordStrengthRequirements(\n            PasswordStrengthRequirements passwordStrengthRequirements) {\n\n        return new PasswordStrenghtRequirementsDTO(passwordStrengthRequirements.getPasswordMinimumLength(),\n                passwordStrengthRequirements.digitsRequired(), //\n                passwordStrengthRequirements.specialCharactersRequired(),\n                passwordStrengthRequirements.bothCasesRequired());\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/util/StringUtils.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.util;\n\nimport static java.util.Objects.isNull;\n\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\n\npublic class StringUtils {\n\n    private StringUtils() {\n        throw new IllegalStateException(\"Utility class\");\n    }\n\n    public static void requireNotEmpty(String value, String message) {\n        if (value == null || value.trim().isEmpty()) {\n            throw new IllegalArgumentException(message);\n        }\n    }\n\n    public static void validateField(String propertyName, String inputToValidate) {\n\n        if (isNull(inputToValidate)) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                    \"Missing '\" + propertyName + \"' property\");\n        }\n\n        if (inputToValidate.trim().isEmpty()) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                    \"`\" + propertyName + \"` value can't be empty\");\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/v2/dto/AdditionalConfigurationsDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.v2.dto;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.eclipse.kura.rest.configuration.api.ComponentConfigurationDTO;\n\npublic class AdditionalConfigurationsDTO {\n\n    private Set<ComponentConfigurationDTO> configurations = new HashSet<>();\n\n    public void setConfigurations(Set<ComponentConfigurationDTO> configurations) {\n        this.configurations = configurations;\n    }\n\n    public Set<ComponentConfigurationDTO> getConfigurations() {\n        return this.configurations;\n    }\n\n    @Override\n    public String toString() {\n        return \"AdditionalConfigurationDTO [configurations=\" + this.configurations + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/v2/dto/IdentityConfigurationDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.v2.dto;\n\npublic class IdentityConfigurationDTO {\n\n    private final IdentityDTO identity;\n    private PermissionConfigurationDTO permissionConfiguration;\n    private PasswordConfigurationDTO passwordConfiguration;\n    private AdditionalConfigurationsDTO additionalConfigurations;\n\n    public IdentityConfigurationDTO(IdentityDTO identity) {\n        this.identity = identity;\n    }\n\n    public IdentityDTO getIdentity() {\n        return this.identity;\n    }\n\n    public PermissionConfigurationDTO getPermissionConfiguration() {\n        return this.permissionConfiguration;\n    }\n\n    public void setPermissionConfiguration(PermissionConfigurationDTO permissionConfiguration) {\n        this.permissionConfiguration = permissionConfiguration;\n    }\n\n    public PasswordConfigurationDTO getPasswordConfiguration() {\n        return this.passwordConfiguration;\n    }\n\n    public void setPasswordConfiguration(PasswordConfigurationDTO passwordConfiguration) {\n        this.passwordConfiguration = passwordConfiguration;\n    }\n\n    public AdditionalConfigurationsDTO getAdditionalConfigurations() {\n        return this.additionalConfigurations;\n    }\n\n    public void setAdditionalConfigurations(AdditionalConfigurationsDTO additionalConfiguration) {\n        this.additionalConfigurations = additionalConfiguration;\n    }\n\n    @Override\n    public String toString() {\n        return \"IdentityConfigurationDTO [identity=\" + this.identity + \", permissionConfiguration=\"\n                + this.permissionConfiguration + \", passwordConfiguration=\" + this.passwordConfiguration\n                + \", additionalConfigurations=\" + this.additionalConfigurations + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/v2/dto/IdentityConfigurationRequestDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.v2.dto;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class IdentityConfigurationRequestDTO {\n\n    private IdentityDTO identity;\n    private Set<String> configurationComponents = new HashSet<>();\n\n    public void setIdentity(IdentityDTO identity) {\n        this.identity = identity;\n    }\n\n    public IdentityDTO getIdentity() {\n        return this.identity;\n    }\n\n    public void setConfigurationComponents(Set<String> configurationComponents) {\n        this.configurationComponents = configurationComponents;\n    }\n\n    public Set<String> getConfigurationComponents() {\n        return this.configurationComponents;\n    }\n\n    @Override\n    public String toString() {\n        return \"IdentityConfigurationRequestDTO [identity=\" + this.identity + \", configurationComponents=\"\n                + this.configurationComponents + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/v2/dto/IdentityDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.v2.dto;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.internal.rest.identity.provider.util.StringUtils.requireNotEmpty;\n\npublic class IdentityDTO {\n\n    private final String name;\n\n    public IdentityDTO(String name) {\n        requireNonNull(name, \"name cannot be null\");\n        requireNotEmpty(name, \"name cannot be empty\");\n\n        this.name = name;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    @Override\n    public String toString() {\n        return \"IdentityDTO [name=\" + this.name + \"]\";\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/v2/dto/PasswordConfigurationDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.v2.dto;\n\npublic class PasswordConfigurationDTO {\n\n    private Boolean passwordChangeNeeded;\n    private Boolean passwordAuthEnabled;\n    private String password;\n\n    public Boolean isPasswordChangeNeeded() {\n        return this.passwordChangeNeeded;\n    }\n\n    public void setPasswordChangeNeeded(Boolean passwordChangeNeeded) {\n        this.passwordChangeNeeded = passwordChangeNeeded;\n    }\n\n    public Boolean isPasswordAuthEnabled() {\n        return this.passwordAuthEnabled;\n    }\n\n    public void setPasswordAuthEnabled(Boolean passwordAuthEnabled) {\n        this.passwordAuthEnabled = passwordAuthEnabled;\n    }\n\n    public String getPassword() {\n        return this.password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    @Override\n    public String toString() {\n        return \"PasswordConfigurationDTO [passwordChangeNeeded=\" + this.passwordChangeNeeded + \", passwordAuthEnabled=\"\n                + this.passwordAuthEnabled + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/v2/dto/PasswordStrenghtRequirementsDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.v2.dto;\n\nimport java.util.Objects;\n\npublic class PasswordStrenghtRequirementsDTO {\n\n    private final int passwordMinimumLength;\n    private final Boolean digitsRequired;\n    private final Boolean specialCharactersRequired;\n    private final Boolean bothCasesRequired;\n\n    public PasswordStrenghtRequirementsDTO(int passwordMinimumLength, Boolean digitsRequired,\n            Boolean specialCharactersRequired, Boolean bothCasesRequired) {\n\n        this.passwordMinimumLength = passwordMinimumLength;\n        this.digitsRequired = digitsRequired;\n        this.specialCharactersRequired = specialCharactersRequired;\n        this.bothCasesRequired = bothCasesRequired;\n    }\n\n    public int getPasswordMinimumLength() {\n        return this.passwordMinimumLength;\n    }\n\n    public Boolean isDigitsRequired() {\n        return this.digitsRequired;\n    }\n\n    public Boolean isSpecialCharactersRequired() {\n        return this.specialCharactersRequired;\n    }\n\n    public Boolean isBothCasesRequired() {\n        return this.bothCasesRequired;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(this.bothCasesRequired, this.digitsRequired, this.passwordMinimumLength,\n                this.specialCharactersRequired);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if ((obj == null) || (getClass() != obj.getClass())) {\n            return false;\n        }\n        PasswordStrenghtRequirementsDTO other = (PasswordStrenghtRequirementsDTO) obj;\n        return this.bothCasesRequired == other.bothCasesRequired && this.digitsRequired == other.digitsRequired\n                && this.passwordMinimumLength == other.passwordMinimumLength\n                && this.specialCharactersRequired == other.specialCharactersRequired;\n    }\n\n    @Override\n    public String toString() {\n        return \"PasswordStrenghtRequirementsDTO [passwordMinimumLength=\" + this.passwordMinimumLength\n                + \", digitsRequired=\" + this.digitsRequired + \", specialCharactersRequired=\"\n                + this.specialCharactersRequired + \", bothCasesRequired=\" + this.bothCasesRequired + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/v2/dto/PermissionConfigurationDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.v2.dto;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\npublic class PermissionConfigurationDTO {\n\n    private Set<PermissionDTO> permissions = new HashSet<>();\n\n    public void setPermissions(Set<PermissionDTO> permissions) {\n        this.permissions = permissions;\n    }\n\n    public Set<PermissionDTO> getPermissions() {\n        return this.permissions;\n    }\n\n    @Override\n    public String toString() {\n        return \"PermissionConfigurationDTO [permissions=\" + this.permissions + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.identity.provider/src/main/java/org/eclipse/kura/internal/rest/identity/provider/v2/dto/PermissionDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.v2.dto;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.internal.rest.identity.provider.util.StringUtils.requireNotEmpty;\n\npublic class PermissionDTO {\n\n    private final String name;\n\n    public PermissionDTO(String name) {\n        requireNonNull(name, \"name cannot be null\");\n        requireNotEmpty(name, \"name cannot be empty\");\n\n        this.name = name;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    @Override\n    public String toString() {\n        return \"PermissionDTO [name=\" + this.name + \"]\";\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.rest.inventory.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.inventory.provider\nBundle-SymbolicName: org.eclipse.kura.rest.inventory.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nImport-Package: jakarta.annotation.security;version=\"2.1.1\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.apache.commons.io;version=\"2.4.0\",\n org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.inventory;version=\"[1.1,2.0)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.request.handler.jaxrs;version=\"[2.0,3.0)\",\n org.eclipse.kura.request.handler.jaxrs.annotation;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.component;version=\"1.3.0\",\n org.osgi.service.useradmin;version=\"1.1.0\";resolution:=optional,\n org.slf4j;version=\"1.7.25\"\n \n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.inventory.provider/OSGI-INF/inventory_rest_service.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.internal.rest.inventory.InventoryRestService\" enabled=\"true\" immediate=\"true\">\n   <implementation class=\"org.eclipse.kura.internal.rest.inventory.InventoryRestService\"/>\n   \n   <property name=\"kura.service.pid\" type=\"String\" value=\"org.eclipse.kura.internal.rest.inventory.InventoryRestService\"/>\n   \n   <reference bind=\"setInventoryHandlerV1\" cardinality=\"1..1\" interface=\"org.eclipse.kura.core.inventory.InventoryHandlerV1\" name=\"InventoryHandlerV1\" policy=\"static\"/>\n   <reference bind=\"setUserAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.useradmin.UserAdmin\" name=\"UserAdmin\" policy=\"static\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.internal.rest.inventory.InventoryRestService\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.internal.rest.inventory.InventoryRestService\"/>\n   <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.inventory.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.inventory.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.inventory.provider/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.inventory.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<artifactId>org.eclipse.kura.rest.inventory.provider</artifactId>\n\t<packaging>eclipse-plugin</packaging>\n\t<version>2.0.0-SNAPSHOT</version>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.inventory.provider/src/main/java/org/eclipse/kura/internal/rest/inventory/InventoryRestService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.inventory;\n\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.core.inventory.InventoryHandlerV1;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Path(\"/inventory/v1\")\npublic class InventoryRestService {\n\n    private static final Logger logger = LoggerFactory.getLogger(InventoryRestService.class);\n\n    private static final String KURA_PERMISSION_REST_CONFIGURATION_ROLE = \"kura.permission.rest.inventory\";\n\n    private InventoryHandlerV1 inventoryHandlerV1;\n\n    public void setUserAdmin(UserAdmin userAdmin) {\n        userAdmin.createRole(KURA_PERMISSION_REST_CONFIGURATION_ROLE, Role.GROUP);\n    }\n\n    public void setInventoryHandlerV1(InventoryHandlerV1 inventoryHandlerV1) {\n        this.inventoryHandlerV1 = inventoryHandlerV1;\n\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists all the available inventory items.\n     *\n     */\n    @GET\n    @RolesAllowed(\"inventory\")\n    @Path(\"/inventory\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public Response getInventorySummary() {\n        try {\n            return makeInventoryDoGetRequest(buildKuraMessage(Arrays.asList(InventoryHandlerV1.INVENTORY), \"\"));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists all the available bundles.\n     *\n     */\n    @GET\n    @RolesAllowed(\"inventory\")\n    @Path(\"/bundles\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public Response getBundles() {\n        try {\n            return makeInventoryDoGetRequest(buildKuraMessage(Arrays.asList(InventoryHandlerV1.RESOURCE_BUNDLES), \"\"));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * POST method.\n     *\n     * Start selected bundle.\n     *\n     */\n    @POST\n    @RolesAllowed(\"inventory\")\n    @Path(\"/bundles/_start\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response startBundle(final String bundleJson) {\n        try {\n            return makeInventoryDoExecRequest(buildKuraMessage(InventoryHandlerV1.START_BUNDLE, bundleJson));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * POST method.\n     *\n     * Stop selected bundle.\n     *\n     */\n    @POST\n    @RolesAllowed(\"inventory\")\n    @Path(\"/bundles/_stop\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response stopBundle(final String bundleJson) {\n        try {\n            return makeInventoryDoExecRequest(buildKuraMessage(InventoryHandlerV1.STOP_BUNDLE, bundleJson));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists all the available Deployment Packages.\n     *\n     */\n    @GET\n    @RolesAllowed(\"inventory\")\n    @Path(\"/deploymentPackages\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public Response getDeploymentPackages() {\n        try {\n            return makeInventoryDoGetRequest(\n                    buildKuraMessage(Arrays.asList(InventoryHandlerV1.RESOURCE_DEPLOYMENT_PACKAGES), \"\"));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists all the available System Packages.\n     *\n     */\n    @GET\n    @RolesAllowed(\"inventory\")\n    @Path(\"/systemPackages\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public Response getSystemPackages() {\n        try {\n            return makeInventoryDoGetRequest(\n                    buildKuraMessage(Arrays.asList(InventoryHandlerV1.RESOURCE_SYSTEM_PACKAGES), \"\"));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists all the available containers.\n     *\n     */\n    @GET\n    @RolesAllowed(\"inventory\")\n    @Path(\"/containers\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public Response getContainers() {\n        try {\n            return makeInventoryDoGetRequest(\n                    buildKuraMessage(Arrays.asList(InventoryHandlerV1.RESOURCE_DOCKER_CONTAINERS), \"\"));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * POST method.\n     *\n     * Start selected container.\n     *\n     */\n    @POST\n    @RolesAllowed(\"inventory\")\n    @Path(\"/containers/_start\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response startContainer(final String bundleJson) {\n        try {\n            return makeInventoryDoExecRequest(buildKuraMessage(InventoryHandlerV1.START_CONTAINER, bundleJson));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * POST method.\n     *\n     * Stop selected container.\n     *\n     */\n    @POST\n    @RolesAllowed(\"inventory\")\n    @Path(\"/containers/_stop\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response stopContainer(final String bundleJson) {\n        try {\n            return makeInventoryDoExecRequest(buildKuraMessage(InventoryHandlerV1.STOP_CONTAINER, bundleJson));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * GET method.\n     *\n     * Lists all the available container images.\n     *\n     */\n    @GET\n    @RolesAllowed(\"inventory\")\n    @Path(\"/images\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public Response getImages() {\n        try {\n            return makeInventoryDoGetRequest(\n                    buildKuraMessage(Arrays.asList(InventoryHandlerV1.RESOURCE_CONTAINER_IMAGES), \"\"));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    /**\n     * POST method.\n     *\n     * Delete selected container image.\n     *\n     */\n    @POST\n    @RolesAllowed(\"inventory\")\n    @Path(\"/images/_delete\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public Response deleteImage(final String bundleJson) {\n        try {\n            return makeInventoryDoExecRequest(buildKuraMessage(InventoryHandlerV1.DELETE_IMAGE, bundleJson));\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    private KuraMessage buildKuraMessage(List<String> requestObject, String body) {\n\n        Map<String, Object> payloadProperties = new HashMap<>();\n        payloadProperties.put(ARGS_KEY.value(), requestObject);\n\n        KuraPayload kuraPayload = new KuraPayload();\n        kuraPayload.setBody(body.getBytes());\n\n        return new KuraMessage(kuraPayload, payloadProperties);\n    }\n\n    private Response makeInventoryDoGetRequest(KuraMessage kuraMessage) throws KuraException {\n        return buildResponse(inventoryHandlerV1.doGet(null, kuraMessage).getPayload());\n    }\n\n    private Response makeInventoryDoExecRequest(KuraMessage kuraMessage) throws KuraException {\n        return buildResponse(inventoryHandlerV1.doExec(null, kuraMessage).getPayload());\n    }\n\n    private Response buildResponse(KuraPayload kuraPayload) throws KuraException {\n        if (kuraPayload instanceof KuraResponsePayload) {\n            KuraResponsePayload kuraResponsePayload = (KuraResponsePayload) kuraPayload;\n            return Response.status(kuraResponsePayload.getResponseCode()).entity(kuraPayload.getBody()).build();\n        } else {\n            throw new KuraException(KuraErrorCode.INVALID_MESSAGE_EXCEPTION);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.keystore.provider\nBundle-SymbolicName: org.eclipse.kura.rest.keystore.provider;singleton:=true\nBundle-Version: 1.0.0.qualifier\nImport-Package: com.google.gson;version=\"2.7.0\",\n com.google.gson.annotations;version=\"2.7.0\",\n jakarta.annotation.security;version=\"2.1.1\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.bouncycastle.asn1.pkcs;version=\"1.78.1\",\n org.bouncycastle.jce.provider;version=\"1.78.1\",\n org.bouncycastle.openssl;version=\"1.78.1\",\n org.bouncycastle.openssl.jcajce;version=\"1.78.1\",\n org.eclipse.kura;version=\"[1.7,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.keystore.util;version=\"[1.1,2.0)\",\n org.eclipse.kura.marshalling;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.4,2.0)\",\n org.eclipse.kura.request.handler.jaxrs;version=\"[2.0,3.0)\",\n org.eclipse.kura.rest.utils;version=\"[1.0,2.0)\",\n org.eclipse.kura.security.keystore;version=\"[1.2,1.3)\",\n org.eclipse.kura.util.service;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.36\"\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/OSGI-INF/org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV1\">\n   <implementation class=\"org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV1\"/>\n\n\t<property name=\"service.pid\" value=\"org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV1\"/>\n <reference bind=\"setUserAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.useradmin.UserAdmin\" name=\"UserAdmin\" policy=\"static\"/>\n <service>\n    <provide interface=\"org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestService\"/>\n </service>\n <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/OSGI-INF/org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV2\">\n   <implementation class=\"org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV2\"/>\n\n\t<property name=\"service.pid\" value=\"org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV2\"/>\n <reference bind=\"setUserAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.useradmin.UserAdmin\" name=\"UserAdmin\" policy=\"static\"/>\n <service>\n    <provide interface=\"org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestService\"/>\n </service>\n <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/OSGI-INF/org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreServiceRequestHandlerV1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreRequestHandlerV1\">\n   <implementation class=\"org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreServiceRequestHandlerV1\"/>\n\n\t<property name=\"service.pid\" value=\"org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreServiceRequestHandlerV1\"/>\n <reference bind=\"setRequestHandlerRegistry\" cardinality=\"0..n\" interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\" name=\"RequestHandlerRegistry\" policy=\"dynamic\" unbind=\"unsetRequestHandlerRegistry\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/OSGI-INF/org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreServiceRequestHandlerV2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2023 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreRequestHandlerV2\">\n   <implementation class=\"org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreServiceRequestHandlerV2\"/>\n\n\t<property name=\"service.pid\" value=\"org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreServiceRequestHandlerV2\"/>\n <reference bind=\"setRequestHandlerRegistry\" cardinality=\"0..n\" interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\" name=\"RequestHandlerRegistry\" policy=\"dynamic\" unbind=\"unsetRequestHandlerRegistry\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/build.properties",
    "content": "#\n#  Copyright (c) 2024 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<artifactId>org.eclipse.kura.rest.keystore.provider</artifactId>\n\t<packaging>eclipse-plugin</packaging>\n\t<version>1.0.0-SNAPSHOT</version>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/provider/CsrResponse.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.provider;\n\npublic class CsrResponse {\n\n    private final String signingRequest;\n\n    public CsrResponse(String signingRequest) {\n        super();\n        this.signingRequest = signingRequest;\n    }\n\n    public String getSigningRequest() {\n        return this.signingRequest;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/provider/KeystoreRestService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.provider;\n\nimport static java.util.Objects.isNull;\nimport static org.eclipse.kura.rest.utils.Validable.validate;\n\nimport java.util.List;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.DELETE;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.QueryParam;\nimport jakarta.ws.rs.core.MediaType;\n\nimport org.eclipse.kura.core.keystore.util.EntryInfo;\nimport org.eclipse.kura.internal.rest.keystore.request.CsrReadRequest;\nimport org.eclipse.kura.internal.rest.keystore.request.EntryRequest;\nimport org.eclipse.kura.internal.rest.keystore.request.KeyPairWriteRequest;\nimport org.eclipse.kura.internal.rest.keystore.request.TrustedCertificateWriteRequest;\nimport org.eclipse.kura.internal.rest.keystore.util.KeystoreRemoteService;\nimport org.eclipse.kura.security.keystore.KeystoreInfo;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\n\npublic class KeystoreRestService extends KeystoreRemoteService {\n\n    protected static final String BAD_REQUEST_MESSAGE = \"Bad request, \";\n\n    private static final String BAD_WRITE_REQUEST_ERROR_MESSAGE = BAD_REQUEST_MESSAGE\n            + \"expected request format: {\\\"keystoreServicePid\\\": \\\"MyKeystoreName\\\", \\\"alias\\\": \"\n            + \"\\\"MyAlias\\\", \\\"type\\\": \\\"TrustedCertificate\\\", \\\"certificate\\\": \\\"...\\\"}\";\n    private static final String BAD_GET_CSR_REQUEST_ERROR_MESSAGE = BAD_REQUEST_MESSAGE\n            + \"expected request format: {\\\"keystoreServicePid\\\": \\\"MyKeystoreName\\\", \\\"alias\\\": \\\"MyAlias\\\", \"\n            + \"\\\"signatureAlgorithm\\\": \\\"...\\\", \\\"attributes\\\": \\\"...\\\"}\";\n    private static final String BAD_DELETE_REQUEST_ERROR_MESSAGE = BAD_REQUEST_MESSAGE\n            + \"expected request format: {\\\"keystoreServicePid\\\": \\\"MyKeystoreName\\\", \\\"alias\\\": \\\"MyAlias\\\"}\";\n\n    public void setUserAdmin(final UserAdmin userAdmin) {\n        userAdmin.createRole(\"kura.permission.rest.keystores\", Role.GROUP);\n    }\n\n    @GET\n    @RolesAllowed(\"keystores\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public List<KeystoreInfo> listKeystores() {\n        return listKeystoresInternal();\n    }\n\n    @GET\n    @Path(\"/entries\")\n    @RolesAllowed(\"keystores\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public List<EntryInfo> getEntries(@QueryParam(\"keystoreServicePid\") String keystoreServicePid,\n            @QueryParam(\"alias\") String alias) {\n        if (isNull(keystoreServicePid) && isNull(alias)) {\n            return getKeysInternal();\n        } else if (!isNull(keystoreServicePid)) {\n            return getKeysByPidInternal(keystoreServicePid);\n        } else {\n            return getKeysByAliasInternal(alias);\n        }\n    }\n\n    @GET\n    @Path(\"/entries/entry\")\n    @RolesAllowed(\"keystores\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public EntryInfo getEntry(@QueryParam(\"keystoreServicePid\") String keystoreServicePid,\n            @QueryParam(\"alias\") String alias) {\n        return getKeyInternal(keystoreServicePid, alias);\n    }\n\n    @POST\n    @Path(\"/entries/csr\")\n    @RolesAllowed(\"keystores\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public CsrResponse getCSR(CsrReadRequest csrReadRequest) {\n        validate(csrReadRequest, BAD_GET_CSR_REQUEST_ERROR_MESSAGE);\n        return new CsrResponse(getCSRInternal(csrReadRequest));\n    }\n\n    @POST\n    @Path(\"/entries/certificate\")\n    @RolesAllowed(\"keystores\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public void storeTrustedCertificateEntry(TrustedCertificateWriteRequest writeRequest) {\n        validate(writeRequest, BAD_WRITE_REQUEST_ERROR_MESSAGE);\n        storeTrustedCertificateEntryInternal(writeRequest);\n    }\n\n    @POST\n    @Path(\"/entries/keypair\")\n    @RolesAllowed(\"keystores\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public void storeKeypairEntry(KeyPairWriteRequest writeRequest) {\n        validate(writeRequest, BAD_WRITE_REQUEST_ERROR_MESSAGE);\n        storeKeyPairEntryInternal(writeRequest);\n    }\n\n    @DELETE\n    @Path(\"/entries\")\n    @RolesAllowed(\"keystores\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public void deleteKeyEntry(EntryRequest deleteRequest) {\n        validate(deleteRequest, BAD_DELETE_REQUEST_ERROR_MESSAGE);\n        deleteKeyEntryInternal(deleteRequest.getKeystoreServicePid(), deleteRequest.getAlias());\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/provider/KeystoreRestServiceV1.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.provider;\n\nimport jakarta.ws.rs.Path;\n\n@Path(\"/keystores/v1\")\npublic class KeystoreRestServiceV1 extends KeystoreRestService {\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/provider/KeystoreRestServiceV2.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.provider;\n\nimport static org.eclipse.kura.rest.utils.Validable.validate;\n\nimport org.eclipse.kura.internal.rest.keystore.request.PrivateKeyWriteRequest;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.core.MediaType;\n\n@Path(\"/keystores/v2\")\npublic class KeystoreRestServiceV2 extends KeystoreRestService {\n\n    private static final String BAD_WRITE_REQUEST_ERROR_MESSAGE = BAD_REQUEST_MESSAGE\n            + \"expected request format: {\\\"keystoreServicePid\\\": \\\"MyKeystoreName\\\", \\\"alias\\\": \"\n            + \"\\\"MyAlias\\\", \\\"certificateChain\\\": \\\"...\\\", \\\"privateKey\\\": \\\"...\\\"}\";\n\n    @POST\n    @Path(\"/entries/privatekey\")\n    @RolesAllowed(\"keystores\")\n    @Consumes(MediaType.APPLICATION_JSON)\n    public void storeKeypairEntry(PrivateKeyWriteRequest writeRequest) {\n        validate(writeRequest, BAD_WRITE_REQUEST_ERROR_MESSAGE);\n        try {\n            storePrivateKeyEntryInternal(writeRequest);\n        } catch (final Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/request/CsrReadRequest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.request;\n\nimport org.eclipse.kura.core.keystore.util.CsrInfo;\nimport org.eclipse.kura.rest.utils.Validable;\n\npublic class CsrReadRequest extends CsrInfo implements Validable {\n\n    public CsrReadRequest(String keystoreServicePid, String alias) {\n        super(keystoreServicePid, alias);\n    }\n\n    public CsrReadRequest(final CsrInfo csrInfo) {\n        super(csrInfo.getKeystoreServicePid(), csrInfo.getAlias());\n        this.setSignatureAlgorithm(csrInfo.getSignatureAlgorithm());\n        this.setAttributes(csrInfo.getAttributes());\n    }\n\n    @Override\n    public String toString() {\n        return \"ReadRequest [keystoreServicePid=\" + this.getKeystoreServicePid() + \", alias=\" + this.getAlias()\n                + \", algorithm=\" + this.getSignatureAlgorithm() + \", attributes=\" + this.getAttributes() + \"]\";\n    }\n\n    @Override\n    public boolean isValid() {\n        return this.getKeystoreServicePid() != null && this.getAlias() != null && this.getSignatureAlgorithm() != null\n                && this.getAttributes() != null;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/request/EntryRequest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.request;\n\nimport org.eclipse.kura.core.keystore.util.EntryInfo;\nimport org.eclipse.kura.rest.utils.Validable;\n\npublic class EntryRequest extends EntryInfo implements Validable {\n\n    public EntryRequest(String keystoreServicePid, String alias) {\n        super(keystoreServicePid, alias);\n    }\n\n    public EntryRequest(final EntryInfo entryInfo) {\n        super(entryInfo.getKeystoreServicePid(), entryInfo.getAlias());\n    }\n\n    @Override\n    public String toString() {\n        return \"DeleteRequest [keystoreServicePid=\" + this.getKeystoreServicePid() + \", alias=\" + this.getAlias() + \"]\";\n    }\n\n    @Override\n    public boolean isValid() {\n        return this.getKeystoreServicePid() != null && this.getAlias() != null;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/request/KeyPairWriteRequest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.request;\n\nimport org.eclipse.kura.core.keystore.util.KeyPairInfo;\nimport org.eclipse.kura.rest.utils.Validable;\n\npublic class KeyPairWriteRequest extends KeyPairInfo implements Validable {\n\n    public KeyPairWriteRequest(String keystoreName, String alias) {\n        super(keystoreName, alias);\n    }\n\n    public KeyPairWriteRequest(final KeyPairInfo keyPairInfo) {\n        super(keyPairInfo.getKeystoreServicePid(), keyPairInfo.getAlias());\n        this.setAlgorithm(keyPairInfo.getAlgorithm());\n        this.setAttributes(keyPairInfo.getAttributes());\n        this.setSignatureAlgorithm(keyPairInfo.getSignatureAlgorithm());\n        this.setSize(keyPairInfo.getSize());\n    }\n\n    @Override\n    public boolean isValid() {\n        if (getKeystoreServicePid() == null || getAlias() == null) {\n            return false;\n        }\n        return !(getAlgorithm() == null || getSize() == 0 || getSignatureAlgorithm() == null\n                || getAttributes() == null);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/request/PrivateKeyWriteRequest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.request;\n\nimport org.eclipse.kura.core.keystore.util.PrivateKeyInfo;\nimport org.eclipse.kura.rest.utils.Validable;\n\npublic class PrivateKeyWriteRequest extends PrivateKeyInfo implements Validable {\n\n    public PrivateKeyWriteRequest(String keystoreServicePid, String alias) {\n        super(keystoreServicePid, alias);\n    }\n\n    public PrivateKeyWriteRequest(final PrivateKeyInfo other) {\n        super(other.getAlias(), other.getKeystoreServicePid());\n        this.setAlgorithm(other.getAlgorithm());\n        this.setSize(other.getSize());\n        this.setPrivateKey(other.getPrivateKey());\n        this.setCertificateChain(other.getCertificateChain());\n    }\n\n    @Override\n    public boolean isValid() {\n        return getKeystoreServicePid() != null && getAlias() != null && getCertificateChain() != null\n                && getCertificateChain().length > 0;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/request/TrustedCertificateWriteRequest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.request;\n\nimport org.eclipse.kura.core.keystore.util.CertificateInfo;\nimport org.eclipse.kura.rest.utils.Validable;\n\npublic class TrustedCertificateWriteRequest extends CertificateInfo implements Validable {\n\n    public TrustedCertificateWriteRequest(String keystoreServicePid, String alias) {\n        super(keystoreServicePid, alias);\n    }\n\n    public TrustedCertificateWriteRequest(final CertificateInfo other) {\n        super(other.getKeystoreServicePid(), other.getAlias());\n        this.setSubjectDN(other.getSubjectDN());\n        this.setSubjectAN(other.getSubjectAN());\n        this.setIssuer(other.getIssuer());\n        this.setStartDate(other.getStartDate());\n        this.setExpirationDate(other.getExpirationDate());\n        this.setAlgorithm(other.getAlgorithm());\n        this.setSize(other.getSize());\n        this.setCertificate(other.getCertificate());\n    }\n\n    @Override\n    public String toString() {\n        return \"WriteRequest [keystoreServicePid=\" + getKeystoreServicePid() + \", alias=\" + getAlias() + \"]\";\n    }\n\n    @Override\n    public boolean isValid() {\n        boolean result = true;\n        if (getKeystoreServicePid() == null || getAlias() == null || getCertificate() == null) {\n            result = false;\n        }\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/request/handler/KeystoreServiceRequestHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.request.handler;\n\nimport static java.util.Objects.isNull;\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\nimport java.util.function.Function;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerContext;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.core.keystore.util.CertificateInfo;\nimport org.eclipse.kura.core.keystore.util.CsrInfo;\nimport org.eclipse.kura.core.keystore.util.EntryInfo;\nimport org.eclipse.kura.core.keystore.util.KeyPairInfo;\nimport org.eclipse.kura.internal.rest.keystore.request.EntryRequest;\nimport org.eclipse.kura.internal.rest.keystore.request.KeyPairWriteRequest;\nimport org.eclipse.kura.internal.rest.keystore.request.TrustedCertificateWriteRequest;\nimport org.eclipse.kura.internal.rest.keystore.util.KeystoreRemoteService;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.eclipse.kura.rest.utils.Validable;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.osgi.framework.ServiceReference;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\n\npublic class KeystoreServiceRequestHandler extends KeystoreRemoteService implements RequestHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(KeystoreServiceRequestHandler.class);\n\n    protected static final String NONE_RESOURCE_FOUND_MESSAGE = \"Resource not found\";\n    protected static final String KEYSTORES = \"keystores\";\n    protected static final String ENTRIES = \"entries\";\n    protected static final String ENTRY = \"entry\";\n    protected static final String CSR = \"csr\";\n    protected static final String CERTIFICATE = \"certificate\";\n    protected static final String KEYPAIR = \"keypair\";\n\n    private final String appId;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    protected KeystoreServiceRequestHandler(final String appId) {\n        this.appId = appId;\n    }\n\n    public void setRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) {\n        try {\n            requestHandlerRegistry.registerRequestHandler(this.appId, this);\n        } catch (KuraException e) {\n            logger.info(\"Unable to register cloudlet {} in {}\", this.appId,\n                    requestHandlerRegistry.getClass().getName());\n        }\n    }\n\n    public void unsetRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) {\n        try {\n            requestHandlerRegistry.unregister(this.appId);\n        } catch (KuraException e) {\n            logger.info(\"Unable to register cloudlet {} in {}\", this.appId,\n                    requestHandlerRegistry.getClass().getName());\n        }\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Public methods\n    //\n    // ----------------------------------------------------------------\n\n    @Override\n    public KuraMessage doGet(final RequestHandlerContext context, final KuraMessage reqMessage) throws KuraException {\n        final List<String> resourcePath = extractResourcePath(reqMessage);\n        KuraPayload reqPayload = reqMessage.getPayload();\n\n        if (resourcePath.isEmpty()) {\n            logger.error(NONE_RESOURCE_FOUND_MESSAGE);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        if (resourcePath.size() == 1 && resourcePath.get(0).equals(KEYSTORES)) {\n            return jsonResponse(listKeystoresInternal());\n        } else if (resourcePath.size() == 2 && resourcePath.get(0).equals(KEYSTORES)\n                && resourcePath.get(1).equals(ENTRIES)) {\n            return doGetEntries(reqPayload);\n        } else if (resourcePath.size() == 3 && resourcePath.get(0).equals(KEYSTORES)\n                && resourcePath.get(1).equals(ENTRIES) && resourcePath.get(2).equals(ENTRY)) {\n            EntryInfo request = unmarshal(new String(reqPayload.getBody(), StandardCharsets.UTF_8), EntryInfo.class);\n            String keystoreServicePid = request.getKeystoreServicePid();\n            String keyAlias = request.getAlias();\n            if (!isNull(keystoreServicePid) && !isNull(keyAlias)) {\n                return jsonResponse(getKeyInternal(keystoreServicePid, keyAlias));\n            } else {\n                throw new KuraException(KuraErrorCode.BAD_REQUEST);\n            }\n        } else {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n    }\n\n    private KuraMessage doGetEntries(KuraPayload reqPayload) {\n        byte[] body = reqPayload.getBody();\n        if (isNull(body) || body.length == 0) {\n            return jsonResponse(getKeysInternal());\n        } else {\n            EntryInfo request = unmarshal(new String(reqPayload.getBody(), StandardCharsets.UTF_8), EntryInfo.class);\n            String keystoreServicePid = request.getKeystoreServicePid();\n            String keyAlias = request.getAlias();\n            if (isNull(keystoreServicePid) && !isNull(keyAlias)) {\n                return jsonResponse(getKeysByAliasInternal(keyAlias));\n            } else {\n                return jsonResponse(getKeysByPidInternal(keystoreServicePid));\n            }\n        }\n    }\n\n    @Override\n    public KuraMessage doPost(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        final List<String> resourcePath = extractResourcePath(reqMessage);\n        KuraPayload reqPayload = reqMessage.getPayload();\n\n        if (resourcePath.size() != 3 || reqPayload.getBody() == null || reqPayload.getBody().length == 0\n                || !resourcePath.get(0).equals(KEYSTORES) || !resourcePath.get(1).equals(ENTRIES)) {\n            logger.error(NONE_RESOURCE_FOUND_MESSAGE);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        if (resourcePath.get(2).equals(CSR)) {\n            return doPostCsr(reqPayload);\n        } else if (resourcePath.get(2).equals(CERTIFICATE)) {\n            String body = new String(reqPayload.getBody(), StandardCharsets.UTF_8);\n            CertificateInfo certificateInfo = unmarshal(body, CertificateInfo.class);\n            validateAs(certificateInfo, TrustedCertificateWriteRequest::new);\n            storeTrustedCertificateEntryInternal(certificateInfo);\n            return new KuraMessage(new KuraResponsePayload(200));\n        } else if (resourcePath.get(2).equals(KEYPAIR)) {\n            String body = new String(reqPayload.getBody(), StandardCharsets.UTF_8);\n            KeyPairInfo keyPairInfo = unmarshal(body, KeyPairInfo.class);\n            validateAs(keyPairInfo, KeyPairWriteRequest::new);\n            storeKeyPairEntryInternal(keyPairInfo);\n            return new KuraMessage(new KuraResponsePayload(200));\n        } else {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n    }\n\n    private KuraMessage doPostCsr(KuraPayload reqPayload) {\n        String body = new String(reqPayload.getBody(), StandardCharsets.UTF_8);\n        CsrInfo csrInfo = unmarshal(body, CsrInfo.class);\n        return jsonResponse(getCSRInternal(csrInfo));\n    }\n\n    @Override\n    public KuraMessage doDel(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        final List<String> resourcePath = extractResourcePath(reqMessage);\n        KuraPayload reqPayload = reqMessage.getPayload();\n\n        if (resourcePath.size() != 2 || reqPayload.getBody() == null || reqPayload.getBody().length == 0\n                || !resourcePath.get(0).equals(KEYSTORES)) {\n            logger.error(NONE_RESOURCE_FOUND_MESSAGE);\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        if (resourcePath.get(1).equals(ENTRIES)) {\n            String body = new String(reqPayload.getBody(), StandardCharsets.UTF_8);\n            EntryInfo request = unmarshal(body, EntryInfo.class);\n            if (request != null) {\n                validateAs(request, EntryRequest::new);\n                deleteKeyEntryInternal(request.getKeystoreServicePid(), request.getAlias());\n                return new KuraMessage(new KuraResponsePayload(200));\n            } else {\n                throw new KuraException(KuraErrorCode.BAD_REQUEST);\n            }\n        } else {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    protected static final List<String> extractResourcePath(final KuraMessage message) throws KuraException {\n        Object requestObject = message.getProperties().get(ARGS_KEY.value());\n        if (requestObject instanceof List) {\n            return (List<String>) requestObject;\n        } else {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n    }\n\n    private static final KuraMessage jsonResponse(final Object response) {\n        final KuraResponsePayload responsePayload = new KuraResponsePayload(200);\n        final Gson gson = new GsonBuilder().disableHtmlEscaping().create();\n        responsePayload.setBody(gson.toJson(response).getBytes(StandardCharsets.UTF_8));\n        return new KuraMessage(responsePayload);\n    }\n\n    private ServiceReference<Unmarshaller>[] getJsonUnmarshallers() {\n        String filterString = String.format(\"(&(kura.service.pid=%s))\",\n                \"org.eclipse.kura.json.marshaller.unmarshaller.provider\");\n        return ServiceUtil.getServiceReferences(this.bundleContext, Unmarshaller.class, filterString);\n    }\n\n    private void ungetServiceReferences(final ServiceReference<?>[] refs) {\n        ServiceUtil.ungetServiceReferences(this.bundleContext, refs);\n    }\n\n    protected <T> T unmarshal(String jsonString, Class<T> clazz) {\n        T result = null;\n        ServiceReference<Unmarshaller>[] unmarshallerSRs = getJsonUnmarshallers();\n        try {\n            for (final ServiceReference<Unmarshaller> unmarshallerSR : unmarshallerSRs) {\n                Unmarshaller unmarshaller = this.bundleContext.getService(unmarshallerSR);\n                result = unmarshaller.unmarshal(jsonString, clazz);\n                if (result != null) {\n                    break;\n                }\n            }\n        } catch (Exception e) {\n            logger.warn(\"Failed to marshal configuration.\");\n        } finally {\n            ungetServiceReferences(unmarshallerSRs);\n        }\n        return result;\n    }\n\n    protected <T, U extends Validable> void validateAs(final T arg, final Function<T, U> ctor) throws KuraException {\n        final Validable validable = ctor.apply(arg);\n\n        if (!validable.isValid()) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/request/handler/KeystoreServiceRequestHandlerV1.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.request.handler;\n\npublic class KeystoreServiceRequestHandlerV1 extends KeystoreServiceRequestHandler {\n\n    public KeystoreServiceRequestHandlerV1() {\n        super(\"KEYS-V1\");\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/request/handler/KeystoreServiceRequestHandlerV2.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.request.handler;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerContext;\nimport org.eclipse.kura.core.keystore.util.PrivateKeyInfo;\nimport org.eclipse.kura.internal.rest.keystore.request.PrivateKeyWriteRequest;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class KeystoreServiceRequestHandlerV2 extends KeystoreServiceRequestHandler {\n\n    private static final Logger logger = LoggerFactory.getLogger(KeystoreServiceRequestHandlerV2.class);\n\n    protected static final String PRIVATEKEY = \"privatekey\";\n\n    private static final List<String> PRIVATE_KEY_RESOURCE = Arrays.asList(KEYSTORES, ENTRIES, PRIVATEKEY);\n\n    public KeystoreServiceRequestHandlerV2() {\n        super(\"KEYS-V2\");\n    }\n\n    @Override\n    public KuraMessage doPost(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException {\n        final List<String> resourcePath = extractResourcePath(reqMessage);\n\n        if (!PRIVATE_KEY_RESOURCE.equals(resourcePath)) {\n            return super.doPost(context, reqMessage);\n        }\n\n        final KuraPayload reqPayload = reqMessage.getPayload();\n\n        final String body = new String(reqPayload.getBody(), StandardCharsets.UTF_8);\n        final PrivateKeyInfo privateKeyInfo = unmarshal(body, PrivateKeyInfo.class);\n        validateAs(privateKeyInfo, PrivateKeyWriteRequest::new);\n        try {\n            storePrivateKeyEntryInternal(privateKeyInfo);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to store private key entry\", e);\n            return new KuraMessage(new KuraResponsePayload(500));\n        }\n        return new KuraMessage(new KuraResponsePayload(200));\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.keystore.provider/src/main/java/org/eclipse/kura/internal/rest/keystore/util/KeystoreRemoteService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.keystore.util;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.security.GeneralSecurityException;\nimport java.security.Key;\nimport java.security.KeyStore;\nimport java.security.KeyStore.Entry;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.KeyStoreException;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateParsingException;\nimport java.security.cert.X509Certificate;\nimport java.security.interfaces.DSAPublicKey;\nimport java.security.interfaces.ECPublicKey;\nimport java.security.interfaces.RSAPublicKey;\nimport java.security.spec.ECParameterSpec;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Base64;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.stream.Collectors;\n\nimport javax.security.auth.x500.X500Principal;\nimport jakarta.ws.rs.WebApplicationException;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.keystore.util.CertificateInfo;\nimport org.eclipse.kura.core.keystore.util.CsrInfo;\nimport org.eclipse.kura.core.keystore.util.EntryInfo;\nimport org.eclipse.kura.core.keystore.util.KeyPairInfo;\nimport org.eclipse.kura.core.keystore.util.KeystoreUtils;\nimport org.eclipse.kura.core.keystore.util.PrivateKeyInfo;\nimport org.eclipse.kura.internal.rest.keystore.request.CsrReadRequest;\nimport org.eclipse.kura.security.keystore.KeystoreInfo;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class KeystoreRemoteService {\n\n    private static final Logger logger = LoggerFactory.getLogger(KeystoreRemoteService.class);\n\n    public static final String BEGIN_CERT = \"-----BEGIN CERTIFICATE-----\";\n    public static final String END_CERT = \"-----END CERTIFICATE-----\";\n    public static final String LINE_SEPARATOR = System.getProperty(\"line.separator\");\n\n    protected Map<String, KeystoreService> keystoreServices = new HashMap<>();\n    protected BundleContext bundleContext;\n    private ServiceTrackerCustomizer<KeystoreService, KeystoreService> keystoreServiceTrackerCustomizer;\n    private ServiceTracker<KeystoreService, KeystoreService> keystoreServiceTracker;\n\n    public void activate(ComponentContext componentContext) {\n        this.bundleContext = componentContext.getBundleContext();\n        this.keystoreServiceTrackerCustomizer = new KeystoreServiceTrackerCustomizer();\n        initKeystoreServiceTracking();\n    }\n\n    public void deactivate(ComponentContext componentContext) {\n        if (this.keystoreServiceTracker != null) {\n            this.keystoreServiceTracker.close();\n        }\n    }\n\n    protected List<KeystoreInfo> listKeystoresInternal() {\n        List<KeystoreInfo> keystores = new ArrayList<>();\n        this.keystoreServices.entrySet().stream().forEach(entry -> {\n            try {\n                if (entry.getValue().getKeyStore() != null) {\n                    keystores.add(buildKeystoreInfo(entry.getKey(), entry.getValue().getKeyStore()));\n                }\n            } catch (KuraException | KeyStoreException e) {\n                throw new WebApplicationException(e);\n            }\n        });\n        return keystores;\n    }\n\n    protected List<EntryInfo> getKeysInternal() {\n        List<EntryInfo> keys = new ArrayList<>();\n        this.keystoreServices.entrySet().stream().forEach(keystoreService -> {\n            if (keystoreService != null) {\n                try {\n                    keystoreService.getValue().getEntries().entrySet().stream().forEach(entry -> {\n                        if (entry.getValue() instanceof PrivateKeyEntry) {\n                            keys.add(buildPrivateKeyInfo(keystoreService.getKey(), entry.getKey(),\n                                    (PrivateKeyEntry) entry.getValue(), false));\n                        } else if (entry.getValue() instanceof TrustedCertificateEntry) {\n                            keys.add(buildCertificateInfo(keystoreService.getKey(), entry.getKey(),\n                                    (TrustedCertificateEntry) entry.getValue(), false));\n                        }\n                    });\n                } catch (KuraException e) {\n                    throw new WebApplicationException(e);\n                }\n            }\n        });\n        return keys;\n    }\n\n    protected List<EntryInfo> getKeysByPidInternal(final String keystoreServicePid) {\n        List<EntryInfo> keys = new ArrayList<>();\n        KeystoreService keystoreService = this.keystoreServices.get(keystoreServicePid);\n        if (keystoreService != null) {\n            try {\n                keystoreService.getEntries().entrySet().stream().forEach(entry -> {\n                    if (entry.getValue() instanceof PrivateKeyEntry) {\n                        keys.add(buildPrivateKeyInfo(keystoreServicePid, entry.getKey(),\n                                (PrivateKeyEntry) entry.getValue(), true));\n                    } else if (entry.getValue() instanceof TrustedCertificateEntry) {\n                        keys.add(buildCertificateInfo(keystoreServicePid, entry.getKey(),\n                                (TrustedCertificateEntry) entry.getValue(), true));\n                    }\n                });\n            } catch (KuraException e) {\n                throw new WebApplicationException(e);\n            }\n        } else {\n            throw new WebApplicationException(404);\n        }\n        return keys;\n    }\n\n    protected List<EntryInfo> getKeysByAliasInternal(final String alias) {\n        List<EntryInfo> keys = new ArrayList<>();\n        this.keystoreServices.entrySet().stream().filter(entry -> {\n            try {\n                return entry.getValue().getAliases().contains(alias);\n            } catch (KuraException e) {\n                throw new WebApplicationException(e);\n            }\n        }).forEach(entry -> {\n            try {\n                Entry keystoreEntry = entry.getValue().getEntry(alias);\n                if (keystoreEntry instanceof PrivateKeyEntry) {\n                    keys.add(buildPrivateKeyInfo(entry.getKey(), alias, (PrivateKeyEntry) keystoreEntry, true));\n                } else if (keystoreEntry instanceof TrustedCertificateEntry) {\n                    keys.add(\n                            buildCertificateInfo(entry.getKey(), alias, (TrustedCertificateEntry) keystoreEntry, true));\n                } else {\n                    throw new WebApplicationException(404);\n                }\n\n            } catch (KuraException e) {\n                throw new WebApplicationException(e);\n            }\n        });\n\n        return keys;\n    }\n\n    protected EntryInfo getKeyInternal(final String keystoreServicePid, final String alias) {\n        Entry entry;\n        KeystoreService keystoreService = this.keystoreServices.get(keystoreServicePid);\n        if (keystoreService != null) {\n            try {\n                entry = keystoreService.getEntry(alias);\n                if (entry instanceof PrivateKeyEntry) {\n                    return buildPrivateKeyInfo(keystoreServicePid, alias, (PrivateKeyEntry) entry, true);\n                } else if (entry instanceof TrustedCertificateEntry) {\n                    return buildCertificateInfo(keystoreServicePid, alias, (TrustedCertificateEntry) entry, true);\n                } else {\n                    throw new WebApplicationException(404);\n                }\n\n            } catch (KuraException e) {\n                throw new WebApplicationException(e);\n            }\n        } else {\n            throw new WebApplicationException(404);\n        }\n    }\n\n    protected String getCSRInternal(final CsrInfo info) {\n        try {\n            X500Principal principal = new X500Principal(info.getAttributes());\n            return this.keystoreServices.get(info.getKeystoreServicePid()).getCSR(info.getAlias(), principal,\n                    info.getSignatureAlgorithm());\n        } catch (KuraException e) {\n            throw new WebApplicationException(e);\n        }\n    }\n\n    protected String getCSRInternal(final CsrReadRequest request) {\n        try {\n            X500Principal principal = new X500Principal(request.getAttributes());\n            return this.keystoreServices.get(request.getKeystoreServicePid()).getCSR(request.getAlias(), principal,\n                    request.getSignatureAlgorithm());\n        } catch (KuraException e) {\n            throw new WebApplicationException(e);\n        }\n    }\n\n    protected void storeTrustedCertificateEntryInternal(final CertificateInfo writeRequest) {\n        try {\n            this.keystoreServices.get(writeRequest.getKeystoreServicePid()).setEntry(writeRequest.getAlias(),\n                    KeystoreUtils.createCertificateEntry(writeRequest.getCertificate()));\n        } catch (GeneralSecurityException | KuraException e) {\n            throw new WebApplicationException(e);\n        }\n    }\n\n    protected void storeKeyPairEntryInternal(final KeyPairInfo writeRequest) {\n        try {\n            this.keystoreServices.get(writeRequest.getKeystoreServicePid()).createKeyPair(writeRequest.getAlias(),\n                    writeRequest.getAlgorithm(), writeRequest.getSize(), writeRequest.getSignatureAlgorithm(),\n                    writeRequest.getAttributes());\n        } catch (KuraException e) {\n            throw new WebApplicationException(e);\n        }\n    }\n\n    protected void storePrivateKeyEntryInternal(final PrivateKeyInfo writeRequest)\n            throws KuraException, IOException, GeneralSecurityException {\n\n        final KeystoreService targetKeystore = Optional\n                .ofNullable(this.keystoreServices.get(writeRequest.getKeystoreServicePid()))\n                .orElseThrow(() -> new KuraException(KuraErrorCode.NOT_FOUND, \"KeystoreService not found\"));\n\n        if (writeRequest.getPrivateKey() == null) {\n            updatePrivateKeyEntryCertificateChain(targetKeystore, writeRequest);\n        } else {\n            createPrivateKeyEntry(targetKeystore, writeRequest);\n        }\n    }\n\n    private void updatePrivateKeyEntryCertificateChain(final KeystoreService targetKeystore,\n            final PrivateKeyInfo writeRequest) throws KuraException, CertificateException {\n        final Entry targetEntry = Optional.ofNullable(targetKeystore.getEntry(writeRequest.getAlias()))\n                .orElseThrow(() -> new KuraException(KuraErrorCode.NOT_FOUND, \"Entry not found\"));\n\n        if (!(targetEntry instanceof PrivateKeyEntry)) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"Target entry is not a PrivateKeyEntry\");\n        }\n\n        final PrivateKeyEntry existingPrivateKeyEntry = (PrivateKeyEntry) targetEntry;\n\n        final Certificate[] certificateChain = KeystoreUtils.parsePublicCertificates(\n                Arrays.stream(writeRequest.getCertificateChain()).collect(Collectors.joining(\"\\n\")));\n\n        final PrivateKeyEntry result = new PrivateKeyEntry(existingPrivateKeyEntry.getPrivateKey(), certificateChain);\n\n        targetKeystore.setEntry(writeRequest.getAlias(), result);\n    }\n\n    private void createPrivateKeyEntry(final KeystoreService targetKeystore, final PrivateKeyInfo writeRequest)\n            throws IOException, GeneralSecurityException, KuraException {\n        final PrivateKeyEntry privateKeyEntry = KeystoreUtils.createPrivateKey(writeRequest.getPrivateKey(),\n                Arrays.stream(writeRequest.getCertificateChain()).collect(Collectors.joining(\"\\n\")));\n\n        targetKeystore.setEntry(writeRequest.getAlias(), privateKeyEntry);\n    }\n\n    protected void deleteKeyEntryInternal(String keystoreServicePid, String alias) {\n        try {\n            this.keystoreServices.get(keystoreServicePid).deleteEntry(alias);\n        } catch (KuraException e) {\n            throw new WebApplicationException(e);\n        }\n    }\n\n    private KeystoreInfo buildKeystoreInfo(String keystoreServicePid, KeyStore keystore) throws KeyStoreException {\n        KeystoreInfo keystoreInfo = new KeystoreInfo(keystoreServicePid);\n        keystoreInfo.setType(keystore.getType().toUpperCase());\n        keystoreInfo.setSize(keystore.size());\n        return keystoreInfo;\n    }\n\n    private CertificateInfo buildCertificateInfo(String keystoreServicePid, String alias,\n            TrustedCertificateEntry certificate, boolean withCertificate) {\n        CertificateInfo certificateInfo = new CertificateInfo(keystoreServicePid, alias);\n        if (certificate != null && certificate.getTrustedCertificate() instanceof X509Certificate) {\n            X509Certificate x509Certificate = (X509Certificate) certificate.getTrustedCertificate();\n            certificateInfo.setSubjectDN(x509Certificate.getSubjectDN().getName());\n            certificateInfo.setIssuer(x509Certificate.getIssuerX500Principal().getName());\n            certificateInfo.setStartDate(x509Certificate.getNotBefore().getTime());\n            certificateInfo.setExpirationDate(x509Certificate.getNotAfter().getTime());\n            certificateInfo.setAlgorithm(x509Certificate.getSigAlgName());\n            certificateInfo.setSize(getSize(x509Certificate.getPublicKey()));\n            try {\n                certificateInfo.setSubjectAN(x509Certificate.getSubjectAlternativeNames());\n            } catch (CertificateParsingException e) {\n                logger.error(\"Cannot parse certificate subject alternative names\", e);\n            }\n            if (withCertificate) {\n                final Base64.Encoder encoder = Base64.getMimeEncoder(64,\n                        LINE_SEPARATOR.getBytes(StandardCharsets.UTF_8));\n                StringBuilder pemCertificate = new StringBuilder();\n                pemCertificate.append(BEGIN_CERT);\n                pemCertificate.append(LINE_SEPARATOR);\n                try {\n                    pemCertificate.append(encoder.encodeToString(x509Certificate.getEncoded()));\n                } catch (CertificateEncodingException e) {\n                    logger.error(\"Cannot encode certificate\", e);\n                }\n                pemCertificate.append(LINE_SEPARATOR);\n                pemCertificate.append(END_CERT);\n                certificateInfo.setCertificate(pemCertificate.toString());\n            }\n        }\n        return certificateInfo;\n    }\n\n    private PrivateKeyInfo buildPrivateKeyInfo(String keystoreServicePid, String alias, PrivateKeyEntry privateKey,\n            boolean withCertificate) {\n        PrivateKeyInfo privateKeyInfo = new PrivateKeyInfo(keystoreServicePid, alias);\n        if (privateKey != null) {\n            privateKeyInfo.setAlgorithm(privateKey.getPrivateKey().getAlgorithm());\n            privateKeyInfo.setSize(getSize(privateKey.getCertificate().getPublicKey()));\n            if (withCertificate) {\n                final Base64.Encoder encoder = Base64.getMimeEncoder(64,\n                        LINE_SEPARATOR.getBytes(StandardCharsets.UTF_8));\n                String[] certificateChain = new String[privateKey.getCertificateChain().length];\n                for (int i = 0; i < certificateChain.length; i++) {\n                    StringBuilder pemCertificate = new StringBuilder();\n                    pemCertificate.append(BEGIN_CERT);\n                    pemCertificate.append(LINE_SEPARATOR);\n                    try {\n                        pemCertificate.append(encoder.encodeToString(privateKey.getCertificateChain()[i].getEncoded()));\n                    } catch (CertificateEncodingException e) {\n                        logger.error(\"Cannot encode certificate\", e);\n                    }\n                    pemCertificate.append(LINE_SEPARATOR);\n                    pemCertificate.append(END_CERT);\n                    certificateChain[i] = pemCertificate.toString();\n                }\n                privateKeyInfo.setCertificateChain(certificateChain);\n            }\n\n        }\n        return privateKeyInfo;\n    }\n\n    private int getSize(Key key) {\n        int size = 0;\n        if (key instanceof RSAPublicKey) {\n            size = ((RSAPublicKey) key).getModulus().bitLength();\n        } else if (key instanceof ECPublicKey) {\n            ECParameterSpec spec = ((ECPublicKey) key).getParams();\n            if (spec != null) {\n                size = spec.getOrder().bitLength();\n            }\n        } else if (key instanceof DSAPublicKey) {\n            DSAPublicKey dsaCertificate = (DSAPublicKey) key;\n            if (dsaCertificate.getParams() != null) {\n                size = dsaCertificate.getParams().getP().bitLength();\n            } else {\n                size = dsaCertificate.getY().bitLength();\n            }\n        }\n        return size;\n    }\n\n    private void initKeystoreServiceTracking() {\n        String filterString = String.format(\"(&(%s=%s))\", Constants.OBJECTCLASS, KeystoreService.class.getName());\n        Filter filter = null;\n        try {\n            filter = this.bundleContext.createFilter(filterString);\n        } catch (InvalidSyntaxException e) {\n            logger.error(\"Filter setup exception \", e);\n        }\n        this.keystoreServiceTracker = new ServiceTracker<>(this.bundleContext, filter,\n                this.keystoreServiceTrackerCustomizer);\n        this.keystoreServiceTracker.open();\n    }\n\n    private final class KeystoreServiceTrackerCustomizer\n            implements ServiceTrackerCustomizer<KeystoreService, KeystoreService> {\n\n        private static final String KURA_SERVICE_PID = \"kura.service.pid\";\n\n        @Override\n        public KeystoreService addingService(final ServiceReference<KeystoreService> reference) {\n            String kuraServicePid = (String) reference.getProperty(KURA_SERVICE_PID);\n            KeystoreRemoteService.this.keystoreServices.put(kuraServicePid,\n                    KeystoreRemoteService.this.bundleContext.getService(reference));\n            return KeystoreRemoteService.this.keystoreServices.get(kuraServicePid);\n        }\n\n        @Override\n        public void modifiedService(final ServiceReference<KeystoreService> reference, final KeystoreService service) {\n            String kuraServicePid = (String) reference.getProperty(KURA_SERVICE_PID);\n            KeystoreRemoteService.this.keystoreServices.put(kuraServicePid,\n                    KeystoreRemoteService.this.bundleContext.getService(reference));\n        }\n\n        @Override\n        public void removedService(final ServiceReference<KeystoreService> reference, final KeystoreService service) {\n            String kuraServicePid = (String) reference.getProperty(KURA_SERVICE_PID);\n            KeystoreRemoteService.this.keystoreServices.remove(kuraServicePid);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Kura Rest Provider\nBundle-SymbolicName: org.eclipse.kura.rest.provider\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: com.google.gson;version=\"2.9.0\",\n jakarta.annotation;version=\"2.1.1\",\n jakarta.annotation.security;version=\"2.1.1\",\n jakarta.servlet;version=\"5.0.0\",\n jakarta.servlet.http;version=\"5.0.0\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.container;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n jakarta.ws.rs.ext;version=\"3.1.0\",\n org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.audit;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.identity;version=\"[1.1,2.0)\",\n org.eclipse.kura.request.handler.jaxrs;version=\"[2.0,3.0)\",\n org.eclipse.kura.util.configuration;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.validation;version=\"[1.0,2.0)\",\n org.osgi.annotation.versioning;version=\"[1.0.0,2.0.0)\";resolution:=optional,\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.component;version=\"1.5.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.21\"\nRequire-Bundle: org.eclipse.osgitech.rest.servlet.whiteboard;bundle-version=\"1.2.3\"\nExport-Package: org.eclipse.kura.rest.auth;version=\"1.0.0\",\n org.eclipse.kura.rest.utils;version=\"1.0.0\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/OSGI-INF/metatype/org.eclipse.kura.internal.rest.provider.RestService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright (c) 2017, 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.internal.rest.provider.RestService\" \n    name=\"RestService\" \n    description=\"This service allows to configure settings related to Kura REST APIs\">\n\n        <AD \n\t        id=\"allowed.ports\" \n\t        name=\"Allowed Ports\" \n\t        type=\"Integer\" \n\t        cardinality=\"3\" \n\t        required=\"false\" \n\t        default=\"443,4443\"\n\t        min=\"1\" \n\t        max=\"65535\" \n\t        description=\"If set to a non empty list, REST API access will be allowed only on the specified ports. If set to an empty list, access will be allowed on all ports. Please make sure that the allowed ports are open in HttpService and Firewall configuration.\">\n        </AD>\n\n        <AD \n        \tid=\"auth.password.enabled\" \n        \tname=\"Password Authentication Enabled\" \n        \ttype=\"Boolean\" \n        \trequired=\"true\" \n        \tdefault=\"true\" \n        \tdescription=\"Enables or disables the built-in password authentication support.\">\n        </AD>\n\n        <AD \n        \tid=\"auth.certificate.enabled\" \n        \tname=\"Certificate Authentication Enabled\" \n        \ttype=\"Boolean\" \n        \trequired=\"true\" \n        \tdefault=\"true\" \n        \tdescription=\"Enables or disables the built-in certificate authentication support.\">\n        </AD>\n        \n        <AD \n        \tid=\"session.management.enabled\" \n        \tname=\"Session Based Authentication Enabled\" \n        \ttype=\"Boolean\" \n        \trequired=\"true\" \n        \tdefault=\"true\" \n        \tdescription=\"If set to true, enables authentication using the dedicated /services/session/v1 endpoints and cookie based session management.\">\n        </AD>\n        \n        <AD \n        \tid=\"session.inactivity.interval\" \n        \tname=\"Session Inactivity Interval (Seconds)\" \n        \ttype=\"Integer\" \n        \trequired=\"true\" \n        \tdefault=\"900\"\n\t\t\tmin=\"1\"\n        \tdescription=\"The session inactivity interval, sessions will expire if no request is performed for the amount of time specified by this parameter in seconds. This parameter is ignored if Session Based Authentication Enabled is set to false.\">\n        </AD>\n        \n        <AD \n        \tid=\"auth.basic.enabled\" \n        \tname=\"Basic Authentication Enabled\" \n        \ttype=\"Boolean\" \n        \trequired=\"true\" \n        \tdefault=\"true\" \n        \tdescription=\"Allows to perform authentication by providing identity name and password as BASIC credentials in the request to any resource endpoint. Requires that the Password Authentication Enabled parameter is set to true.\">\n        </AD>\n        \n        <AD \n        \tid=\"auth.certificate.stateless.enabled\" \n        \tname=\"Enable Certificate Authentication Without Session Management\"\n        \ttype=\"Boolean\" \n        \trequired=\"true\" \n        \tdefault=\"true\" \n        \tdescription=\"If set to true, calling /services/session/v1/certificate to create a session will not be necessary in order to perform certificate based authentication. Presenting a valid HTTPS client certificate and accessing resource endpoint directly is enough for authentication to succeed. Requires that the Certificate Authentication Enabled parameter is set to true.\">\n        </AD>\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.internal.rest.provider.RestService\">\n        <Object ocdref=\"org.eclipse.kura.internal.rest.provider.RestService\" />\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/build.properties",
    "content": "bin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\nadditional.bundles = org.osgi.service.component.annotations,\\\n                     org.osgi.service.metatype.annotations"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<artifactId>org.eclipse.kura.rest.provider</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<build>\n        <plugins>\n            <plugin>\n\t\t\t\t<groupId>biz.aQute.bnd</groupId>\n\t\t\t\t<artifactId>bnd-maven-plugin</artifactId>\n\t\t\t</plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/BasicAuthenticationProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.internal.rest.auth;\n\nimport static java.util.Objects.isNull;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.security.Principal;\nimport java.util.Base64;\nimport java.util.Base64.Decoder;\nimport java.util.Optional;\nimport java.util.StringTokenizer;\n\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport org.eclipse.kura.audit.AuditConstants;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.rest.auth.AuthenticationProvider;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceRegistration;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.Priority;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.container.ContainerResponseContext;\nimport jakarta.ws.rs.container.ContainerResponseFilter;\nimport jakarta.ws.rs.ext.Provider;\n\n@SuppressWarnings(\"restriction\")\n@Priority(200)\npublic class BasicAuthenticationProvider implements AuthenticationProvider {\n\n    private static final String PASSWORD_AUTH_FAILED_MSG = \"{} Rest - Failure - Authentication failed as username or password not matching\";\n\n    private static final Logger logger = LoggerFactory.getLogger(BasicAuthenticationProvider.class);\n\n    private static final Logger auditLogger = LoggerFactory.getLogger(\"AuditLogger\");\n\n    private static final Decoder BASE64_DECODER = Base64.getDecoder();\n\n    private final RestIdentityHelper identityHelper;\n    private final BundleContext bundleContext;\n\n    private Optional<ServiceRegistration<ContainerResponseFilter>> registration = Optional.empty();\n\n    public BasicAuthenticationProvider(final BundleContext bundleContext, final RestIdentityHelper identityHelper) {\n        this.identityHelper = identityHelper;\n        this.bundleContext = bundleContext;\n    }\n\n    @Override\n    public Optional<Principal> authenticate(final HttpServletRequest request,\n            final ContainerRequestContext requestContext) {\n        final AuditContext auditContext = AuditContext.currentOrInternal();\n\n        final String authHeader = requestContext.getHeaderString(\"Authorization\");\n        if (isNull(authHeader)) {\n            return Optional.empty();\n        }\n\n        StringTokenizer tokens = new StringTokenizer(authHeader);\n        String authScheme = tokens.nextToken();\n        if (!\"Basic\".equals(authScheme)) {\n            return Optional.empty();\n        }\n\n        final RequestCredentials credentials;\n\n        try {\n            credentials = RequestCredentials.fromBasicAuthorizationHeader(tokens.nextToken());\n        } catch (final Exception e) {\n            logger.debug(\"failed to parse basic credentials\", e);\n            auditLogger.warn(PASSWORD_AUTH_FAILED_MSG, auditContext);\n            return Optional.empty();\n        }\n\n        try {\n            auditContext.getProperties().put(AuditConstants.KEY_IDENTITY.getValue(), credentials.username);\n\n            if (this.identityHelper.isPasswordChangeRequired(credentials.username)) {\n                auditLogger.warn(PASSWORD_AUTH_FAILED_MSG, auditContext);\n                return Optional.empty();\n            }\n\n            this.identityHelper.checkPassword(credentials.username, credentials.password.toCharArray());\n\n            auditLogger.info(\"{} Rest - Success - Authentication succeeded via password provider\", auditContext);\n\n            return Optional.of(() -> credentials.username);\n        } catch (final Exception e) {\n            auditLogger.warn(PASSWORD_AUTH_FAILED_MSG, auditContext);\n            return Optional.empty();\n        }\n    }\n\n    @Override\n    public void onEnabled() {\n        if (this.registration.isPresent()) {\n            return;\n        }\n\n        this.registration = Optional.of(\n                bundleContext.registerService(ContainerResponseFilter.class, new AuthenticateResponseFilter(), null));\n    }\n\n    @Override\n    public void onDisabled() {\n        registration.ifPresent(ServiceRegistration::unregister);\n        registration = Optional.empty();\n    }\n\n    @Provider\n    private static class AuthenticateResponseFilter implements ContainerResponseFilter {\n\n        @Override\n        public void filter(final ContainerRequestContext request, final ContainerResponseContext response)\n                throws IOException {\n            final int status = response.getStatus();\n\n            if (status == 401 || status == 403) {\n                response.getHeaders().add(\"WWW-Authenticate\", \"Basic realm=\\\"kura-rest-api\\\"\");\n            }\n        }\n\n    }\n\n    private static class RequestCredentials {\n\n        final String username;\n        final String password;\n\n        RequestCredentials(final String username, final String password) {\n            this.username = username;\n            this.password = password;\n        }\n\n        static RequestCredentials fromBasicAuthorizationHeader(final String authHeaderToken) {\n\n            final String credentials = new String(BASE64_DECODER.decode(authHeaderToken), StandardCharsets.UTF_8);\n\n            final int colonIndex = credentials.indexOf(':');\n\n            String username = credentials.substring(0, colonIndex);\n            String password = credentials.substring(colonIndex + 1);\n\n            return new RequestCredentials(username, password);\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/CertificateAuthenticationProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.internal.rest.auth;\n\nimport java.security.Principal;\nimport java.security.cert.X509Certificate;\nimport java.util.Optional;\n\nimport javax.naming.ldap.LdapName;\nimport javax.naming.ldap.Rdn;\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport org.eclipse.kura.audit.AuditConstants;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.rest.auth.AuthenticationProvider;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.Priority;\nimport jakarta.ws.rs.container.ContainerRequestContext;\n\n@SuppressWarnings(\"restriction\")\n@Priority(100)\npublic class CertificateAuthenticationProvider implements AuthenticationProvider {\n\n    private final RestIdentityHelper identityHelper;\n\n    private static final Logger auditLogger = LoggerFactory.getLogger(\"AuditLogger\");\n\n    public CertificateAuthenticationProvider(final RestIdentityHelper identityHelper) {\n        this.identityHelper = identityHelper;\n    }\n\n    @Override\n    public Optional<Principal> authenticate(final HttpServletRequest request,\n            final ContainerRequestContext requestContext) {\n\n        return authenticate(requestContext, \"Certificate Authentication\");\n    }\n\n    public Optional<Principal> authenticate(final ContainerRequestContext requestContext,\n            final String auditAuthenticationKind) {\n        final AuditContext auditContext = AuditContext.currentOrInternal();\n\n        try {\n            final Principal principal = this.authenticate(requestContext);\n\n            auditLogger.info(\"{} Rest - Success - {} succeeded\", auditContext, auditAuthenticationKind);\n\n            return Optional.of(principal);\n\n        } catch (final CertificateAuthException e) {\n            if (e.getReason() == CertificateAuthException.Reason.IDENTITY_NOT_FOUND) {\n                auditLogger.warn(\"{} Rest - Failure - {} failed\", auditContext, auditAuthenticationKind);\n            }\n\n            return Optional.empty();\n        }\n    }\n\n    public Principal authenticate(final ContainerRequestContext requestContext) throws CertificateAuthException {\n        final AuditContext auditContext = AuditContext.currentOrInternal();\n\n        try {\n\n            final Object clientCertificatesRaw = requestContext.getProperty(\"jakarta.servlet.request.X509Certificate\");\n\n            if (!(clientCertificatesRaw instanceof X509Certificate[])) {\n                throw new CertificateAuthException(CertificateAuthException.Reason.CLIENT_CERTIFICATE_CHAIN_MISSING);\n            }\n\n            final X509Certificate[] clientCertificates = (X509Certificate[]) clientCertificatesRaw;\n\n            if (clientCertificates.length == 0) {\n                throw new CertificateAuthException(CertificateAuthException.Reason.CLIENT_CERTIFICATE_CHAIN_MISSING);\n            }\n\n            final LdapName ldapName = new LdapName(clientCertificates[0].getSubjectX500Principal().getName());\n\n            final Optional<Rdn> commonNameRdn = ldapName.getRdns().stream()\n                    .filter(r -> \"cn\".equalsIgnoreCase(r.getType())).findAny();\n\n            if (!commonNameRdn.isPresent()) {\n                throw new CertificateAuthException(CertificateAuthException.Reason.MISSING_COMMON_NAME);\n            }\n\n            final String commonName = (String) commonNameRdn.get().getValue();\n\n            auditContext.getProperties().put(AuditConstants.KEY_IDENTITY.getValue(), commonName);\n\n            if (this.identityHelper.identityExists(commonName)) {\n                return () -> commonName;\n            }\n\n            throw new CertificateAuthException(CertificateAuthException.Reason.IDENTITY_NOT_FOUND);\n\n        } catch (final CertificateAuthException e) {\n\n            throw e;\n        } catch (final Exception e) {\n            throw new CertificateAuthException(CertificateAuthException.Reason.UNEXPECTED_ERROR);\n        }\n    }\n\n    @Override\n    public void onEnabled() {\n        // do nothing\n    }\n\n    @Override\n    public void onDisabled() {\n        // do nothing\n    }\n\n    public static class CertificateAuthException extends Exception {\n\n        public enum Reason {\n            CLIENT_CERTIFICATE_CHAIN_MISSING,\n            MISSING_COMMON_NAME,\n            IDENTITY_NOT_FOUND,\n            UNEXPECTED_ERROR\n        }\n\n        private final Reason reason;\n\n        public CertificateAuthException(final Reason reason) {\n            this.reason = reason;\n        }\n\n        public Reason getReason() {\n            return reason;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/ConfigurationAdminHelper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.internal.rest.auth;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ConfigurationAdminHelper {\n\n    private static final Logger logger = LoggerFactory.getLogger(ConfigurationAdminHelper.class);\n\n    private ConfigurationAdminHelper() {\n    }\n\n    public static Map<String, Object> loadConfigurationProperties(final ConfigurationAdmin configurationAdmin,\n            final String pid) {\n\n        return getConfiguration(configurationAdmin, pid).map(Configuration::getProperties)\n                .map(ConfigurationAdminHelper::dictionaryToMap).orElseGet(() -> new HashMap<>());\n    }\n\n    public static Map<String, Object> loadHttpServiceConfigurationProperties(\n            final ConfigurationAdmin configurationAdmin) {\n\n        return loadConfigurationProperties(configurationAdmin, \"org.eclipse.kura.http.server.manager.HttpService\");\n    }\n\n    public static Set<Integer> getHttpsMutualAuthPorts(final Map<String, Object> properties) {\n        final Object rawPortList = properties.get(\"https.client.auth.ports\");\n\n        if (!(rawPortList instanceof Integer[])) {\n            return Collections.emptySet();\n        }\n\n        final Integer[] portList = (Integer[]) rawPortList;\n\n        return Arrays.stream(portList).filter(Objects::nonNull).collect(Collectors.toSet());\n    }\n\n    private static Optional<Configuration> getConfiguration(final ConfigurationAdmin configurationAdmin,\n            final String pid) {\n        try {\n            return Optional.ofNullable(configurationAdmin.getConfiguration(pid, \"?\"));\n        } catch (final IOException e) {\n            logger.warn(\"Failed to retrieve configuration for {}\", pid, e);\n            return Optional.empty();\n        }\n    }\n\n    private static final Map<String, Object> dictionaryToMap(final Dictionary<String, Object> dict) {\n        final Map<String, Object> result = new HashMap<>(dict.size());\n\n        final Enumeration<String> keys = dict.keys();\n\n        while (keys.hasMoreElements()) {\n            final String key = keys.nextElement();\n\n            result.put(key, dict.get(key));\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/RestIdentityHelper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.internal.rest.auth;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityConfigurationComponent;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.PasswordHash;\nimport org.eclipse.kura.identity.Permission;\n\npublic class RestIdentityHelper {\n\n    private final IdentityService identityService;\n\n    public RestIdentityHelper(final IdentityService identityService) {\n        this.identityService = identityService;\n    }\n\n    public void checkPassword(final String username, final char[] password) throws KuraException {\n        identityService.checkPassword(username, password);\n    }\n\n    public boolean isPasswordChangeRequired(final String username) throws KuraException {\n        return passwordConfiguration(username).map(PasswordConfiguration::isPasswordChangeNeeded).orElse(false);\n    }\n\n    public Optional<PasswordHash> getPasswordHash(final String username) throws KuraException {\n        return passwordConfiguration(username).flatMap(PasswordConfiguration::getPasswordHash);\n    }\n\n    public Set<Permission> getAssignedPermissions(final String username) throws KuraException {\n        return identityConfiguration(username, AssignedPermissions.class)\n                .flatMap(c -> c.getComponent(AssignedPermissions.class))\n                .map(AssignedPermissions::getPermissions)\n                .orElse(Collections.emptySet());\n    }\n\n    public boolean identityExists(final String username) throws KuraException {\n        return identityService.getIdentityConfiguration(username, Collections.emptySet()).isPresent();\n    }\n\n    public void checkPermission(final String username, final Permission permission) throws KuraException {\n        identityService.checkPermission(username, permission);\n    }\n\n    public void updatePassword(final String username, final char[] newPassword, final boolean passwordChangeNeeded)\n            throws KuraException {\n        final PasswordConfiguration existingPasswordConfig = passwordConfiguration(username)\n                .orElseThrow(() -> new KuraException(KuraErrorCode.SECURITY_EXCEPTION));\n\n        final PasswordConfiguration updatedPasswordConfig = new PasswordConfiguration(passwordChangeNeeded,\n                existingPasswordConfig.isPasswordAuthEnabled(), Optional.of(newPassword), Optional.empty());\n\n        final IdentityConfiguration identityConfiguration = new IdentityConfiguration(username,\n                Collections.singletonList(updatedPasswordConfig));\n\n        identityService.updateIdentityConfiguration(identityConfiguration);\n    }\n\n    public PasswordHash computePasswordHash(final char[] password) throws KuraException {\n        return identityService.computePasswordHash(password);\n    }\n\n    private Optional<IdentityConfiguration> identityConfiguration(final String username,\n            final Class<? extends IdentityConfigurationComponent>... components) throws KuraException {\n        final Set<Class<? extends IdentityConfigurationComponent>> componentsToReturn = new HashSet<>(\n                Arrays.asList(components));\n        return identityService.getIdentityConfiguration(username, componentsToReturn);\n    }\n\n    private Optional<PasswordConfiguration> passwordConfiguration(final String username) throws KuraException {\n        return identityConfiguration(username, PasswordConfiguration.class)\n                .flatMap(c -> c.getComponent(PasswordConfiguration.class));\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/RestSessionHelper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.internal.rest.auth;\n\nimport java.security.Principal;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\n\nimport jakarta.servlet.http.Cookie;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.HttpSession;\n\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.identity.PasswordHash;\n\nimport jakarta.ws.rs.container.ContainerRequestContext;\n\n@SuppressWarnings(\"restriction\")\npublic class RestSessionHelper {\n\n    private final RestIdentityHelper identityHelper;\n\n    public RestSessionHelper(final RestIdentityHelper identityHelper) {\n        this.identityHelper = identityHelper;\n    }\n\n    public HttpSession createNewAuthenticatedSession(final HttpServletRequest request, final String user) {\n\n        final Optional<HttpSession> existingSession = getExistingSession(request);\n\n        if (existingSession.isPresent()) {\n            existingSession.get().invalidate();\n        }\n\n        final HttpSession newSession = request.getSession(true);\n        request.changeSessionId();\n\n        newSession.setAttribute(SessionAttributes.AUTORIZED_USER.getValue(), user);\n        updateLastActivity(newSession);\n\n        try {\n            final Optional<PasswordHash> passwordHash = identityHelper.getPasswordHash(user);\n            if (passwordHash.isPresent()) {\n                newSession.setAttribute(SessionAttributes.CREDENTIALS_HASH.getValue(), passwordHash.get());\n            }\n        } catch (final Exception e) {\n            // no need\n        }\n\n        getOrCreateXsrfToken(newSession);\n\n        AuditContext.currentOrInternal().getProperties().put(\"session.id\",\n                Integer.toUnsignedString(Objects.hash(newSession.getId())));\n\n        return newSession;\n    }\n\n    public void lockSession(final HttpSession session) {\n        session.setAttribute(SessionAttributes.LOCKED.getValue(), true);\n    }\n\n    public void unlockSession(final HttpSession session) {\n        session.setAttribute(SessionAttributes.LOCKED.getValue(), false);\n    }\n\n    public boolean isSessionLocked(final HttpSession session) {\n        return Objects.equals(true, session.getAttribute(SessionAttributes.LOCKED.getValue()));\n    }\n\n    public void updateLastActivity(final HttpSession session) {\n\n        session.setAttribute(SessionAttributes.LAST_ACTIVITY.getValue(), System.nanoTime());\n    }\n\n    public Optional<Principal> getPrincipalFromSession(final HttpSession session) {\n\n        final Object authorized = session.getAttribute(SessionAttributes.AUTORIZED_USER.getValue());\n\n        if (!(authorized instanceof String)) {\n            return Optional.empty();\n        }\n\n        final String userName = (String) authorized;\n\n        return Optional.of(principalForIdentity(userName));\n    }\n\n    public boolean credentialsChanged(final HttpSession session, final String userName) {\n        try {\n            return !Objects.equals(session.getAttribute(SessionAttributes.CREDENTIALS_HASH.getValue()),\n                    identityHelper.getPasswordHash(userName).orElse(null));\n        } catch (final Exception e) {\n            return true;\n        }\n    }\n\n    public Optional<Principal> getCurrentPrincipal(final ContainerRequestContext context) {\n        return Optional.ofNullable(context.getSecurityContext())\n                .flatMap(c -> Optional.ofNullable(c.getUserPrincipal()));\n    }\n\n    public boolean isSessionExpired(final HttpSession session, final int maxInactiveInterval) {\n\n        final long now = System.nanoTime();\n\n        if (!session.isNew()) {\n            final long lastActivity = getLastActivity(session);\n\n            final long delta = now - lastActivity;\n            if (maxInactiveInterval > 0 && delta > TimeUnit.SECONDS.toNanos(maxInactiveInterval)) {\n                session.invalidate();\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public Optional<String> getXsrfToken(final HttpSession httpSession) {\n        return Optional.ofNullable(httpSession.getAttribute(SessionAttributes.XSRF_TOKEN.getValue()))\n                .flatMap(t -> t instanceof String ? Optional.of((String) t) : Optional.empty());\n    }\n\n    public String getOrCreateXsrfToken(final HttpSession httpSession) {\n        final Optional<String> existiongToken = getXsrfToken(httpSession);\n\n        if (existiongToken.isPresent()) {\n            return existiongToken.get();\n        }\n\n        final UUID token = UUID.randomUUID();\n\n        final String asString = token.toString();\n\n        httpSession.setAttribute(SessionAttributes.XSRF_TOKEN.getValue(), asString);\n\n        return asString;\n    }\n\n    public boolean isXsrfTokenValid(final HttpServletRequest httpServletRequest) {\n\n        return checkXsrfToken(Optional.ofNullable(httpServletRequest.getHeader(\"X-XSRF-Token\")), httpServletRequest);\n    }\n\n    public boolean checkXsrfToken(final Optional<String> userToken, final HttpServletRequest httpServletRequest) {\n\n        final Optional<HttpSession> session = getExistingSession(httpServletRequest);\n\n        if (!userToken.isPresent() || !session.isPresent()) {\n            return false;\n        }\n\n        return Objects.equals(userToken, getXsrfToken(session.get()));\n    }\n\n    public void logout(final HttpServletRequest request, final HttpServletResponse response) {\n\n        final Optional<HttpSession> maybeSession = getExistingSession(request);\n\n        if (!maybeSession.isPresent()) {\n            return;\n        }\n\n        final HttpSession session = maybeSession.get();\n\n        session.invalidate();\n\n        Cookie[] cookies = request.getCookies();\n        for (Cookie cookie : cookies) {\n            cookie.setMaxAge(0);\n            cookie.setValue(null);\n            cookie.setPath(\"/\");\n            response.addCookie(cookie);\n        }\n    }\n\n    public Optional<HttpSession> getExistingSession(final HttpServletRequest request) {\n        return Optional.ofNullable(request.getSession(false));\n    }\n\n    private static Principal principalForIdentity(final String name) {\n        return () -> name;\n    }\n\n    private static long getLastActivity(final HttpSession session) {\n        final Object lastActivityRaw = session.getAttribute(SessionAttributes.LAST_ACTIVITY.getValue());\n\n        if (!(lastActivityRaw instanceof Long)) {\n            return 0;\n        }\n\n        return (long) lastActivityRaw;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/SessionAttributes.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.auth;\n\npublic enum SessionAttributes {\n\n    AUTORIZED_USER(\"org.eclipse.kura.user\"),\n    LAST_ACTIVITY(\"org.eclipse.kura.lastActivity\"),\n    CREDENTIALS_HASH(\"org.eclipse.kura.credentialsHash\"),\n    AUDIT_CONTEXT(\"org.eclipse.kura.audit.context\"),\n    LOCKED(\"org.eclipse.kura.locked\"),\n    XSRF_TOKEN(\"org.eclipse.kura.xsrf.token\");\n\n    private String value;\n\n    private SessionAttributes(final String value) {\n        this.value = value;\n    }\n\n    public String getValue() {\n        return this.value;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/SessionAuthProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.auth;\n\nimport java.security.Principal;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpSession;\n\nimport org.eclipse.kura.audit.AuditConstants;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.internal.rest.provider.RestServiceOptions;\nimport org.eclipse.kura.rest.auth.AuthenticationProvider;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.Priority;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.core.PathSegment;\n\n@Priority(300)\npublic class SessionAuthProvider implements AuthenticationProvider {\n\n    private static final Logger auditLogger = LoggerFactory.getLogger(\"AuditLogger\");\n\n    private final RestSessionHelper sessionHelper;\n    private RestServiceOptions restServiceOptions;\n    private final Set<String> lockedSessionAllowedPaths;\n    private final Set<String> allowNoXsrfTokenPaths;\n\n    public SessionAuthProvider(final RestSessionHelper sessionHelper, final Set<String> allowSessionLocked,\n            final Set<String> allowNoXsrfToken) {\n        this.sessionHelper = sessionHelper;\n        this.lockedSessionAllowedPaths = allowSessionLocked;\n        this.allowNoXsrfTokenPaths = allowNoXsrfToken;\n    }\n\n    @Override\n    public void onEnabled() {\n        // no need\n    }\n\n    @Override\n    public void onDisabled() {\n        // no need\n    }\n\n    public void setOptions(final RestServiceOptions restServiceOptions) {\n        this.restServiceOptions = restServiceOptions;\n    }\n\n    @Override\n    public Optional<Principal> authenticate(final HttpServletRequest request,\n            final ContainerRequestContext requestContext) {\n\n        final AuditContext auditContext = AuditContext.currentOrInternal();\n\n        final Optional<HttpSession> session = this.sessionHelper.getExistingSession(request);\n\n        if (!session.isPresent()) {\n            return Optional.empty();\n        }\n\n        auditContext.getProperties().put(\"session.id\", Integer.toUnsignedString(Objects.hash(session.get().getId())));\n\n        final Optional<Principal> result = this.sessionHelper.getPrincipalFromSession(session.get());\n\n        if (!result.isPresent()) {\n            return Optional.empty();\n        }\n\n        auditContext.getProperties().put(AuditConstants.KEY_IDENTITY.getValue(), result.get().getName());\n\n        if (!isXsrfTokenValid(request, requestContext)) {\n            auditLogger.warn(\"{} Rest - Failure - Session authentication failed, invalid XSRF token\", auditContext);\n            return Optional.empty();\n        }\n\n        if (this.sessionHelper.isSessionExpired(session.get(),\n                this.restServiceOptions.getSessionInactivityInterval())) {\n            auditLogger.warn(\"{} Rest - Failure - Session authentication failed, session expired\", auditContext);\n            session.get().invalidate();\n            return Optional.empty();\n        }\n\n        if (isSessionLocked(session.get(), requestContext)) {\n            auditLogger.warn(\"{} Rest - Failure - Session authentication failed, session is locked\", auditContext);\n            return Optional.empty();\n        }\n\n        if (sessionHelper.credentialsChanged(session.get(), result.get().getName())) {\n            auditLogger.warn(\"{} Rest - Failure - Session authentication failed, user credentials changed\",\n                    auditContext);\n            session.get().invalidate();\n            return Optional.empty();\n        }\n\n        this.sessionHelper.updateLastActivity(session.get());\n\n        auditLogger.info(\"{} Rest - Success - Authentication succeeded via session provider\", auditContext);\n\n        return result;\n    }\n\n    private boolean isSessionLocked(final HttpSession session, final ContainerRequestContext requestContext) {\n        if (containsPath(lockedSessionAllowedPaths, requestContext)) {\n            return false;\n        }\n\n        return this.sessionHelper.isSessionLocked(session);\n    }\n\n    private boolean isXsrfTokenValid(final HttpServletRequest request, final ContainerRequestContext context) {\n        if (containsPath(allowNoXsrfTokenPaths, context)) {\n            return true;\n        }\n\n        return this.sessionHelper.isXsrfTokenValid(request);\n    }\n\n    private boolean containsPath(final Set<String> paths, final ContainerRequestContext requestContext) {\n        final String reuqestPath = '/' + requestContext.getUriInfo().getPathSegments().stream()\n                .map(PathSegment::getPath).collect(Collectors.joining(\"/\"));\n\n        return paths.contains(reuqestPath);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/SessionRestService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.internal.rest.auth;\n\nimport java.security.Principal;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.audit.AuditConstants;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.identity.LoginBannerService;\nimport org.eclipse.kura.identity.PasswordHash;\nimport org.eclipse.kura.identity.PasswordStrengthRequirements;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.internal.rest.auth.dto.AuthenticationInfoDTO;\nimport org.eclipse.kura.internal.rest.auth.dto.AuthenticationResponseDTO;\nimport org.eclipse.kura.internal.rest.auth.dto.IdentityInfoDTO;\nimport org.eclipse.kura.internal.rest.auth.dto.UpdatePasswordDTO;\nimport org.eclipse.kura.internal.rest.auth.dto.UsernamePasswordDTO;\nimport org.eclipse.kura.internal.rest.auth.dto.XsrfTokenDTO;\nimport org.eclipse.kura.internal.rest.provider.RestServiceOptions;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.eclipse.kura.util.validation.PasswordStrengthValidators;\nimport org.eclipse.kura.util.validation.Validator;\nimport org.eclipse.kura.util.validation.ValidatorOptions;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.servlet.http.HttpSession;\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.WebApplicationException;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.core.Context;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response.Status;\n\n@SuppressWarnings(\"restriction\")\n@Path(SessionRestServiceConstants.BASE_PATH)\npublic class SessionRestService {\n\n    private static final String AUDIT_FORMAT_STRING = \"{} Rest - Failure - {}\";\n    private static final String INVALID_SESSION_MESSAGE = \"Current session is not valid\";\n    private static final String BAD_USERNAME_OR_PASSWORD_MESSAGE = \"Authentication failed as username or password not matching\";\n    private static final String PASSWORD_CHANGE_SAME_PASSWORD_MESSAGE = \"Password change failed as previous password equals new one\";\n\n    private static final Logger auditLogger = LoggerFactory.getLogger(\"AuditLogger\");\n\n    private final RestIdentityHelper identityHelper;\n    private final RestSessionHelper restSessionHelper;\n    private final ConfigurationAdmin configAdmin;\n    private final PasswordStrengthVerificationService passwordStrengthVerificationService;\n    private final LoginBannerService loginBannerService;\n    private RestServiceOptions options;\n\n    public SessionRestService(final RestIdentityHelper identityHelper, final RestSessionHelper restSessionHelper,\n            final ConfigurationAdmin configurationAdmin,\n            final PasswordStrengthVerificationService passwordStrengthVerificationService,\n            final LoginBannerService loginBannerService) {\n        this.identityHelper = identityHelper;\n        this.restSessionHelper = restSessionHelper;\n        this.configAdmin = configurationAdmin;\n        this.passwordStrengthVerificationService = passwordStrengthVerificationService;\n        this.loginBannerService = loginBannerService;\n    }\n\n    public void setOptions(final RestServiceOptions options) {\n        this.options = options;\n    }\n\n    @POST\n    @Path(SessionRestServiceConstants.LOGIN_PASSWORD_PATH)\n    @Consumes(MediaType.APPLICATION_JSON)\n    @Produces(MediaType.APPLICATION_JSON)\n    public AuthenticationResponseDTO authenticateWithUsernameAndPassword(final UsernamePasswordDTO usernamePassword,\n            @Context final HttpServletRequest request) {\n\n        if (!options.isSessionManagementEnabled() || !options.isPasswordAuthEnabled()) {\n            throw new WebApplicationException(Status.NOT_FOUND);\n        }\n\n        final AuditContext auditContext = AuditContext.currentOrInternal();\n\n        usernamePassword.validate();\n\n        auditContext.getProperties().put(AuditConstants.KEY_IDENTITY.getValue(), usernamePassword.getUsername());\n\n        try {\n\n            this.identityHelper.checkPassword(usernamePassword.getUsername(),\n                    usernamePassword.getPassword().toCharArray());\n\n            final HttpSession session = this.restSessionHelper.createNewAuthenticatedSession(request,\n                    usernamePassword.getUsername());\n\n            final AuthenticationResponseDTO response = buildAuthenticationResponse(usernamePassword.getUsername(),\n                    this.loginBannerService.getPostLoginBanner());\n\n            if (response.isPasswordChangeNeeded()) {\n                this.restSessionHelper.lockSession(session);\n            }\n\n            auditLogger.info(\"{} Rest - Success - Create session via password authentication succeeded\", auditContext);\n\n            return response;\n\n        } catch (final KuraException e) {\n            invalidateCurrentSession(request);\n            auditLogger.warn(AUDIT_FORMAT_STRING, auditContext, BAD_USERNAME_OR_PASSWORD_MESSAGE);\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED,\n                    BAD_USERNAME_OR_PASSWORD_MESSAGE);\n        } catch (final Exception e) {\n            invalidateCurrentSession(request);\n            auditLogger.warn(AUDIT_FORMAT_STRING, auditContext, BAD_USERNAME_OR_PASSWORD_MESSAGE);\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED,\n                    BAD_USERNAME_OR_PASSWORD_MESSAGE);\n        }\n    }\n\n    @POST\n    @Path(SessionRestServiceConstants.LOGIN_CERTIFICATE_PATH)\n    @Produces(MediaType.APPLICATION_JSON)\n    public AuthenticationResponseDTO authenticateWithCertificate(@Context final HttpServletRequest request,\n            @Context final ContainerRequestContext requestContext) {\n        if (!options.isSessionManagementEnabled() || !options.isCertificateAuthEnabled()) {\n            throw new WebApplicationException(Status.NOT_FOUND);\n        }\n\n        try {\n\n            final CertificateAuthenticationProvider certificateAuthProvider = new CertificateAuthenticationProvider(\n                    identityHelper);\n\n            final Optional<Principal> principal = certificateAuthProvider.authenticate(requestContext,\n                    \"Create session via certificate authentication\");\n\n            if (principal.isPresent()) {\n                this.restSessionHelper.createNewAuthenticatedSession(request, principal.get().getName());\n            } else {\n\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED,\n                        \"Certificate authentication failed\");\n            }\n\n            return buildAuthenticationResponse(principal.get().getName(), this.loginBannerService.getPostLoginBanner());\n        } catch (final Exception e) {\n            invalidateCurrentSession(request);\n            throw e;\n        }\n    }\n\n    @GET\n    @Path(SessionRestServiceConstants.XSRF_TOKEN_PATH)\n    public XsrfTokenDTO getXSRFToken(@Context final HttpServletRequest request,\n            @Context final ContainerRequestContext requestContext) {\n        if (!options.isSessionManagementEnabled()) {\n            throw new WebApplicationException(Status.NOT_FOUND);\n        }\n\n        final Optional<HttpSession> session = this.restSessionHelper.getExistingSession(request);\n\n        if (!session.isPresent()) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED, INVALID_SESSION_MESSAGE);\n        }\n\n        if (!this.restSessionHelper.getCurrentPrincipal(requestContext).isPresent()) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED, INVALID_SESSION_MESSAGE);\n        }\n\n        return new XsrfTokenDTO(this.restSessionHelper.getOrCreateXsrfToken(session.get()));\n    }\n\n    @POST\n    @Path(SessionRestServiceConstants.CHANGE_PASSWORD_PATH)\n    public void updateUserPassword(@Context final ContainerRequestContext requestContext,\n            @Context final HttpServletRequest request, final UpdatePasswordDTO passwordUpdate) {\n\n        passwordUpdate.validate();\n\n        try {\n            final Optional<String> username = this.restSessionHelper.getCurrentPrincipal(requestContext)\n                    .flatMap(c -> Optional.ofNullable(c.getName()));\n\n            if (!username.isPresent()) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED,\n                        INVALID_SESSION_MESSAGE);\n            }\n\n            this.identityHelper.checkPassword(username.get(), passwordUpdate.getCurrentPassword().toCharArray());\n\n            final String newPassword = passwordUpdate.getNewPassword();\n\n            validatePasswordStrength(newPassword);\n\n            if (isSamePassword(username.get(), newPassword)) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                        PASSWORD_CHANGE_SAME_PASSWORD_MESSAGE);\n            }\n\n            this.identityHelper.updatePassword(username.get(), newPassword.toCharArray(), false);\n\n            final HttpSession session = this.restSessionHelper.createNewAuthenticatedSession(request, username.get());\n            this.restSessionHelper.unlockSession(session);\n\n        } catch (final WebApplicationException e) {\n            invalidateCurrentSession(request);\n            throw e;\n        } catch (final KuraException e) {\n            invalidateCurrentSession(request);\n            if (e.getCode() == KuraErrorCode.SECURITY_EXCEPTION) {\n                auditLogger.warn(AUDIT_FORMAT_STRING, AuditContext.currentOrInternal(),\n                        BAD_USERNAME_OR_PASSWORD_MESSAGE);\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED,\n                        BAD_USERNAME_OR_PASSWORD_MESSAGE);\n            }\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        } catch (final Exception e) {\n            invalidateCurrentSession(request);\n            auditLogger.warn(AUDIT_FORMAT_STRING, AuditContext.currentOrInternal(), BAD_USERNAME_OR_PASSWORD_MESSAGE);\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED,\n                    BAD_USERNAME_OR_PASSWORD_MESSAGE);\n        }\n    }\n\n    @POST\n    @Path(SessionRestServiceConstants.LOGOUT_PATH)\n    public void logout(@Context final HttpServletRequest request, @Context final HttpServletResponse response,\n            @Context final ContainerRequestContext requestContext) {\n        if (!options.isSessionManagementEnabled()) {\n            throw new WebApplicationException(Status.NOT_FOUND);\n        }\n\n        if (!this.restSessionHelper.getCurrentPrincipal(requestContext).isPresent()) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED, INVALID_SESSION_MESSAGE);\n        }\n\n        this.restSessionHelper.logout(request, response);\n\n        auditLogger.info(\"{} Rest - Success - Logout succeeded\", AuditContext.currentOrInternal());\n    }\n\n    @GET\n    @Path(SessionRestServiceConstants.CURRENT_IDENTITY)\n    @Produces(MediaType.APPLICATION_JSON)\n    public IdentityInfoDTO getCurrentIdentityInfo(@Context final ContainerRequestContext requestContext,\n            @Context final HttpServletRequest request) {\n        if (!options.isSessionManagementEnabled()) {\n            throw new WebApplicationException(Status.NOT_FOUND);\n        }\n\n        final Optional<Principal> currentPrincipal = this.restSessionHelper.getCurrentPrincipal(requestContext);\n\n        if (!currentPrincipal.isPresent()) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.UNAUTHORIZED, INVALID_SESSION_MESSAGE);\n        }\n\n        final String identityName = currentPrincipal.get().getName();\n        try {\n            final Set<String> permissions = this.identityHelper.getAssignedPermissions(identityName).stream()\n                    .map(p -> p.getName()).collect(java.util.stream.Collectors.toSet());\n            final boolean needsPasswordChange = this.identityHelper.isPasswordChangeRequired(identityName);\n\n            return new IdentityInfoDTO(identityName, needsPasswordChange, permissions);\n        } catch (final Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @GET\n    @Path(SessionRestServiceConstants.AUTHENTICATION_INFO)\n    @Produces(MediaType.APPLICATION_JSON)\n    public AuthenticationInfoDTO getAuthenticationMethodInfo() {\n\n        final boolean isPasswordAuthEnabled = options.isPasswordAuthEnabled();\n        final boolean isCertificateAuthenticationEnabled = options.isCertificateAuthEnabled();\n\n        final String preLoginBannerMessage = loginBannerService.getPreLoginBanner().orElse(null);\n\n        if (!isCertificateAuthenticationEnabled) {\n            return new AuthenticationInfoDTO(isPasswordAuthEnabled, false, null, preLoginBannerMessage);\n        }\n\n        final Map<String, Object> httpServiceConfig = ConfigurationAdminHelper\n                .loadHttpServiceConfigurationProperties(configAdmin);\n\n        final Set<Integer> httpsClientAuthPorts = ConfigurationAdminHelper.getHttpsMutualAuthPorts(httpServiceConfig);\n\n        if (!httpsClientAuthPorts.isEmpty()) {\n            return new AuthenticationInfoDTO(isPasswordAuthEnabled, true, httpsClientAuthPorts, preLoginBannerMessage);\n        } else {\n            return new AuthenticationInfoDTO(isPasswordAuthEnabled, false, null, preLoginBannerMessage);\n        }\n\n    }\n\n    private void validatePasswordStrength(final String newPassword) {\n        PasswordStrengthRequirements passwordStrengthRequirements;\n        try {\n            passwordStrengthRequirements = this.passwordStrengthVerificationService.getPasswordStrengthRequirements();\n        } catch (KuraException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        final ValidatorOptions validationOptions = new ValidatorOptions(\n                passwordStrengthRequirements.getPasswordMinimumLength(), passwordStrengthRequirements.digitsRequired(),\n                passwordStrengthRequirements.bothCasesRequired(),\n                passwordStrengthRequirements.specialCharactersRequired());\n\n        final List<Validator<String>> validators = PasswordStrengthValidators.fromConfig(validationOptions);\n\n        final List<String> errors = new ArrayList<>();\n\n        for (final Validator<String> validator : validators) {\n            validator.validate(newPassword, errors::add);\n\n            if (!errors.isEmpty()) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                        \"The new password does not satisfy password strenght requirements: \" + errors.get(0));\n            }\n        }\n    }\n\n    private AuthenticationResponseDTO buildAuthenticationResponse(final String username,\n            final Optional<String> message) {\n        final boolean needsPasswordChange;\n        try {\n            needsPasswordChange = this.identityHelper.isPasswordChangeRequired(username);\n        } catch (final Exception e) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.INTERNAL_SERVER_ERROR,\n                    \"An internal error occurred\");\n        }\n\n        if (message.isPresent()) {\n            return new AuthenticationResponseDTO(needsPasswordChange, message.get());\n        }\n\n        return new AuthenticationResponseDTO(needsPasswordChange);\n    }\n\n    private void invalidateCurrentSession(final HttpServletRequest request) {\n        final HttpSession currentSession = request.getSession(false);\n\n        if (currentSession != null) {\n            currentSession.invalidate();\n        }\n    }\n\n    private boolean isSamePassword(final String username, final String newPassword) {\n        try {\n            final Optional<PasswordHash> existingHash = this.identityHelper.getPasswordHash(username);\n            if (!existingHash.isPresent()) {\n                return false;\n            }\n\n            final PasswordHash newHash = this.identityHelper.computePasswordHash(newPassword.toCharArray());\n            return existingHash.get().equals(newHash);\n        } catch (final Exception e) {\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/SessionRestServiceConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.auth;\n\npublic class SessionRestServiceConstants {\n\n    public static final String BASE_PATH = \"/session/v1\";\n    public static final String LOGIN_PASSWORD_PATH = \"/login/password\";\n    public static final String LOGIN_CERTIFICATE_PATH = \"/login/certificate\";\n    public static final String XSRF_TOKEN_PATH = \"/xsrfToken\";\n    public static final String CHANGE_PASSWORD_PATH = \"/changePassword\";\n    public static final String LOGOUT_PATH = \"/logout\";\n    public static final String CURRENT_IDENTITY = \"/currentIdentity\";\n    public static final String AUTHENTICATION_INFO = \"/authenticationInfo\";\n\n    private SessionRestServiceConstants() {\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/dto/AuthenticationInfoDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.auth.dto;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\npublic class AuthenticationInfoDTO {\n\n    private final boolean passwordAuthenticationEnabled;\n    private final boolean certificateAuthenticationEnabled;\n    private final List<Integer> certificateAuthenticationPorts;\n    private final String message;\n\n    public AuthenticationInfoDTO(boolean passwordAuthenticationEnabled, boolean certificateAuthenticationEnabled,\n            Set<Integer> certificateAuthenticationPorts, final String message) {\n        this.passwordAuthenticationEnabled = passwordAuthenticationEnabled;\n        this.certificateAuthenticationEnabled = certificateAuthenticationEnabled;\n\n        if (certificateAuthenticationPorts != null) {\n            this.certificateAuthenticationPorts = new ArrayList<>(certificateAuthenticationPorts);\n            this.certificateAuthenticationPorts.sort(null);\n        } else {\n            this.certificateAuthenticationPorts = null;\n        }\n\n        this.message = message;\n    }\n\n    public boolean isPasswordAuthenticationEnabled() {\n        return this.passwordAuthenticationEnabled;\n    }\n\n    public boolean isCertificateAuthenticationEnabled() {\n        return this.certificateAuthenticationEnabled;\n    }\n\n    public List<Integer> getCertificateAuthenticationPorts() {\n        return this.certificateAuthenticationPorts;\n    }\n\n    public String getMessage() {\n        return this.message;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/dto/AuthenticationResponseDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.auth.dto;\n\npublic class AuthenticationResponseDTO {\n\n    private final boolean passwordChangeNeeded;\n    private final String message;\n\n    public AuthenticationResponseDTO(final boolean passwordChangeNeeded) {\n        this.passwordChangeNeeded = passwordChangeNeeded;\n        this.message = null;\n    }\n\n    public AuthenticationResponseDTO(final boolean passwordChangeNeeded, final String message) {\n        this.passwordChangeNeeded = passwordChangeNeeded;\n        this.message = message;\n    }\n\n    public boolean isPasswordChangeNeeded() {\n        return this.passwordChangeNeeded;\n    }\n\n    public String getMessage() {\n        return this.message;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/dto/IdentityInfoDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.auth.dto;\n\nimport java.util.Set;\n\npublic class IdentityInfoDTO {\n\n    private final String name;\n    private final boolean passwordChangeNeeded;\n    private final Set<String> permissions;\n\n    public IdentityInfoDTO(String name, boolean passwordChangeNeeded, Set<String> permissions) {\n        this.name = name;\n        this.passwordChangeNeeded = passwordChangeNeeded;\n        this.permissions = permissions;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public boolean isPasswordChangeNeeded() {\n        return passwordChangeNeeded;\n    }\n\n    public Set<String> getPermissions() {\n        return permissions;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/dto/UpdatePasswordDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.auth.dto;\n\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\n\npublic class UpdatePasswordDTO {\n\n    private final String currentPassword;\n    private final String newPassword;\n\n    public UpdatePasswordDTO(String currentPassword, String newPassword) {\n        this.currentPassword = currentPassword;\n        this.newPassword = newPassword;\n    }\n\n    public String getCurrentPassword() {\n        return currentPassword;\n    }\n\n    public String getNewPassword() {\n        return newPassword;\n    }\n\n    public void validate() {\n        if (currentPassword == null || currentPassword.trim().isEmpty() || newPassword == null\n                || newPassword.trim().isEmpty()) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                    \"currentPassword or newPassword have not been provided\");\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/dto/UsernamePasswordDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.auth.dto;\n\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\n\npublic class UsernamePasswordDTO {\n\n    private final String username;\n    private final String password;\n\n    public UsernamePasswordDTO(String username, String password) {\n        this.username = username;\n        this.password = password;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void validate() {\n        if (username == null || username.trim().isEmpty() || password == null\n                || password.trim().isEmpty()) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                    \"username and or password fields have not been provided\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/auth/dto/XsrfTokenDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.auth.dto;\n\npublic class XsrfTokenDTO {\n\n    private final String xsrfToken;\n\n    public XsrfTokenDTO(final String xsrfToken) {\n        this.xsrfToken = xsrfToken;\n    }\n\n    public String getXsrfToken() {\n        return xsrfToken;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/provider/AuditFilter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.internal.rest.provider;\n\nimport java.io.IOException;\n\nimport org.eclipse.kura.audit.AuditContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.container.ContainerResponseContext;\nimport jakarta.ws.rs.container.ContainerResponseFilter;\nimport jakarta.ws.rs.core.Context;\n\npublic class AuditFilter implements ContainerResponseFilter {\n\n    private static final Logger auditLogger = LoggerFactory.getLogger(\"AuditLogger\");\n\n    @Context\n    private HttpServletRequest request;\n\n    @Override\n    public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext)\n            throws IOException {\n        int responseStatus = responseContext.getStatus();\n\n        final AuditContext auditContext = RestServiceUtils.initAuditContext(requestContext, request);\n\n        try {\n            if (responseContext.getStatus() == 404) {\n                auditLogger.warn(\"{} Rest - Failure - Service not found\", auditContext);\n                return;\n            }\n\n            if (responseContext.getStatus() == 403) {\n                if (requestContext.getSecurityContext() == null\n                        || requestContext.getSecurityContext().getUserPrincipal() == null) {\n                    responseContext.setStatus(401);\n                } else {\n                    auditLogger.warn(\"{} Rest - Failure - User not authorized to perform the requested operation\",\n                            auditContext);\n                    return;\n                }\n\n            }\n\n            if (responseContext.getStatus() == 401) {\n                auditLogger.warn(\"{} Rest - Failure - User not authenticated\", auditContext);\n                return;\n            }\n\n            if (responseStatus >= 200 && responseStatus < 400) {\n                auditLogger.info(\"{} Rest - Success - Rest request succeeded\", auditContext);\n            } else {\n                auditLogger.warn(\"{} Rest - Failure - Request failed\", auditContext);\n            }\n        } finally {\n            RestServiceUtils.closeAuditContext(requestContext);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/provider/AuthenticationFilter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.internal.rest.provider;\n\nimport java.io.IOException;\nimport java.security.Principal;\nimport java.util.Iterator;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.eclipse.kura.audit.AuditConstants;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.Permission;\nimport org.eclipse.kura.rest.auth.AuthenticationProvider;\n\nimport jakarta.annotation.Priority;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\nimport jakarta.ws.rs.Priorities;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.container.ContainerRequestFilter;\nimport jakarta.ws.rs.core.Context;\nimport jakarta.ws.rs.core.SecurityContext;\nimport jakarta.ws.rs.ext.Provider;\n\n@Provider\n@Priority(Priorities.AUTHENTICATION)\npublic class AuthenticationFilter implements ContainerRequestFilter {\n\n    private static final String KURA_ADMIN_PERMISSION = \"kura.admin\";\n\n    private final Set<AuthenticationProviderHolder> authenticationProviders = new TreeSet<>();\n    private IdentityService identityService;\n\n    @Context\n    private HttpServletRequest request;\n    @Context\n    private HttpServletResponse response;\n\n    public void setIdentityService(final IdentityService identityService) {\n        this.identityService = identityService;\n    }\n\n    public void registerAuthenticationProvider(final AuthenticationProvider authenticationProvider) {\n        synchronized (this.authenticationProviders) {\n            final AuthenticationProviderHolder holder = new AuthenticationProviderHolder(authenticationProvider);\n            this.authenticationProviders.add(holder);\n            holder.onEnabled();\n        }\n    }\n\n    public void unregisterAuthenticationProvider(final AuthenticationProvider authenticationProvider) {\n        synchronized (this.authenticationProviders) {\n            final AuthenticationProviderHolder holder = new AuthenticationProviderHolder(authenticationProvider);\n            if (this.authenticationProviders.remove(holder)) {\n                holder.onDisabled();\n            }\n        }\n    }\n\n    @Override\n    public void filter(final ContainerRequestContext requestContext) throws IOException {\n\n        RestServiceUtils.initAuditContext(requestContext, request);\n\n        final Optional<Principal> principal = authenticate(requestContext);\n        final boolean isSecure = requestContext.getUriInfo().getRequestUri().getScheme().equals(\"https\");\n\n        if (principal.isPresent()) {\n            final AuditContext auditContext = AuditContext.currentOrInternal();\n            auditContext.getProperties().put(AuditConstants.KEY_IDENTITY.getValue(), principal.get().getName());\n\n            requestContext.setSecurityContext(new SecurityContext() {\n\n                final Principal currentPrincipal = principal.get();\n\n                @Override\n                public String getAuthenticationScheme() {\n                    return null;\n                }\n\n                @Override\n                public Principal getUserPrincipal() {\n                    return currentPrincipal;\n                }\n\n                @Override\n                public boolean isSecure() {\n                    return isSecure;\n                }\n\n                @Override\n                public boolean isUserInRole(final String role) {\n                    return AuthenticationFilter.this.isUserInRole(currentPrincipal, role);\n                }\n            });\n        }\n    }\n\n    private Optional<Principal> authenticate(final ContainerRequestContext requestContext) {\n        synchronized (this.authenticationProviders) {\n            for (final AuthenticationProviderHolder provider : this.authenticationProviders) {\n                final Optional<Principal> principal = provider.authenticate(request, requestContext);\n\n                if (principal.isPresent()) {\n                    return principal;\n                }\n            }\n        }\n\n        return Optional.empty();\n    }\n\n    private boolean isUserInRole(final Principal requestUser, final String role) {\n        // Unified authorization path for all identities (regular and temporary)\n        try {\n            this.identityService.checkPermission(requestUser.getName(), new Permission(\"rest.\" + role));\n            return true;\n        } catch (final Exception e) {\n            try {\n                this.identityService.checkPermission(requestUser.getName(), new Permission(KURA_ADMIN_PERMISSION));\n                return true;\n            } catch (final Exception ignored) {\n                return false;\n            }\n        }\n    }\n\n    public void close() {\n        synchronized (this.authenticationProviders) {\n            final Iterator<AuthenticationProviderHolder> iter = this.authenticationProviders.iterator();\n            while (iter.hasNext()) {\n                iter.next().onDisabled();\n                iter.remove();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/provider/AuthenticationProviderHolder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.provider;\n\nimport java.security.Principal;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport jakarta.annotation.Priority;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.ws.rs.container.ContainerRequestContext;\n\nimport org.eclipse.kura.rest.auth.AuthenticationProvider;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nclass AuthenticationProviderHolder implements Comparable<AuthenticationProviderHolder>, AuthenticationProvider {\n\n    private static final Logger logger = LoggerFactory.getLogger(AuthenticationProviderHolder.class);\n\n    private final int priority;\n    private final AuthenticationProvider wrapped;\n\n    public AuthenticationProviderHolder(final AuthenticationProvider provider) {\n        this.priority = getPriority(provider.getClass());\n        this.wrapped = provider;\n    }\n\n    private static int getPriority(final Class<?> classz) {\n        if (classz == Object.class) {\n            return Integer.MAX_VALUE;\n        }\n\n        final Priority priorityAnnotation = classz.getAnnotation(Priority.class);\n\n        if (priorityAnnotation != null) {\n            return priorityAnnotation.value();\n        }\n\n        return getPriority(classz.getSuperclass());\n    }\n\n    @Override\n    public Optional<Principal> authenticate(final HttpServletRequest request,\n            final ContainerRequestContext requestContext) {\n        try {\n            return wrapped.authenticate(request, requestContext);\n        } catch (final Exception e) {\n            logger.warn(\"Unexpected exception calling authentication provider\", e);\n            return Optional.empty();\n        }\n    }\n\n    @Override\n    public void onEnabled() {\n        try {\n            this.wrapped.onEnabled();\n        } catch (final Exception e) {\n            logger.warn(\"Unexpected exception enabling authentication provider\", e);\n        }\n    }\n\n    @Override\n    public void onDisabled() {\n        try {\n            this.wrapped.onDisabled();\n        } catch (final Exception e) {\n            logger.warn(\"Unexpected exception disabling authentication provider\", e);\n        }\n    }\n\n    @Override\n    public int compareTo(AuthenticationProviderHolder other) {\n        return Integer.compare(this.priority, other.priority);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(priority, wrapped);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof AuthenticationProviderHolder)) {\n            return false;\n        }\n        AuthenticationProviderHolder other = (AuthenticationProviderHolder) obj;\n        return priority == other.priority && Objects.equals(wrapped, other.wrapped);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/provider/AuthorizationFilter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.internal.rest.provider;\n\nimport java.io.IOException;\nimport java.util.Arrays;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.Priority;\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.ws.rs.Priorities;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.container.ContainerRequestFilter;\nimport jakarta.ws.rs.container.ResourceInfo;\nimport jakarta.ws.rs.core.Context;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.core.Response.Status;\nimport jakarta.ws.rs.core.SecurityContext;\nimport jakarta.ws.rs.ext.Provider;\n\n@Provider\n@Priority(Priorities.AUTHORIZATION)\npublic class AuthorizationFilter implements ContainerRequestFilter {\n\n    private static final Logger logger = LoggerFactory.getLogger(AuthorizationFilter.class);\n\n    @Context\n    private ResourceInfo resourceInfo;\n\n    @Context\n    private HttpServletRequest request;\n\n    @Override\n    public void filter(final ContainerRequestContext context) throws IOException {\n        final RolesAllowed rolesAllowed = resourceInfo.getResourceMethod().getAnnotation(RolesAllowed.class);\n\n        if (rolesAllowed != null) {\n            final SecurityContext securityContext = context.getSecurityContext();\n            final String rolesAllowedValue = Arrays.toString(rolesAllowed.value());\n\n            if (securityContext == null) {\n                logger.warn(\"Rest request rejected: missing authentication for {} {} (required roles: {})\",\n                        request.getMethod(), request.getRequestURI(), rolesAllowedValue);\n                context.abortWith(Response.status(Status.FORBIDDEN).build());\n                return;\n            }\n\n            if (securityContext.getUserPrincipal() == null) {\n                logger.warn(\"Rest request rejected: missing user principal for {} {} (required roles: {})\",\n                        request.getMethod(), request.getRequestURI(), rolesAllowedValue);\n                context.abortWith(Response.status(Status.FORBIDDEN).build());\n                return;\n            }\n\n            for (final String role : rolesAllowed.value()) {\n                if (securityContext.isUserInRole(role)) {\n                    return;\n                }\n            }\n\n            logger.warn(\"Rest request rejected: user '{}' not authorized for {} {} (required roles: {})\",\n                    securityContext.getUserPrincipal().getName(), request.getMethod(), request.getRequestURI(),\n                    rolesAllowedValue);\n            context.abortWith(Response.status(Status.FORBIDDEN).build());\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/provider/GsonSerializer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.internal.rest.provider;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Type;\nimport java.nio.charset.StandardCharsets;\n\nimport com.google.gson.Gson;\n\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.WebApplicationException;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.MultivaluedMap;\nimport jakarta.ws.rs.ext.MessageBodyReader;\nimport jakarta.ws.rs.ext.MessageBodyWriter;\nimport jakarta.ws.rs.ext.Provider;\n\n@Provider\n@Produces(MediaType.APPLICATION_JSON)\n@Consumes(MediaType.APPLICATION_JSON)\npublic class GsonSerializer<T> implements MessageBodyReader<T>, MessageBodyWriter<T> {\n\n    private static final Gson GSON = new Gson();\n\n    @Override\n    public boolean isWriteable(Class<?> arg0, Type arg1, Annotation[] arg2, MediaType arg3) {\n        return true;\n    }\n\n    @Override\n    public void writeTo(T object, Class<?> arg1, Type arg2, Annotation[] arg3, MediaType arg4,\n            MultivaluedMap<String, Object> arg5, OutputStream entityStream)\n            throws IOException, WebApplicationException {\n        try (final OutputStreamWriter writer = new OutputStreamWriter(entityStream, StandardCharsets.UTF_8)) {\n            GSON.toJson(object, writer);\n        }\n    }\n\n    @Override\n    public boolean isReadable(Class<?> arg0, Type arg1, Annotation[] arg2, MediaType arg3) {\n        return true;\n    }\n\n    @Override\n    public T readFrom(Class<T> type, Type arg1, Annotation[] arg2, MediaType arg3, MultivaluedMap<String, String> arg4,\n            InputStream stream) throws IOException, WebApplicationException {\n        try (final InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8)) {\n            return GSON.fromJson(reader, type);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/provider/IncomingPortCheckFilter.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.internal.rest.provider;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.Set;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.Priority;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.ws.rs.Priorities;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.container.ContainerRequestFilter;\nimport jakarta.ws.rs.core.Context;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.ext.Provider;\n\n@Provider\n@Priority(Priorities.AUTHENTICATION - 100)\nclass IncomingPortCheckFilter implements ContainerRequestFilter {\n\n    private static final Logger logger = LoggerFactory.getLogger(IncomingPortCheckFilter.class);\n\n    @Context\n    private HttpServletRequest request;\n\n    private Set<Integer> allowedPorts = Collections.emptySet();\n\n    public void setAllowedPorts(final Set<Integer> allowedPorts) {\n        this.allowedPorts = allowedPorts;\n    }\n\n    @Override\n    public void filter(final ContainerRequestContext requestContext) throws IOException {\n\n        RestServiceUtils.initAuditContext(requestContext, request);\n\n        if (allowedPorts.isEmpty()) {\n            return;\n        }\n\n        final int port = request.getLocalPort();\n\n        if (!allowedPorts.contains(port)) {\n            logger.warn(\"Rest request rejected on port {} for {} {} (allowed ports: {})\", port, request.getMethod(),\n                    request.getRequestURI(), allowedPorts);\n            requestContext.abortWith(Response.status(Response.Status.NOT_FOUND).build());\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/provider/RestService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.internal.rest.provider;\n\nimport static org.eclipse.kura.internal.rest.auth.SessionRestServiceConstants.BASE_PATH;\nimport static org.eclipse.kura.internal.rest.auth.SessionRestServiceConstants.CHANGE_PASSWORD_PATH;\nimport static org.eclipse.kura.internal.rest.auth.SessionRestServiceConstants.XSRF_TOKEN_PATH;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.identity.LoginBannerService;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.internal.rest.auth.BasicAuthenticationProvider;\nimport org.eclipse.kura.internal.rest.auth.CertificateAuthenticationProvider;\nimport org.eclipse.kura.internal.rest.auth.RestIdentityHelper;\nimport org.eclipse.kura.internal.rest.auth.RestSessionHelper;\nimport org.eclipse.kura.internal.rest.auth.SessionAuthProvider;\nimport org.eclipse.kura.internal.rest.auth.SessionRestService;\nimport org.eclipse.kura.rest.auth.AuthenticationProvider;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.ConfigurationPolicy;\nimport org.osgi.service.component.annotations.Deactivate;\nimport org.osgi.service.component.annotations.Modified;\nimport org.osgi.service.component.annotations.Reference;\nimport org.osgi.service.component.annotations.ReferenceCardinality;\nimport org.osgi.service.component.annotations.ReferencePolicy;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.ws.rs.container.ContainerRequestFilter;\nimport jakarta.ws.rs.container.ContainerResponseFilter;\nimport jakarta.ws.rs.ext.MessageBodyReader;\nimport jakarta.ws.rs.ext.MessageBodyWriter;\n\n@Component(immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE)\npublic class RestService implements ConfigurableComponent {\n\n    private static final String KURA_DEFAULT_JAKARTARS_WHITEBOARD_NAME = \"KuraDefaultJakartarsWhiteboard\";\n\n    private static final Logger logger = LoggerFactory.getLogger(RestService.class);\n\n    private IdentityService identityService;\n    private ConfigurationAdmin configurationAdmin;\n\n    private RestServiceOptions options;\n\n    private final List<ServiceRegistration<?>> registeredServices = new ArrayList<>();\n\n    private AuthenticationProvider basicAuthProvider;\n    private AuthenticationProvider certificateAuthProvider;\n\n    private SessionAuthProvider sessionAuthenticationProvider;\n    private SessionRestService authRestService;\n\n    private final IncomingPortCheckFilter incomingPortCheckFilter = new IncomingPortCheckFilter();\n    private final AuthenticationFilter authenticationFilter = new AuthenticationFilter();\n    private PasswordStrengthVerificationService passwordStrengthVerificationService;\n    private LoginBannerService loginBannerService;\n\n    @Reference\n    public void setIdentityService(final IdentityService identityService) {\n        this.identityService = identityService;\n        this.authenticationFilter.setIdentityService(identityService);\n    }\n\n    @Reference\n    public void setConfigurationAdmin(final ConfigurationAdmin configurationAdmin) {\n        this.configurationAdmin = configurationAdmin;\n    }\n\n    @Reference\n    public void setPasswordStrengthVerificationService(\n            PasswordStrengthVerificationService passwordStrengthVerificationService) {\n        this.passwordStrengthVerificationService = passwordStrengthVerificationService;\n    }\n\n    @Reference\n    public void setLoginBannerService(LoginBannerService loginBannerService) {\n        this.loginBannerService = loginBannerService;\n    }\n\n    @Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)\n    public void bindAuthenticationProvider(final AuthenticationProvider provider) {\n        this.authenticationFilter.registerAuthenticationProvider(provider);\n    }\n\n    public void unbindAuthenticationProvider(final AuthenticationProvider provider) {\n        this.authenticationFilter.unregisterAuthenticationProvider(provider);\n    }\n\n    @Activate\n    public void activate(final Map<String, Object> properties) {\n        logger.info(\"activating...\");\n\n        final BundleContext bundleContext = FrameworkUtil.getBundle(RestService.class).getBundleContext();\n\n        final RestIdentityHelper identityHelper = new RestIdentityHelper(this.identityService);\n        final RestSessionHelper restSessionHelper = new RestSessionHelper(identityHelper);\n        final Dictionary<String, Object> serviceProperties = RestServiceUtils.extensionProperties();\n\n        registeredServices.add(bundleContext.registerService(ContainerRequestFilter.class, this.incomingPortCheckFilter,\n                serviceProperties));\n        registeredServices.add(bundleContext.registerService(ContainerRequestFilter.class, this.authenticationFilter,\n                serviceProperties));\n        registeredServices.add(bundleContext.registerService(ContainerRequestFilter.class, new AuthorizationFilter(),\n                serviceProperties));\n        registeredServices.add(\n                bundleContext.registerService(ContainerResponseFilter.class, new AuditFilter(), serviceProperties));\n        registeredServices.add(bundleContext.registerService(\n                new String[] { MessageBodyReader.class.getName(), MessageBodyWriter.class.getName() },\n                new GsonSerializer<Object>(), serviceProperties));\n\n        this.basicAuthProvider = new BasicAuthenticationProvider(bundleContext, identityHelper);\n        this.certificateAuthProvider = new CertificateAuthenticationProvider(identityHelper);\n        this.sessionAuthenticationProvider = new SessionAuthProvider(//\n                restSessionHelper,\n                new HashSet<>(Arrays.asList(BASE_PATH + CHANGE_PASSWORD_PATH, BASE_PATH + XSRF_TOKEN_PATH)),\n                Collections.singleton(BASE_PATH + XSRF_TOKEN_PATH));\n\n        this.authRestService = new SessionRestService(identityHelper, restSessionHelper, this.configurationAdmin,\n                this.passwordStrengthVerificationService, this.loginBannerService);\n\n        this.registeredServices.add(bundleContext.registerService(SessionRestService.class, this.authRestService,\n                RestServiceUtils.resourceProperties()));\n\n        update(properties);\n\n        try {\n            configureDefaultWhiteboard();\n        } catch (final Exception e) {\n            logger.error(\"failed to configure JakartarsServletWhiteboard whiteboard\", e);\n        }\n\n        logger.info(\"activating...done\");\n    }\n\n    private void configureDefaultWhiteboard() throws IOException, InvalidSyntaxException {\n\n        final Configuration[] configs = this.configurationAdmin.listConfigurations(\n                \"(jersey.jakartars.whiteboard.name=\" + KURA_DEFAULT_JAKARTARS_WHITEBOARD_NAME + \")\");\n\n        if (configs == null) {\n            final Dictionary<String, Object> properties = new Hashtable<>();\n\n            properties.put(\"jersey.context.path\", \"/services\");\n            properties.put(\"jersey.jakartars.whiteboard.name\", KURA_DEFAULT_JAKARTARS_WHITEBOARD_NAME);\n\n            final Configuration newConfiguration = this.configurationAdmin\n                    .createFactoryConfiguration(\"JakartarsServletWhiteboardRuntimeComponent\", null);\n\n            newConfiguration.update(properties);\n\n        }\n\n    }\n\n    @Modified\n    public void update(final Map<String, Object> properties) {\n        logger.info(\"updating...\");\n\n        final RestServiceOptions newOptions = new RestServiceOptions(properties);\n\n        if (!Objects.equals(this.options, newOptions)) {\n            this.options = newOptions;\n            this.authRestService.setOptions(newOptions);\n            this.sessionAuthenticationProvider.setOptions(newOptions);\n            this.incomingPortCheckFilter.setAllowedPorts(newOptions.getAllowedPorts());\n\n            updateBuiltinAuthenticationProviders(newOptions);\n        }\n\n        logger.info(\"updating...done\");\n    }\n\n    @Deactivate\n    public void deactivate() {\n        logger.info(\"deactivating...\");\n\n        for (final ServiceRegistration<?> reg : registeredServices) {\n            reg.unregister();\n        }\n\n        this.authenticationFilter.close();\n\n        logger.info(\"deactivating...done\");\n    }\n\n    private void updateBuiltinAuthenticationProviders(final RestServiceOptions options) {\n        if (options.isPasswordAuthEnabled() && options.isBasicAuthEnabled()) {\n            bindAuthenticationProvider(this.basicAuthProvider);\n        } else {\n            unbindAuthenticationProvider(basicAuthProvider);\n        }\n\n        if (options.isCertificateAuthEnabled() && options.isStatelessCertificateAuthEnabled()) {\n            bindAuthenticationProvider(this.certificateAuthProvider);\n        } else {\n            unbindAuthenticationProvider(this.certificateAuthProvider);\n        }\n\n        if (options.isSessionManagementEnabled()) {\n            bindAuthenticationProvider(this.sessionAuthenticationProvider);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/provider/RestServiceOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.internal.rest.provider;\n\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class RestServiceOptions {\n\n    private static final Property<Integer[]> ALLOWED_PORTS = new Property<>(\"allowed.ports\", new Integer[] {});\n    private static final Property<Boolean> PASSWORD_AUTH_ENABLED = new Property<>(\"auth.password.enabled\", true);\n    private static final Property<Boolean> CERTIFICATE_AUTH_ENABLED = new Property<>(\"auth.certificate.enabled\", true);\n    private static final Property<Boolean> SESSION_MANAGEMENT_ENABLED = new Property<>(\"session.management.enabled\",\n            true);\n    private static final Property<Integer> SESSION_INACTIVITY_INTERVAL = new Property<>(\"session.inactivity.interval\",\n            900);\n    private static final Property<Boolean> BASIC_AUTHENTICATION_ENABLED = new Property<>(\"auth.basic.enabled\", true);\n    private static final Property<Boolean> STATELESS_CERTIFICATE_AUTHENTICATION_ENABLED = new Property<>(\n            \"auth.certificate.stateless.enabled\",\n            true);\n\n    private final Set<Integer> allowedPorts;\n    private final boolean passwordAuthEnabled;\n    private final boolean certificateAuthEnabled;\n    private final boolean sessionManagementEnabled;\n    private final int sessionInactivityInterval;\n    private final boolean basicAuthEnabled;\n    private final boolean statelessCertificateAuthEnabled;\n\n    public RestServiceOptions(final Map<String, Object> properties) {\n        this.allowedPorts = loadIntArrayProperty(ALLOWED_PORTS.get(properties));\n        this.passwordAuthEnabled = PASSWORD_AUTH_ENABLED.get(properties);\n        this.certificateAuthEnabled = CERTIFICATE_AUTH_ENABLED.get(properties);\n        this.sessionManagementEnabled = SESSION_MANAGEMENT_ENABLED.get(properties);\n        this.sessionInactivityInterval = SESSION_INACTIVITY_INTERVAL.get(properties);\n        this.basicAuthEnabled = BASIC_AUTHENTICATION_ENABLED.get(properties);\n        this.statelessCertificateAuthEnabled = STATELESS_CERTIFICATE_AUTHENTICATION_ENABLED.get(properties);\n    }\n\n    public Set<Integer> getAllowedPorts() {\n        return allowedPorts;\n    }\n\n    public boolean isPasswordAuthEnabled() {\n        return passwordAuthEnabled;\n    }\n\n    public boolean isCertificateAuthEnabled() {\n        return certificateAuthEnabled;\n    }\n\n    public boolean isSessionManagementEnabled() {\n        return sessionManagementEnabled;\n    }\n\n    public int getSessionInactivityInterval() {\n        return sessionInactivityInterval;\n    }\n\n    public boolean isBasicAuthEnabled() {\n        return basicAuthEnabled;\n    }\n\n    public boolean isStatelessCertificateAuthEnabled() {\n        return statelessCertificateAuthEnabled;\n    }\n\n    private static Set<Integer> loadIntArrayProperty(final Integer[] list) {\n        if (list == null) {\n            return Collections.emptySet();\n        }\n\n        final Set<Integer> result = new HashSet<>();\n\n        for (int i = 0; i < list.length; i++) {\n            final Integer value = list[i];\n\n            if (value != null) {\n                result.add(value);\n            }\n        }\n\n        return result;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(allowedPorts, basicAuthEnabled, certificateAuthEnabled, passwordAuthEnabled,\n                sessionInactivityInterval, sessionManagementEnabled, statelessCertificateAuthEnabled);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (!(obj instanceof RestServiceOptions)) {\n            return false;\n        }\n        RestServiceOptions other = (RestServiceOptions) obj;\n        return Objects.equals(allowedPorts, other.allowedPorts) && basicAuthEnabled == other.basicAuthEnabled\n                && certificateAuthEnabled == other.certificateAuthEnabled\n                && passwordAuthEnabled == other.passwordAuthEnabled\n                && sessionInactivityInterval == other.sessionInactivityInterval\n                && sessionManagementEnabled == other.sessionManagementEnabled\n                && statelessCertificateAuthEnabled == other.statelessCertificateAuthEnabled;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/internal/rest/provider/RestServiceUtils.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.internal.rest.provider;\n\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.Hashtable;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.audit.AuditConstants;\nimport org.eclipse.kura.audit.AuditContext;\nimport org.eclipse.kura.audit.AuditContext.Scope;\n\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.core.PathSegment;\n\npublic final class RestServiceUtils {\n\n    private RestServiceUtils() {\n    }\n\n    public static AuditContext initAuditContext(final ContainerRequestContext requestContext,\n            final HttpServletRequest request) {\n\n        final Object rawContext = requestContext.getProperty(\"org.eclipse.kura.rest.audit.context\");\n\n        if (rawContext != null) {\n            return (AuditContext) rawContext;\n        }\n\n        final Map<String, String> properties = new HashMap<>();\n\n        String requestIp = requestContext.getHeaderString(\"X-FORWARDED-FOR\");\n        if (requestIp == null) {\n            requestIp = request.getRemoteAddr();\n        }\n\n        properties.put(AuditConstants.KEY_ENTRY_POINT.getValue(), \"RestService\");\n        properties.put(AuditConstants.KEY_IP.getValue(), requestIp);\n        properties.put(\"rest.method\", requestContext.getMethod());\n        properties.put(\"rest.path\", getRequestPath(requestContext));\n\n        final AuditContext result = new AuditContext(properties);\n\n        final Scope scope = AuditContext.openScope(result);\n\n        requestContext.setProperty(\"org.eclipse.kura.rest.audit.context\", result);\n        requestContext.setProperty(\"org.eclipse.kura.rest.audit.scope\", scope);\n\n        return result;\n    }\n\n    private static String getRequestPath(final ContainerRequestContext request) {\n        List<PathSegment> pathSegments = request.getUriInfo().getPathSegments();\n        Iterator<PathSegment> iterator = pathSegments.iterator();\n        StringBuilder pathBuilder = new StringBuilder();\n\n        while (iterator.hasNext()) {\n            pathBuilder.append(iterator.next().getPath());\n            if (iterator.hasNext()) {\n                pathBuilder.append(\"/\");\n            }\n        }\n\n        return pathBuilder.toString();\n    }\n\n    public static void closeAuditContext(ContainerRequestContext request) {\n        final Object rawScope = request.getProperty(\"org.eclipse.kura.rest.audit.scope\");\n\n        if (rawScope instanceof Scope) {\n            ((Scope) rawScope).close();\n        }\n    }\n\n    public static Dictionary<String, Object> singletonDictionary(final String key, final Object value) {\n        final Dictionary<String, Object> result = new Hashtable<>();\n        result.put(key, value);\n        return result;\n    }\n\n    public static Dictionary<String, Object> resourceProperties() {\n        return singletonDictionary(\"osgi.jakartars.resource\", true);\n    }\n\n    public static Dictionary<String, Object> extensionProperties() {\n        return singletonDictionary(\"osgi.jakartars.extension\", true);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/rest/auth/AuthenticationProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.auth;\n\nimport java.security.Principal;\nimport java.util.Optional;\n\nimport jakarta.servlet.http.HttpServletRequest;\n\nimport org.osgi.annotation.versioning.ProviderType;\n\nimport jakarta.ws.rs.container.ContainerRequestContext;\n\n/**\n * A service interface that allows to register custom authentication providers for the {@code RestService}.\n * Registered {@link AuthenticationProvider} instances will be considered along with the currently enabled\n * built in authentication methods (e.g password and certificate authentication).<br>\n * \n * The registered authentication providers will be called in order, the first provider whose\n * {@link AuthenticationProvider#authenticate(HttpServletRequest, ContainerRequestContext)} returns a non-empty optional\n * will determine a successful authentication.\n * If all providers return an empty optional the call failing with 401 status.<br>\n * \n * The order in which the providers are called can be configured with the {@link jakarta.annotation.Priority} annotation.\n * Lower {@link jakarta.annotation.Priority#value()} values mean higher priority.\n * The priorities of the built-in authentication providers is the following:\n * <ul>\n * <li>Certificate authentication: 100</li>\n * <li>Password authentication: 200</li>\n * </ul>\n */\n@ProviderType\npublic interface AuthenticationProvider {\n\n    /**\n     * This method is called when the {@code RestService} tracks the {@link AuthenticationProvider}\n     */\n    public void onEnabled();\n\n    /**\n     * This method is called when the {@code RestService} stops tracking the {@link AuthenticationProvider}\n     */\n    public void onDisabled();\n\n    /**\n     * Called by the {@code RestService} to authenticate a REST call.\n     * This method should attempt to associate the request with a {@link Principal}, the {@link Principal#getName()}\n     * method must\n     * return a Kura identity name.\n     * \n     * @param request\n     *            The received {@link HttpServletRequest}\n     * @param requestContext\n     *            The received {@link ContainerRequestContext}\n     * @return a non-empty optional reporting the identity name if the authentication is successful, or an empty\n     *         optional if the request cannot be authenticated.\n     */\n    public Optional<Principal> authenticate(final HttpServletRequest request,\n            final ContainerRequestContext requestContext);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/rest/utils/Validable.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.rest.utils;\n\nimport jakarta.ws.rs.WebApplicationException;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.core.Response.Status;\n\npublic interface Validable {\n\n    public boolean isValid();\n\n    public static boolean isValid(Validable validable) {\n        if (validable == null) {\n            return false;\n        }\n        return validable.isValid();\n    }\n\n    public static void validate(Validable validable, String exceptionMessage) {\n        if (!isValid(validable)) {\n            throw new WebApplicationException(\n                    Response.status(Status.BAD_REQUEST).entity(exceptionMessage).type(MediaType.TEXT_PLAIN).build());\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.provider/src/main/java/org/eclipse/kura/rest/utils/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n/**\n * Provides all necessary utility APIs for Kura REST APIs\n *\n * @since 1.1\n */\npackage org.eclipse.kura.rest.utils;"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Security REST Service\nBundle-SymbolicName: org.eclipse.kura.rest.security.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nImport-Package: jakarta.annotation.security;version=\"2.1.1\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.container;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.apache.commons.io;version=\"2.11.0\",\n org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.request.handler.jaxrs;version=\"[2.0,3.0)\",\n org.eclipse.kura.request.handler.jaxrs.annotation;version=\"[1.0,2.0)\",\n org.eclipse.kura.rest.configuration.api;version=\"[1.0,2.0)\",\n org.eclipse.kura.security;version=\"[1.3,2.0)\",\n org.eclipse.kura.system;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.component;version=\"[1.3,2.0)\",\n org.osgi.service.useradmin;version=\"1.1.0\";resolution:=optional,\n org.slf4j;version=\"1.7.25\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/OSGI-INF/SecurityRestServiceV1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" immediate=\"true\"\n               name=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV1\">\n    <implementation class=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV1\"/>\n\n    <property name=\"kura.service.pid\" type=\"String\"\n              value=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV1\"/>\n\n    <reference interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\"\n               bind=\"bindRequestHandlerRegistry\"\n               unbind=\"unbindRequestHandlerRegistry\"\n               cardinality=\"0..n\"\n               name=\"RequestHandlerRegistry\"\n               policy=\"dynamic\"/>\n\n    <reference interface=\"org.eclipse.kura.security.SecurityService\"\n               bind=\"bindSecurityService\"\n               cardinality=\"0..1\"\n               name=\"SecurityService\"\n               policy=\"static\"/>\n\n    <reference interface=\"org.osgi.service.useradmin.UserAdmin\"\n               bind=\"bindUserAdmin\"\n               cardinality=\"1..1\"\n               name=\"UserAdmin\"\n               policy=\"static\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV1\"/>\n    </service>\n\n    <property name=\"service.pid\"\n              type=\"String\"\n              value=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV1\"/>\n    <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/OSGI-INF/SecurityRestServiceV2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" immediate=\"true\"\n               name=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV2\">\n    <implementation class=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV2\"/>\n\n    <property name=\"kura.service.pid\" type=\"String\"\n              value=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV2\"/>\n\n    <reference interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\"\n               bind=\"bindRequestHandlerRegistry\"\n               unbind=\"unbindRequestHandlerRegistry\"\n               cardinality=\"0..n\"\n               name=\"RequestHandlerRegistry\"\n               policy=\"dynamic\"/>\n\n    <reference interface=\"org.eclipse.kura.security.SecurityService\"\n               bind=\"bindSecurityService\"\n               cardinality=\"0..1\"\n               name=\"SecurityService\"\n               policy=\"static\"/>\n\n    <reference interface=\"org.osgi.service.useradmin.UserAdmin\"\n               bind=\"bindUserAdmin\"\n               cardinality=\"1..1\"\n               name=\"UserAdmin\"\n               policy=\"static\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV2\"/>\n    </service>\n\n    <property name=\"service.pid\"\n              type=\"String\"\n              value=\"org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV2\"/>\n              \n    <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <artifactId>org.eclipse.kura.rest.security.provider</artifactId>\n    <packaging>eclipse-plugin</packaging>\n    <version>2.0.0-SNAPSHOT</version>\n    \n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/src/main/java/org/eclipse/kura/internal/rest/security/provider/AbstractRestSecurityService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.rest.security.provider;\n\nimport java.util.Optional;\n\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.internal.rest.security.provider.dto.DebugEnabledDTO;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.eclipse.kura.request.handler.jaxrs.JaxRsRequestHandlerProxy;\nimport org.eclipse.kura.security.SecurityService;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.WebApplicationException;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.core.Context;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response;\n\npublic abstract class AbstractRestSecurityService {\n\n    protected static final Logger logger = LoggerFactory.getLogger(AbstractRestSecurityService.class);\n    protected static final String DEBUG_MESSAGE = \"Processing request for method '{}'\";\n\n    protected static final String REST_ROLE_NAME = \"security\";\n    protected static final String KURA_PERMISSION_REST_ROLE = \"kura.permission.rest.\" + REST_ROLE_NAME;\n\n    protected SecurityService security;\n    protected final RequestHandler requestHandler = new JaxRsRequestHandlerProxy(this);\n\n    public void bindSecurityService(SecurityService securityService) {\n        this.security = securityService;\n    }\n\n    public void bindUserAdmin(UserAdmin userAdmin) {\n        userAdmin.createRole(KURA_PERMISSION_REST_ROLE, Role.GROUP);\n    }\n\n    public void bindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.registerRequestHandler(getMqttAppId(), this.requestHandler);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to register {} request handler\", getMqttAppId(), e);\n        }\n    }\n\n    public void unbindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.unregister(getMqttAppId());\n        } catch (final Exception e) {\n            logger.warn(\"Failed to unregister {} request handler\", getMqttAppId(), e);\n        }\n    }\n\n    public abstract String getMqttAppId();\n\n    /**\n     * POST method <br />\n     * This method allows the reload of the security policy's fingerprint\n     */\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/security-policy-fingerprint/reload\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public Response reloadSecurityPolicyFingerprint() {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"reloadSecurityPolicyFingerprint\");\n            this.security.reloadSecurityPolicyFingerprint();\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    /**\n     * POST method <br />\n     * This method allows the reload of the command line fingerprint\n     */\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/command-line-fingerprint/reload\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public Response reloadCommandLineFingerprint() {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"reloadCommandLineFingerprint\");\n            this.security.reloadCommandLineFingerprint();\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    /**\n     * GET method\n     *\n     * @return true if the debug is permitted. False otherwise.\n     */\n    @GET\n    @Path(\"/debug-enabled\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public DebugEnabledDTO isDebugEnabled(final @Context ContainerRequestContext context) {\n        try {\n\n            if (context != null && !Optional.ofNullable(context.getSecurityContext())\n                    .filter(c -> c.getUserPrincipal() != null).isPresent()) {\n                throw new WebApplicationException(Response.Status.UNAUTHORIZED);\n            }\n\n            logger.debug(DEBUG_MESSAGE, \"isDebugEnabled\");\n            return new DebugEnabledDTO(this.security.isDebugEnabled());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/src/main/java/org/eclipse/kura/internal/rest/security/provider/SecurityRestServiceV1.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.rest.security.provider;\n\nimport jakarta.ws.rs.Path;\n\n@Path(\"security/v1\")\npublic class SecurityRestServiceV1 extends AbstractRestSecurityService {\n\n    private static final String MQTT_APP_ID = \"SEC-V1\";\n\n    @Override\n    public String getMqttAppId() {\n        return MQTT_APP_ID;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/src/main/java/org/eclipse/kura/internal/rest/security/provider/SecurityRestServiceV2.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.rest.security.provider;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.CharacterCodingException;\nimport java.nio.charset.CharsetDecoder;\nimport java.nio.charset.CodingErrorAction;\nimport java.nio.charset.StandardCharsets;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.core.Response;\nimport jakarta.ws.rs.core.Response.Status;\n\n@Path(\"security/v2\")\npublic class SecurityRestServiceV2 extends AbstractRestSecurityService {\n\n    private static final Logger logger = LoggerFactory.getLogger(SecurityRestServiceV2.class);\n    private static final String MQTT_APP_ID = \"SEC-V2\";\n\n    @Override\n    public String getMqttAppId() {\n        return MQTT_APP_ID;\n    }\n\n    /**\n     * POST method <br />\n     * This method replaces the security policy with the default production one. Then a fingerprint\n     * reload is performed.\n     */\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/security-policy/apply-default-production\")\n    public Response applyDefaultProductionSecurityPolicy() {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"applyDefaultProductionSecurityPolicy\");\n\n            this.security.applyDefaultProductionSecurityPolicy();\n            this.security.reloadSecurityPolicyFingerprint();\n            this.security.reloadCommandLineFingerprint();\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    /**\n     * POST method <br />\n     * This method replaces the security policy with the provided one. Then a fingerprint reload is\n     * performed.\n     */\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(\"/security-policy/apply\")\n    public Response applySecurityPolicy(InputStream securityPolicyInputStream) {\n        try {\n            logger.debug(DEBUG_MESSAGE, \"applySecurityPolicy\");\n\n            this.security.applySecurityPolicy(readSecurityPolicyString(securityPolicyInputStream));\n            this.security.reloadSecurityPolicyFingerprint();\n            this.security.reloadCommandLineFingerprint();\n        } catch (KuraException e) {\n            if (KuraErrorCode.INVALID_PARAMETER.equals(e.getCode())) {\n                throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST, e.getMessage());\n            }\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n\n        return Response.ok().build();\n    }\n\n    private String readSecurityPolicyString(InputStream securityPolicyInputStream) {\n        if (securityPolicyInputStream == null) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                    \"Security Policy cannot be null or empty\");\n        }\n        int bytesRead;\n        int totalBytesRead = 0;\n        ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n        byte[] data = new byte[1024];\n        try {\n            while ((bytesRead = securityPolicyInputStream.read(data, 0, data.length)) != -1) {\n                totalBytesRead += bytesRead;\n                if (totalBytesRead > 1024 * 1024) {\n                    throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                            \"Security policy too large\");\n                }\n                buffer.write(data, 0, bytesRead);\n            }\n            buffer.flush();\n        } catch (IOException e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n        if (buffer.size() == 0) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                    \"Security Policy cannot be null or empty\");\n        }\n        CharBuffer charBuffer = getCharBuffer(buffer);\n        return charBuffer.toString();\n    }\n\n    private static CharBuffer getCharBuffer(ByteArrayOutputStream buffer) {\n        final CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder().onMalformedInput(CodingErrorAction.REPORT);\n        CharBuffer charBuffer;\n        try {\n            charBuffer = decoder.decode(ByteBuffer.wrap(buffer.toByteArray()));\n        } catch (CharacterCodingException e) {\n            throw DefaultExceptionHandler.buildWebApplicationException(Status.BAD_REQUEST,\n                    \"Security Policy must be UTF-8 encoded\");\n        }\n        return charBuffer;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.security.provider/src/main/java/org/eclipse/kura/internal/rest/security/provider/dto/DebugEnabledDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.security.provider.dto;\n\npublic class DebugEnabledDTO {\n\n    private final boolean enabled;\n\n    public DebugEnabledDTO(boolean enabled) {\n        this.enabled = enabled;\n    }\n\n    public boolean isEnabled() {\n        return this.enabled;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Services REST Service\nBundle-SymbolicName: org.eclipse.kura.rest.service.listing.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nImport-Package: jakarta.annotation.security;version=\"2.1.1\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.container;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.request.handler.jaxrs;version=\"[2.0,3.0)\",\n org.eclipse.kura.request.handler.jaxrs.annotation;version=\"[1.0,2.0)\",\n org.eclipse.kura.rest.configuration.api;version=\"[1.0,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.component;version=\"1.4.0\",\n org.osgi.service.component.runtime;version=\"1.4.0\",\n org.osgi.service.component.runtime.dto;version=\"1.4.0\",\n org.slf4j;version=\"1.7.25\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/OSGI-INF/ServiceListingRestService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" immediate=\"true\" name=\"org.eclipse.kura.internal.rest.service.listing.provider.RestServiceListingProviderstingProvider\">\n    <implementation class=\"org.eclipse.kura.internal.rest.service.listing.provider.RestServiceListingProvider\"/>\n\n    <property name=\"kura.service.pid\" type=\"String\" value=\"org.eclipse.kura.internal.rest.service.listing.provider.RestServiceListingProvider\"/>\n\n    <reference interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\"\n               bind=\"bindRequestHandlerRegistry\"\n               unbind=\"unbindRequestHandlerRegistry\"\n               cardinality=\"0..n\"\n               name=\"RequestHandlerRegistry\"\n               policy=\"dynamic\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.internal.rest.service.listing.provider.RestServiceListingProvider\"/>\n    </service>\n\n    <property name=\"service.pid\"\n              type=\"String\"\n              value=\"org.eclipse.kura.internal.rest.services.provider.RestServicesProvider\"/>\n    <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\"/>\n    <reference bind=\"setServiceComponentRuntime\" cardinality=\"1..1\" interface=\"org.osgi.service.component.runtime.ServiceComponentRuntime\" name=\"ServiceComponentRuntime\" policy=\"static\"/>\n    <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <artifactId>org.eclipse.kura.rest.service.listing.provider</artifactId>\n    <packaging>eclipse-plugin</packaging>\n    <version>2.0.0-SNAPSHOT</version>\n    \n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/RestServiceListingProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.service.listing.provider;\n\nimport java.security.Principal;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.internal.rest.service.listing.provider.dto.FilterDTO;\nimport org.eclipse.kura.internal.rest.service.listing.provider.dto.InterfaceNamesDTO;\nimport org.eclipse.kura.internal.rest.service.listing.provider.dto.RefDTO;\nimport org.eclipse.kura.internal.rest.service.listing.provider.util.FilterBuilder;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.eclipse.kura.request.handler.jaxrs.JaxRsRequestHandlerProxy;\nimport org.eclipse.kura.rest.configuration.api.PidSet;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.component.runtime.ServiceComponentRuntime;\nimport org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.WebApplicationException;\nimport jakarta.ws.rs.container.ContainerRequestContext;\nimport jakarta.ws.rs.core.Context;\nimport jakarta.ws.rs.core.MediaType;\nimport jakarta.ws.rs.core.Response.Status;\n\n@Path(\"serviceListing/v1\")\npublic class RestServiceListingProvider {\n\n    private static final String OBJECT_CLASS = \"objectClass\";\n\n    private static final Logger logger = LoggerFactory.getLogger(RestServiceListingProvider.class);\n\n    private static final String APP_ID_MQTT = \"SVCLIST-V1\";\n\n    private static final String KURA_SERVICE_PID = \"kura.service.pid\";\n\n    private final RequestHandler requestHandler = new JaxRsRequestHandlerProxy(this);\n\n    private ConfigurationService configurationService;\n    private ServiceComponentRuntime scr;\n    private BundleContext bundleContext;\n\n    public void bindRequestHandlerRegistry(RequestHandlerRegistry bindingRegistry) {\n        try {\n            bindingRegistry.registerRequestHandler(APP_ID_MQTT, this.requestHandler);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to register {} request handler\", APP_ID_MQTT, e);\n        }\n    }\n\n    public void unbindRequestHandlerRegistry(RequestHandlerRegistry unbindingRegistry) {\n        try {\n            unbindingRegistry.unregister(APP_ID_MQTT);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to unregister {} request handler\", APP_ID_MQTT, e);\n        }\n    }\n\n    public void setConfigurationService(final ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    public void setServiceComponentRuntime(final ServiceComponentRuntime scr) {\n        this.scr = scr;\n    }\n\n    public void activate(final ComponentContext componentContext) {\n        this.bundleContext = componentContext.getBundleContext();\n    }\n\n    /**\n     * GET method\n     *\n     * @return list of all services running on kura exposing a <kura.service.pid>\n     *         property\n     */\n    @GET\n    @Path(\"/servicePids\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public PidSet getServicePids(@Context final ContainerRequestContext requestContext) {\n        try {\n\n            expectAuthenticatedUser(requestContext);\n\n            final List<ServiceReference<?>> servicesList = Arrays\n                    .asList(bundleContext.getServiceReferences((String) null, (String) null));\n\n            return new PidSet(getServicePids(servicesList));\n\n        } catch (Exception ex) {\n            throw DefaultExceptionHandler.toWebApplicationException(ex);\n        }\n\n    }\n\n    /**\n     * POST method\n     *\n     * @return list of all services running on kura, filtered by the list of\n     *         interfaces that the services must implement. If more <interfacesList>\n     *         contains more than one entry, all of them are put in an AND logic\n     *         value\n     */\n    @POST\n    @Path(\"/servicePids/byInterface\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public PidSet getServicePidsByInterface(final InterfaceNamesDTO interfacesList,\n            @Context final ContainerRequestContext requestContext) {\n        try {\n\n            expectAuthenticatedUser(requestContext);\n\n            interfacesList.validate();\n\n            return new PidSet(getServicesProvidingInterfaces(interfacesList.getInterfacesIds()));\n\n        } catch (final Exception ex) {\n            throw DefaultExceptionHandler.toWebApplicationException(ex);\n        }\n    }\n\n    @POST\n    @Path(\"/servicePids/byProperty\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public PidSet getServicePidsByFilter(final FilterDTO filter,\n            @Context final ContainerRequestContext requestContext) {\n        try {\n\n            expectAuthenticatedUser(requestContext);\n\n            filter.validate();\n\n            return new PidSet(getServicesMatchingFilter(filter.toOSGIFilter()));\n\n        } catch (final Exception ex) {\n            throw DefaultExceptionHandler.toWebApplicationException(ex);\n        }\n    }\n\n    @POST\n    @Path(\"/servicePids/satisfyingReference\")\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public PidSet getServicePidsSatisfyingReference(final RefDTO ref,\n            @Context final ContainerRequestContext requestContext) {\n        try {\n\n            expectAuthenticatedUser(requestContext);\n\n            ref.validate();\n\n            final String componentName = getComponentNameFromPid(ref.getPid())\n                    .orElseThrow(() -> new WebApplicationException(Status.NOT_FOUND));\n            final String targetRef = ref.getReferenceName();\n\n            final String referenceInterface = getReferenceInterface(componentName, targetRef)\n                    .orElseThrow(() -> new WebApplicationException(Status.NOT_FOUND));\n\n            final Set<String> pids = getServicesProvidingInterfaces(Collections.singleton(referenceInterface));\n\n            return new PidSet(pids);\n\n        } catch (final Exception ex) {\n            throw DefaultExceptionHandler.toWebApplicationException(ex);\n        }\n    }\n\n    @GET\n    @Path(\"/factoryPids\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public PidSet getFactoryPids(@Context final ContainerRequestContext requestContext) {\n        try {\n\n            expectAuthenticatedUser(requestContext);\n\n            return new PidSet(configurationService.getFactoryComponentPids());\n\n        } catch (Exception ex) {\n            throw DefaultExceptionHandler.toWebApplicationException(ex);\n        }\n    }\n\n    @POST\n    @Path(\"/factoryPids/byInterface\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public PidSet getFactoryPidsByInterface(final InterfaceNamesDTO interfacesList,\n            @Context final ContainerRequestContext requestContext) {\n        try {\n\n            expectAuthenticatedUser(requestContext);\n\n            interfacesList.validate();\n\n            final Set<String> result = getFactoryComponentDescriptors()\n                    .filter(component -> Arrays.asList(component.serviceInterfaces)\n                            .containsAll(interfacesList.getInterfacesIds()))\n                    .map(component -> component.name).collect(Collectors.toSet());\n\n            return new PidSet(result);\n\n        } catch (Exception ex) {\n            throw DefaultExceptionHandler.toWebApplicationException(ex);\n        }\n    }\n\n    @POST\n    @Path(\"/factoryPids/byProperty\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public PidSet getFactoryPidsByFilter(final FilterDTO filter,\n            @Context final ContainerRequestContext requestContext) {\n        try {\n\n            expectAuthenticatedUser(requestContext);\n\n            filter.validate();\n\n            final Filter osgiFilter = FrameworkUtil.createFilter(filter.toOSGIFilter());\n\n            final Set<String> result = getFactoryComponentDescriptors().filter(component -> {\n                final Map<String, Object> properties = new HashMap<>(component.properties);\n                if (component.serviceInterfaces.length != 0) {\n                    properties.put(OBJECT_CLASS, component.serviceInterfaces);\n                }\n\n                return osgiFilter.matches(properties);\n            }).map(component -> component.name).collect(Collectors.toSet());\n\n            return new PidSet(result);\n\n        } catch (Exception ex) {\n            throw DefaultExceptionHandler.toWebApplicationException(ex);\n        }\n    }\n\n    /*\n     * Utils methods\n     */\n\n    private void expectAuthenticatedUser(final ContainerRequestContext requestContext) {\n        if (requestContext != null && !getPrincipal(requestContext).isPresent()) {\n            throw new WebApplicationException(Status.UNAUTHORIZED);\n        }\n    }\n\n    private Optional<Principal> getPrincipal(final ContainerRequestContext containerRequestContext) {\n        return Optional.ofNullable(containerRequestContext.getSecurityContext())\n                .flatMap(entry -> Optional.ofNullable(entry.getUserPrincipal()));\n    }\n\n    private Set<String> getServicesProvidingInterfaces(final Set<String> interfacesIds) throws InvalidSyntaxException {\n\n        final String filter = new FilterBuilder().and(f -> interfacesIds.forEach(i -> f.property(OBJECT_CLASS, i)))\n                .build();\n\n        return getServicesMatchingFilter(filter);\n    }\n\n    private Set<String> getServicesMatchingFilter(final String filter) throws InvalidSyntaxException {\n\n        List<ServiceReference<?>> servicesList = Optional\n                .ofNullable(bundleContext.getServiceReferences((String) null, filter)).map(Arrays::asList)\n                .orElseGet(Collections::emptyList);\n\n        return getServicePids(servicesList);\n    }\n\n    private Set<String> getServicePids(final List<ServiceReference<?>> references) {\n\n        return references.stream().filter(s -> s.getProperty(KURA_SERVICE_PID) instanceof String)\n                .map(s -> (String) s.getProperty(KURA_SERVICE_PID)).collect(Collectors.toSet());\n\n    }\n\n    private Optional<String> getComponentNameFromPid(final String pid) {\n        try {\n            final ServiceReference<?>[] refs = bundleContext.getServiceReferences((String) null,\n                    \"(kura.service.pid=\" + pid + \")\");\n\n            if (refs == null || refs.length == 0) {\n                return Optional.empty();\n            }\n\n            final ServiceReference<?> ref = refs[0];\n\n            final String result = Optional.ofNullable(ref.getProperty(\"service.factoryPid\"))\n                    .flatMap(s -> s instanceof String ? Optional.of((String) s) : Optional.empty()).orElse(pid);\n\n            return Optional.of(result);\n\n        } catch (final InvalidSyntaxException e) {\n            logger.warn(\"bad pid name: {}\", pid);\n            return Optional.empty();\n        }\n    }\n\n    private Optional<String> getReferenceInterface(final String componentName, final String targetRef) {\n        return scr.getComponentDescriptionDTOs().stream()\n                .filter(componentDescription -> componentDescription.name.equals(componentName)).findAny()\n                .flatMap(componentDescription -> Arrays.stream(componentDescription.references)\n                        .filter(reference -> targetRef.equals(reference.name)).findAny()\n                        .map(reference -> reference.interfaceName)\n\n                );\n    }\n\n    private Stream<ComponentDescriptionDTO> getFactoryComponentDescriptors() {\n        final Set<String> factories = configurationService.getFactoryComponentPids();\n\n        return scr.getComponentDescriptionDTOs().stream().filter(s -> factories.contains(s.name));\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/dto/FilterDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.service.listing.provider.dto;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.internal.rest.service.listing.provider.util.FilterBuilder;\n\npublic class FilterDTO {\n\n    private final String name;\n    private final String value;\n    private final List<FilterDTO> and;\n    private final List<FilterDTO> or;\n    private final FilterDTO not;\n\n    public FilterDTO(String name, String value, List<FilterDTO> and, List<FilterDTO> or, FilterDTO not) {\n        this.name = name;\n        this.value = value;\n        this.and = and;\n        this.or = or;\n        this.not = not;\n    }\n\n    public String toOSGIFilter() {\n\n        return toOSGIFilter(new FilterBuilder()).build();\n    }\n\n    public void validate() throws KuraException {\n        int count = 0;\n\n        if (name != null) {\n            if (name.contains(\" \")) {\n                throw new KuraException(KuraErrorCode.BAD_REQUEST, \"Name must contain no spaces\");\n            }\n\n            if (name.trim().isEmpty()) {\n                throw new KuraException(KuraErrorCode.BAD_REQUEST, \"Name must not be empty\");\n            }\n\n            count++;\n        }\n\n        if (and != null) {\n            count++;\n        }\n\n        if (or != null) {\n            count++;\n        }\n\n        if (not != null) {\n            count++;\n        }\n\n        if (count != 1) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST,\n                    \"Exactly one among the \\\"name\\\", \\\"and\\\", \\\"or\\\" and \\\"not\\\" properties must be specified\");\n        }\n    }\n\n    private FilterBuilder toOSGIFilter(final FilterBuilder filterBuilder) {\n        if (name != null) {\n            filterBuilder.property(name, value);\n        } else if (and != null) {\n            filterBuilder.and(b -> and.forEach(f -> f.toOSGIFilter(b)));\n        } else if (or != null) {\n            filterBuilder.or(b -> or.forEach(f -> f.toOSGIFilter(b)));\n        } else if (not != null) {\n            filterBuilder.not(not::toOSGIFilter);\n        }\n\n        return filterBuilder;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/dto/InterfaceNamesDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.internal.rest.service.listing.provider.dto;\n\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\n\npublic class InterfaceNamesDTO {\n\n    private final Set<String> interfaceNames;\n\n    public InterfaceNamesDTO(final Set<String> interfaceNames) {\n        this.interfaceNames = interfaceNames;\n    }\n\n    public void validate() throws KuraException {\n\n        if (this.interfaceNames == null) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"interfaceNames cannot be null\");\n        }\n\n        if (this.interfaceNames.isEmpty()) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"interfaceNames cannot be empty\");\n        }\n\n        if (this.interfaceNames.stream().anyMatch(Objects::isNull)) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"interfaceNames elements cannot be null\");\n        }\n\n        if (this.interfaceNames.stream().anyMatch(i -> i.trim().isEmpty())) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"interfaceNames elements cannot be empty\");\n        }\n    }\n\n    public Set<String> getInterfacesIds() {\n        return this.interfaceNames;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/dto/RefDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.service.listing.provider.dto;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\n\npublic class RefDTO {\n\n    final String pid;\n    final String referenceName;\n\n    public RefDTO(String pid, String referenceName) {\n        this.pid = pid;\n        this.referenceName = referenceName;\n    }\n\n    public String getPid() {\n        return pid;\n    }\n\n    public String getReferenceName() {\n        return referenceName;\n    }\n\n    public void validate() throws KuraException {\n\n        if (this.pid == null) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"pid must not be null\");\n        }\n\n        if (this.pid.trim().isEmpty()) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"pid must not be empty\");\n        }\n\n        if (this.referenceName == null) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"referenceName must not be null\");\n        }\n\n        if (this.referenceName.trim().isEmpty()) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST, \"referenceName must not be empty\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.service.listing.provider/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/util/FilterBuilder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.service.listing.provider.util;\n\nimport java.util.function.Consumer;\n\npublic class FilterBuilder {\n\n    private final StringBuilder stringBuilder = new StringBuilder();\n\n    public FilterBuilder property(final String name, final String value) {\n        final String escapedValue = value != null ? escapeValue(value) : \"*\";\n\n        stringBuilder.append(\"(\").append(name).append(\"=\").append(escapedValue).append(\")\");\n\n        return this;\n    }\n\n    public FilterBuilder and(final Consumer<FilterBuilder> consumer) {\n        return op(\"&\", consumer);\n    }\n\n    public FilterBuilder or(final Consumer<FilterBuilder> consumer) {\n        return op(\"|\", consumer);\n    }\n\n    public FilterBuilder not(final Consumer<FilterBuilder> consumer) {\n        return op(\"!\", consumer);\n    }\n\n    private FilterBuilder op(final String operator, final Consumer<FilterBuilder> consumer) {\n        stringBuilder.append(\"(\");\n        stringBuilder.append(operator);\n\n        consumer.accept(this);\n\n        stringBuilder.append(\")\");\n\n        return this;\n    }\n\n    private String escapeValue(final String value) {\n        return value.replace(\"(\", \"\\\\(\").replace(\")\", \"\\\\)\").replace(\"*\", \"\\\\*\");\n    }\n\n    public String build() {\n        return stringBuilder.toString();\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: System REST Service\nBundle-SymbolicName: org.eclipse.kura.rest.system.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nImport-Package: jakarta.annotation.security;version=\"2.1.1\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.apache.commons.io;version=\"2.11.0\",\n org.eclipse.kura;version=\"[1.3,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.request.handler.jaxrs;version=\"[2.0,3.0)\",\n org.eclipse.kura.request.handler.jaxrs.annotation;version=\"[1.0,2.0)\",\n org.eclipse.kura.rest.configuration.api;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.7,2.0)\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.component;version=\"[1.3,2.0)\",\n org.osgi.service.useradmin;version=\"1.1.0\";resolution:=optional,\n org.slf4j;version=\"1.7.25\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/OSGI-INF/SystemRestService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.rest.system.SystemRestService\">\n    <implementation class=\"org.eclipse.kura.rest.system.SystemRestService\"/>\n\n    <property name=\"kura.service.pid\" type=\"String\" value=\"org.eclipse.kura.rest.system.SystemRestService\"/>\n\n    <reference interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\"\n               bind=\"bindRequestHandlerRegistry\"\n               unbind=\"unbindRequestHandlerRegistry\"\n               cardinality=\"0..n\"\n               name=\"RequestHandlerRegistry\"\n               policy=\"dynamic\"/>\n\n    <reference interface=\"org.eclipse.kura.system.SystemService\"\n               bind=\"bindSystemService\"\n               cardinality=\"1..1\"\n               name=\"SystemService\"\n               policy=\"static\"/>\n\n    <reference interface=\"org.osgi.service.useradmin.UserAdmin\"\n               bind=\"bindUserAdmin\"\n               cardinality=\"1..1\"\n               name=\"UserAdmin\"\n               policy=\"static\"/>\n\n    <service>\n        <provide interface=\"org.eclipse.kura.rest.system.SystemRestService\"/>\n    </service>\n\n    <property name=\"service.pid\"\n              type=\"String\"\n              value=\"org.eclipse.kura.rest.system.SystemRestService\"/>\n              \n    <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <artifactId>org.eclipse.kura.rest.system.provider</artifactId>\n    <packaging>eclipse-plugin</packaging>\n    <version>2.0.0-SNAPSHOT</version>\n    \n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/src/main/java/org/eclipse/kura/rest/system/Constants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.rest.system;\n\n\npublic class Constants {\n\n    public static final String MQTT_APP_ID = \"SYS-V1\";\n    public static final String REST_APP_ID = \"system/v1\";\n    public static final String RESOURCE_FRAMEWORK_PROPERTIES = \"/properties/framework\";\n    public static final String RESOURCE_FRAMEWORK_PROPERTIES_FILTER = \"/properties/framework/filter\";\n    public static final String RESOURCE_EXTENDED_PROPERTIES = \"/properties/extended\";\n    public static final String RESOURCE_EXTENDED_PROPERTIES_FILTER = \"/properties/extended/filter\";\n    public static final String RESOURCE_KURA_PROPERTIES = \"/properties/kura\";\n    public static final String RESOURCE_KURA_PROPERTIES_FILTER = \"/properties/kura/filter\";\n    public static final String REST_ROLE_NAME = \"system\";\n    public static final String KURA_PERMISSION_REST_ROLE = \"kura.permission.rest.\" + REST_ROLE_NAME;\n\n    private Constants() {\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/src/main/java/org/eclipse/kura/rest/system/SystemRestService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.system;\n\nimport static org.eclipse.kura.rest.system.Constants.KURA_PERMISSION_REST_ROLE;\nimport static org.eclipse.kura.rest.system.Constants.MQTT_APP_ID;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_EXTENDED_PROPERTIES;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_EXTENDED_PROPERTIES_FILTER;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_FRAMEWORK_PROPERTIES;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_FRAMEWORK_PROPERTIES_FILTER;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_KURA_PROPERTIES;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_KURA_PROPERTIES_FILTER;\nimport static org.eclipse.kura.rest.system.Constants.REST_APP_ID;\nimport static org.eclipse.kura.rest.system.Constants.REST_ROLE_NAME;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.core.MediaType;\n\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler;\nimport org.eclipse.kura.request.handler.jaxrs.JaxRsRequestHandlerProxy;\nimport org.eclipse.kura.rest.system.dto.ExtendedPropertiesDTO;\nimport org.eclipse.kura.rest.system.dto.FilterDTO;\nimport org.eclipse.kura.rest.system.dto.FrameworkPropertiesDTO;\nimport org.eclipse.kura.rest.system.dto.KuraPropertiesDTO;\nimport org.eclipse.kura.system.SystemService;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Path(REST_APP_ID)\npublic class SystemRestService {\n\n    private static final Logger logger = LoggerFactory.getLogger(SystemRestService.class);\n    private static final String DEBUG_MESSSAGE = \"Processing request for resource '{}'\";\n\n    private SystemService systemService;\n    private final RequestHandler requestHandler = new JaxRsRequestHandlerProxy(this);\n\n    public void bindSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    public void bindUserAdmin(UserAdmin userAdmin) {\n        userAdmin.createRole(KURA_PERMISSION_REST_ROLE, Role.GROUP);\n    }\n\n    public void bindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.registerRequestHandler(MQTT_APP_ID, this.requestHandler);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to register {} request handler\", MQTT_APP_ID, e);\n        }\n    }\n\n    public void unbindRequestHandlerRegistry(RequestHandlerRegistry registry) {\n        try {\n            registry.unregister(MQTT_APP_ID);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to unregister {} request handler\", MQTT_APP_ID, e);\n        }\n    }\n\n    @GET\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(RESOURCE_FRAMEWORK_PROPERTIES)\n    @Produces(MediaType.APPLICATION_JSON)\n    public FrameworkPropertiesDTO getFrameworkProperties() {\n        try {\n            logger.debug(DEBUG_MESSSAGE, RESOURCE_FRAMEWORK_PROPERTIES);\n            return new FrameworkPropertiesDTO(this.systemService);\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @GET\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(RESOURCE_EXTENDED_PROPERTIES)\n    @Produces(MediaType.APPLICATION_JSON)\n    public ExtendedPropertiesDTO getExtendedProperties() {\n        try {\n            logger.debug(DEBUG_MESSSAGE, RESOURCE_EXTENDED_PROPERTIES);\n            return new ExtendedPropertiesDTO(this.systemService);\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @GET\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(RESOURCE_KURA_PROPERTIES)\n    @Produces(MediaType.APPLICATION_JSON)\n    public KuraPropertiesDTO getKuraProperties() {\n        try {\n            logger.debug(DEBUG_MESSSAGE, RESOURCE_KURA_PROPERTIES);\n            return new KuraPropertiesDTO(this.systemService.getProperties());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(RESOURCE_FRAMEWORK_PROPERTIES_FILTER)\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public FrameworkPropertiesDTO postFrameworkPropertiesFilter(FilterDTO filter) {\n        try {\n            logger.debug(DEBUG_MESSSAGE, RESOURCE_FRAMEWORK_PROPERTIES_FILTER);\n            return new FrameworkPropertiesDTO(this.systemService, filter.getNames());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(RESOURCE_EXTENDED_PROPERTIES_FILTER)\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public ExtendedPropertiesDTO postExtendedPropertiesFilter(FilterDTO filter) {\n        try {\n            logger.debug(DEBUG_MESSSAGE, RESOURCE_EXTENDED_PROPERTIES_FILTER);\n            return new ExtendedPropertiesDTO(this.systemService, filter.getGroupNames());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n    @POST\n    @RolesAllowed(REST_ROLE_NAME)\n    @Path(RESOURCE_KURA_PROPERTIES_FILTER)\n    @Produces(MediaType.APPLICATION_JSON)\n    @Consumes(MediaType.APPLICATION_JSON)\n    public KuraPropertiesDTO postKuraPropertiesFilter(FilterDTO filter) {\n        try {\n            logger.debug(DEBUG_MESSSAGE, RESOURCE_KURA_PROPERTIES_FILTER);\n            return new KuraPropertiesDTO(this.systemService.getProperties(), filter.getNames());\n        } catch (Exception e) {\n            throw DefaultExceptionHandler.toWebApplicationException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/src/main/java/org/eclipse/kura/rest/system/dto/ExtendedPropertiesDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.system.dto;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.function.Predicate;\n\nimport org.eclipse.kura.system.ExtendedProperties;\nimport org.eclipse.kura.system.ExtendedPropertyGroup;\nimport org.eclipse.kura.system.SystemService;\n\n@SuppressWarnings(\"unused\")\npublic class ExtendedPropertiesDTO {\n\n    private String version;\n    private Map<String, Map<String, String>> extendedProperties;\n\n    public ExtendedPropertiesDTO(SystemService systemService) {\n        Optional<ExtendedProperties> properties = systemService.getExtendedProperties();\n\n        if (properties.isPresent()) {\n            populateExtendedProperties(properties.get(), s -> true);\n        }\n    }\n\n    public ExtendedPropertiesDTO(SystemService systemService, List<String> groupNames) {\n        Optional<ExtendedProperties> properties = systemService.getExtendedProperties();\n\n        if (properties.isPresent()) {\n            populateExtendedProperties(properties.get(), groupNames::contains);\n        }\n    }\n\n    private void populateExtendedProperties(ExtendedProperties properties, Predicate<String> condition) {\n        this.version = properties.getVersion();\n        this.extendedProperties = new HashMap<>();\n\n        for (ExtendedPropertyGroup group : properties.getPropertyGroups()) {\n            putIf(group.getName(), group.getProperties(), condition.test(group.getName()));\n        }\n    }\n\n    private void putIf(String key, Map<String, String> value, boolean condition) {\n        if (condition) {\n            this.extendedProperties.put(key, value);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/src/main/java/org/eclipse/kura/rest/system/dto/FilterDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.system.dto;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class FilterDTO {\n\n    private List<String> names;\n    private List<String> groupNames;\n\n    public FilterDTO() {\n        this.names = new ArrayList<>();\n        this.groupNames = new ArrayList<>();\n    }\n\n    public List<String> getNames() {\n        return this.names;\n    }\n\n    public List<String> getGroupNames() {\n        return this.groupNames;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/src/main/java/org/eclipse/kura/rest/system/dto/FrameworkPropertiesDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.system.dto;\n\nimport java.util.List;\nimport java.util.function.Predicate;\n\nimport org.eclipse.kura.system.SystemService;\n\n@SuppressWarnings(\"unused\")\npublic class FrameworkPropertiesDTO {\n\n    // hardware\n    private String biosVersion;\n    private String cpuVersion;\n    private String deviceName;\n    private String modelId;\n    private String modelName;\n    private String partNumber;\n    private String platform;\n    private Integer numberOfProcessors;\n    private Long totalMemory;\n    private Long freeMemory;\n    private String serialNumber;\n\n    // java\n    private String javaHome;\n    private String javaVendor;\n    private String javaVersion;\n    private String javaVmInfo;\n    private String javaVmName;\n    private String javaVmVersion;\n    private String javaVmVendor;\n    private String jdkVendorVersion;\n\n    // os\n    private String osArch;\n    private String osDistro;\n    private String osDistroVersion;\n    private String osName;\n    private String osVersion;\n    private Boolean isLegacyBluetoothBeaconScan;\n    private Boolean isLegacyPPPLoggingEnabled;\n    private String primaryMacAddress;\n    private String primaryNetworkInterfaceName;\n    private String fileSeparator;\n    private String firmwareVersion;\n    private String internetConnectionStatus;\n\n    // kura\n    private String kuraDataDirectory;\n    private String kuraFrameworkConfigDirectory;\n    private String kuraHomeDirectory;\n    private String kuraMarketplaceCompatibilityVersion;\n    private Integer kuraSnapshotsCount;\n    private String kuraSnapshotsDirectory;\n    private String kuraStyleDirectory;\n    private String kuraTemporaryConfigDirectory;\n    private String kuraUserConfigDirectory;\n    private String kuraVersion;\n    private Boolean kuraHaveWebInterface;\n    private Boolean kuraHaveNetAdmin;\n    private Integer kuraWifiTopChannel;\n    private String kuraDefaultNetVirtualDevicesConfig;\n\n    // osgi\n    private String osgiFirmwareName;\n    private String osgiFirmwareVersion;\n\n    // command\n    private String commandUser;\n    private Integer commandZipMaxUploadNumber;\n    private Integer commandZipMaxUploadSize;\n\n    public FrameworkPropertiesDTO(SystemService systemService) {\n        populateProperties(systemService, s -> true);\n    }\n\n    public FrameworkPropertiesDTO(SystemService systemService, List<String> names) {\n        for (String name : names) {\n            populateProperties(systemService, names::contains);\n        }\n    }\n\n    private void populateProperties(SystemService systemService, Predicate<String> filter) {\n        populateHardwareProperties(systemService, filter);\n        populateJavaProperties(systemService, filter);\n        populateOsProperties(systemService, filter);\n        populateKuraProperties(systemService, filter);\n        populateOsgiProperties(systemService, filter);\n        populateCommandProperties(systemService, filter);\n    }\n\n    private void populateHardwareProperties(SystemService systemService, Predicate<String> filter) {\n        if (filter.test(\"biosVersion\")) {\n            this.biosVersion = systemService.getBiosVersion();\n        }\n\n        if (filter.test(\"cpuVersion\")) {\n            this.cpuVersion = systemService.getCpuVersion();\n        }\n\n        if (filter.test(\"deviceName\")) {\n            this.deviceName = systemService.getDeviceName();\n        }\n\n        if (filter.test(\"modelId\")) {\n            this.modelId = systemService.getModelId();\n        }\n\n        if (filter.test(\"modelName\")) {\n            this.modelName = systemService.getModelName();\n        }\n\n        if (filter.test(\"partNumber\")) {\n            this.partNumber = systemService.getPartNumber();\n        }\n\n        if (filter.test(\"platform\")) {\n            this.platform = systemService.getPlatform();\n        }\n\n        if (filter.test(\"numberOfProcessors\")) {\n            this.numberOfProcessors = systemService.getNumberOfProcessors();\n        }\n\n        if (filter.test(\"totalMemory\")) {\n            this.totalMemory = systemService.getTotalMemory();\n        }\n\n        if (filter.test(\"freeMemory\")) {\n            this.freeMemory = systemService.getFreeMemory();\n        }\n\n        if (filter.test(\"serialNumber\")) {\n            this.serialNumber = systemService.getSerialNumber();\n        }\n    }\n\n    private void populateJavaProperties(SystemService systemService, Predicate<String> filter) {\n        if (filter.test(\"javaHome\")) {\n            this.javaHome = systemService.getJavaHome();\n        }\n\n        if (filter.test(\"javaVendor\")) {\n            this.javaVendor = systemService.getJavaVendor();\n        }\n\n        if (filter.test(\"javaVersion\")) {\n            this.javaVersion = systemService.getJavaVersion();\n        }\n\n        if (filter.test(\"javaVmInfo\")) {\n            this.javaVmInfo = systemService.getJavaVmInfo();\n        }\n\n        if (filter.test(\"javaVmName\")) {\n            this.javaVmName = systemService.getJavaVmName();\n        }\n\n        if (filter.test(\"javaVmVersion\")) {\n            this.javaVmVersion = systemService.getJavaVmVersion();\n        }\n\n        if (filter.test(\"javaVmVendor\")) {\n            this.javaVmVendor = systemService.getJavaVmVendor();\n        }\n\n        if (filter.test(\"jdkVendorVersion\")) {\n            this.jdkVendorVersion = systemService.getJdkVendorVersion();\n        }\n    }\n\n    private void populateOsProperties(SystemService systemService, Predicate<String> filter) {\n        if (filter.test(\"osArch\")) {\n            this.osArch = systemService.getOsArch();\n        }\n\n        if (filter.test(\"osDistro\")) {\n            this.osDistro = systemService.getOsDistro();\n        }\n\n        if (filter.test(\"osDistroVersion\")) {\n            this.osDistroVersion = systemService.getOsDistroVersion();\n        }\n\n        if (filter.test(\"osName\")) {\n            this.osName = systemService.getOsName();\n        }\n\n        if (filter.test(\"osVersion\")) {\n            this.osVersion = systemService.getOsVersion();\n        }\n\n        if (filter.test(\"isLegacyBluetoothBeaconScan\")) {\n            this.isLegacyBluetoothBeaconScan = systemService.isLegacyBluetoothBeaconScan();\n        }\n\n        if (filter.test(\"isLegacyPPPLoggingEnabled\")) {\n            this.isLegacyPPPLoggingEnabled = systemService.isLegacyPPPLoggingEnabled();\n        }\n\n        if (filter.test(\"primaryMacAddress\")) {\n            this.primaryMacAddress = systemService.getPrimaryMacAddress();\n        }\n\n        if (filter.test(\"primaryNetworkInterfaceName\")) {\n            this.primaryNetworkInterfaceName = systemService.getPrimaryNetworkInterfaceName();\n        }\n\n        if (filter.test(\"fileSeparator\")) {\n            this.fileSeparator = systemService.getFileSeparator();\n        }\n\n        if (filter.test(\"firmwareVersion\")) {\n            this.firmwareVersion = systemService.getFirmwareVersion();\n        }\n\n        if (filter.test(\"internetConnectionStatus\")) {\n            this.internetConnectionStatus = systemService.getInternetConnectionStatus().toString();\n        }\n    }\n\n    private void populateKuraProperties(SystemService systemService, Predicate<String> filter) {\n        if (filter.test(\"kuraDataDirectory\")) {\n            this.kuraDataDirectory = systemService.getKuraDataDirectory();\n        }\n\n        if (filter.test(\"kuraFrameworkConfigDirectory\")) {\n            this.kuraFrameworkConfigDirectory = systemService.getKuraFrameworkConfigDirectory();\n        }\n\n        if (filter.test(\"kuraHomeDirectory\")) {\n            this.kuraHomeDirectory = systemService.getKuraHome();\n        }\n\n        if (filter.test(\"kuraMarketplaceCompatibilityVersion\")) {\n            this.kuraMarketplaceCompatibilityVersion = systemService.getKuraMarketplaceCompatibilityVersion();\n        }\n\n        if (filter.test(\"kuraSnapshotsCount\")) {\n            this.kuraSnapshotsCount = systemService.getKuraSnapshotsCount();\n        }\n\n        if (filter.test(\"kuraSnapshotsDirectory\")) {\n            this.kuraSnapshotsDirectory = systemService.getKuraSnapshotsDirectory();\n        }\n\n        if (filter.test(\"kuraStyleDirectory\")) {\n            this.kuraStyleDirectory = systemService.getKuraStyleDirectory();\n        }\n\n        if (filter.test(\"kuraTemporaryConfigDirectory\")) {\n            this.kuraTemporaryConfigDirectory = systemService.getKuraTemporaryConfigDirectory();\n        }\n\n        if (filter.test(\"kuraUserConfigDirectory\")) {\n            this.kuraUserConfigDirectory = systemService.getKuraUserConfigDirectory();\n        }\n\n        if (filter.test(\"kuraVersion\")) {\n            this.kuraVersion = systemService.getKuraVersion();\n        }\n\n        if (filter.test(\"kuraHaveWebInterface\")) {\n            this.kuraHaveWebInterface = Boolean.parseBoolean(systemService.getKuraWebEnabled());\n        }\n\n        if (filter.test(\"kuraHaveNetAdmin\")) {\n            this.kuraHaveNetAdmin = (Boolean) systemService.getProperties().get(SystemService.KEY_KURA_HAVE_NET_ADMIN);\n        }\n\n        if (filter.test(\"kuraWifiTopChannel\")) {\n            this.kuraWifiTopChannel = systemService.getKuraWifiTopChannel();\n        }\n\n        if (filter.test(\"kuraDefaultNetVirtualDevicesConfig\")) {\n            this.kuraDefaultNetVirtualDevicesConfig = systemService.getNetVirtualDevicesConfig();\n        }\n    }\n\n    private void populateOsgiProperties(SystemService systemService, Predicate<String> filter) {\n        if (filter.test(\"osgiFirmwareName\")) {\n            this.osgiFirmwareName = systemService.getOsgiFwName();\n        }\n\n        if (filter.test(\"osgiFirmwareVersion\")) {\n            this.osgiFirmwareVersion = systemService.getOsgiFwVersion();\n        }\n    }\n\n    private void populateCommandProperties(SystemService systemService, Predicate<String> filter) {\n        if (filter.test(\"commandUser\")) {\n            this.commandUser = systemService.getCommandUser();\n        }\n\n        if (filter.test(\"commandZipMaxUploadNumber\")) {\n            this.commandZipMaxUploadNumber = systemService.getFileCommandZipMaxUploadNumber();\n        }\n\n        if (filter.test(\"commandZipMaxUploadSize\")) {\n            this.commandZipMaxUploadSize = systemService.getFileCommandZipMaxUploadSize();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.system.provider/src/main/java/org/eclipse/kura/rest/system/dto/KuraPropertiesDTO.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.system.dto;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.function.Predicate;\n\npublic class KuraPropertiesDTO {\n\n    private Map<String, String> kuraProperties;\n\n    public KuraPropertiesDTO(Properties kuraProperties) {\n        this.kuraProperties = new HashMap<>();\n\n        populateKuraProperties(kuraProperties, s -> true);\n    }\n\n    public KuraPropertiesDTO(Properties kuraProperties, List<String> names) {\n        this.kuraProperties = new HashMap<>();\n\n        populateKuraProperties(kuraProperties, names::contains);\n    }\n\n    private void populateKuraProperties(Properties properties, Predicate<String> condition) {\n        for (String key : properties.stringPropertyNames()) {\n            putIf(key, properties.getProperty(key), condition.test(key));\n        }\n    }\n\n    private void putIf(String key, String value, boolean condition) {\n        if (condition) {\n            this.kuraProperties.put(key, value);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.tamper.detection.provider\nBundle-SymbolicName: org.eclipse.kura.rest.tamper.detection.provider;singleton:=true\nBundle-Version: 1.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nImport-Package: com.google.gson;version=\"2.7.0\",\n jakarta.annotation.security;version=\"2.1.1\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.request;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.4,2.0)\",\n org.eclipse.kura.security.tamper.detection;version=\"[1.0,2.0)\",\n org.eclipse.kura.type;version=\"[1.1,2.0)\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.slf4j;version=\"1.7.25\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/OSGI-INF/org.eclipse.kura.rest.tamper.detection.provider.TamperDetectionRequestHandler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.internal.rest.tamper.detection.TamperDetectionRequestHandler\">\n   <implementation class=\"org.eclipse.kura.internal.rest.tamper.detection.TamperDetectionRequestHandler\"/>\n      <reference bind=\"setTamperDetectionService\" cardinality=\"0..n\" interface=\"org.eclipse.kura.security.tamper.detection.TamperDetectionService\" name=\"TamperDetectionService\" policy=\"dynamic\" unbind=\"unsetTamperDetectionService\"/>\n      <reference bind=\"setRequestHandlerRegistry\" cardinality=\"0..n\" interface=\"org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry\" name=\"RequestHandlerRegistry\" policy=\"dynamic\" unbind=\"unsetRequestHandlerRegistry\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/OSGI-INF/org.eclipse.kura.rest.tamper.detection.provider.TamperDetectionRestService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" enabled=\"true\" immediate=\"true\" name=\"org.eclipse.kura.internal.rest.tamper.detection.TamperDetectionRestService\">\n   <implementation class=\"org.eclipse.kura.internal.rest.tamper.detection.TamperDetectionRestService\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.internal.rest.tamper.detection.TamperDetectionRestService\"/>\n   </service>\n   <reference bind=\"setTamperDetectionService\" cardinality=\"0..n\" interface=\"org.eclipse.kura.security.tamper.detection.TamperDetectionService\" name=\"TamperDetectionService\" policy=\"dynamic\" unbind=\"unsetTamperDetectionService\"/>\n   <reference bind=\"setUserAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.useradmin.UserAdmin\" name=\"UserAdmin\" policy=\"static\"/>\n   <property name=\"osgi.jakartars.resource\" type=\"String\" value=\"true\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/,\\\n               OSGI-INF/org.eclipse.kura.rest.tamper.detection.provider.TamperDetectionRestService.xml,\\\n               OSGI-INF/org.eclipse.kura.rest.tamper.detection.provider.TamperDetectionRequestHandler.xml\nsrc.includes = about.html,\\\n               about_files/\nsource.. = src/main/java\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<artifactId>org.eclipse.kura.rest.tamper.detection.provider</artifactId>\n\t<version>1.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/src/main/java/org/eclipse/kura/internal/rest/tamper/detection/TamperDetectionRequestHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.rest.tamper.detection;\n\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.List;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerContext;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.internal.rest.tamper.detection.util.TamperDetectionRemoteService;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.gson.Gson;\n\npublic class TamperDetectionRequestHandler extends TamperDetectionRemoteService implements RequestHandler {\n\n    private static final String APP_ID = \"TAMPER-V1\";\n    private static final KuraMessage EMPTY_RESPONSE = new KuraMessage(new KuraResponsePayload(200));\n\n    private static final String LIST_PATH = \"list\";\n    private static final String PID_PATH = \"pid\";\n\n    private static final String RESET_PATH = \"_reset\";\n\n    private static final Logger logger = LoggerFactory.getLogger(TamperDetectionRequestHandler.class);\n\n    public void setRequestHandlerRegistry(final RequestHandlerRegistry requestHandlerRegistry) {\n        try {\n            requestHandlerRegistry.registerRequestHandler(APP_ID, this);\n        } catch (KuraException e) {\n            logger.info(\"Unable to register cloudlet {} in {}\", APP_ID, requestHandlerRegistry.getClass().getName());\n        }\n    }\n\n    public void unsetRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) {\n        try {\n            requestHandlerRegistry.unregister(APP_ID);\n        } catch (KuraException e) {\n            logger.info(\"Unable to register cloudlet {} in {}\", APP_ID, requestHandlerRegistry.getClass().getName());\n        }\n    }\n\n    @Override\n    public KuraMessage doGet(final RequestHandlerContext context, final KuraMessage reqMessage) throws KuraException {\n\n        final List<String> resourcePath = extractResourcePath(reqMessage);\n\n        if (resourcePath.size() == 1 && resourcePath.get(0).equals(LIST_PATH)) {\n            return jsonResponse(listTamperDetectionServicesInternal());\n        } else if (resourcePath.size() == 2 && resourcePath.get(0).equals(PID_PATH)) {\n            return jsonResponse(getTamperStatusInternal(resourcePath.get(1)));\n        } else {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n    }\n\n    @Override\n    public KuraMessage doExec(final RequestHandlerContext context, final KuraMessage reqMessage) throws KuraException {\n\n        final List<String> resourcePath = extractResourcePath(reqMessage);\n\n        if (resourcePath.size() != 3) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        if (!resourcePath.get(0).equals(PID_PATH) || !resourcePath.get(2).equals(RESET_PATH)) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n\n        resetTamperStatusInternal(resourcePath.get(1));\n\n        return EMPTY_RESPONSE;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static final List<String> extractResourcePath(final KuraMessage message) throws KuraException {\n        Object requestObject = message.getProperties().get(ARGS_KEY.value());\n        if (requestObject instanceof List) {\n            return (List<String>) requestObject;\n        } else {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        }\n    }\n\n    private static final KuraMessage jsonResponse(final Object response) {\n        final KuraResponsePayload responsePayload = new KuraResponsePayload(200);\n\n        final Gson gson = new Gson();\n\n        responsePayload.setBody(gson.toJson(response).getBytes(StandardCharsets.UTF_8));\n\n        return new KuraMessage(responsePayload);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/src/main/java/org/eclipse/kura/internal/rest/tamper/detection/TamperDetectionRestService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.rest.tamper.detection;\n\nimport java.util.List;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.internal.rest.tamper.detection.util.TamperDetectionRemoteService;\nimport org.eclipse.kura.rest.tamper.detection.api.TamperDetectionServiceInfo;\nimport org.eclipse.kura.rest.tamper.detection.api.TamperStatusInfo;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.POST;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.PathParam;\nimport jakarta.ws.rs.Produces;\nimport jakarta.ws.rs.WebApplicationException;\nimport jakarta.ws.rs.core.MediaType;\n\n@Path(\"/tamper/v1\")\npublic class TamperDetectionRestService extends TamperDetectionRemoteService {\n\n    public void setUserAdmin(final UserAdmin userAdmin) {\n        userAdmin.createRole(\"kura.permission.rest.tamper.detection\", Role.GROUP);\n    }\n\n    @GET\n    @Path(\"/list\")\n    @RolesAllowed(\"tamper.detection\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public List<TamperDetectionServiceInfo> listTamperDetectionServices() {\n        return listTamperDetectionServicesInternal();\n    }\n\n    @GET\n    @RolesAllowed(\"tamper.detection\")\n    @Path(\"/pid/{pid}\")\n    @Produces(MediaType.APPLICATION_JSON)\n    public TamperStatusInfo getTamperStatus(@PathParam(\"pid\") final String pid) {\n        try {\n            return getTamperStatusInternal(pid);\n        } catch (final KuraException e) {\n            throw toWebApplicationException(e);\n        }\n    }\n\n    @POST\n    @RolesAllowed(\"tamper.detection\")\n    @Path(\"/pid/{pid}/_reset\")\n    public void resetTamperStatus(@PathParam(\"pid\") final String pid) {\n        try {\n            resetTamperStatusInternal(pid);\n        } catch (final KuraException e) {\n            throw toWebApplicationException(e);\n        }\n    }\n\n    private WebApplicationException toWebApplicationException(final KuraException e) {\n        if (e.getCode() == KuraErrorCode.NOT_FOUND) {\n            return new WebApplicationException(404);\n        } else {\n            return new WebApplicationException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/src/main/java/org/eclipse/kura/internal/rest/tamper/detection/util/TamperDetectionRemoteService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.rest.tamper.detection.util;\n\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.rest.tamper.detection.api.TamperDetectionServiceInfo;\nimport org.eclipse.kura.rest.tamper.detection.api.TamperStatusInfo;\nimport org.eclipse.kura.security.tamper.detection.TamperDetectionService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class TamperDetectionRemoteService {\n\n    private static final Logger logger = LoggerFactory.getLogger(TamperDetectionRemoteService.class);\n    private final Map<String, TamperDetectionService> tamperDetectionServices = new ConcurrentHashMap<>();\n\n    public void setTamperDetectionService(final TamperDetectionService tamperDetectionService,\n            final Map<String, Object> properties) {\n        final Optional<String> pid = getPid(properties);\n\n        if (pid.isPresent()) {\n            this.tamperDetectionServices.put(pid.get(), tamperDetectionService);\n        } else {\n            logger.warn(\"Tamper detection service must set either service.pid or kura.service.pid\");\n        }\n\n    }\n\n    public void unsetTamperDetectionService(final TamperDetectionService tamperDetectionService,\n            final Map<String, Object> properties) {\n        getPid(properties).ifPresent(this.tamperDetectionServices::remove);\n    }\n\n    protected List<TamperDetectionServiceInfo> listTamperDetectionServicesInternal() {\n        return tamperDetectionServices.entrySet().stream()\n                .map(e -> new TamperDetectionServiceInfo(e.getKey(), e.getValue().getDisplayName()))\n                .collect(Collectors.toList());\n    }\n\n    protected TamperStatusInfo getTamperStatusInternal(final String pid) throws KuraException {\n\n        final TamperDetectionService service = this.tamperDetectionServices.get(pid);\n\n        if (service == null) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n\n        return new TamperStatusInfo(service.getTamperStatus());\n    }\n\n    public void resetTamperStatusInternal(final String pid) throws KuraException {\n        final TamperDetectionService service = this.tamperDetectionServices.get(pid);\n\n        if (service == null) {\n            throw new KuraException(KuraErrorCode.NOT_FOUND);\n        }\n\n        service.resetTamperStatus();\n    }\n\n    private static final Optional<String> getPid(final Map<String, Object> properties) {\n        final Object kuraServicePid = properties.get(\"kura.service.pid\");\n\n        if (kuraServicePid instanceof String) {\n            return Optional.of((String) kuraServicePid);\n        }\n\n        final Object servicePid = properties.get(\"service.pid\");\n\n        if (servicePid instanceof String) {\n            return Optional.of((String) servicePid);\n        }\n\n        return Optional.empty();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/src/main/java/org/eclipse/kura/rest/tamper/detection/api/TamperDetectionServiceInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.tamper.detection.api;\n\npublic class TamperDetectionServiceInfo {\n\n    @SuppressWarnings(\"unused\")\n    private final String pid;\n    @SuppressWarnings(\"unused\")\n    private final String displayName;\n\n    public TamperDetectionServiceInfo(String pid, String displayName) {\n        this.pid = pid;\n        this.displayName = displayName;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.rest.tamper.detection.provider/src/main/java/org/eclipse/kura/rest/tamper/detection/api/TamperStatusInfo.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.tamper.detection.api;\n\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.security.tamper.detection.TamperStatus;\n\npublic class TamperStatusInfo {\n\n    @SuppressWarnings(\"unused\")\n    private final boolean isDeviceTampered;\n    @SuppressWarnings(\"unused\")\n    private final Map<String, Object> properties;\n\n    public TamperStatusInfo(final TamperStatus tamperStatus) {\n        this.isDeviceTampered = tamperStatus.isDeviceTampered();\n        this.properties = tamperStatus.getProperties().entrySet().stream()\n                .collect(Collectors.toMap(Entry::getKey, e -> e.getValue().getValue()));\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.stress/.gitignore",
    "content": "/target\n/bin\n"
  },
  {
    "path": "kura/org.eclipse.kura.stress/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.stress\nBundle-SymbolicName: org.eclipse.kura.stress;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura; version=\"[1.0,2.0)\",\n org.eclipse.kura.cloud; version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration; version=\"[1.0,2.0)\",\n org.eclipse.kura.message; version=\"[1.0,2.0)\",\n org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/org.eclipse.kura.stress/OSGI-INF/metatype/org.eclipse.kura.stress.Stress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.stress.Stress\"\n         name=\"Stress\" \n         description=\"Simple resource stress application.\">\n        \n        <Icon resource=\"http://s3.amazonaws.com/kura-resources/application/icon/applications-other.png\" size=\"32\"/>\n        \n        <AD id=\"heap.enable\"\n            name=\"heap.enable\"\n            type=\"Boolean\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"false\" \n            description=\"Enable heap stress.\"/>\n        \n        <AD id=\"heap.threads\"  \n            name=\"heap.threads\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"1\"\n            min=\"1\"\n            description=\"Number of heap allocation threads.\"/>\n            \n        <AD id=\"heap.size\"\n            name=\"heap.size\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"51200\"\n            min=\"1\"\n            description=\"Size in kilobytes of each memory allocation (as new byte[heap.size * 1024]).\"/>\n\n        <AD id=\"heap.stride\"  \n            name=\"heap.stride\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"1024\"\n            min=\"1\" \n            description=\"For each memory allocation, touch (writing 'k') one byte every N kilobytes.\"/>\n        \n        <AD id=\"heap.keep\"  \n            name=\"heap.keep\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"0\"\n            min=\"0\" \n            description=\"The number of milliseconds to keep every allocation (0: forever).\"/>\n\n        <AD id=\"heap.interval\"  \n            name=\"heap.interval\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"1000\"\n            min=\"1\" \n            description=\"The period between allocations in milliseconds.\"/>\n\n        <AD id=\"heap.delay\"\n            name=\"heap.delay\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"0\"\n            min=\"0\"\n            description=\"The start delay between threads in milliseconds.\"/>\n\n        <AD id=\"heap.log\"\n            name=\"heap.log\"\n            type=\"Boolean\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"true\" \n            description=\"Log each heap allocation iteration.\"/>\n                    \n    </OCD>\n    <Designate pid=\"org.eclipse.kura.stress.Stress\">\n        <Object ocdref=\"org.eclipse.kura.stress.Stress\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/org.eclipse.kura.stress/OSGI-INF/stress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n      Red Hat Inc\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" \n    name=\"org.eclipse.kura.stress.Stress\"\n    activate=\"activate\" \n    deactivate=\"deactivate\" \n    modified=\"updated\" \n    enabled=\"true\"\n    immediate=\"true\"\n    configuration-policy=\"require\">\n\t<implementation class=\"org.eclipse.kura.stress.HeapStress\"/>\n\n   <!-- If the component is configurable through the Kura ConfigurationService, it must expose a Service. -->\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.stress.Stress\"/>\n   <service>\n       <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n   \n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.stress/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.stress/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.stress/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/org.eclipse.kura.stress/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.stress</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.stress.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.stress/src/main/java/org/eclipse/kura/stress/HeapStress.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.stress;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class HeapStress implements ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(HeapStress.class);\n\n    private static final String HEAP_ENABLE_PROP_NAME = \"heap.enable\";\n    private static final String HEAP_THREADS_PROP_NAME = \"heap.threads\";\n    private static final String HEAP_KBYTES_PROP_NAME = \"heap.size\";\n    private static final String HEAP_STRIDE_KBYTES_PROP_NAME = \"heap.stride\";\n    private static final String HEAP_HANG_MS_PROP_NAME = \"heap.keep\";\n    private static final String HEAP_INTERVAL_MS_PROP_NAME = \"heap.interval\";\n    private static final String HEAP_LOG_PROP_NAME = \"heap.log\";\n    private static final String HEAP_DELAY_MS_PROP_NAME = \"heap.delay\";\n\n    private final ScheduledExecutorService worker;\n    private final List<ScheduledFuture<?>> handle;\n\n    private Map<String, Object> properties;\n\n    // ----------------------------------------------------------------\n    //\n    // Dependencies\n    //\n    // ----------------------------------------------------------------\n\n    public HeapStress() {\n        super();\n        this.worker = Executors.newScheduledThreadPool(5);\n        this.handle = new ArrayList<ScheduledFuture<?>>();\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    public void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        logger.info(\"Activating Stress...\");\n\n        this.properties = properties;\n        for (String s : properties.keySet()) {\n            logger.info(\"Activate - \" + s + \": \" + properties.get(s));\n        }\n\n        doUpdate();\n\n        logger.info(\"Activating Stress... Done.\");\n    }\n\n    public void deactivate(ComponentContext componentContext) {\n        logger.debug(\"Deactivating Stress...\");\n\n        // shutting down the worker and cleaning up the properties\n        this.worker.shutdown();\n\n        logger.debug(\"Deactivating Stress... Done.\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        logger.info(\"Updated Stress...\");\n\n        // store the properties received\n        this.properties = properties;\n        for (String s : properties.keySet()) {\n            logger.info(\"Update - \" + s + \": \" + properties.get(s));\n        }\n\n        // try to kick off a new job\n        doUpdate();\n        logger.info(\"Updated Stress... Done.\");\n    }\n\n    // ----------------------------------------------------------------\n    //\n    // Private Methods\n    //\n    // ----------------------------------------------------------------\n\n    /**\n     * Called after a new set of properties has been configured on the service\n     */\n    private void doUpdate() {\n        // cancel a current worker handle if one if active\n        for (ScheduledFuture<?> handleItem : this.handle) {\n            if (handleItem != null) {\n                handleItem.cancel(true);\n            }\n        }\n\n        final boolean enable = (Boolean) this.properties.get(HEAP_ENABLE_PROP_NAME);\n        final int threads = (Integer) this.properties.get(HEAP_THREADS_PROP_NAME);\n        final int size = 1024 * (Integer) this.properties.get(HEAP_KBYTES_PROP_NAME);\n        final int stride = 1024 * (Integer) this.properties.get(HEAP_STRIDE_KBYTES_PROP_NAME);\n        final int hang = (Integer) this.properties.get(HEAP_HANG_MS_PROP_NAME);\n        final int interval = (Integer) this.properties.get(HEAP_INTERVAL_MS_PROP_NAME);\n        final boolean log = (Boolean) this.properties.get(HEAP_LOG_PROP_NAME);\n        final int delay = (Integer) this.properties.get(HEAP_DELAY_MS_PROP_NAME);\n\n        if (enable) {\n            for (int i = 0; i < threads; i++) {\n                final int tid = i;\n                ScheduledFuture<?> futureHandle = this.worker.scheduleAtFixedRate(new Runnable() {\n\n                    @Override\n                    public void run() {\n                        String name = Thread.currentThread().getName();\n                        Thread.currentThread().setName(\"Heap stress thread #\" + tid);\n\n                        if (log) {\n                            logger.info(\"Heap stress thread #{} allocating...\", tid);\n                        }\n\n                        stressHeap(size, stride, hang);\n\n                        if (log) {\n                            logger.info(\"Heap stress thread #{} allocating... done\", tid);\n                        }\n\n                        Thread.currentThread().setName(name);\n                    }\n                }, delay * i, interval, TimeUnit.MILLISECONDS);\n                this.handle.add(futureHandle);\n            }\n        }\n    }\n\n    private void stressHeap(int size, int stride, long hang) {\n        byte[] b = new byte[size];\n\n        // touch one byte every stride bytes\n        for (int i = 0; i < b.length; i += stride) {\n            b[i] = 'k';\n        }\n\n        try {\n            if (hang > 0) {\n                Thread.sleep(hang);\n            } else {\n                while (true) {\n                    Thread.sleep(1000);\n                }\n            }\n        } catch (InterruptedException e) {\n            logger.warn(\"Interrupted\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.stress/src/main/resources/stress.dpp",
    "content": "#Deployment Plugin Project File\n#Fri Feb 26 13:57:47 CET 2016\nbuild.ant.name=<.>/src/main/resources/stress_build.xml\nbuild.dp.file=<.>/src/main/resources/stress.dp\nbuild.location=\nbundles.0.bundle_path=<.>/.project\nbundles.0.customizer=false\nbundles.0.headers.count=0\nbundles.0.missing=false\nbundles.0.name=bundles/org.eclipse.kura.stress.jar\nbundles.0.symbolic_name=org.eclipse.kura.stress\nbundles.0.version=1.0.0.qualifier\nbundles.count=1\ncertificates.count=0\ngeneral.signbundles=false\nheaders.other.headers=\nheaders.symbolic.name=stress\nheaders.version=1.0.0\nresources.count=0\n\n"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Kura Asset Accessor Provider\nBundle-SymbolicName: org.eclipse.kura.useradmin.store;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nBundle-Category: Asset-Driver Management\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: com.eclipsesource.json;version=\"0.9.0\",\n org.apache.felix.useradmin;version=\"[1.0,1.1)\",\n org.eclipse.kura;version=\"1.6.0\",\n org.eclipse.kura.configuration;version=\"1.2.0\",\n org.eclipse.kura.util.configuration;version=\"1.0.0\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.component;version=\"1.3.0\",\n org.osgi.service.useradmin;version=\"[1.1,1.2)\",\n org.slf4j;version=\"1.7.25\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/OSGI-INF/metatype/org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n   SPDX-License-Identifier: EPL-2.0\n    \n   Contributors:\n    Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\"\n         name=\"UserAdmin Store\"\n         description=\"This component provides snapshot-based persistence to the OSGi UserAdmin service.\">\n\n        <Icon resource=\"DenaliService\" size=\"32\"/>\n\n\t\t<AD id=\"roles.config\"\n        \tname=\"Role configuration\"\n        \ttype=\"String\"\n        \tcardinality=\"0\"\n        \trequired=\"true\"\n        \tdefault=\"[]\"\n        \tdescription=\"The currently defined UserAdmin Roles.\">\n        </AD>\n        \n        <AD id=\"users.config\"\n        \tname=\"User configuration\"\n        \ttype=\"String\"\n        \tcardinality=\"0\"\n        \trequired=\"true\"\n        \tdefault=\"[]\"\n        \tdescription=\"The currently defined UserAdmin Users.\">\n        </AD>\n        \n        <AD id=\"groups.config\"\n        \tname=\"Group configuration\"\n        \ttype=\"String\"\n        \tcardinality=\"0\"\n        \trequired=\"true\"\n        \tdefault=\"[]\"\n        \tdescription=\"The currently defined UserAdmin Groups.\">\n        </AD>\n\n        <AD id=\"write.delay.ms\"\n        \tname=\"Write Delay (milliseconds)\"\n        \ttype=\"Long\"\n        \tcardinality=\"0\"\n        \trequired=\"true\"\n        \tdefault=\"5000\"\n        \tdescription=\"This service defers the snapshot updates required for persisting changes made through UserAdmin APIs. The snapshot update is performed Write Delay milliseconds after the last change performed through UserAdmin APIs.\">\n        </AD>\n\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\">\n        <Object ocdref=\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\"/>\n    </Designate>\n</MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/OSGI-INF/org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2020, 2021 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n   SPDX-License-Identifier: EPL-2.0\n    \n   Contributors:\n    Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\" modified=\"update\" configuration-policy=\"require\" immediate=\"true\" name=\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\">\n   <implementation class=\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\"/>\n   <service>\n      <provide interface=\"org.apache.felix.useradmin.RoleRepositoryStore\"/>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.osgi.service.useradmin.UserAdminListener\"/>\n   </service>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\"/>\n   <property name=\"kura.ui.service.hide\" type=\"Boolean\" value=\"true\"/>\n   <reference bind=\"setConfigurationService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/build.properties",
    "content": "#\n#  Copyright (c) 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/\nsrc.includes = about.html\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2020, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n     \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.useradmin.store</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/src/main/java/org/eclipse/kura/internal/useradmin/store/DeserializationException.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.useradmin.store;\n\nclass DeserializationException extends Exception {\n\n    private static final long serialVersionUID = 2831107630794357637L;\n\n    public DeserializationException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public DeserializationException(String message) {\n        super(message);\n    }\n\n    public DeserializationException(Throwable cause) {\n        super(cause);\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/src/main/java/org/eclipse/kura/internal/useradmin/store/RoleRepositoryStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.useradmin.store;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.apache.felix.useradmin.RoleFactory;\nimport org.apache.felix.useradmin.RoleRepositoryStore;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.internal.useradmin.store.RoleSerializer.RoleBuilder;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\nimport org.osgi.service.useradmin.UserAdminEvent;\nimport org.osgi.service.useradmin.UserAdminListener;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonValue;\n\npublic class RoleRepositoryStoreImpl implements RoleRepositoryStore, UserAdminListener, ConfigurableComponent {\n\n    private static final String INTERNAL_UPDATE_ID_PROP_NAME = \"internal.update.id\";\n\n    private static final Logger logger = LoggerFactory.getLogger(RoleRepositoryStoreImpl.class);\n\n    private Map<String, Role> roles = new TreeMap<>();\n    private RoleRepositoryStoreOptions options;\n\n    long nextUpdateId = 0;\n    private final Set<Long> updateIds = new HashSet<>();\n\n    private ConfigurationService configurationService;\n\n    private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();\n    private Optional<ScheduledFuture<?>> storeTask = Optional.empty();\n\n    public void setConfigurationService(final ConfigurationService configurationService) {\n        this.configurationService = configurationService;\n    }\n\n    public void activate(final Map<String, Object> properties) {\n        logger.info(\"activating...\");\n\n        doUpdate(properties, RoleFactory::createRole);\n\n        logger.info(\"activating...done\");\n    }\n\n    public synchronized void update(final Map<String, Object> properties) {\n\n        if (isSelfUpdate(properties)) {\n            logger.info(\"Ignoring self update\");\n            return;\n        }\n\n        if (storeTask.isPresent() || !updateIds.isEmpty()) {\n            logger.info(\"Ignoring update since there are uncommitted changes\");\n            return;\n        }\n\n        logger.info(\"updating...\");\n\n        final RoleBuilder roleBuilder;\n\n        final BundleContext bundleContext = FrameworkUtil.getBundle(RoleRepositoryStoreImpl.class).getBundleContext();\n\n        final ServiceReference<UserAdmin> userAdminRef = bundleContext.getServiceReference(UserAdmin.class);\n\n        final UserAdmin userAdmin;\n\n        if (userAdminRef != null) {\n            userAdmin = bundleContext.getService(userAdminRef);\n        } else {\n            userAdmin = null;\n        }\n\n        if (userAdmin != null) {\n            roleBuilder = (type, name) -> userAdmin.createRole(name, type);\n\n            final Set<String> roleNames = new HashSet<>(this.roles.keySet());\n\n            for (final String name : roleNames) {\n                userAdmin.removeRole(name);\n            }\n\n        } else {\n            roleBuilder = RoleFactory::createRole;\n        }\n\n        try {\n            doUpdate(properties, roleBuilder);\n        } finally {\n            if (userAdmin != null) {\n                bundleContext.ungetService(userAdminRef);\n            }\n        }\n\n        logger.info(\"updating...done\");\n    }\n\n    public void deactivate() {\n        logger.info(\"deactivating...\");\n\n        this.executorService.shutdown();\n\n        logger.info(\"deactivating...done\");\n    }\n\n    @Override\n    public synchronized Role addRole(final String name, final int type) throws Exception {\n\n        if (this.roles.containsKey(name)) {\n            return null;\n        }\n\n        final Role role = RoleFactory.createRole(type, name);\n\n        this.roles.put(name, role);\n\n        return role;\n    }\n\n    @Override\n    public synchronized Role getRoleByName(final String name) throws Exception {\n        return this.roles.get(name);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public synchronized Role[] getRoles(final String filterString) throws Exception {\n\n        final Optional<Filter> filter;\n\n        if (filterString != null) {\n            filter = Optional.of(FrameworkUtil.createFilter(filterString));\n        } else {\n            filter = Optional.empty();\n        }\n\n        final List<Role> result = new ArrayList<>();\n\n        for (final Role role : this.roles.values()) {\n            if (!filter.isPresent() || filter.get().match(role.getProperties())) {\n                result.add(role);\n            }\n        }\n\n        return result.toArray(new Role[result.size()]);\n    }\n\n    @Override\n    public synchronized Role removeRole(final String role) throws Exception {\n        return Optional.ofNullable(this.roles.remove(role)).orElse(null);\n    }\n\n    private boolean isSelfUpdate(final Map<String, Object> properties) {\n        final Object id = properties.get(INTERNAL_UPDATE_ID_PROP_NAME);\n\n        if (id instanceof Long) {\n            final long updateId = (Long) id;\n\n            if (this.updateIds.contains(updateId)) {\n                this.updateIds.remove(updateId);\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    public long getNextUpdateId() {\n        final long updateId = this.nextUpdateId++;\n\n        this.updateIds.add(updateId);\n\n        return updateId;\n    }\n\n    private void doUpdate(final Map<String, Object> properties, final RoleBuilder roleBuilder) {\n        this.options = new RoleRepositoryStoreOptions(properties);\n\n        try {\n            this.roles = decode(this.options, roleBuilder);\n        } catch (final Exception e) {\n            logger.warn(\"failed to deserialize roles\", e);\n        }\n    }\n\n    private synchronized void scheduleStore() {\n\n        if (this.storeTask.isPresent()) {\n            this.storeTask.get().cancel(false);\n            this.storeTask = Optional.empty();\n        }\n\n        this.storeTask = Optional.of(\n                this.executorService.schedule(this::storeNow, this.options.getWriteDelayMs(), TimeUnit.MILLISECONDS));\n    }\n\n    private void storeNow() {\n\n        Map<String, Object> properties;\n        try {\n            synchronized (this) {\n\n                final JsonArray rolesArray = new JsonArray();\n                final JsonArray usersArray = new JsonArray();\n                final JsonArray groupsArray = new JsonArray();\n\n                for (final Role role : this.roles.values()) {\n                    final int type = role.getType();\n\n                    if (type == Role.ROLE) {\n                        rolesArray.add(RoleSerializer.serializeRole(role));\n                    } else if (type == Role.USER) {\n                        usersArray.add(RoleSerializer.serializeRole(role));\n                    } else if (type == Role.GROUP) {\n                        groupsArray.add(RoleSerializer.serializeRole(role));\n                    }\n                }\n\n                final RoleRepositoryStoreOptions newOptions = new RoleRepositoryStoreOptions(rolesArray.toString(), //\n                        usersArray.toString(), //\n                        groupsArray.toString(), //\n                        this.options.getWriteDelayMs() //\n                );\n\n                if (newOptions.equals(this.options)) {\n                    logger.info(\"update would not change current configuration, skipping\");\n                    return;\n                }\n\n                properties = newOptions.toProperties();\n                properties.put(INTERNAL_UPDATE_ID_PROP_NAME, getNextUpdateId());\n            }\n\n            this.configurationService.updateConfiguration(RoleRepositoryStoreImpl.class.getName(), properties);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to store configuration\", e);\n        } finally {\n            this.storeTask = Optional.empty();\n        }\n\n    }\n\n    private final Map<String, Role> decode(final RoleRepositoryStoreOptions options, final RoleBuilder roleBuilder)\n            throws DeserializationException {\n        try {\n            final Map<String, Role> result = new TreeMap<>();\n\n            decode(Json.parse(options.getRolesConfig()).asArray(), Role.class, result, roleBuilder);\n            decode(Json.parse(options.getUsersConfig()).asArray(), User.class, result, roleBuilder);\n\n            final JsonArray groups = Json.parse(options.getGroupsConfig()).asArray();\n\n            decode(groups, Group.class, result, roleBuilder);\n\n            for (final JsonValue member : groups) {\n                RoleSerializer.assignMembers(member.asObject(), result);\n            }\n\n            return result;\n\n        } catch (final DeserializationException e) {\n            throw e;\n        } catch (final Exception e) {\n            throw new DeserializationException(\"failed to deserialize role repository\", e);\n        }\n\n    }\n\n    private void decode(final JsonArray array, final Class<? extends Role> classz, final Map<String, Role> target,\n            final RoleBuilder roleBuilder) throws DeserializationException {\n        for (final JsonValue member : array) {\n            final Role role = RoleSerializer.deserializeRole(classz, member.asObject(), roleBuilder);\n            target.put(role.getName(), role);\n        }\n    }\n\n    @Override\n    public void roleChanged(UserAdminEvent arg0) {\n        logger.debug(\"received event\");\n        scheduleStore();\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/src/main/java/org/eclipse/kura/internal/useradmin/store/RoleRepositoryStoreOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.useradmin.store;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class RoleRepositoryStoreOptions {\n\n    private static final String ROLES_CONFIG_ID = \"roles.config\";\n    private static final String USERS_CONFIG_ID = \"users.config\";\n    private static final String GROUPS_CONFIG_ID = \"groups.config\";\n    private static final String WRITE_DELAY_MS_ID = \"write.delay.ms\";\n\n    private static final Property<String> ROLES_CONFIG = new Property<>(ROLES_CONFIG_ID, \"[]\");\n    private static final Property<String> USERS_CONFIG = new Property<>(USERS_CONFIG_ID, \"[]\");\n    private static final Property<String> GROUPS_CONFIG = new Property<>(GROUPS_CONFIG_ID, \"[]\");\n    private static final Property<Long> WRITE_DELAY_MS = new Property<>(WRITE_DELAY_MS_ID, 5000L);\n\n    private final String rolesConfig;\n    private final String usersConfig;\n    private final String groupsConfig;\n    private final long writeDelayMs;\n\n    public RoleRepositoryStoreOptions(String rolesConfig, String usersConfig, String gropusConfig, long writeDelayMs) {\n        this.rolesConfig = rolesConfig;\n        this.usersConfig = usersConfig;\n        this.groupsConfig = gropusConfig;\n        this.writeDelayMs = writeDelayMs;\n    }\n\n    public RoleRepositoryStoreOptions(final Map<String, Object> properties) {\n        this.rolesConfig = ROLES_CONFIG.get(properties);\n        this.usersConfig = USERS_CONFIG.get(properties);\n        this.groupsConfig = GROUPS_CONFIG.get(properties);\n        this.writeDelayMs = WRITE_DELAY_MS.get(properties);\n    }\n\n    public String getRolesConfig() {\n        return this.rolesConfig;\n    }\n\n    public String getUsersConfig() {\n        return this.usersConfig;\n    }\n\n    public String getGroupsConfig() {\n        return this.groupsConfig;\n    }\n\n    public long getWriteDelayMs() {\n        return this.writeDelayMs;\n    }\n\n    public Map<String, Object> toProperties() {\n        final Map<String, Object> result = new HashMap<>();\n\n        result.put(ROLES_CONFIG_ID, this.rolesConfig);\n        result.put(USERS_CONFIG_ID, this.usersConfig);\n        result.put(GROUPS_CONFIG_ID, this.groupsConfig);\n        result.put(WRITE_DELAY_MS_ID, this.writeDelayMs);\n\n        return result;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(groupsConfig, rolesConfig, usersConfig, writeDelayMs);\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (this == obj) {\n            return true;\n        }\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        RoleRepositoryStoreOptions other = (RoleRepositoryStoreOptions) obj;\n        return Objects.equals(groupsConfig, other.groupsConfig) && Objects.equals(rolesConfig, other.rolesConfig)\n                && Objects.equals(usersConfig, other.usersConfig) && writeDelayMs == other.writeDelayMs;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.useradmin.store/src/main/java/org/eclipse/kura/internal/useradmin/store/RoleSerializer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.useradmin.store;\n\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.Dictionary;\nimport java.util.Enumeration;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.TreeSet;\nimport java.util.function.Consumer;\n\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.JsonObject.Member;\nimport com.eclipsesource.json.JsonValue;\n\nclass RoleSerializer {\n\n    private static final Logger logger = LoggerFactory.getLogger(RoleSerializer.class);\n\n    private static final String NAME = \"name\";\n\n    private static final String ROLE_PROPERTIES = \"properties\";\n    private static final String USER_CREDENTIALS = \"credentials\";\n\n    private static final String GROUP_BASIC_MEMBERS = \"basicMembers\";\n    private static final String GROUP_REQUIRED_MEMBERS = \"requiredMembers\";\n\n    private RoleSerializer() {\n    }\n\n    private static JsonArray serializeByteArray(final byte[] value) {\n        final JsonArray result = new JsonArray();\n\n        for (final byte b : value) {\n            result.add(b);\n        }\n\n        return result;\n    }\n\n    private static JsonArray serializeRoleNames(final Role[] roles) {\n\n        final JsonArray result = new JsonArray();\n\n        if (roles == null) {\n            return result;\n        }\n\n        final Set<Role> sorted = new TreeSet<>(Comparator.comparing(Role::getName));\n        sorted.addAll(Arrays.asList(roles));\n\n        for (final Role r : sorted) {\n            result.add(r.getName());\n        }\n\n        return result;\n    }\n\n    @SuppressWarnings(\"rawtypes\")\n    static JsonObject serializeProperties(final Dictionary properties) {\n        final JsonObject result = new JsonObject();\n\n        final Map<String, Object> sorted = new TreeMap<>();\n\n        final Enumeration<?> keys = properties.keys();\n\n        while (keys.hasMoreElements()) {\n            final Object next = keys.nextElement();\n\n            if (!(next instanceof String)) {\n                logger.warn(\"unsupported property key: {}\", next);\n                continue;\n            }\n\n            final String key = (String) next;\n\n            sorted.put(key, properties.get(key));\n        }\n\n        for (final Entry<String, Object> e : sorted.entrySet()) {\n\n            final String key = e.getKey();\n            final Object value = e.getValue();\n\n            if (value instanceof String) {\n                result.add(key, (String) value);\n            } else if (value instanceof byte[]) {\n                result.add(key, serializeByteArray((byte[]) value));\n            } else {\n                logger.warn(\"unsupported property value: {}\", value);\n            }\n        }\n\n        return result;\n    }\n\n    static JsonObject serializeRole(final Role role) {\n        final JsonObject result = new JsonObject();\n\n        result.add(NAME, role.getName());\n\n        if (role instanceof User) {\n            final User asUser = (User) role;\n\n            if (!asUser.getCredentials().isEmpty()) {\n                result.add(USER_CREDENTIALS, serializeProperties(asUser.getCredentials()));\n            }\n        }\n\n        if (role instanceof Group) {\n            final Group asGroup = (Group) role;\n\n            if (asGroup.getMembers() != null) {\n                result.add(GROUP_BASIC_MEMBERS, serializeRoleNames(asGroup.getMembers()));\n            }\n\n            if (asGroup.getRequiredMembers() != null) {\n                result.add(GROUP_REQUIRED_MEMBERS, serializeRoleNames(asGroup.getRequiredMembers()));\n            }\n        }\n\n        if (!role.getProperties().isEmpty()) {\n            result.add(ROLE_PROPERTIES, serializeProperties(role.getProperties()));\n        }\n\n        return result;\n    }\n\n    private static byte[] deserializeByteArray(final JsonArray array) {\n        final byte[] result = new byte[array.size()];\n\n        for (int i = 0; i < array.size(); i++) {\n            result[i] = (byte) array.get(i).asInt();\n        }\n\n        return result;\n    }\n\n    @SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n    private static void deserializeProperties(final JsonObject properties, final Dictionary target) {\n        for (final Member member : properties) {\n            final JsonValue value = member.getValue();\n\n            if (value.isString()) {\n                target.put(member.getName(), value.asString());\n            } else if (value.isArray()) {\n                target.put(member.getName(), deserializeByteArray(value.asArray()));\n            }\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    static <T extends Role> T deserializeRole(final Class<T> classz, final JsonObject object,\n            final RoleBuilder roleBuilder) throws DeserializationException {\n        try {\n            final int type;\n\n            if (classz == Role.class) {\n                type = Role.ROLE;\n            } else if (classz == User.class) {\n                type = Role.USER;\n            } else if (classz == Group.class) {\n                type = Role.GROUP;\n            } else {\n                throw new IllegalArgumentException(\"Unsupported role type\");\n            }\n\n            final String name = object.get(NAME).asString();\n\n            final Role result = roleBuilder.build(type, name);\n\n            final JsonValue roleProperties = object.get(ROLE_PROPERTIES);\n\n            if (roleProperties != null) {\n                deserializeProperties(roleProperties.asObject(), result.getProperties());\n            }\n\n            if (result instanceof User) {\n                final User asUser = (User) result;\n                final JsonValue userCredentials = object.get(USER_CREDENTIALS);\n\n                if (userCredentials != null) {\n                    deserializeProperties(userCredentials.asObject(), asUser.getCredentials());\n                }\n            }\n\n            return (T) result;\n        } catch (final Exception e) {\n            throw new DeserializationException(\"failed to deserialize role\", e);\n        }\n    }\n\n    private static void assignMembers(final JsonArray members, final Map<String, Role> roles,\n            final Consumer<Role> consumer) {\n        for (final JsonValue value : members.asArray()) {\n            final String roleName = value.asString();\n\n            final Role member = roles.get(value.asString());\n\n            if (member == null) {\n                logger.warn(\"Role {} cannot be found\", roleName);\n                continue;\n            }\n\n            consumer.accept(member);\n        }\n    }\n\n    static void assignMembers(final JsonObject object, final Map<String, Role> roles) throws DeserializationException {\n        try {\n            final String name = object.get(NAME).asString();\n\n            final Role role = roles.get(name);\n\n            if (!(role instanceof Group)) {\n                return;\n            }\n\n            final Group asGroup = (Group) role;\n\n            final JsonValue basicMembers = object.get(GROUP_BASIC_MEMBERS);\n\n            if (basicMembers != null) {\n                assignMembers(basicMembers.asArray(), roles, asGroup::addMember);\n            }\n\n            final JsonValue requiredMembers = object.get(GROUP_REQUIRED_MEMBERS);\n\n            if (requiredMembers != null) {\n                assignMembers(requiredMembers.asArray(), roles, asGroup::addRequiredMember);\n            }\n\n        } catch (final Exception e) {\n            throw new DeserializationException(\"failed to deserialize role\", e);\n        }\n    }\n\n    public interface RoleBuilder {\n\n        public Role build(final int type, final String name);\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Kura Base Utilities\nBundle-SymbolicName: org.eclipse.kura.util;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.eclipse.kura;version=\"[1.2,2.0)\",\n org.eclipse.kura.annotation;version=\"[1.0,2.0)\",\n org.eclipse.kura.audit;version=\"1.0.0\",\n org.eclipse.kura.connection.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.data;version=\"[1.1,2.0)\",\n org.eclipse.kura.db;version=\"[2.0,3.0)\",\n org.eclipse.kura.message.store;version=\"[1.0,2.0)\",\n org.eclipse.kura.message.store.provider;version=\"[1.0,1.1)\",\n org.eclipse.kura.type;version=\"[1.1,2.0)\",\n org.eclipse.kura.wire;version=\"[2.0,3.0)\",\n org.eclipse.kura.wire.store.provider;version=\"1.0.0\",\n org.osgi.framework;version=\"[1.7.0,2.0.0)\",\n org.osgi.service.component.runtime;version=\"1.4.0\",\n org.osgi.service.component.runtime.dto;version=\"1.4.0\",\n org.osgi.service.useradmin;version=\"1.1.0\";resolution:=optional,\n org.osgi.util.tracker;version=\"1.5.1\",\n org.slf4j;version=\"1.6.4\"\nExport-Package: org.eclipse.kura.util.base;version=\"1.2.0\",\n org.eclipse.kura.util.collection;version=\"1.0.0\",\n org.eclipse.kura.util.configuration;version=\"1.0.0\",\n org.eclipse.kura.util.jdbc;version=\"1.0.0\";x-internal:=true,\n org.eclipse.kura.util.message.store;version=\"1.0.0\";x-internal:=true,\n org.eclipse.kura.util.osgi;version=\"1.1.0\",\n org.eclipse.kura.util.service;version=\"1.2.0\",\n org.eclipse.kura.util.store.listener;version=\"1.0.0\";x-internal:=true,\n org.eclipse.kura.util.useradmin;version=\"1.1.0\";x-internal:=true,\n org.eclipse.kura.util.validation;version=\"1.0.0\";x-internal:=true,\n org.eclipse.kura.util.wire.store;version=\"1.0.0\";x-internal:=true,\n org.eclipse.kura.util.zip;version=\"1.0.0\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.util/build.properties",
    "content": "#\n#  Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2016, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.util</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/base/StringUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.base;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.io.ByteArrayOutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Iterator;\n\nimport org.eclipse.kura.annotation.Nullable;\n\n/**\n * The Class StringUtil contains all necessary static factory methods for\n * manipulating String instances\n */\npublic final class StringUtil {\n\n    /** Constructor */\n    private StringUtil() {\n        // Static Factory Methods container. No need to instantiate.\n    }\n\n    /**\n     * Returns {@code true} if the given string is null or is the empty string.\n     *\n     * @param string\n     *            a string reference to check\n     * @return {@code true} if the string is null or is the empty string\n     */\n    public static boolean isNullOrEmpty(@Nullable final String string) {\n        return string == null || string.isEmpty();\n    }\n\n    /**\n     * Returns a string containing the tokens joined by delimiters.\n     *\n     * @param tokens\n     *            an array objects to be joined. Strings will be formed from the\n     *            objects by calling object.toString().\n     * @throws NullPointerException\n     *             if any of the arguments is null\n     */\n    public static String join(final CharSequence delimiter, final Iterable<?> tokens) {\n        requireNonNull(delimiter, \"Delimiter cannot be null.\");\n        requireNonNull(tokens, \"Iterable elements cannot be null.\");\n\n        final StringBuilder sb = new StringBuilder();\n        final Iterator<?> it = tokens.iterator();\n        if (it.hasNext()) {\n            sb.append(it.next());\n            while (it.hasNext()) {\n                sb.append(delimiter);\n                sb.append(it.next());\n            }\n        }\n        return sb.toString();\n    }\n\n    /**\n     * Unescape an UTF-8 string.\n     * \n     * @param string\n     *            an UTF-8 escaped string.\n     * @return string in UTF-8 with unescaped characters.\n     */\n\n    public static String unescapeUTF8String(final String string) {\n\n        requireNonNull(string, \"String cannot be null\");\n\n        ByteArrayOutputStream baos = new ByteArrayOutputStream();\n        int i = 0;\n        while (i < string.length()) {\n            if (string.charAt(i) == '\\\\') {\n                i += 2;\n                String hexString = string.substring(i, i + 2);\n                baos.write(Integer.parseInt(hexString, 16));\n                i += 2;\n            } else {\n                baos.write(string.charAt(i));\n                i += 1;\n            }\n        }\n\n        return new String(baos.toByteArray(), StandardCharsets.UTF_8);\n    }\n\n    /**\n     * Covert a string in hexadecimal format.\n     * \n     * @param string\n     *            string to be converted in hex format.\n     * @return string in hex format.\n     */\n\n    public static String toHex(String string) {\n        StringBuilder sb = new StringBuilder();\n        for (byte b : string.getBytes(StandardCharsets.UTF_8)) {\n            sb.append(String.format(\"%02X\", b));\n        }\n        return sb.toString();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/base/TypeUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.base;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.ObjectOutputStream;\n\n/**\n * The Class TypeUtil contains all necessary static factory methods for\n * manipulating java type instances\n */\npublic final class TypeUtil {\n\n    /** Constructor */\n    private TypeUtil() {\n        // Static Factory Methods container. No need to instantiate.\n    }\n\n    /**\n     * Returns a byte array representation of the provided integer value.\n     *\n     * @param value\n     *            The provided integer value\n     * @return the byte array instance\n     */\n    public static byte[] intToBytes(final int value) {\n        final byte[] result = new byte[4];\n        result[0] = (byte) (value >> 24);\n        result[1] = (byte) (value >> 16);\n        result[2] = (byte) (value >> 8);\n        result[3] = (byte) value;\n        return result;\n    }\n\n    /**\n     * Converts to the byte array from the provided object instance\n     *\n     * @param value\n     * @return the byte array\n     * @throws IOException\n     *             if the access to byte stream fails\n     * @throws NullPointerException\n     *             if the argument is null\n     */\n    public static byte[] objectToByteArray(final Object value) throws IOException {\n        requireNonNull(value, \"Value cannot be null.\");\n        final ByteArrayOutputStream b = new ByteArrayOutputStream();\n        final ObjectOutputStream o = new ObjectOutputStream(b);\n        o.writeObject(value);\n        return b.toByteArray();\n    }\n\n    /**\n     * \n     * Convert an hex string to a byte array. Simple copy-paste of the method in standard JRE 8\n     * {@link javax.xml.bind.DatatypeConverter#parseHexBinary(String)}\n     * \n     * @param string\n     * @return the byte array\n     * @throws IllegalArgumentException\n     *             if the hex string is invalid\n     */\n\n    public static byte[] parseHexBinary(String string) {\n        final int len = string.length();\n\n        // \"111\" is not a valid hex encoding.\n        if (len % 2 != 0) {\n            throw new IllegalArgumentException(\"hexBinary needs to be even-length: \" + string);\n        }\n\n        byte[] out = new byte[len / 2];\n\n        for (int i = 0; i < len; i += 2) {\n            int h = hexToBin(string.charAt(i));\n            int l = hexToBin(string.charAt(i + 1));\n            if (h == -1 || l == -1) {\n                throw new IllegalArgumentException(\"contains illegal character for hexBinary: \" + string);\n            }\n\n            out[i / 2] = (byte) (h * 16 + l);\n        }\n\n        return out;\n    }\n\n    private static int hexToBin(char ch) {\n        if ('0' <= ch && ch <= '9') {\n            return ch - '0';\n        }\n        if ('A' <= ch && ch <= 'F') {\n            return ch - 'A' + 10;\n        }\n        if ('a' <= ch && ch <= 'f') {\n            return ch - 'a' + 10;\n        }\n        return -1;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/collection/CollectionUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.collection;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Dictionary;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.CopyOnWriteArrayList;\n\n/**\n * The Class CollectionUtil contains all necessary static factory methods to\n * deal with different collection instances\n */\npublic final class CollectionUtil {\n\n    /** Constructor */\n    private CollectionUtil() {\n        // Static Factory Methods container. No need to instantiate.\n    }\n\n    /**\n     * Converts legacy {@link Dictionary} ADT to {@link Map}\n     *\n     * @param dictionary\n     *            The legacy {@link Dictionary} object to transform\n     * @throws NullPointerException\n     *             if argument is null\n     * @return the {@link Map} instance wrapping all the key-value association\n     *         from the {@link Dictionary}\n     */\n    public static <K, V> Map<K, V> dictionaryToMap(final Dictionary<K, V> dictionary) {\n        requireNonNull(dictionary, \"Dictionary cannot be null.\");\n        final Map<K, V> map = new HashMap<>(dictionary.size());\n        final Enumeration<K> keys = dictionary.keys();\n        while (keys.hasMoreElements()) {\n            final K key = keys.nextElement();\n            map.put(key, dictionary.get(key));\n        }\n        return map;\n    }\n\n    /**\n     * Creates a <i>mutable</i>, empty {@code ArrayList} instance.\n     *\n     * @param <E>\n     *            the element type\n     * @return empty ArrayList instance\n     */\n    public static <E> List<E> newArrayList() {\n        return new ArrayList<>();\n    }\n\n    /**\n     * Creates an {@code ArrayList} instance backed by an array with the\n     * specified initial size; simply delegates to\n     * {@link ArrayList#ArrayList(int)}.\n     *\n     * @param <E>\n     *            the element type\n     * @param initialArraySize\n     *            the initial capacity\n     * @return empty {@code ArrayList} instance with the provided capacity\n     * @throws IllegalArgumentException\n     *             if argument is less than 0\n     */\n    public static <E> List<E> newArrayListWithCapacity(final int initialArraySize) {\n        if (initialArraySize < 0) {\n            throw new IllegalArgumentException(\"Initial Array size must not be less than 0.\");\n        }\n        return new ArrayList<>(initialArraySize);\n    }\n\n    /**\n     * Creates a <i>mutable</i>, empty {@code ConcurrentHashMap} instance.\n     *\n     * @param <K>\n     *            the key type\n     * @param <V>\n     *            the value type\n     * @return a new, empty {@code ConcurrentHashMap}\n     */\n    public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap() {\n        return new ConcurrentHashMap<>();\n    }\n\n    /**\n     * Creates a <i>mutable</i>, empty {@code ConcurrentHashMap} instance.\n     *\n     * @param <K>\n     *            the key type\n     * @param <V>\n     *            the value type\n     * @param map\n     *            the map to contain\n     * @return a new, empty {@code ConcurrentHashMap}\n     * @throws NullPointerException\n     *             if argument is null\n     */\n    public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(final Map<K, V> map) {\n        requireNonNull(map, \"Map cannot be null.\");\n        return new ConcurrentHashMap<>(map);\n    }\n\n    /**\n     * Creates an empty {@code CopyOnWriteArrayList} instance.\n     *\n     * @param <E>\n     *            the element type\n     * @return a new, empty {@code CopyOnWriteArrayList}\n     */\n    public static <E> List<E> newCopyOnWriteArrayList() {\n        return new CopyOnWriteArrayList<>();\n    }\n\n    /**\n     * Creates a <i>mutable</i>, empty {@code HashMap} instance.\n     *\n     * @param <K>\n     *            the key type\n     * @param <V>\n     *            the value type\n     * @return a new, empty {@code HashMap}\n     */\n    public static <K, V> Map<K, V> newHashMap() {\n        return new HashMap<>();\n    }\n\n    /**\n     * Creates a <i>mutable</i> {@code HashMap} instance with the same mappings\n     * as the specified map.\n     *\n     * @param <K>\n     *            the key type\n     * @param <V>\n     *            the value type\n     * @param map\n     *            map the mappings to be inserted\n     * @return a new {@code HashMap}\n     * @throws NullPointerException\n     *             if argument is null\n     */\n    public static <K, V> Map<K, V> newHashMap(final Map<? extends K, ? extends V> map) {\n        requireNonNull(map, \"Map cannot be null.\");\n        return new HashMap<>(map);\n    }\n\n    /**\n     * Creates a <i>mutable</i>, initially empty {@code HashSet} instance.\n     *\n     * @param <E>\n     *            the element type\n     * @return a new, empty {@code HashSet}\n     */\n    public static <E> Set<E> newHashSet() {\n        return new HashSet<>();\n    }\n\n    /**\n     * Creates a <i>mutable</i>, {@code HashSet} instance containing the\n     * provided collection of values.\n     *\n     * @param collection\n     *            the collection of values to wrap\n     * @param <E>\n     *            the element type\n     * @return a new, empty {@code HashSet}\n     * @throws NullPointerException\n     *             if argument is null\n     */\n    public static <E> Set<E> newHashSet(final Collection<? extends E> collection) {\n        requireNonNull(collection, \"Collection cannot be null.\");\n        return new HashSet<>(collection);\n    }\n\n    /**\n     * Creates a <i>mutable</i>, empty, insertion-ordered {@code LinkedHashMap}\n     * instance.\n     *\n     * @param <K>\n     *            the key type\n     * @param <V>\n     *            the value type\n     * @return a new, empty {@code LinkedHashMap}\n     */\n    public static <K, V> Map<K, V> newLinkedHashMap() {\n        return new LinkedHashMap<>();\n    }\n\n    /**\n     * Creates a <i>mutable</i>, empty {@code LinkedList} instance (for Java 6\n     * and earlier).\n     *\n     * @param <E>\n     *            the element type\n     * @return the Linked List\n     */\n    public static <E> List<E> newLinkedList() {\n        return new LinkedList<>();\n    }\n\n    /**\n     * Creates a <i>mutable</i>, empty {@code TreeMap} instance using the\n     * natural ordering of its elements.\n     *\n     * @param <K>\n     *            the key type\n     * @param <V>\n     *            the value type\n     * @return a new, empty {@code TreeMap}\n     */\n    public static <K extends Comparable<K>, V> Map<K, V> newTreeMap() {\n        return new TreeMap<>();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/configuration/Property.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.configuration;\n\nimport java.util.Map;\nimport java.util.Optional;\n\npublic final class Property<T> {\n\n    private final String key;\n    private final Optional<T> defaultValue;\n    private final Class<? extends T> classz;\n\n    @SuppressWarnings(\"unchecked\")\n    public Property(final String key, final T defaultValue) {\n        this.key = key;\n        this.defaultValue = Optional.of(defaultValue);\n        this.classz = (Class<? extends T>) defaultValue.getClass();\n    }\n\n    public Property(final String key, final Class<T> classz) {\n        this.key = key;\n        this.classz = classz;\n        this.defaultValue = Optional.empty();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public T get(final Map<String, Object> properties) {\n        final Object value = properties.get(this.key);\n\n        if (this.classz.isInstance(value)) {\n            return (T) value;\n        }\n        return this.defaultValue.orElseThrow(() -> new IllegalStateException(\"configuration property + \\\"\" + key\n                + \"\\\" has not been provided set and the property does not have a default value\"));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public Optional<T> getOptional(final Map<String, Object> properties) {\n        final Object value = properties.get(this.key);\n\n        if (this.classz.isInstance(value)) {\n            return Optional.of((T) value);\n        }\n        return Optional.empty();\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/jdbc/ConnectionProvider.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.jdbc;\n\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\n\nimport org.eclipse.kura.KuraStoreException;\n\npublic interface ConnectionProvider {\n    public <T> T withConnection(final SQLFunction<Connection, T> task) throws SQLException;\n\n    public default <T> T withConnection(final SQLFunction<Connection, T> task, final String message)\n            throws KuraStoreException {\n        try {\n            return this.withConnection(task);\n        } catch (final Exception e) {\n            throw new KuraStoreException(e, message);\n        }\n    }\n\n    public default <T> T withPreparedStatement(final String sql,\n            final SQLBiFunction<Connection, PreparedStatement, T> task, final String message)\n            throws KuraStoreException {\n\n        return this.withConnection(c -> {\n            try (final PreparedStatement s = c.prepareStatement(sql)) {\n                return task.call(c, s);\n            }\n        }, message);\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/jdbc/JdbcUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.jdbc;\n\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.Optional;\n\npublic class JdbcUtil {\n\n    private JdbcUtil() {\n    }\n\n    public static <T> Optional<T> getFirstColumnValueOrEmpty(final SQLSupplier<ResultSet> resultSet,\n            final SQLBiFunction<ResultSet, Integer, T> extractor) throws SQLException {\n        try (final ResultSet rs = resultSet.get()) {\n            if (rs.next()) {\n                return Optional.of(extractor.call(rs, 1));\n            } else {\n                return Optional.empty();\n            }\n        }\n    }\n\n    public static <T> T getFirstColumnValue(final SQLSupplier<ResultSet> resultSet,\n            final SQLBiFunction<ResultSet, Integer, T> extractor) throws SQLException {\n        return getFirstColumnValueOrEmpty(resultSet, extractor).orElseThrow(() -> new SQLException(\"empty result set\"));\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/jdbc/SQLBiFunction.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.jdbc;\n\nimport java.sql.SQLException;\n\npublic interface SQLBiFunction<T, U, V> {\n\n    public V call(T first, U second) throws SQLException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/jdbc/SQLFunction.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.jdbc;\n\nimport java.sql.SQLException;\n\npublic interface SQLFunction<T, U> {\n\n    public U call(T value) throws SQLException;\n}"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/jdbc/SQLSupplier.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.jdbc;\n\nimport java.sql.SQLException;\n\npublic interface SQLSupplier<T> {\n\n    public T get() throws SQLException;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/message/store/AbstractJdbcMessageStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.message.store;\n\nimport static java.util.Objects.requireNonNull;\nimport static org.eclipse.kura.util.jdbc.JdbcUtil.getFirstColumnValue;\nimport static org.eclipse.kura.util.jdbc.JdbcUtil.getFirstColumnValueOrEmpty;\n\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Timestamp;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.TimeZone;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.message.store.StoredMessage;\nimport org.eclipse.kura.message.store.provider.MessageStore;\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.util.jdbc.SQLFunction;\n\npublic abstract class AbstractJdbcMessageStoreImpl implements MessageStore {\n\n    private static final String TOPIC_ELEMENT = \"topic\";\n\n    protected final String tableName;\n    protected final String escapedTableName;\n    protected final JdbcMessageStoreQueries queries;\n    protected final ConnectionProvider connectionProvider;\n    protected final Calendar utcCalendar;\n\n    protected AbstractJdbcMessageStoreImpl(final ConnectionProvider connectionProvider, final String tableName) {\n        if (tableName == null || tableName.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"Table name cannot be null or empty.\");\n        }\n        this.tableName = tableName;\n        this.connectionProvider = requireNonNull(connectionProvider, \"Connection provider cannot be null\");\n        this.escapedTableName = escapeIdentifier(tableName);\n        this.utcCalendar = buildUTCCalendar();\n        this.queries = buildSqlMessageStoreQueries();\n    }\n\n    protected abstract JdbcMessageStoreQueries buildSqlMessageStoreQueries();\n\n    protected String escapeIdentifier(final String string) {\n        final String sanitizedName = string.replace(\"\\\"\", \"\\\"\\\"\");\n        return \"\\\"\" + sanitizedName + \"\\\"\";\n    }\n\n    protected void createTable() throws KuraStoreException {\n        execute(this.queries.getSqlCreateTable());\n    }\n\n    protected void createIndexes() throws KuraStoreException {\n        execute(this.queries.getSqlCreateNextMessageIndex());\n        execute(this.queries.getSqlCreatePublishedOnIndex());\n        execute(this.queries.getSqlCreateConfirmedOnIndex());\n        execute(this.queries.getSqlCreateDroppedOnIndex());\n    }\n\n    @Override\n    public synchronized int getMessageCount() throws KuraStoreException {\n\n        return (int) getMessageCountInternal();\n    }\n\n    protected long getMessageCountInternal() throws KuraStoreException {\n\n        return this.connectionProvider.withPreparedStatement(this.queries.getSqlMessageCount(),\n                (c, stmt) -> getFirstColumnValue(stmt::executeQuery, ResultSet::getLong), \"Cannot get message count\");\n\n    }\n\n    protected void validate(String topic) throws KuraStoreException {\n        if (topic == null || topic.trim().length() == 0) {\n            throw new KuraStoreException(null, \"topic must be not null and not empty\");\n        }\n    }\n\n    protected long storeInternal(String topic, byte[] payload, int qos, boolean retain, int priority)\n            throws KuraStoreException {\n        validate(topic);\n\n        final Timestamp now = new Timestamp(new Date().getTime());\n\n        return this.connectionProvider.withConnection(c -> {\n\n            final long result;\n\n            try (PreparedStatement pstmt = c.prepareStatement(this.queries.getSqlStore(),\n                    new String[] { \"id\" })) {\n\n                pstmt.setString(1, topic);\n                pstmt.setInt(2, qos);\n                pstmt.setBoolean(3, retain);\n                pstmt.setTimestamp(4, now, this.utcCalendar);\n                pstmt.setTimestamp(5, null);\n                pstmt.setInt(6, -1);\n                pstmt.setTimestamp(7, null);\n                pstmt.setBytes(8, payload);\n                pstmt.setInt(9, priority);\n                pstmt.setString(10, null);\n                pstmt.setTimestamp(11, null);\n                pstmt.execute();\n\n                result = getFirstColumnValue(pstmt::getGeneratedKeys, ResultSet::getLong);\n            }\n\n            if (isExplicitCommitEnabled()) {\n                c.commit();\n            }\n\n            return result;\n        }, \"Cannot store message\");\n\n    }\n\n    @Override\n    public Optional<StoredMessage> get(int msgId) throws KuraStoreException {\n\n        return get(msgId, rs -> buildStoredMessageBuilder(rs, true).build());\n    }\n\n    protected Optional<StoredMessage> get(int msgId, final SQLFunction<ResultSet, StoredMessage> messageBuilder)\n            throws KuraStoreException {\n\n        return this.connectionProvider.withPreparedStatement(this.queries.getSqlGetMessage(), (c, stmt) -> {\n            stmt.setInt(1, msgId);\n\n            return getFirstColumnValueOrEmpty(stmt::executeQuery, (rs, i) -> messageBuilder.call(rs));\n\n        }, \"Cannot get message by ID: \" + msgId);\n    }\n\n    @Override\n    public Optional<StoredMessage> getNextMessage() throws KuraStoreException {\n\n        return getNextMessage(rs -> buildStoredMessageBuilder(rs, true).build());\n\n    }\n\n    protected Optional<StoredMessage> getNextMessage(final SQLFunction<ResultSet, StoredMessage> messageBuilder)\n            throws KuraStoreException {\n\n        return this.connectionProvider.withPreparedStatement(this.queries.getSqlGetNextMessage(),\n                (c, stmt) -> getFirstColumnValueOrEmpty(stmt::executeQuery, (rs, i) -> messageBuilder.call(rs)),\n                \"Cannot get message next message\");\n    }\n\n    @Override\n    public void markAsPublished(int msgId, DataTransportToken token) throws KuraStoreException {\n        final Timestamp now = new Timestamp(new Date().getTime());\n\n        this.connectionProvider.withPreparedStatement(this.queries.getSqlSetPublishedQoS1(), (c, stmt) -> {\n\n            stmt.setTimestamp(1, now, this.utcCalendar);\n            stmt.setInt(2, token.getMessageId());\n            stmt.setString(3, token.getSessionId());\n            stmt.setInt(4, msgId);\n\n            stmt.execute();\n\n            if (isExplicitCommitEnabled()) {\n                c.commit();\n            }\n            return null;\n\n        }, \"Cannot update timestamp\");\n\n    }\n\n    @Override\n    public void markAsPublished(int msgId) throws KuraStoreException {\n        updateTimestamp(this.queries.getSqlSetPublishedQoS0(), msgId);\n    }\n\n    @Override\n    public void markAsConfirmed(int msgId) throws KuraStoreException {\n        updateTimestamp(this.queries.getSqlSetConfirmed(), msgId);\n    }\n\n    @Override\n    public List<StoredMessage> getUnpublishedMessages() throws KuraStoreException {\n\n        return listMessages(this.queries.getSqlAllUnpublishedMessages());\n    }\n\n    @Override\n    public List<StoredMessage> getInFlightMessages() throws KuraStoreException {\n\n        return listMessages(this.queries.getSqlAllInFlightMessages());\n    }\n\n    @Override\n    public synchronized List<StoredMessage> getDroppedMessages() throws KuraStoreException {\n\n        return listMessages(this.queries.getSqlAllDroppedInFlightMessages());\n    }\n\n    @Override\n    public synchronized void unpublishAllInFlighMessages() throws KuraStoreException {\n        execute(this.queries.getSqlUnpublishAllInFlightMessages());\n    }\n\n    @Override\n    public synchronized void dropAllInFlightMessages() throws KuraStoreException {\n        updateTimestamp(this.queries.getSqlDropAllInFlightMessages());\n    }\n\n    @Override\n    public synchronized void deleteStaleMessages(int purgeAgeSeconds) throws KuraStoreException {\n        final long timestamp = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(purgeAgeSeconds);\n\n        deleteStaleMessages(timestamp);\n    }\n\n    @Override\n    public void close() {\n        // nothing to close\n    }\n\n    protected void deleteStaleMessages(final Object timestamp) throws KuraStoreException {\n\n        execute(this.queries.getSqlDeleteDroppedMessages(), timestamp);\n\n        execute(this.queries.getSqlDeleteConfirmedMessages(), timestamp);\n\n        execute(this.queries.getSqlDeletePublishedMessages(), timestamp);\n    }\n\n    protected void updateTimestamp(String sql, Integer... msgIds) throws KuraStoreException {\n        final Timestamp now = new Timestamp(new Date().getTime());\n\n        this.connectionProvider.withPreparedStatement(sql, (c, stmt) -> {\n            stmt.setTimestamp(1, now, this.utcCalendar);\n\n            for (int i = 0; i < msgIds.length; i++) {\n                stmt.setInt(2 + i, msgIds[i]);\n            }\n            stmt.execute();\n\n            if (isExplicitCommitEnabled()) {\n                c.commit();\n            }\n            return null;\n\n        }, \"Cannot update timestamp\");\n    }\n\n    protected List<StoredMessage> listMessages(String sql, Integer... params) throws KuraStoreException {\n        return this.connectionProvider.withPreparedStatement(sql, (c, stmt) -> {\n            if (params != null) {\n                for (int i = 0; i < params.length; i++) {\n                    stmt.setInt(2 + i, params[i]);\n                }\n            }\n\n            try (final ResultSet rs = stmt.executeQuery()) {\n                return buildStoredMessagesNoPayload(rs);\n            }\n        }, \"Cannot list messages\");\n    }\n\n    protected void execute(String sql, Object... params) throws KuraStoreException {\n        this.connectionProvider.withPreparedStatement(sql, (c, stmt) -> {\n\n            for (int i = 0; i < params.length; i++) {\n                stmt.setObject(1 + i, params[i]);\n            }\n\n            stmt.execute();\n\n            if (isExplicitCommitEnabled()) {\n                c.commit();\n            }\n            return null;\n\n        }, \"Cannot execute query\");\n    }\n\n    protected List<StoredMessage> buildStoredMessagesNoPayload(ResultSet rs) throws SQLException {\n        List<StoredMessage> messages = new ArrayList<>();\n        while (rs.next()) {\n            messages.add(buildStoredMessageBuilder(rs, false).build());\n        }\n        return messages;\n    }\n\n    protected StoredMessage.Builder buildStoredMessageBuilder(ResultSet rs, final boolean includePayload)\n            throws SQLException {\n        StoredMessage.Builder builder = new StoredMessage.Builder(rs.getInt(\"id\"))\n                .withTopic(rs.getString(TOPIC_ELEMENT)).withQos(rs.getInt(\"qos\")).withRetain(rs.getBoolean(\"retain\"))\n                .withCreatedOn(rs.getTimestamp(\"createdOn\", this.utcCalendar))\n                .withPublishedOn(rs.getTimestamp(\"publishedOn\", this.utcCalendar))\n                .withConfirmedOn(rs.getTimestamp(\"confirmedOn\", this.utcCalendar)).withPriority(rs.getInt(\"priority\"))\n                .withDroppedOn(rs.getTimestamp(\"droppedOn\"));\n\n        if (includePayload) {\n            builder = builder.withPayload(rs.getBytes(\"payload\"));\n        }\n\n        final String sessionId = rs.getString(\"sessionId\");\n\n        if (sessionId != null) {\n            builder = builder\n                    .withDataTransportToken(new DataTransportToken(rs.getInt(\"publishedMessageId\"), sessionId));\n        }\n\n        return builder;\n    }\n\n    protected Calendar buildUTCCalendar() {\n        return Calendar.getInstance(TimeZone.getTimeZone(\"UTC\"));\n    }\n\n    protected boolean isExplicitCommitEnabled() {\n        return false;\n    }\n\n    protected JdbcMessageStoreQueries getQueries() {\n        return queries;\n    }\n\n    protected ConnectionProvider getConnectionProvider() {\n        return connectionProvider;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/message/store/JdbcMessageStoreQueries.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.message.store;\n\nimport static java.util.Objects.requireNonNull;\n\npublic final class JdbcMessageStoreQueries {\n\n    private final String sqlCreateTable;\n    private final String sqlMessageCount;\n    private final String sqlStore;\n    private final String sqlGetMessage;\n    private final String sqlGetNextMessage;\n    private final String sqlSetPublishedQoS1;\n    private final String sqlSetPublishedQoS0;\n    private final String sqlSetConfirmed;\n    private final String sqlAllUnpublishedMessages;\n    private final String sqlAllInFlightMessages;\n    private final String sqlAllDroppedInFlightMessages;\n    private final String sqlUnpublishAllInFlightMessages;\n    private final String sqlDropAllInFlightMessages;\n    private final String sqlDeleteDroppedMessages;\n    private final String sqlDeleteConfirmedMessages;\n    private final String sqlDeletePublishedMessages;\n    private final String sqlCreateNextMessageIndex;\n    private final String sqlCreatePublishedOnIndex;\n    private final String sqlCreateConfirmedOnIndex;\n    private final String sqlCreateDroppedOnIndex;\n\n    private JdbcMessageStoreQueries(Builder builder) {\n        this.sqlCreateTable = requireNonNull(builder.sqlCreateTable);\n        this.sqlMessageCount = requireNonNull(builder.sqlMessageCount);\n        this.sqlStore = requireNonNull(builder.sqlStore);\n        this.sqlGetMessage = requireNonNull(builder.sqlGetMessage);\n        this.sqlGetNextMessage = requireNonNull(builder.sqlGetNextMessage);\n        this.sqlSetPublishedQoS1 = requireNonNull(builder.sqlSetPublishedQoS1);\n        this.sqlSetPublishedQoS0 = requireNonNull(builder.sqlSetPublishedQoS0);\n        this.sqlSetConfirmed = requireNonNull(builder.sqlSetConfirmed);\n        this.sqlAllUnpublishedMessages = requireNonNull(builder.sqlAllUnpublishedMessages);\n        this.sqlAllInFlightMessages = requireNonNull(builder.sqlAllInFlightMessages);\n        this.sqlAllDroppedInFlightMessages = requireNonNull(builder.sqlAllDroppedInFlightMessages);\n        this.sqlUnpublishAllInFlightMessages = requireNonNull(builder.sqlUnpublishAllInFlightMessages);\n        this.sqlDropAllInFlightMessages = requireNonNull(builder.sqlDropAllInFlightMessages);\n        this.sqlDeleteDroppedMessages = requireNonNull(builder.sqlDeleteDroppedMessages);\n        this.sqlDeleteConfirmedMessages = requireNonNull(builder.sqlDeleteConfirmedMessages);\n        this.sqlDeletePublishedMessages = requireNonNull(builder.sqlDeletePublishedMessages);\n        this.sqlCreateNextMessageIndex = requireNonNull(builder.sqlCreateNextMessageIndex);\n        this.sqlCreatePublishedOnIndex = requireNonNull(builder.sqlCreatePublishedOnIndex);\n        this.sqlCreateConfirmedOnIndex = requireNonNull(builder.sqlCreateConfirmedOnIndex);\n        this.sqlCreateDroppedOnIndex = requireNonNull(builder.sqlCreateDroppedOnIndex);\n    }\n\n    public String getSqlCreateTable() {\n        return sqlCreateTable;\n    }\n\n    public String getSqlMessageCount() {\n        return sqlMessageCount;\n    }\n\n    public String getSqlStore() {\n        return sqlStore;\n    }\n\n    public String getSqlGetMessage() {\n        return sqlGetMessage;\n    }\n\n    public String getSqlGetNextMessage() {\n        return sqlGetNextMessage;\n    }\n\n    public String getSqlSetPublishedQoS1() {\n        return sqlSetPublishedQoS1;\n    }\n\n    public String getSqlSetPublishedQoS0() {\n        return sqlSetPublishedQoS0;\n    }\n\n    public String getSqlSetConfirmed() {\n        return sqlSetConfirmed;\n    }\n\n    public String getSqlAllUnpublishedMessages() {\n        return sqlAllUnpublishedMessages;\n    }\n\n    public String getSqlAllInFlightMessages() {\n        return sqlAllInFlightMessages;\n    }\n\n    public String getSqlAllDroppedInFlightMessages() {\n        return sqlAllDroppedInFlightMessages;\n    }\n\n    public String getSqlUnpublishAllInFlightMessages() {\n        return sqlUnpublishAllInFlightMessages;\n    }\n\n    public String getSqlDropAllInFlightMessages() {\n        return sqlDropAllInFlightMessages;\n    }\n\n    public String getSqlDeleteDroppedMessages() {\n        return sqlDeleteDroppedMessages;\n    }\n\n    public String getSqlDeleteConfirmedMessages() {\n        return sqlDeleteConfirmedMessages;\n    }\n\n    public String getSqlDeletePublishedMessages() {\n        return sqlDeletePublishedMessages;\n    }\n\n    public String getSqlCreateNextMessageIndex() {\n        return sqlCreateNextMessageIndex;\n    }\n\n    public String getSqlCreatePublishedOnIndex() {\n        return sqlCreatePublishedOnIndex;\n    }\n\n    public String getSqlCreateConfirmedOnIndex() {\n        return sqlCreateConfirmedOnIndex;\n    }\n\n    public String getSqlCreateDroppedOnIndex() {\n        return sqlCreateDroppedOnIndex;\n    }\n\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    public static final class Builder {\n\n        private String sqlCreateTable;\n        private String sqlMessageCount;\n        private String sqlStore;\n        private String sqlGetMessage;\n        private String sqlGetNextMessage;\n        private String sqlSetPublishedQoS1;\n        private String sqlSetPublishedQoS0;\n        private String sqlSetConfirmed;\n        private String sqlAllUnpublishedMessages;\n        private String sqlAllInFlightMessages;\n        private String sqlAllDroppedInFlightMessages;\n        private String sqlUnpublishAllInFlightMessages;\n        private String sqlDropAllInFlightMessages;\n        private String sqlDeleteDroppedMessages;\n        private String sqlDeleteConfirmedMessages;\n        private String sqlDeletePublishedMessages;\n        private String sqlCreateNextMessageIndex;\n        private String sqlCreatePublishedOnIndex;\n        private String sqlCreateConfirmedOnIndex;\n        private String sqlCreateDroppedOnIndex;\n\n        public Builder withSqlCreateTable(String sqlCreateTable) {\n            this.sqlCreateTable = sqlCreateTable;\n            return this;\n        }\n\n        public Builder withSqlMessageCount(String sqlMessageCount) {\n            this.sqlMessageCount = sqlMessageCount;\n            return this;\n        }\n\n        public Builder withSqlStore(String sqlStore) {\n            this.sqlStore = sqlStore;\n            return this;\n        }\n\n        public Builder withSqlGetMessage(String sqlGetMessage) {\n            this.sqlGetMessage = sqlGetMessage;\n            return this;\n        }\n\n        public Builder withSqlGetNextMessage(String sqlGetNextMessage) {\n            this.sqlGetNextMessage = sqlGetNextMessage;\n            return this;\n        }\n\n        public Builder withSqlSetPublishedQoS1(String sqlSetPublishedQoS1) {\n            this.sqlSetPublishedQoS1 = sqlSetPublishedQoS1;\n            return this;\n        }\n\n        public Builder withSqlSetPublishedQoS0(String sqlSetPublishedQoS0) {\n            this.sqlSetPublishedQoS0 = sqlSetPublishedQoS0;\n            return this;\n        }\n\n        public Builder withSqlSetConfirmed(String sqlSetConfirmed) {\n            this.sqlSetConfirmed = sqlSetConfirmed;\n            return this;\n        }\n\n        public Builder withSqlAllUnpublishedMessages(String sqlAllUnpublishedMessages) {\n            this.sqlAllUnpublishedMessages = sqlAllUnpublishedMessages;\n            return this;\n        }\n\n        public Builder withSqlAllInFlightMessages(String sqlAllInFlightMessages) {\n            this.sqlAllInFlightMessages = sqlAllInFlightMessages;\n            return this;\n        }\n\n        public Builder withSqlAllDroppedInFlightMessages(String sqlAllDroppedInFlightMessages) {\n            this.sqlAllDroppedInFlightMessages = sqlAllDroppedInFlightMessages;\n            return this;\n        }\n\n        public Builder withSqlUnpublishAllInFlightMessages(String sqlUnpublishAllInFlightMessages) {\n            this.sqlUnpublishAllInFlightMessages = sqlUnpublishAllInFlightMessages;\n            return this;\n        }\n\n        public Builder withSqlDropAllInFlightMessages(String sqlDropAllInFlightMessages) {\n            this.sqlDropAllInFlightMessages = sqlDropAllInFlightMessages;\n            return this;\n        }\n\n        public Builder withSqlDeleteDroppedMessages(String sqlDeleteDroppedMessages) {\n            this.sqlDeleteDroppedMessages = sqlDeleteDroppedMessages;\n            return this;\n        }\n\n        public Builder withSqlDeleteConfirmedMessages(String sqlDeleteConfirmedMessages) {\n            this.sqlDeleteConfirmedMessages = sqlDeleteConfirmedMessages;\n            return this;\n        }\n\n        public Builder withSqlDeletePublishedMessages(String sqlDeletePublishedMessages) {\n            this.sqlDeletePublishedMessages = sqlDeletePublishedMessages;\n            return this;\n        }\n\n        public Builder withSqlCreateNextMessageIndex(String sqlCreateNextMessageIndex) {\n            this.sqlCreateNextMessageIndex = sqlCreateNextMessageIndex;\n            return this;\n        }\n\n        public Builder withSqlCreatePublishedOnIndex(String sqlCreatePublishedOnIndex) {\n            this.sqlCreatePublishedOnIndex = sqlCreatePublishedOnIndex;\n            return this;\n        }\n\n        public Builder withSqlCreateConfirmedOnIndex(String sqlCreateConfirmedOnIndex) {\n            this.sqlCreateConfirmedOnIndex = sqlCreateConfirmedOnIndex;\n            return this;\n        }\n\n        public Builder withSqlCreateDroppedOnIndex(String sqlCreateDroppedOnIndex) {\n            this.sqlCreateDroppedOnIndex = sqlCreateDroppedOnIndex;\n            return this;\n        }\n\n        public JdbcMessageStoreQueries build() {\n            return new JdbcMessageStoreQueries(this);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/osgi/BundleUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.osgi;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\n\n/**\n * The Class BundleUtil contains all necessary static factory methods to deal\n * with OSGi bundles.\n */\npublic class BundleUtil {\n\n    private BundleUtil() {\n        // Static Factory Methods container. No need to instantiate.\n    }\n\n    /**\n     * Returns the set of OSGi bundles in which registered services match one of the classes and all specified\n     * properties.\n     * \n     * @param bundleContext\n     *            the context of bundle.\n     * @param classes\n     *            Array of possible classes.\n     * @param properties\n     *            Map of required properties.\n     * @return A set of OSGi bundles.\n     */\n\n    public static Set<Bundle> getBundles(final BundleContext bundleContext, final Class<?>[] classes,\n            final Map<String, String> properties) {\n        requireNonNull(bundleContext, \"Bundle context cannot be null.\");\n        requireNonNull(properties, \"Filter cannot be null.\");\n        requireNonNull(classes, \"Class array cannot be null.\");\n\n        String classFilter = Arrays.stream(classes).map(FilterUtil::objectClass).reduce(\"\", FilterUtil::or);\n\n        String propertiesFilter = properties.entrySet().stream().map(p -> FilterUtil.equal(p.getKey(), p.getValue()))\n                .reduce(\"\", FilterUtil::and);\n\n        String filterAsString = FilterUtil.and(classFilter, propertiesFilter);\n\n        try {\n            Filter filter = bundleContext.createFilter(filterAsString);\n            ServiceReference<?>[] services = bundleContext.getAllServiceReferences(null, filter.toString());\n\n            if (services == null || services.length == 0) {\n                return Collections.emptySet();\n            }\n\n            return Arrays.stream(services).map(ServiceReference::getBundle).collect(Collectors.toSet());\n\n        } catch (InvalidSyntaxException e) {\n            throw new IllegalArgumentException(e);\n        }\n    }\n\n    /**\n     * Returns the set of OSGi bundles containing the list of required headers key/value in the MANIFEST.MF file.\n     * \n     * @param bundleContext\n     *            the context of the bundle.\n     * @param headers\n     *            the list of key/value required headers\n     * @return the set of bundles\n     */\n\n    public static Set<Bundle> getBundles(final BundleContext bundleContext, final Map<String, String> headers) {\n        requireNonNull(bundleContext, \"Bundle context cannot be null.\");\n        requireNonNull(headers, \"Properties cannot be null.\");\n\n        return Stream.of(bundleContext.getBundles()).filter(contains(headers)).collect(Collectors.toSet());\n    }\n\n    private static Predicate<? super Bundle> contains(Map<String, String> properties) {\n        return b -> {\n            Dictionary<String, String> headers = b.getHeaders();\n\n            Map<String, String> headersMap = Collections.list(headers.keys()).stream()\n                    .collect(Collectors.toMap(Function.identity(), headers::get));\n\n            return headersMap.entrySet().containsAll(properties.entrySet());\n        };\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/osgi/FilterUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.util.osgi;\n\nimport org.eclipse.kura.util.base.StringUtil;\nimport org.osgi.framework.Constants;\n\npublic final class FilterUtil {\n\n    private FilterUtil() {\n    }\n\n    public static String equal(final String property, final String value) {\n        if (property == null || property.isEmpty()) {\n            return \"\";\n        }\n\n        return \"(\" + quote(property) + \"=\" + quote(value) + \")\";\n    }\n\n    public static String objectClass(final Class<?> clazz) {\n        return equal(Constants.OBJECTCLASS, clazz.getName());\n    }\n\n    public static String expressions(final String operation, final String... expressions) {\n\n        if (StringUtil.isNullOrEmpty(operation)) {\n            throw new IllegalArgumentException(\"'operation' must not be null or empty\");\n        }\n\n        if (expressions == null || expressions.length == 0) {\n            return \"\";\n        }\n\n        final StringBuilder builder = new StringBuilder();\n\n        int remaining = 0;\n\n        for (final String expression : expressions) {\n\n            if (expression == null || expression.isEmpty()) {\n                continue;\n            }\n\n            builder.append(expression);\n            remaining++;\n        }\n\n        if (remaining > 1) {\n            return \"(\" + operation + builder.toString() + \")\";\n        } else {\n            return builder.toString();\n        }\n    }\n\n    public static String and(final String... expressions) {\n        return expressions(\"&\", expressions);\n    }\n\n    public static String or(final String... expressions) {\n        return expressions(\"|\", expressions);\n    }\n\n    public static String not(final String expression) {\n        if (expression == null || expression.isEmpty()) {\n            return \"\";\n        }\n\n        return \"(!\" + expression + \")\";\n    }\n\n    public static String simpleFilter(final Class<?> objectClass, final String property, final String value) {\n        return and(objectClass(objectClass), equal(property, value));\n    }\n\n    /**\n     * Quote a value for being used in LDAP style OSGi filter.\n     *\n     * @param value\n     *            The value to quote, may be {@code null}.\n     * @return The quoted value, is {@code null} if the input was {@code null}.\n     */\n    public static String quote(final String value) {\n\n        if (value == null) {\n            return null;\n        }\n\n        final int len = value.length();\n        final StringBuilder sb = new StringBuilder(value.length()); // ideally we have the same length\n\n        for (int i = 0; i < len; i++) {\n            final char c = value.charAt(i);\n\n            switch (c) {\n            case '*': //$FALL-THROUGH$\n            case '(': //$FALL-THROUGH$\n            case ')': //$FALL-THROUGH$\n                sb.append('\\\\');\n                break;\n            default:\n                break;\n            }\n\n            sb.append(c);\n        }\n        return sb.toString();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/osgi/SingleServiceTracker.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc \n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.osgi;\n\nimport java.util.LinkedList;\nimport java.util.ListIterator;\nimport java.util.Objects;\nimport java.util.function.Consumer;\n\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Track the highest ranking service instance.\n *\n * @param <T>\n *            The service type to track\n */\npublic class SingleServiceTracker<T> {\n\n    private static final Logger logger = LoggerFactory.getLogger(SingleServiceTracker.class);\n\n    private static final class Entry<T> {\n\n        private int ranking;\n        private final ServiceReference<T> reference;\n        private final T service;\n\n        public Entry(final int ranking, ServiceReference<T> reference, final T service) {\n            this.ranking = ranking;\n            this.reference = reference;\n            this.service = service;\n        }\n\n        public boolean isBetterThan(final Entry<T> other) {\n            return this.ranking > other.ranking;\n        }\n    }\n\n    private final ServiceTrackerCustomizer<T, T> customizer = new ServiceTrackerCustomizer<T, T>() {\n\n        @Override\n        public T addingService(final ServiceReference<T> reference) {\n            return adding(reference);\n        }\n\n        @Override\n        public void modifiedService(final ServiceReference<T> reference, T service) {\n            modified(reference, service);\n        }\n\n        @Override\n        public void removedService(final ServiceReference<T> reference, T service) {\n            removed(reference, service);\n        }\n    };\n\n    private final BundleContext context;\n    private final Consumer<T> consumer;\n    private final ServiceTracker<T, T> tracker;\n\n    private final LinkedList<Entry<T>> entries = new LinkedList<>();\n    private Entry<T> currentEntry;\n\n    public SingleServiceTracker(final BundleContext context, final Class<T> clazz, final Consumer<T> consumer) {\n        Objects.requireNonNull(context);\n        Objects.requireNonNull(clazz);\n        Objects.requireNonNull(consumer);\n\n        this.context = context;\n        this.consumer = consumer;\n        this.tracker = new ServiceTracker<>(context, clazz, this.customizer);\n    }\n\n    public SingleServiceTracker(final BundleContext context, final Filter filter, final Consumer<T> consumer) {\n        Objects.requireNonNull(context);\n        Objects.requireNonNull(filter);\n        Objects.requireNonNull(consumer);\n\n        this.context = context;\n        this.consumer = consumer;\n        this.tracker = new ServiceTracker<>(context, filter, this.customizer);\n    }\n\n    public void open() {\n        this.tracker.open();\n    }\n\n    public void close() {\n        this.tracker.close();\n    }\n\n    private static int getRanking(ServiceReference<?> reference) {\n        Object ranking = reference.getProperty(Constants.SERVICE_RANKING);\n        if (ranking instanceof Number) {\n            return ((Number) ranking).intValue();\n        } else {\n            return 0;\n        }\n    }\n\n    private void insertEntry(final Entry<T> entry) {\n        if (this.entries.isEmpty()) {\n\n            this.entries.add(entry);\n\n        } else {\n\n            final ListIterator<Entry<T>> i = this.entries.listIterator();\n            while (i.hasNext()) {\n                if (entry.isBetterThan(i.next())) {\n                    i.previous();\n                    break;\n                }\n            }\n\n            i.add(entry);\n\n        }\n    }\n\n    private void updateEntry(final ServiceReference<T> reference) {\n        final ListIterator<Entry<T>> i = this.entries.listIterator();\n\n        while (i.hasNext()) {\n            final Entry<T> entry = i.next();\n\n            if (!entry.reference.equals(reference)) {\n                // not the entry we are looking for\n                continue;\n            }\n\n            final int ranking = getRanking(reference);\n            if (entry.ranking != ranking) {\n                i.remove();\n\n                // update ranking\n                entry.ranking = ranking;\n\n                // re-insert updated entry\n                insertEntry(entry);\n            }\n\n            // the reference is unique\n            break;\n        }\n    }\n\n    protected T adding(final ServiceReference<T> reference) {\n\n        final int ranking = getRanking(reference);\n        final T service = this.context.getService(reference);\n\n        final Entry<T> entry = new Entry<>(ranking, reference, service);\n\n        insertEntry(entry);\n\n        if (this.currentEntry == null || entry.isBetterThan(this.currentEntry)) {\n            setBestEntry(entry);\n        }\n\n        return service;\n    }\n\n    protected void modified(final ServiceReference<T> reference, final T service) {\n\n        updateEntry(reference);\n\n        final Entry<T> bestEntry = this.entries.peekFirst();\n        if (this.currentEntry != bestEntry) {\n            // we have a different entry now\n            setBestEntry(bestEntry);\n        }\n\n    }\n\n    protected void removed(final ServiceReference<T> reference, final T service) {\n\n        if (!this.entries.removeIf(entry -> entry.reference.equals(reference))) {\n            return;\n        }\n\n        if (this.currentEntry == null || this.currentEntry.service != service) {\n            return;\n        }\n\n        // set next best entry\n\n        if (this.entries.isEmpty()) {\n            setBestEntry(null);\n        } else {\n            // the next best entry already is the first one in the list\n            setBestEntry(this.entries.peekFirst());\n        }\n    }\n\n    private void setBestEntry(final Entry<T> entry) {\n\n        this.currentEntry = entry;\n        notifyService(entry != null ? entry.service : null);\n\n    }\n\n    protected void notifyService(final T service) {\n\n        try {\n            this.consumer.accept(service);\n        } catch (final Exception e) {\n            logger.warn(\"Failed to notify changed service\", e);\n        }\n\n    }\n\n    public T getService() {\n\n        final Entry<T> entry = this.currentEntry;\n        return entry != null ? entry.service : null;\n\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/service/ServiceUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Amit Kumar Mondal\n *\n *******************************************************************************/\npackage org.eclipse.kura.util.service;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Function;\nimport java.util.function.Predicate;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.annotation.Nullable;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.runtime.ServiceComponentRuntime;\nimport org.osgi.util.tracker.ServiceTracker;\n\n/**\n * The Class ServiceUtil contains all necessary static factory methods to deal\n * with OSGi services\n */\npublic final class ServiceUtil {\n\n    private ServiceUtil() {\n        // Static Factory Methods container. No need to instantiate.\n    }\n\n    /**\n     * Returns references to <em>all</em> services matching the given class name\n     * and OSGi filter.\n     *\n     * @param bundleContext\n     *            OSGi bundle context\n     * @param clazz\n     *            qualified class type\n     * @param filter\n     *            valid OSGi filter (can be {@code null})\n     * @return {@code non-null} array of references to matching services\n     * @throws NullPointerException\n     *             if {@code bundleContext} or {@code clazz} is {@code null}\n     * @throws IllegalArgumentException\n     *             if the specified {@code filter} contains an invalid filter expression that cannot be parsed.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> ServiceReference<T>[] getServiceReferences(final BundleContext bundleContext,\n            final Class<T> clazz, @Nullable final String filter) {\n        requireNonNull(bundleContext, \"Bundle context cannot be null.\");\n        requireNonNull(clazz, \"Class intance name cannot be null.\");\n\n        try {\n            final Collection<ServiceReference<T>> refs = bundleContext.getServiceReferences(clazz, filter);\n            return refs.toArray(new ServiceReference[0]);\n        } catch (final InvalidSyntaxException ise) {\n            throw new IllegalArgumentException(ise);\n        }\n    }\n\n    public static <T> Collection<ServiceReference<T>> getServiceReferencesAsCollection(\n            final BundleContext bundleContext, Class<T> serviceClass, String filter) throws KuraException {\n\n        try {\n            final Collection<ServiceReference<T>> sr = bundleContext.getServiceReferences(serviceClass, filter);\n\n            if (sr == null) {\n                throw KuraException.internalError(serviceClass.toString() + \" not found.\");\n            }\n\n            return sr;\n        } catch (InvalidSyntaxException e) {\n            throw new IllegalArgumentException(e);\n        }\n\n    }\n\n    public static <T> T getService(final BundleContext bundleContext, ServiceReference<T> serviceReference)\n            throws KuraException {\n        T service = null;\n\n        if (serviceReference != null) {\n            service = bundleContext.getService(serviceReference);\n        }\n        if (service == null) {\n            throw KuraException.internalError(\"Service not found.\");\n        }\n        return service;\n    }\n\n    /**\n     * Resets all the provided service reference use counts. If the provided {@link BundleContext} bundle's use count\n     * for the provided service references are already zero, this would not further decrement the counters to\n     * negative. Otherwise, the provided {@link BundleContext} bundle's use counts for the provided service references\n     * is decremented by one.\n     *\n     * @param bundleContext\n     *            OSGi bundle context\n     * @param refs\n     *            {@code non-null} array of all service references\n     * @throws NullPointerException\n     *             if any of the arguments is {@code null}\n     */\n    public static void ungetServiceReferences(final BundleContext bundleContext, final ServiceReference<?>[] refs) {\n        requireNonNull(bundleContext, \"Bundle context cannot be null.\");\n        requireNonNull(refs, \"Service References cannot be null.\");\n\n        for (final ServiceReference<?> ref : refs) {\n            bundleContext.ungetService(ref);\n        }\n    }\n\n    /**\n     * Waits for the specified amount of time for the services that matches the provided OSGi filter\n     *\n     * @param filter\n     *            valid OSGi filter to match\n     * @param timeout\n     *            the timeout period\n     * @param timeunit\n     *            the {@link TimeUnit} for the timeout\n     * @throws NullPointerException\n     *             if the provided filter or the {@link TimeUnit} is {@code null}\n     * @throws IllegalArgumentException\n     *             if the timeout period is {@code zero} or {@code negative}\n     * @throws InterruptedException\n     *             if another thread has interrupted the current worker thread\n     * @throws InvalidSyntaxException\n     *             if the provided filter syntax is erroneous\n     * @return an {@link Optional} with the tracked service instance if the service instance\n     *         is {@code non-null}, otherwise an empty {@link Optional}\n     */\n    public static Optional<Object> waitForService(final String filter, final long timeout, final TimeUnit timeunit)\n            throws InterruptedException, InvalidSyntaxException {\n        requireNonNull(filter, \"Filter cannot be null.\");\n        requireNonNull(timeunit, \"TimeUnit cannot be null\");\n        if (timeout <= 0) {\n            throw new IllegalArgumentException(\"Timeout period cannot be zero or negative\");\n        }\n\n        final long timeoutInMillis = timeunit.toMillis(timeout);\n        final BundleContext bundleContext = FrameworkUtil.getBundle(ServiceUtil.class).getBundleContext();\n        final Filter filterRef = bundleContext.createFilter(filter);\n        final ServiceTracker<Object, Object> serviceTracker = new ServiceTracker<>(bundleContext, filterRef, null);\n        serviceTracker.open();\n        final Object service = serviceTracker.waitForService(timeoutInMillis);\n        serviceTracker.close();\n\n        return Optional.ofNullable(service);\n    }\n\n    public static <T> T withService(final BundleContext bundleContext, final Function<Optional<Object>, T> func,\n            final String filter) throws InvalidSyntaxException {\n        final ServiceReference<?>[] refs = bundleContext.getServiceReferences((String) null, filter);\n\n        if (refs == null || refs.length == 0) {\n            return func.apply(Optional.empty());\n        }\n\n        final ServiceReference<?> ref = refs[0];\n\n        try {\n            final Object o = bundleContext.getService(ref);\n\n            return func.apply(Optional.ofNullable(o));\n        } finally {\n            bundleContext.ungetService(ref);\n        }\n    }\n\n    /**\n     * Lookup services with a filter and iterate over their instances\n     *\n     * @param serviceClass\n     *            the services to look for\n     * @param consumer\n     *            the consumer which will be called for each service instance\n     * @throws GwtKuraException\n     *             if any service consumer throws an exception\n     * @throws InvalidSyntaxException\n     *             if the filter was not {@code null} and had an invalid syntax\n     */\n    public static <T> void withAllServices(final BundleContext bundleContext, final Class<T> serviceClass,\n            String filter, final ServiceConsumer<T> consumer) throws KuraException {\n\n        withAllServiceReferences(bundleContext, serviceClass, filter, (ref, ctx) -> {\n            final T service = ctx.getService(ref);\n\n            try {\n                consumer.consume(service);\n            } finally {\n                ctx.ungetService(ref);\n            }\n        });\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> void withAllServiceReferences(final BundleContext bundleContext, final Class<T> serviceClass,\n            String filter, final ServiceReferenceConsumer<T> consumer) throws KuraException {\n\n        final ServiceReference<?>[] refs;\n        try {\n            refs = bundleContext.getAllServiceReferences(serviceClass != null ? serviceClass.getName() : null, filter);\n        } catch (InvalidSyntaxException e) {\n            throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                    serviceClass != null ? serviceClass.getName() : \"\");\n        }\n\n        // no result ... do nothing\n        if (refs == null) {\n            return;\n        }\n\n        // iterate over results\n        for (final ServiceReference<?> ref : refs) {\n            consumer.consume((ServiceReference<T>) ref, bundleContext);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static void withAllServices(final BundleContext bundleContext, String filter,\n            final ServiceConsumer<Object> consumer, final Class<?>... classes) throws KuraException {\n\n        if (classes == null || classes.length == 0) {\n            withAllServices(bundleContext, null, filter, consumer);\n        }\n\n        for (Class<?> c : classes) {\n            withAllServices(bundleContext, (Class<Object>) c, filter, consumer);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static void withAllServiceReferences(final BundleContext bundleContext, String filter,\n            final ServiceReferenceConsumer<Object> consumer, final Class<?>... classes) throws KuraException {\n\n        if (classes == null || classes.length == 0) {\n            withAllServiceReferences(bundleContext, null, filter, consumer);\n        }\n\n        for (Class<?> c : classes) {\n            withAllServiceReferences(bundleContext, (Class<Object>) c, filter, consumer);\n        }\n    }\n\n    public static boolean ungetService(final BundleContext bundleContext, ServiceReference<?> serviceReference) {\n\n        if (serviceReference != null) {\n            return bundleContext.ungetService(serviceReference);\n        }\n\n        return false;\n    }\n\n    public static <T, R> R applyToServiceOptionally(final BundleContext bundleContext, final Class<T> serviceClass,\n            final ServiceFunction<T, R> function) throws KuraException {\n\n        final ServiceReference<T> ref = bundleContext.getServiceReference(serviceClass);\n\n        try {\n            if (ref == null) {\n                return function.apply(null);\n            }\n\n            final T service = bundleContext.getService(ref);\n            try {\n                return function.apply(service);\n            } finally {\n                bundleContext.ungetService(ref);\n            }\n        } catch (Exception e) {\n            throw KuraException.internalError(e.getMessage());\n        }\n    }\n\n    public static boolean providesService(final BundleContext bundleContext, final String kuraServicePid,\n            final Class<?> serviceInterface) {\n        return providesService(bundleContext, kuraServicePid, s -> s.contains(serviceInterface.getName()));\n    }\n\n    public static boolean providesService(final BundleContext bundleContext, final String kuraServicePid,\n            final Predicate<Set<String>> filter) {\n\n        final String pidFilter = \"(kura.service.pid=\" + kuraServicePid + \")\";\n\n        try {\n            final ServiceReference<?>[] refs = bundleContext.getAllServiceReferences(null, pidFilter);\n\n            if (refs == null) {\n                return false;\n            }\n\n            for (final ServiceReference<?> ref : refs) {\n                final Object rawProvidedInterfaces = ref.getProperty(\"objectClass\");\n\n                final Set<String> providedInterfaces;\n\n                if (rawProvidedInterfaces instanceof String) {\n                    providedInterfaces = Collections.singleton((String) rawProvidedInterfaces);\n                } else if (rawProvidedInterfaces instanceof String[]) {\n                    providedInterfaces = Arrays.asList((String[]) rawProvidedInterfaces).stream()\n                            .collect(Collectors.toSet());\n                } else {\n                    providedInterfaces = Collections.emptySet();\n                }\n\n                if (filter.test(providedInterfaces)) {\n                    return true;\n                }\n            }\n\n            return false;\n        } catch (InvalidSyntaxException e) {\n            return false;\n        }\n    }\n\n    public static boolean isFactoryOf(final BundleContext bundleContext, final String factoryPid,\n            final Predicate<Set<String>> filter) {\n\n        final ServiceReference<ServiceComponentRuntime>[] refs = getServiceReferences(bundleContext,\n                ServiceComponentRuntime.class, null);\n\n        if (refs == null || refs.length == 0) {\n            return false;\n        }\n\n        final ServiceReference<ServiceComponentRuntime> ref = refs[0];\n\n        try {\n            final ServiceComponentRuntime scr = bundleContext.getService(ref);\n\n            return scr.getComponentDescriptionDTOs().stream().anyMatch(c -> {\n                if (!Objects.equals(factoryPid, c.name)) {\n                    return false;\n                }\n\n                return providedInterfacesMatch(c.serviceInterfaces, filter);\n            });\n        } catch (final Exception e) {\n            return false;\n        } finally {\n            bundleContext.ungetService(ref);\n        }\n    }\n\n    private static boolean providedInterfacesMatch(final String[] providedInterfaces,\n            final Predicate<Set<String>> filter) {\n        if (providedInterfaces == null) {\n            return filter.test(Collections.emptySet());\n        }\n\n        return filter.test(Arrays.stream(providedInterfaces).collect(Collectors.toSet()));\n    }\n\n    public static boolean isFactoryOfAnyService(final BundleContext bundleContext, final String factoryPid,\n            final Class<?>... interfaces) {\n        return isFactoryOf(bundleContext, factoryPid, s -> {\n            for (final Class<?> intf : interfaces) {\n                if (s.contains(intf.getName())) {\n                    return true;\n                }\n            }\n\n            return false;\n        });\n    }\n\n    public interface ServiceFunction<T, R> {\n\n        public R apply(T service) throws KuraException;\n    }\n\n    public interface ServiceConsumer<T> {\n\n        public void consume(T service) throws KuraException;\n    }\n\n    public interface ServiceReferenceConsumer<T> {\n\n        public void consume(ServiceReference<T> service, BundleContext context) throws KuraException;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/store/listener/ConnectionListenerManager.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.util.store.listener;\n\nimport java.util.Set;\nimport java.util.concurrent.CopyOnWriteArraySet;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\nimport org.eclipse.kura.connection.listener.ConnectionListener;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ConnectionListenerManager {\n\n    private static final Logger logger = LoggerFactory.getLogger(ConnectionListenerManager.class);\n\n    private final ExecutorService dispatchThread = Executors.newSingleThreadExecutor();\n    private Set<ConnectionListener> listeners = new CopyOnWriteArraySet<>();\n\n    public void dispatchConnected() {\n        this.dispatchThread.execute(() -> dispatch(ConnectionListener::connected));\n    }\n\n    public void dispatchDisconnected() {\n        this.dispatchThread.execute(() -> dispatch(ConnectionListener::disconnected));\n    }\n\n    private void dispatch(final Consumer<ConnectionListener> consumer) {\n        for (final ConnectionListener listener : listeners) {\n            try {\n                consumer.accept(listener);\n            } catch (final Exception e) {\n                logger.warn(\"Unexpected exception dispatching event\", e);\n            }\n        }\n    }\n\n    public void addAll(Set<ConnectionListener> listeners) {\n        this.listeners.addAll(listeners);\n\n    }\n\n    public void add(ConnectionListener listener) {\n        this.listeners.add(listener);\n\n    }\n\n    public void remove(ConnectionListener listener) {\n        this.listeners.remove(listener);\n    }\n\n    public void shutdown() {\n        this.dispatchThread.shutdown();\n        try {\n            this.dispatchThread.awaitTermination(1, TimeUnit.MINUTES);\n        } catch (InterruptedException e) {\n            logger.warn(\"Interrupted while waiting for executor shutdown\", e);\n            Thread.currentThread().interrupt();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/store/listener/package-info.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.util.store.listener;\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/useradmin/UserAdminHelper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.useradmin;\n\nimport java.io.UnsupportedEncodingException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashSet;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\n\npublic class UserAdminHelper {\n\n    private static final String PERMISSION_ROLE_NAME_PREFIX = \"kura.permission.\";\n    private static final String USER_ROLE_NAME_PREFIX = \"kura.user.\";\n    private static final String PASSWORD_PROPERTY = \"kura.password\";\n    private static final String KURA_NEED_PASSWORD_CHANGE = \"kura.need.password.change\";\n\n    private final UserAdmin userAdmin;\n    private final CryptoService cryptoService;\n\n    public UserAdminHelper(final UserAdmin userAdmin, final CryptoService cryptoService) {\n        this.userAdmin = userAdmin;\n        this.cryptoService = cryptoService;\n    }\n\n    public void verifyUsernamePassword(final String username, final String password) throws AuthenticationException {\n        final User user = getUser(username)\n                .orElseThrow(() -> new AuthenticationException(AuthenticationException.Reason.USER_NOT_FOUND));\n\n        try {\n            String sha256Password = cryptoService.sha256Hash(password);\n\n            if (!Objects.equals(sha256Password, user.getCredentials().get(PASSWORD_PROPERTY))) {\n                throw new AuthenticationException(AuthenticationException.Reason.INCORRECT_PASSWORD);\n            }\n        } catch (final NoSuchAlgorithmException | UnsupportedEncodingException e) {\n            throw new AuthenticationException(AuthenticationException.Reason.ENCRYPTION_ERROR);\n        }\n    }\n\n    public void requirePermissions(final String username, final String... permissions) throws AuthenticationException {\n        final String userRoleName = getUserRoleName(username);\n        final Role role = userAdmin.getRole(userRoleName);\n\n        if (!(role instanceof User)) {\n            throw new AuthenticationException(AuthenticationException.Reason.USER_NOT_FOUND);\n        }\n\n        final Group admin = getOrCreatePermission(\"kura.admin\");\n\n        if (admin.getMembers() != null && Arrays.stream(admin.getMembers()).anyMatch(role::equals)) {\n            return;\n        }\n\n        for (final String permission : permissions) {\n            final String permissionRoleName = getPermissionRoleName(permission);\n            final Role permissionRole = userAdmin.getRole(permissionRoleName);\n\n            if (!(permissionRole instanceof Group)) {\n                throw new AuthenticationException(AuthenticationException.Reason.USER_NOT_IN_ROLE);\n            }\n\n            final Group asGroup = (Group) permissionRole;\n            final Role[] members = asGroup.getMembers();\n\n            if (members == null || Arrays.stream(members).noneMatch(r -> r.getName().equals(userRoleName))) {\n                throw new AuthenticationException(AuthenticationException.Reason.USER_NOT_IN_ROLE);\n            }\n        }\n    }\n\n    public Set<String> getIdentityPermissions(final String name) {\n        final String userRoleName = getUserRoleName(name);\n        final Role role = userAdmin.getRole(userRoleName);\n\n        if (!(role instanceof User)) {\n            return Collections.emptySet();\n        }\n\n        final Set<String> result = new HashSet<>();\n\n        foreachPermission((permission, group) -> {\n\n            final Role[] members = group.getMembers();\n\n            if (members != null && Arrays.stream(members).anyMatch(r -> r.getName().equals(userRoleName))) {\n\n                result.add(getBaseName(group));\n            }\n        });\n\n        return result;\n    }\n\n    public void changeUserPassword(final String username, final String userPassword) throws AuthenticationException {\n        final User user = getUser(username)\n                .orElseThrow(() -> new AuthenticationException(AuthenticationException.Reason.USER_NOT_FOUND));\n\n        try {\n            final String newHash = cryptoService.sha256Hash(userPassword);\n\n            if (Objects.equals(user.getCredentials().get(PASSWORD_PROPERTY), newHash)) {\n                throw new AuthenticationException(AuthenticationException.Reason.PASSWORD_CHANGE_WITH_SAME_PASSWORD);\n            }\n\n            user.getCredentials().put(PASSWORD_PROPERTY, newHash);\n            user.getProperties().remove(KURA_NEED_PASSWORD_CHANGE);\n\n        } catch (final NoSuchAlgorithmException | UnsupportedEncodingException e) {\n            throw new AuthenticationException(AuthenticationException.Reason.ENCRYPTION_ERROR);\n        }\n    }\n\n    public boolean isPasswordChangeRequired(final String username) {\n        final String userRoleName = getUserRoleName(username);\n        final Role role = userAdmin.getRole(userRoleName);\n\n        if (!(role instanceof User)) {\n            return false;\n        }\n\n        final User asUser = (User) role;\n\n        return \"true\".equals(asUser.getProperties().get(KURA_NEED_PASSWORD_CHANGE));\n    }\n\n    public void createUser(final String userName) {\n        User createdUser = getOrCreateUser(userName);\n        Objects.requireNonNull(createdUser, \"Could not create user \" + userName);\n    }\n\n    public void deleteUser(final String userName) {\n\n        final Optional<User> user = getUser(userName);\n\n        if (!user.isPresent()) {\n            return;\n        }\n\n        foreachPermission((name, group) -> group.removeMember(user.get()));\n\n        this.userAdmin.removeRole(user.get().getName());\n    }\n\n    public Optional<Integer> getCredentialsHash(final String userName) {\n        final Optional<User> user = getUser(userName);\n\n        if (!user.isPresent()) {\n            return Optional.empty();\n        }\n\n        final Dictionary<?, ?> credentials = user.get().getCredentials();\n\n        if (credentials == null) {\n            return Optional.empty();\n        }\n\n        return Optional.of(credentials.hashCode());\n    }\n\n    public Set<String> getDefinedPermissions() {\n        final Set<String> result = new HashSet<>();\n\n        foreachPermission((permission, group) -> result.add(permission));\n\n        return result;\n    }\n\n    public Optional<User> getUser(final String name) {\n        final String roleName = getUserRoleName(name);\n\n        final Role role = userAdmin.getRole(roleName);\n\n        if (!(role instanceof User)) {\n            return Optional.empty();\n        }\n\n        if (!getBaseName(role).equals(name)) {\n            return Optional.empty();\n        }\n\n        return Optional.of((User) role);\n    }\n\n    private static String getUserRoleName(final String name) {\n        return USER_ROLE_NAME_PREFIX + name;\n    }\n\n    private static String getPermissionRoleName(final String name) {\n        return PERMISSION_ROLE_NAME_PREFIX + name;\n    }\n\n    private static boolean isKuraUser(final Role role) {\n        return role.getName().startsWith(USER_ROLE_NAME_PREFIX);\n    }\n\n    private static boolean isKuraPermission(final Role role) {\n        return role.getName().startsWith(PERMISSION_ROLE_NAME_PREFIX);\n    }\n\n    private static String getBaseName(final Role role) {\n        final String name = role.getName();\n\n        if (isKuraUser(role)) {\n            return name.substring(USER_ROLE_NAME_PREFIX.length());\n        } else if (isKuraPermission(role)) {\n            return name.substring(PERMISSION_ROLE_NAME_PREFIX.length());\n        } else {\n            throw new IllegalArgumentException(\"not a Kura role\");\n        }\n    }\n\n    public Optional<Group> getPermission(final String name) {\n        final String roleName = getPermissionRoleName(name);\n\n        final Role role = userAdmin.getRole(roleName);\n\n        if (!(role instanceof Group)) {\n            return Optional.empty();\n        }\n\n        return Optional.of((Group) role);\n    }\n\n    public Group getOrCreatePermission(final String name) {\n        return getOrCreateRole(Group.class, getPermissionRoleName(name));\n    }\n\n    public void deletePremission(final String name) {\n        final Role role = this.userAdmin.getRole(getPermissionRoleName(name));\n\n        if (role instanceof Group) {\n            this.userAdmin.removeRole(role.getName());\n        }\n    }\n\n    public User getOrCreateUser(final String name) {\n        return getOrCreateRole(User.class, getUserRoleName(name));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T extends Role> T getOrCreateRole(final Class<T> classz, final String name) {\n\n        final int type;\n\n        if (classz == Role.class) {\n            type = Role.ROLE;\n        } else if (classz == User.class) {\n            type = Role.USER;\n        } else if (classz == Group.class) {\n            type = Role.GROUP;\n        } else {\n            throw new IllegalArgumentException(\"unknown role type\");\n        }\n\n        final Role result = userAdmin.getRole(name);\n\n        if (result != null && result.getType() == type) {\n            return (T) result;\n        } else if (result == null) {\n\n            return (T) userAdmin.createRole(name, type);\n\n        } else {\n            throw new IllegalArgumentException(\"role exists but has different type\");\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <R extends Role, E extends Exception> void foreachRole(final Class<R> classz,\n            final FallibleConsumer<R, E> consumer) throws E {\n        try {\n            final Role[] existingRoles = userAdmin.getRoles(null);\n\n            if (existingRoles != null) {\n                for (final Role role : existingRoles) {\n                    if (!classz.isInstance(role)) {\n                        continue;\n                    }\n\n                    consumer.accept((R) role);\n                }\n            }\n        } catch (InvalidSyntaxException e) {\n            // no need\n        }\n    }\n\n    public <E extends Exception> void foreachUser(final UserConsumer<E> consumer) throws E {\n        foreachRole(User.class, user -> {\n\n            final String name = user.getName();\n\n            if (!name.startsWith(USER_ROLE_NAME_PREFIX)) {\n                return;\n            }\n\n            consumer.accept(name.substring(USER_ROLE_NAME_PREFIX.length()), user);\n        });\n    }\n\n    public <E extends Exception> void foreachPermission(final PermissionConsumer<E> consumer) throws E {\n        foreachRole(Group.class, group -> {\n            final String name = group.getName();\n\n            if (!name.startsWith(PERMISSION_ROLE_NAME_PREFIX)) {\n                return;\n            }\n\n            consumer.accept(name.substring(PERMISSION_ROLE_NAME_PREFIX.length()), group);\n        });\n    }\n\n    public static class AuthenticationException extends Exception {\n\n        private static final long serialVersionUID = -8534499595655286448L;\n\n        public enum Reason {\n            USER_NOT_FOUND,\n            INCORRECT_PASSWORD,\n            USER_NOT_IN_ROLE,\n            PASSWORD_CHANGE_WITH_SAME_PASSWORD,\n            ENCRYPTION_ERROR;\n        }\n\n        private final Reason reason;\n\n        public AuthenticationException(final Reason reason) {\n            this.reason = reason;\n        }\n\n        public Reason getReason() {\n            return reason;\n        }\n    }\n\n    public interface UserConsumer<E extends Exception> {\n\n        public void accept(final String userName, final User user) throws E;\n    }\n\n    public interface PermissionConsumer<E extends Exception> {\n\n        public void accept(final String permissionName, final Group group) throws E;\n    }\n\n    public interface FallibleConsumer<T, E extends Exception> {\n\n        public void accept(final T item) throws E;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/validation/PasswordStrengthValidators.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.validation;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class PasswordStrengthValidators {\n\n    private static final String CONTAINS_DIGITS = \".*\\\\d.*\";\n    private static final String CONTAINS_NOT_ALPHANUMERIC = \".*[^a-zA-Z0-9].*\";\n    private static final String LOWERCASE = \".*[a-z].*\";\n    private static final String UPPERCASE = \".*[A-Z].*\";\n\n    private PasswordStrengthValidators() {\n    }\n\n    public static List<Validator<String>> fromConfig(final ValidatorOptions userOptions) {\n        return fromConfig(userOptions, new DefaultMessages());\n    }\n\n    public static List<Validator<String>> fromConfig(final ValidatorOptions userOptions, final Messages messages) {\n        final List<Validator<String>> result = new ArrayList<>();\n\n        final int minPasswordLength = userOptions.isPasswordMinimumLength();\n\n        if (minPasswordLength > 0) {\n            result.add(passwordLengthValidator(minPasswordLength, messages));\n        }\n\n        if (userOptions.isPasswordRequireDigits()) {\n            result.add(containsDigitsValidator(messages));\n        }\n\n        if (userOptions.isPasswordRequireBothCases()) {\n            result.add(containsBothCases(messages));\n        }\n\n        if (userOptions.isPasswordRequireSpecialChars()) {\n            result.add(containsSpecialChars(messages));\n        }\n\n        return result;\n    }\n\n    private static Validator<String> passwordLengthValidator(final int minPasswordLength, final Messages messages) {\n        return new PredicateValidator(v -> {\n            final int passwordLength = v == null ? 0 : v.length();\n            return passwordLength >= minPasswordLength;\n        }, messages.pwdStrengthMinLength(minPasswordLength));\n    }\n\n    private static Validator<String> containsDigitsValidator(final Messages messages) {\n        return new RegexValidator(CONTAINS_DIGITS, messages.pwdStrengthDigitsRequired()) {\n        };\n    }\n\n    private static Validator<String> containsSpecialChars(final Messages messages) {\n        return new RegexValidator(CONTAINS_NOT_ALPHANUMERIC, messages.pwdStrengthNonAlphanumericRequired()) {\n        };\n    }\n\n    private static Validator<String> containsBothCases(final Messages messages) {\n        final RegexValidator containsLowercase = new RegexValidator(LOWERCASE, messages.pwdStrengthBothCasesRequired());\n        final RegexValidator containsUppercase = new RegexValidator(UPPERCASE, messages.pwdStrengthBothCasesRequired());\n\n        return (v, c) -> {\n            containsLowercase.validate(v, c);\n            containsUppercase.validate(v, c);\n        };\n    }\n\n    public static Validator<String> requireDifferentNameAndPassword(final String identityName) {\n\n        return new PredicateValidator(v -> !v.equalsIgnoreCase(identityName),\n                new DefaultMessages().pwdNotEqualsUsername());\n    }\n\n    public interface Messages {\n\n        public String pwdStrengthDigitsRequired();\n\n        public String pwdStrengthNonAlphanumericRequired();\n\n        public String pwdStrengthBothCasesRequired();\n\n        public String pwdStrengthMinLength(final int value);\n\n        public String pwdNotEqualsUsername();\n    }\n\n    private static class DefaultMessages implements Messages {\n\n        @Override\n        public String pwdStrengthDigitsRequired() {\n            return \"Password must contain at least one digit\";\n        }\n\n        @Override\n        public String pwdStrengthNonAlphanumericRequired() {\n            return \"Password must contain at least one non alphanumeric character\";\n        }\n\n        @Override\n        public String pwdStrengthBothCasesRequired() {\n            return \"Password must contain both uppercase and lowercase characters\";\n        }\n\n        @Override\n        public String pwdStrengthMinLength(final int value) {\n            return \"Password length must be at least \" + value + \" characters\";\n        }\n\n        @Override\n        public String pwdNotEqualsUsername() {\n            return \"The identity name cannot be the same as the password\";\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/validation/PredicateValidator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.validation;\n\nimport java.util.function.Consumer;\nimport java.util.function.Predicate;\n\npublic class PredicateValidator implements Validator<String> {\n\n    private final Predicate<String> predicate;\n    private final String message;\n\n    public PredicateValidator(final Predicate<String> predicate, final String message) {\n        this.predicate = predicate;\n        this.message = message;\n    }\n\n    @Override\n    public void validate(final String value, final Consumer<String> errorMessageConsumer) {\n\n        if (!this.predicate.test(value)) {\n            errorMessageConsumer.accept(this.message);\n        }\n    }\n\n}"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/validation/RegexValidator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.validation;\n\npublic class RegexValidator extends PredicateValidator {\n\n    public RegexValidator(final String pattern, final String message) {\n        super(v -> v.matches(pattern), message);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/validation/Validator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.util.validation;\n\nimport java.util.function.Consumer;\n\npublic interface Validator<T> {\n\n    void validate(T value, Consumer<String> errorMessageConsumer);\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/validation/ValidatorOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.validation;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.util.configuration.Property;\n\npublic class ValidatorOptions {\n\n    private int passwordMinimumLength = 8;\n    private boolean passwordRequireDigits = false;\n    private boolean passwordRequireBothCases = false;\n    private boolean passwordRequireSpecialChars = false;\n\n    private static final String NEW_PASSW_MIN_LENGTH_PROP = \"new.password.min.length\";\n    private static final String NEW_PASSW_REQUIRE_DIGITS = \"new.password.require.digits\";\n    private static final String NEW_PASSW_REQUIRE_SPECIAL_CHARS = \"new.password.require.special.characters\";\n    private static final String NEW_PASSW_REQUIRE_BOTH_CASES = \"new.password.require.both.cases\";\n\n    private final Property<Integer> newPasswMinLenghthProperty = new Property<>(NEW_PASSW_MIN_LENGTH_PROP, 8);\n    private final Property<Boolean> newPassRequireDigits = new Property<>(NEW_PASSW_REQUIRE_DIGITS, false);\n    private final Property<Boolean> newPassRequireSpecialChars = new Property<>(NEW_PASSW_REQUIRE_SPECIAL_CHARS, false);\n    private final Property<Boolean> newPassRequireBothCases = new Property<>(NEW_PASSW_REQUIRE_BOTH_CASES, false);\n\n    public ValidatorOptions(int passwordMinimumLength, boolean passwordRequireDigits, boolean passwordRequireBothCases,\n            boolean passwordRequireSpecialChars) {\n\n        this.passwordMinimumLength = passwordMinimumLength;\n        this.passwordRequireDigits = passwordRequireDigits;\n        this.passwordRequireSpecialChars = passwordRequireSpecialChars;\n        this.passwordRequireBothCases = passwordRequireBothCases;\n    }\n\n    public ValidatorOptions(Map<String, Object> configurationProperties) {\n        if (configurationProperties != null) {\n            this.passwordMinimumLength = this.newPasswMinLenghthProperty.get(configurationProperties);\n            this.passwordRequireDigits = this.newPassRequireDigits.get(configurationProperties);\n            this.passwordRequireSpecialChars = this.newPassRequireSpecialChars.get(configurationProperties);\n            this.passwordRequireBothCases = this.newPassRequireBothCases.get(configurationProperties);\n        }\n    }\n\n    public int isPasswordMinimumLength() {\n        return this.passwordMinimumLength;\n    }\n\n    public boolean isPasswordRequireDigits() {\n        return this.passwordRequireDigits;\n    }\n\n    public boolean isPasswordRequireBothCases() {\n        return this.passwordRequireBothCases;\n    }\n\n    public boolean isPasswordRequireSpecialChars() {\n        return this.passwordRequireSpecialChars;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/wire/store/AbstractJdbcQueryableWireRecordStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.wire.store;\n\nimport static java.util.Objects.isNull;\nimport static java.util.Objects.requireNonNull;\n\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.type.TypedValue;\nimport org.eclipse.kura.type.TypedValues;\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class AbstractJdbcQueryableWireRecordStoreImpl {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractJdbcQueryableWireRecordStoreImpl.class);\n\n    private final ConnectionProvider provider;\n\n    protected AbstractJdbcQueryableWireRecordStoreImpl(final ConnectionProvider provider) {\n        this.provider = requireNonNull(provider, \"Connection provider cannot be null\");\n    }\n\n    protected abstract Optional<Object> extractColumnValue(ResultSet resultSet, ResultSetMetaData metadata,\n            int columnIndex)\n            throws SQLException;\n\n    public List<WireRecord> performQuery(final String query)\n            throws KuraStoreException {\n\n        try {\n            return provider.withConnection(c -> {\n                try (final Statement stmt = c.createStatement();\n                        final ResultSet rset = stmt.executeQuery(query)) {\n                    final List<WireRecord> dataRecords = new ArrayList<>();\n\n                    while (rset.next()) {\n                        final WireRecord wireRecord = new WireRecord(convertSQLRowToWireRecord(rset));\n                        dataRecords.add(wireRecord);\n                    }\n\n                    return dataRecords;\n                }\n            });\n        } catch (final Exception e) {\n            throw new KuraStoreException(e, null);\n        }\n\n    }\n\n    protected Map<String, TypedValue<?>> convertSQLRowToWireRecord(final ResultSet rset)\n            throws SQLException {\n        final Map<String, TypedValue<?>> wireRecordProperties = new HashMap<>();\n        final ResultSetMetaData rmet = rset.getMetaData();\n        for (int columnIndex = 1; columnIndex <= rmet.getColumnCount(); columnIndex++) {\n            String fieldName = rmet.getColumnLabel(columnIndex);\n\n            if (isNull(fieldName)) {\n                fieldName = getWireRecordPropertyName(rmet, columnIndex);\n            }\n\n            final Optional<Object> dbExtractedData = extractColumnValue(rset, rmet, columnIndex);\n\n            if (!dbExtractedData.isPresent()) {\n                continue;\n            }\n\n            try {\n                final TypedValue<?> value = TypedValues.newTypedValue(dbExtractedData.get());\n                wireRecordProperties.put(fieldName, value);\n            } catch (final Exception e) {\n                handleConversionException(rmet, columnIndex, fieldName, dbExtractedData.get(), e);\n            }\n\n        }\n        return wireRecordProperties;\n    }\n\n    protected String getWireRecordPropertyName(final ResultSetMetaData resultSetMetaData, final int columnIndex)\n            throws SQLException {\n        return resultSetMetaData.getColumnName(columnIndex);\n    }\n\n    protected void handleConversionException(final ResultSetMetaData rmet, int columnIndex, String fieldName,\n            final Object dbExtractedData, final Exception e) throws SQLException {\n        logger.error(\n                \"Failed to convert result for column {} (SQL type {}, Java type {}) \"\n                        + \"to any of the supported Wires data type, \"\n                        + \"please consider using a conversion function like CAST in your query. \"\n                        + \"The result for this column will not be included in emitted envelope\",\n                fieldName, rmet.getColumnTypeName(columnIndex), dbExtractedData.getClass().getName(), e);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/wire/store/AbstractJdbcWireRecordStoreImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.wire.store;\n\nimport static java.util.Objects.requireNonNull;\n\nimport java.sql.Connection;\nimport java.sql.DatabaseMetaData;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.text.MessageFormat;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.connection.listener.ConnectionListener;\nimport org.eclipse.kura.type.TypedValue;\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.util.jdbc.JdbcUtil;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.eclipse.kura.wire.store.provider.WireRecordStore;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class AbstractJdbcWireRecordStoreImpl implements WireRecordStore {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractJdbcWireRecordStoreImpl.class);\n\n    private static final String COLUMN_NAME = \"COLUMN_NAME\";\n    private static final String TYPE_NAME = \"TYPE_NAME\";\n\n    protected final String tableName;\n    protected final String escapedTableName;\n    protected final ConnectionProvider connectionProvider;\n    protected final JdbcWireRecordStoreQueries queries;\n\n    private Set<ConnectionListener> connectionListeners;\n\n    protected AbstractJdbcWireRecordStoreImpl(final ConnectionProvider connectionProvider, final String tableName) {\n        if (tableName == null || tableName.trim().isEmpty()) {\n            throw new IllegalArgumentException(\"Table name cannot be null or empty.\");\n        }\n        this.tableName = tableName;\n        this.connectionProvider = requireNonNull(connectionProvider, \"Connection provider cannot be null\");\n        this.escapedTableName = escapeIdentifier(tableName);\n        this.queries = buildSqlWireRecordStoreQueries();\n    }\n\n    protected AbstractJdbcWireRecordStoreImpl(ConnectionProvider connectionProvider, String tableName,\n            Set<ConnectionListener> listeners) {\n        this(connectionProvider, tableName);\n\n        this.connectionListeners = listeners;\n    }\n\n    protected abstract Optional<String> getMappedSqlType(final TypedValue<?> value);\n\n    protected abstract JdbcWireRecordStoreQueries buildSqlWireRecordStoreQueries();\n\n    protected String escapeIdentifier(final String string) {\n        final String escapedName = string.replace(\"\\\"\", \"\\\"\\\"\");\n        return \"\\\"\" + escapedName + \"\\\"\";\n    }\n\n    protected void createTable() throws KuraStoreException {\n        this.connectionProvider.withConnection(c -> {\n            execute(c, this.queries.getSqlCreateTable());\n            return null;\n        }, \"failed to create table\");\n    }\n\n    protected void createTimestampIndex() throws KuraStoreException {\n        this.connectionProvider.withConnection(c -> {\n            execute(c, this.queries.getSqlCreateTimestampIndex());\n            return null;\n        }, \"failed to create index\");\n    }\n\n    @Override\n    public synchronized void truncate(final int noOfRecordsToKeep) throws KuraStoreException {\n\n        this.connectionProvider.withConnection(c -> {\n            if (noOfRecordsToKeep == 0) {\n                logger.info(\"Truncating table {}...\", escapedTableName);\n                execute(c, this.queries.getSqlTruncateTable());\n            } else {\n                final int tableSize = getTableSize(c);\n                final int deleteCount = Math.max(0, tableSize - noOfRecordsToKeep);\n\n                if (deleteCount == 0) {\n                    return null;\n                }\n\n                logger.info(\"Partially emptying table {}\", escapedTableName);\n                execute(c, MessageFormat.format(this.queries.getSqlDeleteRangeTable(), deleteCount));\n            }\n\n            return null;\n        }, \"failed to truncate table\");\n\n    }\n\n    @Override\n    public synchronized int getSize() throws KuraStoreException {\n        return this.connectionProvider.withConnection(this::getTableSize, \"failed to determine table size\");\n    }\n\n    @Override\n    public synchronized void insertRecords(final List<WireRecord> records) throws KuraStoreException {\n        this.connectionProvider.withConnection(c -> {\n\n            for (final WireRecord r : records) {\n                try {\n                    createColumns(c, r);\n                    insertRecord(c, r);\n                } catch (final SQLException e) {\n                    logger.info(\"Reconciling table and columns\");\n                    execute(c, this.queries.getSqlCreateTable());\n                    createColumns(c, r);\n                    insertRecord(c, r);\n                }\n            }\n\n            return null;\n        }, \"failed to insert records\");\n    }\n\n    @Override\n    public void close() {\n        // nothing to close\n    }\n\n    protected void createColumns(final Connection c, final WireRecord wireRecord) throws SQLException {\n\n        final Map<String, String> columnTypes = probeColumnTypes(c);\n\n        for (Entry<String, TypedValue<?>> entry : wireRecord.getProperties().entrySet()) {\n\n            createColumn(c, entry.getKey(), entry.getValue(), columnTypes);\n\n        }\n    }\n\n    protected void createColumn(final Connection c, final String name, final TypedValue<?> value,\n            final Map<String, String> columnTypes) throws SQLException {\n\n        final Optional<String> mappedType = getMappedSqlType(value);\n\n        if (!mappedType.isPresent()) {\n            logger.warn(\"Unsupported typed value: {}\", value);\n            return;\n        }\n\n        final String escapedColName = escapeIdentifier(name);\n\n        if (!columnTypes.containsKey(escapedColName)) {\n\n            logger.debug(\"creating new column: {} {}\", name, mappedType.get());\n            execute(c, MessageFormat.format(queries.getSqlAddColumn(), escapedColName, mappedType.get()));\n\n        } else {\n            final String actualColumnType = columnTypes.get(escapedColName);\n\n            if (!isCorrectColumnType(value, mappedType.get(), actualColumnType)) {\n\n                logger.debug(\"changing column type: {} {}\", name, mappedType.get());\n\n                execute(c, MessageFormat.format(queries.getSqlDropColumn(), escapedColName));\n                execute(c, MessageFormat.format(queries.getSqlAddColumn(), escapedColName, mappedType.get()));\n            }\n        }\n    }\n\n    protected boolean isCorrectColumnType(final TypedValue<?> value, final String mappedType, final String actualType) {\n        return mappedType.equals(actualType);\n    }\n\n    protected Map<String, String> probeColumnTypes(final Connection c) throws SQLException {\n        final Map<String, String> result = new HashMap<>();\n\n        final String catalog = c.getCatalog();\n        final DatabaseMetaData dbMetaData = c.getMetaData();\n        try (final ResultSet rsColumns = dbMetaData.getColumns(catalog, null, tableName, null)) {\n\n            while (rsColumns.next()) {\n                final String colName = getEscapedColumnName(rsColumns);\n                final String type = getColumnType(rsColumns);\n\n                result.put(colName, type);\n            }\n        }\n\n        return result;\n    }\n\n    protected String getEscapedColumnName(final ResultSet columnMetadata) throws SQLException {\n        return escapeIdentifier(columnMetadata.getString(COLUMN_NAME));\n    }\n\n    protected String getColumnType(final ResultSet columnMetadata) throws SQLException {\n        return columnMetadata.getString(TYPE_NAME);\n    }\n\n    protected void insertRecord(Connection connection, final WireRecord wireRecord) throws SQLException {\n\n        final String insertQuery = buildInsertQuerySql(wireRecord.getProperties());\n\n        final long timestamp = System.currentTimeMillis();\n\n        logger.debug(\"Storing data into table {}...\", escapedTableName);\n\n        try (final PreparedStatement stmt = connection.prepareStatement(insertQuery)) {\n            stmt.setLong(1, timestamp);\n\n            int i = 2;\n\n            for (Entry<String, TypedValue<?>> entry : wireRecord.getProperties().entrySet()) {\n\n                setParameterValue(stmt, i, entry.getValue().getValue());\n\n                i++;\n            }\n\n            stmt.execute();\n\n            if (isExplicitCommitEnabled()) {\n                connection.commit();\n            }\n\n            logger.debug(\"Stored typed value\");\n        }\n\n    }\n\n    protected String buildInsertQuerySql(final Map<String, TypedValue<?>> properties) {\n        final StringBuilder sbCols = new StringBuilder();\n        final StringBuilder sbVals = new StringBuilder();\n\n        sbCols.append(\"TIMESTAMP\");\n        sbVals.append(\"?\");\n\n        for (final Entry<String, TypedValue<?>> entry : properties.entrySet()) {\n            final String escapedColName = escapeIdentifier(entry.getKey());\n            sbCols.append(\", \").append(escapedColName);\n            sbVals.append(\", ?\");\n        }\n\n        return MessageFormat.format(queries.getSqlInsertRecord(), sbCols.toString(), sbVals.toString());\n    }\n\n    protected void setParameterValue(final PreparedStatement stmt, final int index, final Object value)\n            throws SQLException {\n        if (value instanceof String) {\n            stmt.setString(index, (String) value);\n        } else if (value instanceof Integer) {\n            stmt.setInt(index, (int) value);\n        } else if (value instanceof Double) {\n            stmt.setDouble(index, (double) value);\n        } else if (value instanceof Boolean) {\n            stmt.setBoolean(index, (boolean) value);\n        } else if (value instanceof Float) {\n            stmt.setFloat(index, (float) value);\n        } else if (value instanceof Long) {\n            stmt.setLong(index, (long) value);\n        } else if (value instanceof byte[]) {\n            stmt.setBytes(index, (byte[]) value);\n        } else {\n            logger.warn(\"Unsupported value type {}\", value.getClass());\n        }\n    }\n\n    protected int getTableSize(final Connection c) throws SQLException {\n        try (final Statement stmt = c.createStatement();\n                final ResultSet rset = stmt.executeQuery(this.queries.getSqlRowCount())) {\n            return JdbcUtil.getFirstColumnValue(() -> stmt.executeQuery(this.queries.getSqlRowCount()),\n                    ResultSet::getInt);\n        }\n    }\n\n    protected void execute(final Connection c, final String sql, final Object... params) throws SQLException {\n        try (final PreparedStatement stmt = c.prepareStatement(sql)) {\n            for (int i = 0; i < params.length; i++) {\n                setParameterValue(stmt, 1 + i, params[i]);\n            }\n            stmt.execute();\n\n            if (isExplicitCommitEnabled()) {\n                c.commit();\n            }\n        }\n    }\n\n    protected boolean isExplicitCommitEnabled() {\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/wire/store/JdbcWireRecordStoreQueries.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.wire.store;\n\nimport static java.util.Objects.requireNonNull;\n\npublic class JdbcWireRecordStoreQueries {\n\n    private final String sqlAddColumn;\n    private final String sqlDropColumn;\n    private final String sqlCreateTable;\n    private final String sqlRowCount;\n    private final String sqlDeleteRangeTable;\n    private final String sqlInsertRecord;\n    private final String sqlTruncateTable;\n    private final String sqlCreateTimestampIndex;\n\n    private JdbcWireRecordStoreQueries(Builder builder) {\n        this.sqlAddColumn = requireNonNull(builder.sqlAddColumn);\n        this.sqlDropColumn = requireNonNull(builder.sqlDropColumn);\n        this.sqlCreateTable = requireNonNull(builder.sqlCreateTable);\n        this.sqlRowCount = requireNonNull(builder.sqlRowCount);\n        this.sqlDeleteRangeTable = requireNonNull(builder.sqlDeleteRangeTable);\n        this.sqlInsertRecord = requireNonNull(builder.sqlInsertRecord);\n        this.sqlTruncateTable = requireNonNull(builder.sqlTruncateTable);\n        this.sqlCreateTimestampIndex = requireNonNull(builder.sqlCreateTimestampIndex);\n    }\n\n    public String getSqlAddColumn() {\n        return sqlAddColumn;\n    }\n\n    public String getSqlDropColumn() {\n        return sqlDropColumn;\n    }\n\n    public String getSqlCreateTable() {\n        return sqlCreateTable;\n    }\n\n    public String getSqlRowCount() {\n        return sqlRowCount;\n    }\n\n    public String getSqlDeleteRangeTable() {\n        return sqlDeleteRangeTable;\n    }\n\n    public String getSqlInsertRecord() {\n        return sqlInsertRecord;\n    }\n\n    public String getSqlTruncateTable() {\n        return sqlTruncateTable;\n    }\n\n    public String getSqlCreateTimestampIndex() {\n        return sqlCreateTimestampIndex;\n    }\n\n    public static Builder builder() {\n        return new Builder();\n    }\n\n    public static final class Builder {\n\n        private String sqlAddColumn;\n        private String sqlDropColumn;\n        private String sqlCreateTable;\n        private String sqlRowCount;\n        private String sqlDeleteRangeTable;\n        private String sqlInsertRecord;\n        private String sqlTruncateTable;\n        private String sqlCreateTimestampIndex;\n\n        public Builder withSqlAddColumn(String sqlAddColumn) {\n            this.sqlAddColumn = sqlAddColumn;\n            return this;\n        }\n\n        public Builder withSqlDropColumn(String sqlDropColumn) {\n            this.sqlDropColumn = sqlDropColumn;\n            return this;\n        }\n\n        public Builder withSqlCreateTable(String sqlCreateTable) {\n            this.sqlCreateTable = sqlCreateTable;\n            return this;\n        }\n\n        public Builder withSqlRowCount(String sqlRowCount) {\n            this.sqlRowCount = sqlRowCount;\n            return this;\n        }\n\n        public Builder withSqlDeleteRangeTable(String sqlDeleteRangeTable) {\n            this.sqlDeleteRangeTable = sqlDeleteRangeTable;\n            return this;\n        }\n\n        public Builder withSqlInsertRecord(String sqlInsertRecord) {\n            this.sqlInsertRecord = sqlInsertRecord;\n            return this;\n        }\n\n        public Builder withSqlTruncateTable(String sqlTruncateTable) {\n            this.sqlTruncateTable = sqlTruncateTable;\n            return this;\n        }\n\n        public Builder withSqlCreateTimestampIndex(String sqlCreateTimestampIndex) {\n            this.sqlCreateTimestampIndex = sqlCreateTimestampIndex;\n            return this;\n        }\n\n        public JdbcWireRecordStoreQueries build() {\n            return new JdbcWireRecordStoreQueries(this);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/zip/UnZip.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.zip;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\n\npublic class UnZip {\n\n    private static final int BUFFER = 1024;\n    private static int tooBig = 0x6400000; // Max size of unzipped data, 100MB\n    private static int tooMany = 1024;     // Max number of files\n\n    private UnZip() {\n        // Do nothing...\n    }\n\n    public static void unZipBytes(byte[] bytes, String outputFolder) throws IOException {\n        ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bytes));\n        unZipZipInputStream(zis, outputFolder);\n    }\n\n    public static void unZipFile(String filename, String outputFolder) throws IOException {\n        File file = new File(filename);\n        ZipInputStream zis = new ZipInputStream(new FileInputStream(file));\n        unZipZipInputStream(zis, outputFolder);\n    }\n\n    private static void unZipZipInputStream(ZipInputStream zis, String outFolder) throws IOException {\n        String outputFolder = outFolder;\n        if (outputFolder == null) {\n            outputFolder = System.getProperty(\"user.dir\");\n        }\n\n        File folder = new File(outputFolder);\n        if (!folder.exists()) {\n            folder.mkdirs();\n        }\n\n        int entries = 0;\n        long total = 0;\n        try {\n            ZipEntry ze = zis.getNextEntry();\n\n            while (ze != null) {\n                byte[] buffer = new byte[BUFFER];\n\n                String expectedFilePath = new StringBuilder(folder.getPath()).append(File.separator)\n                        .append(ze.getName()).toString();\n                File newFile = getFile(expectedFilePath, folder);\n\n                if (ze.isDirectory()) {\n                    newFile.mkdirs();\n                    ze = zis.getNextEntry();\n                    continue;\n                }\n\n                if (newFile.getParent() != null) {\n                    File parent = new File(newFile.getParent());\n                    parent.mkdirs();\n                }\n\n                try (FileOutputStream fos = new FileOutputStream(newFile)) {\n\n                    int len = zis.read(buffer);\n                    while (total + BUFFER <= tooBig && len > 0) {\n                        fos.write(buffer, 0, len);\n                        total += len;\n                        len = zis.read(buffer);\n                    }\n                    fos.flush();\n                }\n\n                entries++;\n                if (entries > tooMany) {\n                    throw new IllegalStateException(\"Too many files to unzip.\");\n                }\n                if (total + BUFFER > tooBig) {\n                    throw new IllegalStateException(\"File being unzipped is too big.\");\n                }\n\n                ze = zis.getNextEntry();\n            }\n\n            zis.closeEntry();\n        } finally {\n            if (zis != null) {\n                zis.close();\n            }\n        }\n    }\n\n    private static File getFile(String expectedFilePath, File folder) throws IOException {\n        String fileName;\n        try {\n            fileName = validateFileName(expectedFilePath, folder.getPath());\n        } catch (KuraException e) {\n            throw new IOException(\"File is outside extraction target directory.\");\n        }\n        return new File(fileName);\n    }\n\n    private static String validateFileName(String zipFileName, String intendedDir) throws IOException, KuraException {\n        File zipFile = new File(zipFileName);\n        String filePath = zipFile.getCanonicalPath();\n\n        File iD = new File(intendedDir);\n        String canonicalID = iD.getCanonicalPath();\n\n        if (filePath.startsWith(canonicalID)) {\n            return filePath;\n        } else {\n            throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION);\n        }\n    }\n\n    public static boolean isZipCompressed(String filePath) throws IOException {\n        byte b1 = 0;\n        byte b2 = 0;\n\n        try (InputStream is = new FileInputStream(filePath)) {\n            b1 = (byte) is.read();\n            b2 = (byte) is.read();\n        } catch (IOException e) {\n            throw new IOException(e);\n        }\n\n        return b1 == 0x50 && b2 == 0x4B;\n    }\n\n    public static boolean isZipCompressed(byte[] bytes) {\n        if (bytes.length > 2) {\n            return bytes[0] == 0x50 && bytes[1] == 0x4B;\n        } else {\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.wire.camel\nBundle-SymbolicName: org.eclipse.kura.wire.camel;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nService-Component: OSGI-INF/*.xml\nImport-Package: org.apache.camel;version=\"[2.21,3.0)\",\n org.apache.camel.builder;version=\"[2.21,3.0)\",\n org.eclipse.kura.camel.component;version=\"[1.1,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.type;version=\"[1.1,2.0)\",\n org.eclipse.kura.util.base;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.osgi;version=\"[1.0,2.0)\",\n org.eclipse.kura.wire;version=\"[2.0,3.0)\",\n org.osgi.framework;version=\"[1.8,2.0)\",\n org.osgi.service.component;version=\"[1.3,2.0)\",\n org.osgi.service.wireadmin;version=\"[1.0.1,1.1)\",\n org.osgi.util.tracker;version=\"[1.5,2.0)\",\n org.slf4j;version=\"[1.7,2.0)\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/OSGI-INF/metatype/org.eclipse.kura.wire.camel.CamelConsume.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metatype:MetaData xmlns:metatype=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n\n  <OCD id=\"org.eclipse.kura.wire.camel.CamelConsume\" name=\"Camel Consumer\" description=\"Consume from an endpoint\">\n    <AD id=\"id\" type=\"String\" name=\"ID\" description=\"The ID of the Camel Context\"/>\n    <AD id=\"endpointUri\" type=\"String\" name=\"Endpoint URI\" description=\"The URI to the Camel endpoint the component will consume from.\"/>\n  </OCD>\n\n  <Designate factoryPid=\"org.eclipse.kura.wire.camel.CamelConsume\">\n    <Object ocdref=\"org.eclipse.kura.wire.camel.CamelConsume\"/>\n  </Designate>\n\n</metatype:MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/OSGI-INF/metatype/org.eclipse.kura.wire.camel.CamelProcess.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metatype:MetaData xmlns:metatype=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n\n  <OCD id=\"org.eclipse.kura.wire.camel.CamelProcess\" name=\"Camel Processor\" description=\"Call an endpoint and extract its result\">\n    <AD id=\"id\" type=\"String\" name=\"ID\" description=\"The ID of the Camel Context\"/>\n    <AD id=\"endpointUri\" type=\"String\" name=\"Endpoint URI\" description=\"The URI to the Camel endpoint the component will to call.\"/>\n  </OCD>\n\n  <Designate factoryPid=\"org.eclipse.kura.wire.camel.CamelProcess\">\n    <Object ocdref=\"org.eclipse.kura.wire.camel.CamelProcess\"/>\n  </Designate>\n\n</metatype:MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/OSGI-INF/metatype/org.eclipse.kura.wire.camel.CamelProduce.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<metatype:MetaData xmlns:metatype=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n\n  <OCD id=\"org.eclipse.kura.wire.camel.CamelProduce\" name=\"Camel Producer\" description=\"Produce an exchange using a Camel endpoint\">\n    <AD id=\"id\" type=\"String\" name=\"ID\" description=\"The ID of the Camel Context\"/>\n    <AD id=\"endpointUri\" type=\"String\" name=\"Endpoint URI\" description=\"The URI to the Camel endpoint the component will produce.\"/>\n  </OCD>\n\n  <Designate factoryPid=\"org.eclipse.kura.wire.camel.CamelProduce\">\n    <Object ocdref=\"org.eclipse.kura.wire.camel.CamelProduce\"/>\n  </Designate>\n\n</metatype:MetaData>"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/OSGI-INF/org.eclipse.kura.wire.camel.CamelConsume.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" immediate=\"true\" modified=\"modified\" name=\"org.eclipse.kura.wire.camel.CamelConsume\">\n   <implementation class=\"org.eclipse.kura.wire.camel.CamelConsume\"/>\n   <reference bind=\"setWireHelperService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.wire.WireHelperService\" name=\"WireHelperService\" policy=\"static\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.wire.WireEmitter\"/>\n      <provide interface=\"org.eclipse.kura.wire.WireComponent\"/>\n      <provide interface=\"org.osgi.service.wireadmin.Producer\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/OSGI-INF/org.eclipse.kura.wire.camel.CamelProcess.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" immediate=\"true\" modified=\"modified\" name=\"org.eclipse.kura.wire.camel.CamelProcess\">\n   <implementation class=\"org.eclipse.kura.wire.camel.CamelProcess\"/>\n   <reference bind=\"setWireHelperService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.wire.WireHelperService\" name=\"WireHelperService\" policy=\"static\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.wire.WireReceiver\"/>\n      <provide interface=\"org.eclipse.kura.wire.WireComponent\"/>\n      <provide interface=\"org.osgi.service.wireadmin.Consumer\"/>\n      <provide interface=\"org.osgi.service.wireadmin.Producer\"/>\n      <provide interface=\"org.eclipse.kura.wire.WireEmitter\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/OSGI-INF/org.eclipse.kura.wire.camel.CamelProduce.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" immediate=\"true\" modified=\"modified\" name=\"org.eclipse.kura.wire.camel.CamelProduce\">\n   <implementation class=\"org.eclipse.kura.wire.camel.CamelProduce\"/>\n   <reference bind=\"setWireHelperService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.wire.WireHelperService\" name=\"WireHelperService\" policy=\"static\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n      <provide interface=\"org.eclipse.kura.wire.WireReceiver\"/>\n      <provide interface=\"org.eclipse.kura.wire.WireComponent\"/>\n      <provide interface=\"org.osgi.service.wireadmin.Consumer\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/build.properties",
    "content": "#\n# Copyright (c) 2018, 2020 Red Hat Inc and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Red Hat Inc\n#\n\nsource.. = src/main/java/\noutput.. = target/classes\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html,\\\n               OSGI-INF/\n\nsrc.includes = about.html\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- \n  Copyright (c) 2018, 2024 Red Hat Inc and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Red Hat Inc\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.wire.camel</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n    </properties>\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/src/main/java/org/eclipse/kura/wire/camel/AbstractCamelWireComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2022 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *  heyoulin <heyoulin@gmail.com>\n *******************************************************************************/\npackage org.eclipse.kura.wire.camel;\n\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.apache.camel.CamelContext;\nimport org.eclipse.kura.camel.component.Configuration;\nimport org.eclipse.kura.util.osgi.FilterUtil;\nimport org.eclipse.kura.util.osgi.SingleServiceTracker;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * An abstract base class for creating wire components using a CamelContext.\n */\npublic abstract class AbstractCamelWireComponent extends AbstractWireComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractCamelWireComponent.class);\n\n    protected final BundleContext context = FrameworkUtil.getBundle(AbstractCamelWireComponent.class)\n            .getBundleContext();\n\n    private SingleServiceTracker<CamelContext> tracker;\n\n    private String contextId;\n\n    protected void closeContextTracker() {\n\n        if (this.tracker != null) {\n            this.tracker.close();\n            this.tracker = null;\n        }\n\n    }\n\n    protected void openContextTracker(final String contextId) throws InvalidSyntaxException {\n\n        closeContextTracker();\n\n        if (contextId == null || contextId.isEmpty()) {\n            return;\n        }\n\n        final Filter filter = this.context\n                .createFilter(FilterUtil.simpleFilter(CamelContext.class, \"camel.context.id\", contextId));\n\n        this.tracker = new SingleServiceTracker<>(this.context, filter, this::bindContext);\n        this.tracker.open();\n    }\n\n    protected void bindContext(final CamelContext context) {\n    }\n\n    @Override\n    protected void activate(final ComponentContext componentContext, final Map<String, ?> properties) throws Exception {\n\n        super.activate(componentContext, properties);\n\n        this.contextId = Configuration.asString(properties, \"id\");\n        openContextTracker(this.contextId);\n    }\n\n    @Override\n    protected void modified(final ComponentContext componentContext, Map<String, ?> properties) throws Exception {\n        deactivate();\n        activate(componentContext, properties);\n    }\n\n    @Override\n    protected void deactivate() {\n\n        closeContextTracker();\n\n        super.deactivate();\n    }\n\n    protected void withContext(final Consumer<CamelContext> consumer) {\n        if (this.tracker == null) {\n            logger.info(\"Camel tracker for context: {} is closed. skip processReceive massage\", this.contextId);\n        } else {\n            final CamelContext camelContext = this.tracker.getService();\n\n            if (camelContext != null) {\n                consumer.accept(camelContext);\n            } else {\n                logger.warn(\"Missing Camel context: {}\", this.contextId);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/src/main/java/org/eclipse/kura/wire/camel/AbstractEndpointWireComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.wire.camel;\n\nimport static org.eclipse.kura.camel.component.Configuration.asString;\n\nimport java.util.Map;\n\nimport org.osgi.service.component.ComponentContext;\n\npublic abstract class AbstractEndpointWireComponent extends AbstractCamelWireComponent {\n\n    protected volatile String endpointUri;\n\n    public void setEndpointUri(final String endpointUri) {\n        this.endpointUri = endpointUri;\n    }\n\n    @Override\n    protected void activate(final ComponentContext componentContext, Map<String, ?> properties) throws Exception {\n        setEndpointUri(asString(properties, \"endpointUri\"));\n        super.activate(componentContext, properties);\n    }\n\n    @Override\n    protected void deactivate() {\n        super.deactivate();\n        setEndpointUri(null);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/src/main/java/org/eclipse/kura/wire/camel/AbstractReceiverWireComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.wire.camel;\n\nimport org.apache.camel.CamelContext;\nimport org.eclipse.kura.util.base.StringUtil;\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.eclipse.kura.wire.WireReceiver;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic abstract class AbstractReceiverWireComponent extends AbstractEndpointWireComponent implements WireReceiver {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractReceiverWireComponent.class);\n\n    @Override\n    public void onWireReceive(final WireEnvelope envelope) {\n        logger.debug(\"Received: {}\", envelope);\n\n        withContext(context -> {\n            try {\n                processReceive(context, envelope);\n            } catch (final Exception e) {\n                logger.warn(\"Failed to produce event\", e);\n            }\n        });\n    }\n\n    private void processReceive(final CamelContext context, final WireEnvelope envelope) throws Exception {\n\n        final String endpointUri = this.endpointUri;\n\n        if (StringUtil.isNullOrEmpty(endpointUri)) {\n            logger.debug(\"Endpoint missing. Component is disabled.\");\n            return;\n        }\n\n        processReceive(context, endpointUri, envelope);\n    }\n\n    protected abstract void processReceive(CamelContext context, String endpointUri, WireEnvelope envelope)\n            throws Exception;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/src/main/java/org/eclipse/kura/wire/camel/AbstractWireComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.wire.camel;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.wire.WireComponent;\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.eclipse.kura.wire.WireHelperService;\nimport org.eclipse.kura.wire.WireSupport;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.wireadmin.Wire;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * An abstract base class for creating wire components.\n */\npublic abstract class AbstractWireComponent implements WireComponent, ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(AbstractWireComponent.class);\n\n    private WireHelperService wireHelperService;\n\n    protected WireSupport wireSupport;\n\n    public void setWireHelperService(final WireHelperService wireHelperService) {\n        this.wireHelperService = wireHelperService;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    protected synchronized void activate(final ComponentContext componentContext, final Map<String, ?> properties)\n            throws Exception {\n        if (this.wireSupport == null) {\n            this.wireSupport = this.wireHelperService.newWireSupport(this,\n                    (ServiceReference<WireComponent>) componentContext.getServiceReference());\n        }\n    }\n\n    protected void modified(final ComponentContext componentContext, final Map<String, ?> properties) throws Exception {\n    }\n\n    protected synchronized void deactivate() {\n        /*\n         * We must not close the wireSupport instance here as we do implement\n         * modify by calls to deactivate/activate and thus we would loose all\n         * information of exiting wirings.\n         */\n    }\n\n    /*\n     * For subclasses implementing WireReceiver\n     */\n    public synchronized void updated(final Wire wire, final Object value) {\n        logger.debug(\"Updated: {}\", wire);\n\n        this.wireSupport.updated(wire, value);\n    }\n\n    /*\n     * For subclasses implementing WireReceiver\n     */\n    public synchronized void producersConnected(final Wire[] wires) {\n        logger.info(\"Producers connected - {}\", (Object) wires);\n        this.wireSupport.producersConnected(wires);\n    }\n\n    /*\n     * For subclasses implementing WireEmitter\n     */\n    public synchronized Object polled(final Wire wire) {\n        logger.debug(\"Polled: {}\", wire);\n        return this.wireSupport.polled(wire);\n    }\n\n    /*\n     * For subclasses implementing WireEmitter\n     */\n    public synchronized void consumersConnected(final Wire[] wires) {\n        logger.info(\"Consumers connected - {}\", (Object) wires);\n        this.wireSupport.consumersConnected(wires);\n    }\n\n    /*\n     * For subclasses implementing WireReceiver\n     */\n    public synchronized void onWireReceive(final WireEnvelope wireEnvelope) {\n        logger.debug(\"onWireReceive: {}\", wireEnvelope);\n    }\n}"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/src/main/java/org/eclipse/kura/wire/camel/CamelConsume.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.wire.camel;\n\nimport static java.util.Arrays.asList;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.Consumer;\nimport org.apache.camel.Endpoint;\nimport org.apache.camel.Message;\nimport org.eclipse.kura.wire.WireEmitter;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CamelConsume extends AbstractEndpointWireComponent implements WireEmitter {\n\n    private static final Logger logger = LoggerFactory.getLogger(CamelConsume.class);\n\n    private Endpoint endpoint;\n    private Consumer consumer;\n\n    private CamelContext camelContext;\n\n    @Override\n    protected void bindContext(final CamelContext context) {\n\n        try {\n            stopConsumer();\n            this.camelContext = context;\n            startConsumer();\n        } catch (Exception e) {\n            logger.warn(\"Failed to bind Camel context\", e);\n        }\n\n    }\n\n    @Override\n    public void setEndpointUri(final String endpointUri) {\n        if (this.endpointUri == null || !this.endpointUri.equals(endpointUri)) {\n            try {\n                stopConsumer();\n                super.setEndpointUri(endpointUri);\n                startConsumer();\n            } catch (final Exception e) {\n                logger.warn(\"Failed to set endpoint URI\", e);\n            }\n        }\n    }\n\n    private void startConsumer() throws Exception {\n        if (this.camelContext == null) {\n            return;\n        }\n\n        if (this.endpoint == null) {\n            logger.info(\"Starting endpoint\");\n            this.endpoint = this.camelContext.getEndpoint(this.endpointUri);\n            this.endpoint.start();\n        }\n\n        if (this.consumer == null) {\n            logger.info(\"Starting consumer\");\n            this.consumer = this.endpoint.createConsumer(exchange -> processMessage(exchange.getIn()));\n            this.consumer.start();\n        }\n\n    }\n\n    private void stopConsumer() throws Exception {\n\n        if (this.consumer != null) {\n            logger.info(\"Stopping consumer\");\n            this.consumer.stop();\n            this.consumer = null;\n        }\n\n        if (this.endpoint != null) {\n            logger.info(\"Stopping endpoint\");\n            this.endpoint.stop();\n            this.endpoint = null;\n        }\n    }\n\n    private void processMessage(final Message message) {\n        logger.debug(\"Process message: {}\", message);\n\n        final WireRecord[] records = message.getBody(WireRecord[].class);\n\n        logger.debug(\"Consumed: {}\", (Object) records);\n\n        if (records != null) {\n            this.wireSupport.emit(asList(records));\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/src/main/java/org/eclipse/kura/wire/camel/CamelProcess.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.wire.camel;\n\nimport static org.apache.camel.builder.DefaultFluentProducerTemplate.on;\n\nimport java.util.Arrays;\n\nimport org.apache.camel.CamelContext;\nimport org.eclipse.kura.wire.WireEmitter;\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CamelProcess extends AbstractReceiverWireComponent implements WireEmitter {\n\n    private static final Logger logger = LoggerFactory.getLogger(CamelProcess.class);\n\n    @Override\n    protected void processReceive(final CamelContext context, final String endpointUri, final WireEnvelope envelope)\n            throws Exception {\n\n        final WireRecord[] result = on(context) //\n                .withBody(envelope) //\n                .to(endpointUri) //\n                .request(WireRecord[].class);\n\n        logger.debug(\"Result: {}\", (Object) result);\n\n        if (result != null) {\n            this.wireSupport.emit(Arrays.asList(result));\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.wire.camel/src/main/java/org/eclipse/kura/wire/camel/CamelProduce.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2022 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *  heyoulin <heyoulin@gmail.com>\n *******************************************************************************/\npackage org.eclipse.kura.wire.camel;\n\nimport static org.apache.camel.builder.DefaultFluentProducerTemplate.on;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.FluentProducerTemplate;\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CamelProduce extends AbstractReceiverWireComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(CamelProduce.class);\n\n    private FluentProducerTemplate template = null;\n\n    @Override\n    protected void bindContext(final CamelContext context) {\n\n        try {\n            closeTemplate();\n            if (context != null) {\n                this.template = on(context);\n            }\n        } catch (Exception e) {\n            logger.warn(\"Failed to bind Camel context\", e);\n        }\n\n    }\n\n    @Override\n    protected void processReceive(final CamelContext context, final String endpointUri, final WireEnvelope envelope)\n            throws Exception {\n        if (template != null && context != null) {\n            try {\n                template //\n                        .withBody(envelope) //\n                        .to(endpointUri) //\n                        .asyncSend();\n            } catch (Exception e) {\n                logger.error(\"asyncSend error\", e);\n            }\n        } else {\n            logger.debug(\"FluentProducerTemplate is changing. Skip send massage and wait next massage\");\n        }\n    }\n\n    @Override\n    protected void deactivate() {\n        closeTemplate();\n    }\n\n    private void closeTemplate() {\n        if (template != null) {\n            try {\n                template.stop();\n            } catch (Exception ignored) {\n            } finally {\n                template = null;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Kura XML Marshaller utility\nBundle-SymbolicName: org.eclipse.kura.xml.marshaller.unmarshaller.provider;singleton:=true\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: javax.xml,\n javax.xml.parsers,\n javax.xml.stream,\n javax.xml.transform,\n javax.xml.transform.dom,\n javax.xml.transform.stream,\n org.apache.commons.io.build;version=\"[2.18,3.0)\",\n org.apache.commons.io.input;version=\"[2.18,3.0)\",\n org.eclipse.kura;version=\"[1.4,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.configuration;version=\"[2.0,3.0)\",\n org.eclipse.kura.core.configuration.metatype;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.inventory.resources;version=\"[1.0,2.0)\",\n org.eclipse.kura.marshalling;version=\"[1.1,1.2)\",\n org.eclipse.kura.system;version=\"[1.5,2.0)\",\n org.slf4j;version=\"1.7.21\",\n org.w3c.dom,\n org.xml.sax\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nExport-Package: org.eclipse.kura.internal.xml.marshaller.unmarshaller;version=\"1.1.0\"\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/OSGI-INF/XmlMarshallerUnmarshallerComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    \n   Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n    Eurotech\n    \n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" enabled=\"true\" immediate=\"false\" name=\"org.eclipse.kura.xml.marshaller.unmarshaller.provider\">\n   <implementation class=\"org.eclipse.kura.internal.xml.marshaller.unmarshaller.XmlMarshallUnmarshallImpl\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.marshalling.Marshaller\"/>\n      <provide interface=\"org.eclipse.kura.marshalling.Unmarshaller\"/>\n   </service>\n   <property name=\"service.pid\" value=\"org.eclipse.kura.xml.marshaller.unmarshaller.provider\"/>\n   <property name=\"kura.service.pid\" value=\"org.eclipse.kura.xml.marshaller.unmarshaller.provider\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/build.properties",
    "content": "#\n#  Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html,\\\n               OSGI-INF/\nsrc.includes = about.html\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\t \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>kura</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.xml.marshaller.unmarshaller.provider</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>eclipse-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/../test/org.eclipse.kura.xml.marshaller.unmarshaller.provider.test/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n</project>\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaBundlesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport org.eclipse.kura.core.inventory.resources.SystemBundle;\nimport org.eclipse.kura.core.inventory.resources.SystemBundles;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\npublic class XmlJavaBundlesMapper implements XmlJavaDataMapper {\n\n    private static final String BUNDLES = \"bundles\";\n    private static final String BUNDLES_BUNDLE = \"bundle\";\n    private static final String BUNDLES_BUNDLE_NAME = \"name\";\n    private static final String BUNDLES_BUNDLE_VERSION = \"version\";\n    private static final String BUNDLES_BUNDLE_ID = \"id\";\n    private static final String BUNDLES_BUNDLE_STATE = \"state\";\n\n    @Override\n    public Element marshal(Document doc, Object object) throws Exception {\n        Element bundles = doc.createElement(BUNDLES);\n        doc.appendChild(bundles);\n\n        SystemBundles xmlBundles = (SystemBundles) object;\n        SystemBundle[] xmlBundleArray = xmlBundles.getBundles();\n\n        for (SystemBundle xmlBundle : xmlBundleArray) {\n            Element bundle = doc.createElement(BUNDLES_BUNDLE);\n            marshallBundle(doc, xmlBundle, bundle);\n            bundles.appendChild(bundle);\n        }\n        return bundles;\n    }\n\n    @Override\n    public <T> T unmarshal(Document doc) throws Exception {\n        return null;\n    }\n\n    //\n    // Marshaller's private methods\n    //\n    private static void marshallBundle(Document doc, SystemBundle xmlBundle, Element bundle) {\n        // Extract data from XmlBundle\n        String bundleName = xmlBundle.getName();\n        String bundleVersion = xmlBundle.getVersion();\n        String bundleId = Long.toString(xmlBundle.getId());\n        String bundleState = xmlBundle.getState();\n\n        // Create xml elements\n        if (bundleName != null && !bundleName.trim().isEmpty()) {\n            Element name = doc.createElement(BUNDLES_BUNDLE_NAME);\n            name.setTextContent(bundleName);\n            bundle.appendChild(name);\n        }\n\n        if (bundleVersion != null && !bundleVersion.trim().isEmpty()) {\n            Element version = doc.createElement(BUNDLES_BUNDLE_VERSION);\n            version.setTextContent(bundleVersion);\n            bundle.appendChild(version);\n        }\n\n        if (bundleId != null && !bundleId.trim().isEmpty()) {\n            Element id = doc.createElement(BUNDLES_BUNDLE_ID);\n            id.setTextContent(bundleId);\n            bundle.appendChild(id);\n        }\n\n        if (bundleState != null && !bundleState.trim().isEmpty()) {\n            Element state = doc.createElement(BUNDLES_BUNDLE_STATE);\n            state.setTextContent(bundleState);\n            bundle.appendChild(state);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaComponentConfigurationsMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.core.configuration.ComponentConfigurationImpl;\nimport org.eclipse.kura.core.configuration.XmlComponentConfigurations;\nimport org.eclipse.kura.core.configuration.XmlConfigPropertiesAdapted;\nimport org.eclipse.kura.core.configuration.XmlConfigPropertiesAdapter;\nimport org.eclipse.kura.core.configuration.XmlConfigPropertyAdapted;\nimport org.eclipse.kura.core.configuration.XmlConfigPropertyAdapted.ConfigPropertyType;\nimport org.w3c.dom.Attr;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\npublic class XmlJavaComponentConfigurationsMapper implements XmlJavaDataMapper {\n\n    private static final String CONFIGURATIONS = \"configurations\";\n    private static final String PROPERTIES = \"properties\";\n\n    private static final String CONFIGURATION_PID = \"pid\";\n\n    private static final String CONFIGURATIONS_CONFIGURATION = \"configuration\";\n    private static final String CONFIGURATIONS_CONFIGURATION_PROPERTY = \"property\";\n    private static final String CONFIGURATIONS_CONFIGURATION_PROPERTY_NAME = \"name\";\n    private static final String CONFIGURATIONS_CONFIGURATION_PROPERTY_ARRAY = \"array\";\n    private static final String CONFIGURATIONS_CONFIGURATION_PROPERTY_ENCRYPTED = \"encrypted\";\n    private static final String CONFIGURATIONS_CONFIGURATION_PROPERTY_TYPE = \"type\";\n    private static final String CONFIGURATIONS_CONFIGURATION_PROPERTY_VALUE = \"value\";\n\n    private Document marshallDoc = null;\n\n    @Override\n    public Element marshal(Document doc, Object object) throws Exception {\n        this.marshallDoc = doc;\n        Element configurations = doc.createElement(ESF_NAMESPACE + \":\" + CONFIGURATIONS);\n        configurations.setAttributeNS(\"http://www.w3.org/2000/xmlns/\", \"xmlns:esf\", \"http://eurotech.com/esf/2.0\");\n        configurations.setAttributeNS(\"http://www.w3.org/2000/xmlns/\", \"xmlns:ocd\",\n                \"http://www.osgi.org/xmlns/metatype/v1.2.0\");\n        doc.appendChild(configurations);\n\n        XmlComponentConfigurations xmlCompConfig = (XmlComponentConfigurations) object;\n        List<ComponentConfiguration> configs = xmlCompConfig.getConfigurations();\n\n        if (configs != null) {\n            for (ComponentConfiguration config : configs) {\n                Element configuration = marshallConfiguration(config);\n                configurations.appendChild(configuration);\n            }\n        }\n        return configurations;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public <T> T unmarshal(Document doc) throws Exception {\n        XmlComponentConfigurations xcc = new XmlComponentConfigurations();\n\n        // Get all configurations\n        NodeList configurationList = doc.getElementsByTagName(ESF_NAMESPACE + \":\" + CONFIGURATIONS_CONFIGURATION);\n\n        List<ComponentConfiguration> compConfList = new ArrayList<>();\n        // Iterate through all the configuration elements inside configurations tag\n        for (int configIndex = 0; configIndex < configurationList.getLength(); configIndex++) {\n            Element configuration = (Element) configurationList.item(configIndex);\n            ComponentConfiguration cci = parseConfiguration(configuration);\n            compConfList.add(cci);\n        }\n        xcc.setConfigurations(compConfList);\n        return (T) xcc;\n    }\n\n    //\n    // Marshaller's private methods\n    //\n    private Element marshallConfiguration(ComponentConfiguration config) throws Exception {\n        // get ComponentConfigurationImpl Object data\n        String configPid = config.getPid();\n        Map<String, Object> configProperty = config.getConfigurationProperties();\n        OCD configOCD = config.getDefinition();\n\n        // create configuration element\n        Element configurationElement = this.marshallDoc\n                .createElement(ESF_NAMESPACE + \":\" + CONFIGURATIONS_CONFIGURATION);\n        Attr propertiesAttribute = this.marshallDoc.createAttribute(CONFIGURATION_PID);\n        propertiesAttribute.setNodeValue(configPid);\n        configurationElement.setAttributeNode(propertiesAttribute);\n\n        // Add OCD node and marshall definitions\n        if (configOCD != null) {\n            Element ocd = new XmlJavaMetadataMapper().marshal(this.marshallDoc, configOCD);\n            configurationElement.appendChild(ocd);\n        }\n\n        // Add properties Node and marshall properties\n        if (configProperty != null) {\n            Element properties = this.marshallDoc.createElement(ESF_NAMESPACE + \":\" + PROPERTIES);\n            marshallProperties(configProperty, properties);\n            configurationElement.appendChild(properties);\n        }\n\n        return configurationElement;\n    }\n\n    private void marshallProperties(Map<String, Object> propertyMap, Element properties) throws Exception {\n        XmlConfigPropertiesAdapter xmlPropAdapter = new XmlConfigPropertiesAdapter();\n        XmlConfigPropertiesAdapted configPropAdapted = xmlPropAdapter.marshal(propertyMap);\n\n        XmlConfigPropertyAdapted[] propArray = configPropAdapted.getProperties();\n        for (XmlConfigPropertyAdapted propertyObj : propArray) {\n            Element property = marshallProperty(propertyObj);\n            if (property != null) {\n                properties.appendChild(property);\n            }\n        }\n    }\n\n    private Element marshallProperty(XmlConfigPropertyAdapted propertyObj) {\n        String name = propertyObj.getName();\n        Boolean array = propertyObj.getArray();\n        Boolean encrypted = propertyObj.isEncrypted();\n        ConfigPropertyType cpt = propertyObj.getType();\n        String[] values = propertyObj.getValues();\n\n        if (values != null) {\n            Element property = this.marshallDoc\n                    .createElement(ESF_NAMESPACE + \":\" + CONFIGURATIONS_CONFIGURATION_PROPERTY);\n            Attr attName = this.marshallDoc.createAttribute(CONFIGURATIONS_CONFIGURATION_PROPERTY_NAME);\n            attName.setNodeValue(name);\n            property.setAttributeNode(attName);\n\n            Attr attArray = this.marshallDoc.createAttribute(CONFIGURATIONS_CONFIGURATION_PROPERTY_ARRAY);\n            attArray.setNodeValue(array.toString());\n            property.setAttributeNode(attArray);\n\n            Attr attEncrypted = this.marshallDoc.createAttribute(CONFIGURATIONS_CONFIGURATION_PROPERTY_ENCRYPTED);\n            attEncrypted.setNodeValue(encrypted.toString());\n            property.setAttributeNode(attEncrypted);\n\n            Attr attType = this.marshallDoc.createAttribute(CONFIGURATIONS_CONFIGURATION_PROPERTY_TYPE);\n\n            attType.setNodeValue(getStringValue(cpt));\n            property.setAttributeNode(attType);\n\n            for (String value : values) {\n                Element valueElem = this.marshallDoc\n                        .createElement(ESF_NAMESPACE + \":\" + CONFIGURATIONS_CONFIGURATION_PROPERTY_VALUE);\n                valueElem.setTextContent(value);\n                property.appendChild(valueElem);\n            }\n            return property;\n        }\n        return null;\n    }\n\n    private String getStringValue(ConfigPropertyType type) {\n        if (type == null) {\n            return \"String\";\n        }\n        if (type.equals(ConfigPropertyType.STRING_TYPE)) {\n            return \"String\";\n        } else if (type.equals(ConfigPropertyType.LONG_TYPE)) {\n            return \"Long\";\n        } else if (type.equals(ConfigPropertyType.DOUBLE_TYPE)) {\n            return \"Double\";\n        } else if (type.equals(ConfigPropertyType.FLOAT_TYPE)) {\n            return \"Float\";\n        } else if (type.equals(ConfigPropertyType.INTEGER_TYPE)) {\n            return \"Integer\";\n        } else if (type.equals(ConfigPropertyType.BYTE_TYPE)) {\n            return \"Byte\";\n        } else if (type.equals(ConfigPropertyType.CHAR_TYPE)) {\n            return \"Char\";\n        } else if (type.equals(ConfigPropertyType.BOOLEAN_TYPE)) {\n            return \"Boolean\";\n        } else if (type.equals(ConfigPropertyType.SHORT_TYPE)) {\n            return \"Short\";\n        } else if (type.equals(ConfigPropertyType.PASSWORD_TYPE)) {\n            return \"Password\";\n        }\n        return \"String\";\n    }\n\n    //\n    // Unmarshaller's private methods\n    //\n    private ComponentConfiguration parseConfiguration(Element configuration) throws Exception {\n        XmlConfigPropertiesAdapter xmlPropAdapter = new XmlConfigPropertiesAdapter();\n\n        // get configuration's properties\n        NodeList propertiesList = configuration.getChildNodes();\n\n        // get effective elements\n        Element[] propertiesArray = getElementNodes(propertiesList);\n\n        XmlConfigPropertiesAdapted xmlPropertiesAdapted = new XmlConfigPropertiesAdapted();\n        for (Element element : propertiesArray) {\n            // parse property elements\n            NodeList propertyList = element.getChildNodes();\n            Element[] propertyArray = getElementNodes(propertyList);\n\n            XmlConfigPropertyAdapted[] xmlConfigProperties = new XmlConfigPropertyAdapted[propertyArray.length];\n            for (int propertyIndex = 0; propertyIndex < propertyArray.length; propertyIndex++) {\n                XmlConfigPropertyAdapted xmlProperty = parseProperty(propertyArray[propertyIndex]);\n                xmlConfigProperties[propertyIndex] = xmlProperty;\n            }\n            xmlPropertiesAdapted.setProperties(xmlConfigProperties);\n        }\n\n        Map<String, Object> propertiesMap = xmlPropAdapter.unmarshal(xmlPropertiesAdapted);\n\n        String pid = configuration.getAttribute(CONFIGURATION_PID);\n        return new ComponentConfigurationImpl(pid, null, propertiesMap);\n    }\n\n    private XmlConfigPropertyAdapted parseProperty(Element property) {\n        NodeList valuesList = property.getChildNodes();\n        Element[] valuesArray = getElementNodes(valuesList);\n        String[] values = new String[valuesArray.length];\n\n        // get values\n        for (int valIndex = 0; valIndex < valuesArray.length; valIndex++) {\n            values[valIndex] = valuesArray[valIndex].getTextContent();\n        }\n\n        String name = property.getAttribute(CONFIGURATIONS_CONFIGURATION_PROPERTY_NAME);\n        String type = property.getAttribute(CONFIGURATIONS_CONFIGURATION_PROPERTY_TYPE);\n        String array = property.getAttribute(CONFIGURATIONS_CONFIGURATION_PROPERTY_ARRAY);\n        String encrypted = property.getAttribute(CONFIGURATIONS_CONFIGURATION_PROPERTY_ENCRYPTED);\n\n        ConfigPropertyType cct = getType(type);\n\n        XmlConfigPropertyAdapted xmlProperty = new XmlConfigPropertyAdapted(name, cct, values);\n        xmlProperty.setArray(Boolean.parseBoolean(array));\n        xmlProperty.setEncrypted(Boolean.parseBoolean(encrypted));\n\n        return xmlProperty;\n    }\n\n    private Element[] getElementNodes(NodeList propertiesList) {\n        List<Element> elementList = new ArrayList<>();\n        for (int propIndex = 0; propIndex < propertiesList.getLength(); propIndex++) {\n            Node currentNode = propertiesList.item(propIndex);\n            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {\n                Element el = (Element) currentNode;\n                elementList.add(el);\n            }\n        }\n        return elementList.toArray(new Element[0]);\n    }\n\n    private ConfigPropertyType getType(String type) {\n        if (type.equals(\"String\")) {\n            return ConfigPropertyType.STRING_TYPE;\n        } else if (type.equals(\"Long\")) {\n            return ConfigPropertyType.LONG_TYPE;\n        } else if (type.equals(\"Double\")) {\n            return ConfigPropertyType.DOUBLE_TYPE;\n        } else if (type.equals(\"Float\")) {\n            return ConfigPropertyType.FLOAT_TYPE;\n        } else if (type.equals(\"Integer\")) {\n            return ConfigPropertyType.INTEGER_TYPE;\n        } else if (type.equals(\"Byte\")) {\n            return ConfigPropertyType.BYTE_TYPE;\n        } else if (type.equals(\"Char\")) {\n            return ConfigPropertyType.CHAR_TYPE;\n        } else if (type.equals(\"Boolean\")) {\n            return ConfigPropertyType.BOOLEAN_TYPE;\n        } else if (type.equals(\"Short\")) {\n            return ConfigPropertyType.SHORT_TYPE;\n        } else if (type.equals(\"Password\")) {\n            return ConfigPropertyType.PASSWORD_TYPE;\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaContainerImagesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport java.util.List;\n\nimport org.eclipse.kura.core.inventory.resources.ContainerImage;\nimport org.eclipse.kura.core.inventory.resources.ContainerImages;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\npublic class XmlJavaContainerImagesMapper implements XmlJavaDataMapper {\n\n    private static final String IMAGES = \"images\";\n    private static final String CONTAINERS_IMAGES = \"image\";\n    private static final String CONTAINERS_IMAGES_NAME = \"name\";\n    private static final String CONTAINERS_IMAGES_VERSION = \"version\";\n\n    @Override\n    public Element marshal(Document doc, Object object) throws Exception {\n        Element packages = doc.createElement(IMAGES);\n        doc.appendChild(packages);\n\n        ContainerImages images = (ContainerImages) object;\n        List<ContainerImage> imageList = images.getContainerImages();\n\n        for (ContainerImage ximage : imageList) {\n            Element packageInstalled = doc.createElement(CONTAINERS_IMAGES);\n            marshalContainer(doc, ximage, packageInstalled);\n            packages.appendChild(packageInstalled);\n        }\n        return packages;\n    }\n\n    @Override\n    public <T> T unmarshal(Document doc) throws Exception {\n        return null;\n    }\n\n    //\n    // Marshaller's private methods\n    //\n    private static void marshalContainer(Document doc, ContainerImage image, Element packageInstalled) {\n        // Extract data from XmlDeploymentPackage\n        String imageName = image.getName();\n        String imageVersion = image.getVersion();\n\n        // Create xml elements\n        if (imageName != null && !imageName.trim().isEmpty()) {\n            Element name = doc.createElement(CONTAINERS_IMAGES_NAME);\n            name.setTextContent(imageName);\n            packageInstalled.appendChild(name);\n        }\n\n        if (imageVersion != null && !imageVersion.trim().isEmpty()) {\n            Element version = doc.createElement(CONTAINERS_IMAGES_VERSION);\n            version.setTextContent(imageVersion);\n            packageInstalled.appendChild(version);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaDataMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\npublic interface XmlJavaDataMapper {\n\n    static final Logger s_logger = LoggerFactory.getLogger(XmlJavaDataMapper.class);\n    static final String ESF_NAMESPACE = \"esf\";\n    static final String OCD_NAMESPACE = \"ocd\";\n\n    public abstract Element marshal(Document doc, Object o) throws Exception;\n\n    public abstract <T> T unmarshal(Document doc) throws Exception;\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaDockerContainersMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport java.util.List;\n\nimport org.eclipse.kura.core.inventory.resources.DockerContainer;\nimport org.eclipse.kura.core.inventory.resources.DockerContainers;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\npublic class XmlJavaDockerContainersMapper implements XmlJavaDataMapper {\n\n    private static final String CONTAINERS = \"containers\";\n    private static final String CONTAINERS_CONTAINER = \"container\";\n    private static final String CONTAINERS_CONTAINER_NAME = \"name\";\n    private static final String CONTAINERS_CONTAINER_VERSION = \"version\";\n    private static final String CONTAINERS_CONTAINER_STATE = \"state\";\n\n    @Override\n    public Element marshal(Document doc, Object object) throws Exception {\n        Element packages = doc.createElement(CONTAINERS);\n        doc.appendChild(packages);\n\n        DockerContainers containers = (DockerContainers) object;\n        List<DockerContainer> containerList = containers.getDockerContainers();\n\n        for (DockerContainer xcontainer : containerList) {\n            Element packageInstalled = doc.createElement(CONTAINERS_CONTAINER);\n            marshalContainer(doc, xcontainer, packageInstalled);\n            packages.appendChild(packageInstalled);\n        }\n        return packages;\n    }\n\n    @Override\n    public <T> T unmarshal(Document doc) throws Exception {\n        return null;\n    }\n\n    //\n    // Marshaller's private methods\n    //\n    private static void marshalContainer(Document doc, DockerContainer container, Element packageInstalled) {\n        // Extract data from XmlDeploymentPackage\n        String containerName = container.getName();\n        String containerVersion = container.getVersion();\n        String containerState = container.getFrameworkContainerState();\n\n        // Create xml elements\n        if (containerName != null && !containerName.trim().isEmpty()) {\n            Element name = doc.createElement(CONTAINERS_CONTAINER_NAME);\n            name.setTextContent(containerName);\n            packageInstalled.appendChild(name);\n        }\n\n        if (containerVersion != null && !containerVersion.trim().isEmpty()) {\n            Element version = doc.createElement(CONTAINERS_CONTAINER_VERSION);\n            version.setTextContent(containerVersion);\n            packageInstalled.appendChild(version);\n        }\n\n        if (containerState != null && !containerState.trim().isEmpty()) {\n            Element state = doc.createElement(CONTAINERS_CONTAINER_STATE);\n            state.setTextContent(containerState);\n            packageInstalled.appendChild(state);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaMetadataMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.Icon;\nimport org.eclipse.kura.configuration.metatype.Option;\nimport org.eclipse.kura.configuration.metatype.Scalar;\nimport org.eclipse.kura.core.configuration.metatype.Tad;\nimport org.eclipse.kura.core.configuration.metatype.Tdesignate;\nimport org.eclipse.kura.core.configuration.metatype.Ticon;\nimport org.eclipse.kura.core.configuration.metatype.Tmetadata;\nimport org.eclipse.kura.core.configuration.metatype.Tobject;\nimport org.eclipse.kura.core.configuration.metatype.Tocd;\nimport org.eclipse.kura.core.configuration.metatype.Toption;\nimport org.eclipse.kura.core.configuration.metatype.Tscalar;\nimport org.w3c.dom.Attr;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\n\npublic class XmlJavaMetadataMapper implements XmlJavaDataMapper {\n\n    private static final String METADATA_LOCALIZATION = \"localization\";\n\n    private static final String METADATA_OCD = \"OCD\";\n    private static final String METADATA_OCD_NAME = \"name\";\n    private static final String METADATA_OCD_ID = \"id\";\n    private static final String METADATA_OCD_DESCRIPTION = \"description\";\n\n    private static final String METADATA_ICON = \"Icon\";\n    private static final String METADATA_ICON_RESOURCE = \"resource\";\n    private static final String METADATA_ICON_SIZE = \"size\";\n\n    private static final String METADATA_AD = \"AD\";\n    private static final String METADATA_AD_ID = \"id\";\n    private static final String METADATA_AD_NAME = \"name\";\n    private static final String METADATA_AD_TYPE = \"type\";\n    private static final String METADATA_AD_CARDINALITY = \"cardinality\";\n    private static final String METADATA_AD_REQUIRED = \"required\";\n    private static final String METADATA_AD_DEFAULT = \"default\";\n    private static final String METADATA_AD_DESCRIPTION = \"description\";\n    private static final String METADATA_AD_MIN = \"min\";\n    private static final String METADATA_AD_MAX = \"max\";\n\n    private static final String METADATA_AD_OPTION = \"Option\";\n    private static final String METADATA_AD_OPTION_LABEL = \"label\";\n    private static final String METADATA_AD_OPTION_VALUE = \"value\";\n\n    private static final String METADATA_DESIGNATE_OBJECT = \"Object\";\n    private static final String METADATA_DESIGNATE_PID = \"pid\";\n    private static final String METADATA_DESIGNATE_FACTORY_PID = \"factoryPid\";\n    private static final String METADATA_DESIGNATE_BUNDLE = \"bundle\";\n    private static final String METADATA_DESIGNATE_OPTIONAL = \"optional\";\n    private static final String METADATA_DESIGNATE_MERGE = \"merge\";\n\n    private static final String METADATA_DESIGNATE_OBJECT_ATTRIBUTE = \"Attribute\";\n    private static final String METADATA_DESIGNATE_OBJECT_OCDREF = \"ocdref\";\n\n    private Document marshallDoc = null;\n\n    //\n    // Public methods\n    //\n    @Override\n    public Element marshal(Document doc, Object o) throws Exception {\n        this.marshallDoc = doc;\n        if (o instanceof Tocd) {\n            Tocd configOCD = (Tocd) o;\n\n            String ocdName = configOCD.getName();\n            String ocdDescription = configOCD.getDescription();\n            String ocdID = configOCD.getId();\n            List<Icon> ocdIcons = configOCD.getIcon();\n            List<AD> ocdADs = configOCD.getAD();\n            configOCD.getAny();\n            configOCD.getOtherAttributes();\n\n            Element ocd = this.marshallDoc.createElement(OCD_NAMESPACE + \":\" + METADATA_OCD);\n\n            if (ocdName != null && !ocdName.trim().isEmpty()) {\n                Attr ocdAttrName = this.marshallDoc.createAttribute(METADATA_OCD_NAME);\n                ocdAttrName.setNodeValue(ocdName);\n                ocd.setAttributeNode(ocdAttrName);\n            }\n\n            if (ocdDescription != null && !ocdDescription.trim().isEmpty()) {\n                Attr ocdAttrDescription = this.marshallDoc.createAttribute(METADATA_OCD_DESCRIPTION);\n                ocdAttrDescription.setNodeValue(ocdDescription);\n                ocd.setAttributeNode(ocdAttrDescription);\n            }\n\n            if (ocdID != null && !ocdID.trim().isEmpty()) {\n                Attr ocdAttrId = this.marshallDoc.createAttribute(METADATA_OCD_ID);\n                ocdAttrId.setNodeValue(ocdID);\n                ocd.setAttributeNode(ocdAttrId);\n            }\n\n            if (ocdADs != null) {\n                for (AD ocdAD : ocdADs) {\n                    Element ad = this.marshallDoc.createElement(OCD_NAMESPACE + \":\" + METADATA_AD);\n                    marshallAD(ocdAD, ad);\n                    ocd.appendChild(ad);\n                }\n            }\n\n            if (ocdIcons != null) {\n                for (Icon ocdIcon : ocdIcons) {\n                    Element icon = this.marshallDoc.createElement(OCD_NAMESPACE + \":\" + METADATA_ICON);\n                    marshallIcon(ocdIcon, icon);\n                    ocd.appendChild(icon);\n                }\n            }\n            return ocd;\n        }\n        return null;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Override\n    public <T> T unmarshal(Document doc) {\n        Element metadata = doc.getDocumentElement();\n        Tmetadata tMetadata = parseMetadataAttributes(metadata);\n\n        NodeList metadataChilds = metadata.getChildNodes();\n        Element[] metadataChildsArray = getElementNodes(metadataChilds);\n\n        for (Element node : metadataChildsArray) {\n            String localName = node.getNodeName();\n            if (localName.equals(\"OCD\")) {\n                Tocd tocd = parseOCD(node);\n                tMetadata.setOCD(tocd);\n            } else if (localName.equals(\"Designate\")) {\n                Tdesignate tDesignate = parseDesignate(node);\n                tMetadata.setDesignate(tDesignate);\n            }\n        }\n\n        return (T) tMetadata;\n    }\n\n    //\n    // Private methods\n    //\n    private void marshallIcon(Icon ocdIcon, Element icon) {\n        String iconResource = ocdIcon.getResource();\n        BigInteger iconSize = ocdIcon.getSize();\n\n        if (iconResource != null && !iconResource.trim().isEmpty()) {\n            Attr attrResource = this.marshallDoc.createAttribute(METADATA_ICON_RESOURCE);\n            attrResource.setNodeValue(iconResource);\n            icon.setAttributeNode(attrResource);\n        }\n        if (iconSize != null) {\n            Attr attrSize = this.marshallDoc.createAttribute(METADATA_ICON_SIZE);\n            attrSize.setNodeValue(iconSize.toString());\n            icon.setAttributeNode(attrSize);\n        }\n    }\n\n    private void marshallAD(AD ocdAD, Element ad) {\n        String adId = ocdAD.getId();\n        String adName = ocdAD.getName();\n        Scalar adType = ocdAD.getType();\n        Integer adCardinality = ocdAD.getCardinality();\n        Boolean adRequired = ocdAD.isRequired();\n        String adDefault = ocdAD.getDefault();\n        String adDescription = ocdAD.getDescription();\n        String adMin = ocdAD.getMin();\n        String adMax = ocdAD.getMax();\n        List<Option> adOptions = ocdAD.getOption();\n\n        if (adName != null) {\n            Attr attrName = this.marshallDoc.createAttribute(METADATA_AD_NAME);\n            attrName.setNodeValue(adName);\n            ad.setAttributeNode(attrName);\n        }\n        if (adId != null) {\n            Attr attrId = this.marshallDoc.createAttribute(METADATA_AD_ID);\n            attrId.setNodeValue(adId);\n            ad.setAttributeNode(attrId);\n        }\n        if (adType != null) {\n            Attr attrType = this.marshallDoc.createAttribute(METADATA_AD_TYPE);\n            attrType.setNodeValue(adType.value());\n            ad.setAttributeNode(attrType);\n        }\n        if (adCardinality != null) {\n            Attr attrCardinality = this.marshallDoc.createAttribute(METADATA_AD_CARDINALITY);\n            attrCardinality.setNodeValue(adCardinality.toString());\n            ad.setAttributeNode(attrCardinality);\n        }\n        if (adRequired != null) {\n            Attr attrRequired = this.marshallDoc.createAttribute(METADATA_AD_REQUIRED);\n            attrRequired.setNodeValue(adRequired.toString());\n            ad.setAttributeNode(attrRequired);\n        }\n        if (adDefault != null) {\n            Attr attrDefault = this.marshallDoc.createAttribute(METADATA_AD_DEFAULT);\n            attrDefault.setNodeValue(adDefault);\n            ad.setAttributeNode(attrDefault);\n        }\n        if (adDescription != null) {\n            Attr attrDescription = this.marshallDoc.createAttribute(METADATA_AD_DESCRIPTION);\n            attrDescription.setNodeValue(adDescription);\n            ad.setAttributeNode(attrDescription);\n        }\n        if (adMin != null) {\n            Attr attrMin = this.marshallDoc.createAttribute(METADATA_AD_MIN);\n            attrMin.setNodeValue(adMin);\n            ad.setAttributeNode(attrMin);\n        }\n        if (adMax != null) {\n            Attr attrMax = this.marshallDoc.createAttribute(METADATA_AD_MAX);\n            attrMax.setNodeValue(adMax);\n            ad.setAttributeNode(attrMax);\n        }\n\n        if (adOptions != null) {\n            for (Option adOption : adOptions) {\n                Element option = this.marshallDoc.createElement(OCD_NAMESPACE + \":\" + METADATA_AD_OPTION);\n                marshallOption(adOption, option);\n                ad.appendChild(option);\n            }\n        }\n    }\n\n    private void marshallOption(Option adOption, Element option) {\n        String label = adOption.getLabel();\n        String value = adOption.getValue();\n\n        if (!label.trim().isEmpty()) {\n            Attr attrLabel = this.marshallDoc.createAttribute(METADATA_AD_OPTION_LABEL);\n            attrLabel.setNodeValue(label);\n            option.setAttributeNode(attrLabel);\n        }\n        if (!value.trim().isEmpty()) {\n            Attr attrValue = this.marshallDoc.createAttribute(METADATA_AD_OPTION_VALUE);\n            attrValue.setNodeValue(value);\n            option.setAttributeNode(attrValue);\n        }\n    }\n\n    private Tocd parseOCD(Element ocd) {\n        String ocdName = ocd.getAttribute(METADATA_OCD_NAME);\n        String ocdID = ocd.getAttribute(METADATA_OCD_ID);\n        String ocdDescription = ocd.getAttribute(METADATA_OCD_DESCRIPTION);\n        Tocd tocd = new Tocd();\n\n        if (ocdID != null && !ocdID.trim().isEmpty()) {\n            tocd.setId(ocdID);\n        }\n        if (ocdName != null && !ocdName.trim().isEmpty()) {\n            tocd.setName(ocdName);\n        }\n        if (ocdDescription != null && !ocdDescription.trim().isEmpty()) {\n            tocd.setDescription(ocdDescription);\n        }\n\n        NodeList ocdChilds = ocd.getChildNodes();\n        Element[] ocdChildElements = getElementNodes(ocdChilds);\n\n        for (Element node : ocdChildElements) {\n            String localName = node.getNodeName();\n            if (localName.equals(METADATA_ICON)) {\n                // parse Icon\n                Ticon tIcon = parseIcon(node);\n                tocd.setIcon(tIcon);\n            } else if (localName.equals(METADATA_AD)) {\n                // parse AD\n                Tad tad = parseAD(node);\n                tocd.addAD(tad);\n            }\n        }\n\n        return tocd;\n    }\n\n    private Tdesignate parseDesignate(Element designate) {\n        String pid = designate.getAttribute(METADATA_DESIGNATE_PID);\n        String factoryPid = designate.getAttribute(METADATA_DESIGNATE_FACTORY_PID);\n        String bundle = designate.getAttribute(METADATA_DESIGNATE_BUNDLE);\n        Boolean optional = Boolean.parseBoolean(designate.getAttribute(METADATA_DESIGNATE_OPTIONAL));\n        Boolean merge = Boolean.parseBoolean(designate.getAttribute(METADATA_DESIGNATE_MERGE));\n\n        Tdesignate tDesignate = new Tdesignate();\n        if (!pid.trim().isEmpty()) {\n            tDesignate.setPid(pid);\n        }\n        if (!factoryPid.trim().isEmpty()) {\n            tDesignate.setFactoryPid(factoryPid);\n        }\n        if (!bundle.trim().isEmpty()) {\n            tDesignate.setBundle(bundle);\n        }\n        tDesignate.setOptional(optional);\n        tDesignate.setMerge(merge);\n\n        NodeList objectsChilds = designate.getChildNodes();\n        Element[] objectsChildElements = getElementNodes(objectsChilds);\n\n        for (Element node : objectsChildElements) {\n            String localName = node.getNodeName();\n            if (localName.equals(METADATA_DESIGNATE_OBJECT)) {\n                // parse Object\n                Tobject tObject = parseObject(node);\n                tDesignate.setObject(tObject);\n            }\n        }\n\n        return tDesignate;\n    }\n\n    @SuppressWarnings(\"checkstyle:emptyBlock\")\n    private Tobject parseObject(Element object) {\n        String ocdref = object.getAttribute(METADATA_DESIGNATE_OBJECT_OCDREF);\n\n        Tobject tObject = new Tobject();\n        if (!ocdref.trim().isEmpty()) {\n            tObject.setOcdref(ocdref);\n        }\n\n        NodeList attributeChilds = object.getChildNodes();\n        Element[] attributeChildElements = getElementNodes(attributeChilds);\n        for (Element node : attributeChildElements) {\n            String localName = node.getNodeName();\n            if (localName.equals(METADATA_DESIGNATE_OBJECT_ATTRIBUTE)) {\n                // parse Attribute\n                // TODO\n            }\n        }\n\n        return tObject;\n    }\n\n    private Ticon parseIcon(Element icon) {\n        Ticon result = new Ticon();\n\n        String resource = icon.getAttribute(METADATA_ICON_RESOURCE);\n        if (resource != null && !resource.trim().isEmpty()) {\n            result.setResource(resource);\n        }\n\n        String iconSize = icon.getAttribute(METADATA_ICON_SIZE);\n        if (iconSize != null) {\n            try {\n                BigInteger size = new BigInteger(iconSize);\n                if (size.signum() >= 0) {\n                    result.setSize(size);\n                } else {\n                    result.setSize(new BigInteger(\"0\"));\n                }\n            } catch (NumberFormatException e) {\n                result.setSize(new BigInteger(\"0\"));\n            }\n        }\n\n        return result;\n    }\n\n    private Tad parseAD(Element adElement) {\n        Tad tad = new Tad();\n\n        String id = adElement.getAttribute(METADATA_AD_ID);\n        String name = adElement.getAttribute(METADATA_AD_NAME);\n        Tscalar type = Tscalar.fromValue(adElement.getAttribute(METADATA_AD_TYPE));\n        Integer cardinality;\n        try {\n            cardinality = Integer.parseInt(adElement.getAttribute(METADATA_AD_CARDINALITY));\n        } catch (NumberFormatException e) {\n            cardinality = null;\n        }\n\n        Boolean required = null;\n        String requiredAttr = adElement.getAttribute(METADATA_AD_REQUIRED);\n        if (requiredAttr != null && !requiredAttr.trim().isEmpty()) {\n            required = Boolean.parseBoolean(adElement.getAttribute(METADATA_AD_REQUIRED));\n        }\n\n        String defaultVal = adElement.getAttribute(METADATA_AD_DEFAULT);\n        String description = adElement.getAttribute(METADATA_AD_DESCRIPTION);\n        String min = adElement.getAttribute(METADATA_AD_MIN);\n        String max = adElement.getAttribute(METADATA_AD_MAX);\n\n        if (id != null && !id.trim().isEmpty()) {\n            tad.setId(id);\n        }\n        if (name != null && !name.trim().isEmpty()) {\n            tad.setName(name);\n        }\n\n        if (type != null) {\n            tad.setType(type);\n        }\n        if (cardinality != null) {\n            tad.setCardinality(cardinality);\n        }\n        if (required != null) {\n            tad.setRequired(required);\n        }\n\n        if (defaultVal != null && !defaultVal.trim().isEmpty()) {\n            tad.setDefault(defaultVal);\n        }\n        if (description != null && !description.trim().isEmpty()) {\n            tad.setDescription(description);\n        }\n        if (min != null && !min.trim().isEmpty()) {\n            tad.setMin(min);\n        }\n        if (max != null && !max.trim().isEmpty()) {\n            tad.setMax(max);\n        }\n\n        // parse Option\n        NodeList optionChilds = adElement.getChildNodes();\n        Element[] optionChildElements = getElementNodes(optionChilds);\n        for (Element node : optionChildElements) {\n            String localName = node.getNodeName();\n            if (localName.equals(METADATA_AD_OPTION)) {\n                // parse Option\n                Toption tOption = parseOption(node);\n                tad.setOption(tOption);\n            }\n        }\n\n        return tad;\n    }\n\n    private Toption parseOption(Element option) {\n        Toption tOption = new Toption();\n\n        String label = option.getAttribute(METADATA_AD_OPTION_LABEL);\n        String value = option.getAttribute(METADATA_AD_OPTION_VALUE);\n\n        if (label != null && !label.trim().isEmpty()) {\n            tOption.setLabel(label);\n        }\n        if (value != null && !value.trim().isEmpty()) {\n            tOption.setValue(value);\n        }\n        return tOption;\n    }\n\n    private Tmetadata parseMetadataAttributes(Element metadata) {\n        Tmetadata tMetadata = new Tmetadata();\n        String localization = metadata.getAttribute(METADATA_LOCALIZATION);\n\n        if (localization != null && !localization.trim().isEmpty()) {\n            tMetadata.setLocalization(localization);\n        }\n\n        return tMetadata;\n    }\n\n    private Element[] getElementNodes(NodeList propertiesList) {\n        List<Element> elementList = new ArrayList<>();\n        for (int propIndex = 0; propIndex < propertiesList.getLength(); propIndex++) {\n            Node currentNode = propertiesList.item(propIndex);\n            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {\n                Element el = (Element) currentNode;\n                elementList.add(el);\n            }\n        }\n        return elementList.toArray(new Element[0]);\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaPackagesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport org.eclipse.kura.core.inventory.resources.SystemBundle;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\npublic class XmlJavaPackagesMapper implements XmlJavaDataMapper {\n\n    private static final String PACKAGES = \"packages\";\n    private static final String PACKAGES_PACKAGE = \"package\";\n    private static final String PACKAGES_PACKAGE_NAME = \"name\";\n    private static final String PACKAGES_PACKAGE_VERSION = \"version\";\n    private static final String PACKAGES_PACKAGE_BUNDLES = \"bundles\";\n    private static final String PACKAGES_PACKAGE_BUNDLES_BUNDLE = \"bundle\";\n    private static final String PACKAGES_PACKAGE_BUNDLES_BUNDLE_NAME = \"name\";\n    private static final String PACKAGES_PACKAGE_BUNDLES_BUNDLE_VERSION = \"version\";\n\n    @Override\n    public Element marshal(Document doc, Object object) throws Exception {\n        Element packages = doc.createElement(PACKAGES);\n        doc.appendChild(packages);\n\n        SystemDeploymentPackages xdps = (SystemDeploymentPackages) object;\n        SystemDeploymentPackage[] xdpArray = xdps.getDeploymentPackages();\n\n        for (SystemDeploymentPackage xdp : xdpArray) {\n            Element packageInstalled = doc.createElement(PACKAGES_PACKAGE);\n            marshalDeploymentPackage(doc, xdp, packageInstalled);\n            packages.appendChild(packageInstalled);\n        }\n        return packages;\n    }\n\n    @Override\n    public <T> T unmarshal(Document doc) throws Exception {\n        return null;\n    }\n\n    //\n    // Marshaller's private methods\n    //\n    private static void marshalDeploymentPackage(Document doc, SystemDeploymentPackage xdp, Element packageInstalled) {\n        // Extract data from XmlDeploymentPackage\n        String packageName = xdp.getName();\n        String packageVersion = xdp.getVersion();\n        SystemBundle[] xbiArray = xdp.getBundleInfos();\n\n        // Create xml elements\n        if (packageName != null && !packageName.trim().isEmpty()) {\n            Element name = doc.createElement(PACKAGES_PACKAGE_NAME);\n            name.setTextContent(packageName);\n            packageInstalled.appendChild(name);\n        }\n\n        if (packageVersion != null && !packageVersion.trim().isEmpty()) {\n            Element version = doc.createElement(PACKAGES_PACKAGE_VERSION);\n            version.setTextContent(packageVersion);\n            packageInstalled.appendChild(version);\n        }\n\n        Element bundles = doc.createElement(PACKAGES_PACKAGE_BUNDLES);\n        packageInstalled.appendChild(bundles);\n\n        if (xbiArray != null) {\n            for (SystemBundle xbi : xbiArray) {\n                Element bundle = doc.createElement(PACKAGES_PACKAGE_BUNDLES_BUNDLE);\n                marshalBundleInfo(doc, xbi, bundle);\n                bundles.appendChild(bundle);\n            }\n        }\n    }\n\n    private static void marshalBundleInfo(Document doc, SystemBundle xbi, Element bundle) {\n        // Extract data from XmlBundleInfo\n        String bundleName = xbi.getName();\n        String bundleVersion = xbi.getVersion();\n\n        // Create xml elements\n        if (bundleName != null && !bundleName.trim().isEmpty()) {\n            Element name = doc.createElement(PACKAGES_PACKAGE_BUNDLES_BUNDLE_NAME);\n            name.setTextContent(bundleName);\n            bundle.appendChild(name);\n        }\n\n        if (bundleVersion != null && !bundleVersion.trim().isEmpty()) {\n            Element version = doc.createElement(PACKAGES_PACKAGE_BUNDLES_BUNDLE_VERSION);\n            version.setTextContent(bundleVersion);\n            bundle.appendChild(version);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaSnapshotIdResultMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport java.util.List;\n\nimport org.eclipse.kura.core.configuration.XmlSnapshotIdResult;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\npublic class XmlJavaSnapshotIdResultMapper implements XmlJavaDataMapper {\n\n    private static final String SNAPSHOT_IDS = \"snapshot-ids\";\n    private static final String SNAPSHOTIDS = \"snapshotIds\";\n\n    @Override\n    public Element marshal(Document doc, Object object) {\n        Element snapshotIDs = doc.createElement(ESF_NAMESPACE + \":\" + SNAPSHOT_IDS);\n        snapshotIDs.setAttributeNS(\"http://www.w3.org/2000/xmlns/\", \"xmlns:esf\", \"http://eurotech.com/esf/2.0\");\n        snapshotIDs.setAttributeNS(\"http://www.w3.org/2000/xmlns/\", \"xmlns:ocd\",\n                \"http://www.osgi.org/xmlns/metatype/v1.2.0\");\n        doc.appendChild(snapshotIDs);\n\n        XmlSnapshotIdResult xmlSnapshotIdResult = (XmlSnapshotIdResult) object;\n        List<Long> snapshotIdVals = xmlSnapshotIdResult.getSnapshotIds();\n\n        if (snapshotIdVals != null) {\n            for (Long snapId : snapshotIdVals) {\n                Element snapshotIds = doc.createElement(ESF_NAMESPACE + \":\" + SNAPSHOTIDS);\n                snapshotIds.setTextContent(snapId.toString());\n                snapshotIDs.appendChild(snapshotIds);\n            }\n        }\n\n        return snapshotIDs;\n    }\n\n    @Override\n    public <T> T unmarshal(Document doc) {\n        throw new IllegalArgumentException();\n    }\n\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaSystemPackagesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport java.util.List;\n\nimport org.eclipse.kura.core.inventory.resources.SystemPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemPackages;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\npublic class XmlJavaSystemPackagesMapper implements XmlJavaDataMapper {\n\n    private static final String SYSTEM_PACKAGES = \"systemPackages\";\n    private static final String SYSTEM_PACKAGES_PACKAGE = \"systemPackage\";\n    private static final String SYSTEM_PACKAGES_PACKAGE_NAME = \"name\";\n    private static final String SYSTEM_PACKAGES_PACKAGE_VERSION = \"version\";\n    private static final String SYSTEM_PACKAGES_PACKAGE_TYPE = \"type\";\n\n    @Override\n    public Element marshal(Document doc, Object object) throws Exception {\n        Element packages = doc.createElement(SYSTEM_PACKAGES);\n        doc.appendChild(packages);\n\n        SystemPackages xmlPackages = (SystemPackages) object;\n        List<SystemPackage> xmlPackagesList = xmlPackages.getSystemPackages();\n\n        xmlPackagesList.stream().forEach(xmlPackage -> {\n            Element p = doc.createElement(SYSTEM_PACKAGES_PACKAGE);\n            marshallPackage(doc, xmlPackage, p);\n            packages.appendChild(p);\n        });\n        return packages;\n    }\n\n    @Override\n    public <T> T unmarshal(Document doc) throws Exception {\n        return null;\n    }\n\n    //\n    // Marshaller's private methods\n    //\n    private static void marshallPackage(Document doc, SystemPackage systemPackage, Element p) {\n        // Extract data from XmlSystemPackage\n        String packageName = systemPackage.getName();\n        String packageVersion = systemPackage.getVersion();\n        String packageType = systemPackage.getTypeString();\n\n        // Create xml elements\n        if (packageName != null && !packageName.trim().isEmpty()) {\n            Element name = doc.createElement(SYSTEM_PACKAGES_PACKAGE_NAME);\n            name.setTextContent(packageName);\n            p.appendChild(name);\n        }\n\n        if (packageVersion != null && !packageVersion.trim().isEmpty()) {\n            Element version = doc.createElement(SYSTEM_PACKAGES_PACKAGE_VERSION);\n            version.setTextContent(packageVersion);\n            p.appendChild(version);\n        }\n\n        if (packageType != null && !packageType.trim().isEmpty()) {\n            Element type = doc.createElement(SYSTEM_PACKAGES_PACKAGE_TYPE);\n            type.setTextContent(packageType);\n            p.appendChild(type);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlJavaSystemResourcesMapper.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport java.util.List;\n\nimport org.eclipse.kura.core.inventory.resources.SystemResourcesInfo;\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\n\npublic class XmlJavaSystemResourcesMapper implements XmlJavaDataMapper {\n\n    private static final String SYSTEM_INVENTORY = \"inventory\";\n    private static final String SYSTEM_INVENTORY_RESOURCE = \"resource\";\n    private static final String SYSTEM_INVENTORY_RESOURCE_NAME = \"name\";\n    private static final String SYSTEM_INVENTORY_RESOURCE_VERSION = \"version\";\n    private static final String SYSTEM_INVENTORY_RESOURCE_TYPE = \"type\";\n\n    @Override\n    public Element marshal(Document doc, Object object) throws Exception {\n        Element inventory = doc.createElement(SYSTEM_INVENTORY);\n        doc.appendChild(inventory);\n\n        SystemResourcesInfo xmlInventory = (SystemResourcesInfo) object;\n        List<SystemResourceInfo> xmlResourceList = xmlInventory.getSystemResources();\n\n        xmlResourceList.stream().forEach(xmlResource -> {\n            Element p = doc.createElement(SYSTEM_INVENTORY_RESOURCE);\n            marshallResource(doc, xmlResource, p);\n            inventory.appendChild(p);\n        });\n        return inventory;\n    }\n\n    @Override\n    public <T> T unmarshal(Document doc) throws Exception {\n        return null;\n    }\n\n    //\n    // Marshaller's private methods\n    //\n    private static void marshallResource(Document doc, SystemResourceInfo systemResourceInfo, Element p) {\n        // Extract data from SystemResourceInfo\n        String resourceName = systemResourceInfo.getName();\n        String resourceVersion = systemResourceInfo.getVersion();\n        String resourceType = systemResourceInfo.getTypeString();\n\n        // Create xml elements\n        if (resourceName != null && !resourceName.trim().isEmpty()) {\n            Element name = doc.createElement(SYSTEM_INVENTORY_RESOURCE_NAME);\n            name.setTextContent(resourceName);\n            p.appendChild(name);\n        }\n\n        if (resourceVersion != null && !resourceVersion.trim().isEmpty()) {\n            Element version = doc.createElement(SYSTEM_INVENTORY_RESOURCE_VERSION);\n            version.setTextContent(resourceVersion);\n            p.appendChild(version);\n        }\n\n        if (resourceType != null && !resourceType.trim().isEmpty()) {\n            Element type = doc.createElement(SYSTEM_INVENTORY_RESOURCE_TYPE);\n            type.setTextContent(resourceType);\n            p.appendChild(type);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/org.eclipse.kura.xml.marshaller.unmarshaller.provider/src/main/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/XmlMarshallUnmarshallImpl.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.StringWriter;\nimport java.nio.charset.StandardCharsets;\n\nimport javax.xml.XMLConstants;\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.stream.FactoryConfigurationError;\nimport javax.xml.transform.OutputKeys;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerException;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.dom.DOMSource;\nimport javax.xml.transform.stream.StreamResult;\n\nimport org.apache.commons.io.input.CharSequenceInputStream;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.metatype.MetaData;\nimport org.eclipse.kura.core.configuration.XmlComponentConfigurations;\nimport org.eclipse.kura.core.configuration.XmlSnapshotIdResult;\nimport org.eclipse.kura.core.configuration.metatype.Tmetadata;\nimport org.eclipse.kura.core.inventory.resources.ContainerImages;\nimport org.eclipse.kura.core.inventory.resources.DockerContainers;\nimport org.eclipse.kura.core.inventory.resources.SystemBundles;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemResourcesInfo;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.w3c.dom.Document;\nimport org.xml.sax.SAXException;\n\npublic class XmlMarshallUnmarshallImpl implements Marshaller, Unmarshaller {\n\n    private static final Logger logger = LoggerFactory.getLogger(XmlMarshallUnmarshallImpl.class);\n    private static final String VALUE_CONSTANT = \"value\";\n\n    @Override\n    public String marshal(Object object) throws KuraException {\n        StringWriter sw = new StringWriter();\n        try {\n            marshal(object, new StreamResult(sw));\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, VALUE_CONSTANT);\n        }\n        return sw.toString();\n    }\n\n    @Override\n    public void marshal(OutputStream out, Object object) throws KuraException {\n        try {\n            marshal(object, new StreamResult(new OutputStreamWriter(out, StandardCharsets.UTF_8)));\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.ENCODE_ERROR, VALUE_CONSTANT);\n        }\n\n    }\n\n    private void marshal(Object object, StreamResult streamResult) throws Exception {\n        try {\n            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();\n            docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);\n            docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, \"\");\n            docFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, \"\");\n            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();\n\n            // root elements\n            Document doc = docBuilder.newDocument();\n            doc.setXmlStandalone(true);\n\n            if (object instanceof XmlSnapshotIdResult) {\n                // Resulting xml:\n                // <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n                // <esf:snapshot-ids xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\"\n                // xmlns:esf=\"http://eurotech.com/esf/2.0\">\n                // <esf:snapshotIds>1434122113492</esf:snapshotIds>\n                // <esf:snapshotIds>1434122124387</esf:snapshotIds>\n                // </esf:snapshot-ids>\n\n                new XmlJavaSnapshotIdResultMapper().marshal(doc, object);\n\n            } else if (object instanceof XmlComponentConfigurations) {\n                new XmlJavaComponentConfigurationsMapper().marshal(doc, object);\n            } else if (object instanceof SystemDeploymentPackages) {\n                // Expected resulting xml:\n                // <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n                // <packages>\n                // <package>\n                // <name>org.eclipse.kura.demo.heater</name>\n                // <version>1.2.0.qualifier</version>\n                // <bundles>\n                // <bundle>\n                // <name>org.eclipse.kura.demo.heater</name>\n                // <version>1.0.1</version>\n                // </bundle>\n                // </bundles>\n                // </package>\n                // </packages>\n\n                new XmlJavaPackagesMapper().marshal(doc, object);\n\n            } else if (object instanceof SystemBundles) {\n                // Expected resulting xml:\n                // <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n                // <bundles>\n                // <bundle>\n                // <name>org.eclipse.osgi</name>\n                // <version>3.8.1.v20120830-144521</version>\n                // <id>0</id>\n                // <state>ACTIVE</state>\n                // </bundle>\n                // </bundles>\n\n                new XmlJavaBundlesMapper().marshal(doc, object);\n\n            } else if (object instanceof SystemPackages) {\n                // Expected resulting xml:\n                // <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n                // <systemPackages>\n                // <systemPackage>\n                // <name>rfkill</name>\n                // <version>2.33.1-0.1</version>\n                // <type>DEB</type>\n                // </systemPackage>\n                // </systemPackages>\n\n                new XmlJavaSystemPackagesMapper().marshal(doc, object);\n\n            } else if (object instanceof SystemResourcesInfo) {\n                // Expected resulting xml:\n                // <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n                // <inventory>\n                // <resource>\n                // <name>rfkill</name>\n                // <version>2.33.1-0.1</version>\n                // <type>DEB</type>\n                // </resource>\n                // </inventory>\n\n                new XmlJavaSystemResourcesMapper().marshal(doc, object);\n            } else if (object instanceof DockerContainers) {\n                // Expected resulting xml:\n                // <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n                // <inventory>\n                // <resource>\n                // <name>example_container</name>\n                // <version>imageName:imagetag</version>\n                // <type>DOCKER</type>\n                // </resource>\n                // </inventory>\n\n                new XmlJavaDockerContainersMapper().marshal(doc, object);\n            } else if (object instanceof ContainerImages) {\n                // Expected resulting xml:\n                // <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n                // <inventory>\n                // <resource>\n                // <name>example_image</name>\n                // <version>imagetag</version>\n                // <type>CONTAINER_IMAGE</type>\n                // </resource>\n                // </inventory>\n\n                new XmlJavaContainerImagesMapper().marshal(doc, object);\n            }\n\n            // write the content into xml file\n            TransformerFactory transformerFactory = TransformerFactory.newInstance();\n            transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);\n            transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, \"\");\n            transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, \"\");\n\n            Transformer transformer = transformerFactory.newTransformer();\n            transformer.setOutputProperty(OutputKeys.INDENT, \"yes\");\n            transformer.setOutputProperty(\"{http://xml.apache.org/xslt}indent-amount\", \"4\");\n            DOMSource source = new DOMSource(doc);\n\n            transformer.transform(source, streamResult);\n        } catch (ParserConfigurationException pce) {\n            logger.warn(\"Parser Exception\", pce);\n        } catch (TransformerException tfe) {\n            logger.warn(\"Transformer Exception\", tfe);\n        }\n    }\n\n    // un-marshalling\n    @Override\n    public <T> T unmarshal(String stringInput, Class<T> clazz) throws KuraException {\n        CharSequenceInputStream stream = CharSequenceInputStream.builder().setBufferSize(8192)\n                .setCharset(StandardCharsets.UTF_8).setCharSequence(stringInput).get();\n        return doUnmarshal(stream, clazz);\n    }\n\n    @Override\n    public <T> T unmarshal(InputStream inputStream, Class<T> clazz) throws KuraException {\n        return doUnmarshal(inputStream, clazz);\n    }\n\n    private <T> T doUnmarshal(InputStream inputStream, Class<T> clazz) throws KuraException {\n        DocumentBuilderFactory factory = null;\n        DocumentBuilder parser = null;\n\n        try {\n            factory = DocumentBuilderFactory.newInstance();\n            factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);\n            factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, \"\");\n            factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, \"\");\n            parser = factory.newDocumentBuilder();\n        } catch (FactoryConfigurationError fce) {\n            // The implementation is not available or cannot be instantiated\n            logger.error(\"Parser Factory configuration Error\");\n            throw fce;\n        } catch (ParserConfigurationException pce) {\n            // the parser cannot be created with the specified configuration\n            logger.error(\"Parser configuration exception\");\n            throw new FactoryConfigurationError(pce);\n        }\n\n        // parse the document\n        Document doc = null;\n        try {\n            doc = parser.parse(inputStream);\n            doc.getDocumentElement().normalize();\n        } catch (SAXException | IOException | IllegalArgumentException se) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_CONSTANT, se);\n        }\n\n        // identify the correct parser that has to execute\n        if (clazz.equals(XmlComponentConfigurations.class)) {\n            try {\n                // Snapshot parser\n                return new XmlJavaComponentConfigurationsMapper().unmarshal(doc);\n            } catch (Exception e) {\n                throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_CONSTANT, e);\n            }\n        } else if (clazz.equals(MetaData.class) || clazz.equals(Tmetadata.class)) {\n            // MetaData parser\n            return new XmlJavaMetadataMapper().unmarshal(doc);\n        } else {\n            throw new IllegalArgumentException(\"Class not supported!\");\n        }\n    }\n}\n"
  },
  {
    "path": "kura/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n     Red Hat Inc\n     Cavium\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>org.eclipse.kura</groupId>\n    <artifactId>kura</artifactId>\n    <version>6.0.0-SNAPSHOT</version>\n\n    <packaging>pom</packaging>\n\n    <modules>\n        <module>kura-pde-deps</module>\n        <module>target-definition</module>\n        <module>org.eclipse.kura.api</module>\n        <module>org.eclipse.kura.camel</module>\n        <module>org.eclipse.kura.camel.cloud.factory</module>\n        <module>org.eclipse.kura.camel.xml</module>\n        <module>org.eclipse.kura.core</module>\n        <module>org.eclipse.kura.core.certificates</module>\n        <module>org.eclipse.kura.core.keystore</module>\n        <module>org.eclipse.kura.cloud.base.provider</module>\n        <module>org.eclipse.kura.core.cloud.factory</module>\n        <module>org.eclipse.kura.core.comm</module>\n        <module>org.eclipse.kura.core.configuration</module>\n        <module>org.eclipse.kura.core.crypto</module>\n        <module>org.eclipse.kura.core.identity</module>\n        <module>org.eclipse.kura.core.inventory</module>\n        <module>org.eclipse.kura.core.status</module>\n        <module>org.eclipse.kura.core.system</module>\n        <module>org.eclipse.kura.driver.helper.provider</module>\n        <module>org.eclipse.kura.driver.block</module>\n        <module>org.eclipse.kura.driver.s7plc.provider</module>\n        <module>org.eclipse.kura.linux.clock</module>\n        <module>org.eclipse.kura.linux.usb</module>\n        <module>org.eclipse.kura.linux.usb.x86_64</module>\n        <module>org.eclipse.kura.linux.usb.aarch64</module>\n        <module>org.eclipse.kura.linux.watchdog</module>\n        <module>org.eclipse.kura.protocol.modbus</module>\n        <module>org.eclipse.kura.stress</module>\n        <module>org.eclipse.kura.util</module>\n        <module>org.eclipse.kura.wire.camel</module>\n        <module>org.eclipse.kura.rest.provider</module>\n        <module>org.eclipse.kura.misc.cloudcat</module>\n        <module>org.eclipse.kura.json.marshaller.unmarshaller.provider</module>\n        <module>org.eclipse.kura.xml.marshaller.unmarshaller.provider</module>\n        <module>org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider</module>\n        <module>org.eclipse.kura.cloudconnection.raw.mqtt.provider</module>\n        <module>org.eclipse.kura.http.server.manager</module>\n        <module>org.eclipse.kura.useradmin.store</module>\n        <module>org.eclipse.kura.rest.tamper.detection.provider</module>\n        <module>org.eclipse.kura.log.filesystem.provider</module>\n        <module>org.eclipse.kura.rest.cloudconnection.provider</module>\n        <module>org.eclipse.kura.rest.configuration.provider</module>\n        <module>org.eclipse.kura.rest.identity.provider</module>\n        <module>org.eclipse.kura.rest.inventory.provider</module>\n        <module>org.eclipse.kura.rest.keystore.provider</module>\n        <module>org.eclipse.kura.rest.security.provider</module>\n        <module>org.eclipse.kura.rest.service.listing.provider</module>\n        <module>org.eclipse.kura.rest.system.provider</module>\n        <module>org.eclipse.kura.request.handler.jaxrs</module>\n        <module>org.eclipse.kura.container.orchestration.provider</module>\n        <module>org.eclipse.kura.container.provider</module>\n        <module>org.eclipse.kura.event.publisher</module>\n        <module>org.eclipse.kura.configuration.change.manager</module>\n        <module>org.eclipse.kura.db.sqlite.provider</module>\n        <module>org.eclipse.kura.db.h2db.provider</module>\n        <module>org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider</module>\n        <module>org.eclipse.kura.cloudconnection.kapua.mqtt.provider</module>\n        <module>org.eclipse.kura.jul.to.slf4j.configuration</module>\n        <module>emulator</module>\n        <module>test-util</module>\n        <module>tools</module>\n    </modules>\n\n    <properties>\n        <!-- SCM: Note that we are in the \"kura\" sub-dir here already -->\n        <tycho.scmUrl>scm:git:ssh://github.com/eclipse/kura/kura</tycho.scmUrl>\n        <tycho-version>5.0.2</tycho-version>\n        <osgi-dp-plugin-version>0.3.0</osgi-dp-plugin-version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>\n        <kura.basedir>${project.basedir}</kura.basedir>\n        <kura.build.version>${maven.build.timestamp}</kura.build.version>\n        <bnd.baseline.continueOnError>false</bnd.baseline.continueOnError>\n        <check.plugins.exist.remote>false</check.plugins.exist.remote>\n        <kura.addons.url>https://artifactory.dev.everyware.io/artifactory/kura-addons</kura.addons.url>\n\n        <maven.compiler.release>21</maven.compiler.release>\n\n        <bnd.baseline.version>6.3.1</bnd.baseline.version>\n        <exists-maven-plugin.version>0.0.3</exists-maven-plugin.version>\n        <findbugs-maven-plugin.version>3.0.5</findbugs-maven-plugin.version>\n        <jacoco.version>0.8.13</jacoco.version>\n        <lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>\n        <license-maven-plugin.version>2.2</license-maven-plugin.version>\n        <maven-antrun-plugin.version>1.8</maven-antrun-plugin.version>\n        <maven-compiler-plugin.version>3.15.0</maven-compiler-plugin.version>\n        <maven-checkstyle-plugin.version>3.1.0</maven-checkstyle-plugin.version>\n        <maven-deploy-plugin.version>3.0.0</maven-deploy-plugin.version>\n        <maven-site-plugin.version>3.3</maven-site-plugin.version>\n        <maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>\n        <maven-clean-plugin.version>3.2.0</maven-clean-plugin.version>\n        <slf4j.version>1.7.36</slf4j.version>\n        <wagon-ssh.version>1.0-beta-6</wagon-ssh.version>\n        <properties-maven-plugin.version>1.2.1</properties-maven-plugin.version>\n        <bnd.version>7.1.0</bnd.version>\n\n        <!-- external dependencies, embedded in some bundles that are not available in target platform -->\n        <org.eclipse.paho.client.mqttv3.version>1.2.1</org.eclipse.paho.client.mqttv3.version>\n        <perfmark-api.version>0.26.0</perfmark-api.version>\n        <protobuf.version>4.30.2</protobuf.version>\n        <docker-java.version>3.5.3</docker-java.version>\n        <httpcore5.version>5.3.4</httpcore5.version>\n        <jna.version>5.17.0</jna.version>\n        <commons-compress.version>1.27.1</commons-compress.version>\n        <commons-codec.version>1.18.0</commons-codec.version>\n        <httpclient5.version>5.5</httpclient5.version>\n    </properties>\n\n    <distributionManagement>\n        <repository>\n            <id>repo.eclipse.org</id>\n            <name>Eclipse Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </repository>\n        <snapshotRepository>\n            <id>repo.eclipse.org</id>\n            <name>Eclipse Kura Repository - Snapshots</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </snapshotRepository>\n    </distributionManagement>\n\n    <dependencyManagement>\n        <dependencies>\n            <!--\n            External dependencies, embedded in some bundles that are not available in target platform.\n            Excluding all the transitive dependencies since we are declaring all the required ones explicitly.\n            -->\n            <dependency>\n                <groupId>org.eclipse.paho</groupId>\n                <artifactId>org.eclipse.paho.client.mqttv3</artifactId>\n                <version>${org.eclipse.paho.client.mqttv3.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>com.google.protobuf</groupId>\n                <artifactId>protobuf-java</artifactId>\n                <version>${protobuf.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>com.google.protobuf</groupId>\n                <artifactId>protobuf-java-util</artifactId>\n                <version>${protobuf.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>com.github.docker-java</groupId>\n                <artifactId>docker-java</artifactId>\n                <version>${docker-java.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>com.github.docker-java</groupId>\n                <artifactId>docker-java-core</artifactId>\n                <version>${docker-java.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>com.github.docker-java</groupId>\n                <artifactId>docker-java-api</artifactId>\n                <version>${docker-java.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>com.github.docker-java</groupId>\n                <artifactId>docker-java-transport</artifactId>\n                <version>${docker-java.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>com.github.docker-java</groupId>\n                <artifactId>docker-java-transport-httpclient5</artifactId>\n                <version>${docker-java.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.httpcomponents.client5</groupId>\n                <artifactId>httpclient5</artifactId>\n                <version>${httpclient5.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.httpcomponents.core5</groupId>\n                <artifactId>httpcore5</artifactId>\n                <version>${httpcore5.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.httpcomponents.core5</groupId>\n                <artifactId>httpcore5-h2</artifactId>\n                <version>${httpcore5.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>net.java.dev.jna</groupId>\n                <artifactId>jna</artifactId>\n                <version>${jna.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-compress</artifactId>\n                <version>${commons-compress.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>commons-codec</groupId>\n                <artifactId>commons-codec</artifactId>\n                <version>${commons-codec.version}</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>*</groupId>\n                        <artifactId>*</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n\n            <!-- Kura BOM -->\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.api</artifactId>\n                <version>3.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.camel</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.camel.cloud.factory</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.camel.xml</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.cloud.base.provider</artifactId>\n                <version>1.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.cloudconnection.kapua.mqtt.provider</artifactId>\n                <version>1.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.cloudconnection.raw.mqtt.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.configuration.change.manager</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.container.orchestration.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.container.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.certificates</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.cloud.factory</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.comm</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.configuration</artifactId>\n                <version>3.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.crypto</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.identity</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.inventory</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.keystore</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.status</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.system</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.tamper.detection.provider</artifactId>\n                <version>1.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.db.h2db.provider</artifactId>\n                <version>1.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.db.sqlite.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.driver.block</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.driver.helper.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.driver.s7plc.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.emulator</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.emulator.clock</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.emulator.gpio</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.emulator.net</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.emulator.position</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.emulator.usb</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.emulator.watchdog</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.event.publisher</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.http.server.manager</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.json.marshaller.unmarshaller.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.linux.clock</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.linux.usb</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.linux.usb.aarch64</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.linux.usb.x86_64</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.linux.watchdog</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.log.filesystem.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.misc.cloudcat</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.protocol.modbus</artifactId>\n                <version>3.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.request.handler.jaxrs</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.cloudconnection.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.configuration.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.identity.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.inventory.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.keystore.provider</artifactId>\n                <version>1.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.security.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.service.listing.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.rest.system.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.stress</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.useradmin.store</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.util</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.wire.camel</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.xml.marshaller.unmarshaller.provider</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.jul.to.slf4j.configuration</artifactId>\n                <version>1.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.core.testutil</artifactId>\n                <version>6.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.test</artifactId>\n                <version>6.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.util.test.driver</artifactId>\n                <version>6.0.0-SNAPSHOT</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <profiles>\n        <profile>\n            <id>javadocs</id>\n            <activation>\n                <activeByDefault>false</activeByDefault>\n            </activation>\n            <modules>\n                <module>org.eclipse.kura.docs</module>\n            </modules>\n        </profile>\n        <profile>\n            <id>bree</id>\n            <build>\n                <plugins>\n                    <plugin>\n                        <groupId>org.eclipse.tycho</groupId>\n                        <artifactId>tycho-compiler-plugin</artifactId>\n                        <version>${tycho-version}</version>\n                        <configuration>\n                            <useJDK>BREE</useJDK>\n                        </configuration>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n        <profile>\n            <id>tools</id>\n            <activation>\n                <activeByDefault>false</activeByDefault>\n            </activation>\n            <modules>\n                <module>tools</module>\n            </modules>\n        </profile>\n        <profile>\n            <id>tests</id>\n            <activation>\n                <property>\n                    <name>!skipTests</name>\n                </property>\n            </activation>\n            <modules>\n                <module>test</module>\n            </modules>\n        </profile>\n        <profile>\n            <id>check-exists-plugin</id>\n            <properties>\n                <check.plugins.exist.remote>true</check.plugins.exist.remote>\n            </properties>\n        </profile>\n    </profiles>\n\n    <repositories>\n        <repository>\n            <id>license-feature</id>\n            <url>https://download.eclipse.org/cbi/updates/license/</url>\n            <layout>p2</layout>\n        </repository>\n        <repository>\n            <id>kura_addons</id>\n            <name>Eclipse Kura Addons Maven Repository</name>\n            <url>${kura.addons.url}</url>\n            <snapshots>\n                <enabled>true</enabled>\n                <updatePolicy>always</updatePolicy>\n            </snapshots>\n        </repository>\n        <!--\n            See Github issue #1755\n            https://github.com/bndtools/bnd/issues/1755\n        -->\n        <repository>\n            <id>repo.eclipse.org.releases</id>\n            <name>Eclipse Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </repository>\n\n        <repository>\n            <id>repo.eclipse.org.snapshot</id>\n            <name>Eclipse Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </repository>\n    </repositories>\n\n    <build>\n        <extensions>\n            <extension>\n                <groupId>org.apache.maven.wagon</groupId>\n                <artifactId>wagon-ssh</artifactId>\n                <version>${wagon-ssh.version}</version>\n            </extension>\n        </extensions>\n\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <version>${maven-checkstyle-plugin.version}</version>\n                <dependencies>\n                    <dependency>\n                        <groupId>org.slf4j</groupId>\n                        <artifactId>jcl-over-slf4j</artifactId>\n                        <version>${slf4j.version}</version>\n                    </dependency>\n                    <dependency>\n                        <groupId>org.slf4j</groupId>\n                        <artifactId>slf4j-jdk14</artifactId>\n                        <version>${slf4j.version}</version>\n                    </dependency>\n                </dependencies>\n                <executions>\n                    <execution>\n                        <id>checkstyle-validation</id>\n                        <phase>process-sources</phase>\n                        <configuration>\n                            <encoding>UTF-8</encoding>\n                            <consoleOutput>true</consoleOutput>\n                            <failsOnError>true</failsOnError>\n                            <linkXRef>false</linkXRef>\n                            <configLocation>../checkstyle_checks.xml</configLocation>\n                            <suppressionsLocation>../suppressions.xml</suppressionsLocation>\n                        </configuration>\n                        <goals>\n                            <goal>check</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>${maven-compiler-plugin.version}</version>\n                <configuration>\n                    <release>${maven.compiler.release}</release>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>findbugs-maven-plugin</artifactId>\n                <version>${findbugs-maven-plugin.version}</version>\n                <configuration>\n                    <findbugsXmlOutput>true</findbugsXmlOutput>\n                    <findbugsXmlWithMessages>true</findbugsXmlWithMessages>\n                    <xmlOutput>true</xmlOutput>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-deploy-plugin</artifactId>\n                <version>${maven-deploy-plugin.version}</version>\n                <configuration>\n                    <skip>false</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-maven-plugin</artifactId>\n                <version>${tycho-version}</version>\n                <extensions>true</extensions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-packaging-plugin</artifactId>\n                <configuration>\n                    <sourceReferences>\n                        <generate>true</generate>\n                    </sourceReferences>\n                </configuration>\n                <dependencies>\n                    <dependency>\n                        <groupId>org.eclipse.tycho.extras</groupId>\n                        <artifactId>tycho-sourceref-jgit</artifactId>\n                        <version>${tycho-version}</version>\n                    </dependency>\n                </dependencies>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-compiler-plugin</artifactId>\n                <version>${tycho-version}</version>\n                <configuration>\n                    <!-- make us aware of warnings -->\n                    <showWarnings>true</showWarnings>\n                    <!-- Kura does not set bootdelegation, we let the compiler check for this -->\n                    <requireJavaPackageImports>true</requireJavaPackageImports>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-source-plugin</artifactId>\n                <version>${tycho-version}</version>\n                <executions>\n                    <execution>\n                        <id>plugin-source</id>\n                        <goals>\n                            <goal>plugin-source</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-site-plugin</artifactId>\n                <version>${maven-site-plugin.version}</version>\n            </plugin>\n            <plugin>\n                <!-- license:format to add license:check to check -->\n                <groupId>com.mycila</groupId>\n                <artifactId>license-maven-plugin</artifactId>\n                <version>${license-maven-plugin.version}</version>\n                <configuration>\n                    <header>distrib/eclipse_license.txt</header>\n                    <properties>\n                        <owner>Eurotech and/or its affiliates</owner>\n                        <contributor>Eurotech</contributor>\n                        <dates>2011, 2014</dates>\n                    </properties>\n                    <includes>\n                        <include>**/*.java</include>\n                        <include>**/*.properties</include>\n                        <include>**/*.sh</include>\n                        <include>**/*.xml</include>\n                        <include>**/denali.css</include>\n                        <include>**/.conf</include>\n                    </includes>\n                    <mapping>\n                        <conf>SCRIPT_STYLE</conf>\n                    </mapping>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <version>${maven-antrun-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>verify-jdeps</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <exportAntProperties>true</exportAntProperties>\n                            <target name=\"verify.jdeps\">\n                                <available file=\"jdeps\" filepath=\"${env.PATH}\"\n                                    property=\"jdeps.present\" />\n                            </target>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.honton.chas</groupId>\n                <artifactId>exists-maven-plugin</artifactId>\n                <version>${exists-maven-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>remote</goal>\n                        </goals>\n                        <configuration>\n                            <skipIfSnapshot>true</skipIfSnapshot>\n                            <failIfExists>${check.plugins.exist.remote}</failIfExists>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>target-platform-configuration</artifactId>\n                    <version>${tycho-version}</version>\n                    <configuration>\n                        <environments>\n                            <environment>\n                                <os>win32</os>\n                                <ws>win32</ws>\n                                <arch>x86</arch>\n                            </environment>\n                            <environment>\n                                <os>linux</os>\n                                <ws>gtk</ws>\n                                <arch>x86</arch>\n                            </environment>\n                        </environments>\n                        <target>\n                            <artifact>\n                                <groupId>org.eclipse.kura</groupId>\n                                <artifactId>target-definition</artifactId>\n                                <version>6.0.0-SNAPSHOT</version>\n                            </artifact>\n                        </target>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-packaging-plugin</artifactId>\n                    <version>${tycho-version}</version>\n                    <configuration>\n                        <strictVersions>true</strictVersions>\n                        <format>${kura.build.version}</format>\n                        <skipPomGeneration>true</skipPomGeneration>\n                        <deriveHeaderFromSource>false</deriveHeaderFromSource>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>biz.aQute.bnd</groupId>\n                    <artifactId>bnd-maven-plugin</artifactId>\n                    <version>${bnd.version}</version>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>bnd-process</goal>\n                            </goals>\n                            <configuration>\n                                <packagingTypes>eclipse-plugin,eclipse-test-plugin</packagingTypes>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>biz.aQute.bnd</groupId>\n                    <artifactId>bnd-baseline-maven-plugin</artifactId>\n                    <version>${bnd.baseline.version}</version>\n                    <configuration>\n                        <continueOnError>${bnd.baseline.continueOnError}</continueOnError>\n                        <fullReport>true</fullReport>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <id>baseline</id>\n                            <goals>\n                                <goal>baseline</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>org.jacoco</groupId>\n                    <artifactId>jacoco-maven-plugin</artifactId>\n                    <version>${jacoco.version}</version>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>prepare-agent</goal>\n                            </goals>\n                        </execution>\n                        <execution>\n                            <id>report</id>\n                            <phase>verify</phase>\n                            <goals>\n                                <goal>report-aggregate</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-clean-plugin</artifactId>\n                    <version>${maven-clean-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-surefire-plugin</artifactId>\n                    <version>${tycho-version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-surefire-plugin</artifactId>\n                    <version>${maven-surefire-plugin.version}</version>\n                </plugin>\n\n                <!-- This plugin's configuration is used to store Eclipse m2e settings only. It has\n                no influence on the Maven build itself. -->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>${lifecycle-mapping.version}</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>biz.aQute.bnd</groupId>\n                                        <artifactId>bnd-maven-plugin</artifactId>\n                                        <versionRange>[0.0.0,)</versionRange>\n                                        <goals>\n                                            <goal>bnd-process</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore />\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.jacoco</groupId>\n                                        <artifactId>jacoco-maven-plugin</artifactId>\n                                        <versionRange>[0.6.4.201312101107,)</versionRange>\n                                        <goals>\n                                            <goal>prepare-agent</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.apache.maven.plugins</groupId>\n                                        <artifactId>maven-dependency-plugin</artifactId>\n                                        <versionRange>[2.1,)</versionRange>\n                                        <goals>\n                                            <goal>copy-dependencies</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.apache.maven.plugins</groupId>\n                                        <artifactId>maven-antrun-plugin</artifactId>\n                                        <versionRange>[1.7,)</versionRange>\n                                        <goals>\n                                            <goal>run</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore />\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.codehaus.mojo</groupId>\n                                        <artifactId>build-helper-maven-plugin</artifactId>\n                                        <versionRange>[1.9,)</versionRange>\n                                        <goals>\n                                            <goal>regex-property</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.apache.maven.plugins</groupId>\n                                        <artifactId>maven-checkstyle-plugin</artifactId>\n                                        <versionRange>[2.14,)</versionRange>\n                                        <goals>\n                                            <goal>check</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.codehaus.mojo</groupId>\n                                        <artifactId>exec-maven-plugin</artifactId>\n                                        <versionRange>[1.2,)</versionRange>\n                                        <goals>\n                                            <goal>exec</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>org.codehaus.mojo</groupId>\n                                        <artifactId>properties-maven-plugin</artifactId>\n                                        <versionRange>[1.2.1,)</versionRange>\n                                        <goals>\n                                            <goal>read-project-properties</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/setups/formatting/KuraCleanupProfile.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<profiles version=\"2\">\n<profile kind=\"CleanUpProfile\" name=\"KuraCleanup_v3\" version=\"2\">\n<setting id=\"cleanup.qualify_static_method_accesses_with_declaring_class\" value=\"false\"/>\n<setting id=\"cleanup.always_use_this_for_non_static_method_access\" value=\"false\"/>\n<setting id=\"cleanup.organize_imports\" value=\"true\"/>\n<setting id=\"cleanup.remove_trailing_whitespaces_ignore_empty\" value=\"false\"/>\n<setting id=\"cleanup.format_source_code_changes_only\" value=\"false\"/>\n<setting id=\"cleanup.qualify_static_field_accesses_with_declaring_class\" value=\"false\"/>\n<setting id=\"cleanup.add_generated_serial_version_id\" value=\"true\"/>\n<setting id=\"cleanup.remove_redundant_semicolons\" value=\"true\"/>\n<setting id=\"cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class\" value=\"true\"/>\n<setting id=\"cleanup.remove_redundant_type_arguments\" value=\"true\"/>\n<setting id=\"cleanup.remove_unused_imports\" value=\"true\"/>\n<setting id=\"cleanup.insert_inferred_type_arguments\" value=\"false\"/>\n<setting id=\"cleanup.make_private_fields_final\" value=\"true\"/>\n<setting id=\"cleanup.use_lambda\" value=\"true\"/>\n<setting id=\"cleanup.always_use_blocks\" value=\"true\"/>\n<setting id=\"cleanup.use_this_for_non_static_field_access_only_if_necessary\" value=\"false\"/>\n<setting id=\"cleanup.sort_members_all\" value=\"false\"/>\n<setting id=\"cleanup.remove_trailing_whitespaces_all\" value=\"true\"/>\n<setting id=\"cleanup.add_missing_annotations\" value=\"true\"/>\n<setting id=\"cleanup.always_use_this_for_non_static_field_access\" value=\"true\"/>\n<setting id=\"cleanup.make_parameters_final\" value=\"false\"/>\n<setting id=\"cleanup.sort_members\" value=\"false\"/>\n<setting id=\"cleanup.remove_private_constructors\" value=\"true\"/>\n<setting id=\"cleanup.always_use_parentheses_in_expressions\" value=\"false\"/>\n<setting id=\"cleanup.remove_unused_local_variables\" value=\"true\"/>\n<setting id=\"cleanup.convert_to_enhanced_for_loop\" value=\"true\"/>\n<setting id=\"cleanup.remove_unused_private_fields\" value=\"true\"/>\n<setting id=\"cleanup.remove_redundant_modifiers\" value=\"false\"/>\n<setting id=\"cleanup.never_use_blocks\" value=\"false\"/>\n<setting id=\"cleanup.add_missing_deprecated_annotations\" value=\"true\"/>\n<setting id=\"cleanup.use_this_for_non_static_field_access\" value=\"true\"/>\n<setting id=\"cleanup.remove_unnecessary_nls_tags\" value=\"true\"/>\n<setting id=\"cleanup.qualify_static_member_accesses_through_instances_with_declaring_class\" value=\"true\"/>\n<setting id=\"cleanup.add_missing_nls_tags\" value=\"false\"/>\n<setting id=\"cleanup.remove_unnecessary_casts\" value=\"true\"/>\n<setting id=\"cleanup.use_blocks_only_for_return_and_throw\" value=\"false\"/>\n<setting id=\"cleanup.format_source_code\" value=\"true\"/>\n<setting id=\"cleanup.convert_functional_interfaces\" value=\"true\"/>\n<setting id=\"cleanup.add_default_serial_version_id\" value=\"false\"/>\n<setting id=\"cleanup.remove_unused_private_methods\" value=\"true\"/>\n<setting id=\"cleanup.remove_trailing_whitespaces\" value=\"true\"/>\n<setting id=\"cleanup.make_type_abstract_if_missing_method\" value=\"false\"/>\n<setting id=\"cleanup.add_serial_version_id\" value=\"true\"/>\n<setting id=\"cleanup.use_this_for_non_static_method_access\" value=\"true\"/>\n<setting id=\"cleanup.use_this_for_non_static_method_access_only_if_necessary\" value=\"true\"/>\n<setting id=\"cleanup.use_anonymous_class_creation\" value=\"false\"/>\n<setting id=\"cleanup.add_missing_override_annotations_interface_methods\" value=\"true\"/>\n<setting id=\"cleanup.remove_unused_private_members\" value=\"false\"/>\n<setting id=\"cleanup.make_local_variable_final\" value=\"false\"/>\n<setting id=\"cleanup.add_missing_methods\" value=\"true\"/>\n<setting id=\"cleanup.never_use_parentheses_in_expressions\" value=\"true\"/>\n<setting id=\"cleanup.qualify_static_member_accesses_with_declaring_class\" value=\"true\"/>\n<setting id=\"cleanup.use_parentheses_in_expressions\" value=\"true\"/>\n<setting id=\"cleanup.add_missing_override_annotations\" value=\"true\"/>\n<setting id=\"cleanup.use_blocks\" value=\"true\"/>\n<setting id=\"cleanup.make_variable_declarations_final\" value=\"true\"/>\n<setting id=\"cleanup.correct_indentation\" value=\"true\"/>\n<setting id=\"cleanup.remove_unused_private_types\" value=\"true\"/>\n</profile>\n</profiles>\n"
  },
  {
    "path": "kura/setups/formatting/KuraFormatter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<profiles version=\"16\">\n<profile kind=\"CodeFormatterProfile\" name=\"Kura_formatter_v_3\" version=\"16\">\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_ellipsis\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_logical_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_imports\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_javadoc_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indentation.size\" value=\"4\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.align_with_spaces\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.disabling_tag\" value=\"@formatter:off\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation\" value=\"2\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_enum_constants\" value=\"49\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_imports\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_package\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.indent_root_tags\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.enabling_tag\" value=\"@formatter:on\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_logical_operator\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_block\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.line_length\" value=\"120\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.use_on_off_tags\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_method_body_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_method_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_additive_operator\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_relational_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_shift_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_lambda_body\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.compact_else_if\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_type_parameters\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_compact_loops\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_relational_operator\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_unary_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_ellipsis\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_additive_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_line_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.align_type_members_on_columns\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_assignment\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_module_statements\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_conditional_expression\" value=\"80\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block_in_case\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_header\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_additive_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_method_declaration\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.join_wrapped_lines\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_conditional_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_shift_operator\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines\" value=\"2147483647\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_resources_in_try\" value=\"80\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_code_block_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.tabulation.size\" value=\"4\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_source_code\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_field\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer\" value=\"2\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_method\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_assignment_operator\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_switch\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_html\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_compact_if\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_empty_lines\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_type_arguments\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_unary_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_label\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_member_type\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_logical_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_relational_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_block_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.indent_tag_description\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_string_concatenation\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_body\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_multiple_fields\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_array_initializer\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_logical_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_shift_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration\" value=\"common_lines\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_shift_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line\" value=\"one_line_never\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_constant\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_package\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_additive_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.join_lines_in_comments\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.indent_parameter_description\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.tabulation.char\" value=\"space\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_relational_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_string_concatenation\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_import_groups\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.lineSplit\" value=\"120\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch\" value=\"insert\"/>\n</profile>\n</profiles>\n"
  },
  {
    "path": "kura/setups/kura.setup",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<setup:Project\n    xmi:version=\"2.0\"\n    xmlns:xmi=\"http://www.omg.org/XMI\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xmlns:git=\"http://www.eclipse.org/oomph/setup/git/1.0\"\n    xmlns:jdt=\"http://www.eclipse.org/oomph/setup/jdt/1.0\"\n    xmlns:launching=\"http://www.eclipse.org/oomph/setup/launching/1.0\"\n    xmlns:maven=\"http://www.eclipse.org/oomph/setup/maven/1.0\"\n    xmlns:predicates=\"http://www.eclipse.org/oomph/predicates/1.0\"\n    xmlns:projects=\"http://www.eclipse.org/oomph/setup/projects/1.0\"\n    xmlns:resources=\"http://www.eclipse.org/oomph/resources/1.0\"\n    xmlns:setup=\"http://www.eclipse.org/oomph/setup/1.0\"\n    xmlns:setup.p2=\"http://www.eclipse.org/oomph/setup/p2/1.0\"\n    xmlns:setup.targlets=\"http://www.eclipse.org/oomph/setup/targlets/1.0\"\n    xmlns:setup.workingsets=\"http://www.eclipse.org/oomph/setup/workingsets/1.0\"\n    xsi:schemaLocation=\"http://www.eclipse.org/oomph/setup/git/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/Git.ecore http://www.eclipse.org/oomph/setup/jdt/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/JDT.ecore http://www.eclipse.org/oomph/setup/launching/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/Launching.ecore http://www.eclipse.org/oomph/setup/maven/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/Maven.ecore http://www.eclipse.org/oomph/predicates/1.0 https://raw.githubusercontent.com/eclipse-oomph/oomph/master/setups/models/Predicates.ecore http://www.eclipse.org/oomph/setup/projects/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/Projects.ecore http://www.eclipse.org/oomph/resources/1.0 https://raw.githubusercontent.com/eclipse-oomph/oomph/master/setups/models/Resources.ecore http://www.eclipse.org/oomph/setup/targlets/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/SetupTarglets.ecore http://www.eclipse.org/oomph/setup/workingsets/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/SetupWorkingSets.ecore\"\n    name=\"iot.kura\"\n    label=\"Eclipse Kura\">\n  <setupTask\n      xsi:type=\"setup:VariableTask\"\n      name=\"eclipse.target.platform\"\n      value=\"Neon\"/>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"Choose developer type\">\n    <setupTask\n        xsi:type=\"setup:VariableTask\"\n        name=\"kura.developer.type\"\n        storageURI=\"scope://Workspace\"\n        label=\"Developer Type\">\n      <choice\n          value=\"developer\"\n          label=\"Developer\"/>\n      <description>Select which type of developer for Kura you are</description>\n    </setupTask>\n    <setupTask\n        xsi:type=\"setup:EclipseIniTask\"\n        option=\"-Dkura.developer.type=\"\n        value=\"${kura.developer.type}\"\n        vm=\"true\"/>\n  </setupTask>\n  <setupTask\n      xsi:type=\"jdt:JRETask\"\n      version=\"JavaSE-1.8\"\n      location=\"${jre.location-1.8}\">\n    <description>Define the JRE needed to compile and run the Java projects of ${scope.project.label}</description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:EclipseIniTask\"\n      excludedTriggers=\"STARTUP\"\n      option=\"-Xmx\"\n      value=\"1024m\"\n      vm=\"true\">\n    <description>Set the heap space needed to work with the projects of ${scope.project.label}</description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:ResourceCreationTask\"\n      excludedTriggers=\"STARTUP MANUAL\"\n      targetURL=\"${workspace.location|uri}/.metadata/.plugins/org.eclipse.jdt.ui/dialog_settings.xml\"\n      encoding=\"UTF-8\">\n    <description>Initialize JDT's package explorer to show working sets as its root objects</description>\n    <content>\n      &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?>\n      &lt;section name=&quot;Workbench&quot;>\n      \t&lt;section name=&quot;org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart&quot;>\n      \t\t&lt;item value=&quot;true&quot; key=&quot;group_libraries&quot;/>\n      \t\t&lt;item value=&quot;false&quot; key=&quot;linkWithEditor&quot;/>\n      \t\t&lt;item value=&quot;2&quot; key=&quot;layout&quot;/>\n      \t\t&lt;item value=&quot;2&quot; key=&quot;rootMode&quot;/>\n      \t\t&lt;item value=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;packageExplorer configured=&amp;quot;true&amp;quot; group_libraries=&amp;quot;1&amp;quot; layout=&amp;quot;2&amp;quot; linkWithEditor=&amp;quot;0&amp;quot; rootMode=&amp;quot;2&amp;quot; sortWorkingSets=&amp;quot;false&amp;quot; workingSetName=&amp;quot;&amp;quot;&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;localWorkingSetManager&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;workingSet editPageId=&amp;quot;org.eclipse.jdt.internal.ui.OthersWorkingSet&amp;quot; factoryID=&amp;quot;org.eclipse.ui.internal.WorkingSetFactory&amp;quot; id=&amp;quot;1382792884467_1&amp;quot; label=&amp;quot;Other Projects&amp;quot; name=&amp;quot;Other Projects&amp;quot;/&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;/localWorkingSetManager&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;activeWorkingSet workingSetName=&amp;quot;Other Projects&amp;quot;/&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;allWorkingSets workingSetName=&amp;quot;Other Projects&amp;quot;/&amp;gt;&amp;#x0D;&amp;#x0A;&amp;lt;/packageExplorer&amp;gt;&quot; key=&quot;memento&quot;/>\n      \t&lt;/section>\n      &lt;/section>\n\n    </content>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup.p2:P2Task\">\n    <requirement\n        name=\"org.eclipse.m2e.feature.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.m2e.wtp.feature.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.oomph.setup.projects.feature.group\"/>\n    <requirement\n        name=\"org.eclipse.egit.gitflow.feature.feature.group\"/>\n    <requirement\n        name=\"com.mountainminds.eclemma.feature.feature.group\"\n        optional=\"true\"/>\n    <requirement\n        name=\"org.sonarlint.eclipse.feature.feature.group\"\n        optional=\"true\"/>\n    <requirement\n        name=\"org.sonatype.tycho.m2e.feature.feature.group\" />\n    <repository\n        url=\"https://download.eclipse.org/eclemma/releases/3.1.6/\" />\n    <repository\n        url=\"https://eclipse-uc.sonarlint.org/\" />\n    <repository\n        url=\"https://github.com/tesla/m2eclipse-tycho/releases/download/latest/\" />\n\n    <description>Install the tools needed in the IDE to work with the source code for ${scope.project.label}</description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"git:GitCloneTask\"\n      id=\"git.clone\"\n      remoteURI=\"eclipse-kura/kura\">\n    <annotation\n        source=\"http://www.eclipse.org/oomph/setup/InducedChoices\">\n      <detail\n          key=\"inherit\">\n        <value>github.remoteURIs</value>\n      </detail>\n      <detail\n          key=\"label\">\n        <value>${scope.project.label} Git repository</value>\n      </detail>\n      <detail\n          key=\"target\">\n        <value>remoteURI</value>\n      </detail>\n    </annotation>\n    <description>${scope.project.label}</description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"Import Setup\">\n    <setupTask\n        xsi:type=\"projects:ProjectsImportTask\">\n      <sourceLocator\n          rootFolder=\"${git.clone.location}/kura/setups\">\n        <projectFactory\n            xsi:type=\"resources:EclipseProjectFactory\"/>\n      </sourceLocator>\n    </setupTask>\n    <description></description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"User Preferences\">\n    <setupTask\n        xsi:type=\"setup:CompoundTask\"\n        name=\"org.eclipse.jdt.ui\">\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/cleanup_profile\"\n          value=\"_KuraCleanup_v2\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/cleanup_settings_version\"\n          value=\"2\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/formatter_profile\"\n          value=\"_Kura_formatter_v_2\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/formatter_settings_version\"\n          value=\"12\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.cleanupprofiles\"\n          value=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?>&#xA;&lt;profiles version=&quot;2&quot;>&#xA;&lt;profile kind=&quot;CleanUpProfile&quot; name=&quot;KuraCleanup_v2&quot; version=&quot;2&quot;>&#xA;&lt;setting id=&quot;cleanup.format_source_code&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.convert_functional_interfaces&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.add_missing_annotations&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_this_for_non_static_method_access_only_if_necessary&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_unused_private_types&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.insert_inferred_type_arguments&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.qualify_static_member_accesses_through_instances_with_declaring_class&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.qualify_static_method_accesses_with_declaring_class&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.add_generated_serial_version_id&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.make_variable_declarations_final&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.add_missing_methods&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.always_use_this_for_non_static_field_access&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_type_arguments&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_trailing_whitespaces_ignore_empty&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.correct_indentation&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.never_use_parentheses_in_expressions&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.add_serial_version_id&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_unused_private_methods&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_this_for_non_static_field_access&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_blocks_only_for_return_and_throw&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_unused_private_members&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.add_missing_override_annotations_interface_methods&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_trailing_whitespaces_all&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.make_type_abstract_if_missing_method&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.always_use_this_for_non_static_method_access&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_unnecessary_nls_tags&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.format_source_code_changes_only&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.qualify_static_field_accesses_with_declaring_class&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.add_missing_nls_tags&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_this_for_non_static_field_access_only_if_necessary&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_unnecessary_casts&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.qualify_static_member_accesses_with_declaring_class&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_parentheses_in_expressions&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_unused_private_fields&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.make_parameters_final&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_redundant_type_arguments&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_trailing_whitespaces&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_unused_imports&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_anonymous_class_creation&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.organize_imports&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.sort_members&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_private_constructors&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.convert_to_enhanced_for_loop&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.always_use_blocks&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.never_use_blocks&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_lambda&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.always_use_parentheses_in_expressions&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_this_for_non_static_method_access&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.remove_unused_local_variables&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.make_private_fields_final&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.add_missing_deprecated_annotations&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.add_default_serial_version_id&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;cleanup.sort_members_all&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.use_blocks&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.add_missing_override_annotations&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;cleanup.make_local_variable_final&quot; value=&quot;false&quot;/>&#xA;&lt;/profile>&#xA;&lt;/profiles>&#xA;\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.cleanupprofiles.version\"\n          value=\"2\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/org.eclipse.jdt.ui.formatterprofiles\"\n          value=\"&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?>&#xA;&lt;profiles version=&quot;12&quot;>&#xA;&lt;profile kind=&quot;CodeFormatterProfile&quot; name=&quot;Kura_formatter_v_2&quot; version=&quot;12&quot;>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_ellipsis&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_after_imports&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.format_javadoc_comments&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indentation.size&quot; value=&quot;4&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.disabling_tag&quot; value=&quot;@formatter:off&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.continuation_indentation&quot; value=&quot;2&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_enum_constants&quot; value=&quot;49&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_before_imports&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_after_package&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_binary_operator&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant&quot; value=&quot;0&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.indent_root_tags&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.enabling_tag&quot; value=&quot;@formatter:on&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.compiler.problem.enumIdentifier&quot; value=&quot;error&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_statements_compare_to_block&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.line_length&quot; value=&quot;120&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.use_on_off_tags&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_method_declaration&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body&quot; value=&quot;0&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_binary_expression&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_block&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_lambda_body&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.compact_else_if&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.compiler.problem.assertIdentifier&quot; value=&quot;error&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_binary_operator&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_unary_operator&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_ellipsis&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.format_line_comments&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.align_type_members_on_columns&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_assignment&quot; value=&quot;0&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_conditional_expression&quot; value=&quot;80&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_block_in_case&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.format_header&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode&quot; value=&quot;enabled&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_method_declaration&quot; value=&quot;0&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.join_wrapped_lines&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_resources_in_try&quot; value=&quot;80&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.compiler.source&quot; value=&quot;1.8&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.tabulation.size&quot; value=&quot;4&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.format_source_code&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_before_field&quot; value=&quot;0&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer&quot; value=&quot;2&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_before_method&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.compiler.codegen.targetPlatform&quot; value=&quot;1.8&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_switch&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.format_html&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_compact_if&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_empty_lines&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_unary_operator&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation&quot; value=&quot;0&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_after_label&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_before_member_type&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_semicolon&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.format_block_comments&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_statements_compare_to_body&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.alignment_for_multiple_fields&quot; value=&quot;16&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_array_initializer&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.wrap_before_binary_operator&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.compiler.compliance&quot; value=&quot;1.8&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_enum_constant&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.brace_position_for_type_declaration&quot; value=&quot;end_of_line&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_before_package&quot; value=&quot;0&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.join_lines_in_comments&quot; value=&quot;false&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional&quot; value=&quot;insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.comment.indent_parameter_description&quot; value=&quot;true&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.tabulation.char&quot; value=&quot;space&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.blank_lines_between_import_groups&quot; value=&quot;1&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.lineSplit&quot; value=&quot;120&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation&quot; value=&quot;do not insert&quot;/>&#xA;&lt;setting id=&quot;org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch&quot; value=&quot;insert&quot;/>&#xA;&lt;/profile>&#xA;&lt;/profiles>&#xA;\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.add_default_serial_version_id\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.add_generated_serial_version_id\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.add_missing_annotations\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.add_missing_deprecated_annotations\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.add_missing_methods\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.add_missing_nls_tags\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.add_missing_override_annotations\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.add_missing_override_annotations_interface_methods\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.add_serial_version_id\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.always_use_blocks\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.always_use_parentheses_in_expressions\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.always_use_this_for_non_static_field_access\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.always_use_this_for_non_static_method_access\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.convert_functional_interfaces\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.convert_to_enhanced_for_loop\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.correct_indentation\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.format_source_code\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.format_source_code_changes_only\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.insert_inferred_type_arguments\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.make_local_variable_final\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.make_parameters_final\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.make_private_fields_final\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.make_type_abstract_if_missing_method\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.make_variable_declarations_final\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.never_use_blocks\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.never_use_parentheses_in_expressions\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.on_save_use_additional_actions\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.organize_imports\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.qualify_static_field_accesses_with_declaring_class\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.qualify_static_member_accesses_with_declaring_class\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.qualify_static_method_accesses_with_declaring_class\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_private_constructors\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_redundant_type_arguments\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_trailing_whitespaces\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_trailing_whitespaces_all\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_trailing_whitespaces_ignore_empty\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_unnecessary_casts\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_unnecessary_nls_tags\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_unused_imports\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_unused_local_variables\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_unused_private_fields\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_unused_private_members\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_unused_private_methods\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.remove_unused_private_types\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.sort_members\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.sort_members_all\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_anonymous_class_creation\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_blocks\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_blocks_only_for_return_and_throw\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_lambda\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_parentheses_in_expressions\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_this_for_non_static_field_access\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_this_for_non_static_field_access_only_if_necessary\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_this_for_non_static_method_access\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_this_for_non_static_method_access_only_if_necessary\"\n          value=\"true\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.jdt.ui/sp_cleanup.use_type_arguments\"\n          value=\"false\"/>\n    </setupTask>\n    <setupTask\n        xsi:type=\"setup:CompoundTask\"\n        name=\"org.eclipse.wst.xml.core\">\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.wst.xml.core/formatCommentText\"\n          value=\"false\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.wst.xml.core/indentationChar\"\n          value=\"space\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.wst.xml.core/indentationSize\"\n          value=\"4\"/>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.wst.xml.core/lineWidth\"\n          value=\"120\"/>\n    </setupTask>\n    <setupTask\n        xsi:type=\"setup:CompoundTask\"\n        name=\"org.eclipse.m2e.core\">\n      <setupTask\n          xsi:type=\"setup:ResourceCreationTask\"\n          targetURL=\"${workspace.location|uri}/.metadata/.plugins/org.eclipse.m2e.core/lifecycle-mapping-metadata.xml\"\n          encoding=\"UTF-8\">\n        <content>\n          &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?>\n          &lt;lifecycleMappingMetadata>\n              &lt;lifecycleMappingFilters>\n                  &lt;lifecycleMappingFilter>\n                      &lt;symbolicName>org.eclipse.m2e.pde.connector&lt;/symbolicName>\n                      &lt;versionRange>[2.1.2,)&lt;/versionRange>\n                      &lt;packagingTypes>\n                          &lt;packagingType>eclipse-test-plugin&lt;/packagingType>\n                          &lt;packagingType>eclipse-plugin&lt;/packagingType>\n                          &lt;packagingType>eclipse-feature&lt;/packagingType>\n                      &lt;/packagingTypes>\n                  &lt;/lifecycleMappingFilter>\n              &lt;/lifecycleMappingFilters>\n          &lt;/lifecycleMappingMetadata>\n        </content>\n      </setupTask>\n      <setupTask\n          xsi:type=\"setup:PreferenceTask\"\n          key=\"/instance/org.eclipse.m2e.core/eclipse.m2.WorkspacelifecycleMappingsLocation\"\n          value=\"${workspace.location}/.metadata/.plugins/org.eclipse.m2e.core/lifecycle-mapping-metadata.xml\"/>\n    </setupTask>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"Dependencies\">\n    <setupTask\n        xsi:type=\"setup:CompoundTask\"\n        name=\"target-platform\">\n      <setupTask\n          xsi:type=\"maven:MavenImportTask\">\n        <sourceLocator\n            rootFolder=\"${git.clone.location}/target-platform\">\n          <projectFactory\n              xsi:type=\"resources:MavenProjectFactory\"/>\n          <predicate\n              xsi:type=\"predicates:LocationPredicate\"\n              pattern=\".*/target-platform$\"/>\n        </sourceLocator>\n      </setupTask>\n      <setupTask\n          xsi:type=\"launching:LaunchTask\"\n          launcher=\"setups/launchers/build-target-platform.launch\"/>\n    </setupTask>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup.targlets:TargletTask\"\n      filter=\"\">\n    <targlet\n        name=\"${scope.project.label}\"\n        activeRepositoryList=\"${eclipse.target.platform}\"\n        includeAllPlatforms=\"true\">\n      <requirement\n          name=\"*\"/>\n      <dropinLocation\n          rootFolder=\"${git.clone.location}/target-platform/p2-repo-common/target/repository\"/>\n      <dropinLocation\n          rootFolder=\"${git.clone.location}/target-platform/p2-repo-equinox_3.16.0/target/repository\"/>\n      <dropinLocation\n          rootFolder=\"${git.clone.location}/target-platform/p2-repo-test-deps/target/repository\"/>\n      <dropinLocation\n          rootFolder=\"${git.clone.location}/target-platform/usb4java-javax/target\"\n          recursive=\"false\"/>\n      <dropinLocation\n          rootFolder=\"${git.clone.location}/target-platform/org.eclipse.soda.dk.comm/target\"\n          recursive=\"false\"/>\n    </targlet>\n    <description>Kura</description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup.workingsets:WorkingSetTask\">\n    <workingSet\n        name=\"${scope.project.label}\">\n      <predicate\n          xsi:type=\"predicates:AndPredicate\">\n        <operand\n            xsi:type=\"predicates:NamePredicate\"\n            pattern=\"org.eclipse.kura.*\"/>\n        <operand\n            xsi:type=\"predicates:NotPredicate\">\n          <operand\n              xsi:type=\"predicates:NamePredicate\"\n              pattern=\"org.eclipse.kura.*\\.test.*\"/>\n        </operand>\n        <operand\n            xsi:type=\"predicates:NotPredicate\">\n          <operand\n              xsi:type=\"predicates:NamePredicate\"\n              pattern=\"org.eclipse.kura.example.*\"/>\n        </operand>\n        <operand\n            xsi:type=\"predicates:NotPredicate\">\n          <operand\n              xsi:type=\"predicates:NamePredicate\"\n              pattern=\"org.eclipse.kura.demo.*\"/>\n        </operand>\n      </predicate>\n    </workingSet>\n    <workingSet\n        name=\"Karaf\">\n      <predicate\n          xsi:type=\"predicates:OrPredicate\">\n        <operand\n            xsi:type=\"predicates:LocationPredicate\"\n            pattern=\".*\\/karaf\\/.*\"/>\n        <operand\n            xsi:type=\"predicates:NamePredicate\"\n            pattern=\"karaf\"/>\n      </predicate>\n    </workingSet>\n    <workingSet\n        name=\"Target Platform\">\n      <predicate\n          xsi:type=\"predicates:OrPredicate\">\n        <operand\n            xsi:type=\"predicates:LocationPredicate\"\n            pattern=\".*/target-platform.*\"/>\n        <operand\n            xsi:type=\"predicates:LocationPredicate\"\n            pattern=\".*/target-definition.*\"/>\n      </predicate>\n    </workingSet>\n    <workingSet\n        name=\"Features\"\n        id=\"\">\n      <predicate\n          xsi:type=\"predicates:AndPredicate\">\n        <operand\n            xsi:type=\"predicates:OrPredicate\">\n          <operand\n              xsi:type=\"predicates:LocationPredicate\"\n              pattern=\".*/features/.*\"/>\n          <operand\n              xsi:type=\"predicates:NamePredicate\"\n              pattern=\".*\\.feature.*\"/>\n        </operand>\n        <operand\n            xsi:type=\"predicates:NotPredicate\">\n          <operand\n              xsi:type=\"predicates:LocationPredicate\"\n              pattern=\".*\\/karaf\\/.*\"/>\n        </operand>\n      </predicate>\n    </workingSet>\n    <workingSet\n        name=\"Tests\">\n      <predicate\n          xsi:type=\"predicates:OrPredicate\">\n        <operand\n            xsi:type=\"predicates:LocationPredicate\"\n            pattern=\".*/test/.*\"/>\n        <operand\n            xsi:type=\"predicates:NamePredicate\"\n            pattern=\"org.eclipse.kura.*\\.test.*\"/>\n      </predicate>\n    </workingSet>\n    <workingSet\n        name=\"Examples\">\n      <predicate\n          xsi:type=\"predicates:OrPredicate\">\n        <operand\n            xsi:type=\"predicates:LocationPredicate\"\n            pattern=\".*/examples/.*\"/>\n        <operand\n            xsi:type=\"predicates:NamePredicate\"\n            pattern=\"org.eclipse.kura.example.*\"/>\n        <operand\n            xsi:type=\"predicates:NamePredicate\"\n            pattern=\"org.eclipse.kura.demo.*\"/>\n      </predicate>\n    </workingSet>\n    <description>The dynamic working sets for ${scope.project.label}</description>\n  </setupTask>\n  <setupTask\n      xsi:type=\"setup:CompoundTask\"\n      name=\"Developer Type\">\n    <setupTask\n        xsi:type=\"setup:CompoundTask\"\n        filter=\"(kura.developer.type=user)\"\n        name=\"User\">\n      <setupTask\n          xsi:type=\"maven:MavenImportTask\">\n        <sourceLocator\n            rootFolder=\"${git.clone.location}/kura/org.eclipse.kura.api\"/>\n        <sourceLocator\n            rootFolder=\"${git.clone.location}/kura/emulator/org.eclipse.kura.emulator\"/>\n        <sourceLocator\n            rootFolder=\"${git.clone.location}/kura/examples/org.eclipse.kura.demo.heater\"/>\n      </setupTask>\n    </setupTask>\n    <setupTask\n        xsi:type=\"setup:CompoundTask\"\n        filter=\"(kura.developer.type=developer)\"\n        name=\"Developer\">\n      <setupTask\n          xsi:type=\"launching:LaunchTask\"\n          id=\"build-full\"\n          launcher=\"setups/launchers/build-full.launch\">\n        <description>Build Kura Core</description>\n      </setupTask>\n      <setupTask\n          xsi:type=\"maven:MavenImportTask\"\n          id=\"import.core\"\n          predecessor=\"build-full\"\n          projectNameTemplate=\"\">\n        <sourceLocator\n            rootFolder=\"${git.clone.location}/kura\"\n            locateNestedProjects=\"true\">\n          <predicate\n              xsi:type=\"predicates:AndPredicate\">\n            <operand\n                xsi:type=\"predicates:NotPredicate\">\n              <operand\n                  xsi:type=\"predicates:LocationPredicate\"\n                  pattern=\".*/org.eclipse.kura.windows.*\"/>\n            </operand>\n          </predicate>\n        </sourceLocator>\n        <sourceLocator\n            rootFolder=\"${git.clone.location}/karaf\"/>\n        <sourceLocator\n            rootFolder=\"${git.clone.location}/kura/examples\"\n            locateNestedProjects=\"true\"/>\n        <sourceLocator\n            rootFolder=\"${git.clone.location}/kura/features\"\n            locateNestedProjects=\"true\"/>\n      </setupTask>\n    </setupTask>\n  </setupTask>\n  <stream name=\"develop\"\n      label=\"Development\"/>\n  <logicalProjectContainer\n      xsi:type=\"setup:ProjectCatalog\"\n      href=\"index:/org.eclipse.setup#//@projectCatalogs[name='org.eclipse']\"/>\n  <description>Eclipse Kura provides cool stuff.</description>\n</setup:Project>\n"
  },
  {
    "path": "kura/setups/launchers/build-full.launch",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<launchConfiguration type=\"org.eclipse.m2e.Maven2LaunchConfigurationType\">\n<booleanAttribute key=\"M2_DEBUG_OUTPUT\" value=\"false\"/>\n<stringAttribute key=\"M2_GOALS\" value=\"-f pom.xml clean install\"/>\n<booleanAttribute key=\"M2_NON_RECURSIVE\" value=\"false\"/>\n<booleanAttribute key=\"M2_OFFLINE\" value=\"false\"/>\n<listAttribute key=\"M2_PROPERTIES\"/>\n<stringAttribute key=\"M2_RUNTIME\" value=\"EMBEDDED\"/>\n<booleanAttribute key=\"M2_SKIP_TESTS\" value=\"true\"/>\n<intAttribute key=\"M2_THREADS\" value=\"1\"/>\n<booleanAttribute key=\"M2_UPDATE_SNAPSHOTS\" value=\"false\"/>\n<stringAttribute key=\"M2_USER_SETTINGS\" value=\"\"/>\n<booleanAttribute key=\"M2_WORKSPACE_RESOLUTION\" value=\"false\"/>\n<stringAttribute key=\"org.eclipse.debug.core.ATTR_REFRESH_SCOPE\" value=\"${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/target-definition&quot; type=&quot;4&quot;/&gt;&#10;&lt;item path=&quot;/target-platform&quot; type=&quot;4&quot;/&gt;&#10;&lt;/resources&gt;}\"/>\n<stringAttribute key=\"org.eclipse.jdt.launching.JRE_CONTAINER\" value=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8\"/>\n<stringAttribute key=\"org.eclipse.jdt.launching.WORKING_DIRECTORY\" value=\"${project_loc:target-platform}/../kura\"/>\n</launchConfiguration>\n"
  },
  {
    "path": "kura/setups/launchers/build-target-platform.launch",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<launchConfiguration type=\"org.eclipse.m2e.Maven2LaunchConfigurationType\">\n<booleanAttribute key=\"M2_DEBUG_OUTPUT\" value=\"false\"/>\n<stringAttribute key=\"M2_GOALS\" value=\"clean install\"/>\n<booleanAttribute key=\"M2_NON_RECURSIVE\" value=\"false\"/>\n<booleanAttribute key=\"M2_OFFLINE\" value=\"false\"/>\n<stringAttribute key=\"M2_PROFILES\" value=\"\"/>\n<listAttribute key=\"M2_PROPERTIES\"/>\n<stringAttribute key=\"M2_RUNTIME\" value=\"EMBEDDED\"/>\n<booleanAttribute key=\"M2_SKIP_TESTS\" value=\"false\"/>\n<intAttribute key=\"M2_THREADS\" value=\"1\"/>\n<booleanAttribute key=\"M2_UPDATE_SNAPSHOTS\" value=\"false\"/>\n<stringAttribute key=\"M2_USER_SETTINGS\" value=\"\"/>\n<booleanAttribute key=\"M2_WORKSPACE_RESOLUTION\" value=\"false\"/>\n<stringAttribute key=\"org.eclipse.debug.core.ATTR_REFRESH_SCOPE\" value=\"${project}\"/>\n<stringAttribute key=\"org.eclipse.jdt.launching.JRE_CONTAINER\" value=\"org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8\"/>\n<stringAttribute key=\"org.eclipse.jdt.launching.WORKING_DIRECTORY\" value=\"${project_loc:target-platform}\"/>\n</launchConfiguration>\n"
  },
  {
    "path": "kura/setups/toolchains/toolchains-rhel7.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF8\"?>\n<!--\n  - RHEL based toolchain file:\n  -   sudo yum install java-1.6.0-openjdk-devel java-1.7.0-openjdk-devel java-1.8.0-openjdk-devel\n  -->\n<toolchains>\n\t<toolchain>\n\t\t<type>jdk</type>\n\t\t<provides>\n\t\t\t<version>1.6</version>\n\t\t\t<id>JavaSE-1.6</id>\n\t\t</provides>\n\t\t<configuration>\n\t\t\t<jdkHome>/usr/lib/jvm/java-1.6.0/jre</jdkHome>\n\t\t</configuration>\n\t</toolchain>\n\t<toolchain>\n\t\t<type>jdk</type>\n\t\t<provides>\n\t\t\t<version>1.7</version>\n\t\t\t<id>JavaSE-1.7</id>\n\t\t</provides>\n\t\t<configuration>\n\t\t\t<jdkHome>/usr/lib/jvm/java-1.7.0</jdkHome>\n\t\t</configuration>\n\t</toolchain>\n\t<toolchain>\n\t\t<type>jdk</type>\n\t\t<provides>\n\t\t\t<version>1.8</version>\n\t\t\t<id>JavaSE-1.8</id>\n\t\t</provides>\n\t\t<configuration>\n\t\t\t<jdkHome>/usr/lib/jvm/java-1.8.0</jdkHome>\n\t\t</configuration>\n\t</toolchain>\n</toolchains>\n"
  },
  {
    "path": "kura/setups/toolchains/toolchains-travis.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF8\"?>\n<!--\n  - Travis CI based toolchain file\n  -->\n<toolchains>\n\t<toolchain>\n\t\t<type>jdk</type>\n\t\t<provides>\n\t\t\t<version>1.6</version>\n\t\t\t<id>JavaSE-1.6</id>\n\t\t</provides>\n\t\t<configuration>\n\t\t\t<jdkHome>/usr/lib/jvm/java-6-openjdk-amd64/jre</jdkHome>\n\t\t</configuration>\n\t</toolchain>\n\t<toolchain>\n\t\t<type>jdk</type>\n\t\t<provides>\n\t\t\t<version>1.7</version>\n\t\t\t<id>JavaSE-1.7</id>\n\t\t</provides>\n\t\t<configuration>\n\t\t\t<jdkHome>/usr/lib/jvm/java-7-openjdk-amd64/jre</jdkHome>\n\t\t</configuration>\n\t</toolchain>\n\t<toolchain>\n\t\t<type>jdk</type>\n\t\t<provides>\n\t\t\t<version>1.8</version>\n\t\t\t<id>JavaSE-1.8</id>\n\t\t</provides>\n\t\t<configuration>\n\t\t\t<jdkHome>/usr/lib/jvm/java-8-oracle/jre</jdkHome>\n\t\t</configuration>\n\t</toolchain>\n</toolchains>\n"
  },
  {
    "path": "kura/target-definition/kura-equinox.target",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!--\n\n    Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<?pde version=\"3.8\"?>\n<target name=\"Kura Target Definition\" sequenceNumber=\"47\">\n    <locations>\n        <location includeDependencyDepth=\"direct\" includeDependencyScopes=\"compile,test\"\n            missingManifest=\"ignore\" type=\"Maven\">\n\n            <dependencies>\n                <dependency>\n                    <groupId>org.eclipse.kura</groupId>\n                    <artifactId>target-platform-pde-deps</artifactId>\n                    <version>6.0.0-SNAPSHOT</version>\n                    <type>pom</type>\n                </dependency>\n            </dependencies>\n\n            <repositories>\n                <repository>\n                    <id>eurotech-kura</id>\n                    <url>https://artifactory.dev.everyware.io/artifactory/kura-addons</url>\n                </repository>\n                <repository>\n                    <id>eclipse-releases</id>\n                    <url>https://repo.eclipse.org/content/groups/releases/</url>\n                </repository>\n                <repository>\n                    <id>kura-releases</id>\n                    <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n                </repository>\n                <repository>\n                    <id>central</id>\n                    <url>https://repo1.maven.org/maven2/</url>\n                </repository>\n                <repository>\n                    <id>jitpack.io</id>\n                    <url>https://jitpack.io</url>\n                </repository>\n            </repositories>\n        </location>\n    </locations>\n</target>"
  },
  {
    "path": "kura/target-definition/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    \n    <modelVersion>4.0.0</modelVersion>\n    \n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <groupId>org.eclipse.kura</groupId>\n    <artifactId>target-definition</artifactId>\n    <packaging>eclipse-target-definition</packaging>\n    <name>Kura Target Definition</name>\n    \n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n    </properties>\n    \n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-maven-plugin</artifactId>\n                <extensions>true</extensions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>initialize</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>run</goal>\n                        </goals>\n                        <configuration>\n                            <tasks>\n                                <echo\n                                    file=\"${project.basedir}/../distrib/build.properties\"\n                                    append=\"false\">kura.build.version=${kura.build.version}</echo>\n                            </tasks>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-site-plugin</artifactId>\n                <version>${maven-site-plugin.version}</version>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Unit tests for 'org.eclipse.kura.camel'\nBundle-SymbolicName: org.eclipse.kura.camel.test\nBundle-Version: 6.0.0.qualifier\nFragment-Host: org.eclipse.kura.camel;bundle-version=\"1.1.1\"\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: javax.activation,\n javax.xml.bind,\n org.apache.camel.component.mock;version=\"[2.17.2,3.0.0)\",\n org.apache.commons.io;version=\"[2.4.0,3.0.0)\",\n org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\nsource.. = src/main/java\noutput.. = target/classes\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright (c) 2016, 2024 Red Hat Inc and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n    Contributors:\n     Red Hat Inc\n     Eurotech\n     \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.camel.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/DependencyRunnerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.camel.runner.DependencyRunner;\nimport org.eclipse.kura.camel.runner.DependencyRunner.Listener;\nimport org.eclipse.kura.camel.runner.ServiceDependency;\nimport org.junit.Test;\n\npublic class DependencyRunnerTest {\n\n    private static class MockListener implements Listener<Map<String, Object>> {\n\n        public static class Event {\n\n            private final Map<String, Object> services;\n\n            public Event() {\n                this.services = null;\n            }\n\n            public Event(Map<String, Object> services) {\n                this.services = new HashMap<>(services);\n            }\n\n            public Map<String, Object> getServices() {\n                return this.services;\n            }\n        }\n\n        private final LinkedList<Event> events = new LinkedList<>();\n\n        @Override\n        public void ready(final List<ServiceDependency.Handle<Map<String, Object>>> dependencies) {\n            final Map<String, Object> services = new HashMap<>();\n\n            for (final ServiceDependency.Handle<Map<String, Object>> dep : dependencies) {\n                dep.consume(services);\n            }\n\n            System.out.println(\"Ready: \" + services);\n            this.events.add(new Event(services));\n        }\n\n        @Override\n        public void notReady() {\n            System.out.println(\"Not ready\");\n            this.events.add(new Event());\n        }\n\n        public LinkedList<Event> getEvents() {\n            return this.events;\n        }\n    }\n\n    private static class MockServiceDependency<T> implements ServiceDependency<T, Map<String, Object>> {\n\n        private class Handle implements ServiceDependency.Handle<Map<String, Object>> {\n\n            private final String name;\n\n            private T service;\n\n            private final Runnable listener;\n\n            public Handle(final String name, T service, Runnable listener) {\n                this.name = name;\n                this.service = service;\n                this.listener = listener;\n            }\n\n            public void setService(T service) {\n                this.service = service;\n\n                if (this.listener != null) {\n                    this.listener.run();\n                }\n            }\n\n            @Override\n            public void stop() {\n                MockServiceDependency.this.handles.remove(this);\n            }\n\n            @Override\n            public boolean isSatisfied() {\n                return this.service != null;\n            }\n\n            @Override\n            public void consume(Map<String, Object> context) {\n                context.put(this.name, this.service);\n            }\n\n        }\n\n        private final String name;\n\n        private T service;\n\n        private final List<MockServiceDependency<T>.Handle> handles = new LinkedList<>();\n\n        public MockServiceDependency(final String name) {\n            this.name = name;\n        }\n\n        public MockServiceDependency(final String name, final T service) {\n            this.name = name;\n            this.service = service;\n        }\n\n        @Override\n        public Handle start(final Runnable listener) {\n            final Handle handle = new Handle(this.name, this.service, listener);\n            this.handles.add(handle);\n            return handle;\n        }\n\n        public void setService(T service) {\n            this.service = service;\n            for (Handle handle : this.handles) {\n                handle.setService(service);\n            }\n        }\n    }\n\n    @Test\n    public void testEmpty1() {\n        final MockListener listener = new MockListener();\n        final DependencyRunner<Map<String, Object>> runner = new DependencyRunner<>(\n                Collections.<ServiceDependency<?, Map<String, Object>>> emptyList(), listener);\n\n        // no events yet\n\n        expectNoEvents(listener);\n\n        // start\n\n        runner.start();\n        expectEvent(listener, Collections.<String, Object> emptyMap());\n\n        // stop\n\n        runner.stop();\n        expectEvent(listener, null);\n\n        // nothing in addition\n\n        expectNoEvents(listener);\n    }\n\n    private static final Object A = new Object();\n    private static final Object B = new Object();\n    private static final Object C = new Object();\n\n    @Test\n    public void testSimple1() {\n        final MockListener listener = new MockListener();\n\n        final MockServiceDependency<Object> service1 = new MockServiceDependency<>(\"foo\", A);\n        final MockServiceDependency<Object> service2 = new MockServiceDependency<>(\"bar\", B);\n\n        Map<String, Object> all = new HashMap<>();\n        all.put(\"foo\", A);\n        all.put(\"bar\", B);\n\n        List<ServiceDependency<?, Map<String, Object>>> deps = new LinkedList<>();\n        deps.add(service1);\n        deps.add(service2);\n\n        final DependencyRunner<Map<String, Object>> runner = new DependencyRunner<>(deps, listener);\n\n        // no events yet\n\n        expectNoEvents(listener);\n\n        // start\n\n        runner.start();\n        expectEvent(listener, all);\n\n        // stop\n\n        runner.stop();\n        expectEvent(listener, null);\n\n        // nothing in addition\n\n        expectNoEvents(listener);\n    }\n\n    @Test\n    public void testSimple2() {\n        final MockListener listener = new MockListener();\n\n        final MockServiceDependency<Object> service1 = new MockServiceDependency<>(\"foo\");\n        final MockServiceDependency<Object> service2 = new MockServiceDependency<>(\"bar\");\n\n        Map<String, Object> all = new HashMap<>();\n        all.put(\"foo\", A);\n        all.put(\"bar\", B);\n\n        List<ServiceDependency<?, Map<String, Object>>> deps = new LinkedList<>();\n        deps.add(service1);\n        deps.add(service2);\n\n        final DependencyRunner<Map<String, Object>> runner = new DependencyRunner<>(deps, listener);\n\n        // no events yet\n\n        expectNoEvents(listener);\n\n        // start - but not ready\n\n        runner.start();\n        expectNoEvents(listener);\n\n        // set A - no event - no change\n        service1.setService(A);\n        expectNoEvents(listener);\n\n        // set B - change to ready - event\n        service2.setService(B);\n        expectEvent(listener, all);\n\n        // stop\n\n        runner.stop();\n        expectEvent(listener, null);\n\n        // nothing in addition\n\n        expectNoEvents(listener);\n    }\n\n    public void testRebind1() {\n        final MockListener listener = new MockListener();\n\n        final MockServiceDependency<Object> service1 = new MockServiceDependency<>(\"foo\");\n        final MockServiceDependency<Object> service2 = new MockServiceDependency<>(\"bar\");\n\n        Map<String, Object> all1 = new HashMap<>();\n        all1.put(\"foo\", A);\n        all1.put(\"bar\", B);\n\n        Map<String, Object> all2 = new HashMap<>();\n        all2.put(\"foo\", A);\n        all2.put(\"bar\", C);\n\n        List<ServiceDependency<?, Map<String, Object>>> deps = new LinkedList<>();\n        deps.add(service1);\n        deps.add(service2);\n\n        final DependencyRunner<Map<String, Object>> runner = new DependencyRunner<>(deps, listener);\n\n        // no events yet\n\n        expectNoEvents(listener);\n\n        // start - but not ready\n\n        runner.start();\n        expectNoEvents(listener);\n\n        // set A - no event - no change\n\n        service1.setService(A);\n        expectNoEvents(listener);\n\n        // set B - change to ready - event\n\n        service2.setService(B);\n        expectEvent(listener, all1);\n\n        // remove B\n\n        service2.setService(null);\n        expectEvent(listener, null);\n\n        // add C - change to ready - event\n\n        service2.setService(C);\n        expectEvent(listener, all2);\n\n        // stop\n\n        runner.stop();\n        expectEvent(listener, null);\n\n        // nothing in addition\n\n        expectNoEvents(listener);\n    }\n\n    private void expectNoEvents(MockListener listener) {\n        assertTrue(listener.getEvents().isEmpty());\n    }\n\n    private void expectEvent(final MockListener listener, final Map<String, Object> expectedServices) {\n        final MockListener.Event event = listener.getEvents().pollFirst();\n\n        assertNotNull(event);\n        assertEquals(expectedServices, event.getServices());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/component/AbstractRouterTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.component;\n\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.Route;\nimport org.apache.camel.component.mock.MockEndpoint;\nimport org.apache.commons.io.IOUtils;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.osgi.framework.FrameworkUtil;\n\n/**\n * Unit test base for testing an activated router\n */\npublic abstract class AbstractRouterTest {\n\n    private static final String XML_PROPERTY = \"xml.data\";\n    protected AbstractXmlCamelComponent router;\n\n    @Before\n    public void before() throws Exception {\n        this.router = createRouter();\n        this.router.activate(FrameworkUtil.getBundle(AbstractRouterTest.class).getBundleContext(),\n                Collections.<String, Object> emptyMap());\n    }\n\n    @After\n    public void after() throws Exception {\n        this.router.stop();\n    }\n\n    protected CamelContext getCamelContext() {\n        return this.router.getCamelContext();\n    }\n\n    protected Route firstRoute() {\n        return this.router.getCamelContext().getRoutes().iterator().next();\n    }\n\n    protected static Map<String, Object> xmlProperties(String resourceName) {\n        return Collections.<String, Object> singletonMap(XML_PROPERTY, readStringResource(resourceName));\n    }\n\n    protected static AbstractXmlCamelComponent createRouter() {\n        return new AbstractXmlCamelComponent(XML_PROPERTY) {\n        };\n    }\n\n    protected static String readStringResource(String resourceName) {\n        try (InputStreamReader reader = new InputStreamReader(RouterTest.class.getResourceAsStream(resourceName),\n                StandardCharsets.UTF_8)) {\n            return IOUtils.toString(reader);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Get a mock endpoint\n     * <br>\n     * <strong>Note:</strong> This call will fail if the endpoint is not of\n     * instance MockEndpoint.\n     */\n    protected MockEndpoint getMockEndpoint(String endpoint) {\n        return (MockEndpoint) this.router.getCamelContext().getEndpoint(endpoint);\n    }\n\n    /**\n     * Assert all mock endpoints\n     */\n    protected void assertMockEndpoints() throws InterruptedException {\n        MockEndpoint.assertIsSatisfied(this.router.getCamelContext());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/component/PayloadTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.component;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.util.Map;\n\nimport org.apache.camel.ProducerTemplate;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.junit.Test;\n\npublic class PayloadTest extends AbstractRouterTest {\n\n    @Test\n    public void test1() throws Exception {\n\n        // Given\n\n        final Map<String, Object> properties = xmlProperties(\"xml/payload1.xml\");\n\n        // Expect\n\n        getMockEndpoint(\"mock:foo-string\").expectedBodiesReceived(\"bar\");\n        getMockEndpoint(\"mock:foo-int\").expectedBodiesReceived(42);\n        getMockEndpoint(\"mock:foo-boolean\").expectedBodiesReceived(true);\n        \n        // When\n\n        this.router.modified(properties);\n\n        final ProducerTemplate pt = this.router.getCamelContext().createProducerTemplate();\n        pt.sendBody(\"direct:start\", createPayload1());\n\n        // Assert\n\n        assertEquals(1, this.router.getCamelContext().getRoutes().size());\n        assertMockEndpoints();\n    }\n\n    private KuraPayload createPayload1() {\n        final KuraPayload payload = new KuraPayload();\n\n        payload.addMetric(\"foo-string\", \"bar\");\n        payload.addMetric(\"foo-int\", 42);\n        payload.addMetric(\"foo-boolean\", true);\n\n        return payload;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/component/RouterTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.component;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.util.Collections;\nimport java.util.Map;\n\nimport org.junit.Test;\n\npublic class RouterTest extends AbstractRouterTest {\n\n    @Test\n    public void testLoadNothing() throws Exception {\n\n        // Given\n\n        final Map<String, Object> properties = Collections.emptyMap();\n\n        // When\n\n        this.router.modified(properties);\n\n        // Then\n\n        // expect no route\n        assertEquals(0, this.router.getCamelContext().getRoutes().size());\n    }\n\n    @Test\n    public void testLoadXmlOnce() throws Exception {\n\n        // Given\n\n        final Map<String, Object> properties = xmlProperties(\"xml/test1.xml\");\n\n        // When\n\n        this.router.modified(properties);\n\n        // Then\n\n        // expect one route\n        assertEquals(1, this.router.getCamelContext().getRoutes().size());\n\n        // with ID = test1\n        assertEquals(\"test1\", firstRoute().getId());\n    }\n\n    @Test\n    public void testLoadXmlTwice() throws Exception {\n\n        // Given\n\n        final Map<String, Object> properties = xmlProperties(\"xml/test1.xml\");\n\n        // When\n\n        this.router.modified(properties);\n        this.router.modified(properties);\n\n        // Then\n\n        // expect still one route\n        assertEquals(1, this.router.getCamelContext().getRoutes().size());\n\n        // with ID = test1\n        assertEquals(\"test1\", firstRoute().getId());\n    }\n\n    @Test\n    public void testLoadXmlUpdateSame() throws Exception {\n\n        // Given\n\n        final Map<String, Object> properties1 = xmlProperties(\"xml/test1.xml\");\n        final Map<String, Object> properties2 = xmlProperties(\"xml/test1a.xml\");\n\n        // When\n\n        this.router.modified(properties1);\n\n        // Then\n\n        // expect still one route\n        assertEquals(1, this.router.getCamelContext().getRoutes().size());\n        // with ID = test1\n        assertEquals(\"test1\", firstRoute().getId());\n\n        // When\n\n        this.router.modified(properties2);\n\n        // Then\n\n        // expect still one route\n        assertEquals(1, this.router.getCamelContext().getRoutes().size());\n        // with ID = test1\n        assertEquals(\"test1\", firstRoute().getId());\n    }\n\n    @Test\n    public void testLoadXmlUpdateOther() throws Exception {\n\n        // Given\n\n        final Map<String, Object> properties1 = xmlProperties(\"xml/test1.xml\");\n        final Map<String, Object> properties2 = xmlProperties(\"xml/test2.xml\");\n\n        // When ... load test1\n\n        this.router.modified(properties1);\n\n        // Then\n\n        // expect one route\n        assertEquals(1, this.router.getCamelContext().getRoutes().size());\n        // with ID = test1\n        assertEquals(\"test1\", firstRoute().getId());\n\n        // When ... update to test2\n\n        this.router.modified(properties2);\n\n        // Then\n\n        // expect still one route\n        assertEquals(1, this.router.getCamelContext().getRoutes().size());\n        // with ID = test2\n        assertEquals(\"test2\", firstRoute().getId());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/component/xml/payload1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<routes\n\txmlns=\"http://camel.apache.org/schema/spring\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.17.2.xsd\"\n\t>\n    <route> \n        <from uri=\"direct:start\"/>\n        <split>\n            <simple>${body.metrics().entrySet()}</simple>\n            <setHeader headerName=\"item\">\n                <simple>${body.key()}</simple>\n            </setHeader>\n            <setBody>\n                <simple>${body.value()}</simple>\n            </setBody>\n            <toD uri=\"mock:${header.item}\"/>\n        </split>\n    </route>\n</routes>"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/component/xml/test1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<routes\n\txmlns=\"http://camel.apache.org/schema/spring\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.17.2.xsd\"\n\t>\n\t<route id=\"test1\">\n\t\t<from uri=\"direct:start\" />\n\t\t<to uri=\"log:foo\" />\n\t</route>\n</routes>"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/component/xml/test1a.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<routes\n\txmlns=\"http://camel.apache.org/schema/spring\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.17.2.xsd\"\n\t>\n\t<route id=\"test1\">\n\t\t<from uri=\"direct:start\" />\n\t\t<to uri=\"log:foo2\" />\n\t</route>\n</routes>"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/component/xml/test2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<routes\n\txmlns=\"http://camel.apache.org/schema/spring\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.17.2.xsd\"\n\t>\n\t<route id=\"test2\">\n\t\t<from uri=\"direct:start2\" />\n\t\t<to uri=\"log:bar\" />\n\t</route>\n</routes>"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/runner/ScriptRunnerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.runner;\n\nimport javax.script.ScriptException;\nimport javax.script.SimpleBindings;\n\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class ScriptRunnerTest {\n\n    /**\n     * Test a simple call\n     */\n    @Test\n    public void testScript1() throws ScriptException {\n        final ScriptRunner runner = ScriptRunner.create(null, \"JavaScript\", \"42;\");\n\n        final Object result = runner.run();\n\n        Assert.assertTrue(result instanceof Number);\n        Assert.assertEquals(42.0, ((Number) result).doubleValue(),0.001);\n    }\n\n    /**\n     * Test a call with arguments\n     */\n    @Test\n    public void testScript2() throws ScriptException {\n        final ScriptRunner runner = ScriptRunner.create(null, \"JavaScript\", \"foo + 'bar';\");\n\n        SimpleBindings bindings = new SimpleBindings();\n        bindings.put(\"foo\", \"bar\");\n        final Object result = runner.run(bindings);\n\n        Assert.assertEquals(\"barbar\", result);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/main/java/org/eclipse/kura/camel/type/TypeConverterTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.camel.type;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.camel.component.AbstractRouterTest;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.type.TypedValue;\nimport org.eclipse.kura.type.TypedValues;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.junit.Test;\n\npublic class TypeConverterTest extends AbstractRouterTest {\n\n    private <T> T convertTo(Class<T> clazz, Object value) {\n        return getCamelContext().getTypeConverter().convertTo(clazz, value);\n    }\n\n    @Test\n    public void testFromMap() throws InterruptedException {\n        final KuraPayload result = convertTo(KuraPayload.class, Collections.singletonMap(\"foo\", \"bar\"));\n\n        assertNotNull(result);\n        assertNotNull(result.getTimestamp());\n\n        assertEquals(\"bar\", result.getMetric(\"foo\"));\n    }\n\n    @Test\n    public void testRecordToMap() {\n\n        final Map<?, ?> result = convertTo(Map.class, new WireRecord[] { createDefaultRecord() });\n\n        assertNotNull(result);\n        assertEquals(createDefaultRecordExpected(), result);\n\n    }\n\n    @Test\n    public void testRecordsToMap() {\n\n        final Map<?, ?> result = convertTo(Map.class, createDefaultRecord());\n\n        assertNotNull(result);\n        assertEquals(createDefaultRecordExpected(), result);\n\n    }\n\n    private WireRecord createDefaultRecord() {\n\n        final Map<String, TypedValue<?>> values = new HashMap<>();\n\n        values.put(\"FOO\", TypedValues.newTypedValue(\"bar\"));\n        values.put(\"BAR\", TypedValues.newTypedValue(42));\n\n        return new WireRecord(values);\n\n    }\n\n    private Map<String, Object> createDefaultRecordExpected() {\n\n        final Map<String, Object> expected = new HashMap<>();\n\n        expected.put(\"FOO\", \"bar\");\n        expected.put(\"BAR\", 42);\n\n        return expected;\n\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/test/java/org/eclipse/kura/camel/bean/PayloadFactoryTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.camel.bean;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.Date;\n\nimport org.eclipse.kura.camel.bean.PayloadFactory;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.junit.Test;\n\n\npublic class PayloadFactoryTest {\n\n    @Test\n    public void testCreateTimestamp() {\n        PayloadFactory pf = new PayloadFactory();\n\n        Date timestamp = new Date();\n\n        KuraPayload payload = pf.create(timestamp);\n\n        assertNotNull(payload);\n        assertNotNull(payload.getTimestamp());\n        assertEquals(timestamp, payload.getTimestamp());\n    }\n\n    @Test\n    public void testCreateKVP() {\n        PayloadFactory pf = new PayloadFactory();\n\n        String key = \"key\";\n        Object value = \"val\";\n\n        KuraPayload payload = pf.create(key, value);\n\n        assertNotNull(payload);\n        assertNotNull(payload.getTimestamp());\n        assertTrue(new Date().getTime() >= payload.getTimestamp().getTime());\n\n        Object metric = payload.getMetric(key);\n        assertNotNull(metric);\n        assertEquals(value, metric);\n    }\n\n    @Test\n    public void testAppendKVP() {\n        PayloadFactory pf = new PayloadFactory();\n\n        String key = \"key\";\n        Object value = \"val\";\n        KuraPayload payload = new KuraPayload();\n\n        KuraPayload payload2 = pf.append(payload, key, value);\n\n        assertNotNull(payload);\n        assertNotNull(payload2);\n        assertEquals(payload, payload2);\n        assertNull(payload.getTimestamp());\n\n        Object metric = payload.getMetric(key);\n        assertNotNull(metric);\n        assertEquals(value, metric);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/test/java/org/eclipse/kura/camel/camelcloud/DefaultCamelCloudServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.camel.camelcloud;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.ArgumentMatchers.anyInt;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.concurrent.ExecutorService;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.spi.ExecutorServiceManager;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.camel.internal.camelcloud.CamelCloudClient;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.junit.Test;\n\n/*\n * Unit test - no point in integration tests as it is not registered as a service.\n */\npublic class DefaultCamelCloudServiceTest {\n\n    @Test\n    public void testNewClientDefaultEndpointRelease() throws KuraException, NoSuchFieldException {\n        CamelContext camelContextMock = mock(CamelContext.class);\n        ExecutorServiceManager esmMock = mock(ExecutorServiceManager.class);\n        ExecutorService esMock = mock(ExecutorService.class);\n        when(esmMock.newThreadPool(any(), anyString(), anyInt(), anyInt())).thenReturn(esMock);\n        when(camelContextMock.getExecutorServiceManager()).thenReturn(esmMock);\n\n        DefaultCamelCloudService dccs = new DefaultCamelCloudService(camelContextMock);\n\n        String applicationId = \"app\";\n        CloudClient cloudClient = dccs.newCloudClient(applicationId);\n\n        assertNotNull(cloudClient);\n        assertTrue(cloudClient instanceof CamelCloudClient);\n        assertEquals(cloudClient.getApplicationId(), applicationId);\n\n        String endp = (String) TestUtil.getFieldValue(cloudClient, \"baseEndpoint\");\n        assertEquals(\"vm:%s\", endp);\n\n        // check registered clients\n        String[] identifiers = dccs.getCloudApplicationIdentifiers();\n        assertEquals(1, identifiers.length);\n        assertEquals(identifiers[0], applicationId);\n\n        // release\n        dccs.release(applicationId);\n\n        // check registered clients\n        identifiers = dccs.getCloudApplicationIdentifiers();\n        assertEquals(0, identifiers.length);\n\n        verify(esmMock, times(1)).shutdown(esMock);\n    }\n\n    @Test\n    public void testNewClientCustomEndpointDispose() throws KuraException, NoSuchFieldException {\n        CamelContext camelContextMock = mock(CamelContext.class);\n        ExecutorServiceManager esmMock = mock(ExecutorServiceManager.class);\n        ExecutorService esMock = mock(ExecutorService.class);\n        when(esmMock.newThreadPool(any(), anyString(), anyInt(), anyInt())).thenReturn(esMock);\n        when(camelContextMock.getExecutorServiceManager()).thenReturn(esmMock);\n\n        DefaultCamelCloudService dccs = new DefaultCamelCloudService(camelContextMock);\n\n        String applicationId = \"app\";\n\n        String endpoint = \"endpoint\";\n        dccs.registerBaseEndpoint(applicationId, endpoint);\n\n        CloudClient cloudClient = dccs.newCloudClient(applicationId);\n\n        assertNotNull(cloudClient);\n        assertTrue(cloudClient instanceof CamelCloudClient);\n        assertEquals(cloudClient.getApplicationId(), applicationId);\n\n        String endp = (String) TestUtil.getFieldValue(cloudClient, \"baseEndpoint\");\n        assertEquals(endpoint, endp);\n\n        // check registered clients\n        String[] identifiers = dccs.getCloudApplicationIdentifiers();\n        assertEquals(1, identifiers.length);\n        assertEquals(identifiers[0], applicationId);\n\n        // release all clients\n        dccs.dispose();\n\n        // check registered clients\n        identifiers = dccs.getCloudApplicationIdentifiers();\n        assertEquals(0, identifiers.length);\n\n        verify(esmMock, times(2)).shutdown(esMock); // one more time due to the recursive call\n    }\n\n    @Test\n    public void testNewClientDisposeError() throws KuraException, NoSuchFieldException {\n        CamelContext camelContextMock = mock(CamelContext.class);\n        ExecutorServiceManager esmMock = mock(ExecutorServiceManager.class);\n        ExecutorService esMock = mock(ExecutorService.class);\n        when(esmMock.newThreadPool(any(), anyString(), anyInt(), anyInt())).thenReturn(esMock);\n        doThrow(new RuntimeException(\"test\")).when(esmMock).shutdown(esMock);\n        when(camelContextMock.getExecutorServiceManager()).thenReturn(esmMock);\n\n        DefaultCamelCloudService dccs = new DefaultCamelCloudService(camelContextMock);\n\n        String applicationId = \"app\";\n\n        CloudClient cloudClient = dccs.newCloudClient(applicationId);\n\n        assertNotNull(cloudClient);\n        assertTrue(cloudClient instanceof CamelCloudClient);\n        assertEquals(cloudClient.getApplicationId(), applicationId);\n\n        // check registered clients\n        String[] identifiers = dccs.getCloudApplicationIdentifiers();\n        assertEquals(1, identifiers.length);\n        assertEquals(identifiers[0], applicationId);\n\n        // release all clients with exception\n        try {\n            dccs.dispose();\n            fail(\"Exception was expected.\");\n        } catch (RuntimeException e) {\n            assertNotNull(e.getCause());\n            assertEquals(\"test\", e.getCause().getMessage());\n        }\n\n        // check registered clients\n        identifiers = dccs.getCloudApplicationIdentifiers();\n        assertEquals(0, identifiers.length);\n\n        verify(esmMock, times(1)).shutdown(esMock); // one more time due to the recursive call\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/test/java/org/eclipse/kura/camel/cloud/KuraCloudComponentResolverTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.camel.cloud;\n\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.Component;\nimport org.junit.Test;\n\npublic class KuraCloudComponentResolverTest {\n\n    @Test\n    public void testResolveComponentWrongName() throws Exception {\n        KuraCloudComponentResolver resolver = new KuraCloudComponentResolver();\n        String name = \"test\";\n        CamelContext context = null;\n\n        Component component = resolver.resolveComponent(name, context);\n\n        assertNull(component);\n    }\n\n    @Test\n    public void testResolveComponent() throws Exception {\n        KuraCloudComponentResolver resolver = new KuraCloudComponentResolver();\n        String name = KuraCloudComponent.DEFAULT_NAME;\n        CamelContext context = null;\n\n        Component component = resolver.resolveComponent(name, context);\n\n        assertNotNull(component);\n        assertNull(component.getCamelContext());\n    }\n\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/test/java/org/eclipse/kura/camel/cloud/KuraCloudComponentTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.camel.cloud;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.Endpoint;\nimport org.apache.camel.spi.Registry;\nimport org.eclipse.kura.camel.internal.cloud.CloudClientCache;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.junit.Test;\n\npublic class KuraCloudComponentTest {\n\n    @Test\n    public void testDoStartNoRegistry() {\n        final CamelContext ctxMock = mock(CamelContext.class);\n\n        KuraCloudComponent kcc = new KuraCloudComponent() {\n\n            @Override\n            public CamelContext getCamelContext() {\n                return ctxMock;\n            }\n        };\n\n        try {\n            kcc.doStart();\n            fail(\"Exception was expected.\");\n        } catch (IllegalArgumentException e) {\n            assertEquals(\"Registry cannot be null.\", e.getMessage());\n        } catch (Exception e) {\n            fail(\"This exception was not expected.\");\n        }\n    }\n\n    @Test\n    public void testDoStartNullSvc() throws Exception {\n        final CamelContext ctxMock = mock(CamelContext.class);\n        Registry regMock = mock(Registry.class);\n        when(ctxMock.getRegistry()).thenReturn(regMock);\n\n        Class<CloudService> clazz = CloudService.class;\n        Set<CloudService> set = new HashSet<CloudService>();\n        set.add(null);\n        when(regMock.findByType(clazz)).thenReturn(set);\n\n        KuraCloudComponent kcc = new KuraCloudComponent() {\n\n            @Override\n            public CamelContext getCamelContext() {\n                return ctxMock;\n            }\n        };\n\n        try {\n            kcc.doStart();\n            fail(\"Exception was expected.\");\n        } catch (IllegalStateException e) {\n            assertEquals(\"'cloudService' is not set and not found in Camel context service registry\", e.getMessage());\n        } catch (Exception e) {\n            fail(\"This exception was not expected.\");\n        }\n\n        assertNull(TestUtil.getFieldValue(kcc, \"cloudService\"));\n    }\n\n    @Test\n    public void testDoStart() throws Exception {\n        final CamelContext ctxMock = mock(CamelContext.class);\n        Registry regMock = mock(Registry.class);\n        when(ctxMock.getRegistry()).thenReturn(regMock);\n\n        Class<CloudService> clazz = CloudService.class;\n        Set<CloudService> set = new HashSet<CloudService>();\n        CloudService cs = mock(clazz);\n        set.add(cs);\n        when(regMock.findByType(clazz)).thenReturn(set);\n\n        KuraCloudComponent kcc = new KuraCloudComponent(ctxMock);\n\n        kcc.doStart();\n\n        assertEquals(cs, TestUtil.getFieldValue(kcc, \"cloudService\"));\n        assertNotNull(TestUtil.getFieldValue(kcc, \"cache\"));\n    }\n\n    @Test\n    public void testDoStop() throws Exception {\n        final CloudClientCache cacheMock = mock(CloudClientCache.class);\n\n        KuraCloudComponent kcc = new KuraCloudComponent();\n\n        TestUtil.setFieldValue(kcc, \"cache\", cacheMock);\n\n        assertNotNull(TestUtil.getFieldValue(kcc, \"cache\"));\n\n        kcc.doStop();\n\n        assertNull(TestUtil.getFieldValue(kcc, \"cache\"));\n        verify(cacheMock, times(1)).close();\n    }\n\n    @Test\n    public void testCreateEndpointWrongRem() throws Exception {\n        KuraCloudComponent kcc = new KuraCloudComponent();\n\n        String uri = \"uri\";\n        String remain = \"remain\";\n        Map<String, Object> parameters = new HashMap<String, Object>();\n\n        try {\n            kcc.createEndpoint(uri, remain, parameters);\n            fail(\"Exception was expected.\");\n        } catch (IllegalArgumentException e) {\n            assertTrue(e.getMessage().startsWith(\"Wrong kura-cloud URI format\"));\n        }\n    }\n\n    @Test\n    public void testCreateEndpoint() throws Exception {\n        KuraCloudComponent kcc = new KuraCloudComponent();\n        final CamelContext ctxMock = mock(CamelContext.class);\n        kcc.setCamelContext(ctxMock);\n\n        String uri = \"uri\";\n        String remain = \"app/topic\";\n        Map<String, Object> parameters = new HashMap<String, Object>();\n\n        Endpoint endpoint = kcc.createEndpoint(uri, remain, parameters);\n\n        assertNotNull(endpoint);\n        assertEquals(uri, endpoint.getEndpointUri());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/test/java/org/eclipse/kura/camel/cloud/KuraCloudProducerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.camel.cloud;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport org.apache.camel.Exchange;\nimport org.apache.camel.Message;\nimport org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.junit.Test;\n\npublic class KuraCloudProducerTest {\n\n    @Test\n    public void testProcessNoBody() throws Exception {\n        // process without body\n\n        KuraCloudEndpoint endpointMock = mock(KuraCloudEndpoint.class);\n        KuraCloudProducer kcp = new KuraCloudProducer(endpointMock, null);\n\n        Exchange exchangeMock = mock(Exchange.class);\n        Message msgMock = mock(Message.class);\n        when(exchangeMock.getIn()).thenReturn(msgMock);\n\n        try {\n            kcp.process(exchangeMock);\n        } catch (RuntimeException e) {\n            assertEquals(\"Cannot produce null payload.\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void testProcessNoControl() throws Exception {\n        // process with body and no control flag\n\n        KuraCloudEndpoint endpointMock = mock(KuraCloudEndpoint.class);\n        CloudClient clientMock = mock(CloudClient.class);\n        KuraCloudProducer kcp = new KuraCloudProducer(endpointMock, clientMock);\n\n        Exchange exchangeMock = mock(Exchange.class);\n        Message msgMock = mock(Message.class);\n        when(exchangeMock.getIn()).thenReturn(msgMock);\n\n        Object body = new byte[] { 0x01, 0x02, 0x03 };\n        when(msgMock.getBody()).thenReturn(body);\n\n        String topic = \"topic\";\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_TOPIC, String.class)).thenReturn(topic);\n        int qos = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS, Integer.class)).thenReturn(qos);\n        int prio = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY, Integer.class)).thenReturn(prio);\n        boolean retain = false;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN, Boolean.class)).thenReturn(retain);\n        boolean control = false;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL, Boolean.class)).thenReturn(control);\n        String deviceId = \"id\";\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID, String.class)).thenReturn(deviceId);\n\n        when(clientMock.publish(eq(topic), (KuraPayload) any(), eq(qos), eq(retain), eq(prio)))\n                .thenAnswer(invocation -> {\n                    Object[] args = invocation.getArguments();\n                    KuraPayload payload = (KuraPayload) args[1];\n                    assertEquals(body, payload.getBody());\n                    return 1;\n                });\n\n        kcp.process(exchangeMock);\n\n        verify(clientMock, times(1)).publish(eq(topic), (KuraPayload) any(), eq(qos), eq(retain), eq(prio));\n    }\n\n    @Test\n    public void testProcessControlNoDeviceId() throws Exception {\n        // process with control flag and no device id\n\n        KuraCloudEndpoint endpointMock = mock(KuraCloudEndpoint.class);\n        CloudClient clientMock = mock(CloudClient.class);\n        KuraCloudProducer kcp = new KuraCloudProducer(endpointMock, clientMock);\n\n        Exchange exchangeMock = mock(Exchange.class);\n        Message msgMock = mock(Message.class);\n        when(exchangeMock.getIn()).thenReturn(msgMock);\n\n        Object body = new byte[] { 0x01, 0x02, 0x03 };\n        when(msgMock.getBody()).thenReturn(body);\n\n        String topic = \"topic\";\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_TOPIC, String.class)).thenReturn(topic);\n        int qos = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS, Integer.class)).thenReturn(qos);\n        int prio = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY, Integer.class)).thenReturn(prio);\n        boolean retain = false;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN, Boolean.class)).thenReturn(retain);\n        boolean control = true;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL, Boolean.class)).thenReturn(control);\n        String deviceId = null;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID, String.class)).thenReturn(deviceId);\n\n        when(clientMock.controlPublish(eq(topic), (KuraPayload) any(), eq(qos), eq(retain), eq(prio)))\n                .thenAnswer(invocation -> {\n                    Object[] args = invocation.getArguments();\n                    KuraPayload payload = (KuraPayload) args[1];\n                    assertEquals(body, payload.getBody());\n                    return 1;\n                });\n\n        kcp.process(exchangeMock);\n\n        verify(clientMock, times(1)).controlPublish(eq(topic), (KuraPayload) any(), eq(qos), eq(retain),\n                eq(prio));\n    }\n\n    @Test\n    public void testProcessOtherBody() throws Exception {\n        // process with Object body and no control flag\n\n        KuraCloudEndpoint endpointMock = mock(KuraCloudEndpoint.class);\n        CloudClient clientMock = mock(CloudClient.class);\n        KuraCloudProducer kcp = new KuraCloudProducer(endpointMock, clientMock);\n\n        Exchange exchangeMock = mock(Exchange.class);\n        Message msgMock = mock(Message.class);\n        when(exchangeMock.getIn()).thenReturn(msgMock);\n\n        Object body = new Object();\n        when(msgMock.getBody()).thenReturn(body);\n        byte[] bodyB = new byte[] { 0x01, 0x02, 0x03 };\n        when(msgMock.getBody(byte[].class)).thenReturn(bodyB);\n\n        String topic = \"topic\";\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_TOPIC, String.class)).thenReturn(topic);\n        int qos = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS, Integer.class)).thenReturn(qos);\n        int prio = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY, Integer.class)).thenReturn(prio);\n        boolean retain = false;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN, Boolean.class)).thenReturn(retain);\n        boolean control = false;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL, Boolean.class)).thenReturn(control);\n        String deviceId = \"id\";\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID, String.class)).thenReturn(deviceId);\n\n        when(clientMock.publish(eq(topic), (KuraPayload) any(), eq(qos), eq(retain), eq(prio)))\n                .thenAnswer(invocation -> {\n                    Object[] args = invocation.getArguments();\n                    KuraPayload payload = (KuraPayload) args[1];\n                    assertEquals(bodyB, payload.getBody());\n                    return 1;\n                });\n\n        kcp.process(exchangeMock);\n\n        verify(clientMock, times(1)).publish(eq(topic), (KuraPayload) any(), eq(qos), eq(retain), eq(prio));\n    }\n\n    @Test\n    public void testProcessOtherBodyString() throws Exception {\n        // process with String body and no control flag\n\n        KuraCloudEndpoint endpointMock = mock(KuraCloudEndpoint.class);\n        CloudClient clientMock = mock(CloudClient.class);\n        KuraCloudProducer kcp = new KuraCloudProducer(endpointMock, clientMock);\n\n        Exchange exchangeMock = mock(Exchange.class);\n        Message msgMock = mock(Message.class);\n        when(exchangeMock.getIn()).thenReturn(msgMock);\n\n        Object body = new Object();\n        when(msgMock.getBody()).thenReturn(body);\n        byte[] bodyB = null;\n        when(msgMock.getBody(byte[].class)).thenReturn(bodyB);\n        String bodyS = \"body\";\n        when(msgMock.getBody(String.class)).thenReturn(bodyS);\n\n        String topic = \"topic\";\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_TOPIC, String.class)).thenReturn(topic);\n        int qos = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS, Integer.class)).thenReturn(qos);\n        int prio = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY, Integer.class)).thenReturn(prio);\n        boolean retain = false;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN, Boolean.class)).thenReturn(retain);\n        boolean control = false;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL, Boolean.class)).thenReturn(control);\n        String deviceId = \"id\";\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID, String.class)).thenReturn(deviceId);\n\n        when(clientMock.publish(eq(topic), (KuraPayload) any(), eq(qos), eq(retain), eq(prio)))\n                .thenAnswer(invocation -> {\n                    Object[] args = invocation.getArguments();\n                    KuraPayload payload = (KuraPayload) args[1];\n                    assertArrayEquals(bodyS.getBytes(), payload.getBody());\n                    return 1;\n                });\n\n        kcp.process(exchangeMock);\n\n        verify(clientMock, times(1)).publish(eq(topic), (KuraPayload) any(), eq(qos), eq(retain), eq(prio));\n    }\n\n    @Test\n    public void testProcess() throws Exception {\n        // process with body and control flag and device id\n\n        KuraCloudEndpoint endpointMock = mock(KuraCloudEndpoint.class);\n        CloudClient clientMock = mock(CloudClient.class);\n        KuraCloudProducer kcp = new KuraCloudProducer(endpointMock, clientMock);\n\n        Exchange exchangeMock = mock(Exchange.class);\n        Message msgMock = mock(Message.class);\n        when(exchangeMock.getIn()).thenReturn(msgMock);\n\n        Object body = new byte[] { 0x01, 0x02, 0x03 };\n        when(msgMock.getBody()).thenReturn(body);\n\n        String topic = \"topic\";\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_TOPIC, String.class)).thenReturn(topic);\n        int qos = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS, Integer.class)).thenReturn(qos);\n        int prio = 1;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY, Integer.class)).thenReturn(prio);\n        boolean retain = false;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN, Boolean.class)).thenReturn(retain);\n        boolean control = true;\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL, Boolean.class)).thenReturn(control);\n        String deviceId = \"id\";\n        when(msgMock.getHeader(KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID, String.class)).thenReturn(deviceId);\n\n        when(clientMock.controlPublish(eq(deviceId), eq(topic), (KuraPayload) any(), eq(qos), eq(retain),\n                eq(prio))).thenAnswer(invocation -> {\n                    Object[] args = invocation.getArguments();\n                    KuraPayload payload = (KuraPayload) args[2];\n                    assertEquals(body, payload.getBody());\n                    return 1;\n                });\n\n        kcp.process(exchangeMock);\n\n        verify(clientMock, times(1)).controlPublish(eq(deviceId), eq(topic), (KuraPayload) any(), eq(qos),\n                eq(retain), eq(prio));\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/test/java/org/eclipse/kura/camel/component/ConfigurationTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.camel.component;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.Test;\n\n\npublic class ConfigurationTest {\n\n    @Test\n    public void testBoolean() {\n        String key = \"key\";\n\n        assertFalse(Configuration.asBoolean(null, key));\n\n        assertTrue(Configuration.asBoolean(null, key, true));\n\n        Map<String, Object> properties = new HashMap<String, Object>();\n        assertTrue(Configuration.asBoolean(properties, key, true));\n\n        properties.put(key, Boolean.FALSE);\n        assertFalse(Configuration.asBoolean(properties, key, true));\n\n        assertTrue(Configuration.asBoolean(null, key, Boolean.TRUE));\n\n        properties = new HashMap<String, Object>();\n        assertTrue(Configuration.asBoolean(properties, key, Boolean.TRUE));\n\n        properties.put(key, Boolean.FALSE);\n        assertFalse(Configuration.asBoolean(properties, key, Boolean.TRUE));\n    }\n\n    @Test\n    public void testDouble() {\n        String key = \"key\";\n        double eps = 0.000001;\n\n        assertNull(Configuration.asDouble(null, key));\n\n        assertEquals(1.0, Configuration.asDouble(null, key, 1.0), eps);\n\n        Map<String, Object> properties = new HashMap<String, Object>();\n        assertEquals(1.0, Configuration.asDouble(properties, key, 1.0), eps);\n\n        Double one = new Double(1.0);\n        properties.put(key, one);\n        assertEquals(1.0, Configuration.asDouble(properties, key, 0.0), eps);\n\n        assertEquals(one, Configuration.asDouble(null, key, one));\n\n        properties = new HashMap<String, Object>();\n        assertEquals(one, Configuration.asDouble(properties, key, one));\n\n        properties.put(key, 0.0);\n        assertEquals(new Double(0.0), Configuration.asDouble(properties, key, one));\n    }\n\n    @Test\n    public void testInt() {\n        String key = \"key\";\n\n        assertEquals(1, Configuration.asInt(null, key, 1));\n\n        Map<String, Object> properties = new HashMap<String, Object>();\n        assertEquals(1, Configuration.asInt(properties, key, 1));\n\n        Integer one = new Integer(1);\n        properties.put(key, one);\n        assertEquals(1, Configuration.asInt(properties, key, 0));\n    }\n\n    @Test\n    public void testInteger() {\n        String key = \"key\";\n        Integer one = new Integer(1);\n\n        assertNull(Configuration.asInteger(null, key));\n\n        assertEquals(one, Configuration.asInteger(null, key, one));\n\n        Map<String, Object> properties = new HashMap<String, Object>();\n        assertEquals(new Integer(1), Configuration.asInteger(properties, key, 1));\n\n        properties.put(key, one);\n        assertEquals(one, Configuration.asInteger(properties, key, 0));\n    }\n\n    @Test\n    public void testLong() {\n        String key = \"key\";\n\n        assertNull(Configuration.asLong(null, key));\n\n        assertEquals(1, Configuration.asLong(null, key, 1));\n\n        Map<String, Object> properties = new HashMap<String, Object>();\n        assertEquals(1, Configuration.asLong(properties, key, 1));\n\n        Long one = new Long(1);\n        properties.put(key, one);\n        assertEquals(1, Configuration.asLong(properties, key, 0));\n\n        assertEquals(one, Configuration.asLong(null, key, one));\n\n        properties = new HashMap<String, Object>();\n        assertEquals(one, Configuration.asLong(properties, key, one));\n\n        properties.put(key, 0);\n        assertEquals(new Long(0), Configuration.asLong(properties, key, one));\n    }\n\n    @Test\n    public void testString() {\n        String key = \"key\";\n\n        assertNull(Configuration.asString(null, key));\n\n        String defVal = \"str\";\n        assertEquals(defVal, Configuration.asString(null, key, defVal));\n\n        Map<String, Object> properties = new HashMap<String, Object>();\n        assertEquals(defVal, Configuration.asString(properties, key, defVal));\n\n        String str = \"other string\";\n        properties.put(key, str);\n        assertEquals(str, Configuration.asString(properties, key, defVal));\n    }\n\n    @Test\n    public void testStringNotEmpty() {\n        String key = \"key\";\n        String defVal = \"str\";\n\n        assertEquals(defVal, Configuration.asStringNotEmpty(null, key, defVal));\n\n        Map<String, Object> properties = new HashMap<String, Object>();\n        assertEquals(defVal, Configuration.asStringNotEmpty(properties, key, defVal));\n\n        properties.put(key, new Object());\n        assertEquals(defVal, Configuration.asStringNotEmpty(properties, key, defVal));\n\n        properties.put(key, key);\n        assertEquals(key, Configuration.asStringNotEmpty(properties, key, defVal));\n\n        properties.put(key, \"\");\n        assertEquals(defVal, Configuration.asStringNotEmpty(properties, key, defVal));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/test/java/org/eclipse/kura/camel/internal/camelcloud/CamelCloudClientTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.camel.internal.camelcloud;\n\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_MESSAGEID;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS;\nimport static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN;\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.Map;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutorService;\n\nimport org.apache.camel.CamelContext;\nimport org.apache.camel.ProducerTemplate;\nimport org.apache.camel.StartupListener;\nimport org.apache.camel.builder.RouteBuilder;\nimport org.apache.camel.spi.ExecutorServiceManager;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.camel.camelcloud.CamelCloudService;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.junit.Test;\n\npublic class CamelCloudClientTest {\n\n    @Test\n    public void testPublish() throws KuraException {\n        CamelCloudService cloudServiceMock = mock(CamelCloudService.class);\n        CamelContext camelContextMock = mock(CamelContext.class);\n        String applicationId = \"appId\";\n        String baseEndpoint = \"endpoint\";\n\n        String appTopic = \"topic\";\n        byte[] payload = new byte[] { 0x01, 0x02 };\n        int qos = 0;\n        boolean retain = false;\n        int priority = 0;\n\n        ExecutorServiceManager esmgrMock = mock(ExecutorServiceManager.class);\n        when(camelContextMock.getExecutorServiceManager()).thenReturn(esmgrMock);\n\n        ProducerTemplate producerMock = mock(ProducerTemplate.class);\n        when(camelContextMock.createProducerTemplate()).thenReturn(producerMock);\n\n        ExecutorService execSvcMock = mock(ExecutorService.class);\n        when(esmgrMock.newThreadPool(any(), eq(\"CamelCloudClient/\" + applicationId), eq(0), eq(1)))\n                .thenReturn(execSvcMock);\n\n        doAnswer(invocation -> {\n            final String target = invocation.getArgument(0, String.class);\n            assertEquals(\"endpoint\" + applicationId + \":\" + appTopic, target);\n\n            final KuraPayload load = invocation.getArgument(1, KuraPayload.class);\n            assertArrayEquals(payload, load.getBody());\n\n            final Map<String, Object> headers = invocation.getArgument(2, Map.class);\n            assertFalse((boolean) headers.get(CAMEL_KURA_CLOUD_CONTROL));\n            assertNotNull(headers.get(CAMEL_KURA_CLOUD_MESSAGEID));\n            assertNull(headers.get(CAMEL_KURA_CLOUD_DEVICEID));\n            assertEquals(qos, headers.get(CAMEL_KURA_CLOUD_QOS));\n            assertEquals(retain, headers.get(CAMEL_KURA_CLOUD_RETAIN));\n            assertEquals(priority, headers.get(CAMEL_KURA_CLOUD_PRIORITY));\n\n            return null;\n        }).when(producerMock).sendBodyAndHeaders(anyString(), any(), any());\n\n        CamelCloudClient ccc = new CamelCloudClient(cloudServiceMock, camelContextMock, applicationId, baseEndpoint);\n\n        ccc.publish(appTopic, payload, qos, retain, priority);\n\n        verify(producerMock).sendBodyAndHeaders(anyString(), any(), any());\n    }\n\n    @Test\n    public void testPublishWithDeviceId() throws KuraException {\n        CamelCloudService cloudServiceMock = mock(CamelCloudService.class);\n        CamelContext camelContextMock = mock(CamelContext.class);\n        String applicationId = \"appId\";\n        String baseEndpoint = \"endpoint:%s\";\n\n        String deviceId = \"deviceId\";\n        String appTopic = \"topc\";\n        byte[] payload = new byte[] { 0x01 };\n        int qos = 2;\n        boolean retain = false;\n        int priority = 7;\n\n        ExecutorServiceManager esmgrMock = mock(ExecutorServiceManager.class);\n        when(camelContextMock.getExecutorServiceManager()).thenReturn(esmgrMock);\n\n        ProducerTemplate producerMock = mock(ProducerTemplate.class);\n        when(camelContextMock.createProducerTemplate()).thenReturn(producerMock);\n\n        ExecutorService execSvcMock = mock(ExecutorService.class);\n        when(esmgrMock.newThreadPool(any(), eq(\"CamelCloudClient/\" + applicationId), eq(0), eq(1)))\n                .thenReturn(execSvcMock);\n\n        doAnswer(invocation -> {\n            final String target = invocation.getArgument(0, String.class);\n            assertEquals(\"endpoint:\" + deviceId + \":\" + applicationId + \":\" + appTopic, target);\n\n            final KuraPayload load = invocation.getArgument(1, KuraPayload.class);\n            assertArrayEquals(payload, load.getBody());\n\n            final Map<String, Object> headers = invocation.getArgument(2, Map.class);\n            assertFalse((boolean) headers.get(CAMEL_KURA_CLOUD_CONTROL));\n            assertNotNull(headers.get(CAMEL_KURA_CLOUD_MESSAGEID));\n            assertEquals(deviceId, headers.get(CAMEL_KURA_CLOUD_DEVICEID));\n            assertEquals(qos, headers.get(CAMEL_KURA_CLOUD_QOS));\n            assertEquals(retain, headers.get(CAMEL_KURA_CLOUD_RETAIN));\n            assertEquals(priority, headers.get(CAMEL_KURA_CLOUD_PRIORITY));\n\n            return null;\n        }).when(producerMock).sendBodyAndHeaders(anyString(), any(), any());\n\n        CamelCloudClient ccc = new CamelCloudClient(cloudServiceMock, camelContextMock, applicationId, baseEndpoint);\n\n        ccc.publish(deviceId, appTopic, payload, qos, retain, priority);\n\n        verify(producerMock).sendBodyAndHeaders(anyString(), any(), any());\n    }\n\n    @Test\n    public void testControlPublishWithDeviceId() throws KuraException {\n        CamelCloudService cloudServiceMock = mock(CamelCloudService.class);\n        CamelContext camelContextMock = mock(CamelContext.class);\n        String applicationId = \"appId\";\n        String baseEndpoint = \"endpoint:%s\";\n\n        String deviceId = \"deviceId\";\n        String appTopic = \"topc\";\n        byte[] payload = new byte[] { 0x01 };\n        int qos = 2;\n        boolean retain = false;\n        int priority = 7;\n\n        ExecutorServiceManager esmgrMock = mock(ExecutorServiceManager.class);\n        when(camelContextMock.getExecutorServiceManager()).thenReturn(esmgrMock);\n\n        ProducerTemplate producerMock = mock(ProducerTemplate.class);\n        when(camelContextMock.createProducerTemplate()).thenReturn(producerMock);\n\n        ExecutorService execSvcMock = mock(ExecutorService.class);\n        when(esmgrMock.newThreadPool(any(), eq(\"CamelCloudClient/\" + applicationId), eq(0), eq(1)))\n                .thenReturn(execSvcMock);\n\n        doAnswer(invocation -> {\n            final String target = invocation.getArgument(0, String.class);\n            assertEquals(\"endpoint:\" + deviceId + \":\" + applicationId + \":\" + appTopic, target);\n\n            final KuraPayload load = invocation.getArgument(1, KuraPayload.class);\n            assertArrayEquals(payload, load.getBody());\n\n            final Map<String, Object> headers = invocation.getArgument(2, Map.class);\n            assertTrue((boolean) headers.get(CAMEL_KURA_CLOUD_CONTROL));\n            assertNotNull(headers.get(CAMEL_KURA_CLOUD_MESSAGEID));\n            assertEquals(deviceId, headers.get(CAMEL_KURA_CLOUD_DEVICEID));\n            assertEquals(qos, headers.get(CAMEL_KURA_CLOUD_QOS));\n            assertEquals(retain, headers.get(CAMEL_KURA_CLOUD_RETAIN));\n            assertEquals(priority, headers.get(CAMEL_KURA_CLOUD_PRIORITY));\n\n            return null;\n        }).when(producerMock).sendBodyAndHeaders(anyString(), any(), any());\n\n        CamelCloudClient ccc = new CamelCloudClient(cloudServiceMock, camelContextMock, applicationId, baseEndpoint);\n\n        ccc.controlPublish(deviceId, appTopic, payload, qos, retain, priority);\n\n        verify(producerMock).sendBodyAndHeaders(anyString(), any(), any());\n    }\n\n    @Test\n    public void testSubscribeException1() throws Exception {\n        CamelCloudService cloudServiceMock = mock(CamelCloudService.class);\n        CamelContext camelContextMock = mock(CamelContext.class);\n        String applicationId = \"appId\";\n        String baseEndpoint = \"endpoint\";\n\n        String deviceId = \"deviceId\";\n        String appTopic = \"topc\";\n        int qos = 2;\n\n        ExecutorServiceManager esmgrMock = mock(ExecutorServiceManager.class);\n        when(camelContextMock.getExecutorServiceManager()).thenReturn(esmgrMock);\n\n        ProducerTemplate producerMock = mock(ProducerTemplate.class);\n        when(camelContextMock.createProducerTemplate()).thenReturn(producerMock);\n\n        ExecutorService execSvcMock = mock(ExecutorService.class);\n        when(esmgrMock.newThreadPool(any(), eq(\"CamelCloudClient/\" + applicationId), eq(0), eq(1)))\n                .thenReturn(execSvcMock);\n\n        CamelCloudClient ccc = new CamelCloudClient(cloudServiceMock, camelContextMock, applicationId, baseEndpoint);\n\n        doThrow(new RuntimeException(\"test\")).when(camelContextMock).addStartupListener(any());\n\n        try {\n            ccc.subscribe(deviceId, appTopic, qos);\n            fail(\"Expected an exception\");\n        } catch (Exception e) {\n            assertEquals(\"test\", e.getCause().getMessage());\n        }\n    }\n\n    @Test\n    public void testSubscribeException2() throws Exception {\n        CamelCloudService cloudServiceMock = mock(CamelCloudService.class);\n        CamelContext camelContextMock = mock(CamelContext.class);\n        String applicationId = \"appId\";\n        String baseEndpoint = \"endpoint\";\n\n        String deviceId = \"deviceId\";\n        String appTopic = \"topc\";\n        int qos = 2;\n\n        ExecutorServiceManager esmgrMock = mock(ExecutorServiceManager.class);\n        when(camelContextMock.getExecutorServiceManager()).thenReturn(esmgrMock);\n\n        ProducerTemplate producerMock = mock(ProducerTemplate.class);\n        when(camelContextMock.createProducerTemplate()).thenReturn(producerMock);\n\n        ExecutorService execSvcMock = mock(ExecutorService.class);\n        when(esmgrMock.newThreadPool(any(), eq(\"CamelCloudClient/\" + applicationId), eq(0), eq(1)))\n        .thenReturn(execSvcMock);\n\n        CamelCloudClient ccc = new CamelCloudClient(cloudServiceMock, camelContextMock, applicationId, baseEndpoint);\n\n        when(execSvcMock.submit((Callable<?>) any())).thenAnswer(invocation -> {\n            Callable<?> task = invocation.getArgument(0, Callable.class);\n\n            task.call();\n\n            return null;\n        });\n\n        doAnswer(invocation -> {\n            StartupListener listener = invocation.getArgument(0, StartupListener.class);\n\n            listener.onCamelContextStarted(camelContextMock, false);\n\n            return null;\n        }).when(camelContextMock).addStartupListener(any());\n\n        doThrow(new RuntimeException(\"test\")).when(camelContextMock).addRoutes(any());\n\n        try {\n            ccc.subscribe(deviceId, appTopic, qos);\n            fail(\"Expected an exception\");\n        } catch (Exception e) {\n            assertEquals(\"test\", e.getCause().getCause().getMessage());\n        }\n    }\n\n    @Test\n    public void testSubscribe() throws Exception {\n        CamelCloudService cloudServiceMock = mock(CamelCloudService.class);\n        CamelContext camelContextMock = mock(CamelContext.class);\n        String applicationId = \"appId\";\n        String baseEndpoint = \"endpoint\";\n\n        String deviceId = \"deviceId\";\n        String appTopic = \"topc\";\n        int qos = 2;\n\n        ExecutorServiceManager esmgrMock = mock(ExecutorServiceManager.class);\n        when(camelContextMock.getExecutorServiceManager()).thenReturn(esmgrMock);\n\n        ProducerTemplate producerMock = mock(ProducerTemplate.class);\n        when(camelContextMock.createProducerTemplate()).thenReturn(producerMock);\n\n        ExecutorService execSvcMock = mock(ExecutorService.class);\n        when(esmgrMock.newThreadPool(any(), eq(\"CamelCloudClient/\" + applicationId), eq(0), eq(1)))\n                .thenReturn(execSvcMock);\n\n        CamelCloudClient ccc = new CamelCloudClient(cloudServiceMock, camelContextMock, applicationId, baseEndpoint);\n\n        when(execSvcMock.submit((Callable<?>) any())).thenAnswer(invocation -> {\n            Callable<?> task = invocation.getArgument(0, Callable.class);\n\n            task.call();\n\n            return null;\n        });\n\n        doAnswer(invocation -> {\n            StartupListener listener = invocation.getArgument(0, StartupListener.class);\n\n            listener.onCamelContextStarted(camelContextMock, false);\n\n            return null;\n        }).when(camelContextMock).addStartupListener(any());\n\n        doAnswer(invocation -> {\n            RouteBuilder builder = invocation.getArgument(0, RouteBuilder.class);\n\n            builder.configure();\n\n            return null;\n        }).when(camelContextMock).addRoutes(any());\n\n        ccc.subscribe(deviceId, appTopic, qos);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.camel.test/src/test/java/org/eclipse/kura/camel/internal/utils/KuraServiceFactoryTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.camel.internal.utils;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport org.apache.camel.spi.Registry;\nimport org.junit.Test;\n\npublic class KuraServiceFactoryTest {\n\n    @Test\n    public void testNull() {\n        Class<KuraServiceFactoryTest> clazz = KuraServiceFactoryTest.class;\n\n        try {\n            KuraServiceFactory.retrieveService(clazz, null);\n            fail(\"Exception was expected.\");\n        } catch (Exception e) {\n            assertEquals(\"Registry cannot be null.\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void testOther() {\n        Registry regMock = mock(Registry.class);\n\n        Class<KuraServiceFactoryTest> clazz = KuraServiceFactoryTest.class;\n\n        try {\n            KuraServiceFactory.retrieveService(clazz, regMock);\n            fail(\"Exception was expected.\");\n        } catch (Exception e) {\n            assertEquals(\"No \" + clazz.getCanonicalName() + \" service instance found in a registry.\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void testMulti() {\n        Class<KuraServiceFactoryTest> clazz = KuraServiceFactoryTest.class;\n\n        Registry regMock = mock(Registry.class);\n        Set<KuraServiceFactoryTest> set = new HashSet<KuraServiceFactoryTest>();\n        set.add(new KuraServiceFactoryTest());\n        set.add(new KuraServiceFactoryTest());\n        when(regMock.findByType(clazz)).thenReturn(set);\n\n        try {\n            KuraServiceFactory.retrieveService(clazz, regMock);\n            fail(\"Exception was expected.\");\n        } catch (Exception e) {\n            assertTrue(e.getMessage().startsWith(\"Too many\"));\n        }\n    }\n\n    @Test\n    public void testNull2() {\n        Class<KuraServiceFactoryTest> clazz = KuraServiceFactoryTest.class;\n\n        Registry regMock = mock(Registry.class);\n        Set<KuraServiceFactoryTest> set = new HashSet<KuraServiceFactoryTest>();\n        set.add(null);\n        when(regMock.findByType(clazz)).thenReturn(set);\n\n        KuraServiceFactoryTest service = KuraServiceFactory.retrieveService(clazz, regMock);\n        assertNull(service);\n    }\n\n    @Test\n    public void testSingle() {\n        Class<KuraServiceFactoryTest> clazz = KuraServiceFactoryTest.class;\n\n        Registry regMock = mock(Registry.class);\n        Set<KuraServiceFactoryTest> set = new HashSet<KuraServiceFactoryTest>();\n        KuraServiceFactoryTest tst = new KuraServiceFactoryTest();\n        set.add(tst);\n        when(regMock.findByType(clazz)).thenReturn(set);\n\n        KuraServiceFactoryTest service = KuraServiceFactory.retrieveService(clazz, regMock);\n        assertEquals(tst, service);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.cloud.base.provider.test\nBundle-SymbolicName: org.eclipse.kura.cloud.base.provider.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: javax.comm,\n javax.xml.parsers,\n javax.xml.stream,\n junit.framework,\n org.bouncycastle.asn1.x500;version=\"1.78.1\",\n org.eclipse.kura.cloud;version=\"[1.0,2.0)\",\n org.eclipse.kura.comm;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.configuration;version=\"[2.0,3.0)\",\n org.eclipse.kura.core.configuration.metatype;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.configuration.util;version=\"[2.0,3.0)\",\n org.eclipse.kura.core.inventory;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.inventory.resources;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.core.testutil.event;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.http;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.pki;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\",\n org.eclipse.kura.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.marshalling;version=\"1.0.0\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.security.keystore;version=\"[1.1,2.0)\",\n org.eclipse.kura.util.service;version=\"1.0.0\",\n org.eclipse.kura.util.wire.test;version=\"1.1.0\",\n org.eclipse.kura.watchdog;version=\"[1.0,2.0)\",\n org.h2;version=\"2.1.210\",\n org.h2.api;version=\"2.1.210\",\n org.h2.jdbcx;version=\"2.1.210\",\n org.h2.tools;version=\"2.1.210\",\n org.junit,\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.mockito.verification;version=\"4.8.1\",\n org.osgi.framework,\n org.osgi.service.cm,\n org.osgi.service.component,\n org.osgi.service.deploymentadmin;version=\"1.0.0\",\n org.osgi.service.event,\n org.osgi.service.io;version=\"1.0.0\",\n org.slf4j;version=\"1.6.4\",\n org.w3c.dom,\n org.xml.sax\nFragment-Host: org.eclipse.kura.cloud.base.provider\nBundle-ActivationPolicy: lazy\nComment: org.eclipse.kura.emulator is needed as we need to start-up the emulator to run the tests!!\nRequire-Bundle: org.eclipse.equinox.io,\n org.junit,\n org.eclipse.kura.test,\n org.eclipse.kura.emulator,\n moquette-broker\nComment2: require moquette-broker. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=485926\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about_files/,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.eclipse.kura.test,\\\n                     org.junit\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.cloud.base.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.build.directory}/site/jacoco-aggregate/jacoco.xml\n        </sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/src/main/java/org/eclipse/kura/core/test/BaseCloudTests.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.security.KeyPair;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.cert.Certificate;\nimport java.security.cert.X509Certificate;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.bouncycastle.asn1.x500.X500Name;\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.pki.TestCA;\nimport org.eclipse.kura.core.testutil.pki.TestCA.CertificateCreationOptions;\nimport org.eclipse.kura.core.testutil.pki.TestCA.TestCAException;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.util.wire.test.WireTestUtil;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.moquette.broker.Server;\nimport io.moquette.broker.config.FluentConfig;\nimport io.moquette.broker.config.IConfig;\n\npublic class BaseCloudTests {\n\n    private static final Logger logger = LoggerFactory.getLogger(BaseCloudTests.class);\n\n    protected static final String BROKER_ADDR_MQTT = \"mqtt://localhost:1883\";\n    protected static final String BROKER_ADDR_MQTTS = \"mqtts://localhost:8883\";\n    protected static final String BROKER_ADDR_WSS = \"wss://localhost:8083\";\n\n    protected static final String DEFAULT_CLOUD_SERVICE_PID = \"org.eclipse.kura.cloud.CloudService\";\n    protected static final String DEFAULT_DATA_SERVICE_PID = \"org.eclipse.kura.data.DataService\";\n    protected static final String DEFAULT_MQTT_DATA_TRANSPORT_SERVICE_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    protected static ConfigurationService configurationService;\n    protected static DataService dataService;\n    protected static CloudService cloudService;\n    private static Server mqttBroker;\n\n    protected static TestCA brokerCA;\n    protected static X509Certificate brokerCertificate;\n    protected static File brokerKeyStore;\n    protected static File mqttKeyStore;\n    protected static File mqttKeyStoreKeyOnly;\n    protected static File mqttTrustStore;\n\n    @BeforeClass\n    public static void setupTestClass() throws Exception {\n        try {\n            logger.info(\"Setup BaseCloudTests\");\n\n            configureKeystores();\n            startMoquetteBroker(brokerKeyStore.getAbsolutePath());\n\n            configurationService = WireTestUtil\n                    .trackService(ConfigurationService.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n            dataService = WireTestUtil.trackService(DataService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n            cloudService = WireTestUtil.trackService(CloudService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n            configureCloudService();\n            configureDataService();\n            configureMqttDataTransport();\n\n            connectDataService();\n        } catch (Exception e) {\n            throw new Exception(\"Failed to reconfigure the broker settings - failing out\", e);\n        }\n    }\n\n    @AfterClass\n    public static void teardownTestClass() throws Exception {\n        logger.info(\"teardownTestClass...\");\n        if (dataService != null && dataService.isConnected()) {\n            dataService.disconnect(0);\n        }\n        stopMoquetteBroker();\n    }\n\n    private static void startMoquetteBroker(String jksPath) throws IOException {\n        if (mqttBroker != null) {\n            logger.info(\"Moquette broker already running\");\n            return;\n        }\n\n        IConfig brokerConfig = new FluentConfig().port(1883).host(\"0.0.0.0\").disablePersistence().build();\n        brokerConfig.setProperty(IConfig.NETTY_MAX_BYTES_PROPERTY_NAME, \"16777216\");\n        brokerConfig.setProperty(IConfig.JKS_PATH_PROPERTY_NAME, jksPath);\n        brokerConfig.setProperty(IConfig.KEY_STORE_PASSWORD_PROPERTY_NAME, \"changeit\");\n        brokerConfig.setProperty(IConfig.KEY_MANAGER_PASSWORD_PROPERTY_NAME, \"changeit\");\n        brokerConfig.setProperty(IConfig.SSL_PORT_PROPERTY_NAME, \"8883\");\n        brokerConfig.setProperty(IConfig.WEB_SOCKET_PORT_PROPERTY_NAME, \"8080\");\n        brokerConfig.setProperty(IConfig.WSS_PORT_PROPERTY_NAME, \"8083\");\n\n        mqttBroker = new Server();\n        mqttBroker.startServer(brokerConfig);\n\n        Runtime.getRuntime().addShutdownHook(new Thread(BaseCloudTests::stopMoquetteBroker));\n        logger.info(\"Moquette broker started\");\n    }\n\n    private static void stopMoquetteBroker() {\n        if (mqttBroker != null) {\n            mqttBroker.stopServer();\n            mqttBroker = null;\n            logger.info(\"Moquette broker stopped\");\n        }\n    }\n\n    private static void configureKeystores() throws TestCAException, IOException {\n        final KeyPair brokerKeyPair = TestCA.generateKeyPair();\n        final TestCA clientCA = new TestCA(\n                CertificateCreationOptions.builder(new X500Name(\"cn=client CA, dc=baz.com\")).build());\n        final KeyPair clientKeyPair = TestCA.generateKeyPair();\n        final X509Certificate clientCertificate = clientCA.createAndSignCertificate(\n                CertificateCreationOptions.builder(new X500Name(\"cn=client, dc=baz.com\")).build(), clientKeyPair);\n\n        brokerCA = new TestCA(CertificateCreationOptions.builder(new X500Name(\"cn=broker CA, dc=bar.com\")).build());\n        brokerCertificate = brokerCA.createAndSignCertificate(\n                CertificateCreationOptions.builder(new X500Name(\"cn=broker, dc=bar.com\")).build(), brokerKeyPair);\n\n        brokerKeyStore = TestCA.writeKeystore( //\n                new PrivateKeyEntry(brokerKeyPair.getPrivate(),\n                        new Certificate[] { brokerCertificate, brokerCA.getCertificate() }), //\n                new TrustedCertificateEntry(clientCA.getCertificate()));\n        mqttKeyStore = TestCA.writeKeystore(\n                new PrivateKeyEntry(clientKeyPair.getPrivate(),\n                        new Certificate[] { clientCertificate, clientCA.getCertificate() }),\n                new TrustedCertificateEntry(brokerCertificate));\n        mqttKeyStoreKeyOnly = TestCA.writeKeystore(new PrivateKeyEntry(clientKeyPair.getPrivate(),\n                new Certificate[] { clientCertificate, clientCA.getCertificate() }));\n        mqttTrustStore = TestCA.writeKeystore(new TrustedCertificateEntry(brokerCA.getCertificate()));\n    }\n\n    private static void configureCloudService()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n        final Map<String, Object> cloudServiceProperties = new HashMap<>();\n        cloudServiceProperties.put(\"payload.encoding\", \"simple-json\");\n        /*\n         * Set a control topic without $ as prefix: some brokers do not allow access to topics starting with $ (like\n         * moquette, mosquitto)\n         */\n        cloudServiceProperties.put(\"topic.control-prefix\", \"EDC\");\n\n        ServiceUtil\n                .updateComponentConfiguration(configurationService, DEFAULT_CLOUD_SERVICE_PID, cloudServiceProperties)\n                .get(30, TimeUnit.SECONDS);\n    }\n\n    private static void configureDataService()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n        Map<String, Object> dataProps = new HashMap<>();\n        dataProps.put(\"connect.auto-on-startup\", false);\n        dataProps.put(\"enable.rate.limit\", false);\n\n        ServiceUtil\n                .updateComponentConfiguration(configurationService, DEFAULT_DATA_SERVICE_PID, dataProps)\n                .get(30, TimeUnit.SECONDS);\n    }\n\n    private static void configureMqttDataTransport()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n        final Map<String, Object> properties = new HashMap<>();\n        properties.put(\"broker-url\", \"mqtt://localhost:1883/\");\n        properties.put(\"username\", \"mqtt\");\n        properties.put(\"client-id\", \"test\");\n        properties.put(\"topic.context.account-name\", \"mqtt\");\n\n        ServiceUtil.updateComponentConfiguration(configurationService, DEFAULT_MQTT_DATA_TRANSPORT_SERVICE_PID,\n                properties).get(30, TimeUnit.SECONDS);\n    }\n\n    protected static void connectDataService() throws KuraConnectException {\n        if (!dataService.isConnected()) {\n            dataService.connect();\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/src/main/java/org/eclipse/kura/core/test/CloudServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloud.CloudClientListener;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.Test;\n\npublic class CloudServiceTest extends BaseCloudTests implements CloudClientListener {\n\n    private int publishedMsgId;\n    private boolean publishPublished;\n    private boolean publishConfirmed;\n    private boolean publishArrived;\n\n    private int controlMsgId;\n    private boolean controlPublished;\n    private boolean controlConfirmed;\n    private boolean controlArrived;\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testServiceExists() {\n        assertNotNull(CloudServiceTest.cloudService);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testService() throws Exception {\n        this.publishArrived = false;\n        this.controlArrived = false;\n\n        CloudClient cloudAppClient = CloudServiceTest.cloudService.newCloudClient(\"testService\");\n        cloudAppClient.addCloudClientListener(this);\n\n        // test regular subscriptions\n        int count = 0;\n        while (!cloudAppClient.isConnected() && count < 10) {\n            Thread.sleep(1000);\n            count++;\n        }\n        if (!cloudAppClient.isConnected()) {\n            throw new Exception(\"Not connected\");\n        }\n        cloudAppClient.subscribe(\"test\", 1);\n\n        // test default subscriptions\n        int priority = 5;\n\n        KuraPayload payload = new KuraPayload();\n        payload.setBody(\"payload\".getBytes());\n        this.publishedMsgId = cloudAppClient.publish(\"test\", payload, 1, false, priority);\n\n        KuraPayload controlPayload = new KuraPayload();\n        controlPayload.setBody(\"control_payload\".getBytes());\n        this.controlMsgId = cloudAppClient.controlPublish(\"control_test\", controlPayload, 1, false, priority);\n\n        Thread.sleep(1000);\n\n        assertTrue(\"publish not published!\", this.publishPublished);\n        assertTrue(\"publish not confirmed!\", this.publishConfirmed);\n        assertTrue(\"publish not arrived!\", this.publishArrived);\n\n        assertTrue(\"control not published!\", this.controlPublished);\n        assertTrue(\"control not confirmed!\", this.controlConfirmed);\n        assertTrue(\"control not arrived!\", this.controlArrived);\n\n        cloudAppClient.release();\n    }\n\n    @Override\n    public void onConnectionLost() {\n        // Ignore\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        // Ignore\n    }\n\n    @Override\n    public void onControlMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) {\n        assertEquals(\"control_test\", appTopic);\n        assertEquals(\"control_payload\", new String(msg.getBody()));\n        this.controlArrived = true;\n    }\n\n    @Override\n    public void onMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) {\n        assertEquals(\"test\", appTopic);\n        assertEquals(\"payload\", new String(msg.getBody()));\n        this.publishArrived = true;\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String appTopic) {\n        if (messageId == this.publishedMsgId) {\n            assertEquals(\"test\", appTopic);\n            this.publishConfirmed = true;\n        }\n        if (messageId == this.controlMsgId) {\n            assertEquals(\"control_test\", appTopic);\n            this.controlConfirmed = true;\n        }\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String appTopic) {\n        if (messageId == this.publishedMsgId) {\n            assertEquals(\"test\", appTopic);\n            this.publishPublished = true;\n        }\n        if (messageId == this.controlMsgId) {\n            assertEquals(\"control_test\", appTopic);\n            this.controlPublished = true;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/src/main/java/org/eclipse/kura/core/test/DataServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.data.DataServiceListener;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@SuppressWarnings(\"deprecation\")\npublic class DataServiceTest extends BaseCloudTests implements DataServiceListener {\n\n    private static final Logger logger = LoggerFactory.getLogger(DataServiceTest.class);\n\n    private static Set<Integer> s_qos0MsgIds = new HashSet<Integer>();\n    private static Set<Integer> s_qos12MsgIds = new HashSet<Integer>();\n    private static Set<Integer> s_qos12HighPriorityMsgIds = new HashSet<Integer>();\n\n    private static Lock s_lock = new ReentrantLock();\n    private static Condition s_connected = s_lock.newCondition();\n    private static Condition s_disconnecting = s_lock.newCondition();\n    private static Condition s_disconnected = s_lock.newCondition();\n    private static Condition s_arrived = s_lock.newCondition();\n\n    static final int MAX_MSGS = 100;\n    static final int ALL_CONFIRMED_QOS1_TIMEOUT = 60;\n    static final int ALL_CONFIRMED_QOS2_TIMEOUT = 120;\n    static final int DFLT_MSG_PRIORITY = 5;\n    static final int HIGH_MSG_PRIORITY = 0;\n    static final String MSG_SEMATIC_TOPIC1 = \"data/service/test/\" + UUID.randomUUID().toString();\n    static final String MSG_SEMATIC_TOPIC2 = \"data/service/test/\" + UUID.randomUUID().toString();\n    static final String MSG_TOPIC1 = \"#account-name/#client-id/\" + MSG_SEMATIC_TOPIC1;\n    static final String MSG_TOPIC2 = \"#account-name/#client-id/\" + MSG_SEMATIC_TOPIC2;\n    static final String MSG_PAYLOAD = \"Lorem ipsum dolor sit amet\";\n\n    @Test\n    public void testConnect() throws KuraConnectException {\n        connectDataService();\n    }\n\n    @Test\n    public void testDisconnect() throws KuraConnectException, InterruptedException {\n        connectDataService();\n\n        dataService.disconnect(0);\n        assertFalse(dataService.isConnected());\n\n        // TODO: if auto-connect is enabled check it does not\n        // automatically reconnects.\n\n        // test onConnectionEstablished\n        s_lock.lock();\n        try {\n            dataService.connect();\n            s_connected.await(30, TimeUnit.SECONDS);\n        } catch (KuraConnectException e) {\n            throw e;\n        } catch (InterruptedException e) {\n            throw e;\n        } finally {\n            s_lock.unlock();\n        }\n\n        // test onDisconnecting/onDisconnected\n        s_lock.lock();\n        dataService.disconnect(0);\n        s_disconnecting.await(1, TimeUnit.SECONDS);\n        s_disconnected.await(1, TimeUnit.SECONDS);\n        s_lock.unlock();\n    }\n\n    @Test\n    @Ignore // reason: don't know what this does with all the locks\n    public void testPublish() throws KuraConnectException, KuraStoreException {\n        connectDataService();\n\n        // publish at QoS = 0\n        synchronized (s_qos0MsgIds) {\n            s_qos0MsgIds.clear();\n        }\n\n        for (int i = 0; i < MAX_MSGS; i++) {\n            try {\n                synchronized (s_qos0MsgIds) {\n                    Integer id = dataService.publish(MSG_TOPIC1, MSG_PAYLOAD.getBytes(), 0, false, DFLT_MSG_PRIORITY);\n                    s_qos0MsgIds.add(id);\n                }\n            } catch (KuraStoreException e) {\n                break;\n            }\n        }\n\n        // publish at QoS = 1\n        synchronized (s_qos12MsgIds) {\n            s_qos12MsgIds.clear();\n        }\n\n        for (int i = 0; i < MAX_MSGS; i++) {\n            try {\n                synchronized (s_qos12MsgIds) {\n                    Integer id = dataService.publish(MSG_TOPIC1, MSG_PAYLOAD.getBytes(), 1, false, DFLT_MSG_PRIORITY);\n                    s_qos12MsgIds.add(id);\n                    logger.info(\"Added id: {}\", id);\n                }\n            } catch (KuraStoreException e) {\n                break;\n            }\n        }\n\n        boolean allConfirmed = false;\n        for (int i = 0; i < ALL_CONFIRMED_QOS1_TIMEOUT; i++) {\n            synchronized (s_qos12MsgIds) {\n                logger.info(\"confirm check round {}\", i);\n                s_qos12MsgIds.forEach(element -> logger.info(\"To confirm: {}\", element));\n                if (s_qos12MsgIds.isEmpty()) {\n                    allConfirmed = true;\n                    break;\n                }\n            }\n        }\n\n        logger.info(\"All confirmed value: {}\", allConfirmed);\n        assertTrue(allConfirmed);\n\n        // publish at QoS = 2\n        synchronized (s_qos12MsgIds) {\n            s_qos12MsgIds.clear();\n        }\n\n        for (int i = 0; i < MAX_MSGS; i++) {\n            try {\n                synchronized (s_qos12MsgIds) {\n                    Integer id = dataService.publish(MSG_TOPIC1, MSG_PAYLOAD.getBytes(), 2, false, DFLT_MSG_PRIORITY);\n                    s_qos12MsgIds.add(id);\n                }\n            } catch (KuraStoreException e) {\n                break;\n            }\n        }\n\n        allConfirmed = false;\n        for (int i = 0; i < ALL_CONFIRMED_QOS2_TIMEOUT; i++) {\n            synchronized (s_qos12MsgIds) {\n                if (s_qos12MsgIds.isEmpty()) {\n                    allConfirmed = true;\n                    break;\n                }\n            }\n        }\n\n        assertTrue(allConfirmed);\n\n        //\n        // publish at two different priorities at QoS = 1\n\n        // First publish half of the messages at default priority\n        synchronized (s_qos12MsgIds) {\n            s_qos12MsgIds.clear();\n        }\n\n        for (int i = 0; i < MAX_MSGS; i++) {\n            try {\n                synchronized (s_qos12MsgIds) {\n                    Integer id = dataService.publish(MSG_TOPIC1, MSG_PAYLOAD.getBytes(), 1, false, DFLT_MSG_PRIORITY);\n                    s_qos12MsgIds.add(id);\n                    logger.info(\"Added id: {}\", id);\n                }\n            } catch (KuraStoreException e) {\n                break;\n            }\n        }\n\n        // ... then publish half of the messages at higher priority\n        synchronized (s_qos12HighPriorityMsgIds) {\n            s_qos12HighPriorityMsgIds.clear();\n        }\n\n        for (int i = 0; i < MAX_MSGS; i++) {\n            try {\n                synchronized (s_qos12HighPriorityMsgIds) {\n                    Integer id = dataService.publish(MSG_TOPIC1, MSG_PAYLOAD.getBytes(), 1, false, HIGH_MSG_PRIORITY);\n                    s_qos12HighPriorityMsgIds.add(id);\n                }\n            } catch (KuraStoreException e) {\n                break;\n            }\n        }\n\n        // messages published at higher priority are expected to be\n        // confirmed before messages published at default priority\n        allConfirmed = false;\n        for (int i = 0; i < ALL_CONFIRMED_QOS1_TIMEOUT; i++) {\n            synchronized (s_qos12MsgIds) {\n                synchronized (s_qos12HighPriorityMsgIds) {\n                    logger.info(\"confirm check round {}\", i);\n                    s_qos12HighPriorityMsgIds\n                            .forEach(element -> logger.info(\"To confirm s_qos12HighPriorityMsgIds: {}\", element));\n                    s_qos12MsgIds.forEach(element -> logger.info(\"To confirm s_qos12MsgIds: {}\", element));\n                    if (!s_qos12HighPriorityMsgIds.isEmpty() && s_qos12MsgIds.isEmpty()) {\n                        fail(\"High priority messages should be confirmed before default priority messages\");\n                    } else if (s_qos12HighPriorityMsgIds.isEmpty() && s_qos12MsgIds.isEmpty()) {\n                        allConfirmed = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        logger.info(\"All confirmed value: {}\", allConfirmed);\n        assertTrue(allConfirmed);\n    }\n\n    @Test\n    @Ignore // reason: this can never work\n    public void testSubscribe() throws KuraException, InterruptedException {\n        connectDataService();\n\n        s_lock.lock();\n        try {\n            dataService.subscribe(MSG_TOPIC2, 0);\n            dataService.publish(MSG_TOPIC2, MSG_PAYLOAD.getBytes(), 0, false, HIGH_MSG_PRIORITY);\n            boolean arrived = s_arrived.await(5, TimeUnit.SECONDS);\n            assertTrue(\"Message did not arrive to subscriber\", arrived);\n        } catch (KuraException e) {\n            throw e;\n        } catch (InterruptedException e) {\n            throw e;\n        } finally {\n            s_lock.unlock();\n        }\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        s_lock.lock();\n        s_connected.signal();\n        s_lock.unlock();\n    }\n\n    @Override\n    public void onDisconnecting() {\n        s_lock.lock();\n        s_disconnecting.signal();\n        s_lock.unlock();\n    }\n\n    @Override\n    public void onDisconnected() {\n        s_lock.lock();\n        s_disconnected.signal();\n        s_lock.unlock();\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n        s_lock.lock();\n        if (topic.endsWith(MSG_SEMATIC_TOPIC2)) {\n            s_arrived.signal();\n        }\n        s_lock.unlock();\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        synchronized (s_qos0MsgIds) {\n            s_qos0MsgIds.remove(messageId);\n        }\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        synchronized (s_qos12MsgIds) {\n            s_qos12MsgIds.remove(messageId);\n        }\n        synchronized (s_qos12HighPriorityMsgIds) {\n            s_qos12HighPriorityMsgIds.remove(messageId);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/src/main/java/org/eclipse/kura/core/test/MqttDataTransportTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.fail;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.security.cert.X509CRL;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.core.testutil.event.EventAdminUtil;\nimport org.eclipse.kura.core.testutil.http.TestServer;\nimport org.eclipse.kura.core.testutil.pki.TestCA;\nimport org.eclipse.kura.core.testutil.pki.TestCA.CRLCreationOptions;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.eclipse.kura.security.keystore.KeystoreChangedEvent;\nimport org.eclipse.kura.util.wire.test.WireTestUtil;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\n\npublic class MqttDataTransportTest extends BaseCloudTests {\n\n    private static final String TEST_MQTT_DATA_TRANSPORT_PID = \"test\";\n    private static final String SSL_MANAGER_SERVICE_FACTORY_PID = \"org.eclipse.kura.ssl.SslManagerService\";\n    private static final String TEST_SSL_MANAGER_SERVICE_FILTER = \"(kura.service.pid=testSsl)\";\n    private static final String TEST_KEYSTORE_FILTER = \"(kura.service.pid=testKeystore)\";\n    private static final String TEST_TRUSTSTORE_FILTER = \"(kura.service.pid=testTruststore)\";\n    private static final String TEST_SSL_MANAGER_SERVICE_PID = \"testSsl\";\n    private static final String TEST_KEYSTORE_PID = \"testKeystore\";\n    private static final String TEST_TRUSTSTORE_PID = \"testTruststore\";\n    private static final String KEYSTORE_SERVICE_FACTORY_PID = \"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\";\n    private static final String MQTT_DATA_TRANSPORT_FACTORY_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    @Test\n    public void shouldConnectOverPlainMqtt() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n            final DataTransportService test = fixture.createFactoryConfiguration(DataTransportService.class,\n                    TEST_MQTT_DATA_TRANSPORT_PID, MQTT_DATA_TRANSPORT_FACTORY_PID, MqttDataTransportOptions\n                            .defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTT).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            test.connect();\n        }\n    }\n\n    @Test\n    public void shouldNotConnectOverMqttsWithoutKeystore() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n            final DataTransportService test = fixture.createFactoryConfiguration(DataTransportService.class,\n                    TEST_MQTT_DATA_TRANSPORT_PID, MQTT_DATA_TRANSPORT_FACTORY_PID, MqttDataTransportOptions\n                            .defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTTS).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            try {\n                test.connect();\n            } catch (final KuraConnectException e) {\n                return;\n            }\n\n            fail(\"connection should have failed\");\n        }\n    }\n\n    @Test\n    public void shouldNotConnectOverMqttsWithHostnameIdentificationEnabled() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withHostnameVerification(true)\n                            .withKeystoreTargetFilter(TEST_KEYSTORE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTTS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            try {\n                test.connect();\n            } catch (final KuraConnectException e) {\n                return;\n            }\n\n            fail(\"connection should have failed\");\n        }\n    }\n\n    @Test\n    public void shouldNotConnectOverWssWithHostnameIdentificationEnabled() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withHostnameVerification(true)\n                            .withKeystoreTargetFilter(TEST_KEYSTORE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_WSS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            try {\n                test.connect();\n            } catch (final KuraConnectException e) {\n                return;\n            }\n\n            fail(\"connection should have failed\");\n        }\n    }\n\n    @Test\n    public void shouldConnectOverMqttsWithHostnameIdentificationDisabled() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withHostnameVerification(false).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTTS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            test.connect();\n        }\n    }\n\n    @Test\n    public void shouldSupportRevocation() throws Exception {\n        final BundleContext bundleContext = FrameworkUtil.getBundle(MqttDataTransportTest.class).getBundleContext();\n\n        final TestServer server = new TestServer(8087, Optional.empty());\n\n        server.setResource(\"/crl.pem\", encodeCrl(brokerCA.generateCRL(CRLCreationOptions.builder().build())));\n\n        try (final Fixture fixture = new Fixture()) {\n\n            CompletableFuture<KeystoreChangedEvent> nextEvent = EventAdminUtil.nextEvent(\n                    new String[] { KeystoreChangedEvent.EVENT_TOPIC }, KeystoreChangedEvent.class, bundleContext);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID,\n                    KeystoreServiceOptions.defaultConfiguration().withKeystorePath(mqttTrustStore.getAbsolutePath())\n                            .withCrlManagerEnabled(true).withCrlUrls(new String[] { \"http://localhost:8087/crl.pem\" })\n                            .toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            nextEvent.get(10, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withHostnameVerification(false).withRevocationCheckEnabled(true)\n                            .withRevocationCheckMode(SslManagerServiceOptions.RevocationCheckMode.CRL_ONLY)\n                            .toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTTS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n\n            test.connect();\n\n            nextEvent = EventAdminUtil.nextEvent(new String[] { KeystoreChangedEvent.EVENT_TOPIC },\n                    KeystoreChangedEvent.class, bundleContext);\n\n            brokerCA.revokeCertificate(brokerCertificate);\n            server.setResource(\"/crl.pem\", encodeCrl(brokerCA.generateCRL(CRLCreationOptions.builder().build())));\n\n            nextEvent.get(10, TimeUnit.SECONDS);\n\n            test.disconnect(0);\n\n            try {\n                test.connect();\n            } catch (final KuraConnectException e) {\n                return;\n            }\n\n            fail(\"connection should have failed\");\n        } finally {\n            server.close();\n        }\n    }\n\n    private static byte[] encodeCrl(final X509CRL crl) throws IOException {\n        final byte[] crlData;\n\n        try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {\n            TestCA.encodeToPEM(crl, out);\n            crlData = out.toByteArray();\n        }\n\n        return crlData;\n    }\n\n    @Test\n    public void shouldConnectOverWssWithHostnameIdentificationDisabled() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withHostnameVerification(false).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_WSS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            test.connect();\n        }\n    }\n\n    @Test\n    @Ignore // reason: moquette broker not configured with truststore\n    public void shouldNotConnectOverMqttsWithClientSideAuthWithoutKey() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withHostnameVerification(false).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTTS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            try {\n                test.connect();\n            } catch (final KuraConnectException e) {\n                return;\n            }\n\n            fail(\"connection should have failed\");\n        }\n    }\n\n    @Test\n    @Ignore // reason: moquette broker not configured with truststore\n    public void shouldNotConnectOverWssWithClientSideAuthWithoutKey() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withHostnameVerification(false).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_WSS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            try {\n                test.connect();\n            } catch (final KuraConnectException e) {\n                return;\n            }\n\n            fail(\"connection should have failed\");\n        }\n    }\n\n    @Test\n    public void shouldConnectOverMqttsWithClientSideAuth() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttKeyStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withHostnameVerification(false).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTTS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            test.connect();\n        }\n    }\n\n    @Test\n    public void shouldConnectOverWssWithClientSideAuth() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttKeyStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withHostnameVerification(false).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_WSS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            test.connect();\n        }\n    }\n\n    @Test\n    public void shouldConnectOverWssWithClientSideAuthWithSeparateTruststore() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_TRUSTSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID,\n                    KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttKeyStoreKeyOnly.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withTruststoreTargetFilter(TEST_TRUSTSTORE_FILTER).withHostnameVerification(false)\n                            .toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_WSS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            test.connect();\n        }\n    }\n\n    @Test\n    public void shouldNotConnectOverWssWithClientSideAuthWithWrongTruststore() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_TRUSTSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withTruststoreTargetFilter(TEST_KEYSTORE_FILTER).withHostnameVerification(false)\n                            .toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_WSS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            try {\n                test.connect();\n            } catch (final KuraConnectException e) {\n                return;\n            }\n\n            fail(\"connection should have failed\");\n        }\n    }\n\n    @Test\n    public void shouldConnectOverMqttsWithClientSideAuthWithSeparateTruststore() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_TRUSTSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID,\n                    KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttKeyStoreKeyOnly.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withTruststoreTargetFilter(TEST_TRUSTSTORE_FILTER).withHostnameVerification(false)\n                            .toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTTS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            test.connect();\n        }\n    }\n\n    @Test\n    public void connectionShouldFailIfSeparateTruststoreIsUnset() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_TRUSTSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID,\n                    KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttKeyStoreKeyOnly.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withTruststoreTargetFilter(TEST_TRUSTSTORE_FILTER).withHostnameVerification(false)\n                            .toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTTS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            WireTestUtil\n                    .updateComponentConfiguration(configurationService, TEST_SSL_MANAGER_SERVICE_PID,\n                            SslManagerServiceOptions.defaultConfiguration()\n                                    .withTruststoreTargetFilter(\"(kura.service.pid=changeit)\").toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            try {\n                test.connect();\n            } catch (final KuraConnectException e) {\n                return;\n            }\n\n            fail(\"connection should have failed\");\n        }\n    }\n\n    @Test\n    public void shouldNotConnectOverMqttsWithClientSideAuthWithWrongTruststore() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_TRUSTSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttTrustStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withTruststoreTargetFilter(TEST_KEYSTORE_FILTER).withHostnameVerification(false)\n                            .toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_MQTTS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            try {\n                test.connect();\n            } catch (final KuraConnectException e) {\n                return;\n            }\n\n            fail(\"connection should have failed\");\n        }\n    }\n\n    @Test\n    public void connectionShouldFailWithRevocationChechEnabled() throws Exception {\n        try (final Fixture fixture = new Fixture()) {\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_KEYSTORE_PID,\n                    KEYSTORE_SERVICE_FACTORY_PID, KeystoreServiceOptions.defaultConfiguration()\n                            .withKeystorePath(mqttKeyStore.getAbsolutePath()).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            fixture.createFactoryConfiguration(ConfigurableComponent.class, TEST_SSL_MANAGER_SERVICE_PID,\n                    SSL_MANAGER_SERVICE_FACTORY_PID,\n                    SslManagerServiceOptions.defaultConfiguration().withKeystoreTargetFilter(TEST_KEYSTORE_FILTER)\n                            .withHostnameVerification(false).withRevocationCheckEnabled(true).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            final DataTransportService test = fixture\n                    .createFactoryConfiguration(DataTransportService.class, TEST_MQTT_DATA_TRANSPORT_PID,\n                            MQTT_DATA_TRANSPORT_FACTORY_PID,\n                            MqttDataTransportOptions.defaultConfiguration().withBrokerUrl(BROKER_ADDR_WSS)\n                                    .withSslManagerTargetFilter(TEST_SSL_MANAGER_SERVICE_FILTER).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n\n            assertNotNull(test);\n            test.connect();\n        }\n    }\n\n    private static class MqttDataTransportOptions {\n\n        private Optional<String> brokerUrl = Optional.empty();\n        private Optional<String> username = Optional.empty();\n        private Optional<String> password = Optional.empty();\n        private Optional<String> sslManagerTargetFilter = Optional.empty();\n\n        private MqttDataTransportOptions() {\n        }\n\n        static MqttDataTransportOptions defaultConfiguration() {\n            return new MqttDataTransportOptions().withUsername(\"mqtt\").withPassword(\"bar\");\n        }\n\n        MqttDataTransportOptions withBrokerUrl(final String arg) {\n            this.brokerUrl = Optional.of(arg);\n            return this;\n        }\n\n        MqttDataTransportOptions withUsername(final String arg) {\n            this.username = Optional.of(arg);\n            return this;\n        }\n\n        MqttDataTransportOptions withPassword(final String arg) {\n            this.password = Optional.of(arg);\n            return this;\n        }\n\n        MqttDataTransportOptions withSslManagerTargetFilter(final String arg) {\n            this.sslManagerTargetFilter = Optional.of(arg);\n            return this;\n        }\n\n        Map<String, Object> toProperties() {\n            final Map<String, Object> result = new HashMap<>();\n\n            this.brokerUrl.ifPresent(v -> result.put(\"broker-url\", v));\n            this.username.ifPresent(v -> result.put(\"username\", v));\n            this.password.ifPresent(v -> result.put(\"password\", v));\n            this.sslManagerTargetFilter.ifPresent(v -> result.put(\"SslManagerService.target\", v));\n\n            return result;\n        }\n    }\n\n    private static class SslManagerServiceOptions {\n\n        public enum RevocationCheckMode {\n            PREFER_OCSP,\n            PREFER_CRL,\n            CRL_ONLY\n        }\n\n        private Optional<Boolean> hostnameVerification = Optional.empty();\n        private Optional<String> keystoreTargetFilter = Optional.empty();\n        private Optional<String> truststoreTargetFilter = Optional.empty();\n        private Optional<Boolean> revocationCheckEnabled = Optional.empty();\n        private Optional<RevocationCheckMode> revocationCheckMode = Optional.empty();\n\n        private SslManagerServiceOptions() {\n        }\n\n        static SslManagerServiceOptions defaultConfiguration() {\n            return new SslManagerServiceOptions();\n        }\n\n        SslManagerServiceOptions withRevocationCheckEnabled(final boolean revocationCheckEnabled) {\n            this.revocationCheckEnabled = Optional.of(revocationCheckEnabled);\n            return this;\n        }\n\n        SslManagerServiceOptions withRevocationCheckMode(final RevocationCheckMode revocationCheckMode) {\n            this.revocationCheckMode = Optional.of(revocationCheckMode);\n            return this;\n        }\n\n        SslManagerServiceOptions withHostnameVerification(final boolean hostnameVerification) {\n            this.hostnameVerification = Optional.of(hostnameVerification);\n            return this;\n        }\n\n        SslManagerServiceOptions withKeystoreTargetFilter(final String keystoreTargetFilter) {\n            this.keystoreTargetFilter = Optional.of(keystoreTargetFilter);\n            return this;\n        }\n\n        SslManagerServiceOptions withTruststoreTargetFilter(final String truststoreTargetFilter) {\n            this.truststoreTargetFilter = Optional.of(truststoreTargetFilter);\n            return this;\n        }\n\n        Map<String, Object> toProperties() {\n            final Map<String, Object> result = new HashMap<>();\n\n            this.hostnameVerification.ifPresent(v -> result.put(\"ssl.hostname.verification\", v));\n            this.keystoreTargetFilter.ifPresent(v -> result.put(\"KeystoreService.target\", v));\n            this.truststoreTargetFilter.ifPresent(v -> result.put(\"TruststoreKeystoreService.target\", v));\n            this.revocationCheckEnabled.ifPresent(v -> result.put(\"ssl.revocation.check.enabled\", v));\n            this.revocationCheckMode.ifPresent(v -> result.put(\"ssl.revocation.mode\", v.name()));\n\n            return result;\n        }\n    }\n\n    private static class KeystoreServiceOptions {\n\n        private Optional<String> keystorePath = Optional.empty();\n        private Optional<String> keystorePassword = Optional.empty();\n        private boolean crlManagerEnabled = false;\n        private Optional<String[]> crlUrls = Optional.empty();\n\n        private KeystoreServiceOptions() {\n        }\n\n        static KeystoreServiceOptions defaultConfiguration() {\n            return new KeystoreServiceOptions();\n        }\n\n        KeystoreServiceOptions withCrlManagerEnabled(boolean crlManagerEnabled) {\n            this.crlManagerEnabled = crlManagerEnabled;\n            return this;\n        }\n\n        KeystoreServiceOptions withCrlUrls(String[] crlUrls) {\n            this.crlUrls = Optional.of(crlUrls);\n            return this;\n        }\n\n        KeystoreServiceOptions withKeystorePath(final String keystorePath) {\n            this.keystorePath = Optional.of(keystorePath);\n            return this;\n        }\n\n        Map<String, Object> toProperties() {\n            final Map<String, Object> result = new HashMap<>();\n\n            this.keystorePath.ifPresent(v -> result.put(\"keystore.path\", v));\n            this.keystorePassword.ifPresent(v -> result.put(\"keystore.password\", v));\n            result.put(\"crl.check.interval\", 1L);\n            result.put(\"crl.check.interval.time.unit\", TimeUnit.SECONDS.name());\n            result.put(\"crl.update.interval\", 1L);\n            result.put(\"crl.update.interval.time.unit\", TimeUnit.SECONDS.name());\n            result.put(\"crl.management.enabled\", crlManagerEnabled);\n            this.crlUrls.ifPresent(u -> result.put(\"crl.urls\", u));\n\n            return result;\n        }\n    }\n\n    private static class Fixture implements AutoCloseable {\n\n        private final Set<String> createdPids = new HashSet<>();\n\n        public <T> CompletableFuture<T> createFactoryConfiguration(final Class<T> classz, final String pid,\n                final String factoryPid, final Map<String, Object> properties) {\n            return WireTestUtil.createFactoryConfiguration(configurationService, classz, pid, factoryPid, properties)\n                    .whenComplete((ok, ex) -> {\n                        if (ex == null) {\n                            createdPids.add(pid);\n                        }\n                    });\n        }\n\n        @Override\n        public void close() throws Exception {\n\n            for (final String pid : createdPids) {\n                WireTestUtil.deleteFactoryConfiguration(configurationService, pid).get(30, TimeUnit.SECONDS);\n            }\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/src/test/java/org/eclipse/kura/core/data/DataServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.data;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyLong;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.message.store.StoredMessage;\nimport org.eclipse.kura.message.store.provider.MessageStore;\nimport org.eclipse.kura.message.store.provider.MessageStoreProvider;\nimport org.eclipse.kura.status.CloudConnectionStatusComponent;\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\nimport org.eclipse.kura.status.CloudConnectionStatusService;\nimport org.eclipse.kura.watchdog.WatchdogService;\nimport org.eclipse.paho.client.mqttv3.MqttException;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mockito;\nimport org.mockito.verification.VerificationMode;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.service.component.ComponentContext;\n\npublic class DataServiceImplTest {\n\n    private DataServiceImpl dataServiceImpl;\n    private DataTransportService dataTransportServiceMock;\n    private CloudConnectionStatusService ccssMock;\n    private Map<String, Object> properties;\n    private Optional<Exception> exception = Optional.empty();\n    private final MessageStoreProvider messageStoreProvider = Mockito.mock(MessageStoreProvider.class);\n    private final MessageStore messageStore = Mockito.mock(MessageStore.class);\n    private final List<StoredMessage> storedMessages = new ArrayList<>();\n\n    @Before\n    public void cleanUp() {\n        this.dataServiceImpl = null;\n        this.dataTransportServiceMock = null;\n        this.properties = new HashMap<>();\n    }\n\n    @Test\n    public void shouldHandleMessageStoreConnectedEventWithDtDisconnected() {\n\n        givenDataService();\n        givenDataTrasportServiceDisconnected();\n        givenAlwaysConnectedStrategy();\n        givenIsActive();\n\n        whenMessageStoreConnectionEventHappen();\n\n        thenStartConnectionTaskIsInvoked();\n    }\n\n    @Test\n    public void shouldHandleMessageStoreDisconnectedEventWithDtConnected() {\n        givenDataService();\n        givenDataTrasportServiceConnected();\n        givenIsActive();\n\n        whenMessageStoreDisconnectionEventHappen();\n\n        thenDataTrasportIsDisconnected();\n    }\n\n    @Test\n    public void shouldNotAllowNegativePriority() throws KuraStoreException {\n        givenDataService();\n        givenMessageStoreProvider();\n        givenDataTrasportServiceConnected();\n        givenIsActive();\n\n        whenMessageIsPublished(\"foo\", new byte[4], 0, false, -1);\n\n        thenExceptionIsThrown(IllegalArgumentException.class);\n        thenStoredMessageCountIs(0);\n    }\n    \n    @Test\n    public void shouldStoreMessagesWithNullPayload() throws KuraStoreException {\n        givenDataService();\n        givenMessageStoreProvider();\n        givenDataTrasportServiceConnected();\n        givenConfigurationProperty(\"maximum.payload.size\", 4L);\n        givenIsActive();\n\n        whenMessageIsPublished(\"foo\", null, 0, false, 9);\n\n        thenNoExceptionIsTrown();\n        thenMessageIsStored(0, \"foo\", null, 0, false, 9);\n    }\n\n    @Test\n    public void shouldStoreMessagesWithPayloadSizeLessThanConfiguredThreshold() throws KuraStoreException {\n        givenDataService();\n        givenMessageStoreProvider();\n        givenDataTrasportServiceConnected();\n        givenConfigurationProperty(\"maximum.payload.size\", 4L);\n        givenIsActive();\n\n        whenMessageIsPublished(\"foo\", new byte[3], 0, false, 9);\n\n        thenNoExceptionIsTrown();\n        thenMessageIsStored(0, \"foo\", new byte[3], 0, false, 9);\n    }\n\n    @Test\n    public void shouldStoreMessagesWithPayloadSizeEqualThanConfiguredThreshold() throws KuraStoreException {\n        givenDataService();\n        givenMessageStoreProvider();\n        givenDataTrasportServiceConnected();\n        givenConfigurationProperty(\"maximum.payload.size\", 4L);\n        givenIsActive();\n\n        whenMessageIsPublished(\"foo\", new byte[4], 0, false, 9);\n\n        thenNoExceptionIsTrown();\n        thenMessageIsStored(0, \"foo\", new byte[4], 0, false, 9);\n    }\n    \n    @Test\n    public void shouldNotDisconnectOnConfigChange() throws KuraStoreException {\n        givenDataService();\n        givenMessageStoreProvider();\n        givenDataTrasportServiceDisconnected();\n        givenConfigurationProperty(\"connect.auto-on-startup\", true);\n        givenIsActive();\n        givenDataTrasportServiceConnected();\n\n        whenConfigurationIsChanged(\"enable.recovery.on.connection.failure\", true);\n\n        thenDataTrasportStaysConnected();\n        thenCloudConnectionStatusServiceIsNotChanged();\n    }\n\n    @Test\n    public void shouldNotStoreMessagesWithPayloadSizeGreaterThanConfiguredThreshold() throws KuraStoreException {\n        givenDataService();\n        givenMessageStoreProvider();\n        givenDataTrasportServiceConnected();\n        givenConfigurationProperty(\"maximum.payload.size\", 4L);\n        givenIsActive();\n\n        whenMessageIsPublished(\"foo\", new byte[5], 0, false, 9);\n\n        thenExceptionIsThrown(KuraStoreException.class);\n        thenExceptionMessageContains(\"size exceeds\");\n    }\n\n    private void givenConfigurationProperty(final String key, final Object value) {\n        this.properties.put(key, value);\n    }\n\n    private void givenMessageStoreProvider() throws KuraStoreException {\n        Mockito.when(messageStoreProvider.openMessageStore(Mockito.any())).thenReturn(messageStore);\n        Mockito.when(messageStore.store(Mockito.anyString(), Mockito.any(), Mockito.anyInt(), Mockito.anyBoolean(),\n                Mockito.anyInt()))\n                .thenAnswer(i -> {\n                    this.storedMessages.add(new StoredMessage.Builder(0) //\n                            .withTopic(i.getArgument(0)) //\n                            .withPayload(i.getArgument(1)) //\n                            .withQos(i.getArgument(2)) //\n                            .withRetain(i.getArgument(3)) //\n                            .withPriority(i.getArgument(4)) //\n                            .build());\n                    return null;\n                });\n        this.dataServiceImpl.setMessageStoreProvider(messageStoreProvider);\n    }\n\n    private void givenIsActive() {\n        ComponentContext ctxMock = mock(ComponentContext.class);\n        when(ctxMock.getBundleContext()).thenReturn(mock(BundleContext.class));\n\n        this.dataServiceImpl.activate(ctxMock, this.properties);\n    }\n\n    private void givenAlwaysConnectedStrategy() {\n        this.properties.put(\"connect.auto-on-startup\", true);\n    }\n\n    private void givenDataTrasportServiceConnected() {\n        this.dataTransportServiceMock = mock(DataTransportService.class);\n        try {\n            TestUtil.setFieldValue(this.dataServiceImpl, \"dataTransportService\", this.dataTransportServiceMock);\n            when(this.dataTransportServiceMock.isConnected()).thenReturn(true);\n        } catch (NoSuchFieldException e) {\n            fail(e.getMessage());\n        }\n    }\n\n    private void givenDataTrasportServiceDisconnected() {\n        this.dataTransportServiceMock = mock(DataTransportService.class);\n        try {\n            TestUtil.setFieldValue(this.dataServiceImpl, \"dataTransportService\", this.dataTransportServiceMock);\n            when(this.dataTransportServiceMock.isConnected()).thenReturn(false);\n        } catch (NoSuchFieldException e) {\n            fail(e.getMessage());\n        }\n    }\n\n    private void givenDataService() {\n        this.dataServiceImpl = spy(new DataServiceImpl());\n\n        try {\n            DataServiceOptions dataServiceOptions = new DataServiceOptions(Collections.emptyMap());\n            MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n            MessageStore messageStoreMock = mock(MessageStore.class);\n            this.ccssMock = mock(CloudConnectionStatusService.class);\n            WatchdogService watchdogServiceMock = mock(WatchdogService.class);\n            initMockMessageStore(messageStoreProviderMock, messageStoreMock);\n            TestUtil.setFieldValue(this.dataServiceImpl, \"dataServiceOptions\", dataServiceOptions);\n            this.dataServiceImpl.setMessageStoreProvider(messageStoreProviderMock);\n            this.dataServiceImpl.setCloudConnectionStatusService(ccssMock);\n            this.dataServiceImpl.setWatchdogService(watchdogServiceMock);\n        } catch (NoSuchFieldException | KuraStoreException e) {\n            fail(e.getMessage());\n        }\n\n    }\n    \n    private void whenConfigurationIsChanged(final String key, final Object value) {\n        this.properties.put(key, value);\n        this.dataServiceImpl.updated(properties);\n    }\n\n    private void whenMessageIsPublished(final String topic, final byte[] payload, final int qos, final boolean retain,\n            final int priority) {\n        try {\n        this.dataServiceImpl.publish(topic, payload, qos, retain, priority);\n        } catch (final Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void whenMessageStoreDisconnectionEventHappen() {\n        this.dataServiceImpl.disconnected();\n    }\n\n    private void whenMessageStoreConnectionEventHappen() {\n        this.dataServiceImpl.connected();\n    }\n\n    private void thenDataTrasportIsDisconnected() {\n        verify(this.dataTransportServiceMock, times(1)).disconnect(anyLong());\n    }\n\n    private void thenDataTrasportIsConnected() {\n        try {\n            verify(this.dataTransportServiceMock, times(1)).connect();\n        } catch (KuraConnectException e) {\n            fail();\n        }\n    }\n    \n    private void thenDataTrasportStaysConnected() {\n        try {\n            verify(this.dataTransportServiceMock, times(0)).connect();\n        } catch (KuraConnectException e) {\n            fail();\n        }\n    }\n\n    private void thenCloudConnectionStatusServiceIsNotChanged() {\n        verify(this.ccssMock, times(1)).updateStatus(any(CloudConnectionStatusComponent.class), eq(CloudConnectionStatusEnum.SLOW_BLINKING));\n    }\n    \n    private void thenStartConnectionTaskIsInvoked() {\n        verify(this.dataServiceImpl, times(2)).startConnectionTask();\n    }\n\n    private void thenMessageIsStored(final int index, final String topic, final byte[] payload, final int qos, final boolean retain,\n            final int priority) {\n        final StoredMessage message = this.storedMessages.get(index);\n\n        assertEquals(topic, message.getTopic());\n        assertArrayEquals(payload, message.getPayload());\n        assertEquals(qos, message.getQos());\n        assertEquals(retain, message.isRetain());\n        assertEquals(priority, message.getPriority());\n    }\n\n    private void thenStoredMessageCountIs(final int expectedCount) {\n        assertEquals(expectedCount, this.storedMessages.size());\n    }\n\n    private void thenNoExceptionIsTrown() {\n        assertFalse(this.exception.isPresent());\n    }\n\n    private void thenExceptionIsThrown(final Class<?> classz) {\n        assertEquals(Optional.of(classz), this.exception.map(Object::getClass));\n    }\n\n    private void thenExceptionMessageContains(final String message) {\n        assertTrue(this.exception.filter(e -> e.getMessage().contains(message)).isPresent());\n    }\n\n    @Test\n    public void testStartDbStore() throws Throwable {\n        // test starting the store\n\n        final int hkInterval = 1000;\n        final int age = 100;\n        final int capacity = 5000;\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"store.housekeeper-interval\", hkInterval);\n        properties.put(\"store.purge-age\", age);\n        properties.put(\"store.capacity\", capacity);\n        properties.put(\"kura.service.pid\", \"foo\");\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(properties);\n\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        List<StoredMessage> messages = new ArrayList<>();\n        int id = 123;\n        int pmi = 1234;\n        String sessionId = \"session\";\n        StoredMessage msg = new StoredMessage.Builder(id).withDataTransportToken(new DataTransportToken(pmi, sessionId))\n                .build();\n        messages.add(msg);\n        when(messageStoreMock.getInFlightMessages()).thenReturn(messages);\n\n        // the actual invocation\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n\n        verify(messageStoreProviderMock, times(1)).openMessageStore(\"foo\");\n\n        @SuppressWarnings(\"unchecked\")\n        Map<DataTransportToken, Integer> ifMsgs = (Map<DataTransportToken, Integer>) TestUtil.getFieldValue(svc,\n                \"inFlightMsgIds\");\n\n        assertEquals(1, ifMsgs.size());\n        ifMsgs.forEach((key, value) -> {\n            assertEquals(id, (int) value);\n            assertEquals(pmi, key.getMessageId());\n            assertEquals(sessionId, key.getSessionId());\n        });\n    }\n\n    @Test\n    public void testConnectionEstablished() throws NoSuchFieldException, KuraStoreException {\n        // new session, don't publish in-flight messages\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        CloudConnectionStatusService ccssMock = mock(CloudConnectionStatusService.class);\n        svc.setCloudConnectionStatusService(ccssMock);\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock);\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n        DataServiceListenerS dataServiceListeners = new DataServiceListenerS(ctxMock);\n        TestUtil.setFieldValue(svc, \"dataServiceListeners\", dataServiceListeners);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"in-flight-messages.republish-on-new-session\", false);\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(properties);\n\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n\n        @SuppressWarnings(\"unchecked\")\n        Map<DataTransportToken, Integer> inFlightMsgIds = mock(Map.class);\n        TestUtil.setFieldValue(svc, \"inFlightMsgIds\", inFlightMsgIds);\n\n        svc.onConnectionEstablished(true);\n\n        verify(ccssMock, times(1)).updateStatus(svc, CloudConnectionStatusEnum.ON);\n        verify(messageStoreMock, times(1)).dropAllInFlightMessages();\n        verify(inFlightMsgIds, times(1)).clear();\n    }\n\n    @Test\n    public void testConnectionEstablishedErrorLog() throws NoSuchFieldException, KuraStoreException {\n        // new session, don't publish in-flight messages, trigger error log\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        CloudConnectionStatusService ccssMock = mock(CloudConnectionStatusService.class);\n        svc.setCloudConnectionStatusService(ccssMock);\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        DataTransportService dataTransportServiceMock = mock(DataTransportService.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock);\n\n        doThrow(new KuraStoreException(\"test\")).when(messageStoreMock).dropAllInFlightMessages();\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n        DataServiceListenerS dataServiceListeners = new DataServiceListenerS(ctxMock);\n        TestUtil.setFieldValue(svc, \"dataServiceListeners\", dataServiceListeners);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"in-flight-messages.republish-on-new-session\", false);\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(properties);\n\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        @SuppressWarnings(\"unchecked\")\n        Map<DataTransportToken, Integer> inFlightMsgIds = mock(Map.class);\n        TestUtil.setFieldValue(svc, \"inFlightMsgIds\", inFlightMsgIds);\n\n        svc.setDataTransportService(dataTransportServiceMock);\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n        svc.onConnectionEstablished(true);\n\n        verify(ccssMock, times(1)).updateStatus(svc, CloudConnectionStatusEnum.ON);\n        verify(messageStoreMock, times(1)).dropAllInFlightMessages();\n        verify(inFlightMsgIds, times(0)).clear();\n    }\n\n    @Test\n    public void testConnectionEstablishedWithPublish() throws NoSuchFieldException, KuraStoreException {\n        // new session, publish in-flight messages\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        CloudConnectionStatusService ccssMock = mock(CloudConnectionStatusService.class);\n        svc.setCloudConnectionStatusService(ccssMock);\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock);\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n        DataServiceListenerS dataServiceListeners = new DataServiceListenerS(ctxMock);\n        TestUtil.setFieldValue(svc, \"dataServiceListeners\", dataServiceListeners);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"in-flight-messages.republish-on-new-session\", true);\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(properties);\n\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n\n        @SuppressWarnings(\"unchecked\")\n        Map<DataTransportToken, Integer> inFlightMsgIds = mock(Map.class);\n        TestUtil.setFieldValue(svc, \"inFlightMsgIds\", inFlightMsgIds);\n\n        svc.onConnectionEstablished(true);\n\n        verify(ccssMock, times(1)).updateStatus(svc, CloudConnectionStatusEnum.ON);\n        verify(messageStoreMock, times(1)).unpublishAllInFlighMessages();\n        verify(inFlightMsgIds, times(1)).clear();\n    }\n\n    @Test\n    public void testConnectionEstablishedWithPublishErrorLog() throws NoSuchFieldException, KuraStoreException {\n        // new session, publish in-flight messages, trigger error log\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        CloudConnectionStatusService ccssMock = mock(CloudConnectionStatusService.class);\n        svc.setCloudConnectionStatusService(ccssMock);\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        DataTransportService dataTransportServiceMock = mock(DataTransportService.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock);\n\n        doThrow(new KuraStoreException(\"test\")).when(messageStoreMock).unpublishAllInFlighMessages();\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n        DataServiceListenerS dataServiceListeners = new DataServiceListenerS(ctxMock);\n        TestUtil.setFieldValue(svc, \"dataServiceListeners\", dataServiceListeners);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"in-flight-messages.republish-on-new-session\", true);\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(properties);\n\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        @SuppressWarnings(\"unchecked\")\n        Map<DataTransportToken, Integer> inFlightMsgIds = mock(Map.class);\n        TestUtil.setFieldValue(svc, \"inFlightMsgIds\", inFlightMsgIds);\n\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n        svc.setDataTransportService(dataTransportServiceMock);\n        svc.onConnectionEstablished(true);\n\n        verify(ccssMock, times(1)).updateStatus(svc, CloudConnectionStatusEnum.ON);\n        verify(messageStoreMock, times(1)).unpublishAllInFlighMessages();\n        verify(inFlightMsgIds, times(0)).clear();\n    }\n\n    @Test\n    public void testActivateAndConnect() throws NoSuchFieldException, InterruptedException, KuraStoreException {\n        // stop and start connection monitor task scheduling the executor, wait for it\n        // to run a couple of times, then\n        // connect\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock);\n\n        ScheduledFuture<?> connectionMonitorFutureMock = mock(ScheduledFuture.class);\n        TestUtil.setFieldValue(svc, \"connectionMonitorFuture\", connectionMonitorFutureMock);\n        when(connectionMonitorFutureMock.isDone()).thenReturn(false).thenReturn(true);\n\n        CloudConnectionStatusService ccssMock = mock(CloudConnectionStatusService.class);\n        svc.setCloudConnectionStatusService(ccssMock);\n\n        WatchdogService wsMock = mock(WatchdogService.class);\n        svc.setWatchdogService(wsMock);\n\n        Object lock = new Object();\n        doAnswer(invocation -> {\n            synchronized (lock) {\n                lock.notifyAll();\n            }\n            return null;\n        }).when(wsMock).unregisterCriticalComponent(svc);\n\n        ScheduledExecutorService cme = Executors.newSingleThreadScheduledExecutor();\n        TestUtil.setFieldValue(svc, \"connectionMonitorExecutor\", cme);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"connect.auto-on-startup\", true);\n        properties.put(\"connect.retry-interval\", 2);\n        properties.put(\"kura.service.pid\", \"foo\");\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(properties);\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n        when(ctxMock.getBundleContext()).thenReturn(mock(BundleContext.class));\n        DataServiceListenerS dataServiceListeners = new DataServiceListenerS(ctxMock);\n        TestUtil.setFieldValue(svc, \"dataServiceListeners\", dataServiceListeners);\n\n        DataTransportService dtsMock = mock(DataTransportService.class);\n        TestUtil.setFieldValue(svc, \"dataTransportService\", dtsMock);\n        when(dtsMock.isConnected()).thenReturn(false); // trigger call to connect()\n\n        svc.activate(ctxMock, properties);\n\n        // attach a H2DbService after a while\n        // add also DataTransportService - to report it's not connected\n        Thread.sleep(3000);\n\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n\n        synchronized (lock) {\n            lock.wait(20000);\n        }\n\n        verify(wsMock, times(1)).unregisterCriticalComponent(svc);\n    }\n\n    @Test\n    public void testActivateAndFailConnecting()\n            throws NoSuchFieldException, InterruptedException, KuraConnectException, KuraStoreException {\n        // stop and start connection monitor task scheduling the executor, then try to\n        // connect and fail with\n        // authentication exceptions and a few more\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        ScheduledFuture<?> connectionMonitorFutureMock = mock(ScheduledFuture.class);\n        TestUtil.setFieldValue(svc, \"connectionMonitorFuture\", connectionMonitorFutureMock);\n        when(connectionMonitorFutureMock.isDone()).thenReturn(false).thenReturn(true);\n\n        CloudConnectionStatusService ccssMock = mock(CloudConnectionStatusService.class);\n        svc.setCloudConnectionStatusService(ccssMock);\n\n        WatchdogService wsMock = mock(WatchdogService.class);\n        svc.setWatchdogService(wsMock);\n\n        AtomicInteger count = new AtomicInteger(0);\n        Object lock = new Object();\n        doAnswer(invocation -> {\n            if (count.incrementAndGet() > 8) { // shouldn't happen\n                synchronized (lock) {\n                    lock.notifyAll();\n                }\n            }\n            return null;\n        }).when(wsMock).checkin(svc);\n\n        ScheduledExecutorService cme = Executors.newSingleThreadScheduledExecutor();\n        TestUtil.setFieldValue(svc, \"connectionMonitorExecutor\", cme);\n\n        // executor service parameters\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"connect.auto-on-startup\", true);\n        properties.put(\"connect.retry-interval\", 1);\n        properties.put(\"connection.recovery.max.failures\", 4);\n        properties.put(\"kura.service.pid\", \"foo\");\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(properties);\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n        when(ctxMock.getBundleContext()).thenReturn(mock(BundleContext.class));\n        DataServiceListenerS dataServiceListeners = new DataServiceListenerS(ctxMock);\n        TestUtil.setFieldValue(svc, \"dataServiceListeners\", dataServiceListeners);\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock);\n\n        // for connection monitor task to try connecting and fail\n        DataTransportService dtsMock = mock(DataTransportService.class);\n        TestUtil.setFieldValue(svc, \"dataTransportService\", dtsMock);\n        when(dtsMock.isConnected()).thenReturn(false); // trigger call to connect()\n\n        // for the exception to be verified as non-critical: 1-3: authentication exc.,\n        // 4.-: ordinary exceptions\n        MqttException cause = new MqttException(MqttException.REASON_CODE_FAILED_AUTHENTICATION);\n        Throwable exc1 = new KuraConnectException(cause, \"test\");\n        cause = new MqttException(MqttException.REASON_CODE_INVALID_CLIENT_ID);\n        Throwable exc2 = new KuraConnectException(cause, \"test\");\n        cause = new MqttException(MqttException.REASON_CODE_NOT_AUTHORIZED);\n        Throwable exc3 = new KuraConnectException(cause, \"test\");\n        cause = new MqttException(MqttException.REASON_CODE_BROKER_UNAVAILABLE);\n        Throwable exc4 = new KuraConnectException(cause, \"test\");\n        doThrow(exc1).doThrow(exc2).doThrow(exc3).doThrow(exc4)\n                .doThrow(new KuraConnectException(\"test ordinary exception\")).when(dtsMock).connect();\n\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n        svc.activate(ctxMock, properties);\n\n        // wait long enough for the task can run 7-8 times\n        synchronized (lock) {\n            lock.wait(8000);\n        }\n\n        // initial checkin + 3 * authentication + (other mqtt + 3)\n        assertEquals(8, count.intValue());\n    }\n\n    @Test\n    public void testMessageConfirmedNoMessageFound() throws NoSuchFieldException {\n        // invokes the logger - inflight message not found\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        int msgId = 1234;\n        String sessionId = \"sess1234\";\n        DataTransportToken token = new DataTransportToken(msgId, sessionId);\n\n        Map<DataTransportToken, Integer> inFlightMsgIds = new HashMap<>();\n        TestUtil.setFieldValue(svc, \"inFlightMsgIds\", inFlightMsgIds);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"in-flight-messages.max-number\", 0);\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(properties);\n\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        svc.onMessageConfirmed(token);\n    }\n\n    @Test\n    public void testMessageConfirmedConfirmedMessageException() throws NoSuchFieldException, KuraStoreException {\n        // invokes the logger - confirmed message not found\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        int msgId = 1234;\n        String sessionId = \"sess1234\";\n        DataTransportToken token = new DataTransportToken(msgId, sessionId);\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        DataTransportService dataTransportServiceMock = mock(DataTransportService.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock);\n\n        doThrow(new KuraStoreException(\"test\")).when(messageStoreMock).markAsConfirmed(msgId);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"in-flight-messages.max-number\", 0);\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(properties);\n\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n        svc.setDataTransportService(dataTransportServiceMock);\n\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n\n        Map<DataTransportToken, Integer> inFlightMsgIds = new HashMap<>();\n        inFlightMsgIds.put(token, msgId);\n        TestUtil.setFieldValue(svc, \"inFlightMsgIds\", inFlightMsgIds);\n\n        svc.onMessageConfirmed(token);\n\n        verify(messageStoreMock, times(1)).markAsConfirmed(msgId);\n    }\n\n    @Test\n    public void testGetUnpublishedMessageIds() throws NoSuchFieldException, KuraStoreException {\n        // build message ids from unpublished list\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(Collections.emptyMap());\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        List<StoredMessage> unpublished = new ArrayList<>();\n        StoredMessage msg = new StoredMessage.Builder(1).withTopic(\"notpublished\").build();\n        unpublished.add(msg);\n        msg = new StoredMessage.Builder(2).withTopic(\"unpublished\").build();\n        unpublished.add(msg);\n\n        List<StoredMessage> inflight = new ArrayList<>();\n        msg = new StoredMessage.Builder(3).withTopic(\"unpublished\").build();\n        inflight.add(msg);\n\n        List<StoredMessage> dropped = new ArrayList<>();\n        msg = new StoredMessage.Builder(4).withTopic(\"unpublished\").build();\n        inflight.add(msg);\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock, unpublished, inflight, dropped);\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n\n        String topic = \"unp.*\";\n\n        List<Integer> ids = svc.getUnpublishedMessageIds(topic);\n\n        assertEquals(1, ids.size());\n        assertEquals(2, (int) ids.get(0));\n    }\n\n    @Test\n    public void testGetInFlightMessageIds() throws NoSuchFieldException, KuraStoreException {\n        // build message ids from in-flight list\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(Collections.emptyMap());\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        List<StoredMessage> unpublished = new ArrayList<>();\n        StoredMessage msg = new StoredMessage.Builder(1).withTopic(\"inf\").build();\n        unpublished.add(msg);\n        msg = new StoredMessage.Builder(2).withTopic(\"unpub\").build();\n        unpublished.add(msg);\n\n        List<StoredMessage> inflight = new ArrayList<>();\n        msg = new StoredMessage.Builder(3).withTopic(\"unpublished\").build();\n        inflight.add(msg);\n        msg = new StoredMessage.Builder(4).withTopic(\"info\").build();\n        inflight.add(msg);\n\n        List<StoredMessage> dropped = new ArrayList<>();\n        msg = new StoredMessage.Builder(5).withTopic(\"inf\").build();\n        dropped.add(msg);\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock, unpublished, inflight, dropped);\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n\n        String topic = \"inf.*\";\n\n        List<Integer> ids = svc.getInFlightMessageIds(topic);\n\n        assertEquals(1, ids.size());\n        assertEquals(4, (int) ids.get(0));\n    }\n\n    @Test\n    public void testGetDroppedMessageIds() throws NoSuchFieldException, KuraStoreException {\n        // build message ids from the dropped list\n\n        DataServiceImpl svc = new DataServiceImpl();\n\n        DataServiceOptions dataServiceOptions = new DataServiceOptions(Collections.emptyMap());\n        TestUtil.setFieldValue(svc, \"dataServiceOptions\", dataServiceOptions);\n\n        List<StoredMessage> unpublished = new ArrayList<>();\n        StoredMessage msg = new StoredMessage.Builder(1).withTopic(\"someone dropped it\").build();\n        unpublished.add(msg);\n        msg = new StoredMessage.Builder(2).withTopic(\"unpub\").build();\n        unpublished.add(msg);\n\n        List<StoredMessage> inflight = new ArrayList<>();\n        msg = new StoredMessage.Builder(3).withTopic(\"unpublished\").build();\n        inflight.add(msg);\n        msg = new StoredMessage.Builder(4).withTopic(\"info\").build();\n        inflight.add(msg);\n        msg = new StoredMessage.Builder(5).withTopic(\"not dropped\").build();\n        inflight.add(msg);\n\n        List<StoredMessage> dropped = new ArrayList<>();\n        msg = new StoredMessage.Builder(6).withTopic(\"great drop\").build();\n        dropped.add(msg);\n        msg = new StoredMessage.Builder(7).withTopic(\"do not drop it\").build();\n        dropped.add(msg);\n\n        MessageStoreProvider messageStoreProviderMock = mock(MessageStoreProvider.class);\n        MessageStore messageStoreMock = mock(MessageStore.class);\n        initMockMessageStore(messageStoreProviderMock, messageStoreMock, unpublished, inflight, dropped);\n        svc.setMessageStoreProvider(messageStoreProviderMock);\n\n        String topic = \".*drop\";\n\n        List<Integer> ids = svc.getDroppedInFlightMessageIds(topic);\n\n        assertEquals(1, ids.size());\n        assertEquals(6, (int) ids.get(0));\n    }\n\n    private void initMockMessageStore(final MessageStoreProvider messageStoreProviderMock,\n            final MessageStore messageStoreMock, List<StoredMessage> unpublished,\n            List<StoredMessage> inFlight, List<StoredMessage> dropped) throws KuraStoreException {\n\n        when(messageStoreProviderMock.openMessageStore(ArgumentMatchers.any())).thenReturn(messageStoreMock);\n\n        when(messageStoreMock.getUnpublishedMessages()).thenReturn(unpublished);\n        when(messageStoreMock.getInFlightMessages()).thenReturn(inFlight);\n        when(messageStoreMock.getDroppedMessages()).thenReturn(dropped);\n\n    }\n\n    private void initMockMessageStore(final MessageStoreProvider messageStoreProvider, final MessageStore messageStore)\n            throws KuraStoreException {\n        initMockMessageStore(messageStoreProvider, messageStore, Collections.emptyList(), Collections.emptyList(),\n                Collections.emptyList());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/src/test/java/org/eclipse/kura/core/data/DataServiceOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.core.data;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.db.H2DbService;\nimport org.junit.Test;\n\npublic class DataServiceOptionsTest {\n\n    private static final String AUTOCONNECT_PROP_NAME = \"connect.auto-on-startup\";\n    private static final String CONNECT_DELAY_PROP_NAME = \"connect.retry-interval\";\n    private static final String DISCONNECT_DELAY_PROP_NAME = \"disconnect.quiesce-timeout\";\n    private static final String STORE_DB_SERVICE_INSTANCE_PROP_NAME = \"store.db.service.pid\";\n    private static final String STORE_HOUSEKEEPER_INTERVAL_PROP_NAME = \"store.housekeeper-interval\";\n    private static final String STORE_PURGE_AGE_PROP_NAME = \"store.purge-age\";\n    private static final String STORE_CAPACITY_PROP_NAME = \"store.capacity\";\n    private static final String REPUBLISH_IN_FLIGHT_MSGS_PROP_NAME = \"in-flight-messages.republish-on-new-session\";\n    private static final String MAX_IN_FLIGHT_MSGS_PROP_NAME = \"in-flight-messages.max-number\";\n    private static final String IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_PROP_NAME = \"in-flight-messages.congestion-timeout\";\n    private static final String RATE_LIMIT_ENABLE_PROP_NAME = \"enable.rate.limit\";\n    private static final String RATE_LIMIT_AVERAGE_RATE_PROP_NAME = \"rate.limit.average\";\n    private static final String RATE_LIMIT_TIME_UNIT_PROP_NAME = \"rate.limit.time.unit\";\n    private static final String RATE_LIMIT_BURST_SIZE_PROP_NAME = \"rate.limit.burst.size\";\n    private static final String RECOVERY_ENABLE_PROP_NAME = \"enable.recovery.on.connection.failure\";\n    private static final String RECOVERY_MAX_FAILURES_PROP_NAME = \"connection.recovery.max.failures\";\n    private static final String CONNECTION_SCHEDULE_ENABLED = \"connection.schedule.enabled\";\n    private static final String CONNECTION_SCHECULE_EXPRESSION = \"connection.schedule.expression\";\n    private static final String CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS = \"connection.schedule.inactivity.interval.seconds\";\n    private static final String CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE = \"connection.schedule.priority.override.enable\";\n    private static final String CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD = \"connection.schedule.priority.override.threshold\";\n\n    private static final boolean AUTOCONNECT_PROP_DEFAULT = false;\n    private static final int CONNECT_DELAY_DEFAULT = 60;\n    private static final int DISCONNECT_DELAY_DEFAULT = 10;\n    private static final String DB_SERVICE_INSTANCE_DEFAULT = H2DbService.DEFAULT_INSTANCE_PID;\n    private static final int STORE_HOUSEKEEPER_INTERVAL_DEFAULT = 900;\n    private static final int STORE_PURGE_AGE_DEFAULT = 60;\n    private static final int STORE_CAPACITY_DEFAULT = 10000;\n    private static final boolean REPUBLISH_IN_FLIGHT_MSGS_DEFAULT = true;\n    private static final int MAX_IN_FLIGHT_MSGS_DEFAULT = 9;\n    private static final int IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_DEFAULT = 0;\n    private static final boolean RATE_LIMIT_ENABLE_DEFAULT = true;\n    private static final int RATE_LIMIT_AVERAGE_RATE_DEFAULT = 1;\n    private static final int RATE_LIMIT_BURST_SIZE_DEFAULT = 1;\n    private static final boolean RECOVERY_ENABLE_DEFAULT = true;\n    private static final int RECOVERY_MAX_FAILURES_DEFAULT = 10;\n    private static final boolean CONNECTION_SCHEDULE_ENABLED_DEFAULT = false;\n    private static final boolean CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE_DEFAULT = false;\n    private static final int CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD_DEFAULT = 1;\n\n    private static final boolean AUTOCONNECT_PROP_CHANGED = true;\n    private static final int CONNECT_DELAY_CHANGED = 65;\n    private static final int DISCONNECT_DELAY_CHANGED = 15;\n    private static final String DB_SERVICE_INSTANCE_CHANGED = H2DbService.DEFAULT_INSTANCE_PID;\n    private static final int STORE_HOUSEKEEPER_INTERVAL_CHANGED = 950;\n    private static final int STORE_PURGE_AGE_CHANGED = 65;\n    private static final int STORE_CAPACITY_CHANGED = 10050;\n    private static final boolean REPUBLISH_IN_FLIGHT_MSGS_CHANGED = true;\n    private static final int MAX_IN_FLIGHT_MSGS_CHANGED = 5;\n    private static final int IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_CHANGED = 1;\n    private static final boolean RATE_LIMIT_ENABLE_CHANGED = false;\n    private static final int RATE_LIMIT_AVERAGE_RATE_CHANGED = 2;\n    private static final int RATE_LIMIT_BURST_SIZE_CHANGED = 2;\n    private static final boolean RECOVERY_ENABLE_CHANGED = false;\n    private static final int RECOVERY_MAX_FAILURES_CHANGED = 15;\n    private static final boolean CONNECTION_SCHEDULE_ENABLED_CHANGED = true;\n    private static final boolean CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE_CHANGED = true;\n    private static final int CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD_CHANGED = 2;\n\n    private static final int CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS_CHANGED = 5;\n    private static final String RATE_LIMIT_TIME_UNIT_PROP_NAME_CHANGED = \"MILLISECONDS\";\n    private static final String CONNECTION_SCHECULE_EXPRESSION_CHANGED = \"0 0 0 ? * * *\";\n\n    private DataServiceOptions dataServiceOptions;\n    Map<String, Object> properties;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldReturnDefaultsTest() {\n        givenEmptyProperties();\n        whenDataServiceOptionsIsCreated();\n        thenCheckIfAllDefaultsAreSet();\n\n    }\n\n    @Test\n    public void shouldReturnChangedTest() {\n        givenFullChangedProperties();\n        whenDataServiceOptionsIsCreated();\n        thenCheckIfAllChangesAreSet();\n\n    }\n\n    @Test\n    public void shouldReturnTrueToPriorityOverrideEnabled() {\n        givenPropertiesThatEnableOverrideSchedule();\n        whenDataServiceOptionsIsCreated();\n        thenConnectionScheduleEnabled();\n        thenCheckpriorityEquals(3);\n    }\n\n    @Test\n    public void shouldReturnTrueToPriorityOverrideDisabled() {\n        givenPropertiesThatDisableOverrideSchedule();\n        whenDataServiceOptionsIsCreated();\n        thenConnectionScheduleDisabled();\n        thenCheckpriorityEquals(3);\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenPropertiesThatEnableOverrideSchedule() {\n        // Create DataServiceOptions\n        properties = new HashMap<>();\n\n        properties.put(\"connection.schedule.priority.override.enable\", true);\n        properties.put(\"connection.schedule.priority.override.threshold\", 3);\n        properties.put(\"connect.auto-on-startup\", true);\n        properties.put(\"connection.schedule.inactivity.interval.seconds\", 2);\n        properties.put(\"connection.schedule.enabled\", true);\n        properties.put(\"connection.schedule.expression\", \"0 0 0 ? * * *\");\n    }\n\n    private void givenPropertiesThatDisableOverrideSchedule() {\n        // Create DataServiceOptions\n        properties = new HashMap<>();\n\n        properties.put(\"connection.schedule.priority.override.enable\", false);\n        properties.put(\"connection.schedule.priority.override.threshold\", 3);\n        properties.put(\"connect.auto-on-startup\", false);\n        properties.put(\"connection.schedule.inactivity.interval.seconds\", 2);\n        properties.put(\"connection.schedule.enabled\", false);\n    }\n\n    private void givenEmptyProperties() {\n        // Create DataServiceOptions\n        properties = new HashMap<>();\n    }\n\n    private void givenFullChangedProperties() {\n        // Create DataServiceOptions\n        properties = new HashMap<>();\n\n        properties.put(AUTOCONNECT_PROP_NAME, AUTOCONNECT_PROP_CHANGED);\n        properties.put(CONNECT_DELAY_PROP_NAME, CONNECT_DELAY_CHANGED);\n        properties.put(DISCONNECT_DELAY_PROP_NAME, DISCONNECT_DELAY_CHANGED);\n        properties.put(STORE_DB_SERVICE_INSTANCE_PROP_NAME, DB_SERVICE_INSTANCE_CHANGED);\n        properties.put(STORE_HOUSEKEEPER_INTERVAL_PROP_NAME, STORE_HOUSEKEEPER_INTERVAL_CHANGED);\n        properties.put(STORE_PURGE_AGE_PROP_NAME, STORE_PURGE_AGE_CHANGED);\n        properties.put(STORE_CAPACITY_PROP_NAME, STORE_CAPACITY_CHANGED);\n        properties.put(REPUBLISH_IN_FLIGHT_MSGS_PROP_NAME, REPUBLISH_IN_FLIGHT_MSGS_CHANGED);\n        properties.put(MAX_IN_FLIGHT_MSGS_PROP_NAME, MAX_IN_FLIGHT_MSGS_CHANGED);\n        properties.put(IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_PROP_NAME, IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_CHANGED);\n        properties.put(RATE_LIMIT_ENABLE_PROP_NAME, RATE_LIMIT_ENABLE_CHANGED);\n        properties.put(RATE_LIMIT_AVERAGE_RATE_PROP_NAME, RATE_LIMIT_AVERAGE_RATE_CHANGED);\n        properties.put(RATE_LIMIT_TIME_UNIT_PROP_NAME, RATE_LIMIT_TIME_UNIT_PROP_NAME_CHANGED);\n        properties.put(RATE_LIMIT_BURST_SIZE_PROP_NAME, RATE_LIMIT_BURST_SIZE_CHANGED);\n        properties.put(RECOVERY_ENABLE_PROP_NAME, RECOVERY_ENABLE_CHANGED);\n        properties.put(RECOVERY_MAX_FAILURES_PROP_NAME, RECOVERY_MAX_FAILURES_CHANGED);\n        properties.put(CONNECTION_SCHEDULE_ENABLED, CONNECTION_SCHEDULE_ENABLED_CHANGED);\n        properties.put(CONNECTION_SCHECULE_EXPRESSION, CONNECTION_SCHECULE_EXPRESSION_CHANGED);\n        properties.put(CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS,\n                CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS_CHANGED);\n        properties.put(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE,\n                CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE_CHANGED);\n        properties.put(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD,\n                CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD_CHANGED);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenDataServiceOptionsIsCreated() {\n        this.dataServiceOptions = new DataServiceOptions(properties);\n    }\n\n    /*\n     * Then\n     */\n    private void thenConnectionScheduleEnabled() {\n        assertTrue(this.dataServiceOptions.isConnectionSchedulePriorityOverrideEnabled());\n    }\n\n    private void thenConnectionScheduleDisabled() {\n        assertFalse(this.dataServiceOptions.isConnectionSchedulePriorityOverrideEnabled());\n    }\n\n    private void thenCheckpriorityEquals(int priority) {\n        assertEquals(this.dataServiceOptions.getConnectionSchedulePriorityOverridePriority(), priority);\n    }\n\n    private void thenCheckIfAllDefaultsAreSet() {\n\n        assertEquals(AUTOCONNECT_PROP_DEFAULT, this.dataServiceOptions.isAutoConnect());\n        assertEquals(CONNECT_DELAY_DEFAULT, this.dataServiceOptions.getConnectDelay());\n        assertEquals(DISCONNECT_DELAY_DEFAULT, this.dataServiceOptions.getDisconnectDelay());\n        assertEquals(DB_SERVICE_INSTANCE_DEFAULT, this.dataServiceOptions.getDbServiceInstancePid());\n        assertEquals(STORE_HOUSEKEEPER_INTERVAL_DEFAULT, this.dataServiceOptions.getStoreHousekeeperInterval());\n        assertEquals(STORE_PURGE_AGE_DEFAULT, this.dataServiceOptions.getStorePurgeAge());\n        assertEquals(STORE_CAPACITY_DEFAULT, this.dataServiceOptions.getStoreCapacity());\n        assertEquals(REPUBLISH_IN_FLIGHT_MSGS_DEFAULT, this.dataServiceOptions.isPublishInFlightMessages());\n        assertEquals(MAX_IN_FLIGHT_MSGS_DEFAULT, this.dataServiceOptions.getMaxInFlightMessages());\n        assertEquals(IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_DEFAULT,\n                this.dataServiceOptions.getInFlightMessagesCongestionTimeout());\n        assertEquals(RATE_LIMIT_ENABLE_DEFAULT, this.dataServiceOptions.isRateLimitEnabled());\n        assertEquals(RATE_LIMIT_AVERAGE_RATE_DEFAULT, this.dataServiceOptions.getRateLimitAverageRate());\n        assertEquals(RATE_LIMIT_BURST_SIZE_DEFAULT, this.dataServiceOptions.getRateLimitBurstSize());\n        assertEquals(RECOVERY_ENABLE_DEFAULT, this.dataServiceOptions.isConnectionRecoveryEnabled());\n        assertEquals(RECOVERY_MAX_FAILURES_DEFAULT, this.dataServiceOptions.getRecoveryMaximumAllowedFailures());\n        assertEquals(CONNECTION_SCHEDULE_ENABLED_DEFAULT, this.dataServiceOptions.isConnectionScheduleEnabled());\n        assertEquals(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE_DEFAULT,\n                this.dataServiceOptions.isConnectionSchedulePriorityOverrideEnabled());\n        assertEquals(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD_DEFAULT,\n                this.dataServiceOptions.getConnectionSchedulePriorityOverridePriority());\n    }\n\n    private void thenCheckIfAllChangesAreSet() {\n\n        assertEquals(AUTOCONNECT_PROP_CHANGED, this.dataServiceOptions.isAutoConnect());\n        assertEquals(CONNECT_DELAY_CHANGED, this.dataServiceOptions.getConnectDelay());\n        assertEquals(DISCONNECT_DELAY_CHANGED, this.dataServiceOptions.getDisconnectDelay());\n        assertEquals(DB_SERVICE_INSTANCE_CHANGED, this.dataServiceOptions.getDbServiceInstancePid());\n        assertEquals(STORE_HOUSEKEEPER_INTERVAL_CHANGED, this.dataServiceOptions.getStoreHousekeeperInterval());\n        assertEquals(STORE_PURGE_AGE_CHANGED, this.dataServiceOptions.getStorePurgeAge());\n        assertEquals(STORE_CAPACITY_CHANGED, this.dataServiceOptions.getStoreCapacity());\n        assertEquals(REPUBLISH_IN_FLIGHT_MSGS_CHANGED, this.dataServiceOptions.isPublishInFlightMessages());\n        assertEquals(MAX_IN_FLIGHT_MSGS_CHANGED, this.dataServiceOptions.getMaxInFlightMessages());\n        assertEquals(IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_CHANGED,\n                this.dataServiceOptions.getInFlightMessagesCongestionTimeout());\n        assertEquals(RATE_LIMIT_ENABLE_CHANGED, this.dataServiceOptions.isRateLimitEnabled());\n        assertEquals(RATE_LIMIT_AVERAGE_RATE_CHANGED, this.dataServiceOptions.getRateLimitAverageRate());\n        assertEquals(RATE_LIMIT_BURST_SIZE_CHANGED, this.dataServiceOptions.getRateLimitBurstSize());\n        assertEquals(RECOVERY_ENABLE_CHANGED, this.dataServiceOptions.isConnectionRecoveryEnabled());\n        assertEquals(RECOVERY_MAX_FAILURES_CHANGED, this.dataServiceOptions.getRecoveryMaximumAllowedFailures());\n        assertEquals(CONNECTION_SCHEDULE_ENABLED_CHANGED, this.dataServiceOptions.isConnectionScheduleEnabled());\n        assertEquals(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE_CHANGED,\n                this.dataServiceOptions.isConnectionSchedulePriorityOverrideEnabled());\n        assertEquals(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD_CHANGED,\n                this.dataServiceOptions.getConnectionSchedulePriorityOverridePriority());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloud.base.provider.test/src/test/java/org/eclipse/kura/core/data/ScheduleStrategyTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.data;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.core.data.AutoConnectStrategy.ConnectionManager;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.quartz.CronExpression;\n\npublic class ScheduleStrategyTest {\n\n    private DataServiceOptions dataServiceOptions;\n\n    @Test\n    public void shouldScheduleFirstConnectionAttempt() {\n        givenTime(\"1/1/2000\");\n        givenCronExpression(\"0/2 * * * * ?\");\n\n        whenScheduleStrategyIsCreated();\n\n        thenTimeoutIsRequestedAfterMs(2000);\n    }\n\n    @Test\n    public void shouldRequestConnection() {\n        givenTime(\"1/1/2000\");\n        givenCronExpression(\"0/2 * * * * ?\");\n        givenScheduleStrategy();\n\n        whenTimeoutOccurs();\n\n        thenConnectionTaskIsStarted();\n    }\n\n    @Test\n    public void shouldScheduleDisconnectTimeout() {\n        givenTime(\"1/1/2000\");\n        givenCronExpression(\"0/2 * * * * ?\");\n        givenScheduleStrategy();\n        givenTimeout();\n\n        whenConnectionIsEstablished();\n\n        thenTimeoutIsRequestedAfterMs(60000);\n    }\n\n    @Test\n    public void shouldRequestDisconnect() {\n        givenTime(\"1/1/2000\");\n        givenCronExpression(\"0/2 * * * * ?\");\n        givenScheduleStrategy();\n        givenTimeout();\n        givenConnectionEstablished();\n\n        whenTimeoutOccurs();\n\n        thenDisconnectIsRequested();\n        thenConnectionTaskIsStopped();\n    }\n\n    @Test\n    public void shouldForceReconnectOutsideOfSchedule() {\n        givenTime(\"1/1/2000\");\n        givenCronExpression(\"0/2 * * * * ?\");\n        givenScheduleStrategy();\n        givenTimeout();\n\n        whenScheduleStrategyIsCreatedWithAlternativeConstructor();\n\n        whenMessageIsSent();\n\n        thenConnectionTaskIsNotStarted();\n\n        whenPriorityMessageIsSent();\n\n        thenConnectionTaskIsStarted();\n    }\n    \n    @Test\n    public void shouldReconnectIfMessageIsSentDuringDisconnect() {\n        givenTime(\"1/1/2000\");\n        givenCronExpression(\"0/2 * * * * ?\");\n        givenScheduleStrategy();\n        givenTimeout();\n        \n        whenScheduleStrategyIsCreatedWithAlternativeConstructor();\n        \n        whenMessageIsSent();\n        \n        thenConnectionTaskIsNotStarted();\n        \n        whenPriorityMessageIsSent();\n        \n        thenConnectionTaskIsStarted();\n        \n        //Create Minor Delay\n        whenMessageIsSent();\n        whenMessageIsSent();\n        whenMessageIsSent();\n        \n        whenPriorityMessageIsSent();\n        \n        thenConnectionTaskIsStarted();\n    }\n\n    private final ExecutorState executorState = new ExecutorState();\n    private final ConnectionManagerState connectionManagerState = new ConnectionManagerState();\n    private Date now;\n    private CronExpression expression;\n    private ScheduleStrategy strategy;\n    private long disconnectTimeoutMs = 60000;\n\n    private void givenCronExpression(String expressionString) {\n        try {\n            this.expression = new CronExpression(expressionString);\n        } catch (ParseException e) {\n            throw new IllegalStateException(\"failed to parse cron expression\", e);\n        }\n\n    }\n\n    private void givenTime(final String time) {\n        try {\n            now = new SimpleDateFormat(\"dd/MM/yyyy\").parse(time);\n        } catch (ParseException e) {\n            throw new IllegalStateException(\"failed to parse date\", e);\n        }\n    }\n\n    private void givenScheduleStrategy() {\n        whenScheduleStrategyIsCreated();\n    }\n\n    private void givenTimeout() {\n        whenTimeoutOccurs();\n    }\n\n    private void givenConnectionEstablished() {\n        whenConnectionIsEstablished();\n    }\n\n    private void whenTimeoutOccurs() {\n        executorState.triggerTimeout();\n    }\n\n    private void whenScheduleStrategyIsCreated() {\n\n        // Create DataServiceOptions\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"connection.schedule.priority.override.enable\", true);\n        properties.put(\"connection.schedule.priority.override.threshold\", 3);\n        properties.put(\"connect.auto-on-startup\", true);\n        properties.put(\"connection.schedule.inactivity.interval.seconds\", disconnectTimeoutMs);\n        properties.put(\"connection.schedule.enabled\", true);\n        properties.put(\"connection.schedule.expression\", expression.toString());\n\n        this.dataServiceOptions = new DataServiceOptions(properties);\n\n        this.strategy = new ScheduleStrategy(expression, disconnectTimeoutMs,\n                this.connectionManagerState.connectionManager,\n                this.executorState.executor, () -> this.now, this.dataServiceOptions);\n    }\n\n    private void whenScheduleStrategyIsCreatedWithAlternativeConstructor() {\n\n        // Create DataServiceOptions\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"connection.schedule.priority.override.enable\", true);\n        properties.put(\"connection.schedule.priority.override.threshold\", 3);\n        properties.put(\"connect.auto-on-startup\", true);\n        properties.put(\"connection.schedule.inactivity.interval.seconds\", disconnectTimeoutMs);\n        properties.put(\"connection.schedule.enabled\", true);\n        properties.put(\"connection.schedule.expression\", expression.toString());\n        properties.put(\"connection.schedule.inactivity.interval.seconds\", (long) 1);\n\n        this.dataServiceOptions = new DataServiceOptions(properties);\n\n        this.strategy = new ScheduleStrategy(this.expression, this.dataServiceOptions,\n                this.connectionManagerState.connectionManager);\n    }\n\n    private void whenConnectionIsEstablished() {\n        this.strategy.onConnectionEstablished();\n    }\n\n    private void whenMessageIsSent() {\n        this.strategy.onPublishRequested(\"test/topic\", null, 0, false, 7);\n    }\n\n    private void whenPriorityMessageIsSent() {\n        this.strategy.onPublishRequested(\"test/topic\", null, 0, false, 0);\n    }\n\n    private void thenTimeoutIsRequestedAfterMs(long expectedDelay) {\n        assertEquals(expectedDelay, this.executorState.getDelay());\n    }\n\n    private void thenConnectionTaskIsStarted() {\n        try {\n            connectionManagerState.startConnectionTask.get(30, TimeUnit.SECONDS);\n        } catch (Exception e) {\n            fail(\"connection task not started\");\n        }\n    }\n\n    private void thenConnectionTaskIsNotStarted() {\n        assertFalse(connectionManagerState.connectionManager.isConnected());\n    }\n\n    private void thenConnectionTaskIsStopped() {\n        try {\n            connectionManagerState.stopConnectionTask.get(30, TimeUnit.SECONDS);\n        } catch (Exception e) {\n            fail(\"connection task not stopped\");\n        }\n    }\n\n    private void thenDisconnectIsRequested() {\n        try {\n            connectionManagerState.disconnect.get(30, TimeUnit.SECONDS);\n        } catch (Exception e) {\n            fail(\"disconnect not requested\");\n        }\n    }\n\n    private class ConnectionManagerState {\n        private ConnectionManager connectionManager = mock(ConnectionManager.class);\n        private CompletableFuture<?> startConnectionTask = new CompletableFuture<>();\n        private CompletableFuture<?> stopConnectionTask = new CompletableFuture<>();\n        private CompletableFuture<?> disconnect = new CompletableFuture<>();\n\n        ConnectionManagerState() {\n            doAnswer(i -> {\n                startConnectionTask.complete(null);\n                return null;\n            }).when(connectionManager).startConnectionTask();\n\n            doAnswer(i -> {\n                stopConnectionTask.complete(null);\n                return null;\n            }).when(connectionManager).stopConnectionTask();\n\n            doAnswer(i -> {\n                disconnect.complete(null);\n                return null;\n            }).when(connectionManager).disconnect();\n\n            when(connectionManager.isConnected()).thenReturn(false);\n        }\n    }\n\n    private class ExecutorState {\n        private ScheduledExecutorService executor = mock(ScheduledExecutorService.class);\n        private CompletableFuture<Runnable> task = new CompletableFuture<>();\n        private CompletableFuture<Long> lastDelay = new CompletableFuture<>();\n\n        public ExecutorState() {\n            Mockito.when(executor.schedule((Runnable) Mockito.any(), Mockito.anyLong(), Mockito.any()))\n                    .thenAnswer(i -> {\n\n                        this.task.complete(i.getArgument(0, Runnable.class));\n                        this.lastDelay.complete(i.getArgument(1, Long.class));\n\n                        return Mockito.mock(ScheduledFuture.class);\n                    });\n\n            Mockito.doAnswer(i -> {\n                i.getArgument(0, Runnable.class).run();\n\n                return Mockito.mock(ScheduledFuture.class);\n            }).when(executor).execute(Mockito.any());\n        }\n\n        private void triggerTimeout() {\n            try {\n                this.task.get(30, TimeUnit.SECONDS).run();\n                this.task = new CompletableFuture<>();\n                this.lastDelay = new CompletableFuture<>();\n            } catch (Exception e) {\n                throw new IllegalStateException(\"timeout not set\");\n            }\n        }\n\n        private long getDelay() {\n            try {\n                return lastDelay.get(30, TimeUnit.SECONDS);\n            } catch (Exception e) {\n                throw new IllegalStateException(\"timeout not set\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/.gitignore",
    "content": "/lib\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test\nBundle-SymbolicName: org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .,\n lib/protobuf-java.jar\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.core.testutil,\n org.eclipse.kura.data.transport.listener;version=\"1.0.1\",\n org.eclipse.kura.test.annotation;version=\"1.0.0\",\n org.eclipse.kura.util.wire.test;version=\"1.1.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.service.cm;version=\"1.4.0\",\n org.slf4j;version=\"1.6.4\"\nFragment-Host: org.eclipse.kura.cloudconnection.kapua.mqtt.provider\nRequire-Bundle: moquette-broker\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/OSGI-INF/cloud-publisher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n  Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n  \n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"CloudPublisherTest\">\n   <implementation class=\"org.eclipse.kura.core.cloud.CloudPublisherImplTest\"/>\n   <reference name=\"ConfigurationService\"\n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"bindCfgSvc\"\n              unbind=\"unbindCfgSvc\"\n              interface=\"org.eclipse.kura.configuration.ConfigurationService\"/>\n   <reference name=\"DefaultCloudServiceFactory\"\n              policy=\"static\"\n              cardinality=\"1..n\"\n              bind=\"bindCloudFactory\"\n              unbind=\"unbindCloudFactory\"\n              interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n   <reference bind=\"bindCloudService\"\n              unbind=\"unbindCloudService\"\n              cardinality=\"0..1\"\n              interface=\"org.eclipse.kura.cloud.CloudService\"\n              name=\"cloudService\"\n              target=\"(kura.service.pid=org.eclipse.kura.cloud.CloudService)\"\n              policy=\"dynamic\"/>\n   <reference bind=\"bindCloudPublisher\"\n              unbind=\"unbindCloudPublisher\"\n              cardinality=\"0..1\"\n              interface=\"org.eclipse.kura.cloudconnection.publisher.CloudPublisher\"\n              name=\"cloudPublisher\"\n              target=\"(kura.service.pid=org.eclipse.kura.cloud.publisher.CloudPublisher-1)\"\n              policy=\"dynamic\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/OSGI-INF/cloud-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  \n  Copyright (c) 2018, 2021 Eurotech and/or its affiliates and others\n  \n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"CloudServiceTest\">\n   <implementation class=\"org.eclipse.kura.core.cloud.CloudServiceTest\"/>\n   <reference name=\"ConfigurationService\"\n              policy=\"static\"\n              cardinality=\"1..1\"\n              bind=\"bindCfgSvc\"\n              unbind=\"unbindCfgSvc\"\n              interface=\"org.eclipse.kura.configuration.ConfigurationService\"/>\n   <reference name=\"DefaultCloudServiceFactory\"\n              policy=\"static\"\n              cardinality=\"1..n\"\n              bind=\"bindCloudFactory\"\n              unbind=\"unbindCloudFactory\"\n              interface=\"org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory\"/>\n   <reference bind=\"bindCloudService\"\n              unbind=\"unbindCloudService\"\n              cardinality=\"0..1\"\n              interface=\"org.eclipse.kura.cloud.CloudService\"\n              name=\"cloudService\"\n              target=\"(kura.service.pid=org.eclipse.kura.cloud.CloudService)\"\n              policy=\"dynamic\"/>\n   <reference bind=\"bindDataTransportService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.data.DataTransportService\" name=\"DataTransportService\" policy=\"static\"/>\n   <reference bind=\"bindCryptoService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.crypto.CryptoService\" name=\"CryptoService\" policy=\"static\"/>\n   <reference bind=\"bindEventAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.event.EventAdmin\" name=\"EventAdmin\" policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html,\\\n               lib/protobuf-java.jar\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n     Red Hat Inc\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.google.protobuf</groupId>\n            <artifactId>protobuf-java</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>3.0.0</version>\n                <executions>\n                    <execution>\n                        <phase>generate-sources</phase>\n                        <configuration>\n                            <outputDirectory>${project.basedir}/lib</outputDirectory>\n                            <stripVersion>true</stripVersion>\n                            <includeArtifactIds>\n                                protobuf-java\n                            </includeArtifactIds>\n                        </configuration>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/main/java/org/eclipse/kura/core/cloud/CloudPublisherImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\n\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\npublic class CloudPublisherImplTest {\n\n    private static CountDownLatch dependencyLatch = new CountDownLatch(4);\n\n    private static ConfigurationService cfgSvc;\n\n    private static CloudConnectionFactory cloudConnectionFactory;\n\n    private static CloudServiceImpl cloudServiceImpl;\n\n    private static CloudPublisher cloudPublisher;\n\n    @BeforeClass\n    public static void setup() throws KuraException {\n        try {\n            dependencyLatch.await(10, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n        }\n    }\n\n    public void bindCfgSvc(ConfigurationService cfgSvc) {\n        CloudPublisherImplTest.cfgSvc = cfgSvc;\n        dependencyLatch.countDown();\n    }\n\n    public void unbindCfgSvc(ConfigurationService cfgSvc) {\n        CloudPublisherImplTest.cfgSvc = null;\n    }\n\n    public void bindCloudFactory(CloudConnectionFactory cloudConnectionFactory) throws KuraException {\n        CloudPublisherImplTest.cloudConnectionFactory = cloudConnectionFactory;\n        if (\"org.eclipse.kura.cloud.CloudService\".equals(cloudConnectionFactory.getFactoryPid())) {\n            cloudConnectionFactory.createConfiguration(\"org.eclipse.kura.cloud.CloudService\");\n            dependencyLatch.countDown();\n        }\n    }\n\n    public void bindCloudService(CloudService cloudService) throws KuraException {\n        cloudServiceImpl = (CloudServiceImpl) cloudService;\n        cfgSvc.createFactoryConfiguration(\"org.eclipse.kura.cloud.publisher.CloudPublisher\",\n                \"org.eclipse.kura.cloud.publisher.CloudPublisher-1\",\n                Collections.singletonMap(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(),\n                        \"org.eclipse.kura.cloud.CloudService\"),\n                true);\n        dependencyLatch.countDown();\n    }\n\n    public void unbindCloudService(CloudService cloudService) {\n        cloudServiceImpl = null;\n    }\n\n    public void unbindCloudFactory(CloudConnectionFactory cloudConnectionFactory) {\n        CloudPublisherImplTest.cloudConnectionFactory = null;\n    }\n\n    public void bindCloudPublisher(CloudPublisher cloudPublisher) {\n        CloudPublisherImplTest.cloudPublisher = cloudPublisher;\n        dependencyLatch.countDown();\n    }\n\n    public void unbindCloudPublisher(CloudPublisher cloudPublisher) {\n        CloudPublisherImplTest.cloudPublisher = null;\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testServiceExists() {\n        assertNotNull(CloudPublisherImplTest.cfgSvc);\n        assertNotNull(CloudPublisherImplTest.cloudConnectionFactory);\n        assertNotNull(CloudPublisherImplTest.cloudServiceImpl);\n        assertNotNull(CloudPublisherImplTest.cloudPublisher);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test(expected = IllegalArgumentException.class)\n    public void testPublishNullMessage() throws KuraException {\n        cloudPublisher.publish(null);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testPublishQos0() throws KuraException {\n        KuraPayload payload = new KuraPayload();\n        KuraMessage message = new KuraMessage(payload);\n\n        String result = cloudPublisher.publish(message);\n        assertNull(result);\n    }\n    \n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testPublishQos1() throws KuraException {\n        KuraPayload payload = new KuraPayload();\n        KuraMessage message = new KuraMessage(payload);\n\n        ComponentConfiguration cloudPubConfig = cfgSvc.getComponentConfiguration(\"org.eclipse.kura.cloud.publisher.CloudPublisher-1\");\n        Map<String, Object> cloudPubConfigProps = cloudPubConfig.getConfigurationProperties();\n        cloudPubConfigProps.put(\"qos\", 1);\n        cfgSvc.updateConfiguration(\"org.eclipse.kura.cloud.publisher.CloudPublisher-1\", cloudPubConfigProps);\n        \n        String result = cloudPublisher.publish(message);\n        assertNotNull(result);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/main/java/org/eclipse/kura/core/cloud/CloudServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport static org.eclipse.kura.util.wire.test.WireTestUtil.createFactoryConfiguration;\nimport static org.eclipse.kura.util.wire.test.WireTestUtil.updateComponentConfiguration;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.lang.reflect.Proxy;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.data.util.MqttTopicUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.eclipse.kura.message.KuraBirthPayload;\nimport org.eclipse.kura.message.KuraDeviceProfile;\nimport org.eclipse.kura.net.status.NetworkStatusService;\nimport org.eclipse.kura.net.status.modem.ModemConnectionStatus;\nimport org.eclipse.kura.net.status.modem.ModemInterfaceStatus;\nimport org.eclipse.kura.net.status.modem.ModemInterfaceStatus.ModemInterfaceStatusBuilder;\nimport org.eclipse.kura.net.status.modem.Sim;\nimport org.eclipse.kura.security.tamper.detection.TamperDetectionService;\nimport org.eclipse.kura.security.tamper.detection.TamperEvent;\nimport org.eclipse.kura.security.tamper.detection.TamperStatus;\nimport org.eclipse.kura.system.ExtendedProperties;\nimport org.eclipse.kura.system.ExtendedPropertyGroup;\nimport org.eclipse.kura.system.SystemService;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.event.EventAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonObject;\n\nimport io.moquette.broker.Server;\nimport io.moquette.broker.config.FluentConfig;\nimport io.moquette.broker.config.IConfig;\n\npublic class CloudServiceTest {\n\n    private static final String MODEM_RSSI = \"modem_rssi\";\n    private static final String MODEM_ICCID = \"modem_iccid\";\n    private static final String MODEM_IMSI = \"modem_imsi\";\n    private static final String MODEM_IMEI = \"modem_imei\";\n    private static final String TAMPER_STATUS = \"tamper_status\";\n    private static final String MODEM_FIRMWARE_VERSION = \"modem_firmware_version\";\n    private static final String FOO_FW_VER1 = \"fooFwVer1\";\n    private static final String FOO_ICCID1 = \"fooIccid1\";\n    private static final String FOO_IMSI1 = \"fooImsi1\";\n    private static final String FOO_IMEI1 = \"fooImei1\";\n    private static final String MQTT_DATA_TRANSPORT_FACTORY_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n    private static final String DEFAULT_CLOUD_SERVICE_PID = \"org.eclipse.kura.cloud.CloudService\";\n    private static final String DEFAULT_MQTT_DATA_TRANSPORT_SERVICE_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n    private static final Logger logger = LoggerFactory.getLogger(CloudServiceTest.class);\n\n    private static CountDownLatch dependencyLatch = new CountDownLatch(6);\n    private static ConfigurationService cfgSvc;\n    private static CloudConnectionFactory cloudConnectionFactory;\n    private static DataTransportService mqttDataTransport;\n    private static DataTransportInspector underTestInspector;\n    private static CryptoService cryptoService;\n    private static CloudServiceImpl cloudServiceImpl;\n    private static DataTransportInspector observerInspector;\n    private static EventAdmin eventAdmin;\n    private static NetworkStatusService networkStatusService;\n\n    private static final Server mqttBroker = new Server();\n\n    @BeforeClass\n    public static void setup()\n            throws KuraException, InterruptedException, ExecutionException, TimeoutException, InvalidSyntaxException,\n            IOException {\n        try {\n            dependencyLatch.await(10, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n        }\n\n        Map<String, Object> updatedProp = new HashMap<>();\n        updatedProp.put(\"client-id\", \"test\");\n\n        startMoquetteBroker();\n\n        updateComponentConfiguration(cfgSvc, DEFAULT_MQTT_DATA_TRANSPORT_SERVICE_PID, updatedProp).get(30,\n                TimeUnit.SECONDS);\n\n        final Map<String, Object> cloudServiceProperties = new HashMap<>();\n        cloudServiceProperties.put(\"payload.encoding\", \"simple-json\");\n        /*\n         * Set a control topic without $ as prefix: some brokers do not allow access to topics starting with $ (like\n         * moquette, mosquitto)\n         */\n        cloudServiceProperties.put(\"topic.control-prefix\", \"EDC\");\n\n        updateComponentConfiguration(cfgSvc, DEFAULT_CLOUD_SERVICE_PID, cloudServiceProperties).get(30,\n                TimeUnit.SECONDS);\n\n        DataTransportService observer = createFactoryConfiguration(cfgSvc, DataTransportService.class, \"observer\",\n                MQTT_DATA_TRANSPORT_FACTORY_PID, getConfigForLocalBroker(\"observer\")).get(30, TimeUnit.SECONDS);\n        observerInspector = new DataTransportInspector(observer);\n\n        final CompletableFuture<Void> connected = observerInspector.connected();\n\n        observer.connect();\n\n        connected.get(1, TimeUnit.MINUTES);\n\n        underTestInspector = new DataTransportInspector(mqttDataTransport);\n\n    }\n\n    @AfterClass\n    public static void cleanup() {\n        mqttBroker.stopServer();\n    }\n\n    private static void startMoquetteBroker() throws IOException {\n        IConfig brokerConfig = new FluentConfig().port(1883).host(\"0.0.0.0\").disablePersistence().build();\n\n        mqttBroker.startServer(brokerConfig);\n\n        Runtime.getRuntime().addShutdownHook(new Thread(mqttBroker::stopServer));\n    }\n\n    public void bindCfgSvc(ConfigurationService cfgSvc) {\n        CloudServiceTest.cfgSvc = cfgSvc;\n        dependencyLatch.countDown();\n    }\n\n    public void unbindCfgSvc(ConfigurationService cfgSvc) {\n        CloudServiceTest.cfgSvc = null;\n    }\n\n    public void bindCloudFactory(CloudConnectionFactory cloudConnectionFactory) throws KuraException {\n        CloudServiceTest.cloudConnectionFactory = cloudConnectionFactory;\n        if (DEFAULT_CLOUD_SERVICE_PID.equals(cloudConnectionFactory.getFactoryPid())) {\n            cloudConnectionFactory.createConfiguration(DEFAULT_CLOUD_SERVICE_PID);\n            dependencyLatch.countDown();\n        }\n    }\n\n    public void bindCloudService(CloudService cloudService) {\n        cloudServiceImpl = (CloudServiceImpl) cloudService;\n        dependencyLatch.countDown();\n    }\n\n    public void unbindCloudService(CloudService cloudService) {\n        cloudServiceImpl = null;\n    }\n\n    public void bindDataTransportService(DataTransportService service) {\n        mqttDataTransport = service;\n        dependencyLatch.countDown();\n    }\n\n    public void unbindCloudFactory(CloudConnectionFactory cloudConnectionFactory) {\n        CloudServiceTest.cloudConnectionFactory = null;\n    }\n\n    public void bindCryptoService(CryptoService service) {\n        cryptoService = service;\n        dependencyLatch.countDown();\n    }\n\n    public void bindEventAdmin(EventAdmin service) {\n        eventAdmin = service;\n        dependencyLatch.countDown();\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testServiceExists() {\n        assertNotNull(CloudServiceTest.cfgSvc);\n        assertNotNull(CloudServiceTest.cloudConnectionFactory);\n        assertNotNull(CloudServiceTest.cloudServiceImpl);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test(expected = KuraException.class)\n    public void testConnectCannotConnect()\n            throws KuraException, InterruptedException, ExecutionException, TimeoutException, InvalidSyntaxException {\n\n        final CompletableFuture<Void> diconnected = underTestInspector.disconnected();\n\n        cloudServiceImpl.disconnect();\n\n        diconnected.get(30, TimeUnit.SECONDS);\n\n        updateComponentConfiguration(cfgSvc, DEFAULT_MQTT_DATA_TRANSPORT_SERVICE_PID, getConfigForNonExistingBroker())\n                .get(1, TimeUnit.MINUTES);\n\n        cloudServiceImpl.connect();\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testDisconnect() {\n        cloudServiceImpl.disconnect();\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetConnectionInfo() {\n        Map<String, String> connectionProps = cloudServiceImpl.getInfo();\n\n        assertNotNull(connectionProps);\n        assertEquals(4, connectionProps.size());\n        assertNotNull(connectionProps.get(\"Broker URL\"));\n        assertNotNull(connectionProps.get(\"Account\"));\n        assertNotNull(connectionProps.get(\"Username\"));\n        assertNotNull(connectionProps.get(\"Client ID\"));\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetNotificationPublisherPid() {\n        String pid = cloudServiceImpl.getNotificationPublisherPid();\n        assertEquals(\"org.eclipse.kura.cloud.publisher.CloudNotificationPublisher\", pid);\n    }\n\n    @Test\n    public void shouldSupportAdditionalBirthProperties()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n\n        clearNetworkStatusServiceMock();\n\n        cloudServiceImpl.setSystemService(createMockSystemService(Optional.empty()));\n        final JsonObject metrics = publishBirthAndGetMetrics();\n\n        assertEquals(\"getCpuVersion\", metrics.get(KuraDeviceProfile.CPU_VERSION_KEY).asString());\n\n    }\n\n    @Test\n    public void shouldSupportEmptyExtendedProperties()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n\n        cloudServiceImpl.setSystemService(createMockSystemService(Optional.empty()));\n        final JsonObject metrics = publishBirthAndGetMetrics();\n\n        assertNull(metrics.get(\"extended_properties\"));\n    }\n\n    @Test\n    public void shouldSupportExtendedPropertiesSerialization()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n\n        final Map<String, String> first = new HashMap<>();\n\n        first.put(\"string\", \"str\");\n        first.put(\"foo\", \"bar\");\n\n        final Map<String, String> empty = Collections.emptyMap();\n\n        final ExtendedPropertyGroup firstGroup = new ExtendedPropertyGroup(\"first\", first);\n        final ExtendedPropertyGroup emptyGroup = new ExtendedPropertyGroup(\"empty\", empty);\n\n        final ExtendedProperties properties = new ExtendedProperties(\"1.5\", Arrays.asList(firstGroup, emptyGroup));\n\n        cloudServiceImpl.setSystemService(createMockSystemService(Optional.of(properties)));\n        final JsonObject metrics = publishBirthAndGetMetrics();\n\n        final JsonObject parsedExtendedPropertes = Json.parse(metrics.get(\"extended_properties\").asString()).asObject();\n\n        assertEquals(\"1.5\", parsedExtendedPropertes.get(\"version\").asString());\n\n        final JsonObject groups = parsedExtendedPropertes.get(\"properties\").asObject();\n\n        final JsonObject firstObject = groups.get(\"first\").asObject();\n\n        assertEquals(2, firstObject.size());\n        assertEquals(\"str\", firstObject.get(\"string\").asString());\n        assertEquals(\"bar\", firstObject.get(\"foo\").asString());\n\n        final JsonObject emptyObject = groups.get(\"empty\").asObject();\n\n        assertTrue(emptyObject.isEmpty());\n\n    }\n\n    @Test\n    public void shouldNotPublishTamperStatusIfTamperDetectionIsNotAvailable()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n\n        final JsonObject metrics = publishBirthAndGetMetrics();\n\n        assertNull(metrics.get(TAMPER_STATUS));\n    }\n\n    @Test\n    public void shouldPublishTamperStatusIfTamperDetectionIsAvailable()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n\n        final TamperDetectionService tamperDetectionService = Mockito.mock(TamperDetectionService.class);\n        Mockito.when(tamperDetectionService.getTamperStatus())\n                .thenReturn(new TamperStatus(true, Collections.emptyMap()));\n\n        final ServiceRegistration<?> reg = FrameworkUtil.getBundle(CloudServiceTest.class).getBundleContext()\n                .registerService(TamperDetectionService.class, tamperDetectionService, null);\n\n        try {\n            JsonObject metrics = publishBirthAndGetMetrics();\n\n            assertEquals(KuraBirthPayload.TamperStatus.TAMPERED.name(), metrics.get(TAMPER_STATUS).asString());\n\n            Mockito.when(tamperDetectionService.getTamperStatus())\n                    .thenReturn(new TamperStatus(false, Collections.emptyMap()));\n\n            metrics = publishBirthAndGetMetrics();\n\n            assertEquals(KuraBirthPayload.TamperStatus.NOT_TAMPERED.name(), metrics.get(TAMPER_STATUS).asString());\n        } finally {\n            reg.unregister();\n        }\n    }\n\n    @Test\n    public void shouldRepublishBirthOnTamperEvent()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n\n        final TamperDetectionService tamperDetectionService = Mockito.mock(TamperDetectionService.class);\n        Mockito.when(tamperDetectionService.getTamperStatus())\n                .thenReturn(new TamperStatus(true, Collections.emptyMap()));\n\n        final ServiceRegistration<?> reg = FrameworkUtil.getBundle(CloudServiceTest.class).getBundleContext()\n                .registerService(TamperDetectionService.class, tamperDetectionService, null);\n\n        try {\n            JsonObject metrics = publishBirthAndGetMetrics();\n\n            assertEquals(KuraBirthPayload.TamperStatus.TAMPERED.name(), metrics.get(TAMPER_STATUS).asString());\n\n            final TamperStatus tamperStatus = new TamperStatus(false, Collections.emptyMap());\n\n            Mockito.when(tamperDetectionService.getTamperStatus()).thenReturn(tamperStatus);\n\n            final CompletableFuture<byte[]> message = observerInspector.nextMessage(\"EDC/mqtt/underTest/MQTT/BIRTH\");\n            eventAdmin.postEvent(new TamperEvent(\"foo\", tamperStatus));\n\n            metrics = getMetrics(message.get(35, TimeUnit.SECONDS));\n\n            assertEquals(KuraBirthPayload.TamperStatus.NOT_TAMPERED.name(), metrics.get(TAMPER_STATUS).asString());\n        } finally {\n            reg.unregister();\n        }\n    }\n\n    @Test\n    public void shouldPublishBirthMessageWithModemInfoWhenNetworkStatusServiceIsPresent()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n\n        createNetworkStatusServiceMock();\n        final JsonObject metrics = publishBirthAndGetMetrics();\n\n        assertEquals(FOO_IMEI1, metrics.get(MODEM_IMEI).asString());\n        assertEquals(FOO_IMSI1, metrics.get(MODEM_IMSI).asString());\n        assertEquals(FOO_ICCID1, metrics.get(MODEM_ICCID).asString());\n        assertEquals(\"1\", metrics.get(MODEM_RSSI).asString());\n        assertEquals(FOO_FW_VER1, metrics.get(MODEM_FIRMWARE_VERSION).asString());\n\n    }\n\n    @Test\n    public void shouldPublishBirthMessageWithConnectedModemInfoWhenMultipleModems()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n\n        createNetworkStatusServiceMockWithMultipleModems();\n        final JsonObject metrics = publishBirthAndGetMetrics();\n\n        assertEquals(\"fooImei2\", metrics.get(MODEM_IMEI).asString());\n        assertEquals(\"fooImsi2\", metrics.get(MODEM_IMSI).asString());\n        assertEquals(\"fooIccid2\", metrics.get(MODEM_ICCID).asString());\n        assertEquals(\"2\", metrics.get(MODEM_RSSI).asString());\n        assertEquals(\"fooFwVer2\", metrics.get(MODEM_FIRMWARE_VERSION).asString());\n\n    }\n\n    private JsonObject publishBirthAndGetMetrics()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n        final CompletableFuture<Void> disconnected = underTestInspector.disconnected();\n\n        cloudServiceImpl.disconnect();\n\n        disconnected.get(30, TimeUnit.SECONDS);\n\n        updateComponentConfiguration(cfgSvc, DEFAULT_MQTT_DATA_TRANSPORT_SERVICE_PID,\n                getConfigForLocalBroker(\"underTest\")).get(1, TimeUnit.MINUTES);\n\n        final CompletableFuture<byte[]> message = observerInspector.nextMessage(\"EDC/mqtt/underTest/MQTT/BIRTH\");\n\n        for (int i = 0; i < 3; i++) {\n            try {\n                final CompletableFuture<Void> connected = underTestInspector.connected();\n\n                cloudServiceImpl.connect();\n\n                connected.get(30, TimeUnit.SECONDS);\n                break;\n            } catch (final InterruptedException e) {\n                logger.warn(\"connection failed\", e);\n                Thread.currentThread().interrupt();\n            }\n        }\n\n        assertEquals(true, cloudServiceImpl.isConnected());\n\n        return getMetrics(message.get(30, TimeUnit.SECONDS));\n    }\n\n    private static JsonObject getMetrics(final byte[] message) {\n        final JsonObject messageObject = Json.parse(new String(message, StandardCharsets.UTF_8)).asObject();\n        return messageObject.get(\"metrics\").asObject();\n    }\n\n    private static Map<String, Object> getConfigForLocalBroker(final String clientId) throws KuraException {\n        final Map<String, Object> properties = new HashMap<>();\n\n        properties.put(\"broker-url\", \"mqtt://localhost:1883/\");\n        properties.put(\"username\", \"mqtt\");\n        properties.put(\"client-id\", clientId);\n        properties.put(\"topic.context.account-name\", \"mqtt\");\n        properties.put(\"password\", new String(cryptoService.encryptAes(\"foo\".toCharArray())));\n\n        return properties;\n    }\n\n    private Map<String, Object> getConfigForNonExistingBroker() {\n        final Map<String, Object> properties = new HashMap<>();\n\n        properties.put(\"broker-url\", \"mqtt://broker-url:1883/\");\n\n        return properties;\n    }\n\n    private static SystemService createMockSystemService(final Optional<ExtendedProperties> extendedProperties) {\n        return (SystemService) Proxy.newProxyInstance(CloudServiceTest.class.getClassLoader(),\n                new Class<?>[] { SystemService.class }, (obj, method, args) -> {\n                    if (\"getExtendedProperties\".equals(method.getName())) {\n                        return extendedProperties;\n                    } else if (method.getReturnType() == String.class) {\n                        return method.getName();\n                    } else if (method.getReturnType() == int.class) {\n                        return 0;\n                    } else if (method.getReturnType() == long.class) {\n                        return 0L;\n                    } else {\n                        return null;\n                    }\n                });\n    }\n\n    private static class DataTransportInspector {\n\n        private final DataTransportService dataTransportService;\n\n        private Optional<CompletableFuture<Void>> connectFuture = Optional.empty();\n        private Optional<CompletableFuture<Void>> disconnectFuture = Optional.empty();\n        private Optional<MessageLookup> messageLookup = Optional.empty();\n\n        DataTransportInspector(final DataTransportService dataTransportService) {\n            this.dataTransportService = dataTransportService;\n\n            dataTransportService.addDataTransportListener(new DataTransportListener() {\n\n                @Override\n                public void onConnectionEstablished(boolean newSession) {\n                    try {\n                        dataTransportService.subscribe(\"#\", 0);\n                    } catch (Exception e) {\n                        logger.warn(\"failed to subscribe\", e);\n                    }\n                    if (connectFuture.isPresent()) {\n                        connectFuture.get().complete(null);\n                    }\n                    connectFuture = Optional.empty();\n                }\n\n                @Override\n                public void onDisconnecting() {\n                    // do nothing\n                }\n\n                @Override\n                public void onDisconnected() {\n                    if (disconnectFuture.isPresent()) {\n                        disconnectFuture.get().complete(null);\n                    }\n                    disconnectFuture = Optional.empty();\n                }\n\n                @Override\n                public void onConfigurationUpdating(boolean wasConnected) {\n                    // do nothing\n\n                }\n\n                @Override\n                public void onConfigurationUpdated(boolean wasConnected) {\n                    // do nothing\n                }\n\n                @Override\n                public void onConnectionLost(Throwable cause) {\n                    if (disconnectFuture.isPresent()) {\n                        disconnectFuture.get().complete(null);\n                    }\n                    disconnectFuture = Optional.empty();\n                }\n\n                @Override\n                public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n                    if (!messageLookup.isPresent()) {\n                        return;\n                    }\n\n                    final MessageLookup lookup = messageLookup.get();\n\n                    if (MqttTopicUtil.isMatched(lookup.topicFilter, topic)) {\n                        lookup.future.complete(payload);\n                        messageLookup = Optional.empty();\n                    }\n                }\n\n                @Override\n                public void onMessageConfirmed(DataTransportToken token) {\n                    // do nothing\n                }\n\n            });\n        }\n\n        private static class MessageLookup {\n\n            private final CompletableFuture<byte[]> future;\n            private final String topicFilter;\n\n            public MessageLookup(CompletableFuture<byte[]> future, String topicFilter) {\n                this.future = future;\n                this.topicFilter = topicFilter;\n            }\n        }\n\n        CompletableFuture<Void> connected() {\n            if (dataTransportService.isConnected()) {\n                return CompletableFuture.completedFuture(null);\n            }\n\n            final CompletableFuture<Void> result = new CompletableFuture<>();\n\n            this.connectFuture = Optional.of(result);\n\n            return result;\n        }\n\n        CompletableFuture<Void> disconnected() {\n            if (!dataTransportService.isConnected()) {\n                return CompletableFuture.completedFuture(null);\n            }\n\n            final CompletableFuture<Void> result = new CompletableFuture<>();\n\n            this.disconnectFuture = Optional.of(result);\n\n            return result;\n        }\n\n        CompletableFuture<byte[]> nextMessage(final String topicFilter) {\n            final CompletableFuture<byte[]> result = new CompletableFuture<>();\n\n            this.messageLookup = Optional.of(new MessageLookup(result, topicFilter));\n\n            return result;\n        }\n    }\n\n    private void createNetworkStatusServiceMock() throws KuraException {\n        networkStatusService = Mockito.mock(NetworkStatusService.class);\n        when(networkStatusService.getInterfaceIds()).thenReturn(Arrays.asList(new String[] { \"1-8\" }));\n        ModemInterfaceStatusBuilder modemStatusBuilder = ModemInterfaceStatus.builder();\n        modemStatusBuilder.withConnectionStatus(ModemConnectionStatus.CONNECTED).withSerialNumber(FOO_IMEI1)\n                .withFirmwareVersion(FOO_FW_VER1).withSignalStrength(1);\n        Sim sim = Sim.builder().withIccid(FOO_ICCID1).withImsi(FOO_IMSI1).withActive(true).withPrimary(true).build();\n        modemStatusBuilder.withAvailableSims(Arrays.asList(new Sim[] { sim }));\n        when(networkStatusService.getNetworkStatus(\"1-8\")).thenReturn(Optional.of(modemStatusBuilder.build()));\n\n        cloudServiceImpl.setNetworkStatusService(networkStatusService);\n    }\n\n    private void createNetworkStatusServiceMockWithMultipleModems() throws KuraException {\n        networkStatusService = Mockito.mock(NetworkStatusService.class);\n        when(networkStatusService.getInterfaceIds()).thenReturn(Arrays.asList(new String[] { \"1-8\", \"1-6\" }));\n\n        ModemInterfaceStatusBuilder firstModemStatusBuilder = ModemInterfaceStatus.builder();\n        firstModemStatusBuilder.withConnectionStatus(ModemConnectionStatus.FAILED).withSerialNumber(FOO_IMEI1)\n                .withFirmwareVersion(FOO_FW_VER1).withSignalStrength(1);\n        Sim sim1 = Sim.builder().withIccid(FOO_ICCID1).withImsi(FOO_IMSI1).withActive(true).withPrimary(true).build();\n        firstModemStatusBuilder.withAvailableSims(Arrays.asList(new Sim[] { sim1 }));\n        when(networkStatusService.getNetworkStatus(\"1-8\")).thenReturn(Optional.of(firstModemStatusBuilder.build()));\n\n        ModemInterfaceStatusBuilder secondModemStatusBuilder = ModemInterfaceStatus.builder();\n        secondModemStatusBuilder.withConnectionStatus(ModemConnectionStatus.CONNECTED).withSerialNumber(\"fooImei2\")\n                .withFirmwareVersion(\"fooFwVer2\").withSignalStrength(2);\n        Sim sim2 = Sim.builder().withIccid(\"fooIccid2\").withImsi(\"fooImsi2\").withActive(true).withPrimary(true).build();\n        secondModemStatusBuilder.withAvailableSims(Arrays.asList(new Sim[] { sim2 }));\n        when(networkStatusService.getNetworkStatus(\"1-6\")).thenReturn(Optional.of(secondModemStatusBuilder.build()));\n\n        cloudServiceImpl.setNetworkStatusService(networkStatusService);\n    }\n\n    private void clearNetworkStatusServiceMock() {\n        if (networkStatusService != null) {\n            cloudServiceImpl.unsetNetworkStatusService(networkStatusService);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/cloud/BirthMessagesTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport static org.junit.Assert.assertNull;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyBoolean;\nimport static org.mockito.ArgumentMatchers.anyInt;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.after;\nimport static org.mockito.Mockito.doNothing;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.Hashtable;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.position.PositionLockedEvent;\nimport org.eclipse.kura.security.tamper.detection.TamperEvent;\nimport org.eclipse.kura.system.SystemAdminService;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatchers;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventAdmin;\n\npublic class BirthMessagesTest {\n\n    private static final String BIRTH_TOPIC_PREFIX = \"$EDC\" + CloudServiceOptions.getTopicSeparator()\n            + CloudServiceOptions.getTopicAccountToken() + CloudServiceOptions.getTopicSeparator()\n            + CloudServiceOptions.getTopicClientIdToken() + CloudServiceOptions.getTopicSeparator();\n\n    private static final long SEND_DELAY = 25000L;\n    private static final long SLACK_DELAY = 10000L;\n\n    private CloudServiceImpl cloudService = new CloudServiceImpl();\n    private DataService dataService = mock(DataService.class);\n    private Exception occurredException;\n    private Event event;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldNotPublishOnActivationWhenDisconnected() throws KuraException {\n        givenDisconnected();\n\n        whenActivate();\n\n        thenNoExceptionOccurred();\n        thenNoBirthIsPublished();\n    }\n\n    @Test\n    public void shouldPublishImmediatelyOnActivationWhenConnected() throws KuraException {\n        givenConnected();\n\n        whenActivate();\n\n        thenNoExceptionOccurred();\n        thenBirthIsPublishedImmediately(BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicBirthSuffix());\n    }\n\n    @Test\n    public void shouldNotPublishOnUpdatedWhenDisconnected() throws KuraException {\n        givenDisconnected();\n\n        whenUpdated();\n\n        thenNoExceptionOccurred();\n        thenNoBirthIsPublished();\n    }\n\n    @Test\n    public void shouldPublishWithDelayOnUpdateWhenConnected() throws KuraException {\n        givenConnected();\n\n        whenUpdated();\n\n        thenNoExceptionOccurred();\n        thenBirthIsPublishedAfter(SEND_DELAY, BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicBirthSuffix());\n    }\n\n    @Test\n    public void shouldPublishImmediatelyWhenDeactivate() throws KuraException {\n        givenConfiguredCloudService();\n        givenConnected();\n\n        whenDeactivate();\n\n        thenNoExceptionOccurred();\n        thenDisconnectIsPublishedImmediately(BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicDisconnectSuffix());\n    }\n\n    @Test\n    public void shouldPublishWithDelayOnPositionLockedEvent() throws KuraException {\n        givenPositionLockedEvent();\n        givenConfiguredCloudService();\n        givenConnected();\n\n        whenHandleEvent();\n\n        thenNoExceptionOccurred();\n        thenBirthIsPublishedAfter(SEND_DELAY, BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicBirthSuffix());\n    }\n\n    @Test\n    public void shouldPublishWithDelayOnTamperEvent() throws KuraException {\n        givenTamperEvent();\n        givenConfiguredCloudService();\n        givenConnected();\n\n        whenHandleEvent();\n\n        thenNoExceptionOccurred();\n        thenBirthIsPublishedAfter(SEND_DELAY, BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicBirthSuffix());\n    }\n\n    @Test\n    public void shouldPublishImmediatelyOnConnectionEstabilished() throws KuraException {\n        givenConfiguredCloudService();\n\n        whenOnConnectionEstabilished();\n\n        thenNoExceptionOccurred();\n        thenBirthIsPublishedImmediately(BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicBirthSuffix());\n    }\n\n    @Test\n    public void shouldPublishImmediatelyOnDisconnecting() throws KuraException {\n        givenConfiguredCloudService();\n        givenConnected();\n\n        whenOnDisconnecting();\n\n        thenNoExceptionOccurred();\n        thenDisconnectIsPublishedImmediately(BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicDisconnectSuffix());\n    }\n\n    @Test\n    public void shouldPublishWithDelayWhenRegisterRequestHandler() throws KuraException {\n        givenConfiguredCloudService();\n        givenConnected();\n\n        whenRegisterRequestHandler();\n\n        thenNoExceptionOccurred();\n        thenBirthIsPublishedAfter(SEND_DELAY, BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicAppsSuffix());\n    }\n\n    @Test\n    public void shouldPublishWithDelayWhenUnregisterRequestHandler() throws KuraException {\n        givenConfiguredCloudService();\n        givenConnected();\n\n        whenUnregisterRequestHandler();\n\n        thenNoExceptionOccurred();\n        thenBirthIsPublishedAfter(SEND_DELAY, BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicAppsSuffix());\n    }\n\n    @Test\n    public void shouldPublishBirthOnInstalledEvent() throws KuraException {\n        givenDeploymentAdminPackageInstallEvent();\n        givenConfiguredCloudService();\n        givenConnected();\n\n        whenHandleEvent();\n\n        thenBirthIsPublishedAfter(SEND_DELAY, BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicBirthSuffix());\n    }\n\n    @Test\n    public void shouldPublishBirthOnUninstalledEvent() throws KuraException {\n        givenDeploymentAdminPackageUninstallEvent();\n        givenConfiguredCloudService();\n        givenConnected();\n\n        whenHandleEvent();\n\n        thenBirthIsPublishedAfter(SEND_DELAY, BIRTH_TOPIC_PREFIX + CloudServiceOptions.getTopicBirthSuffix());\n    }\n\n    @Test\n    public void shouldNotPublishBirthOnInstalledEventIfNotConnected() throws KuraException {\n        givenDeploymentAdminPackageInstallEvent();\n        givenConfiguredCloudService();\n        givenDisconnected();\n\n        whenHandleEvent();\n\n        thenNoBirthIsPublished();\n    }\n\n    @Test\n    public void shouldNotPublishBirthOnUninstalledEventIfNotConnected() throws KuraException {\n        givenDeploymentAdminPackageUninstallEvent();\n        givenConfiguredCloudService();\n        givenDisconnected();\n\n        whenHandleEvent();\n\n        thenNoBirthIsPublished();\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenConfiguredCloudService() {\n        this.cloudService.activate(getMockComponentContext(), getDefaultProperties());\n    }\n\n    private void givenConnected() {\n        when(this.dataService.isConnected()).thenReturn(true);\n    }\n\n    private void givenDisconnected() {\n        when(this.dataService.isConnected()).thenReturn(false);\n    }\n\n    private void givenPositionLockedEvent() {\n        this.event = new Event(PositionLockedEvent.POSITION_LOCKED_EVENT_TOPIC, new HashMap<String, Object>());\n    }\n\n    private void givenTamperEvent() {\n        this.event = new Event(TamperEvent.TAMPER_EVENT_TOPIC, new HashMap<String, Object>());\n    }\n\n    private void givenDeploymentAdminPackageInstallEvent() {\n        this.event = new Event(CloudServiceImpl.EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL, new HashMap<String, Object>());\n    }\n\n    private void givenDeploymentAdminPackageUninstallEvent() {\n        this.event = new Event(CloudServiceImpl.EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL, new HashMap<String, Object>());\n    }\n\n    /*\n     * When\n     */\n\n    private void whenActivate() {\n        try {\n            givenConfiguredCloudService();\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenUpdated() {\n        try {\n            this.cloudService.updated(getDefaultProperties());\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenDeactivate() {\n        try {\n            this.cloudService.deactivate(getMockComponentContext());\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenHandleEvent() {\n        try {\n            this.cloudService.handleEvent(this.event);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenOnConnectionEstabilished() {\n        try {\n            this.cloudService.onConnectionEstablished();\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenOnDisconnecting() {\n        try {\n            this.cloudService.onDisconnecting();\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenRegisterRequestHandler() {\n        try {\n            RequestHandler handler = mock(RequestHandler.class);\n            this.cloudService.registerRequestHandler(\"example.id\", handler);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenUnregisterRequestHandler() {\n        try {\n            this.cloudService.unregister(\"example.id\");\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenNoExceptionOccurred() {\n        String errorMessage = \"Empty message\";\n        if (Objects.nonNull(this.occurredException)) {\n            StringWriter sw = new StringWriter();\n            this.occurredException.printStackTrace(new PrintWriter(sw));\n\n            errorMessage = String.format(\"No exception expected, \\\"%s\\\" found. Caused by: %s\",\n                    this.occurredException.getClass().getName(), sw.toString());\n        }\n\n        assertNull(errorMessage, this.occurredException);\n    }\n\n    private void thenNoBirthIsPublished() throws KuraStoreException {\n        verify(this.dataService, times(0)).publish(anyString(), any(), anyInt(), anyBoolean(), anyInt());\n    }\n\n    private void thenBirthIsPublishedAfter(long delayMillis, String expectedTopic) throws KuraException {\n        verify(this.dataService, after(delayMillis).never()).publish(eq(expectedTopic), any(), eq(0), eq(false), eq(0));\n        verify(this.dataService, after(delayMillis + SLACK_DELAY).times(1)).publish(eq(expectedTopic), any(), eq(1),\n                eq(false), eq(0));\n    }\n\n    private void thenBirthIsPublishedImmediately(String expectedTopic) throws KuraException {\n        verify(this.dataService, timeout(SLACK_DELAY).times(1)).publish(eq(expectedTopic), any(), eq(1), eq(false),\n                eq(0));\n    }\n\n    private void thenDisconnectIsPublishedImmediately(String expectedTopic) throws KuraException {\n        verify(this.dataService, timeout(SLACK_DELAY).times(1)).publish(eq(expectedTopic), any(), eq(0), eq(false),\n                eq(0));\n    }\n\n    /*\n     * Utilities\n     */\n\n    @Before\n    public void setup() {\n        SystemService systemService = mock(SystemService.class);\n        when(systemService.getDeviceName()).thenReturn(\"test-device\");\n        when(systemService.getHostname()).thenReturn(\"localhost\");\n        when(systemService.getModelName()).thenReturn(\"test-model\");\n        when(systemService.getModelId()).thenReturn(\"test-model-id\");\n        when(systemService.getPartNumber()).thenReturn(\"test-part-number\");\n        when(systemService.getSerialNumber()).thenReturn(\"test-sn\");\n        when(systemService.getFirmwareVersion()).thenReturn(\"test-fm-vers\");\n        when(systemService.getCpuVersion()).thenReturn(\"test-cpu-vers\");\n        when(systemService.getBiosVersion()).thenReturn(\"test-bios-vers\");\n        when(systemService.getOsName()).thenReturn(\"test-os\");\n        when(systemService.getOsVersion()).thenReturn(\"test-os-vers\");\n        when(systemService.getJavaVmName()).thenReturn(\"test-jvm\");\n        when(systemService.getJavaVmVersion()).thenReturn(\"test-jvm-vers\");\n        when(systemService.getJavaVmInfo()).thenReturn(\"test-jvm-info\");\n        when(systemService.getJavaVendor()).thenReturn(\"test-java-vendor\");\n        when(systemService.getJavaVersion()).thenReturn(\"17\");\n        when(systemService.getKuraVersion()).thenReturn(\"develop\");\n        when(systemService.getNumberOfProcessors()).thenReturn(4);\n        when(systemService.getTotalMemory()).thenReturn(8000L);\n        when(systemService.getOsArch()).thenReturn(\"x86\");\n        when(systemService.getOsgiFwName()).thenReturn(\"test-osgi-fm\");\n        when(systemService.getOsgiFwVersion()).thenReturn(\"test-osgi-vers\");\n\n        SystemAdminService systemAdminService = mock(SystemAdminService.class);\n        when(systemAdminService.getUptime()).thenReturn(\"1 day\");\n\n        Marshaller marshaller = new Marshaller() {\n\n            @Override\n            public String marshal(Object object) throws KuraException {\n                if (object instanceof KuraPayload) {\n                    return \"this is a birth message\";\n                }\n                return null;\n            }\n\n            @Override\n            public void marshal(final OutputStream out, Object object) throws KuraException {\n                try {\n                    if (object instanceof KuraPayload) {\n                        out.write(object.toString().getBytes(StandardCharsets.UTF_8));\n                    }\n                } catch (IOException ex) {\n                    // do nothing\n                }\n            }\n        };\n\n        EventAdmin eventAdmin = mock(EventAdmin.class);\n        doNothing().when(eventAdmin).postEvent(any());\n\n        this.cloudService.setDataService(this.dataService);\n        this.cloudService.setSystemService(systemService);\n        this.cloudService.setSystemAdminService(systemAdminService);\n        this.cloudService.setJsonMarshaller(marshaller);\n        this.cloudService.setEventAdmin(eventAdmin);\n    }\n\n    private Map<String, Object> getDefaultProperties() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(ConfigurationService.KURA_SERVICE_PID, \"test.pid\");\n        properties.put(\"payload.encoding\", \"simple-json\");\n        properties.put(\"topic.control-prefix\", \"$EDC\");\n        properties.put(\"republish.mqtt.birth.cert.on.gps.lock\", true);\n        properties.put(\"republish.mqtt.birth.cert.on.modem.detect\", true);\n        properties.put(\"republish.mqtt.birth.cert.on.tamper.event\", true);\n\n        return properties;\n    }\n\n    private ComponentContext getMockComponentContext() {\n        Dictionary<String, Object> componentContextProperties = new Hashtable<>();\n        componentContextProperties.put(ConfigurationService.KURA_SERVICE_PID, \"test.pid\");\n\n        ServiceRegistration registration = mock(ServiceRegistration.class);\n        BundleContext bundleContext = mock(BundleContext.class);\n        when(bundleContext.registerService(ArgumentMatchers.anyString(), ArgumentMatchers.any(),\n                ArgumentMatchers.any(Dictionary.class))).thenReturn(registration);\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        when(componentContext.getProperties()).thenReturn(componentContextProperties);\n        when(componentContext.getBundleContext()).thenReturn(bundleContext);\n\n        return componentContext;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/cloud/CloudClientImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport static org.junit.Assert.*;\nimport static org.mockito.Mockito.*;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudClientListener;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.junit.Test;\n\npublic class CloudClientImplTest {\n\n    @Test\n    public void testCloudClientImpl() throws NoSuchFieldException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        assertEquals(\"appId\", cloudClient.getApplicationId());\n        assertEquals(mockDataService, (DataService) TestUtil.getFieldValue(cloudClient, \"dataService\"));\n        assertEquals(mockCloudService, (CloudServiceImpl) TestUtil.getFieldValue(cloudClient, \"cloudServiceImpl\"));\n        assertNotNull((List<CloudClientListenerAdapter>) TestUtil.getFieldValue(cloudClient, \"listeners\"));\n    }\n\n    @Test\n    public void testRelease() {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        cloudClient.release();\n        verify(mockCloudService, times(1)).removeCloudClient(cloudClient);\n    }\n\n    @Test\n    public void testAddCloudClientListener() throws NoSuchFieldException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudClientListener mocktListener = mock(CloudClientListener.class);\n        cloudClient.addCloudClientListener(mocktListener);\n\n        List<CloudClientListenerAdapter> listeners = (List<CloudClientListenerAdapter>) TestUtil\n                .getFieldValue(cloudClient, \"listeners\");\n\n        assertEquals(1, listeners.size());\n        assertEquals(mocktListener, listeners.get(0).getCloudClientListenerAdapted());\n    }\n\n    @Test\n    public void testRemoveCloudClientListener() throws NoSuchFieldException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudClientListener mocktListener = mock(CloudClientListener.class);\n        cloudClient.addCloudClientListener(mocktListener);\n        cloudClient.removeCloudClientListener(mocktListener);\n\n        List<CloudClientListenerAdapter> listeners = (List<CloudClientListenerAdapter>) TestUtil\n                .getFieldValue(cloudClient, \"listeners\");\n\n        assertEquals(0, listeners.size());\n    }\n\n    @Test\n    public void testIsConnected() {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        doReturn(false).when(mockDataService).isConnected();\n        assertFalse(cloudClient.isConnected());\n\n        doReturn(true).when(mockDataService).isConnected();\n        assertTrue(cloudClient.isConnected());\n    }\n\n    @Test\n    public void testPublishStringKuraPayloadIntBoolean() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Parameters for publish method\n        String appTopic = \"appTopic\";\n        KuraPayload payload = new KuraPayload();\n        int qos = 0;\n        boolean retain = false;\n\n        // Prepare data service and cloud service mocks\n        StringBuilder sb = new StringBuilder();\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator());\n        sb.append(options.getTopicClientIdToken()).append(options.getTopicSeparator()).append(\"appId\");\n        sb.append(options.getTopicSeparator()).append(appTopic);\n\n        String fullTopic = sb.toString();\n        byte[] appPayload = { 1, 2, 3 };\n        int priority = 5;\n        int expectedValue = 42;\n\n        doReturn(appPayload).when(mockCloudService).encodePayload(payload);\n        doReturn(expectedValue).when(mockDataService).publish(fullTopic, appPayload, qos, retain, priority);\n\n        // Execute method\n        int value = cloudClient.publish(appTopic, payload, qos, retain);\n        assertEquals(expectedValue, value);\n    }\n\n    @Test\n    public void testPublishStringKuraPayloadIntBooleanInt() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Parameters for publish method\n        String appTopic = \"appTopic\";\n        KuraPayload payload = new KuraPayload();\n        int qos = 0;\n        boolean retain = false;\n        int priority = 6;\n\n        // Prepare data service and cloud service mocks\n        StringBuilder sb = new StringBuilder();\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator());\n        sb.append(options.getTopicClientIdToken()).append(options.getTopicSeparator()).append(\"appId\");\n        sb.append(options.getTopicSeparator()).append(appTopic);\n\n        String fullTopic = sb.toString();\n        byte[] appPayload = { 1, 2, 3 };\n        int expectedValue = 42;\n\n        doReturn(appPayload).when(mockCloudService).encodePayload(payload);\n        doReturn(expectedValue).when(mockDataService).publish(fullTopic, appPayload, qos, retain, priority);\n\n        // Execute method\n        int value = cloudClient.publish(appTopic, payload, qos, retain, priority);\n        assertEquals(expectedValue, value);\n    }\n\n    @Test\n    public void testPublishStringByteArrayIntBooleanInt() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Parameters for publish method\n        String appTopic = \"appTopic\";\n        byte[] payload = { 1, 2, 3 };\n        int qos = 0;\n        boolean retain = false;\n        int priority = 6;\n\n        // Prepare data service mock\n        StringBuilder sb = new StringBuilder();\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator());\n        sb.append(options.getTopicClientIdToken()).append(options.getTopicSeparator()).append(\"appId\");\n        sb.append(options.getTopicSeparator()).append(appTopic);\n\n        String fullTopic = sb.toString();\n        int expectedValue = 42;\n\n        doReturn(expectedValue).when(mockDataService).publish(fullTopic, payload, qos, retain, priority);\n\n        // Execute method\n        int value = cloudClient.publish(appTopic, payload, qos, retain, priority);\n        assertEquals(expectedValue, value);\n    }\n\n    @Test\n    public void testControlPublishStringKuraPayloadIntBooleanInt() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Parameters for publish method\n        String appTopic = \"appTopic\";\n        KuraPayload payload = new KuraPayload();\n        int qos = 0;\n        boolean retain = false;\n        int priority = 6;\n\n        // Prepare data service and cloud service mocks\n        StringBuilder sb = new StringBuilder();\n        sb.append(options.getTopicControlPrefix()).append(options.getTopicSeparator());\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator());\n        sb.append(options.getTopicClientIdToken()).append(options.getTopicSeparator()).append(\"appId\");\n        sb.append(options.getTopicSeparator()).append(appTopic);\n\n        String fullTopic = sb.toString();\n        byte[] appPayload = { 1, 2, 3 };\n        int expectedValue = 42;\n\n        doReturn(appPayload).when(mockCloudService).encodePayload(payload);\n        doReturn(expectedValue).when(mockDataService).publish(fullTopic, appPayload, qos, retain, priority);\n\n        // Execute method\n        int value = cloudClient.controlPublish(appTopic, payload, qos, retain, priority);\n        assertEquals(expectedValue, value);\n    }\n\n    @Test\n    public void testSubscribeStringInt() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Prepare data service mock\n        String appTopic = \"appTopic\";\n        int qos = 0;\n\n        StringBuilder sb = new StringBuilder();\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator());\n        sb.append(options.getTopicClientIdToken()).append(options.getTopicSeparator()).append(\"appId\");\n        sb.append(options.getTopicSeparator()).append(appTopic);\n\n        String fullTopic = sb.toString();\n\n        // Execute method\n        cloudClient.subscribe(appTopic, qos);\n        verify(mockDataService, times(1)).subscribe(fullTopic, qos);\n    }\n\n    @Test\n    public void testControlSubscribeStringInt() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Prepare data service mock\n        String appTopic = \"appTopic\";\n        int qos = 0;\n\n        StringBuilder sb = new StringBuilder();\n        sb.append(options.getTopicControlPrefix()).append(options.getTopicSeparator());\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator());\n        sb.append(options.getTopicClientIdToken()).append(options.getTopicSeparator()).append(\"appId\");\n        sb.append(options.getTopicSeparator()).append(appTopic);\n\n        String fullTopic = sb.toString();\n\n        // Execute method\n        cloudClient.controlSubscribe(appTopic, qos);\n        verify(mockDataService, times(1)).subscribe(fullTopic, qos);\n    }\n\n    @Test\n    public void testUnsubscribeString() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Prepare data service mock\n        String appTopic = \"appTopic\";\n\n        StringBuilder sb = new StringBuilder();\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator());\n        sb.append(options.getTopicClientIdToken()).append(options.getTopicSeparator()).append(\"appId\");\n        sb.append(options.getTopicSeparator()).append(appTopic);\n\n        String fullTopic = sb.toString();\n\n        // Execute method\n        cloudClient.unsubscribe(appTopic);\n        verify(mockDataService, times(1)).unsubscribe(fullTopic);\n    }\n\n    @Test\n    public void testControlUnsubscribeStringString() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Prepare data service mock\n        String appTopic = \"appTopic\";\n\n        StringBuilder sb = new StringBuilder();\n        sb.append(options.getTopicControlPrefix()).append(options.getTopicSeparator());\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator());\n        sb.append(options.getTopicClientIdToken()).append(options.getTopicSeparator()).append(\"appId\");\n        sb.append(options.getTopicSeparator()).append(appTopic);\n\n        String fullTopic = sb.toString();\n\n        // Execute method\n        cloudClient.controlUnsubscribe(appTopic);\n        verify(mockDataService, times(1)).unsubscribe(fullTopic);\n    }\n\n    @Test\n    public void testGetUnpublishedMessageIds() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Prepare data service mock\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"^(\").append(\"\\\\$EDC\").append(options.getTopicSeparator()).append(\")?\");\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator()).append(\".+\");\n        sb.append(options.getTopicSeparator()).append(\"appId\").append(\"(/.+)?\");\n\n        String topicRegex = sb.toString();\n        ArrayList<Integer> expectedMessageIds = new ArrayList<>();\n        expectedMessageIds.add(1);\n        expectedMessageIds.add(2);\n        expectedMessageIds.add(3);\n\n        doReturn(expectedMessageIds).when(mockDataService).getUnpublishedMessageIds(topicRegex);\n\n        // Execute method\n        List<Integer> messageIds = cloudClient.getUnpublishedMessageIds();\n        assertArrayEquals(expectedMessageIds.toArray(), messageIds.toArray());\n    }\n\n    @Test\n    public void testGetInFlightMessageIds() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Prepare data service mock\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"^(\").append(\"\\\\$EDC\").append(options.getTopicSeparator()).append(\")?\");\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator()).append(\".+\");\n        sb.append(options.getTopicSeparator()).append(\"appId\").append(\"(/.+)?\");\n\n        String topicRegex = sb.toString();\n        ArrayList<Integer> expectedMessageIds = new ArrayList<>();\n        expectedMessageIds.add(1);\n        expectedMessageIds.add(2);\n        expectedMessageIds.add(3);\n\n        doReturn(expectedMessageIds).when(mockDataService).getInFlightMessageIds(topicRegex);\n\n        // Execute method\n        List<Integer> messageIds = cloudClient.getInFlightMessageIds();\n        assertArrayEquals(expectedMessageIds.toArray(), messageIds.toArray());\n    }\n\n    @Test\n    public void testGetDroppedInFlightMessageIds() throws KuraException {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, null);\n        doReturn(options).when(mockCloudService).getCloudServiceOptions();\n\n        // Prepare data service mock\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"^(\").append(\"\\\\$EDC\").append(options.getTopicSeparator()).append(\")?\");\n        sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator()).append(\".+\");\n        sb.append(options.getTopicSeparator()).append(\"appId\").append(\"(/.+)?\");\n\n        String topicRegex = sb.toString();\n        ArrayList<Integer> expectedMessageIds = new ArrayList<>();\n        expectedMessageIds.add(1);\n        expectedMessageIds.add(2);\n        expectedMessageIds.add(3);\n\n        doReturn(expectedMessageIds).when(mockDataService).getDroppedInFlightMessageIds(topicRegex);\n\n        // Execute method\n        List<Integer> messageIds = cloudClient.getDroppedInFlightMessageIds();\n        assertArrayEquals(expectedMessageIds.toArray(), messageIds.toArray());\n    }\n\n    @Test\n    public void testOnMessageArrived() {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudClientListener mocktListener = mock(CloudClientListener.class);\n        cloudClient.addCloudClientListener(mocktListener);\n\n        String deviceId = \"deviceId\";\n        String appTopic = \"appTopic\";\n        KuraPayload payload = new KuraPayload();\n        int qos = 1;\n        boolean retain = false;\n\n        cloudClient.onMessageArrived(deviceId, appTopic, payload, qos, retain);\n\n        verify(mocktListener, times(1)).onMessageArrived(deviceId, appTopic, payload, qos, retain);\n    }\n\n    @Test\n    public void testOnControlMessageArrived() {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudClientListener mocktListener = mock(CloudClientListener.class);\n        cloudClient.addCloudClientListener(mocktListener);\n\n        String deviceId = \"deviceId\";\n        String appTopic = \"appTopic\";\n        KuraPayload payload = new KuraPayload();\n        int qos = 1;\n        boolean retain = false;\n\n        cloudClient.onControlMessageArrived(deviceId, appTopic, payload, qos, retain);\n\n        verify(mocktListener, times(1)).onControlMessageArrived(deviceId, appTopic, payload, qos, retain);\n    }\n\n    @Test\n    public void testOnMessageConfirmed() {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudClientListener mocktListener = mock(CloudClientListener.class);\n        cloudClient.addCloudClientListener(mocktListener);\n\n        int pubId = 1;\n        String appTopic = \"appTopic\";\n\n        cloudClient.onMessageConfirmed(pubId, appTopic);\n\n        verify(mocktListener, times(1)).onMessageConfirmed(pubId, appTopic);\n    }\n\n    @Test\n    public void testOnMessagePublished() {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudClientListener mocktListener = mock(CloudClientListener.class);\n        cloudClient.addCloudClientListener(mocktListener);\n\n        int pubId = 1;\n        String appTopic = \"appTopic\";\n\n        cloudClient.onMessagePublished(pubId, appTopic);\n\n        verify(mocktListener, times(1)).onMessagePublished(pubId, appTopic);\n    }\n\n    @Test\n    public void testOnConnectionEstablished() {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudClientListener mocktListener = mock(CloudClientListener.class);\n        cloudClient.addCloudClientListener(mocktListener);\n\n        cloudClient.onConnectionEstablished();\n\n        verify(mocktListener, times(1)).onConnectionEstablished();\n    }\n\n    @Test\n    public void testOnConnectionLost() {\n        DataService mockDataService = mock(DataService.class);\n        CloudServiceImpl mockCloudService = mock(CloudServiceImpl.class);\n        CloudClientImpl cloudClient = new CloudClientImpl(\"appId\", mockDataService, mockCloudService);\n\n        CloudClientListener mocktListener = mock(CloudClientListener.class);\n        cloudClient.addCloudClientListener(mocktListener);\n\n        cloudClient.onConnectionLost();\n\n        verify(mocktListener, times(1)).onConnectionLost();\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/cloud/CloudServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport static org.junit.Assert.*;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.service.component.ComponentContext;\n\n\npublic class CloudServiceImplTest {\n    \n    static CloudServiceImpl cloudServiceImpl;\n    \n    \n    @BeforeClass\n    public static void testSetup() {\n        DataService dataService = mock(DataService.class);\n        SystemService systemService = mock(SystemService.class);\n        \n        cloudServiceImpl = new CloudServiceImpl();\n        \n        cloudServiceImpl.setDataService(dataService);\n        cloudServiceImpl.setSystemService(systemService);\n    }\n\n    @Test\n    public void testNewCloudClientDataServiceNotConnected() throws KuraException {\n        CloudServiceImpl cloudServiceImpl = new CloudServiceImpl();\n        \n        CloudClient cloudClient = cloudServiceImpl.newCloudClient(\"testAPP\");\n        \n        assertNotNull(cloudClient);\n    }\n    \n    @Test\n    public void testNewCloudClientGetCloudApplicationIdentifiersEmpty() throws KuraException {\n        CloudServiceImpl cloudServiceImpl = new CloudServiceImpl();\n        \n        String[] cloudAppsIds = cloudServiceImpl.getCloudApplicationIdentifiers();\n        \n        assertNotNull(cloudAppsIds);\n        assertArrayEquals(new String[0], cloudAppsIds);\n    }\n    \n    @Test\n    public void testNewCloudClientGetCloudApplicationIdentifiersOneCloudClient() throws KuraException {\n        CloudServiceImpl cloudServiceImpl = new CloudServiceImpl();\n        \n        String testAppId = \"testAPP\";\n        cloudServiceImpl.newCloudClient(testAppId);\n        \n        String[] cloudAppsIds = cloudServiceImpl.getCloudApplicationIdentifiers();\n        \n        assertNotNull(cloudAppsIds);\n        assertEquals(1, cloudAppsIds.length);\n        assertEquals(testAppId, cloudAppsIds[0]);\n    }\n    \n    @Test\n    public void testNewCloudClientGetCloudApplicationIdentifiersOneRequestHandler() throws KuraException {\n        CloudServiceImpl cloudServiceImpl = new CloudServiceImpl();\n        \n        String testAppId = \"testAPP\";\n        RequestHandler requestHandler = mock(RequestHandler.class);\n        cloudServiceImpl.registerRequestHandler(testAppId, requestHandler);\n        \n        String[] cloudAppsIds = cloudServiceImpl.getCloudApplicationIdentifiers();\n        \n        assertNotNull(cloudAppsIds);\n        assertEquals(1, cloudAppsIds.length);\n        assertEquals(testAppId, cloudAppsIds[0]);\n    }\n    \n    @Test\n    public void testGetCloudServiceOptions() {\n        ComponentContext componentContext = mock(ComponentContext.class);\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(ConfigurationService.KURA_SERVICE_PID, \"Cloud Service\");\n        \n        BundleContext bundleContext = mock(BundleContext.class);\n        when(componentContext.getBundleContext()).thenReturn(bundleContext);\n        \n        cloudServiceImpl.activate(componentContext, properties);\n        \n        CloudServiceOptions options = cloudServiceImpl.getCloudServiceOptions();\n        \n        assertNotNull(options);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/cloud/CloudServiceOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.cloud.CloudPayloadEncoding;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\npublic class CloudServiceOptionsTest {\n\n    private static final String TEST_TOPIC_CONTROL_PREFIX = \"newTopicControlPrefix\";\n    private static final String TOPIC_CONTROL_PREFIX = \"topic.control-prefix\";\n    private static final String TOPIC_CONTROL_PREFIX_DEFAULT = \"$EDC\";\n\n    private static final String DEVICE_DISPLAY_NAME = \"device.display-name\";\n    private static final String DEVICE_CUSTOM_NAME = \"device.custom-name\";\n    private static final String ENCODE_GZIP = \"encode.gzip\";\n    private static final String REPUB_BIRTH_ON_GPS_LOCK = \"republish.mqtt.birth.cert.on.gps.lock\";\n    private static final String ENABLE_DFLT_SUBSCRIPTIONS = \"enable.default.subscriptions\";\n    private static final String PAYLOAD_ENCODING = \"payload.encoding\";\n\n    private static SystemService systemService;\n    private static CloudServiceOptions options;\n\n    @BeforeClass\n    public static void testSetup() {\n        systemService = mock(SystemService.class);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(DEVICE_DISPLAY_NAME, \"device-name\");\n        properties.put(ENCODE_GZIP, true);\n        properties.put(REPUB_BIRTH_ON_GPS_LOCK, true);\n        properties.put(TOPIC_CONTROL_PREFIX, TEST_TOPIC_CONTROL_PREFIX);\n        properties.put(ENABLE_DFLT_SUBSCRIPTIONS, false);\n        properties.put(PAYLOAD_ENCODING, \"simple-json\");\n\n        options = new CloudServiceOptions(properties, systemService);\n    }\n\n    @Test\n    public void testGetDeviceDisplayNameNullProps() {\n        SystemService systemService = mock(SystemService.class);\n\n        CloudServiceOptions options = new CloudServiceOptions(null, systemService);\n\n        String deviceDisplayName = options.getDeviceDisplayName();\n\n        assertNotNull(deviceDisplayName);\n        assertEquals(\"\", deviceDisplayName);\n    }\n\n    @Test\n    public void testGetDeviceDisplayNameDeviceName() {\n        String deviceName = \"DeviceName\";\n        when(systemService.getDeviceName()).thenReturn(deviceName);\n\n        String deviceDisplayName = options.getDeviceDisplayName();\n\n        assertNotNull(deviceDisplayName);\n        assertEquals(deviceName, deviceDisplayName);\n    }\n\n    @Test\n    public void testGetDeviceDisplayNameHostnameOther() {\n        when(systemService.getOsName()).thenReturn(\"Other\");\n        when(systemService.getHostname()).thenReturn(\"UNKNOWN\");\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(DEVICE_DISPLAY_NAME, \"hostname\");\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        String deviceDisplayName = options.getDeviceDisplayName();\n\n        assertNotNull(deviceDisplayName);\n        assertEquals(\"UNKNOWN\", deviceDisplayName);\n    }\n\n    @Test\n    public void testGetDeviceDisplayNameCustomNullProp() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(DEVICE_DISPLAY_NAME, \"custom\");\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        String deviceDisplayName = options.getDeviceDisplayName();\n\n        assertNotNull(deviceDisplayName);\n        assertEquals(\"\", deviceDisplayName);\n    }\n\n    @Test\n    public void testGetDeviceDisplayNameCustomInteger() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(DEVICE_DISPLAY_NAME, \"custom\");\n        properties.put(DEVICE_CUSTOM_NAME, 1);\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        String deviceDisplayName = options.getDeviceDisplayName();\n\n        assertNotNull(deviceDisplayName);\n        assertEquals(\"\", deviceDisplayName);\n    }\n\n    @Test\n    public void testGetDeviceDisplayNameCustom() {\n        String testDeviceCustomName = \"test\";\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(DEVICE_DISPLAY_NAME, \"custom\");\n        properties.put(DEVICE_CUSTOM_NAME, testDeviceCustomName);\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        String deviceDisplayName = options.getDeviceDisplayName();\n\n        assertNotNull(deviceDisplayName);\n        assertEquals(testDeviceCustomName, deviceDisplayName);\n    }\n\n    @Test\n    public void testGetDeviceDisplayNameServer() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(DEVICE_DISPLAY_NAME, \"server\");\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        String deviceDisplayName = options.getDeviceDisplayName();\n\n        assertNotNull(deviceDisplayName);\n        assertEquals(\"\", deviceDisplayName);\n    }\n\n    @Test\n    public void testGetDeviceDisplayNameNotValid() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(DEVICE_DISPLAY_NAME, \"invalid\");\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        String deviceDisplayName = options.getDeviceDisplayName();\n\n        assertNotNull(deviceDisplayName);\n        assertEquals(\"\", deviceDisplayName);\n    }\n\n    @Test\n    public void testGetEncodeGZipNullProps() {\n        CloudServiceOptions options = new CloudServiceOptions(null, systemService);\n\n        boolean gzip = options.getEncodeGzip();\n\n        assertFalse(gzip);\n    }\n\n    @Test\n    public void testGetEncodeGZipPropNull() {\n        Map<String, Object> properties = new HashMap<>();\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        boolean gzip = options.getEncodeGzip();\n\n        assertFalse(gzip);\n    }\n\n    @Test\n    public void testGetEncodeGZipPropNotBoolean() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(ENCODE_GZIP, \"invalid\");\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        boolean gzip = options.getEncodeGzip();\n\n        assertFalse(gzip);\n    }\n\n    @Test\n    public void testGetEncodeGZip() {\n\n        boolean gzip = options.getEncodeGzip();\n\n        assertTrue(gzip);\n    }\n\n    @Test\n    public void testGetRepubBirthCertOnGpsLockNullProps() {\n        CloudServiceOptions options = new CloudServiceOptions(null, systemService);\n\n        boolean republish = options.getRepubBirthCertOnGpsLock();\n\n        assertFalse(republish);\n    }\n\n    @Test\n    public void testGetRepubBirthCertOnGpsLockPropNull() {\n        Map<String, Object> properties = new HashMap<>();\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        boolean republish = options.getRepubBirthCertOnGpsLock();\n\n        assertFalse(republish);\n    }\n\n    @Test\n    public void testGetRepubBirthCertOnGpsLockPropNotBoolean() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(REPUB_BIRTH_ON_GPS_LOCK, \"invalid\");\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        boolean republish = options.getRepubBirthCertOnGpsLock();\n\n        assertFalse(republish);\n    }\n\n    @Test\n    public void testGetRepubBirthCertOnGpsLock() {\n\n        boolean republish = options.getRepubBirthCertOnGpsLock();\n\n        assertTrue(republish);\n    }\n\n    @Test\n    public void testGetTopicControlPrefixNullProps() {\n        CloudServiceOptions options = new CloudServiceOptions(null, systemService);\n\n        String topicControlPrefix = options.getTopicControlPrefix();\n\n        assertNotNull(topicControlPrefix);\n        assertEquals(TOPIC_CONTROL_PREFIX_DEFAULT, topicControlPrefix);\n    }\n\n    @Test\n    public void testGetTopicControlPrefixPropNull() {\n        Map<String, Object> properties = new HashMap<>();\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        String topicControlPrefix = options.getTopicControlPrefix();\n\n        assertNotNull(topicControlPrefix);\n        assertEquals(TOPIC_CONTROL_PREFIX_DEFAULT, topicControlPrefix);\n    }\n\n    @Test\n    public void testGetTopicControlPrefixPropNotString() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(TOPIC_CONTROL_PREFIX, true);\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        String topicControlPrefix = options.getTopicControlPrefix();\n\n        assertNotNull(topicControlPrefix);\n        assertEquals(TOPIC_CONTROL_PREFIX_DEFAULT, topicControlPrefix);\n    }\n\n    @Test\n    public void testGetTopicControlPrefix() {\n\n        String topicControlPrefix = options.getTopicControlPrefix();\n\n        assertNotNull(topicControlPrefix);\n        assertEquals(TEST_TOPIC_CONTROL_PREFIX, topicControlPrefix);\n    }\n\n    @Test\n    public void testGetEnableDefaultSubscriptionsNullProps() {\n        CloudServiceOptions options = new CloudServiceOptions(null, systemService);\n\n        boolean enable = options.getEnableDefaultSubscriptions();\n\n        assertTrue(enable);\n    }\n\n    @Test\n    public void testGetEnableDefaultSubscriptionsPropNull() {\n        Map<String, Object> properties = new HashMap<>();\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        boolean enable = options.getEnableDefaultSubscriptions();\n\n        assertTrue(enable);\n    }\n\n    @Test\n    public void testGetEnableDefaultSubscriptionsPropNotBoolean() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(ENABLE_DFLT_SUBSCRIPTIONS, \"invalid\");\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        boolean enable = options.getEnableDefaultSubscriptions();\n\n        assertTrue(enable);\n    }\n\n    @Test\n    public void testEnableDefaultSubscriptions() {\n\n        boolean enable = options.getEnableDefaultSubscriptions();\n\n        assertFalse(enable);\n    }\n\n    @Test\n    public void testGetPayloadEncodingNullProps() {\n        CloudServiceOptions options = new CloudServiceOptions(null, systemService);\n\n        CloudPayloadEncoding cloudPayloadEncoding = options.getPayloadEncoding();\n\n        assertNotNull(cloudPayloadEncoding);\n        assertEquals(CloudPayloadEncoding.KURA_PROTOBUF, cloudPayloadEncoding);\n    }\n\n    @Test\n    public void testGetPayloadEncodingPropNull() {\n        Map<String, Object> properties = new HashMap<>();\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        CloudPayloadEncoding cloudPayloadEncoding = options.getPayloadEncoding();\n\n        assertNotNull(cloudPayloadEncoding);\n        assertEquals(CloudPayloadEncoding.KURA_PROTOBUF, cloudPayloadEncoding);\n    }\n\n    @Test\n    public void testGetPayloadEncodingPropNotString() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(TOPIC_CONTROL_PREFIX, true);\n\n        CloudServiceOptions options = new CloudServiceOptions(properties, systemService);\n\n        CloudPayloadEncoding cloudPayloadEncoding = options.getPayloadEncoding();\n\n        assertNotNull(cloudPayloadEncoding);\n        assertEquals(CloudPayloadEncoding.KURA_PROTOBUF, cloudPayloadEncoding);\n    }\n\n    @Test\n    public void testGetPayloadEncoding() {\n\n        CloudPayloadEncoding cloudPayloadEncoding = options.getPayloadEncoding();\n\n        assertNotNull(cloudPayloadEncoding);\n        assertEquals(CloudPayloadEncoding.SIMPLE_JSON, cloudPayloadEncoding);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/cloud/LifeCyclePayloadBuilderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.cloud;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.message.KuraDeviceProfile;\nimport org.eclipse.kura.net.NetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.eclipse.kura.net.NetworkService;\nimport org.eclipse.kura.position.PositionService;\nimport org.eclipse.kura.system.SystemAdminService;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.osgi.util.measurement.Measurement;\nimport org.osgi.util.measurement.Unit;\nimport org.osgi.util.position.Position;\n\npublic class LifeCyclePayloadBuilderTest {\n\n    private SystemService systemService;\n    private SystemAdminService sysAdminService;\n    private Optional<NetworkService> networkService;\n    private Optional<PositionService> positionService;\n    private CloudServiceImpl cloudServiceImpl;\n    private LifeCyclePayloadBuilder lifeCyclePayloadBuilder;\n    private KuraDeviceProfile kuraDeviceProfile;\n\n    private final List<NetInterface<? extends NetInterfaceAddress>> emptyNetInterfacesList = new ArrayList<NetInterface<? extends NetInterfaceAddress>>();\n\n    @Test\n    public void shoudBuildDeviceProfileWithPositionIfPositionServiceIsAvaiable() throws KuraException {\n        givenSystemService();\n        givenSystemAdminService();\n        givenNetworkService(emptyNetInterfacesList);\n        givenPositionService();\n        givenCloudServiceImpl();\n        givenLifeCyclePayloadBuilder();\n\n        whenBuildDeviceProfile();\n\n        thenDeviceProfileHasPosition();\n    }\n\n    @Test\n    public void shoudBuildDeviceProfileWithoutPositionIfPositionServiceIsNotAvaiable() throws KuraException {\n        givenSystemService();\n        givenSystemAdminService();\n        givenNetworkService(emptyNetInterfacesList);\n        givenCloudServiceImpl();\n        givenLifeCyclePayloadBuilder();\n\n        whenBuildDeviceProfile();\n\n        thenDeviceProfileHasNotPosition();\n    }\n\n    private void givenCloudServiceImpl() {\n        this.cloudServiceImpl = mock(CloudServiceImpl.class);\n        when(this.cloudServiceImpl.getSystemService()).thenReturn(this.systemService);\n        when(this.cloudServiceImpl.getSystemAdminService()).thenReturn(this.sysAdminService);\n        when(this.cloudServiceImpl.getNetworkService()).thenReturn(this.networkService);\n        when(this.cloudServiceImpl.getPositionService()).thenReturn(this.positionService);\n    }\n\n    private void givenLifeCyclePayloadBuilder() {\n        this.lifeCyclePayloadBuilder = new LifeCyclePayloadBuilder(this.cloudServiceImpl);\n    }\n\n    private void givenSystemService() {\n        this.systemService = mock(SystemService.class);\n        when(this.systemService.getDeviceName()).thenReturn(\"deviceName\");\n        when(this.systemService.getModelName()).thenReturn(\"modelName\");\n        when(this.systemService.getModelId()).thenReturn(\"modelId\");\n        when(this.systemService.getPartNumber()).thenReturn(\"partNumber\");\n        when(this.systemService.getSerialNumber()).thenReturn(\"serialNumber\");\n        when(this.systemService.getFirmwareVersion()).thenReturn(\"firmwareVersion\");\n        when(this.systemService.getCpuVersion()).thenReturn(\"cpuVersion\");\n        when(this.systemService.getBiosVersion()).thenReturn(\"biosVersion\");\n        when(this.systemService.getOsName()).thenReturn(\"osName\");\n        when(this.systemService.getOsVersion()).thenReturn(\"osVersion\");\n        when(this.systemService.getJavaVmName()).thenReturn(\"javaVmName\");\n        when(this.systemService.getJavaVmVersion()).thenReturn(\"javaVmVersion\");\n        when(this.systemService.getJavaVmInfo()).thenReturn(\"javaVmInfo\");\n        when(this.systemService.getJavaVendor()).thenReturn(\"javaVendor\");\n        when(this.systemService.getJavaVersion()).thenReturn(\"javaVersion\");\n        when(this.systemService.getKuraVersion()).thenReturn(\"kuraVersion\");\n        when(this.systemService.getNumberOfProcessors()).thenReturn(1);\n        when(this.systemService.getTotalMemory()).thenReturn(1L);\n        when(this.systemService.getOsArch()).thenReturn(\"osArch\");\n        when(this.systemService.getOsgiFwName()).thenReturn(\"osgiFwName\");\n        when(this.systemService.getOsgiFwVersion()).thenReturn(\"osgiFwVersion\");\n        when(this.systemService.getJavaVmVendor()).thenReturn(\"javaVmVendor\");\n        when(this.systemService.getJdkVendorVersion()).thenReturn(\"jdkVendorVersion\");\n    }\n\n    private void givenSystemAdminService() {\n        this.sysAdminService = mock(SystemAdminService.class);\n        when(this.sysAdminService.getUptime()).thenReturn(\"0\");\n    }\n\n    private void givenNetworkService(List<NetInterface<? extends NetInterfaceAddress>> netInterfaces)\n            throws KuraException {\n        this.networkService = Optional.of(mock(NetworkService.class));\n        when(this.networkService.get().getActiveNetworkInterfaces()).thenReturn(netInterfaces);\n    }\n\n    private void givenPositionService() {\n        this.positionService = Optional.of(mock(PositionService.class));\n        Position position = new Position(new Measurement(Math.toRadians(1.0), Unit.rad),\n                new Measurement(Math.toRadians(2.0), Unit.rad), new Measurement(3.0, Unit.m),\n                new Measurement(4.0, Unit.m_s), new Measurement(Math.toRadians(5.0), Unit.rad));\n        when(this.positionService.get().getPosition()).thenReturn(position);\n    }\n\n    private void whenBuildDeviceProfile() {\n        this.kuraDeviceProfile = this.lifeCyclePayloadBuilder.buildDeviceProfile();\n    }\n\n    private void thenDeviceProfileHasPosition() {\n        assertEquals(Double.valueOf(1.0), kuraDeviceProfile.getLatitude());\n        assertEquals(Double.valueOf(2.0), kuraDeviceProfile.getLongitude());\n        assertEquals(Double.valueOf(3.0), kuraDeviceProfile.getAltitude());\n    }\n\n    private void thenDeviceProfileHasNotPosition() {\n        assertEquals(Double.valueOf(0.0), kuraDeviceProfile.getLatitude());\n        assertEquals(Double.valueOf(0.0), kuraDeviceProfile.getLongitude());\n        assertEquals(Double.valueOf(0.0), kuraDeviceProfile.getAltitude());\n    }\n\n    @Before\n    public void clear() {\n        this.positionService = Optional.empty();\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/cloud/publisher/CloudPublisherImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.publisher;\n\nimport org.eclipse.kura.KuraException;\nimport org.junit.Test;\n\npublic class CloudPublisherImplTest {\n\n    @Test(expected = KuraException.class)\n    public void testPublishNoCloudService() throws KuraException {\n        CloudPublisherImpl cloudPublisherImpl = new CloudPublisherImpl();\n        cloudPublisherImpl.publish(null);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/cloud/publisher/CloudPublisherOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.publisher;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.core.message.MessageType;\nimport org.junit.Test;\n\npublic class CloudPublisherOptionsTest {\n\n    @Test(expected = NullPointerException.class)\n    public void testEmptyProps() {\n        new CloudPublisherOptions(null);\n    }\n\n    @Test\n    public void testNotAllProps() {\n        Map<String, Object> props = new HashMap<>();\n        props.put(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(),\n                \"org.eclipse.kura.cloud.CloudService\");\n        CloudPublisherOptions options = new CloudPublisherOptions(props);\n        assertNotNull(options);\n        assertNotNull(options.getCloudServicePid());\n        assertNotNull(options.getQos());\n    }\n\n    @Test\n    public void testGetCloudServicePid() {\n        Map<String, Object> props = new HashMap<>();\n        String cloudServicePid = \"org.eclipse.kura.cloud.CloudService1\";\n        props.put(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), cloudServicePid);\n        CloudPublisherOptions options = new CloudPublisherOptions(props);\n        assertNotNull(options);\n        assertEquals(cloudServicePid, options.getCloudServicePid());\n    }\n\n    @Test\n    public void testGetAppId() {\n        String appId = \"W2\";\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"appId\", appId);\n        \n        CloudPublisherOptions options = new CloudPublisherOptions(props);\n        assertNotNull(options);\n        assertEquals(appId, options.getAppId());\n    }\n    \n    @Test\n    public void testGetAppTopic() {\n        String appTopic = \"A2/$assetName\";\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"app.topic\", appTopic);\n        CloudPublisherOptions options = new CloudPublisherOptions(props);\n        assertNotNull(options);\n        assertEquals(appTopic, options.getAppTopic());\n    }\n    \n    @Test\n    public void testGetQos() {\n        int qos = 1;\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"qos\", qos);\n        CloudPublisherOptions options = new CloudPublisherOptions(props);\n        assertNotNull(options);\n        assertEquals(qos, options.getQos());\n    }\n    \n    @Test\n    public void testIsRetain() {\n        boolean retain = true;\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"retain\", retain);\n        CloudPublisherOptions options = new CloudPublisherOptions(props);\n        assertNotNull(options);\n        assertEquals(retain, options.isRetain());\n    }\n    \n    @Test\n    public void testMessageType() {\n        MessageType messageType = MessageType.CONTROL;\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"message.type\", \"control\");\n        CloudPublisherOptions options = new CloudPublisherOptions(props);\n        assertNotNull(options);\n        assertEquals(messageType.name(), options.getMessageType().name());\n    }\n    \n    @Test\n    public void testGetPriority() {\n        int priority= 1;\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"priority\", priority);\n        CloudPublisherOptions options = new CloudPublisherOptions(props);\n        assertNotNull(options);\n        assertEquals(priority, options.getPriority());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/cloud/publisher/NotificationPublisherImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.cloud.publisher;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.core.cloud.CloudServiceImpl;\nimport org.eclipse.kura.core.cloud.CloudServiceOptions;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatchers;\n\npublic class NotificationPublisherImplTest {\n\n    private static final String MESSAGE_TYPE_KEY = \"messageType\";\n\n    private static final String REQUESTOR_CLIENT_ID_KEY = \"requestorClientId\";\n\n    private static final String APP_ID_KEY = \"appId\";\n\n    @Test(expected = KuraException.class)\n    public void testPublishNullCloudService() throws KuraException {\n        NotificationPublisherImpl notificationPublisherImpl = new NotificationPublisherImpl(null);\n\n        notificationPublisherImpl.publish(new KuraMessage(null));\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testPublishNullMessage() throws KuraException {\n        CloudServiceImpl cloudServiceImpl = mock(CloudServiceImpl.class);\n        NotificationPublisherImpl notificationPublisherImpl = new NotificationPublisherImpl(cloudServiceImpl);\n\n        notificationPublisherImpl.publish(null);\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testPublishNullProps() throws KuraException {\n        CloudServiceImpl cloudServiceImpl = mock(CloudServiceImpl.class);\n        NotificationPublisherImpl notificationPublisherImpl = new NotificationPublisherImpl(cloudServiceImpl);\n\n        KuraPayload payload = new KuraPayload();\n        KuraMessage message = new KuraMessage(payload);\n        notificationPublisherImpl.publish(message);\n    }\n\n    @Test\n    public void testPublish() throws KuraException {\n        CloudServiceImpl cloudServiceImpl = mock(CloudServiceImpl.class);\n        SystemService systemService = mock(SystemService.class);\n        DataService dataService = mock(DataService.class);\n\n        Map<String, Object> optionsProps = new HashMap<>();\n        CloudServiceOptions options = new CloudServiceOptions(optionsProps, systemService);\n\n        when(cloudServiceImpl.getCloudServiceOptions()).thenReturn(options);\n        when(cloudServiceImpl.encodePayload(ArgumentMatchers.any())).thenReturn(new byte[0]);\n        when(cloudServiceImpl.getDataService()).thenReturn(dataService);\n        when(cloudServiceImpl.publish(ArgumentMatchers.any())).thenReturn(\"1\");\n\n        NotificationPublisherImpl notificationPublisherImpl = new NotificationPublisherImpl(cloudServiceImpl);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(APP_ID_KEY, \"appId\");\n        properties.put(MESSAGE_TYPE_KEY, \"messageType\");\n        properties.put(REQUESTOR_CLIENT_ID_KEY, \"requestorClientId\");\n        KuraPayload payload = new KuraPayload();\n        KuraMessage message = new KuraMessage(payload, properties);\n        String messageId = notificationPublisherImpl.publish(message);\n\n        assertNotNull(messageId);\n        assertEquals(\"1\", messageId);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/message/KuraBirthPayloadTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.message;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nimport org.eclipse.kura.message.KuraBirthPayload;\nimport org.eclipse.kura.message.KuraBirthPayload.KuraBirthPayloadBuilder;\nimport org.eclipse.kura.message.KuraBirthPayload.TamperStatus;\nimport org.eclipse.kura.message.KuraDeviceProfile;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.junit.Test;\nimport org.junit.experimental.runners.Enclosed;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\n@RunWith(Enclosed.class)\npublic class KuraBirthPayloadTest {\n\n    public static class BirthPayloadTest extends StepsCollection {\n\n        @Test\n        public void shouldReturnBirthPayloadWithDefaults() {\n            givenBuilderWithDefaultRequiredValues();\n\n            whenKuraPayloadBuilderBuild();\n\n            thenBirthPayloadContainsAllDefaultRequiredValues();\n            thenBirthPayloadContainsApplicationFramework(KuraDeviceProfile.DEFAULT_APPLICATION_FRAMEWORK);\n            thenBirthPayloadContainsTamperStatus(TamperStatus.UNSUPPORTED);\n            thenBirthPayloadNotContainsKuraPosition();\n            thenBirthPayloadNotContainsJdkVendorVersion();\n        }\n\n        @Test\n        public void shouldReturnBirthPayloadWithCorrectPosition() {\n            givenBuilderWithDefaultRequiredValues();\n            givenBuilderWithPosition(new Double(200), new Double(300));\n\n            whenKuraPayloadBuilderBuild();\n\n            thenBirthPayloadContainsPosition(new Double(200), new Double(300));\n        }\n\n        @Test\n        public void shouldReturnBirthPayloadWithCorrectApplicationFramework() {\n            givenBuilderWithDefaultRequiredValues();\n            givenBuilderWithApplicationFramework(\"test123\");\n\n            whenKuraPayloadBuilderBuild();\n\n            thenBirthPayloadContainsApplicationFramework(\"test123\");\n        }\n\n        @Test\n        public void shouldReturnBirthPayloadWithJdkVendorVersion() {\n            givenBuilderWithDefaultRequiredValues();\n            givenBuilderWithJdkVendorVersion(\"JDK 123\");\n\n            whenKuraPayloadBuilderBuild();\n\n            thenBirthPayloadContainsJdkVendorVersion(\"JDK 123\");\n        }\n\n    }\n\n    @RunWith(Parameterized.class)\n    public static class TamperStatusParametricTest extends StepsCollection {\n\n        @Parameters\n        public static Collection<TamperStatus> TamperStatusParams() {\n            List<TamperStatus> params = new ArrayList<>();\n            params.add(TamperStatus.UNSUPPORTED);\n            params.add(TamperStatus.TAMPERED);\n            params.add(TamperStatus.UNSUPPORTED);\n            return params;\n        }\n\n        private TamperStatus testedTamperStatus;\n\n        public TamperStatusParametricTest(TamperStatus status) {\n            this.testedTamperStatus = status;\n        }\n\n        @Test\n        public void shouldReturnBirthPayloadWithCorrectTamperStatus() {\n            givenBuilderWithDefaultRequiredValues();\n            givenBuilderWithTamperStatus(this.testedTamperStatus);\n\n            whenKuraPayloadBuilderBuild();\n\n            thenBirthPayloadContainsTamperStatus(this.testedTamperStatus);\n        }\n\n        @Test\n        public void shouldReturnCorrectToStringRepresentation() {\n            givenBuilderWithDefaultRequiredValues();\n            givenBuilderWithTamperStatus(this.testedTamperStatus);\n            givenBuilderWithJdkVendorVersion(\"JDK 123\");\n            givenBuilderWithApplicationFramework(\"test123\");\n            givenBuilderWithPosition(new Double(200), new Double(300));\n\n            whenToString();\n\n            thenToStringRepresentationIsCorrect();\n        }\n\n    }\n\n    static class StepsCollection {\n\n        private static final String DEFAULT_TEST_VALUE = \"value\";\n\n        private KuraBirthPayloadBuilder builder;\n        private KuraBirthPayload birthPayload;\n        private String toStringRepresentation;\n\n        /*\n         * Given\n         */\n\n        void givenBuilderWithDefaultRequiredValues() {\n            this.builder = new KuraBirthPayloadBuilder();\n            this.builder.withUptime(DEFAULT_TEST_VALUE);\n            this.builder.withDisplayName(DEFAULT_TEST_VALUE);\n            this.builder.withAvailableProcessors(DEFAULT_TEST_VALUE);\n            this.builder.withTotalMemory(DEFAULT_TEST_VALUE);\n            this.builder.withOsArch(DEFAULT_TEST_VALUE);\n            this.builder.withOsgiFramework(DEFAULT_TEST_VALUE);\n            this.builder.withOsgiFrameworkVersion(DEFAULT_TEST_VALUE);\n            this.builder.withModelName(DEFAULT_TEST_VALUE);\n            this.builder.withModelId(DEFAULT_TEST_VALUE);\n            this.builder.withPartNumber(DEFAULT_TEST_VALUE);\n            this.builder.withSerialNumber(DEFAULT_TEST_VALUE);\n            this.builder.withFirmwareVersion(DEFAULT_TEST_VALUE);\n            this.builder.withBiosVersion(DEFAULT_TEST_VALUE);\n            this.builder.withCpuVersion(DEFAULT_TEST_VALUE);\n            this.builder.withOs(DEFAULT_TEST_VALUE);\n            this.builder.withOsVersion(DEFAULT_TEST_VALUE);\n            this.builder.withJvmName(DEFAULT_TEST_VALUE);\n            this.builder.withJvmVersion(DEFAULT_TEST_VALUE);\n            this.builder.withJvmProfile(DEFAULT_TEST_VALUE);\n            this.builder.withKuraVersion(DEFAULT_TEST_VALUE);\n            // this.builder.withApplicationFramework(DEFAULT_TEST_VALUE);\n            this.builder.withApplicationFrameworkVersion(DEFAULT_TEST_VALUE);\n            this.builder.withConnectionInterface(DEFAULT_TEST_VALUE);\n            this.builder.withConnectionIp(DEFAULT_TEST_VALUE);\n            this.builder.withAcceptEncoding(DEFAULT_TEST_VALUE);\n            this.builder.withApplicationIdentifiers(DEFAULT_TEST_VALUE);\n            this.builder.withModemImei(DEFAULT_TEST_VALUE);\n            this.builder.withModemIccid(DEFAULT_TEST_VALUE);\n            this.builder.withModemImsi(DEFAULT_TEST_VALUE);\n            this.builder.withModemRssi(DEFAULT_TEST_VALUE);\n            this.builder.withModemFirmwareVersion(DEFAULT_TEST_VALUE);\n            // this.builder.withPosition(position);\n            this.builder.withPayloadEncoding(DEFAULT_TEST_VALUE);\n            // this.builder.withTamperStatus(status);\n            this.builder.withJvmVendor(DEFAULT_TEST_VALUE);\n            this.builder.withJdkVendorVersion(null);\n        }\n\n        void givenBuilderWithApplicationFramework(String applicationFramework) {\n            this.builder.withApplicationFramework(applicationFramework);\n        }\n\n        void givenBuilderWithTamperStatus(TamperStatus status) {\n            this.builder.withTamperStatus(status);\n        }\n\n        void givenBuilderWithPosition(double latitude, double longitude) {\n            KuraPosition position = new KuraPosition();\n            position.setLatitude(latitude);\n            position.setLongitude(longitude);\n            this.builder.withPosition(position);\n        }\n\n        void givenBuilderWithJdkVendorVersion(String jdkVendorVersion) {\n            this.builder.withJdkVendorVersion(jdkVendorVersion);\n        }\n\n        /*\n         * When\n         */\n\n        void whenKuraPayloadBuilderBuild() {\n            this.birthPayload = this.builder.build();\n        }\n\n        void whenToString() {\n            whenKuraPayloadBuilderBuild();\n            this.toStringRepresentation = this.birthPayload.toString();\n        }\n\n        /*\n         * Then\n         */\n\n        void thenBirthPayloadContainsAllDefaultRequiredValues() {\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getUptime());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getDisplayName());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getAvailableProcessors());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getTotalMemory());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getOsArch());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getOsgiFramework());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getOsgiFrameworkVersion());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getModelName());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getModelId());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getPartNumber());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getSerialNumber());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getFirmwareVersion());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getBiosVersion());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getCpuVersion());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getOs());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getOsVersion());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getJvmName());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getJvmVersion());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getJvmProfile());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getKuraVersion());\n            // this.birthPayload.getApplicationFramework();\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getApplicationFrameworkVersion());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getConnectionInterface());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getConnectionIp());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getAcceptEncoding());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getApplicationIdentifiers());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getModemImei());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getModemIccid());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getModemImsi());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getModemRssi());\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getModemFirmwareVersion());\n            // this.birthPayload.getPosition();\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getPayloadEncoding());\n            // this.birthPayload.getTamperStatus();\n            assertEquals(DEFAULT_TEST_VALUE, this.birthPayload.getJvmVendor());\n            // this.birthPayload.getJdkVendorVersion();\n        }\n\n        void thenBirthPayloadContainsApplicationFramework(String expectedApplicationFramework) {\n            assertEquals(expectedApplicationFramework, this.birthPayload.getApplicationFramework());\n        }\n\n        void thenBirthPayloadContainsTamperStatus(TamperStatus expectedTamperStatus) {\n            assertEquals(expectedTamperStatus, this.birthPayload.getTamperStatus());\n        }\n\n        void thenBirthPayloadNotContainsKuraPosition() {\n            assertNull(this.birthPayload.getPosition());\n        }\n\n        void thenBirthPayloadNotContainsJdkVendorVersion() {\n            assertNull(this.birthPayload.getJdkVendorVersion());\n        }\n\n        void thenBirthPayloadContainsPosition(Double expectedLatitude, Double expectedLongitude) {\n            KuraPosition position = this.birthPayload.getPosition();\n            assertNotNull(position);\n            assertEquals(expectedLatitude, position.getLatitude());\n            assertEquals(expectedLongitude, position.getLongitude());\n        }\n\n        void thenBirthPayloadContainsJdkVendorVersion(String expectedJdkVendorVersion) {\n            assertEquals(expectedJdkVendorVersion, this.birthPayload.getJdkVendorVersion());\n        }\n\n        void thenToStringRepresentationIsCorrect() {\n            assertTrue(this.toStringRepresentation.startsWith(\"KuraBirthPayload [\"));\n            assertTrue(this.toStringRepresentation.endsWith(\"]\"));\n\n            assertEquals(\"Some properties are missing in the toString method.\", 30,\n                    this.toStringRepresentation.split(\",\").length);\n\n            for (String keyValueField : this.toStringRepresentation.split(\",\")) {\n                assertTrue(keyValueField.contains(\"=\"));\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/message/KuraDisconnectPayloadTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.message;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport org.eclipse.kura.message.KuraDisconnectPayload;\nimport org.junit.Test;\n\n\npublic class KuraDisconnectPayloadTest {\n\n    @Test\n    public void testComplete() {\n        String uptime = \"0 days 1:2:34 hms\";\n        String displayName = \"dname\";\n        KuraDisconnectPayload payload = new KuraDisconnectPayload(uptime, displayName);\n\n        assertEquals(uptime, payload.getUptime());\n        assertEquals(displayName, payload.getDisplayName());\n\n        assertTrue(payload.toString().contains(uptime));\n        assertTrue(payload.toString().contains(displayName));\n    }\n\n    @Test\n    public void testCopy() {\n        String uptime = \"0 days 1:2:34 hms\";\n        String displayName = \"dname\";\n        KuraDisconnectPayload payload = new KuraDisconnectPayload(uptime, displayName);\n        byte[] bytes = { 1, 2, 3 };\n        payload.setBody(bytes);\n\n        KuraDisconnectPayload payload2 = new KuraDisconnectPayload(payload);\n\n        assertEquals(uptime, payload2.getUptime());\n        assertEquals(displayName, payload2.getDisplayName());\n        assertArrayEquals(bytes, payload2.getBody());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/message/protobuf/KuraPayloadProtoBuilderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.message.protobuf;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.List;\n\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.Builder;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition;\nimport org.junit.Test;\n\nimport com.google.protobuf.ByteString;\n\npublic class KuraPayloadProtoBuilderTest {\n\n    @Test\n    public void testBuilderMerge() {\n        // test that merging an existing KuraPayload in a Builder works\n\n        String metricName = \"metric.name\";\n        String metric2Name = \"metric2.name\";\n        long time = 1503300000000L;\n        double lon = 14.0;\n        double lat = 46.0;\n        String bodyTxt = \"test\";\n\n        Builder builder = KuraPayload.newBuilder();\n        KuraMetric metric = KuraMetric.newBuilder().setName(metricName).setType(ValueType.STRING)\n                .setStringValue(\"metric.value\").build();\n        builder.addMetric(metric);\n        KuraPosition pos = KuraPosition.newBuilder().setLongitude(lon).setLatitude(lat).setPrecision(0.01).build();\n        builder.setPosition(pos);\n        builder.setTimestamp(time);\n        builder.setBody(ByteString.copyFromUtf8(bodyTxt));\n\n        assertTrue(builder.isInitialized());\n        assertTrue(builder.hasPosition());\n        assertTrue(builder.hasTimestamp());\n\n        KuraPayload payload = builder.build();\n\n        Builder builder2 = KuraPayload.newBuilder();\n        KuraMetric metric2 = KuraMetric.newBuilder().setName(metric2Name).setType(ValueType.DOUBLE)\n                .setDoubleValue(3.1415926).build();\n        builder2.addMetric(metric2);\n        builder2.setBody(ByteString.copyFromUtf8(\"test2\"));\n\n        builder2.mergeFrom(payload);\n\n        KuraPayload payload2 = builder2.build();\n\n        final KuraPosition pos2 = payload2.getPosition();\n        assertNotNull(pos2);\n        assertEquals(lon, pos2.getLongitude(), 0.000001);\n        assertEquals(lat, pos2.getLatitude(), 0.000001);\n\n        final List<KuraMetric> metrics = payload2.getMetricList();\n        assertNotNull(metrics);\n        assertEquals(2, metrics.size());\n\n        assertEquals(metric2Name, metrics.get(0).getName());\n        assertEquals(metricName, metrics.get(1).getName());\n\n        assertEquals(time, payload2.getTimestamp());\n\n        assertEquals(bodyTxt, payload2.getBody().toStringUtf8());\n    }\n\n    @Test\n    public void testBuilderMergeNoMetric() {\n        // test that merging works if the new Builder has no metric, yet\n\n        String metricName = \"metric.name\";\n        double lon = 13.0;\n        double lat = 46.0;\n\n        Builder builder = KuraPayload.newBuilder();\n        KuraMetric metric = KuraMetric.newBuilder().setName(metricName).setType(ValueType.STRING)\n                .setStringValue(\"metric.value\").build();\n        builder.addMetric(0, metric);\n        KuraPosition pos = KuraPosition.newBuilder().setLongitude(lon).setLatitude(lat).setPrecision(0.01).build();\n        builder.setPosition(pos);\n\n        assertTrue(builder.isInitialized());\n\n        KuraPayload payload = builder.build();\n\n        Builder builder2 = KuraPayload.newBuilder();\n        KuraPosition pos2 = KuraPosition.newBuilder().setLongitude(13.0).setLatitude(40.0).setPrecision(0.01).build();\n        builder2.setPosition(pos2);\n        builder2.setBody(ByteString.copyFromUtf8(\"test2\"));\n\n        builder2.mergeFrom(payload);\n\n        KuraPayload payload2 = builder2.build();\n\n        final List<KuraMetric> metrics = payload2.getMetricList();\n        assertNotNull(metrics);\n        assertEquals(1, metrics.size());\n\n        assertEquals(metricName, metrics.get(0).getName());\n\n        assertEquals(\"test2\", payload2.getBody().toStringUtf8());\n\n        assertEquals(pos, payload2.getPosition());\n    }\n\n    @Test\n    public void testBuilderClear() {\n        // test various clear() methods\n\n        String metricName = \"metric.name\";\n        double lon = 14.0;\n        double lat = 46.0;\n        String bodyTxt = \"test\";\n\n        Builder builder = KuraPayload.newBuilder();\n        KuraMetric metric = KuraMetric.newBuilder().setName(metricName).setType(ValueType.STRING)\n                .setStringValue(\"metric.value\").build();\n        builder.addMetric(metric);\n        KuraPosition pos = KuraPosition.newBuilder().setLongitude(lon).setLatitude(lat).setPrecision(0.01).build();\n        builder.setPosition(pos);\n        builder.setTimestamp(1503300000000L);\n        builder.setBody(ByteString.copyFromUtf8(bodyTxt));\n\n        assertTrue(builder.isInitialized());\n        assertTrue(builder.hasPosition());\n        assertTrue(builder.hasTimestamp());\n        assertTrue(builder.hasBody());\n        assertEquals(1, builder.getMetricCount());\n\n        builder.clearBody();\n        builder.clearMetric();\n        builder.clearPosition();\n        builder.clearTimestamp();\n\n        assertTrue(builder.isInitialized());\n        assertFalse(builder.hasPosition());\n        assertFalse(builder.hasTimestamp());\n        assertFalse(builder.hasBody());\n        assertEquals(0, builder.getMetricCount());\n    }\n\n    @Test\n    public void testBuilderClearAll() {\n        // test the clear() method\n\n        String metricName = \"metric.name\";\n        long time = 1503300000000L;\n        double lon = 14.0;\n        double lat = 46.0;\n        String bodyTxt = \"test\";\n\n        Builder builder = KuraPayload.newBuilder();\n        KuraMetric metric = KuraMetric.newBuilder().setName(metricName).setType(ValueType.STRING)\n                .setStringValue(\"metric.value\").build();\n        builder.addMetric(metric);\n        KuraPosition pos = KuraPosition.newBuilder().setLongitude(lon).setLatitude(lat).setPrecision(0.01).build();\n        builder.setPosition(pos);\n        builder.setTimestamp(time);\n        builder.setBody(ByteString.copyFromUtf8(bodyTxt));\n\n        assertTrue(builder.isInitialized());\n        assertTrue(builder.hasPosition());\n        assertTrue(builder.hasTimestamp());\n        assertTrue(builder.hasBody());\n        assertEquals(1, builder.getMetricCount());\n\n        builder.clear();\n\n        assertTrue(builder.isInitialized());\n        assertFalse(builder.hasPosition());\n        assertFalse(builder.hasTimestamp());\n        assertFalse(builder.hasBody());\n        assertEquals(0, builder.getMetricCount());\n    }\n\n    @Test(expected = NullPointerException.class)\n    public void testBuilderSetPositionNull() {\n        // test setting position to null\n\n        Builder builder = KuraPayload.newBuilder();\n        builder.setPosition((KuraPosition) null);\n    }\n\n    @Test\n    public void testBuilderSetPosition() {\n        // test setting position builder\n\n        double lon = 14.0;\n        double lat = 46.0;\n\n        Builder builder = KuraPayload.newBuilder();\n        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder posBuilder = KuraPosition\n                .newBuilder().setLongitude(lon).setLatitude(lat).setPrecision(0.01);\n        builder.setPosition(posBuilder);\n\n        assertTrue(builder.hasPosition());\n\n        assertEquals(posBuilder.build(), builder.getPosition());\n    }\n\n    @Test\n    public void testBuilderMergeWithMetricBuilder() {\n        // test that merging an existing KuraPayload in a Builder works\n\n        String metricName = \"metric.name\";\n        String metric2Name = \"metric2.name\";\n\n        Builder builder = KuraPayload.newBuilder();\n        KuraMetric metric = KuraMetric.newBuilder().setName(metricName).setType(ValueType.STRING)\n                .setStringValue(\"metric.value\").build();\n        builder.addMetric(metric);\n\n        KuraPayload payload = builder.build();\n\n        Builder builder2 = KuraPayload.newBuilder();\n        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder mBuilder = builder2\n                .addMetricBuilder();\n\n        assertEquals(1, builder2.getMetricCount()); // it's not valid, but it's still 'there'\n\n        mBuilder.setName(metric2Name).setType(ValueType.DOUBLE).setDoubleValue(3.1415926);\n\n        builder2.mergeFrom(payload);\n\n        KuraPayload payload2 = builder2.build();\n\n        final List<KuraMetric> metrics = payload2.getMetricList();\n        assertNotNull(metrics);\n        assertEquals(2, metrics.size());\n        assertEquals(metric2Name, metrics.get(0).getName());\n        assertEquals(metricName, metrics.get(1).getName());\n    }\n\n    @Test\n    public void testBuilderInsertMetric() {\n        // test that inserting a metric works\n\n        String metricName = \"metric.name\";\n        String metric2Name = \"metric2.name\";\n\n        Builder builder = KuraPayload.newBuilder();\n        KuraMetric metric = KuraMetric.newBuilder().setName(metricName).setType(ValueType.STRING)\n                .setStringValue(\"metric.value\").build();\n        builder.addMetric(metric);\n\n        metric = KuraMetric.newBuilder().setName(metric2Name).setType(ValueType.INT32).setIntValue(123).build();\n        builder.addMetric(0, metric);\n\n        KuraPayload payload = builder.build();\n\n        final List<KuraMetric> metrics = payload.getMetricList();\n        assertNotNull(metrics);\n        assertEquals(2, metrics.size());\n        assertEquals(metric2Name, metrics.get(0).getName());\n        assertEquals(metricName, metrics.get(1).getName());\n    }\n\n    @Test\n    public void testBuilderInsertMetricBuilder() {\n        // test that inserting a metric builder works\n\n        String metricName = \"metric.name\";\n        String metric2Name = \"metric2.name\";\n\n        Builder builder = KuraPayload.newBuilder();\n        KuraMetric.Builder metricBuilder = KuraMetric.newBuilder().setName(metricName).setType(ValueType.STRING)\n                .setStringValue(\"metric.value\");\n        builder.addMetric(metricBuilder);\n\n        metricBuilder = KuraMetric.newBuilder().setName(metric2Name).setType(ValueType.INT32).setIntValue(123);\n        builder.addMetric(0, metricBuilder);\n\n        KuraPayload payload = builder.build();\n\n        final List<KuraMetric> metrics = payload.getMetricList();\n        assertNotNull(metrics);\n        assertEquals(2, metrics.size());\n        assertEquals(metric2Name, metrics.get(0).getName());\n        assertEquals(metricName, metrics.get(1).getName());\n    }\n\n    @Test\n    public void testBuilderSetMetric() {\n        // test that overwriting a metric works\n\n        String metricName = \"metric.name\";\n        String metric2Name = \"metric2.name\";\n\n        Builder builder = KuraPayload.newBuilder();\n        KuraMetric metric = KuraMetric.newBuilder().setName(metricName).setType(ValueType.STRING)\n                .setStringValue(\"metric.value\").build();\n        builder.addMetric(metric);\n\n        metric = KuraMetric.newBuilder().setName(metric2Name).setType(ValueType.INT32).setIntValue(123).build();\n        builder.setMetric(0, metric);\n\n        KuraPayload payload = builder.build();\n\n        final List<KuraMetric> metrics = payload.getMetricList();\n        assertNotNull(metrics);\n        assertEquals(1, metrics.size());\n        assertEquals(metric2Name, metrics.get(0).getName());\n    }\n\n    @Test\n    public void testBuilderSetMetricWithBuilder() {\n        // test that overwriting a metric with a builder works\n\n        String metricName = \"metric.name\";\n        String metric2Name = \"metric2.name\";\n\n        Builder builder = KuraPayload.newBuilder();\n        KuraMetric.Builder metricBuilder = KuraMetric.newBuilder().setName(metricName).setType(ValueType.STRING)\n                .setStringValue(\"metric.value\");\n        builder.addMetric(metricBuilder);\n\n        metricBuilder = KuraMetric.newBuilder().setName(metric2Name).setType(ValueType.INT32).setIntValue(123);\n        builder.setMetric(0, metricBuilder);\n\n        KuraPayload payload = builder.build();\n\n        final List<KuraMetric> metrics = payload.getMetricList();\n        assertNotNull(metrics);\n        assertEquals(1, metrics.size());\n        assertEquals(metric2Name, metrics.get(0).getName());\n    }\n\n    @Test\n    public void testBuilderGetPositionBuilder() {\n        // test if position builder is returned\n\n        Builder builder = KuraPayload.newBuilder();\n        org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder positionBuilder = builder\n                .getPositionBuilder();\n\n        assertNotNull(positionBuilder);\n\n        assertTrue(builder.hasPosition());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/message/protobuf/KuraPayloadProtoMetricBuilderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.message.protobuf;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType;\nimport org.junit.Test;\n\nimport com.google.protobuf.ByteString;\n\npublic class KuraPayloadProtoMetricBuilderTest {\n\n    @Test\n    public void testBuilderNameStringHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        try {\n            builder.setName(null);\n\n            fail(\"Exception was expected\");\n        } catch (NullPointerException e) {\n            // OK\n        }\n\n        builder.setName(\"name\");\n\n        assertTrue(builder.hasName());\n\n        assertEquals(\"name\", builder.getName());\n\n        assertEquals(\"name\", builder.getNameBytes().toStringUtf8());\n\n        builder.clearName();\n\n        assertFalse(builder.hasName());\n    }\n\n    @Test\n    public void testBuilderNameBytesHandling() {\n        Builder builder = KuraMetric.newBuilder();\n        ByteString byteString = ByteString.copyFromUtf8(\"name\");\n\n        try {\n            builder.setNameBytes(null);\n\n            fail(\"Exception was expected\");\n        } catch (NullPointerException e) {\n            // OK\n        }\n\n        builder.setNameBytes(byteString);\n\n        assertTrue(builder.hasName());\n\n        assertEquals(byteString, builder.getNameBytes());\n\n        assertEquals(\"name\", builder.getName());\n\n        builder.clearName();\n\n        assertFalse(builder.hasName());\n    }\n\n    @Test\n    public void testBuilderTypeHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        try {\n            builder.setType(null);\n\n            fail(\"Exception was expected\");\n        } catch (NullPointerException e) {\n            // OK\n        }\n\n        builder.setType(ValueType.BYTES);\n\n        assertTrue(builder.hasType());\n\n        assertEquals(ValueType.BYTES, builder.getType());\n\n        builder.clearType();\n\n        assertFalse(builder.hasType());\n    }\n\n    @Test\n    public void testBuilderIntHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        int value = 123;\n\n        builder.setIntValue(value);\n\n        assertTrue(builder.hasIntValue());\n\n        assertEquals(value, builder.getIntValue());\n\n        builder.clearIntValue();\n\n        assertFalse(builder.hasIntValue());\n    }\n\n    @Test\n    public void testBuilderLongHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        long value = 12345678901234L;\n\n        builder.setLongValue(value);\n\n        assertTrue(builder.hasLongValue());\n\n        assertEquals(value, builder.getLongValue());\n\n        builder.clearLongValue();\n\n        assertFalse(builder.hasLongValue());\n    }\n\n    @Test\n    public void testBuilderFloatHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        float value = 123.4f;\n\n        builder.setFloatValue(value);\n\n        assertTrue(builder.hasFloatValue());\n\n        assertEquals(value, builder.getFloatValue(), 0.000001);\n\n        builder.clearFloatValue();\n\n        assertFalse(builder.hasFloatValue());\n    }\n\n    @Test\n    public void testBuilderDoubleHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        double value = 1234.5;\n\n        builder.setDoubleValue(value);\n\n        assertTrue(builder.hasDoubleValue());\n\n        assertEquals(value, builder.getDoubleValue(), 0.000001);\n\n        builder.clearDoubleValue();\n\n        assertFalse(builder.hasDoubleValue());\n    }\n\n    @Test\n    public void testBuilderStringHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        String value = \"test\";\n\n        try {\n            builder.setStringValue(null);\n\n            fail(\"Exception was expected\");\n        } catch (NullPointerException e) {\n            // OK\n        }\n\n        builder.setStringValue(value);\n\n        assertTrue(builder.hasStringValue());\n\n        assertEquals(value, builder.getStringValue());\n\n        assertEquals(value, builder.getStringValueBytes().toStringUtf8());\n\n        builder.clearStringValue();\n\n        assertFalse(builder.hasStringValue());\n    }\n\n    @Test\n    public void testBuilderStringBytesHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        String value = \"test\";\n        ByteString byteString = ByteString.copyFromUtf8(value);\n\n        try {\n            builder.setStringValueBytes(null);\n\n            fail(\"Exception was expected\");\n        } catch (NullPointerException e) {\n            // OK\n        }\n\n        builder.setStringValueBytes(byteString);\n\n        assertTrue(builder.hasStringValue());\n\n        assertEquals(byteString, builder.getStringValueBytes());\n\n        assertEquals(value, builder.getStringValue());\n\n        builder.clearStringValue();\n\n        assertFalse(builder.hasStringValue());\n    }\n\n    @Test\n    public void testBuilderBytesHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        ByteString value = ByteString.copyFromUtf8(\"test\");\n\n        try {\n            builder.setBytesValue(null);\n\n            fail(\"Exception was expected\");\n        } catch (NullPointerException e) {\n            // OK\n        }\n\n        builder.setBytesValue(value);\n\n        assertTrue(builder.hasBytesValue());\n\n        assertEquals(value, builder.getBytesValue());\n\n        builder.clearBytesValue();\n\n        assertFalse(builder.hasBytesValue());\n    }\n\n    @Test\n    public void testBuilderBoolHandling() {\n        Builder builder = KuraMetric.newBuilder();\n\n        builder.setBoolValue(true);\n\n        assertTrue(builder.hasBoolValue());\n\n        assertTrue(builder.getBoolValue());\n\n        builder.clearBoolValue();\n\n        assertFalse(builder.hasBoolValue());\n    }\n\n    @Test\n    public void testBuilderBool() {\n        Builder builder = KuraMetric.newBuilder();\n        builder.setName(\"name\").setType(ValueType.BOOL).setBoolValue(true);\n        KuraMetric metric = builder.build();\n\n        assertEquals(\"name\", metric.getName());\n        assertEquals(ValueType.BOOL, metric.getType());\n        assertTrue(metric.getBoolValue());\n    }\n\n    @Test\n    public void testBuilderInitClear() {\n        Builder builder = KuraMetric.newBuilder();\n\n        assertFalse(builder.isInitialized());\n\n        builder.setName(\"name\");\n\n        assertFalse(builder.isInitialized());\n\n        builder.setType(ValueType.BOOL);\n\n        assertTrue(builder.isInitialized());\n\n        builder.setBoolValue(true);\n        builder.setIntValue(123);\n        builder.setLongValue(123456789123456L);\n        builder.setFloatValue(123.4f);\n        builder.setDoubleValue(1234.5);\n        builder.setStringValue(\"test\");\n        builder.setBytesValue(ByteString.copyFromUtf8(\"test\"));\n\n        assertTrue(builder.hasName());\n        assertTrue(builder.hasType());\n        assertTrue(builder.hasBoolValue());\n        assertTrue(builder.hasIntValue());\n        assertTrue(builder.hasLongValue());\n        assertTrue(builder.hasFloatValue());\n        assertTrue(builder.hasDoubleValue());\n        assertTrue(builder.hasStringValue());\n        assertTrue(builder.hasBytesValue());\n\n        builder.clear();\n\n        assertFalse(builder.isInitialized());\n        assertFalse(builder.hasName());\n        assertFalse(builder.hasType());\n        assertFalse(builder.hasBoolValue());\n        assertFalse(builder.hasIntValue());\n        assertFalse(builder.hasLongValue());\n        assertFalse(builder.hasFloatValue());\n        assertFalse(builder.hasDoubleValue());\n        assertFalse(builder.hasStringValue());\n        assertFalse(builder.hasBytesValue());\n    }\n\n    @Test\n    public void testBuilderMerge() {\n        Builder builder = KuraMetric.newBuilder();\n\n        builder.setName(\"name\");\n        builder.setType(ValueType.BOOL);\n        builder.setBoolValue(true);\n        builder.setIntValue(123);\n        builder.setLongValue(123456789123456L);\n        builder.setFloatValue(123.4f);\n        builder.setDoubleValue(1234.5);\n        builder.setStringValue(\"test\");\n        builder.setBytesValue(ByteString.copyFromUtf8(\"test\"));\n\n        assertTrue(builder.hasName());\n        assertTrue(builder.hasType());\n        assertTrue(builder.hasBoolValue());\n        assertTrue(builder.hasIntValue());\n        assertTrue(builder.hasLongValue());\n        assertTrue(builder.hasFloatValue());\n        assertTrue(builder.hasDoubleValue());\n        assertTrue(builder.hasStringValue());\n        assertTrue(builder.hasBytesValue());\n\n        Builder builder2 = KuraMetric.newBuilder();\n\n        assertFalse(builder2.isInitialized());\n        assertFalse(builder2.hasName());\n        assertFalse(builder2.hasType());\n        assertFalse(builder2.hasBoolValue());\n        assertFalse(builder2.hasIntValue());\n        assertFalse(builder2.hasLongValue());\n        assertFalse(builder2.hasFloatValue());\n        assertFalse(builder2.hasDoubleValue());\n        assertFalse(builder2.hasStringValue());\n        assertFalse(builder2.hasBytesValue());\n\n        builder2.mergeFrom(builder.build());\n\n        assertTrue(builder2.hasName());\n        assertTrue(builder2.hasType());\n        assertTrue(builder2.hasBoolValue());\n        assertTrue(builder2.hasIntValue());\n        assertTrue(builder2.hasLongValue());\n        assertTrue(builder2.hasFloatValue());\n        assertTrue(builder2.hasDoubleValue());\n        assertTrue(builder2.hasStringValue());\n        assertTrue(builder2.hasBytesValue());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/java/org/eclipse/kura/core/message/protobuf/KuraPayloadProtoPositionBuilderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.message.protobuf;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition;\nimport org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder;\nimport org.junit.Test;\n\npublic class KuraPayloadProtoPositionBuilderTest {\n\n    @Test\n    public void testBuilderLatitude() {\n        Builder builder = KuraPosition.newBuilder();\n\n        double value = 46.0;\n        builder.setLatitude(value);\n\n        assertTrue(builder.hasLatitude());\n\n        assertEquals(value, builder.getLatitude(), 0.000001);\n\n        builder.clearLatitude();\n\n        assertFalse(builder.hasLatitude());\n    }\n\n    @Test\n    public void testBuilderLongitude() {\n        Builder builder = KuraPosition.newBuilder();\n\n        double value = 13.0;\n        builder.setLongitude(value);\n\n        assertTrue(builder.hasLongitude());\n\n        assertEquals(value, builder.getLongitude(), 0.000001);\n\n        builder.clearLongitude();\n\n        assertFalse(builder.hasLongitude());\n    }\n\n    @Test\n    public void testBuilderAltitude() {\n        Builder builder = KuraPosition.newBuilder();\n\n        double value = 300.0;\n        builder.setAltitude(value);\n\n        assertTrue(builder.hasAltitude());\n\n        assertEquals(value, builder.getAltitude(), 0.000001);\n\n        builder.clearAltitude();\n\n        assertFalse(builder.hasAltitude());\n    }\n\n    @Test\n    public void testBuilderHeading() {\n        Builder builder = KuraPosition.newBuilder();\n\n        double value = 110.0;\n        builder.setHeading(value);\n\n        assertTrue(builder.hasHeading());\n\n        assertEquals(value, builder.getHeading(), 0.000001);\n\n        builder.clearHeading();\n\n        assertFalse(builder.hasHeading());\n    }\n\n    @Test\n    public void testBuilderPrecision() {\n        Builder builder = KuraPosition.newBuilder();\n\n        double value = 0.000001;\n        builder.setPrecision(value);\n\n        assertTrue(builder.hasPrecision());\n\n        assertEquals(value, builder.getPrecision(), 0.000001);\n\n        builder.clearPrecision();\n\n        assertFalse(builder.hasPrecision());\n    }\n\n    @Test\n    public void testBuilderSatellites() {\n        Builder builder = KuraPosition.newBuilder();\n\n        int value = 6;\n        builder.setSatellites(value);\n\n        assertTrue(builder.hasSatellites());\n\n        assertEquals(value, builder.getSatellites());\n\n        builder.clearSatellites();\n\n        assertFalse(builder.hasSatellites());\n    }\n\n    @Test\n    public void testBuilderSpeed() {\n        Builder builder = KuraPosition.newBuilder();\n\n        double value = 10.0;\n        builder.setSpeed(value);\n\n        assertTrue(builder.hasSpeed());\n\n        assertEquals(value, builder.getSpeed(), 0.000001);\n\n        builder.clearSpeed();\n\n        assertFalse(builder.hasSpeed());\n    }\n\n    @Test\n    public void testBuilderStatus() {\n        Builder builder = KuraPosition.newBuilder();\n\n        int value = 4;\n        builder.setStatus(value);\n\n        assertTrue(builder.hasStatus());\n\n        assertEquals(value, builder.getStatus());\n\n        builder.clearStatus();\n\n        assertFalse(builder.hasStatus());\n    }\n\n    @Test\n    public void testBuilderTimestamp() {\n        Builder builder = KuraPosition.newBuilder();\n\n        long value = 1503300000000L;\n        builder.setTimestamp(value);\n\n        assertTrue(builder.hasTimestamp());\n\n        assertEquals(value, builder.getTimestamp());\n\n        builder.clearTimestamp();\n\n        assertFalse(builder.hasTimestamp());\n    }\n\n    @Test\n    public void testBuilderInitClear() {\n        Builder builder = KuraPosition.newBuilder();\n\n        assertFalse(builder.isInitialized());\n\n        builder.setLatitude(46.0);\n\n        assertFalse(builder.isInitialized());\n\n        builder.setLongitude(13.0);\n\n        assertTrue(builder.isInitialized());\n\n        builder.setAltitude(300.0);\n        builder.setHeading(110.0);\n        builder.setPrecision(0.01);\n        builder.setSatellites(6);\n        builder.setSpeed(10);\n        builder.setStatus(4);\n        builder.setTimestamp(1503300000000L);\n\n        assertTrue(builder.hasAltitude());\n        assertTrue(builder.hasHeading());\n        assertTrue(builder.hasLatitude());\n        assertTrue(builder.hasLongitude());\n        assertTrue(builder.hasPrecision());\n        assertTrue(builder.hasSatellites());\n        assertTrue(builder.hasSpeed());\n        assertTrue(builder.hasStatus());\n        assertTrue(builder.hasTimestamp());\n\n        builder.clear();\n\n        assertFalse(builder.isInitialized());\n        assertFalse(builder.hasAltitude());\n        assertFalse(builder.hasHeading());\n        assertFalse(builder.hasLatitude());\n        assertFalse(builder.hasLongitude());\n        assertFalse(builder.hasPrecision());\n        assertFalse(builder.hasSatellites());\n        assertFalse(builder.hasSpeed());\n        assertFalse(builder.hasStatus());\n        assertFalse(builder.hasTimestamp());\n    }\n\n    @Test\n    public void testBuilderMerge() {\n        Builder builder = KuraPosition.newBuilder();\n\n        double lat = 46.0;\n        double lon = 13.0;\n        double alt = 300.0;\n        double head = 110.0;\n        double prec = 0.01;\n        int sat = 6;\n        int speed = 10;\n        int status = 4;\n        long time = 1503300000000L;\n        double eps = 0.000001;\n\n        builder.setLatitude(lat);\n        builder.setLongitude(lon);\n        builder.setAltitude(alt);\n        builder.setHeading(head);\n        builder.setPrecision(prec);\n        builder.setSatellites(sat);\n        builder.setSpeed(speed);\n        builder.setStatus(status);\n        builder.setTimestamp(time);\n\n        KuraPosition position = builder.build();\n        assertEquals(lat, position.getLatitude(), eps);\n        assertEquals(lon, position.getLongitude(), eps);\n        assertEquals(alt, position.getAltitude(), eps);\n        assertEquals(head, position.getHeading(), eps);\n        assertEquals(prec, position.getPrecision(), eps);\n        assertEquals(sat, position.getSatellites());\n        assertEquals(speed, position.getSpeed(), eps);\n        assertEquals(status, position.getStatus());\n        assertEquals(time, position.getTimestamp());\n\n        Builder builder2 = KuraPosition.newBuilder();\n\n        assertFalse(builder2.isInitialized());\n        assertFalse(builder2.hasAltitude());\n        assertFalse(builder2.hasHeading());\n        assertFalse(builder2.hasLatitude());\n        assertFalse(builder2.hasLongitude());\n        assertFalse(builder2.hasPrecision());\n        assertFalse(builder2.hasSatellites());\n        assertFalse(builder2.hasSpeed());\n        assertFalse(builder2.hasStatus());\n        assertFalse(builder2.hasTimestamp());\n\n        builder2.mergeFrom(position);\n\n        assertTrue(builder2.isInitialized());\n        assertTrue(builder2.hasAltitude());\n        assertTrue(builder2.hasHeading());\n        assertTrue(builder2.hasLatitude());\n        assertTrue(builder2.hasLongitude());\n        assertTrue(builder2.hasPrecision());\n        assertTrue(builder2.hasSatellites());\n        assertTrue(builder2.hasSpeed());\n        assertTrue(builder2.hasStatus());\n        assertTrue(builder2.hasTimestamp());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/src/test/resources/log4j.properties",
    "content": "log4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test\nBundle-SymbolicName: org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nFragment-Host: org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider\nImport-Package: org.eclipse.kura.core.testutil.service;version=\"1.0.0\",\n org.junit;version=\"[4.12,5.0)\",\n org.junit.experimental.runners;version=\"[4.12,5.0)\",\n org.junit.rules;version=\"[4.12,5.0)\",\n org.junit.runner;version=\"[4.12,5.0)\",\n org.junit.runners;version=\"[4.12,5.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.verification;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.util.tracker;version=\"[1.5,2.0)\"\nRequire-Bundle: moquette-broker;bundle-version=\"0.18.0\",\n org.eclipse.kura.emulator;bundle-version=\"[0.7.1,3.0.0)\",\n org.eclipse.equinox.io;bundle-version=\"1.0.400\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/OSGI-INF/SparkplugIntegrationTest.xml",
    "content": "<!--\n\n    Copyright (c) 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" \n               name=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test.SparkplugIntegrationTest\"\n               activate=\"activate\">\n\n    <implementation class=\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test.SparkplugIntegrationTest\"/>\n\n    <reference interface=\"org.eclipse.kura.configuration.ConfigurationService\"\n               name=\"ConfigurationService\"\n               bind=\"bindConfigurationService\"\n               policy=\"static\"\n               cardinality=\"1..1\"/>\n\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/test/java/,\\\n           src/main/java\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n      SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/provider/test/SparkplugDataTransportTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyBoolean;\nimport static org.mockito.ArgumentMatchers.anyInt;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.verify;\n\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugBProtobufPayloadBuilder;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugPayloads;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugTopics;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransportOptions;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.eclipse.paho.client.mqttv3.MqttCallback;\nimport org.eclipse.paho.client.mqttv3.MqttException;\nimport org.eclipse.paho.client.mqttv3.MqttMessage;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.DataType;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload.Metric;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport com.google.gson.Gson;\nimport com.google.gson.JsonObject;\nimport com.google.protobuf.InvalidProtocolBufferException;\n\n/**\n * Payloads are already tested in unit tests, not verifying them here\n *\n */\npublic class SparkplugDataTransportTest extends SparkplugIntegrationTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(SparkplugDataTransportTest.class);\n    private static final long DEFAULT_TIMEOUT_MS = 10_000L;\n\n    private DataTransportListener listener = mock(DataTransportListener.class);\n    private MqttCallback callback = mock(MqttCallback.class);\n\n    @Before\n    public void setup() throws Exception {\n        sparkplugDataTransport.addDataTransportListener(this.listener);\n        client.setCallback(callback);\n        client.subscribe(\"spBv1.0/g1/NBIRTH/n1\", 0);\n        client.subscribe(\"spBv1.0/g1/NDEATH/n1\", 1);\n    }\n\n    @After\n    public void cleanup() throws MqttException {\n        sparkplugDataTransport.removeDataTransportListener(this.listener);\n        client.unsubscribe(\"spBv1.0/g1/NBIRTH/n1\");\n        client.unsubscribe(\"spBv1.0/g1/NDEATH/n1\");\n        sparkplugDataTransport.disconnect(0L);\n    }\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldSendNodeBirthWithoutPrimaryHost() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n\n        whenConnect();\n\n        thenListenerNotifiedOnConnectionEstabilished(1);\n        thenMessageDeliveredOnce(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n    }\n\n    @Test\n    public void shouldNotSendNodeBirthWithPrimaryHostOffline() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"h1\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenPrimaryHostReportsState(\"h1\", false, new Date().getTime());\n\n        thenListenerNotNotifiedOnConnectionEstabilished();\n    }\n\n    @Test\n    public void shouldSendNodeBirthWithPrimaryHostOnline() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"h1\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenPrimaryHostReportsState(\"h1\", true, new Date().getTime());\n\n        thenListenerNotifiedOnConnectionEstabilished(1);\n        thenMessageDeliveredOnce(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n    }\n\n    @Test\n    public void shouldDisconnectCleanWhenPrimaryHostOffline() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"h1\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n        givenPrimaryHostReportsState(\"h1\", true, new Date().getTime());\n\n        whenPrimaryHostReportsState(\"h1\", false, new Date().getTime());\n\n        thenListenerNotifiedOnDisconnecting();\n        thenListenerNotifiedOnDisconnected();\n        thenMessageDeliveredOnce(\"spBv1.0/g1/NDEATH/n1\", 0, false, 0L);\n    }\n\n    @Test\n    public void shouldIgnoreStateMessagesWithOutdatedTimestamp() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"h1\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n        givenPrimaryHostReportsState(\"h1\", true, new Date().getTime());\n\n        whenPrimaryHostReportsState(\"h1\", false, 1234L);\n\n        thenListenerNotNotifiedOnDisconnecting();\n        thenListenerNotNotifiedOnDisconnected();\n    }\n\n    @Test\n    public void shouldIgnoreStateMessagesWithoutPrimaryHost() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenPrimaryHostReportsState(\"h1\", false, new Date().getTime());\n\n        thenListenerNotNotifiedOnDisconnecting();\n        thenListenerNotNotifiedOnDisconnected();\n    }\n\n    @Test\n    public void shouldIgnoreStateMessagesFromOtherPrimaryHost() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"h1\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n        givenPrimaryHostReportsState(\"h1\", true, new Date().getTime());\n\n        whenPrimaryHostReportsState(\"h2\", false, new Date().getTime());\n\n        thenListenerNotNotifiedOnDisconnecting();\n        thenListenerNotNotifiedOnDisconnected();\n    }\n\n    @Test\n    public void shouldDisconnectCleanWithDeathCertificate() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenDisconnect(0L);\n\n        thenListenerNotifiedOnDisconnecting();\n        thenListenerNotifiedOnDisconnected();\n        thenMessageDeliveredOnce(\"spBv1.0/g1/NDEATH/n1\", 0, false, 0L);\n    }\n\n    @Test\n    public void shouldRestabilishSessionWhenRebirthRequestArrives() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenPrimaryHostRequestsRebirth(\"g1\", \"n1\", true, new Date().getTime());\n\n        thenListenerNotifiedOnDisconnecting();\n        thenListenerNotifiedOnDisconnected();\n        thenListenerNotifiedOnConnectionEstabilished(2);\n        thenMessageDeliveredOnce(\"spBv1.0/g1/NDEATH/n1\", 0, false, 0L);\n        thenMessageDeliveredTwice(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n    }\n\n    @Test\n    public void shouldIgnoreRebirthWhenDifferentNode() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenPrimaryHostRequestsRebirth(\"g1\", \"n2\", true, new Date().getTime());\n\n        thenListenerNotifiedOnConnectionEstabilished(1);\n        thenListenerNotNotifiedOnDisconnecting();\n        thenListenerNotNotifiedOnDisconnected();\n    }\n\n    @Test\n    public void shouldIgnoreRebirthWhenDifferentGroup() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenPrimaryHostRequestsRebirth(\"g2\", \"n1\", true, new Date().getTime());\n\n        thenListenerNotifiedOnConnectionEstabilished(1);\n        thenListenerNotNotifiedOnDisconnecting();\n        thenListenerNotNotifiedOnDisconnected();\n    }\n\n    @Test\n    public void shouldIgnoreRebirthWhenMetricIsFalse() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenPrimaryHostRequestsRebirth(\"g1\", \"n1\", false, new Date().getTime());\n\n        thenListenerNotifiedOnConnectionEstabilished(1);\n        thenListenerNotNotifiedOnDisconnecting();\n        thenListenerNotNotifiedOnDisconnected();\n    }\n\n    @Test\n    public void shouldForwardSTATEmessagesToListeners() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"h1\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenPrimaryHostReportsState(\"h1\", false, new Date().getTime());\n\n        thenListenerNotifiedOnMessageArrived(\"spBv1.0/STATE/h1\");\n    }\n\n    @Test\n    public void shouldForwardNCMDmessagesToListeners() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n\n        whenPrimaryHostRequestsRebirth(\"g1\", \"n1\", false, new Date().getTime());\n\n        thenListenerNotifiedOnMessageArrived(\"spBv1.0/g1/NCMD/n1\");\n    }\n\n    @Test\n    public void shouldIncrementBdSeqOnSuccessfulReconnection() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnected();\n        givenDisconnect(0L);\n\n        whenConnect();\n\n        thenMessageDeliveredOnce(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n        thenMessageDeliveredOnce(\"spBv1.0/g1/NDEATH/n1\", 0, false, 0L);\n        thenMessageDeliveredOnce(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 1L);\n    }\n\n    @Test\n    public void shouldNotIncrementBdSeqOnUnsuccessfulConnection() throws Exception {\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://wrong.url:1883\", \"test.device\", \"mqtt\", 60, 30);\n        givenConnectedAdmitToFail();\n        givenUpdated(\"g1\", \"n1\", \"\", \"tcp://localhost:1883\", \"test.device\", \"mqtt\", 60, 30);\n\n        whenConnect();\n\n        thenMessageDeliveredOnce(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenUpdated(String groupId, String nodeId, String primaryHostId, String serverUris, String clientId,\n            String username, int keepAlive, int connectionTimeoutSec) {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(SparkplugDataTransportOptions.KEY_GROUP_ID, groupId);\n        properties.put(SparkplugDataTransportOptions.KEY_NODE_ID, nodeId);\n        properties.put(SparkplugDataTransportOptions.KEY_PRIMARY_HOST_APPLICATION_ID, primaryHostId);\n        properties.put(SparkplugDataTransportOptions.KEY_SERVER_URIS, serverUris);\n        properties.put(SparkplugDataTransportOptions.KEY_CLIENT_ID, clientId);\n        properties.put(SparkplugDataTransportOptions.KEY_USERNAME, username);\n        properties.put(SparkplugDataTransportOptions.KEY_KEEP_ALIVE, keepAlive);\n        properties.put(SparkplugDataTransportOptions.KEY_CONNECTION_TIMEOUT, connectionTimeoutSec);\n\n        sparkplugDataTransport.update(properties);\n    }\n\n    private void givenConnected() throws KuraException {\n        sparkplugDataTransport.connect();\n    }\n\n    private void givenConnectedAdmitToFail() {\n        try {\n            givenConnected();\n        } catch (Exception e) {\n        }\n    }\n\n    private void givenPrimaryHostReportsState(String hostId, boolean isOnline, long timestamp) throws MqttException {\n        JsonObject rootObject = new JsonObject();\n        rootObject.addProperty(\"online\", isOnline);\n        rootObject.addProperty(\"timestamp\", timestamp);\n\n        Gson gson = new Gson();\n\n        String topic = SparkplugTopics.getStateTopic(hostId);\n        byte[] payload = gson.toJson(rootObject).getBytes();\n\n        logger.info(\"Sending STATE message [ online: {}, timestamp: {} ]\", isOnline, timestamp);\n\n        // for testing, do not publish with retain true\n        client.publish(topic, payload, 1, false);\n    }\n\n    private void givenDisconnect(long quiesceTimeout) {\n        sparkplugDataTransport.disconnect(quiesceTimeout);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenConnect() throws KuraException, MqttException {\n        givenConnected();\n    }\n\n    private void whenPrimaryHostReportsState(String hostId, boolean isOnline, long timestamp) throws MqttException {\n        givenPrimaryHostReportsState(hostId, isOnline, timestamp);\n    }\n\n    private void whenDisconnect(long quiesceTimeout) {\n        givenDisconnect(quiesceTimeout);\n    }\n\n    private void whenPrimaryHostRequestsRebirth(String groupId, String nodeId, boolean isRebirthRequested,\n            long timestamp) throws MqttException {\n        SparkplugBProtobufPayloadBuilder payloadBuilder = new SparkplugBProtobufPayloadBuilder();\n        payloadBuilder.withMetric(SparkplugPayloads.NODE_CONTROL_REBIRTH_METRIC_NAME, isRebirthRequested,\n                DataType.Boolean, timestamp);\n        payloadBuilder.withTimestamp(timestamp);\n\n        client.publish(SparkplugTopics.getNodeCommandTopic(groupId, nodeId), payloadBuilder.build(), 0, false);\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenListenerNotifiedOnConnectionEstabilished(int expectedTimes) {\n        verify(this.listener, timeout(DEFAULT_TIMEOUT_MS).times(expectedTimes)).onConnectionEstablished(true);\n    }\n\n    private void thenListenerNotNotifiedOnConnectionEstabilished() {\n        verify(this.listener, never()).onConnectionEstablished(true);\n    }\n\n    private void thenListenerNotifiedOnDisconnecting() {\n        verify(this.listener, timeout(DEFAULT_TIMEOUT_MS).times(1)).onDisconnecting();\n    }\n\n    private void thenListenerNotNotifiedOnDisconnecting() {\n        verify(this.listener, never()).onDisconnecting();\n    }\n\n    private void thenListenerNotifiedOnDisconnected() {\n        verify(this.listener, timeout(DEFAULT_TIMEOUT_MS).times(1)).onDisconnected();\n    }\n\n    private void thenListenerNotNotifiedOnDisconnected() {\n        verify(this.listener, never()).onDisconnected();\n    }\n\n    private void thenListenerNotifiedOnMessageArrived(String topic) {\n        verify(this.listener, timeout(DEFAULT_TIMEOUT_MS).times(1)).onMessageArrived(eq(topic), any(byte[].class),\n                anyInt(), anyBoolean());\n    }\n\n    private void thenMessageDeliveredOnce(String expectedTopic, int expectedQos, boolean expectedRetained,\n            long expectedBdSeq) throws Exception {\n        thenMessageDelivered(expectedTopic, expectedQos, expectedRetained, expectedBdSeq, 1);\n    }\n\n    private void thenMessageDeliveredTwice(String expectedTopic, int expectedQos, boolean expectedRetained,\n            long expectedBdSeq) throws Exception {\n        thenMessageDelivered(expectedTopic, expectedQos, expectedRetained, expectedBdSeq, 2);\n    }\n\n    private void thenMessageDelivered(String expectedTopic, int expectedQos, boolean expectedRetained,\n            long expectedBdSeq, int expectedTimes) throws Exception {\n        verify(this.callback, timeout(DEFAULT_TIMEOUT_MS).times(expectedTimes)).messageArrived(eq(expectedTopic),\n                argThat((MqttMessage message) -> isMessageMatching(message, expectedQos, expectedRetained,\n                        expectedBdSeq)));\n    }\n\n    private static boolean isMessageMatching(MqttMessage message, int expectedQos, boolean expectedRetained,\n            long expectedBdSeq) {\n        if (message.getQos() != expectedQos) {\n            return false;\n        }\n\n        if (message.isRetained() != expectedRetained) {\n            return false;\n        }\n\n        try {\n            Payload receivedPayload = Payload.parseFrom(message.getPayload());\n\n            Optional<Metric> bdSeqMetric = receivedPayload.getMetricsList().stream()\n                    .filter(metric -> metric.getName().equals(SparkplugBProtobufPayloadBuilder.BDSEQ_METRIC_NAME))\n                    .findFirst();\n\n            if (!bdSeqMetric.isPresent()) {\n                return false;\n            }\n\n            if (bdSeqMetric.get().getLongValue() != expectedBdSeq) {\n                return false;\n            }\n\n            return true;\n        } catch (InvalidProtocolBufferException e) {\n            return false;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/provider/test/SparkplugDeviceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test;\n\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.verify;\n\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraDisconnectException;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransportOptions;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.eclipse.paho.client.mqttv3.MqttCallback;\nimport org.eclipse.paho.client.mqttv3.MqttException;\nimport org.eclipse.paho.client.mqttv3.MqttMessage;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload.Metric;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatcher;\n\npublic class SparkplugDeviceTest extends SparkplugIntegrationTest {\n\n    private static final long DEFAULT_TIMEOUT_MS = 10_000L;\n\n    private DataTransportListener listener = mock(DataTransportListener.class);\n    private MqttCallback callback = mock(MqttCallback.class);\n\n    private Map<String, Object> kuraMetricsToPublish = new HashMap<>();\n    private Date kuraTimestampToPublish;\n    private byte[] kuraBodyToPublish;\n    private KuraPosition kuraPositionToPublish;\n    private Date kuraPositionDate;\n\n    @Before\n    public void setup() throws Exception {\n        sparkplugDataTransport.addDataTransportListener(this.listener);\n        client.setCallback(callback);\n        client.subscribe(\"spBv1.0/g1/NBIRTH/n1\", 0);\n        client.subscribe(\"spBv1.0/g1/DBIRTH/n1/d1\", 0);\n        client.subscribe(\"spBv1.0/g1/DDATA/n1/d1\", 0);\n        setupDataTransportService(\"g1\", \"n1\", \"\");\n    }\n\n    @After\n    public void cleanup() throws MqttException {\n        sparkplugDataTransport.removeDataTransportListener(this.listener);\n        client.unsubscribe(\"spBv1.0/g1/NBIRTH/n1\");\n        client.unsubscribe(\"spBv1.0/g1/DBIRTH/n1/d1\");\n        client.unsubscribe(\"spBv1.0/g1/DDATA/n1/d1\");\n        sparkplugDataTransport.disconnect(0L);\n    }\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldPublishDeviceBirth() throws Exception {\n        givenUpdate(\"d1\");\n        givenEndpointConnect();\n        givenKuraMetricToPublish(\"metric.string\", \"test string\");\n\n        whenPublish();\n\n        thenMessageDelivered(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n        thenMessageDelivered(\"spBv1.0/g1/DBIRTH/n1/d1\", 0, false, 1L);\n    }\n\n    @Test\n    public void shouldPublishDeviceDataMessageOnUnchangedMetrics() throws Exception {\n        givenUpdate(\"d1\");\n        givenEndpointConnect();\n        givenKuraMetricToPublish(\"metric.string\", \"test string\");\n        givenPublish();\n\n        whenPublish();\n\n        thenMessageDelivered(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n        thenMessageDelivered(\"spBv1.0/g1/DBIRTH/n1/d1\", 0, false, 1L);\n        thenMessageDelivered(\"spBv1.0/g1/DDATA/n1/d1\", 0, false, 2L);\n    }\n\n    @Test\n    public void shouldRepublishDeviceBirthOnChangedMetrics() throws Exception {\n        givenUpdate(\"d1\");\n        givenEndpointConnect();\n        givenKuraMetricToPublish(\"metric.string\", \"test string\");\n        givenPublish();\n        givenKuraMetricToPublish(\"metric.int\", 12);\n\n        whenPublish();\n\n        thenMessageDelivered(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n        thenMessageDelivered(\"spBv1.0/g1/DBIRTH/n1/d1\", 0, false, 1L);\n    }\n\n    @Test\n    public void shouldRepublishDeviceBirthOnReconnection() throws Exception {\n        givenUpdate(\"d1\");\n        givenKuraMetricToPublish(\"metric.string\", \"test string\");\n        givenEndpointConnect();\n        givenPublish();\n        givenReconnect();\n\n        whenPublish();\n\n        thenMessageDelivered(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n        thenMessageDelivered(\"spBv1.0/g1/DBIRTH/n1/d1\", 0, false, 1L);\n        thenMessageDelivered(\"spBv1.0/g1/NBIRTH/n1\", 0, false, 0L);\n        thenMessageDelivered(\"spBv1.0/g1/DBIRTH/n1/d1\", 0, false, 1L);\n    }\n\n    @Test\n    public void shouldPublishTimestamp() throws Exception {\n        givenUpdate(\"d1\");\n        givenEndpointConnect();\n        givenKuraTimestampToPublish(new Date());\n\n        whenPublish();\n\n        thenDeliveredMessageContainsTimestamp(\"spBv1.0/g1/DBIRTH/n1/d1\", this.kuraTimestampToPublish.getTime());\n    }\n\n    @Test\n    public void shouldPublishBody() throws Exception {\n        givenUpdate(\"d1\");\n        givenEndpointConnect();\n        givenKuraBodyToPublish(\"some random data\".getBytes());\n\n        whenPublish();\n\n        thenDeliveredMessageContainsBody(\"spBv1.0/g1/DBIRTH/n1/d1\", \"some random data\".getBytes());\n    }\n\n    @Test\n    public void shouldFlattenKuraPositionIntoMetrics() throws Exception {\n        givenUpdate(\"d1\");\n        givenEndpointConnect();\n        givenKuraPositionToPublish(699.3, 200.0, 250.5, 349.0, 89.98, 12, 30.2, 1, new Date());\n\n        whenPublish();\n\n        thenDeliveredMessageContainsKuraPositionMetrics(\"spBv1.0/g1/DBIRTH/n1/d1\", 699.3, 200.0, 250.5, 349.0, 89.98,\n                12, 30.2, 1, this.kuraPositionDate.getTime());\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenUpdate(String deviceId) {\n        final Map<String, Object> properties = new HashMap<>();\n        properties.put(SparkplugDevice.KEY_DEVICE_ID, deviceId);\n        sparkplugDevice.update(properties);\n    }\n\n    private void givenEndpointConnect() throws KuraConnectException {\n        sparkplugCloudEndpoint.connect();\n    }\n\n    private void givenKuraMetricToPublish(String key, Object value) {\n        this.kuraMetricsToPublish.put(key, value);\n    }\n\n    private void givenKuraTimestampToPublish(Date timestamp) {\n        this.kuraTimestampToPublish = timestamp;\n    }\n\n    private void givenKuraBodyToPublish(byte[] body) {\n        this.kuraBodyToPublish = body;\n    }\n\n    private void givenKuraPositionToPublish(double altitude, double heading, double latitude, double longitude,\n            double precision, int satellites, double speed, int status, Date timestamp) {\n        this.kuraPositionToPublish = new KuraPosition();\n        this.kuraPositionToPublish.setAltitude(altitude);\n        this.kuraPositionToPublish.setHeading(heading);\n        this.kuraPositionToPublish.setLatitude(latitude);\n        this.kuraPositionToPublish.setLongitude(longitude);\n        this.kuraPositionToPublish.setPrecision(precision);\n        this.kuraPositionToPublish.setSatellites(satellites);\n        this.kuraPositionToPublish.setSpeed(speed);\n        this.kuraPositionToPublish.setStatus(status);\n        this.kuraPositionToPublish.setTimestamp(timestamp);\n        this.kuraPositionDate = timestamp;\n    }\n\n    private void givenPublish() throws KuraException {\n        KuraPayload payload = new KuraPayload();\n\n        this.kuraMetricsToPublish.forEach(payload::addMetric);\n\n        payload.setTimestamp(this.kuraTimestampToPublish);\n        payload.setBody(this.kuraBodyToPublish);\n        payload.setPosition(this.kuraPositionToPublish);\n\n        sparkplugDevice.publish(new KuraMessage(payload, new HashMap<>()));\n    }\n\n    private void givenReconnect() throws KuraConnectException, KuraDisconnectException {\n        sparkplugCloudEndpoint.disconnect();\n        sparkplugCloudEndpoint.connect();\n    }\n\n    /*\n     * When\n     */\n\n    private void whenPublish() throws KuraException {\n        givenPublish();\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenMessageDelivered(String expectedTopic, int expectedQos, boolean expectedRetained,\n            long expectedSeq) throws Exception {\n        verifyMessageDeliveredWithMatcher(expectedTopic, (MqttMessage message) -> {\n            try {\n                Payload receivedPayload = Payload.parseFrom(message.getPayload());\n\n                boolean matches = message.getQos() == expectedQos;\n                matches &= message.isRetained() == expectedRetained;\n                matches &= receivedPayload.getSeq() == expectedSeq;\n\n                return matches;\n            } catch (Exception e) {\n                return false;\n            }\n        });\n    }\n\n    private void thenDeliveredMessageContainsTimestamp(String expectedTopic, long expectedTimestamp) throws Exception {\n        verifyMessageDeliveredWithMatcher(expectedTopic, (MqttMessage message) -> {\n            try {\n                Payload receivedPayload = Payload.parseFrom(message.getPayload());\n\n                return expectedTimestamp == receivedPayload.getTimestamp();\n            } catch (Exception e) {\n                return false;\n            }\n        });\n    }\n\n    private void thenDeliveredMessageContainsBody(String expectedTopic, byte[] expectedBody) throws Exception {\n        verifyMessageDeliveredWithMatcher(expectedTopic, (MqttMessage message) -> {\n            try {\n                Payload receivedPayload = Payload.parseFrom(message.getPayload());\n                return Arrays.equals(expectedBody, receivedPayload.getBody().toByteArray());\n            } catch (Exception e) {\n                return false;\n            }\n        });\n    }\n\n    private void thenDeliveredMessageContainsKuraPositionMetrics(String expectedTopic, double expectedAltitude, double expectedHeading, double expectedLatitude, double expectedLongitude,\n            double expectedPrecision, int expectedSatellites, double expectedSpeed, int expectedStatus,\n            long expectedTimestamp) throws Exception {\n        verifyMessageDeliveredWithMatcher(expectedTopic, (MqttMessage message) -> {\n            try {\n                Payload receivedPayload = Payload.parseFrom(message.getPayload());\n                List<Metric> metrics = receivedPayload.getMetricsList();\n\n                Optional<Metric> altitude = metrics.stream()\n                        .filter(metric -> metric.getName().equals(\"kura.position.altitude\")).findFirst();\n                Optional<Metric> heading = metrics.stream()\n                        .filter(metric -> metric.getName().equals(\"kura.position.heading\")).findFirst();\n                Optional<Metric> latitude = metrics.stream()\n                        .filter(metric -> metric.getName().equals(\"kura.position.latitude\")).findFirst();\n                Optional<Metric> longitude = metrics.stream()\n                        .filter(metric -> metric.getName().equals(\"kura.position.longitude\")).findFirst();\n                Optional<Metric> precision = metrics.stream()\n                        .filter(metric -> metric.getName().equals(\"kura.position.precision\")).findFirst();\n                Optional<Metric> satellites = metrics.stream()\n                        .filter(metric -> metric.getName().equals(\"kura.position.satellites\")).findFirst();\n                Optional<Metric> speed = metrics.stream()\n                        .filter(metric -> metric.getName().equals(\"kura.position.speed\")).findFirst();\n                Optional<Metric> status = metrics.stream()\n                        .filter(metric -> metric.getName().equals(\"kura.position.status\")).findFirst();\n                Optional<Metric> timestamp = metrics.stream()\n                        .filter(metric -> metric.getName().equals(\"kura.position.timestamp\")).findFirst();\n\n                if (!altitude.isPresent() || !heading.isPresent() || !latitude.isPresent() || !longitude.isPresent()\n                        || !precision.isPresent() || !satellites.isPresent() || !speed.isPresent()\n                        || !status.isPresent() || !timestamp.isPresent()) {\n                    return false;\n                }\n                \n                boolean matches = altitude.get().getDoubleValue() == expectedAltitude;\n                matches &= heading.get().getDoubleValue() == expectedHeading;\n                matches &= latitude.get().getDoubleValue() == expectedLatitude;\n                matches &= longitude.get().getDoubleValue() == expectedLongitude;\n                matches &= precision.get().getDoubleValue() == expectedPrecision;\n                matches &= satellites.get().getIntValue() == expectedSatellites;\n                matches &= speed.get().getDoubleValue() == expectedSpeed;\n                matches &= status.get().getIntValue() == expectedStatus;\n                matches &= timestamp.get().getLongValue() == expectedTimestamp;\n\n                return matches;\n            } catch (Exception e) {\n                return false;\n            }\n        });\n    }\n\n    /*\n     * Utils\n     */\n\n    private void setupDataTransportService(String groupId, String nodeId, String primaryHostId) {\n        final Map<String, Object> properties = new HashMap<>();\n        properties.put(SparkplugDataTransportOptions.KEY_GROUP_ID, groupId);\n        properties.put(SparkplugDataTransportOptions.KEY_NODE_ID, nodeId);\n        properties.put(SparkplugDataTransportOptions.KEY_PRIMARY_HOST_APPLICATION_ID, primaryHostId);\n        properties.put(SparkplugDataTransportOptions.KEY_SERVER_URIS, \"tcp://localhost:1883\");\n        properties.put(SparkplugDataTransportOptions.KEY_CLIENT_ID, \"test.device\");\n        properties.put(SparkplugDataTransportOptions.KEY_USERNAME, \"mqtt\");\n        properties.put(SparkplugDataTransportOptions.KEY_KEEP_ALIVE, 60);\n        properties.put(SparkplugDataTransportOptions.KEY_CONNECTION_TIMEOUT, 30);\n\n        sparkplugDataTransport.update(properties);\n    }\n\n    private void verifyMessageDeliveredWithMatcher(String expectedTopic, ArgumentMatcher<MqttMessage> matcher)\n            throws Exception {\n        verify(this.callback, timeout(DEFAULT_TIMEOUT_MS).atLeastOnce()).messageArrived(eq(expectedTopic),\n                argThat(matcher));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/provider/test/SparkplugIntegrationTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test;\n\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.mock;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.eclipse.kura.ssl.SslManagerService;\nimport org.eclipse.paho.client.mqttv3.MqttClient;\nimport org.eclipse.paho.client.mqttv3.MqttConnectOptions;\nimport org.eclipse.paho.client.mqttv3.MqttException;\nimport org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.moquette.broker.Server;\nimport io.moquette.broker.config.ClasspathResourceLoader;\nimport io.moquette.broker.config.IConfig;\nimport io.moquette.broker.config.IResourceLoader;\nimport io.moquette.broker.config.ResourceLoaderConfig;\n\npublic class SparkplugIntegrationTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(SparkplugIntegrationTest.class);\n\n    private static final String SPARKPLUG_FACTORY_PID = \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.SparkplugCloudConnectionFactory\";\n    static final String CLOUD_ENDPOINT_PID = \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\";\n    static final String DATA_TRANSPORT_SERVICE_PID = \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\";\n    static final String SPARKPLUG_DEVICE_PID = \"test.device\";\n\n    private static CountDownLatch dependenciesLatch = new CountDownLatch(1);\n\n    static ConfigurationService configurationService;\n    static SparkplugCloudEndpoint sparkplugCloudEndpoint;\n    static SparkplugDataTransport sparkplugDataTransport;\n    static SparkplugDevice sparkplugDevice;\n    static MqttClient client;\n    static Server mqttBroker;\n\n    public void bindConfigurationService(ConfigurationService confService) {\n        configurationService = confService;\n        dependenciesLatch.countDown();\n        logger.info(\"ConfigurationService ready\");\n    }\n\n    public void activate() {\n        logger.info(\"Activating {}\", this.getClass().getName());\n    }\n\n    @BeforeClass\n    public static void initialize() {\n        try {\n            if (!dependenciesLatch.await(30, TimeUnit.SECONDS)) {\n                throw new IllegalStateException(\"Test dependencies not satisfied\");\n            }\n\n            startMqttBroker();\n            createSparkplugCloudConnection();\n            connectDefaultPahoClient();\n            createSparkplugDevice();\n\n            logger.info(\"Test environment successfully setup\");\n        } catch (InterruptedException e) {\n            fail(\"Error in environment setup. See logs\");\n            Thread.currentThread().interrupt();\n        } catch (Exception e) {\n            logger.error(\"Error during test environment setup\", e);\n        }\n    }\n\n    @AfterClass\n    public static void tearDown() throws MqttException {\n        client.disconnect();\n        stopBroker();\n    }\n\n    @Test\n    public void shouldBeSetup() {\n        assertNotNull(configurationService);\n        assertNotNull(sparkplugCloudEndpoint);\n        assertNotNull(sparkplugDataTransport);\n    }\n\n    public static void startMqttBroker() throws Exception {\n        IResourceLoader classpathLoader = new ClasspathResourceLoader();\n        IConfig classPathConfig = new ResourceLoaderConfig(classpathLoader);\n\n        mqttBroker = new Server();\n        mqttBroker.startServer(classPathConfig);\n        logger.info(\"Moquette MQTT broker started\");\n\n        Runtime.getRuntime().addShutdownHook(new Thread(() -> stopBroker()));\n    }\n\n    public static void stopBroker() {\n        mqttBroker.stopServer();\n        logger.info(\"Moquette MQTT broker stopped\");\n    }\n\n    public static <T> T trackService(Class<T> clazz, String pid)\n            throws InterruptedException, ExecutionException, TimeoutException {\n        return (T) ServiceUtil.trackService(clazz, Optional.of(String.format(\"(kura.service.pid=%s)\", pid))).get(30,\n                TimeUnit.SECONDS);\n    }\n\n    private static void createSparkplugCloudConnection()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException {\n        if (!configurationService.getConfigurableComponentPids().contains(SPARKPLUG_FACTORY_PID)) {\n            CloudConnectionFactory factory = ServiceUtil.createFactoryConfiguration(configurationService,\n                    CloudConnectionFactory.class, SPARKPLUG_FACTORY_PID, SPARKPLUG_FACTORY_PID, null)\n                    .get(30, TimeUnit.SECONDS);\n            factory.createConfiguration(CLOUD_ENDPOINT_PID);\n\n            sparkplugCloudEndpoint = (SparkplugCloudEndpoint) trackService(CloudEndpoint.class, CLOUD_ENDPOINT_PID);\n            sparkplugDataTransport = (SparkplugDataTransport) trackService(DataTransportService.class,\n                    DATA_TRANSPORT_SERVICE_PID);\n\n            deactivateSsl();\n\n            logger.info(\"Got references for Sparkplug CloudEndpoint and DataTransportService\");\n        }\n    }\n\n    private static void createSparkplugDevice()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException {\n        if (!configurationService.getConfigurableComponentPids().contains(SPARKPLUG_DEVICE_PID)) {\n            final Map<String, Object> properties = new HashMap<>();\n            properties.put(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), CLOUD_ENDPOINT_PID);\n            properties.put(SparkplugDevice.KEY_DEVICE_ID, \"d1\");\n\n            configurationService.createFactoryConfiguration(\n                    \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice\", SPARKPLUG_DEVICE_PID,\n                    properties, false);\n            sparkplugDevice = (SparkplugDevice) trackService(CloudPublisher.class, SPARKPLUG_DEVICE_PID);\n        }\n    }\n\n    private static void connectDefaultPahoClient() throws Exception {\n        client = new MqttClient(\"tcp://localhost:1883\", \"sparkplug.it.test\", new MemoryPersistence());\n        MqttConnectOptions options = new MqttConnectOptions();\n        options.setAutomaticReconnect(false);\n        options.setCleanSession(true);\n        client.connect(options);\n    }\n\n    private static void deactivateSsl() {\n        SslManagerService sslService = mock(SslManagerService.class);\n        sparkplugDataTransport.setSslManagerService(sslService);\n        sparkplugDataTransport.unsetSslManagerService(sslService);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/main/resources/config/moquette.conf",
    "content": "#\n# Copyright (c) 2024 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nport 1883\nhost 0.0.0.0\nallow_anonymous true\npersistence_enabled false\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/test/CloudDeliveryListenerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.junit.Test;\n\npublic class CloudDeliveryListenerTest extends StepsCollection {\n\n    private CloudDeliveryListener cloudDeliveryListener = mock(CloudDeliveryListener.class);\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldNotifyOnMessageConfirmed() {\n        givenCloudDeliveryListener(this.cloudDeliveryListener);\n\n        whenOnMessageConfirmed(121, \"test\");\n\n        thenCloudDeliveryListenerNotifiedOnMessageConfirmed(\"121\", 1);\n    }\n\n    @Test\n    public void shouldNotNotifyOnMessageConfirmed() {\n        givenCloudDeliveryListener(this.cloudDeliveryListener);\n        givenUnregisterCloudDeliveryListener(this.cloudDeliveryListener);\n\n        whenOnMessageConfirmed(121, \"test\");\n\n        thenCloudDeliveryListenerNotifiedOnMessageConfirmed(\"121\", 0);\n    }\n\n    /*\n     * Steps\n     */\n\n    private void thenCloudDeliveryListenerNotifiedOnMessageConfirmed(String expectedMessageId, int expectedTimes) {\n        verify(this.cloudDeliveryListener, times(expectedTimes)).onMessageConfirmed(expectedMessageId);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/test/ConnectionStatusCallbackTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.test;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport org.eclipse.kura.cloud.CloudConnectionEstablishedEvent;\nimport org.eclipse.kura.cloud.CloudConnectionLostEvent;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.data.DataService;\nimport org.junit.Test;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventAdmin;\n\npublic class ConnectionStatusCallbackTest extends StepsCollection {\n\n    private CloudConnectionListener listener = mock(CloudConnectionListener.class);\n    private EventAdmin eventAdmin = mock(EventAdmin.class);\n    private DataService dataService = mock(DataService.class);\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldNotifyOnConnectionEstabilishedAndPostEvent() {\n        givenEventAdmin(this.eventAdmin);\n        givenDataService(this.dataService);\n        givenCloudConnectionListener(this.listener);\n\n        whenOnConnectionEstabilished();\n\n        thenCloudConnectionListenerNotifiedOnConnectionEstabilished(1);\n        thenEventAdminPostedEvent(CloudConnectionEstablishedEvent.class);\n    }\n\n    @Test\n    public void shouldNotNotifyOnConnectionEstabilishedButShouldPostEvent() {\n        givenEventAdmin(this.eventAdmin);\n        givenDataService(this.dataService);\n        givenCloudConnectionListener(this.listener);\n        givenUnregisterCloudConnectionListener(this.listener);\n\n        whenOnConnectionEstabilished();\n\n        thenCloudConnectionListenerNotifiedOnConnectionEstabilished(0);\n        thenEventAdminPostedEvent(CloudConnectionEstablishedEvent.class);\n    }\n\n    @Test\n    public void shouldNotifyOnDisconnectedAndPostEvent() {\n        givenEventAdmin(this.eventAdmin);\n        givenDataService(this.dataService);\n        givenCloudConnectionListener(this.listener);\n\n        whenOnDisconnected();\n\n        thenCloudConnectionListenerNotifiedOnDisconnected(1);\n        thenEventAdminPostedEvent(CloudConnectionLostEvent.class);\n    }\n\n    @Test\n    public void shouldNotNotifyOnDisconnectedButShouldPostEvent() {\n        givenEventAdmin(this.eventAdmin);\n        givenDataService(this.dataService);\n        givenCloudConnectionListener(this.listener);\n        givenUnregisterCloudConnectionListener(this.listener);\n\n        whenOnDisconnected();\n\n        thenCloudConnectionListenerNotifiedOnDisconnected(0);\n        thenEventAdminPostedEvent(CloudConnectionLostEvent.class);\n    }\n\n    @Test\n    public void shouldNotifyOnConnectionLostAndPostEvent() {\n        givenEventAdmin(this.eventAdmin);\n        givenDataService(this.dataService);\n        givenCloudConnectionListener(this.listener);\n\n        whenOnConnectionLost();\n\n        thenCloudConnectionListenerNotifiedOnConnectionLost(1);\n        thenEventAdminPostedEvent(CloudConnectionLostEvent.class);\n    }\n\n    @Test\n    public void shouldNotNotifyOnConnectionLostButShouldPostEvent() {\n        givenEventAdmin(this.eventAdmin);\n        givenDataService(this.dataService);\n        givenCloudConnectionListener(this.listener);\n        givenUnregisterCloudConnectionListener(this.listener);\n\n        whenOnConnectionLost();\n\n        thenCloudConnectionListenerNotifiedOnConnectionLost(0);\n        thenEventAdminPostedEvent(CloudConnectionLostEvent.class);\n    }\n\n    /*\n     * Steps\n     */\n\n    private void thenCloudConnectionListenerNotifiedOnConnectionEstabilished(int expectedTimes) {\n        verify(this.listener, times(expectedTimes)).onConnectionEstablished();\n    }\n\n    private void thenCloudConnectionListenerNotifiedOnDisconnected(int expectedTimes) {\n        verify(this.listener, times(expectedTimes)).onDisconnected();\n    }\n\n    private void thenCloudConnectionListenerNotifiedOnConnectionLost(int expectedTimes) {\n        verify(this.listener, times(expectedTimes)).onConnectionLost();\n    }\n\n    private <T extends Event> void thenEventAdminPostedEvent(Class<T> eventType) {\n        verify(this.eventAdmin, times(1)).postEvent(any(eventType));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/test/DataServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraDisconnectException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.junit.Test;\n\npublic class DataServiceTest extends StepsCollection {\n\n    private DataService dataService = mock(DataService.class);\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldRegisterAsDataServiceListenerToDataService() {\n        givenDataService(this.dataService);\n\n        whenActivate(new PropertiesBuilder().add(ConfigurationService.KURA_SERVICE_PID, \"test-pid\").build());\n\n        thenDataServiceAddedDataServiceListener(this.endpoint);\n    }\n\n    @Test\n    public void shouldCallDataServiceIsConnected() {\n        givenDataService(this.dataService);\n\n        whenIsConnected();\n\n        thenDataServiceCalledIsConnected();\n    }\n\n    @Test\n    public void shouldCallDataServiceDisconnect() throws KuraDisconnectException {\n        givenDataService(this.dataService);\n\n        whenDisconnect();\n\n        thenDataServiceCalledDisconnect(0);\n    }\n\n    @Test\n    public void shouldCallDataServiceConnect() throws KuraConnectException {\n        givenDataService(this.dataService);\n\n        whenConnect();\n\n        thenDataServiceCalledConnect();\n    }\n\n    /*\n     * Steps\n     */\n\n    private void thenDataServiceAddedDataServiceListener(DataServiceListener listener) {\n        verify(this.dataService, times(1)).addDataServiceListener(listener);\n    }\n\n    private void thenDataServiceCalledIsConnected() {\n        verify(this.dataService, times(1)).isConnected();\n    }\n\n    private void thenDataServiceCalledDisconnect(long expectedQuiesceTimeout) {\n        verify(this.dataService, times(1)).disconnect(expectedQuiesceTimeout);\n    }\n\n    private void thenDataServiceCalledConnect() throws KuraConnectException {\n        verify(this.dataService, times(1)).connect();\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/test/StepsCollection.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraDisconnectException;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint;\nimport org.eclipse.kura.data.DataService;\nimport org.osgi.service.event.EventAdmin;\n\npublic class StepsCollection {\n\n    SparkplugCloudEndpoint endpoint = new SparkplugCloudEndpoint();\n    private Exception occurredException;\n\n    /*\n     * Given\n     */\n\n    void givenDataService(DataService dataService) {\n        this.endpoint.setDataService(dataService);\n    }\n\n    void givenEventAdmin(EventAdmin eventAdmin) {\n        this.endpoint.setEventAdmin(eventAdmin);\n    }\n\n    void givenCloudConnectionListener(CloudConnectionListener listener) {\n        this.endpoint.registerCloudConnectionListener(listener);\n    }\n\n    void givenUnregisterCloudConnectionListener(CloudConnectionListener listener) {\n        this.endpoint.unregisterCloudConnectionListener(listener);\n    }\n\n    void givenCloudDeliveryListener(CloudDeliveryListener listener) {\n        this.endpoint.registerCloudDeliveryListener(listener);\n    }\n\n    void givenUnregisterCloudDeliveryListener(CloudDeliveryListener listener) {\n        this.endpoint.unregisterCloudDeliveryListener(listener);\n    }\n    \n    void givenActivated(Map<String, Object> properties) {\n        this.endpoint.activate(properties);\n    }\n\n    /*\n     * When\n     */\n\n    void whenOnConnectionEstabilished() {\n        this.endpoint.onConnectionEstablished();\n    }\n\n    void whenOnDisconnected() {\n        this.endpoint.onDisconnected();\n    }\n\n    void whenOnConnectionLost() {\n        this.endpoint.onConnectionLost(new Throwable());\n    }\n\n    void whenActivate(Map<String, Object> properties) {\n        try {\n            givenActivated(properties);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    void whenUpdate() {\n        this.endpoint.update();\n    }\n\n    void whenIsConnected() {\n        this.endpoint.isConnected();\n    }\n\n    void whenDisconnect() throws KuraDisconnectException {\n        this.endpoint.disconnect();\n    }\n\n    void whenConnect() throws KuraConnectException {\n        this.endpoint.connect();\n    }\n\n    void whenOnMessageConfirmed(int messageId, String topic) {\n        this.endpoint.onMessageConfirmed(messageId, topic);\n    }\n\n    void whenDeactivate() {\n        try {\n            this.endpoint.deactivate();\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n\n    }\n\n    /*\n     * Then\n     */\n\n    <E extends Exception> void thenExceptionOccurred(Class<E> expectedException) {\n        assertNotNull(this.occurredException);\n        assertEquals(expectedException.getName(), this.occurredException.getClass().getName());\n    }\n\n    /*\n     * Utilities\n     */\n\n    class PropertiesBuilder {\n\n        private Map<String, Object> properties = new HashMap<>();\n\n        public PropertiesBuilder add(String key, Object value) {\n            this.properties.put(key, value);\n            return this;\n        }\n\n        public Map<String, Object> build() {\n            return this.properties;\n        }\n\n    }\n\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/test/SubscriptionRecordTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotEquals;\n\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SubscriptionRecord;\nimport org.junit.Test;\n\npublic class SubscriptionRecordTest {\n\n    private SubscriptionRecord record1;\n    private SubscriptionRecord record2;\n    private SubscriptionRecord record3;\n    private Object otherType;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void equalsShouldBeReflective() {\n        whenInitSubscriptionRecord1(\"t1\", 0);\n\n        thenObjectsAreEqual(this.record1, this.record1);\n        thenHashCodesAreSame(this.record1.hashCode(), this.record1.hashCode());\n    }\n\n    @Test\n    public void equalsShouldBeSymmetric() {\n        whenInitSubscriptionRecord1(\"t1\", 0);\n        whenInitSubscriptionRecord2(\"t1\", 0);\n\n        thenObjectsAreEqual(this.record1, this.record2);\n        thenHashCodesAreSame(this.record1.hashCode(), this.record2.hashCode());\n    }\n\n    @Test\n    public void equalsShouldBeTransitive() {\n        whenInitSubscriptionRecord1(\"t1\", 0);\n        whenInitSubscriptionRecord2(\"t1\", 0);\n        whenInitSubscriptionRecord3(\"t1\", 0);\n\n        thenObjectsAreEqual(this.record1, this.record2);\n        thenObjectsAreEqual(this.record2, this.record3);\n        thenObjectsAreEqual(this.record1, this.record3);\n        thenHashCodesAreSame(this.record1.hashCode(), this.record2.hashCode());\n        thenHashCodesAreSame(this.record2.hashCode(), this.record3.hashCode());\n        thenHashCodesAreSame(this.record1.hashCode(), this.record3.hashCode());\n    }\n\n    @Test\n    public void shouldNotEqualWithDifferentTopic() {\n        whenInitSubscriptionRecord1(\"t1\", 0);\n        whenInitSubscriptionRecord2(\"t2\", 0);\n        \n        thenObjectsAreNotEqual(this.record1, this.record2);\n        thenHashCodesAreDifferent(this.record1.hashCode(), this.record2.hashCode());\n    }\n\n    @Test\n    public void shouldNotEqualWithDifferentQos() {\n        whenInitSubscriptionRecord1(\"t1\", 0);\n        whenInitSubscriptionRecord2(\"t1\", 1);\n\n        thenObjectsAreNotEqual(this.record1, this.record2);\n        thenHashCodesAreDifferent(this.record1.hashCode(), this.record2.hashCode());\n    }\n\n    @Test\n    public void shouldNotEqualWithDifferentType() {\n        whenInitSubscriptionRecord1(\"t1\", 0);\n        whenInitOtherTypeObject();\n\n        thenObjectsAreNotEqual(this.record1, this.otherType);\n        thenHashCodesAreDifferent(this.record1.hashCode(), this.otherType.hashCode());\n    }\n\n    /*\n     * Steps\n     */\n\n    private void whenInitSubscriptionRecord1(String topicFilter, int qos) {\n        this.record1 = new SubscriptionRecord(topicFilter, qos);\n    }\n\n    private void whenInitSubscriptionRecord2(String topicFilter, int qos) {\n        this.record2 = new SubscriptionRecord(topicFilter, qos);\n    }\n\n    private void whenInitSubscriptionRecord3(String topicFilter, int qos) {\n        this.record3 = new SubscriptionRecord(topicFilter, qos);\n    }\n\n    private void whenInitOtherTypeObject() {\n        this.otherType = new Object();\n    }\n\n    private void thenObjectsAreEqual(Object o1, Object o2) {\n        assertEquals(o1, o2);\n    }\n\n    private void thenObjectsAreNotEqual(Object o1, Object o2) {\n        assertNotEquals(o1, o2);\n    }\n\n    private void thenHashCodesAreSame(int hash1, int hash2) {\n        assertEquals(hash1, hash2);\n    }\n\n    private void thenHashCodesAreDifferent(int hash1, int hash2) {\n        assertNotEquals(hash1, hash2);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/test/SubscriptionsMapTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.test;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\n\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SubscriptionRecord;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SubscriptionsMap;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.junit.Test;\n\npublic class SubscriptionsMapTest {\n\n    private SubscriptionsMap subscriptionsMap = new SubscriptionsMap();\n    private List<String> returnedTopicsToUnsubscribe = new LinkedList<>();\n    private List<CloudSubscriberListener> returnedMatchingListeners = new LinkedList<>();\n    private CloudSubscriberListener subListener1 = mock(CloudSubscriberListener.class);\n    private CloudSubscriberListener subListener2 = mock(CloudSubscriberListener.class);\n    private CloudSubscriberListener subListener3 = mock(CloudSubscriberListener.class);\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void removeSomeShouldNotReturnTopicsToUnsubscribe() {\n        givenSubscriptionMapWith(\"t1\", 0, this.subListener1);\n        givenSubscriptionMapWith(\"t1\", 0, this.subListener2);\n        \n        whenRemoveIsCalledFor(this.subListener1);\n\n        thenSubscriptionRecordsContains(new SubscriptionRecord(\"t1\", 0));\n        thenMatchingListenersContains(\"t1\", 0, this.subListener2);\n        thenReturnedTopicsToUnsubscribeIsEmpty();\n    }\n\n    @Test\n    public void removeAllShouldReturnTopicsToUnsubscribe() {\n        givenSubscriptionMapWith(\"t1\", 0, this.subListener1);\n        givenSubscriptionMapWith(\"t1\", 0, this.subListener2);\n\n        whenRemoveIsCalledFor(this.subListener1, this.subListener2);\n\n        thenSubscriptionRecordsNotContains(new SubscriptionRecord(\"t1\", 0));\n        thenMatchingListenersNotContains(\"t1\", 0, this.subListener2);\n        thenReturnedTopicsToUnsubscribeContains(\"t1\");\n    }\n\n    @Test\n    public void shouldMatchSingleLevelWildCard1() {\n        givenSubscriptionMapWith(\"A/B\", 0, this.subListener1);\n        givenSubscriptionMapWith(\"A/+/C\", 0, this.subListener2);\n        givenSubscriptionMapWith(\"A/B/C\", 0, this.subListener3);\n\n        whenGetListenersMatching(\"A/B/C\", 0);\n\n        thenReturnedMatchingListenersNotContains(this.subListener1);\n        thenReturnedMatchingListenersContains(this.subListener2);\n        thenReturnedMatchingListenersContains(this.subListener3);\n    }\n\n    @Test\n    public void shouldMatchSingleLevelWildCard2() {\n        givenSubscriptionMapWith(\"A/B\", 0, this.subListener1);\n        givenSubscriptionMapWith(\"A/+\", 0, this.subListener2);\n        givenSubscriptionMapWith(\"A/B/C\", 0, this.subListener3);\n\n        whenGetListenersMatching(\"A/B\", 0);\n\n        thenReturnedMatchingListenersContains(this.subListener1);\n        thenReturnedMatchingListenersContains(this.subListener2);\n        thenReturnedMatchingListenersNotContains(this.subListener3);\n    }\n\n    @Test\n    public void shouldMatchMultiLevelWildCard() {\n        givenSubscriptionMapWith(\"A/B\", 0, this.subListener1);\n        givenSubscriptionMapWith(\"A/#\", 0, this.subListener2);\n        givenSubscriptionMapWith(\"A/B/C\", 0, this.subListener3);\n\n        whenGetListenersMatching(\"A/B/C\", 0);\n\n        thenReturnedMatchingListenersNotContains(this.subListener1);\n        thenReturnedMatchingListenersContains(this.subListener2);\n        thenReturnedMatchingListenersContains(this.subListener3);\n    }\n\n    @Test\n    public void shouldMatchWithCorrectQos() {\n        givenSubscriptionMapWith(\"A/B\", 1, this.subListener1);\n        givenSubscriptionMapWith(\"A/#\", 0, this.subListener2);\n        givenSubscriptionMapWith(\"A/B/C\", 1, this.subListener3);\n\n        whenGetListenersMatching(\"A/B/C\", 0);\n\n        thenReturnedMatchingListenersNotContains(this.subListener1);\n        thenReturnedMatchingListenersContains(this.subListener2);\n        thenReturnedMatchingListenersNotContains(this.subListener3);\n    }\n\n    @Test\n    public void shouldMatchWithMaximumSubscribedQos() {\n        givenSubscriptionMapWith(\"A/B/C\", 0, this.subListener1);\n\n        whenGetListenersMatching(\"A/B/C\", 1);\n\n        thenReturnedMatchingListenersContains(this.subListener1);\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenSubscriptionMapWith(String topicFilter, int qos, CloudSubscriberListener listener) {\n        this.subscriptionsMap.add(topicFilter, qos, listener);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenRemoveIsCalledFor(CloudSubscriberListener... listeners) {\n        for (CloudSubscriberListener listener : listeners) {\n            this.returnedTopicsToUnsubscribe.addAll(this.subscriptionsMap.remove(listener));\n        }\n    }\n\n    private void whenGetListenersMatching(String topic, int qos) {\n        this.returnedMatchingListeners = this.subscriptionsMap.getMatchingListeners(topic, qos);\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenSubscriptionRecordsContains(SubscriptionRecord subscription) {\n        assertTrue(this.subscriptionsMap.getSubscriptionRecords().contains(subscription));\n    }\n\n    private void thenSubscriptionRecordsNotContains(SubscriptionRecord subscription) {\n        assertFalse(this.subscriptionsMap.getSubscriptionRecords().contains(subscription));\n    }\n\n    private void thenMatchingListenersContains(String topic, int qos, CloudSubscriberListener listener) {\n        whenGetListenersMatching(topic, qos);\n        thenReturnedMatchingListenersContains(listener);\n    }\n\n    private void thenMatchingListenersNotContains(String topic, int qos, CloudSubscriberListener listener) {\n        whenGetListenersMatching(topic, qos);\n        thenReturnedMatchingListenersNotContains(listener);\n    }\n\n    private void thenReturnedTopicsToUnsubscribeIsEmpty() {\n        assertTrue(this.returnedTopicsToUnsubscribe.isEmpty());\n    }\n\n    private void thenReturnedTopicsToUnsubscribeContains(String expectedTopic) {\n        assertTrue(this.returnedTopicsToUnsubscribe.contains(expectedTopic));\n    }\n\n    private void thenReturnedMatchingListenersContains(CloudSubscriberListener listener) {\n        assertTrue(this.returnedMatchingListeners.contains(listener));\n    }\n\n    private void thenReturnedMatchingListenersNotContains(CloudSubscriberListener listener) {\n        assertFalse(this.returnedMatchingListeners.contains(listener));\n    }\n\n    /*\n     * Utils\n     */\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/factory/test/SparkplugCloudConnectionFactoryTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.SparkplugCloudConnectionFactory;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class SparkplugCloudConnectionFactoryTest {\n\n    private SparkplugCloudConnectionFactory factory = new SparkplugCloudConnectionFactory();\n    private ConfigurationService configuratioServiceMock = mock(ConfigurationService.class);\n    private String returnedFactoryPid;\n    private Exception occurredException;\n    private List<String> returnedStackComponentPids;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldReturnCorrectFactoryPid() {\n        whenGetFactoryPid();\n        thenReturnedFactoryPidEquals(\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\");\n    }\n\n    @Test\n    public void shouldFailWithOtherComponentPid() {\n        whenCreateConfiguration(\"org.eclipse.kura.cloudconnection.nonsparkplug.mqtt.endpoint.Example\");\n\n        thenExceptionOccurred(KuraException.class);\n    }\n\n    @Test\n    public void shouldCreateCloudStackComponentsWithSuffix() throws KuraException {\n        whenCreateConfiguration(\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint-test\");\n\n        thenFactoryComponentIsCreated(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\",\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint-test\",\n                new ExpectedPropertiesBuilder()\n                    .withProperty(\"DataService.target\",\n                        \"(kura.service.pid=org.eclipse.kura.cloudconnection.sparkplug.mqtt.data.SparkplugDataService-test)\")\n                    .withProperty(CloudConnectionFactory.KURA_CLOUD_CONNECTION_FACTORY_PID,\n                        \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.SparkplugCloudConnectionFactory\")\n                    .withProperty(\"DataTransportService.target\",\n                        \"(kura.service.pid=org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport-test)\")\n                    .build(),\n                false);\n        thenFactoryComponentIsCreated(\n                \"org.eclipse.kura.data.DataService\",\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.data.SparkplugDataService-test\",\n                new ExpectedPropertiesBuilder()\n                    .withProperty(\"DataTransportService.target\",\n                        \"(kura.service.pid=org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport-test)\")\n                    .build(),\n                false);\n        thenFactoryComponentIsCreated(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\",\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport-test\",\n                null,\n                true);\n    }\n    \n    @Test\n    public void shouldCreateCloudStackComponentsWithoutSuffix() throws KuraException {\n        whenCreateConfiguration(\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\");\n\n        thenFactoryComponentIsCreated(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\",\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\",\n                new ExpectedPropertiesBuilder()\n                    .withProperty(\"DataService.target\",\n                        \"(kura.service.pid=org.eclipse.kura.cloudconnection.sparkplug.mqtt.data.SparkplugDataService)\")\n                    .withProperty(CloudConnectionFactory.KURA_CLOUD_CONNECTION_FACTORY_PID,\n                        \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.SparkplugCloudConnectionFactory\")\n                    .withProperty(\"DataTransportService.target\",\n                            \"(kura.service.pid=org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport)\")\n                    .build(),\n                false);\n        thenFactoryComponentIsCreated(\n                \"org.eclipse.kura.data.DataService\",\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.data.SparkplugDataService\",\n                new ExpectedPropertiesBuilder()\n                    .withProperty(\"DataTransportService.target\",\n                        \"(kura.service.pid=org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport)\")\n                    .build(),\n                false);\n        thenFactoryComponentIsCreated(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\",\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\",\n                null,\n                true);\n    }\n\n    @Test\n    public void shouldReturnCorrectStackComponentPidsWithSuffix() throws KuraException {\n        whenGetStackComponentsPids(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint-test\");\n\n        thenReturnedStackComponentPidsContain(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint-test\");\n        thenReturnedStackComponentPidsContain(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.data.SparkplugDataService-test\");\n        thenReturnedStackComponentPidsContain(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport-test\");\n    }\n\n    @Test\n    public void shouldReturnCorrectStackComponentPidsWithoutSuffix() throws KuraException {\n        whenGetStackComponentsPids(\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\");\n\n        thenReturnedStackComponentPidsContain(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint\");\n        thenReturnedStackComponentPidsContain(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.data.SparkplugDataService\");\n        thenReturnedStackComponentPidsContain(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport\");\n    }\n\n    @Test\n    public void shouldDeleteCloudStackComponentsWithSuffix() throws KuraException {\n        whenDeleteConfiguration(\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint-test\");\n\n        thenFactoryComponentIsDeleted(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint-test\", false);\n        thenFactoryComponentIsDeleted(\"org.eclipse.kura.cloudconnection.sparkplug.mqtt.data.SparkplugDataService-test\",\n                false);\n        thenFactoryComponentIsDeleted(\n                \"org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport-test\", true);\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    /*\n     * When\n     */\n\n    private void whenGetFactoryPid() {\n        this.returnedFactoryPid = this.factory.getFactoryPid();\n    }\n\n    private void whenCreateConfiguration(String userPid) {\n        try {\n            this.factory.createConfiguration(userPid);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenGetStackComponentsPids(String userPid) throws KuraException {\n        this.returnedStackComponentPids = this.factory.getStackComponentsPids(userPid);\n    }\n\n    private void whenDeleteConfiguration(String userPid) throws KuraException {\n        this.factory.deleteConfiguration(userPid);\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenReturnedFactoryPidEquals(String expectedFactoryPid) {\n        assertEquals(expectedFactoryPid, this.returnedFactoryPid);\n    }\n\n    private <E extends Exception> void thenExceptionOccurred(Class<E> expectedException) {\n        assertNotNull(this.occurredException);\n        assertEquals(expectedException.getName(), this.occurredException.getClass().getName());\n    }\n\n    private void thenFactoryComponentIsCreated(String expectedFactoryPid, String expectedPid,\n            Map<String, Object> expectedProperties, boolean expectedTakeSnapshot) throws KuraException {\n        verify(this.configuratioServiceMock, times(1)).createFactoryConfiguration(expectedFactoryPid, expectedPid,\n                expectedProperties, expectedTakeSnapshot);\n    }\n\n    private void thenReturnedStackComponentPidsContain(String expectedPid) {\n        assertTrue(this.returnedStackComponentPids.contains(expectedPid));\n    }\n\n    private void thenFactoryComponentIsDeleted(String expectedPid, boolean expectedTakeSnapshot) throws KuraException {\n        verify(this.configuratioServiceMock, times(1)).deleteFactoryConfiguration(expectedPid, expectedTakeSnapshot);\n    }\n\n    /*\n     * Utilities\n     */\n\n    @Before\n    public void setup() {\n        this.factory.setConfigurationService(this.configuratioServiceMock);\n    }\n\n    private class ExpectedPropertiesBuilder {\n        \n        private Map<String, Object> properties = new HashMap<>();\n\n        public ExpectedPropertiesBuilder withProperty(String key, Object value) {\n            this.properties.put(key, value);\n            return this;\n        }\n        \n        public Map<String, Object> build() {\n            return this.properties;\n        }\n        \n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/test/SparkplugBProtobufPayloadBuilderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugBProtobufPayloadBuilder;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.DataType;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload.Metric;\nimport org.junit.Test;\nimport org.junit.experimental.runners.Enclosed;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\n@RunWith(Enclosed.class)\npublic class SparkplugBProtobufPayloadBuilderTest {\n\n    /*\n     * Scenarios\n     */\n\n    @RunWith(Parameterized.class)\n    public static class TypeMapperTest extends Steps {\n\n        @Parameters\n        public static Collection<TypeMapperCase> parameters() {\n            long timestamp = new Date().getTime();\n\n            List<TypeMapperCase> supportedTypes = Arrays.asList(\n                    new TypeMapperCase(\"metric.boolean\", false, timestamp, DataType.Boolean),\n                    new TypeMapperCase(\"metric.bytes\", \"somebytes\".getBytes(), timestamp, DataType.Bytes),\n                    new TypeMapperCase(\"metric.double\", (double) 11.2, timestamp, DataType.Double),\n                    new TypeMapperCase(\"metric.float\", (float) 99.1, timestamp, DataType.Float),\n                    new TypeMapperCase(\"metric.int8\", 1, timestamp, DataType.Int8),\n                    new TypeMapperCase(\"metric.int16\", 16, timestamp, DataType.Int16),\n                    new TypeMapperCase(\"metric.int32\", 32, timestamp, DataType.Int32),\n                    new TypeMapperCase(\"metric.int64\", 64L, timestamp, DataType.Int64),\n                    new TypeMapperCase(\"metric.uint8\", 8, timestamp, DataType.UInt8),\n                    new TypeMapperCase(\"metric.uint16\", 16, timestamp, DataType.UInt16),\n                    new TypeMapperCase(\"metric.uint32\", 322L, timestamp, DataType.UInt32),\n                    new TypeMapperCase(\"metric.uint64\", 9999L, timestamp, DataType.UInt64),\n                    new TypeMapperCase(\"metric.string\", \"a string\", timestamp, DataType.String),\n                    new TypeMapperCase(\"metric.text\", \"a text\", timestamp, DataType.Text),\n                    new TypeMapperCase(\"metric.uuid\", \"a uuid\", timestamp, DataType.UUID));\n\n            Object randomData = new Object();\n            Exception ex = new UnsupportedOperationException();\n            List<TypeMapperCase> unsupportedTypes = Arrays.asList(\n                    new TypeMapperCase(\"metric.dataset\", randomData, timestamp, DataType.DataSet, ex),\n                    new TypeMapperCase(\"metric.template\", randomData, timestamp, DataType.Template, ex),\n                    new TypeMapperCase(\"metric.propertyset\", randomData, timestamp, DataType.PropertySet, ex),\n                    new TypeMapperCase(\"metric.propertysetlist\", randomData, timestamp, DataType.PropertySetList,\n                            ex),\n                    new TypeMapperCase(\"metric.file\", randomData, timestamp, DataType.File, ex),\n                    new TypeMapperCase(\"metric.booleanarray\", randomData, timestamp, DataType.BooleanArray, ex),\n                    new TypeMapperCase(\"metric.datetimearray\", randomData, timestamp, DataType.DateTimeArray, ex),\n                    new TypeMapperCase(\"metric.unit8array\", randomData, timestamp, DataType.UInt8Array, ex),\n                    new TypeMapperCase(\"metric.uint64array\", randomData, timestamp, DataType.UInt64Array, ex),\n                    new TypeMapperCase(\"metric.uint32array\", randomData, timestamp, DataType.UInt32Array, ex),\n                    new TypeMapperCase(\"metric.uint16array\", randomData, timestamp, DataType.UInt16Array, ex),\n                    new TypeMapperCase(\"metric.stringarray\", randomData, timestamp, DataType.StringArray, ex),\n                    new TypeMapperCase(\"metric.int8array\", randomData, timestamp, DataType.Int8Array, ex),\n                    new TypeMapperCase(\"metric.int64array\", randomData, timestamp, DataType.Int64Array, ex),\n                    new TypeMapperCase(\"metric.int32array\", randomData, timestamp, DataType.Int32Array, ex),\n                    new TypeMapperCase(\"metric.int16array\", randomData, timestamp, DataType.Int16Array, ex),\n                    new TypeMapperCase(\"metric.floatarray\", randomData, timestamp, DataType.FloatArray, ex),\n                    new TypeMapperCase(\"metric.doubleArray\", randomData, timestamp, DataType.DoubleArray, ex),\n                    new TypeMapperCase(\"metric.unknown\", randomData, timestamp, DataType.Unknown, ex));\n\n            return Stream.concat(supportedTypes.stream(), unsupportedTypes.stream()).collect(Collectors.toList());\n        }\n\n        private TypeMapperCase testCase;\n\n        public TypeMapperTest(TypeMapperCase testCase) {\n            this.testCase = testCase;\n        }\n\n        @Test\n        public void shouldBuildMetric() {\n            givenMetric(this.testCase.getName(), this.testCase.getValue(), this.testCase.getTimestamp());\n            \n            whenBuildPayload();\n            \n            thenPayloadContainsMetric(this.testCase.getName(), this.testCase.getValue(), this.testCase.getTimestamp(),\n                    this.testCase.getExpectedDataType(), this.testCase.getExpectedException());\n        }\n    }\n\n    public static class SparkplugPropertiesTest extends Steps {\n\n        @Test\n        public void shouldReturnCorrectBdSeq() {\n            givenBdSeq(12L, 120L);\n            \n            whenBuildPayload();\n            \n            thenPayloadContainsMetric(\"bdSeq\", 12L, 120L, DataType.Int64, Optional.empty());\n        }\n\n        @Test\n        public void shouldReturnCorrectSeq() {\n            givenSeq(13L);\n\n            whenBuildPayload();\n\n            thenSeqEquals(13L);\n        }\n\n        @Test\n        public void shouldReturnCorrectTimestamp() {\n            givenTimestamp(13123L);\n\n            whenBuildPayload();\n\n            thenTimestampEquals(13123L);\n        }\n\n        @Test\n        public void shouldReturnCorrectBody() {\n            givenBody(\"example.body\".getBytes());\n\n            whenBuildPayload();\n\n            thenBodyEquals(\"example.body\".getBytes());\n        }\n\n    }\n\n    /*\n     * Steps\n     */\n\n    public abstract static class Steps {\n\n        private SparkplugBProtobufPayloadBuilder builder;\n        private Payload payload;\n        private Exception occurredException;\n\n        /*\n         * Given\n         */\n\n        void givenMetric(String name, Object value, long timestamp) {\n            try {\n                this.builder = new SparkplugBProtobufPayloadBuilder().withMetric(name, value, timestamp);\n            } catch (Exception e) {\n                this.occurredException = e;\n            }\n        }\n\n        void givenBdSeq(long bdSeq, long timestamp) {\n            this.builder = new SparkplugBProtobufPayloadBuilder().withBdSeq(bdSeq, timestamp);\n        }\n\n        void givenSeq(long seq) {\n            this.builder = new SparkplugBProtobufPayloadBuilder().withSeq(seq);\n        }\n\n        void givenTimestamp(long timestamp) {\n            this.builder = new SparkplugBProtobufPayloadBuilder().withTimestamp(timestamp);\n        }\n\n        void givenBody(byte[] body) {\n            this.builder = new SparkplugBProtobufPayloadBuilder().withBody(body);\n        }\n\n        /*\n         * When\n         */\n\n        void whenBuildPayload() {\n            if (Objects.isNull(this.occurredException)) {\n                this.payload = this.builder.buildPayload();\n            }\n        }\n\n        /*\n         * Then\n         */\n\n        void thenPayloadContainsMetric(String expectedName, Object expectedValue, long expectedTimestamp,\n                DataType expectedDataType, Optional<Exception> expectedException) {\n            if (expectedException.isPresent()) {\n                thenExceptionOccurred(expectedException.get().getClass());\n            } else {\n                Metric metric = this.payload.getMetricsList().stream().filter(m -> m.getName().equals(expectedName))\n                        .collect(Collectors.toList()).get(0);\n\n                Object actualValue = null;\n\n                switch (expectedDataType) {\n                case Boolean:\n                    actualValue = metric.getBooleanValue();\n                    break;\n                case Bytes:\n                    actualValue = metric.getBytesValue().toByteArray();\n                    break;\n                case DateTime:\n                case Int64:\n                case UInt32:\n                case UInt64:\n                    actualValue = metric.getLongValue();\n                    break;\n                case Double:\n                    actualValue = metric.getDoubleValue();\n                    break;\n                case Int8:\n                case Int16:\n                case Int32:\n                case UInt8:\n                case UInt16:\n                    actualValue = metric.getIntValue();\n                    break;\n                case Float:\n                    actualValue = metric.getFloatValue();\n                    break;\n                case String:\n                case Text:\n                case UUID:\n                    actualValue = metric.getStringValue();\n                    break;\n                case File:\n                case DataSet:\n                case DateTimeArray:\n                case Int16Array:\n                case Int32Array:\n                case Int64Array:\n                case Int8Array:\n                case PropertySet:\n                case PropertySetList:\n                case StringArray:\n                case Template:\n                case UInt16Array:\n                case FloatArray:\n                case UInt32Array:\n                case UInt64Array:\n                case DoubleArray:\n                case UInt8Array:\n                case BooleanArray:\n                case Unknown:\n                default:\n                    break;\n                }\n\n                assertEquals(expectedName, metric.getName());\n                assertEquals(expectedTimestamp, metric.getTimestamp());\n\n                if (actualValue instanceof byte[]) {\n                    assertTrue(Arrays.equals((byte[]) expectedValue, (byte[]) actualValue));\n                } else {\n                    assertEquals(expectedValue, actualValue);\n                }\n            }\n        }\n\n        <E extends Exception> void thenExceptionOccurred(Class<E> expectedException) {\n            assertNotNull(\"No exception thrown\", this.occurredException);\n            assertEquals(expectedException.getName(), this.occurredException.getClass().getName());\n        }\n\n        void thenSeqEquals(long expectedSeq) {\n            assertEquals(expectedSeq, this.payload.getSeq());\n        }\n\n        void thenTimestampEquals(long expectedTimestamp) {\n            assertEquals(expectedTimestamp, this.payload.getTimestamp());\n        }\n\n        void thenBodyEquals(byte[] expectedBody) {\n            assertTrue(Arrays.equals(expectedBody, this.payload.getBody().toByteArray()));\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/test/TypeMapperCase.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.test;\n\nimport java.util.Optional;\n\nimport org.eclipse.tahu.protobuf.SparkplugBProto.DataType;\n\nclass TypeMapperCase {\n\n    private String name;\n    private Object value;\n    private long timestamp;\n    private DataType expectedDataType;\n    private Exception expectedException;\n\n    public TypeMapperCase(String name, Object value, long timestamp, DataType expectedDataType) {\n        this.name = name;\n        this.value = value;\n        this.timestamp = timestamp;\n        this.expectedDataType = expectedDataType;\n    }\n\n    public TypeMapperCase(String name, Object value, long timestamp, DataType expectedDataType, Exception expectedException) {\n        this(name, value, timestamp, expectedDataType);\n        this.expectedException = expectedException;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public Object getValue() {\n        return this.value;\n    }\n\n    public long getTimestamp() {\n        return this.timestamp;\n    }\n\n    public DataType getExpectedDataType() {\n        return this.expectedDataType;\n    }\n\n    public Optional<Exception> getExpectedException() {\n        return Optional.ofNullable(this.expectedException);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/subscriber/test/SparkplugSubscriberTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.test;\n\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber;\nimport org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber;\nimport org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.tahu.protobuf.SparkplugBProto;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload.DataSet;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload.Metric;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload.Metric.MetricValueExtension;\nimport org.eclipse.tahu.protobuf.SparkplugBProto.Payload.Template;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatcher;\nimport org.osgi.service.event.EventAdmin;\n\nimport com.google.protobuf.ByteString;\n\npublic class SparkplugSubscriberTest {\n\n    private DataService dataService = mock(DataService.class);\n    private SparkplugCloudEndpoint endpoint = new SparkplugCloudEndpoint();\n    private SparkplugSubscriber sub1 = new SparkplugSubscriber();\n    private SparkplugSubscriber sub2 = new SparkplugSubscriber();\n    private SparkplugSubscriber sub3 = new SparkplugSubscriber();\n    private SparkplugSubscriber sub4 = new SparkplugSubscriber();\n    private CloudSubscriberListener subListener = mock(CloudSubscriberListener.class);\n    private CloudConnectionListener cloudConnectionListener = mock(CloudConnectionListener.class);\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldForwardMessagesToCorrectSubscribers() throws Exception {\n        givenInitialSetup(true);\n        givenRegisterSubscriber(\"a/b/c\", 0, this.sub1);\n        givenRegisterSubscriber(\"a/+/c\", 0, this.sub2);\n        givenRegisterSubscriber(\"a/#\", 0, this.sub3);\n        givenRegisterSubscriber(\"a/b\", 0, this.sub4);\n        givenRegisterCloudSubscriberListener(this.sub1, this.subListener);\n        givenRegisterCloudSubscriberListener(this.sub2, this.subListener);\n        givenRegisterCloudSubscriberListener(this.sub3, this.subListener);\n        givenRegisterCloudSubscriberListener(this.sub4, this.subListener);\n\n        whenOnMessageArrivedWithAllSupportedMetrics(\"a/b/c\", 0);\n\n        thenSubscriberListenerNotifiedOnMessageArrived(this.subListener, 3);\n    }\n\n    @Test\n    public void shouldNotForwardMessagesToUnsubscribed() throws Exception {\n        givenInitialSetup(true);\n        givenRegisterSubscriber(\"a/b/c\", 0, this.sub1);\n        givenRegisterSubscriber(\"a/+/c\", 0, this.sub2);\n        givenRegisterSubscriber(\"a/#\", 0, this.sub3);\n        givenRegisterSubscriber(\"a/b\", 0, this.sub4);\n        givenRegisterCloudSubscriberListener(this.sub1, this.subListener);\n        givenRegisterCloudSubscriberListener(this.sub2, this.subListener);\n        givenRegisterCloudSubscriberListener(this.sub3, this.subListener);\n        givenRegisterCloudSubscriberListener(this.sub4, this.subListener);\n        givenUnregisterSubscriber(this.sub1);\n        givenUnregisterSubscriber(this.sub2);\n\n        whenOnMessageArrivedWithAllSupportedMetrics(\"a/b/c\", 0);\n\n        thenSubscriberListenerNotifiedOnMessageArrived(this.subListener, 1);\n    }\n\n    @Test\n    public void shouldSubscribeOnConnectionEstabilished() throws Exception {\n        givenInitialSetup(false);\n        givenRegisterSubscriber(\"a/b/c\", 0, this.sub1);\n        givenRegisterSubscriber(\"a/+/c\", 0, this.sub2);\n        givenRegisterSubscriber(\"a/#\", 1, this.sub3);\n        givenRegisterSubscriber(\"a/#\", 0, this.sub4);\n\n        whenEndpointEstablishConnection();\n\n        thenSubscribed(\"a/b/c\", 0);\n        thenSubscribed(\"a/+/c\", 0);\n        thenSubscribed(\"a/#\", 1);\n        thenSubscribed(\"a/#\", 0);\n    }\n\n    @Test\n    public void shouldNotifyCloudConnectionListenerOnDisconnected() {\n        givenCloudConnectionListener(this.sub1, this.cloudConnectionListener);\n        \n        whenOnDisconnected(this.sub1);\n        \n        thenConnectionListenerNotifiedOnDisconnected(this.cloudConnectionListener);\n    }\n\n    @Test\n    public void shouldNotifyCloudConnectionListenerOnConnectionLost() {\n        givenCloudConnectionListener(this.sub1, this.cloudConnectionListener);\n\n        whenOnConnectionLost(this.sub1);\n\n        thenConnectionListenerNotifiedOnConnectionLost(this.cloudConnectionListener);\n    }\n\n    @Test\n    public void shouldNotifyCloudConnectionListenerOnConnectionEstablished() {\n        givenCloudConnectionListener(this.sub1, this.cloudConnectionListener);\n\n        whenOnConnectionEstablished(this.sub1);\n\n        thenConnectionListenerNotifiedOnConnectionEstablished(this.cloudConnectionListener);\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenInitialSetup(boolean isConnected) {\n        when(this.dataService.isConnected()).thenReturn(isConnected);\n        this.endpoint.setDataService(this.dataService);\n        \n        EventAdmin mockEventAdmin = mock(EventAdmin.class);\n        this.endpoint.setEventAdmin(mockEventAdmin);\n    }\n\n    private void givenRegisterSubscriber(String topicFilter, int qos, CloudSubscriberListener listener)\n            throws Exception {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(SparkplugSubscriber.KEY_TOPIC_FILTER, topicFilter);\n        properties.put(SparkplugSubscriber.KEY_QOS, qos);\n\n        this.endpoint.registerSubscriber(properties, listener);\n    }\n\n    private void givenUnregisterSubscriber(CloudSubscriberListener listener) {\n\n        this.endpoint.unregisterSubscriber(listener);\n    }\n\n    private void givenRegisterCloudSubscriberListener(CloudSubscriber subscriber, CloudSubscriberListener listener)\n            throws Exception {\n        subscriber.registerCloudSubscriberListener(listener);\n    }\n\n    private void givenCloudConnectionListener(CloudSubscriber subscriber, CloudConnectionListener listener) {\n        subscriber.registerCloudConnectionListener(listener);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenOnMessageArrivedWithAllSupportedMetrics(String topic, int qos) {\n        SparkplugBProto.Payload.Builder builder = Payload.newBuilder();\n\n        builder.addMetrics(getBooleanMetric(\"metric.boolean\", true));\n        builder.addMetrics(getBytesMetric(\"metric.bytes\", \"test\".getBytes()));\n        builder.addMetrics(getDatasetMetric(\"metric.dataset\", DataSet.getDefaultInstance()));\n        builder.addMetrics(getDoubleMetric(\"metric.double\", 12.3));\n        builder.addMetrics(getExtensionValueMetric(\"metric.extension\", MetricValueExtension.getDefaultInstance()));\n        builder.addMetrics(getFloatMetric(\"metric.float\", 12f));\n        builder.addMetrics(getIntegerMetric(\"metric.int\", 11));\n        builder.addMetrics(getLongMetric(\"metric.long\", 123L));\n        builder.addMetrics(getStringMetric(\"metric.string\", \"test\"));\n        builder.addMetrics(getTemplateMetric(\"metric.template\", Template.getDefaultInstance()));\n\n        builder.setBody(ByteString.copyFrom(\"example\".getBytes()));\n        builder.setTimestamp(1000L);\n        builder.setSeq(100L);\n\n        this.endpoint.onMessageArrived(topic, builder.build().toByteArray(), qos, false);\n    }\n\n    private void whenEndpointEstablishConnection() {\n        when(this.dataService.isConnected()).thenReturn(true);\n        this.endpoint.onConnectionEstablished();\n    }\n\n    private void whenOnDisconnected(SparkplugSubscriber subscriber) {\n        subscriber.onDisconnected();\n    }\n\n    private void whenOnConnectionLost(SparkplugSubscriber subscriber) {\n        subscriber.onConnectionLost();\n    }\n\n    private void whenOnConnectionEstablished(SparkplugSubscriber subscriber) {\n        subscriber.onConnectionEstablished();\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenSubscriberListenerNotifiedOnMessageArrived(CloudSubscriberListener subscriberListener,\n            int expectedTimes) {\n        verify(subscriberListener, timeout(1000L).times(expectedTimes))\n                .onMessageArrived(argThat(new ArgumentMatcher<KuraMessage>() {\n\n            @Override\n            public boolean matches(KuraMessage message) {\n                KuraPayload payload = message.getPayload();\n                \n                boolean bodyMatches = Arrays.equals(payload.getBody(), \"example\".getBytes());\n                boolean timestampMatches = payload.getTimestamp().getTime() == 1000L;\n                boolean seqMatches = ((long) payload.getMetric(\"seq\")) == 100L;\n                \n                return bodyMatches && timestampMatches && seqMatches;\n            }\n\n        }));\n    }\n\n    private void thenConnectionListenerNotifiedOnDisconnected(CloudConnectionListener subscriberListener) {\n        verify(subscriberListener, timeout(1000L).times(1)).onDisconnected();\n    }\n\n    private void thenConnectionListenerNotifiedOnConnectionLost(CloudConnectionListener subscriberListener) {\n        verify(subscriberListener, timeout(1000L).times(1)).onConnectionLost();\n    }\n\n    private void thenConnectionListenerNotifiedOnConnectionEstablished(CloudConnectionListener subscriberListener) {\n        verify(subscriberListener, timeout(1000L).times(1)).onConnectionEstablished();\n    }\n\n    private void thenSubscribed(String expectedTopicFilter, int expectedQos) throws KuraException {\n        verify(this.dataService, times(1)).subscribe(expectedTopicFilter, expectedQos);\n    }\n\n\n\n    /*\n     * Utils\n     */\n\n    private Metric getBooleanMetric(String name, boolean value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setBooleanValue(value);\n        return metricBuilder.build();\n    }\n\n    private Metric getBytesMetric(String name, byte[] value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setBytesValue(ByteString.copyFrom(value));\n        return metricBuilder.build();\n    }\n\n    private Metric getDatasetMetric(String name, DataSet value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setDatasetValue(value);\n        return metricBuilder.build();\n    }\n\n    private Metric getDoubleMetric(String name, double value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setDoubleValue(value);\n        return metricBuilder.build();\n    }\n\n    private Metric getExtensionValueMetric(String name, MetricValueExtension value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setExtensionValue(value);\n        return metricBuilder.build();\n    }\n\n    private Metric getFloatMetric(String name, float value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setFloatValue(value);\n        return metricBuilder.build();\n    }\n\n    private Metric getIntegerMetric(String name, int value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setIntValue(value);\n        return metricBuilder.build();\n    }\n\n    private Metric getLongMetric(String name, long value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setLongValue(value);\n        return metricBuilder.build();\n    }\n    \n    private Metric getStringMetric(String name, String value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setStringValue(value);\n        return metricBuilder.build();\n    }\n\n    private Metric getTemplateMetric(String name, Template value) {\n        Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder();\n        metricBuilder.setName(name);\n        metricBuilder.setTemplateValue(value);\n        return metricBuilder.build();\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/test/ConfigurationUpdateTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.test;\n\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.anyBoolean;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.security.GeneralSecurityException;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.net.ssl.SSLContext;\n\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransportOptions;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.eclipse.kura.ssl.SslManagerService;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class ConfigurationUpdateTest {\n\n    private SparkplugDataTransport transport = new SparkplugDataTransport();;\n    private DataTransportListener listener = mock(DataTransportListener.class);\n    private SslManagerService sslManagerService = mock(SslManagerService.class);\n    private Exception occurredException;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void test() {\n        assertTrue(true);\n    }\n\n    @Test\n    public void shouldUpdateConfigurationOnSetSslManager() {\n        givenUpdated(\"tcp://localhost:1883\", \"g1\", \"n1\", \"\", \"test.client\", 30, 60);\n\n        whenSetSslManagerService();\n\n        thenUpdateWasCalled(2);\n    }\n\n    @Test\n    public void shouldNotUpdateConfigurationOnNewSslManagerButNullOptions() {\n        whenSetSslManagerService();\n\n        thenUpdateWasCalled(0);\n    }\n\n    @Test\n    public void shouldUpdateConfigurationOnUnsetSslManager() {\n        givenSetSslManagerService();\n        givenUpdated(\"tcp://localhost:1883\", \"g1\", \"n1\", \"\", \"test.client\", 30, 60);\n\n        whenUnsetSslManagerService();\n\n        thenUpdateWasCalled(2);\n    }\n\n    @Test\n    public void shouldNotThrowExceptionsOnDisconnectWithUnconfiguredService() {\n        whenDisconnect();\n\n        thenNoExceptionOccurred();\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenUpdated(String servers, String groupId, String nodeId, String primaryHostId, String clientId,\n            int connectionTimeout, int keepAlive) {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(SparkplugDataTransportOptions.KEY_CLIENT_ID, clientId);\n        properties.put(SparkplugDataTransportOptions.KEY_CONNECTION_TIMEOUT, connectionTimeout);\n        properties.put(SparkplugDataTransportOptions.KEY_GROUP_ID, groupId);\n        properties.put(SparkplugDataTransportOptions.KEY_NODE_ID, nodeId);\n        properties.put(SparkplugDataTransportOptions.KEY_PRIMARY_HOST_APPLICATION_ID, primaryHostId);\n        properties.put(SparkplugDataTransportOptions.KEY_SERVER_URIS, servers);\n        properties.put(SparkplugDataTransportOptions.KEY_KEEP_ALIVE, keepAlive);\n\n        this.transport.update(properties);\n    }\n\n    private void givenSetSslManagerService() {\n        this.transport.setSslManagerService(this.sslManagerService);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenSetSslManagerService() {\n        givenSetSslManagerService();\n    }\n\n    private void whenUnsetSslManagerService() {\n        this.transport.unsetSslManagerService(this.sslManagerService);\n    }\n\n    private void whenDisconnect() {\n        try {\n            this.transport.disconnect(0);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenUpdateWasCalled(int expectedTimes) {\n        verify(this.listener, times(expectedTimes)).onConfigurationUpdated(anyBoolean());\n    }\n\n    private void thenNoExceptionOccurred() {\n        assertNull(\"Exception has occurred\", this.occurredException);\n    }\n\n    /*\n     * Utils\n     */\n\n    @Before\n    public void setup() throws GeneralSecurityException, IOException {\n        this.transport.addDataTransportListener(this.listener);\n        SSLContext context = mock(SSLContext.class);\n        when(this.sslManagerService.getSSLContext()).thenReturn(context);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/src/test/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/test/SparkplugDataTransportOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransportOptions;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.paho.client.mqttv3.MqttConnectOptions;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.experimental.runners.Enclosed;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\n@RunWith(Enclosed.class)\npublic class SparkplugDataTransportOptionsTest {\n\n    /*\n     * Scenarios\n     */\n\n    @RunWith(Parameterized.class)\n    public static class ServerUrisParameterFailTest extends Steps {\n\n        @Parameters\n        public static Collection<String> params() {\n            List<String> data = new LinkedList<>();\n            data.add(null);\n            data.add(\"\");\n            data.add(\"tcp://broker:1883/\");\n            data.add(\"tcp://broker:1883 tcp://broker:1883/\");\n            data.add(\"tcp://broker:1883  tcp://broker2:1883\");\n            return data;\n        }\n\n        private String serverUris;\n\n        public ServerUrisParameterFailTest(String param) {\n            this.serverUris = param;\n        }\n\n        @Test\n        public void shouldThrowKuraExceptionOnWrongServerUri() {\n            givenProperty(SparkplugDataTransportOptions.KEY_SERVER_URIS, this.serverUris);\n            givenProperty(SparkplugDataTransportOptions.KEY_CLIENT_ID, \"test\");\n\n            whenOptionsCreated();\n\n            thenExceptionOccurred(KuraException.class);\n        }\n    }\n\n    @RunWith(Parameterized.class)\n    public static class ServerUrisParameterTest extends Steps {\n\n        @Parameters\n        public static Collection<String> params() {\n            List<String> data = new LinkedList<>();\n            data.add(\"tcp://broker:1883\");\n            data.add(\"tcp://broker1:1883 tcp://broker2:1883\");\n            return data;\n        }\n\n        private String serverUris;\n\n        public ServerUrisParameterTest(String param) {\n            this.serverUris = param;\n        }\n\n        @Test\n        public void shouldReturnCorrectPrimaryServerId() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_SERVER_URIS, this.serverUris);\n            givenProperty(SparkplugDataTransportOptions.KEY_CLIENT_ID, \"test\");\n            givenOptionsCreated();\n\n            whenGetServers();\n\n            thenReturnedServersContains(this.serverUris.split(\" \"));\n        }\n    }\n\n    @RunWith(Parameterized.class)\n    public static class MandatoryPropertiesTest extends Steps {\n\n        @Parameters\n        public static Collection<Object[]> params() {\n            Collection<Object[]> data = new LinkedList<>();\n\n            data.add(new Object[] { SparkplugDataTransportOptions.KEY_GROUP_ID, null });\n            data.add(new Object[] { SparkplugDataTransportOptions.KEY_GROUP_ID, \"\" });\n            data.add(new Object[] { SparkplugDataTransportOptions.KEY_NODE_ID, null });\n            data.add(new Object[] { SparkplugDataTransportOptions.KEY_NODE_ID, \"\" });\n            data.add(new Object[] { SparkplugDataTransportOptions.KEY_CLIENT_ID, null });\n            data.add(new Object[] { SparkplugDataTransportOptions.KEY_CLIENT_ID, \"\" });\n            data.add(new Object[] { SparkplugDataTransportOptions.KEY_KEEP_ALIVE, null });\n            data.add(new Object[] { SparkplugDataTransportOptions.KEY_CONNECTION_TIMEOUT, null });\n\n            return data;\n        }\n\n        private String testKey;\n        private Object testValue;\n\n        public MandatoryPropertiesTest(String key, Object value) {\n            this.testKey = key;\n            this.testValue = value;\n        }\n\n        @Test\n        public void shouldThrowKuraExceptionOnNullMandatoryProperty() {\n            givenProperty((String) this.testKey, this.testValue);\n\n            whenOptionsCreated();\n\n            thenExceptionOccurred(KuraException.class);\n        }\n\n    }\n\n    public static class GettersTest extends Steps {\n\n        @Test\n        public void shouldReturnCorrectGroupId() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_GROUP_ID, \"g1\");\n            givenOptionsCreated();\n\n            whenGetGroupId();\n\n            thenReturnedStringEquals(\"g1\");\n        }\n\n        @Test\n        public void shouldReturnCorrectNodeId() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_NODE_ID, \"n1\");\n            givenOptionsCreated();\n\n            whenGetNodeId();\n\n            thenReturnedStringEquals(\"n1\");\n        }\n\n        @Test\n        public void shouldReturnCorrectPrimaryHostApplicationId() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_PRIMARY_HOST_APPLICATION_ID, \"h1\");\n            givenOptionsCreated();\n\n            whenGetPrimaryHostApplicationId();\n\n            thenRetunedPrimaryHostApplicationIs(\"h1\");\n        }\n\n        @Test\n        public void shouldReturnEmptyPrimaryHostApplicationId() throws KuraException {\n            givenOptionsCreated();\n\n            whenGetPrimaryHostApplicationId();\n\n            thenRetunedPrimaryHostApplicationIdIsEmpty();\n        }\n\n        @Test\n        public void shouldReturnCorrectClientId() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_CLIENT_ID, \"test.client\");\n            givenOptionsCreated();\n\n            whenGetClientId();\n\n            thenReturnedStringEquals(\"test.client\");\n        }\n\n        @Test\n        public void shouldReturnCorrectUsername() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_USERNAME, \"user\");\n            givenOptionsCreated();\n\n            whenGetUsername();\n\n            thenReturnedStringEquals(\"user\");\n        }\n\n        @Test\n        public void shouldReturnCorrectConnectionTimeoutMs() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_CONNECTION_TIMEOUT, 30);\n            givenOptionsCreated();\n\n            whenGetConnectionTimeoutMs();\n\n            thenReturnedLongEquals(30000L);\n        }\n    }\n\n    public static class MqttConnectOptionsTest extends Steps {\n\n        @Test\n        public void shouldReturnCorrectPassword() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_PASSWORD, \"secret\");\n            givenOptionsCreated();\n\n            whenGetMqttConnectOptions();\n\n            thenMqttConnectOptionsContainsPassword(\"secret\");\n        }\n\n        @Test\n        public void shouldNotSetPasswordWhenEmpty() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_PASSWORD, \"\");\n            givenOptionsCreated();\n\n            whenGetMqttConnectOptions();\n\n            thenMqttConnectOptionsNotSetsPassword();\n        }\n\n        @Test\n        public void shouldNotSetUsernameAndPassword() throws KuraException {\n            givenOptionsCreated();\n\n            whenGetMqttConnectOptions();\n\n            thenMqttConnectOptionsNotSetsUsername();\n            thenMqttConnectOptionsNotSetsPassword();\n        }\n\n        @Test\n        public void shouldReturnCorrectKeepAlive() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_KEEP_ALIVE, 12);\n            givenOptionsCreated();\n\n            whenGetMqttConnectOptions();\n\n            thenMqttConnectOptionsContainsKeepAlive(12);\n        }\n\n        @Test\n        public void shouldReturnCorrectConnectionTimeout() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_CONNECTION_TIMEOUT, 20);\n            givenOptionsCreated();\n\n            whenGetMqttConnectOptions();\n\n            thenMqttConnectOptionsContainsConnectionTimeout(20);\n        }\n\n        @Test\n        public void shouldSetCleanSessionTrue() throws KuraException {\n            givenOptionsCreated();\n\n            whenGetMqttConnectOptions();\n\n            thenMqttConnectOptionsHasCleanSessionEnabled();\n        }\n\n        @Test\n        public void shouldSetAutoReconnectFalse() throws KuraException {\n            givenOptionsCreated();\n\n            whenGetMqttConnectOptions();\n\n            thenMqttConnectOptionsHasAutoReconnectDisabled();\n        }\n\n    }\n\n    /*\n     * Steps\n     */\n\n    public abstract static class Steps {\n\n        private SparkplugDataTransportOptions options;\n        private Map<String, Object> properties = new HashMap<>();\n        private Exception occurredException;\n        private String returnedString;\n        private List<String> returnedServers = new LinkedList<>();\n        private Optional<String> returnedPrimaryHostApplicationId = Optional.empty();\n        private long returnedLong;\n        private MqttConnectOptions mqttConnectOptions;\n        private CryptoService cryptoServiceMock;\n\n        @Before\n        public void defaults() throws KuraException {\n            givenProperty(SparkplugDataTransportOptions.KEY_GROUP_ID, \"g1\");\n            givenProperty(SparkplugDataTransportOptions.KEY_NODE_ID, \"n1\");\n            givenProperty(SparkplugDataTransportOptions.KEY_SERVER_URIS, \"tcp://broker:1883\");\n            givenProperty(SparkplugDataTransportOptions.KEY_CLIENT_ID, \"test.client\");\n            givenProperty(SparkplugDataTransportOptions.KEY_KEEP_ALIVE, 60);\n            givenProperty(SparkplugDataTransportOptions.KEY_CONNECTION_TIMEOUT, 30);\n            this.cryptoServiceMock = mock(CryptoService.class);\n            doAnswer(invocation -> (char[]) invocation.getArgument(0)).when(cryptoServiceMock)\n                    .decryptAes(any(char[].class));\n        }\n\n        /*\n         * Given\n         */\n\n        void givenProperty(String key, Object value) {\n            this.properties.put(key, value);\n        }\n\n        void givenOptionsCreated() throws KuraException {\n            this.options = new SparkplugDataTransportOptions(this.properties, this.cryptoServiceMock);\n        }\n\n        /*\n         * When\n         */\n\n        void whenOptionsCreated() {\n            try {\n                givenOptionsCreated();\n            } catch (Exception e) {\n                this.occurredException = e;\n            }\n        }\n\n        void whenGetGroupId() {\n            this.returnedString = this.options.getGroupId();\n        }\n\n        void whenGetNodeId() {\n            this.returnedString = this.options.getNodeId();\n        }\n\n        void whenGetPrimaryHostApplicationId() {\n            this.returnedPrimaryHostApplicationId = this.options.getPrimaryHostApplicationId();\n        }\n\n        void whenGetServers() {\n            this.returnedServers = this.options.getServers();\n        }\n\n        void whenGetClientId() {\n            this.returnedString = this.options.getClientId();\n        }\n\n        void whenGetUsername() {\n            this.returnedString = this.options.getUsername();\n        }\n\n        void whenGetConnectionTimeoutMs() {\n            this.returnedLong = this.options.getConnectionTimeoutMs();\n        }\n\n        void whenGetMqttConnectOptions() {\n            this.mqttConnectOptions = this.options.getMqttConnectOptions();\n        }\n\n        /*\n         * Then\n         */\n\n        <E extends Exception> void thenExceptionOccurred(Class<E> expectedException) {\n            assertNotNull(this.occurredException);\n            assertEquals(expectedException.getName(), this.occurredException.getClass().getName());\n        }\n\n        void thenReturnedStringEquals(String expectedResult) {\n            assertEquals(expectedResult, this.returnedString);\n        }\n\n        void thenReturnedLongEquals(long expectedLong) {\n            assertEquals(expectedLong, this.returnedLong);\n        }\n\n        void thenReturnedServersContains(String[] expectedServers) {\n            for (String expectedServer : expectedServers) {\n                assertTrue(this.returnedServers.contains(expectedServer));\n            }\n        }\n\n        void thenRetunedPrimaryHostApplicationIdIsEmpty() {\n            assertFalse(this.returnedPrimaryHostApplicationId.isPresent());\n        }\n\n        void thenRetunedPrimaryHostApplicationIs(String expectedPrimaryHostApplicationId) {\n            assertTrue(this.returnedPrimaryHostApplicationId.isPresent());\n            assertEquals(expectedPrimaryHostApplicationId, this.returnedPrimaryHostApplicationId.get());\n        }\n\n        void thenMqttConnectOptionsContainsPassword(String expectedPassword) {\n            assertEquals(expectedPassword, new String(this.mqttConnectOptions.getPassword()));\n        }\n\n        void thenMqttConnectOptionsContainsKeepAlive(int expectedKeepAlive) {\n            assertEquals(expectedKeepAlive, this.mqttConnectOptions.getKeepAliveInterval());\n        }\n\n        void thenMqttConnectOptionsNotSetsUsername() {\n            assertNull(this.mqttConnectOptions.getUserName());\n        }\n\n        void thenMqttConnectOptionsNotSetsPassword() {\n            assertNull(this.mqttConnectOptions.getPassword());\n        }\n\n        void thenMqttConnectOptionsHasCleanSessionEnabled() {\n            assertTrue(this.mqttConnectOptions.isCleanSession());\n        }\n\n        void thenMqttConnectOptionsHasAutoReconnectDisabled() {\n            assertFalse(this.mqttConnectOptions.isAutomaticReconnect());\n        }\n\n        void thenMqttConnectOptionsContainsConnectionTimeout(int expectedConnectionTimeout) {\n            assertEquals(expectedConnectionTimeout, this.mqttConnectOptions.getConnectionTimeout());\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.configuration.change.manager.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.configuration.change.manager.test\nBundle-SymbolicName: org.eclipse.kura.configuration.change.manager.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.configuration.change.manager\nImport-Package: com.google.gson;version=\"2.7.0\",\n org.eclipse.kura;version=\"1.6.0\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection.publisher;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,1.3)\",\n org.eclipse.kura.core.testutil.service;version=\"1.0.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.7\",\n org.osgi.service.cm;version=\"1.4.0\",\n org.osgi.util.tracker;version=\"[1.5,2.0)\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.configuration.change.manager.test/build.properties",
    "content": "#\n#  Copyright (c) 2022 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api"
  },
  {
    "path": "kura/test/org.eclipse.kura.configuration.change.manager.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Eurotech\n     \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.configuration.change.manager.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.configuration.change.manager.test/src/test/java/org/eclipse/kura/configuration/change/manager/test/ComponentsServiceTrackerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.configuration.change.manager.test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.change.manager.ComponentsServiceTracker;\nimport org.eclipse.kura.configuration.change.manager.ServiceTrackerListener;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.cm.ConfigurationAdmin;\n\npublic class ComponentsServiceTrackerTest {\n\n    private ComponentsServiceTracker tracker;\n    private ServiceTrackerListener listener;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void addingServiceWithKuraPidShouldNotifyListener() throws InvalidSyntaxException {\n        givenComponentsServiceTracker();\n        givenServiceTrackerListener();\n\n        whenAddingServiceWithKuraPid(\"example1\");\n\n        thenListenerIsNotified(\"example1\");\n    }\n\n    @Test\n    public void addingServiceWithServiceFactoryPidShouldNotifyListener() throws InvalidSyntaxException {\n        givenComponentsServiceTracker();\n        givenServiceTrackerListener();\n\n        whenAddingServiceWithServiceFactoryPid(\"example1\");\n\n        thenListenerIsNotified(\"example1\");\n    }\n\n    @Test\n    public void addingServiceWithServicePidShouldNotifyListener() throws InvalidSyntaxException {\n        givenComponentsServiceTracker();\n        givenServiceTrackerListener();\n\n        whenAddingServiceWithServicePid(\"example1\");\n\n        thenListenerIsNotified(\"example1\");\n    }\n\n    @Test\n    public void addingServiceWithWithUnknownPropertyShouldNotNotifyListener() throws InvalidSyntaxException {\n        givenComponentsServiceTracker();\n        givenServiceTrackerListener();\n\n        whenAddingServiceWithUnknownProperty();\n\n        thenListenerIsNotNotified();\n    }\n\n    @Test\n    public void modifiedServiceShouldNotifyListener() throws InvalidSyntaxException {\n        givenComponentsServiceTracker();\n        givenServiceTrackerListener();\n\n        whenModifiedService(\"modified-pid\");\n\n        thenListenerIsNotified(\"modified-pid\");\n    }\n\n    @Test\n    public void removedServiceShouldNotifyListener() throws InvalidSyntaxException {\n        givenComponentsServiceTracker();\n        givenServiceTrackerListener();\n\n        whenRemovedService(\"removed-pid\");\n\n        thenListenerIsNotified(\"removed-pid\");\n    }\n\n    @Test\n    public void notRegisteredListenerShouldNotBeNotified() throws InvalidSyntaxException {\n        givenComponentsServiceTracker();\n        givenServiceTrackerListener();\n        givenRemoveServiceTrackerListener();\n\n        whenRemovedService(\"removed-pid2\");\n\n        thenListenerIsNotNotified();\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenComponentsServiceTracker() throws InvalidSyntaxException {\n        BundleContext mockContext = mock(BundleContext.class);\n        Filter mockFilter = mock(Filter.class);\n\n        when(mockContext.createFilter(Mockito.anyString())).thenReturn(mockFilter);\n        when(mockContext.getService(Mockito.any())).thenReturn(new Object());\n        when(mockContext.ungetService(Mockito.any())).thenReturn(true);\n        this.tracker = new ComponentsServiceTracker(mockContext);\n    }\n\n    private void givenServiceTrackerListener() {\n        this.listener = mock(ServiceTrackerListener.class);\n        this.tracker.addServiceTrackerListener(this.listener);\n    }\n\n    private void givenRemoveServiceTrackerListener() {\n        this.tracker.removeServiceTrackerListener(this.listener);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenAddingServiceWithKuraPid(String kuraPid) {\n        @SuppressWarnings(\"unchecked\")\n        ServiceReference<Object> ref = (ServiceReference<Object>) mock(ServiceReference.class);\n        when(ref.getProperty(ConfigurationService.KURA_SERVICE_PID)).thenReturn(kuraPid);\n\n        callAddingService(ref);\n    }\n\n    private void whenAddingServiceWithServiceFactoryPid(String serviceFactoryPid) {\n        @SuppressWarnings(\"unchecked\")\n        ServiceReference<Object> ref = (ServiceReference<Object>) mock(ServiceReference.class);\n        when(ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID)).thenReturn(serviceFactoryPid);\n        \n        callAddingService(ref);\n    }\n\n    private void whenAddingServiceWithServicePid(String servicePid) {\n        @SuppressWarnings(\"unchecked\")\n        ServiceReference<Object> ref = (ServiceReference<Object>) mock(ServiceReference.class);\n        when(ref.getProperty(Constants.SERVICE_PID)).thenReturn(servicePid);\n\n        callAddingService(ref);\n    }\n\n    private void whenAddingServiceWithUnknownProperty() {\n        @SuppressWarnings(\"unchecked\")\n        ServiceReference<Object> ref = (ServiceReference<Object>) mock(ServiceReference.class);\n        when(ref.getProperty(\"unknwonKey\")).thenReturn(\"unknownValue\");\n\n        callAddingService(ref);\n    }\n\n    private void whenModifiedService(String kuraPid) {\n        @SuppressWarnings(\"unchecked\")\n        ServiceReference<Object> ref = (ServiceReference<Object>) mock(ServiceReference.class);\n        when(ref.getProperty(ConfigurationService.KURA_SERVICE_PID)).thenReturn(kuraPid);\n\n        this.tracker.modifiedService(ref, new Object());\n    }\n\n    private void whenRemovedService(String kuraPid) {\n        @SuppressWarnings(\"unchecked\")\n        ServiceReference<Object> ref = (ServiceReference<Object>) mock(ServiceReference.class);\n        when(ref.getProperty(ConfigurationService.KURA_SERVICE_PID)).thenReturn(kuraPid);\n\n        this.tracker.removedService(ref, new Object());\n    }\n\n    private void callAddingService(ServiceReference<Object> reference) {\n        this.tracker.addingService(reference);\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenListenerIsNotified(String changedPid) {\n        verify(this.listener, times(1)).onConfigurationChanged(changedPid);\n    }\n\n    private void thenListenerIsNotNotified() {\n        verify(this.listener, times(0)).onConfigurationChanged(Mockito.any());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.configuration.change.manager.test/src/test/java/org/eclipse/kura/configuration/change/manager/test/ConfigurationChangeManagerOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.configuration.change.manager.test;\n\nimport static org.eclipse.kura.configuration.change.manager.ConfigurationChangeManagerOptions.DEFAULT_ENABLED;\nimport static org.eclipse.kura.configuration.change.manager.ConfigurationChangeManagerOptions.DEFAULT_SEND_DELAY;\nimport static org.eclipse.kura.configuration.change.manager.ConfigurationChangeManagerOptions.KEY_ENABLED;\nimport static org.eclipse.kura.configuration.change.manager.ConfigurationChangeManagerOptions.KEY_SEND_DELAY;\nimport static org.junit.Assert.assertEquals;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.change.manager.ConfigurationChangeManagerOptions;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class ConfigurationChangeManagerOptionsTest {\n\n    private Map<String, Object> properties;\n    private ConfigurationChangeManagerOptions options;\n    private Object returnValue;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldReturnEnabled() {\n        givenProperty(KEY_ENABLED, true);\n        givenOptionsInstatiated();\n\n        whenIsEnabled();\n\n        thenReturnValueIs(true);\n    }\n\n    @Test\n    public void shouldReturnDisabled() {\n        givenProperty(KEY_ENABLED, false);\n        givenOptionsInstatiated();\n\n        whenIsEnabled();\n\n        thenReturnValueIs(false);\n    }\n\n    @Test\n    public void shouldReturnDefaultEnabledValue() {\n        givenOptionsInstatiated();\n\n        whenIsEnabled();\n\n        thenReturnValueIs(DEFAULT_ENABLED);\n    }\n\n    @Test\n    public void shouldReturnCorrectSendDelay() {\n        givenProperty(KEY_SEND_DELAY, 1000L);\n        givenOptionsInstatiated();\n\n        whenGetSendDelay();\n\n        thenReturnValueIs(1000L);\n    }\n\n    @Test\n    public void shouldReturnDefaultSendDelay() {\n        givenOptionsInstatiated();\n\n        whenGetSendDelay();\n\n        thenReturnValueIs(DEFAULT_SEND_DELAY);\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenProperty(String key, Object value) {\n        this.properties.put(key, value);\n    }\n\n    private void givenOptionsInstatiated() {\n        this.options = new ConfigurationChangeManagerOptions(this.properties);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenIsEnabled() {\n        this.returnValue = this.options.isEnabled();\n    }\n\n    private void whenGetSendDelay() {\n        this.returnValue = this.options.getSendDelay();\n    }\n\n    /*\n     * Then\n     */\n\n    @SuppressWarnings(\"unchecked\")\n    private <T> void thenReturnValueIs(T expectedValue) {\n        assertEquals(expectedValue, (T) this.returnValue);\n    }\n\n\n    /*\n     * Utility\n     */\n\n    @Before\n    public void cleanUp() {\n        this.properties = new HashMap<>();\n        this.options = null;\n        this.returnValue = null;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.configuration.change.manager.test/src/test/java/org/eclipse/kura/configuration/change/manager/test/ConfigurationChangeManagerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.configuration.change.manager.test;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager;\nimport org.eclipse.kura.configuration.change.manager.ConfigurationChangeManagerOptions;\nimport org.eclipse.kura.configuration.change.manager.test.mocks.MockCloudPublisher;\nimport org.eclipse.kura.configuration.change.manager.test.mocks.MockServiceTracker;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.osgi.framework.InvalidSyntaxException;\n\npublic class ConfigurationChangeManagerTest {\n\n    private MockCloudPublisher mockPublisher = new MockCloudPublisher();\n    private MockServiceTracker mockServiceTracker = new MockServiceTracker();\n    private ConfigurationChangeManager configurationChangeManager = new ConfigurationChangeManager();\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldNotPublishWhenDisabled() throws InterruptedException, ExecutionException {\n        givenConfigurationChangeManager(false, 0L);\n\n        whenConfigurationChanges(\"test.pid\");\n\n        thenNoMessagesPublished(0L);\n    }\n\n    @Test\n    public void shouldPublishOneMessage() throws InterruptedException, ExecutionException, TimeoutException {\n        givenConfigurationChangeManager(true, 2L);\n\n        whenConfigurationChanges(\"test1\", \"test2\");\n\n        thenMessagePublished(2L, \"test1\", \"test2\");\n    }\n\n    @Test\n    public void shouldAccumulateAndPublishOneMessages() throws InterruptedException, ExecutionException {\n        givenConfigurationChangeManager(true, 10L);\n\n        whenConfigurationChanges(\"pid1\", \"pid2\", \"pid3\", \"pid4\", \"pid5\", \"pid5\");\n\n        thenMessagePublished(10L, \"pid1\", \"pid2\", \"pid3\", \"pid4\", \"pid5\");\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenConfigurationChangeManager(boolean enabled, long sendDelaySec) {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(ConfigurationChangeManagerOptions.KEY_ENABLED, enabled);\n        properties.put(ConfigurationChangeManagerOptions.KEY_SEND_DELAY, sendDelaySec);\n\n        try {\n            this.configurationChangeManager.updated(properties);\n        } catch (NullPointerException npe) {\n            // expected NPE since the service tracker cannot be instatiated (BundleContext not available)\n        }\n    }\n\n    /*\n     * When\n     */\n\n    private void whenConfigurationChanges(String... changedPids) {\n        for (String pid : changedPids) {\n            this.mockServiceTracker.simulateConfigChange(pid);\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenNoMessagesPublished(long sendDelaySec)\n            throws InterruptedException, ExecutionException {\n        CountDownLatch waitForSendDelay = new CountDownLatch(1);\n        this.mockPublisher.addPublishCountLatch(waitForSendDelay);\n        assertFalse(waitForSendDelay.await(sendDelaySec + 5, TimeUnit.SECONDS));\n    }\n\n    private void thenMessagePublished(long sendDelaySec, String... changedPids)\n            throws InterruptedException, ExecutionException {\n        CountDownLatch waitForSendDelay = new CountDownLatch(1);\n        this.mockPublisher.addPublishCountLatch(waitForSendDelay);\n        waitForSendDelay.await(sendDelaySec + 5, TimeUnit.SECONDS);\n\n        for (String pid : changedPids) {\n            assertTrue(\"Not all pids have been published.\", this.mockPublisher.isPidPublished(pid));\n        }\n    }\n\n    /*\n     * Utilities\n     */\n\n    @Before\n    public void cleanup() throws InvalidSyntaxException {\n        this.configurationChangeManager.setCloudPublisher(this.mockPublisher);\n        this.mockServiceTracker.setServiceTrackerListener(this.configurationChangeManager);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.configuration.change.manager.test/src/test/java/org/eclipse/kura/configuration/change/manager/test/mocks/MockCloudPublisher.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.configuration.change.manager.test.mocks;\n\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.listener.CloudConnectionListener;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\n\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonElement;\nimport com.google.gson.JsonParser;\n\npublic class MockCloudPublisher implements CloudPublisher {\n\n    private List<CountDownLatch> publishLatches = new LinkedList<>();\n    private List<String> publishedPids = new LinkedList<>();\n\n    public void addPublishCountLatch(CountDownLatch publishLatch) {\n        this.publishLatches.add(publishLatch);\n    }\n\n    @Override\n    public String publish(KuraMessage message) throws KuraException {\n        JsonArray array = JsonParser.parseString(new String(message.getPayload().getBody())).getAsJsonArray();\n        for (JsonElement element : array) {\n            this.publishedPids.add(element.getAsJsonObject().get(\"pid\").getAsString());\n        }\n\n        this.publishLatches.remove(0).countDown();\n        return null;\n    }\n\n    @Override\n    public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        // nothing to do\n\n    }\n\n    @Override\n    public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) {\n        // nothing to do\n\n    }\n\n    @Override\n    public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        // nothing to do\n\n    }\n\n    @Override\n    public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) {\n        // nothing to do\n    }\n    \n    public synchronized boolean isPidPublished(String pid) {\n        return this.publishedPids.remove(pid);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.configuration.change.manager.test/src/test/java/org/eclipse/kura/configuration/change/manager/test/mocks/MockServiceTracker.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.configuration.change.manager.test.mocks;\n\nimport org.eclipse.kura.configuration.change.manager.ServiceTrackerListener;\n\npublic class MockServiceTracker {\n\n    ServiceTrackerListener listener;\n\n    public void setServiceTrackerListener(ServiceTrackerListener listener) {\n        this.listener = listener;\n    }\n\n    public void simulateConfigChange(String changedPid) {\n        listener.onConfigurationChanged(changedPid);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/.gitignore",
    "content": "/target/\nlib/*\n/lib/\n\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.container.orchestration.provider.test\nBundle-SymbolicName: org.eclipse.kura.container.orchestration.provider.test\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nFragment-Host: org.eclipse.kura.container.orchestration.provider\nAutomatic-Module-Name: org.eclipse.kura.container.orchestration.provider.test\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.eclipse.kura;version=\"1.6.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.container.orchestration.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n    <version>2.0.0-SNAPSHOT</version>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.build.directory}/site/jacoco-aggregate/jacoco.xml\n        </sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/src/test/java/org/eclipse/kura/container/orchestration/provider/ContainerConfigurationTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration.ContainerConfigurationBuilder;\nimport org.eclipse.kura.container.orchestration.ContainerNetworkConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerPort;\nimport org.eclipse.kura.container.orchestration.ImageConfiguration;\nimport org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;\nimport org.junit.Test;\n\npublic class ContainerConfigurationTest {\n\n    private static final List<String> CONTAINER_ENV_VARS = Arrays.asList(\"test=test\");\n    private static final String CONTAINER_IMAGE_TAG = \"tag1\";\n    private static final String CONTAINER_IMAGE = \"image1\";\n    private static final String CONTAINER_NAME = \"cont1\";\n    private static final String REGISTRY_URL = \"https://test\";\n    private static final String REGISTRY_USERNAME = \"test\";\n    private static final String REGISTRY_PASSWORD = \"test1\";\n    private static final List<ContainerPort> CONTAINER_PORTS = new ArrayList<>(\n            Arrays.asList(new ContainerPort(1521, 1521), new ContainerPort(81, 81)));\n    private static final Map<String, String> CONTAINER_VOLUMES = Collections.singletonMap(\"key1\", \"val1\");\n    private static final Map<String, String> CONTAINER_LOGGER_PARAMETERS = Collections.singletonMap(\"key2\", \"val2\");\n    private static final String CONTAINER_LOGGER_TYPE = \"test2\";\n    private static final List<String> CONTAINER_DEVICE_LIST = Arrays.asList(\"/dev/gpio1\", \"/dev/gpio2\");\n    private static final Long MEMORY = 1000L;\n    private static final Float CPUS = 1.3F;\n    private static final String GPUS = \"all\";\n    private static final String RUNTIME = \"coolRuntime\";\n    private ContainerConfiguration firstContainerConfig;\n    private ContainerConfiguration secondContainerConfig;\n    private ContainerConfigurationBuilder containerConfigurationBuilder;\n    private ImageConfiguration firstImageConfig;\n    private ImageConfiguration seccondImageConfig;\n    private boolean comparisonResult;\n    private int hashResult;\n\n    @Test(expected = NullPointerException.class)\n    public void testRequiredContainerName() {\n        givenContainerNoParams();\n    }\n\n    @Test(expected = NullPointerException.class)\n    public void testRequiredContainerImage() {\n        givenContainerNoImage();\n    }\n\n    @Test(expected = NullPointerException.class)\n    public void testRequiredContainerCredentials() {\n        givenContainerNoCredentials();\n    }\n\n    @Test\n    public void testSupportOfParameters() {\n        givenContainerBuilder();\n\n        whenContainerConfigurationBuilt();\n\n        thenContainerPropertiesMatchExpected();\n    }\n\n    @Test\n    public void testContainerDoesntEquals() {\n        givenContainerOne();\n        givenContainerTwoDifferent();\n\n        whenContainersCompared();\n\n        thenFirstContainerDoesntEqualSecond();\n    }\n\n    @Test\n    public void testContainerHashCode() {\n        givenContainerOne();\n        givenContainerTwoDifferent();\n\n        whenContainerTwoHash();\n\n        thenHashNoMatch();\n    }\n\n    /**\n     * End Of Tests\n     */\n\n    // given\n    private void givenContainerNoParams() {\n\n        this.firstContainerConfig = ContainerConfiguration.builder().build();\n    }\n\n    private void givenContainerNoImage() {\n\n        this.firstContainerConfig = ContainerConfiguration.builder().setContainerName(CONTAINER_NAME).build();\n    }\n\n    private void givenContainerNoCredentials() {\n        this.firstImageConfig = new ImageConfiguration.ImageConfigurationBuilder().setImageName(CONTAINER_IMAGE)\n                .setImageTag(CONTAINER_IMAGE_TAG).setImageDownloadTimeoutSeconds(0).build();\n\n        this.firstContainerConfig = ContainerConfiguration.builder().setContainerName(CONTAINER_NAME)\n                .setImageConfiguration(firstImageConfig).build();\n    }\n\n    private void givenContainerBuilder() {\n        this.firstImageConfig = new ImageConfiguration.ImageConfigurationBuilder().setImageName(CONTAINER_IMAGE)\n                .setImageTag(CONTAINER_IMAGE_TAG)\n                .setRegistryCredentials(Optional.of(new PasswordRegistryCredentials(Optional.of(REGISTRY_URL),\n                        REGISTRY_USERNAME, new Password(REGISTRY_PASSWORD))))\n                .setImageDownloadTimeoutSeconds(0).build();\n\n        this.containerConfigurationBuilder = ContainerConfiguration.builder().setContainerName(CONTAINER_NAME)\n                .setImageConfiguration(firstImageConfig).setContainerPorts(CONTAINER_PORTS)\n                .setEnvVars(CONTAINER_ENV_VARS).setDeviceList(CONTAINER_DEVICE_LIST).setVolumes(CONTAINER_VOLUMES)\n                .setPrivilegedMode(false).setFrameworkManaged(false).setLoggerParameters(CONTAINER_LOGGER_PARAMETERS)\n                .setLoggingType(CONTAINER_LOGGER_TYPE)\n                .setContainerNetowrkConfiguration(\n                        new ContainerNetworkConfiguration.ContainerNetworkConfigurationBuilder()\n                                .setNetworkMode(Optional.of(\"bridge\")).build())\n                .setMemory(Optional.of(MEMORY)).setCpus(Optional.of(CPUS)).setGpus(Optional.of(GPUS))\n                .setRuntime(Optional.of(RUNTIME));\n    }\n\n    private void givenContainerOne() {\n        givenContainerBuilder();\n        whenContainerConfigurationBuilt();\n    }\n\n    private void givenContainerTwoDifferent() {\n\n        givenContainerBuilder();\n        this.seccondImageConfig = new ImageConfiguration.ImageConfigurationBuilder().setImageName(\"different\")\n                .setImageTag(\"different\")\n                .setRegistryCredentials(Optional.of(new PasswordRegistryCredentials(Optional.of(\"different\"),\n                        REGISTRY_USERNAME, new Password(\"different\"))))\n                .setImageDownloadTimeoutSeconds(0).build();\n        this.secondContainerConfig = this.containerConfigurationBuilder.setImageConfiguration(seccondImageConfig)\n                .build();\n    }\n\n    private void whenContainerConfigurationBuilt() {\n        this.firstContainerConfig = this.containerConfigurationBuilder.build();\n    }\n\n    private void whenContainersCompared() {\n        this.comparisonResult = this.firstContainerConfig.equals(this.secondContainerConfig);\n    }\n\n    private void whenContainerTwoHash() {\n        this.hashResult = this.secondContainerConfig.hashCode();\n    }\n\n    // then\n    private void thenContainerPropertiesMatchExpected() {\n        assertEquals(CONTAINER_NAME, this.firstContainerConfig.getContainerName());\n        assertEquals(CONTAINER_IMAGE, this.firstContainerConfig.getImageConfiguration().getImageName());\n        assertEquals(CONTAINER_IMAGE_TAG, this.firstContainerConfig.getImageConfiguration().getImageTag());\n\n        assertEquals(CONTAINER_PORTS, this.firstContainerConfig.getContainerPorts());\n        assertEquals(CONTAINER_VOLUMES, this.firstContainerConfig.getContainerVolumes());\n        assertEquals(CONTAINER_LOGGER_PARAMETERS, this.firstContainerConfig.getLoggerParameters());\n        assertEquals(CONTAINER_LOGGER_TYPE, this.firstContainerConfig.getContainerLoggingType());\n        assertEquals(CONTAINER_ENV_VARS, this.firstContainerConfig.getContainerEnvVars());\n        assertEquals(CONTAINER_DEVICE_LIST, this.firstContainerConfig.getContainerDevices());\n\n        PasswordRegistryCredentials prc = (PasswordRegistryCredentials) this.firstContainerConfig\n                .getImageConfiguration().getRegistryCredentials().get();\n        assertEquals(REGISTRY_URL, prc.getUrl().get());\n        assertEquals(REGISTRY_USERNAME, prc.getUsername());\n        assertEquals(REGISTRY_PASSWORD, new String(prc.getPassword().getPassword()));\n\n        assertFalse(this.firstContainerConfig.isContainerPrivileged());\n        assertFalse(this.firstContainerConfig.isFrameworkManaged());\n        assertEquals(0, this.firstContainerConfig.getImageConfiguration().getimageDownloadTimeoutSeconds());\n        assertEquals(Optional.of(MEMORY), this.firstContainerConfig.getMemory());\n        assertEquals(Optional.of(CPUS), this.firstContainerConfig.getCpus());\n        assertEquals(Optional.of(GPUS), this.firstContainerConfig.getGpus());\n    }\n\n    private void thenFirstContainerDoesntEqualSecond() {\n        assertFalse(this.comparisonResult);\n    }\n\n    private void thenHashNoMatch() {\n        assertNotEquals(this.firstContainerConfig.hashCode(), this.hashResult);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/src/test/java/org/eclipse/kura/container/orchestration/provider/ContainerInstanceDescriptorTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.apache.commons.lang3.ArrayUtils;\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ContainerPort;\nimport org.junit.Test;\n\npublic class ContainerInstanceDescriptorTest {\n\n    private static final String H2_DB_NAME = \"Kura_H2DB\";\n    private static final String H2_DB_IMAGE = \"joedoe/h2db\";\n    private static final List<ContainerPort> H2_DB_PORTS = new ArrayList<>(\n            Arrays.asList(new ContainerPort(1521, 1521), new ContainerPort(81, 81)));\n    private ContainerInstanceDescriptor firstContainerConfig;\n    private ContainerInstanceDescriptor seccondContainerConfig;\n\n    @Test\n    public void testSupportOfBasicParameters() {\n        givenContainerOne();\n\n        thenCompareContainerOneToExpectedOutput();\n    }\n\n    @Test\n    public void testContainerDoesntEquals() {\n        givenContainerOne();\n        givenContainerTwoDiffrent();\n\n        thenFirstContainerDoesntEqualSeccond();\n    }\n\n    /**\n     * End Of Tests\n     */\n\n    // given\n    private void givenContainerOne() {\n\n        this.firstContainerConfig = ContainerInstanceDescriptor.builder().setContainerImageTag(H2_DB_NAME)\n                .setContainerName(H2_DB_NAME).setContainerImage(H2_DB_IMAGE).setContainerPorts(H2_DB_PORTS).build();\n    }\n\n    private void givenContainerTwoDiffrent() {\n\n        this.seccondContainerConfig = ContainerInstanceDescriptor.builder().setContainerImageTag(H2_DB_NAME)\n                .setContainerName(H2_DB_NAME).setContainerImage(H2_DB_IMAGE).setContainerImageTag(\"diffrent\")\n                .setContainerPorts(H2_DB_PORTS).build();\n    }\n\n    // then\n    private void thenCompareContainerOneToExpectedOutput() {\n        assertEquals(H2_DB_NAME, this.firstContainerConfig.getContainerName());\n        assertEquals(H2_DB_IMAGE, this.firstContainerConfig.getContainerImage());\n        assertTrue(ArrayUtils.isEquals(H2_DB_PORTS, this.firstContainerConfig.getContainerPorts()));\n    }\n\n    private void thenFirstContainerDoesntEqualSeccond() {\n        assertFalse(firstContainerConfig.equals(this.seccondContainerConfig));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/src/test/java/org/eclipse/kura/container/orchestration/provider/ContainerOrchestrationServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.container.orchestration.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyList;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ImageConfiguration;\nimport org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;\nimport org.eclipse.kura.container.orchestration.PortInternetProtocol;\nimport org.eclipse.kura.container.orchestration.provider.impl.ContainerOrchestrationServiceImpl;\nimport org.junit.Test;\nimport org.mockito.Answers;\nimport org.mockito.Mock;\nimport org.mockito.Mockito;\n\nimport com.github.dockerjava.api.DockerClient;\nimport com.github.dockerjava.api.command.CreateContainerCmd;\nimport com.github.dockerjava.api.command.CreateContainerResponse;\nimport com.github.dockerjava.api.command.ListContainersCmd;\nimport com.github.dockerjava.api.command.ListImagesCmd;\nimport com.github.dockerjava.api.model.Container;\nimport com.github.dockerjava.api.model.ContainerPort;\nimport com.github.dockerjava.api.model.Image;\n\npublic class ContainerOrchestrationServiceImplTest {\n\n    private static final String CONTAINER_INSTANCE_DIGEST = \"sha256:test\";\n    private static final String[] REPO_DIGESTS_ARRAY = new String[] {\n            \"ubuntu@sha256:c26ae7472d624ba1fafd296e73cecc4f93f853088e6a9c13c0d52f6ca5865107\" };\n    private static final String[] EXPECTED_DIGESTS_ARRAY = new String[] {\n            \"sha256:c26ae7472d624ba1fafd296e73cecc4f93f853088e6a9c13c0d52f6ca5865107\" };\n    private static final String IMAGE_TAG_LATEST = \"latest\";\n    private static final String IMAGE_NAME_NGINX = \"nginx\";\n    private static final String CONTAINER_NAME_FRANK = \"frank\";\n    private static final String CONTAINER_ID_2 = \"1f134f3s4\";\n    private static final String CONTAINER_ID_1 = \"1f12d3s23\";\n\n    private static final String DOCKER_HOST_URL = \"dockerService.dockerHost\";\n    private static final String IS_ENABLED = \"dockerService.enabled\";\n    private static final String DEFAULT_DOCKER_HOST_URL = \"unix:///var/run/docker.sock\";\n    private static final boolean DEFAULT_IS_ENABLED = false;\n\n    private static final String REPOSITORY_ENABLED = \"repository.enabled\";\n    private static final String REPOSITORY_URL = \"repository.hostname\";\n    private static final String REPOSITORY_USERNAME = \"repository.username\";\n    private static final String REPOSITORY_PASSWORD = \"repository.password\";\n\n    private static final String ENFORCEMENT_ENABLED = \"enforcement.enabled\";\n\n    private static final String REGISTRY_URL = \"https://test\";\n    private static final String REGISTRY_USERNAME = \"test\";\n    private static final String REGISTRY_PASSWORD = \"test1\";\n\n    private static final String IMAGES_DOWNLOAD_TIMEOUT = \"dockerService.default.download.timeout\";\n    private static final int DEFAULT_IMAGES_DOWNLOAD_TIMEOUT = 120;\n\n    private static final boolean DEFAULT_REPOSITORY_ENABLED = false;\n    private static final String DEFAULT_REPOSITORY_URL = \"\";\n    private static final String DEFAULT_REPOSITORY_USERNAME = \"\";\n    private static final String DEFAULT_REPOSITORY_PASSWORD = \"\";\n\n    private static final ContainerPort TCP_CONTAINER_PORT = new ContainerPort().withIp(\"0.0.0.0\").withPrivatePort(100)\n            .withPublicPort(101).withType(\"tcp\");\n    private static final ContainerPort UDP_CONTAINER_PORT = new ContainerPort().withIp(\"0.0.0.0\").withPrivatePort(200)\n            .withPublicPort(201).withType(\"udp\");\n    private static final ContainerPort SCTP_CONTAINER_PORT = new ContainerPort().withIp(\"0.0.0.0\").withPrivatePort(300)\n            .withPublicPort(301).withType(\"sctp\");\n\n    private ContainerOrchestrationServiceImpl dockerService;\n\n    @Mock(answer = Answers.RETURNS_DEEP_STUBS)\n    private DockerClient localDockerClient;\n    @Mock(answer = Answers.RETURNS_DEEP_STUBS)\n    private ListContainersCmd mockedListContainersCmd;\n\n    // for tests\n    private String[] runningContainers;\n    private ContainerInstanceDescriptor[] runningContainerDescriptor;\n\n    private ContainerConfiguration containerConfig1;\n    private ImageConfiguration imageConfig;\n\n    private Map<String, Object> properties;\n    private String containerId;\n\n    CreateContainerCmd createContainerCmd = mock(CreateContainerCmd.class);\n    CreateContainerResponse createContainerResponse = mock(CreateContainerResponse.class);\n\n    Set<String> digestsList;\n\n    @Test\n    public void testServiceActivateEmptyProperties() {\n        // Should use default properties\n        givenEmptyProperties();\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenActivateInstance();\n\n        thenNotStartedMicroservice();\n        thenNotStoppedMicroservice();\n    }\n\n    @Test\n    public void testServiceActivateDefaultPropertiesDisabled() {\n        givenFullProperties(DEFAULT_IS_ENABLED);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenActivateInstance();\n\n        thenNotStartedMicroservice();\n        thenNotStoppedMicroservice();\n    }\n\n    @Test\n    public void testServiceActivateDefaultPropertiesEnabledAndAuth() {\n        givenFullProperties(true, true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenActivateInstance();\n\n        thenNotStartedMicroservice();\n        thenNotStoppedMicroservice();\n    }\n\n    @Test\n    public void testServiceActivateDefaultPropertiesEnabledWithAuthAndNoRepo() {\n        givenAuthWithRepoAndCredentials();\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenActivateInstance();\n\n        thenNotStartedMicroservice();\n        thenNotStoppedMicroservice();\n    }\n\n    @Test\n    public void testServiceUpdateDefaultPropertiesEnabled() {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenUpdateInstance();\n\n        thenNotStartedMicroservice();\n        thenNotStoppedMicroservice();\n    }\n\n    @Test\n    public void testServiceDeactivateDefaultPropertiesEnabled() {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDeactivateInstance();\n\n        thenNotStartedMicroservice();\n        thenNotStoppedMicroservice();\n    }\n\n    @Test\n    public void testServiceListContainerWhenEmpty() {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDockerClientMockHasNoContainers();\n\n        thenContainerListEqualsExpectedStringArray();\n    }\n\n    @Test\n    public void testServiceListContainerWithSomeContainer() {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDockerClientMockSomeContainers();\n\n        thenContainerListEqualsExpectedStringArray();\n    }\n\n    @Test\n    public void testServiceListContainerByIdWhenEmpty() {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDockerClientMockHasNoContainers();\n\n        thenContainerListByIdEqualsExpectedStringArray();\n    }\n\n    @Test\n    public void testServiceListContainerByIdWithSomeContainer() {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDockerClientMockSomeContainers();\n\n        thenContainerListByIdEqualsExpectedStringArray();\n    }\n\n    @Test\n    public void testServiceListContainerByContainerDescriptorWhenEmpty() {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDockerClientMockHasNoContainers();\n\n        thenContainerListByContainerDescriptorEqualsExpectedStringArray();\n    }\n\n    @Test\n    public void testServiceListContainerByContainerDescriptorWithSomeContainer() {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDockerClientMockSomeContainers();\n\n        thenContainerListByContainerDescriptorEqualsExpectedStringArray();\n    }\n\n    @Test\n    public void testServiceListContainerByContainerDescriptorWithContainerWithPorts() throws KuraException {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDockerClientMockContainerWithPorts();\n\n        thenContainerPortsInfosArePresent();\n    }\n\n    @Test\n    public void testGetContainerIDbyName() throws KuraException {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDockerClientMockSomeContainers();\n\n        thenGetFirstContainerIDbyName();\n    }\n\n    @Test\n    public void testCreateContainer() throws KuraException, InterruptedException {\n        givenFullProperties(true);\n        givenDockerServiceImpl();\n        givenDockerClient();\n\n        whenDockerClientMockSomeContainers();\n        whenMockforContainerCreation();\n        whenRunContainer();\n\n        thenTestIfNewContainerExists();\n    }\n\n    @Test\n    public void testStopContainer() throws KuraException, InterruptedException {\n        givenFullProperties(true);\n        givenDockerServiceImplSpy();\n        givenDockerClient();\n\n        whenDockerClientMockSomeContainers();\n        whenMockforContainerCreation();\n        whenRunContainer();\n        whenStopContainer();\n\n        thenTestIfNewContainerDoesNotExists();\n    }\n\n    @Test\n    public void testDeleteImage() throws KuraException, InterruptedException {\n        givenFullProperties(true);\n        givenDockerServiceImplSpy();\n        givenDockerClient();\n\n        whenImageIsDeletedById(\"y456y5146hrth\");\n\n        thenCheckIfImageWasDeleted();\n    }\n\n    @Test\n    public void testListImage() throws KuraException, InterruptedException {\n        givenFullProperties(true);\n        givenDockerServiceImplSpy();\n        givenDockerClient();\n\n        whenMockForImageListing();\n\n        whenImagesAreListed();\n\n        thenCheckIfImagesWereListed();\n    }\n\n    @Test\n    public void testImageDigestsByContainerName() throws KuraException, InterruptedException {\n        givenFullProperties(true);\n        givenDockerServiceImplSpy();\n        givenDockerClient();\n\n        whenMockForImageDigestsListing();\n        whenDockerClientMockSomeContainers();\n        whenGetImageDigestsByContainerId(CONTAINER_ID_1);\n\n        thenDigestsListEqualsExpectedOne(EXPECTED_DIGESTS_ARRAY);\n    }\n\n    @Test\n    public void testContainerInstanceDigestIsAddedToAllowlist() throws KuraException, InterruptedException {\n\n        givenFullProperties(true);\n        givenEnforcementEnabledProperty(true);\n        givenDockerServiceImplSpy();\n        givenDockerClient();\n\n        whenActivateInstance();\n        whenDockerClientMockCreateContainer();\n        whenMockForContainerInstancesDigestAdding();\n        whenRunContainer();\n\n        thenContainerInstanceDigestIsAddedToAllowlist();\n        thenContainerInstanceDigestIsExpectedOne(CONTAINER_INSTANCE_DIGEST);\n    }\n\n    @Test\n    public void testContainerInstanceDigestIsAddedToAndRemovedFromAllowlist()\n            throws KuraException, InterruptedException {\n\n        givenFullProperties(true);\n        givenEnforcementEnabledProperty(true);\n        givenDockerServiceImplSpy();\n        givenDockerClient();\n\n        whenActivateInstance();\n        whenDockerClientMockCreateContainer();\n        whenMockForContainerInstancesDigestAdding();\n        whenRunContainer();\n        whenStopContainer();\n        whenDeleteContainer();\n\n        thenContainerInstanceDigestIsNotInAllowlist();\n    }\n\n    /**\n     * givens\n     */\n\n    private void givenDockerServiceImpl() {\n        this.dockerService = new ContainerOrchestrationServiceImpl();\n    }\n\n    private void givenDockerServiceImplSpy() throws KuraException, InterruptedException {\n        this.dockerService = Mockito.spy(new ContainerOrchestrationServiceImpl());\n        Mockito.doNothing().when(this.dockerService).pullImage(any(ImageConfiguration.class));\n    }\n\n    private void givenDockerClient() {\n        this.localDockerClient = mock(DockerClient.class, Mockito.RETURNS_DEEP_STUBS);\n        this.dockerService.setDockerClient(this.localDockerClient);\n    }\n\n    private void givenEmptyProperties() {\n        this.properties = new HashMap<>();\n    }\n\n    private void givenFullProperties(boolean b) {\n        this.properties = new HashMap<>();\n\n        this.properties.put(DOCKER_HOST_URL, DEFAULT_DOCKER_HOST_URL);\n        this.properties.put(IS_ENABLED, b);\n\n        this.properties.put(REPOSITORY_ENABLED, DEFAULT_REPOSITORY_ENABLED);\n        this.properties.put(REPOSITORY_URL, DEFAULT_REPOSITORY_URL);\n        this.properties.put(REPOSITORY_USERNAME, DEFAULT_REPOSITORY_USERNAME);\n        this.properties.put(REPOSITORY_PASSWORD, DEFAULT_REPOSITORY_PASSWORD);\n        this.properties.put(IMAGES_DOWNLOAD_TIMEOUT, DEFAULT_IMAGES_DOWNLOAD_TIMEOUT);\n    }\n\n    private void givenFullProperties(boolean b, boolean customRepoEnabled) {\n        this.properties = new HashMap<>();\n\n        this.properties.put(DOCKER_HOST_URL, DEFAULT_DOCKER_HOST_URL);\n        this.properties.put(IS_ENABLED, b);\n\n        this.properties.put(REPOSITORY_ENABLED, customRepoEnabled);\n        this.properties.put(REPOSITORY_URL, DEFAULT_REPOSITORY_URL);\n        this.properties.put(REPOSITORY_USERNAME, DEFAULT_REPOSITORY_USERNAME);\n        this.properties.put(REPOSITORY_PASSWORD, DEFAULT_REPOSITORY_PASSWORD);\n        this.properties.put(IMAGES_DOWNLOAD_TIMEOUT, DEFAULT_IMAGES_DOWNLOAD_TIMEOUT);\n    }\n\n    private void givenAuthWithRepoAndCredentials() {\n        this.properties = new HashMap<>();\n\n        this.properties.put(DOCKER_HOST_URL, DEFAULT_DOCKER_HOST_URL);\n        this.properties.put(IS_ENABLED, true);\n\n        this.properties.put(REPOSITORY_ENABLED, true);\n        this.properties.put(REPOSITORY_URL, \"testrepo.net\");\n        this.properties.put(REPOSITORY_USERNAME, \"Tester\");\n        this.properties.put(REPOSITORY_PASSWORD, \"ng4#$fuhn834F84nf8nw8GF3\");\n        this.properties.put(IMAGES_DOWNLOAD_TIMEOUT, DEFAULT_IMAGES_DOWNLOAD_TIMEOUT);\n    }\n\n    private void givenEnforcementEnabledProperty(boolean enabled) {\n        this.properties.put(ENFORCEMENT_ENABLED, enabled);\n    }\n\n    /**\n     * when\n     */\n\n    private void whenActivateInstance() {\n        this.dockerService.activate(this.properties);\n    }\n\n    private void whenUpdateInstance() {\n        this.dockerService.activate(this.properties);\n    }\n\n    private void whenDeactivateInstance() {\n        this.dockerService.deactivate();\n    }\n\n    private void whenDockerClientMockHasNoContainers() {\n        List<Container> containerListmock = new LinkedList<>();\n        this.runningContainers = new String[0];\n        this.runningContainerDescriptor = new ContainerInstanceDescriptor[0];\n        this.mockedListContainersCmd = mock(ListContainersCmd.class, Mockito.RETURNS_DEEP_STUBS);\n        when(this.localDockerClient.listContainersCmd()).thenReturn(this.mockedListContainersCmd);\n        when(this.mockedListContainersCmd.withShowAll(true)).thenReturn(this.mockedListContainersCmd);\n        when(this.mockedListContainersCmd.exec()).thenReturn(containerListmock);\n    }\n\n    private void whenDockerClientMockSomeContainers() {\n        List<Container> containerListmock = new LinkedList<>();\n        // Build Container Mock\n        Container mcont1 = mock(Container.class);\n        when(mcont1.getId()).thenReturn(CONTAINER_ID_1);\n        when(mcont1.toString()).thenReturn(CONTAINER_ID_1);\n        when(mcont1.getNames()).thenReturn(new String[] { \"jim\", \"/jim\" });\n        when(mcont1.getImage()).thenReturn(IMAGE_NAME_NGINX);\n        when(mcont1.getPorts()).thenReturn(new ContainerPort[0]);\n        when(mcont1.getState()).thenReturn(\"running\");\n        containerListmock.add(mcont1);\n\n        Container mcont2 = mock(Container.class);\n        when(mcont2.getId()).thenReturn(CONTAINER_ID_2);\n        when(mcont2.toString()).thenReturn(CONTAINER_ID_2);\n        when(mcont2.getNames()).thenReturn(new String[] { CONTAINER_NAME_FRANK, \"/frank\" });\n        when(mcont2.getImage()).thenReturn(\"nginx2\");\n        when(mcont2.getPorts()).thenReturn(new ContainerPort[0]);\n        when(mcont2.getState()).thenReturn(\"running\");\n        containerListmock.add(mcont2);\n\n        this.runningContainers = new String[] { mcont1.toString(), mcont2.toString() };\n\n        // Build Respective CD's\n        ContainerInstanceDescriptor mcontCD1 = ContainerInstanceDescriptor.builder().setContainerID(mcont1.getId())\n                .setContainerName(mcont1.getNames()[0]).setContainerImage(mcont1.getImage()).build();\n\n        ContainerInstanceDescriptor mcontCD2 = ContainerInstanceDescriptor.builder().setContainerID(mcont2.getId())\n                .setContainerName(mcont2.getNames()[0]).setContainerImage(mcont2.getImage()).build();\n\n        this.runningContainerDescriptor = new ContainerInstanceDescriptor[] { mcontCD1, mcontCD2 };\n\n        this.mockedListContainersCmd = mock(ListContainersCmd.class, Mockito.RETURNS_DEEP_STUBS);\n        when(this.localDockerClient.listContainersCmd()).thenReturn(this.mockedListContainersCmd);\n        when(this.mockedListContainersCmd.withShowAll(true)).thenReturn(this.mockedListContainersCmd);\n        when(this.mockedListContainersCmd.exec()).thenReturn(containerListmock);\n    }\n\n    private void whenDockerClientMockCreateContainer() {\n\n        this.createContainerCmd = mock(CreateContainerCmd.class, Mockito.RETURNS_DEEP_STUBS);\n        this.createContainerResponse = new CreateContainerResponse();\n        this.createContainerResponse.setId(\"containerId\");\n        when(this.localDockerClient.createContainerCmd(anyString())).thenReturn(this.createContainerCmd);\n        when(this.createContainerCmd.withHostConfig(any())).thenReturn(this.createContainerCmd);\n        when(this.createContainerCmd.withHostConfig(any()).exec()).thenReturn(this.createContainerResponse);\n        when(this.createContainerCmd.withExposedPorts(anyList())).thenReturn(this.createContainerCmd);\n        when(this.createContainerCmd.withName(any())).thenReturn(this.createContainerCmd);\n    }\n\n    private void whenDockerClientMockContainerWithPorts() {\n\n        List<Container> containerListmock = new LinkedList<>();\n        // Build Container Mock\n        Container mcont1 = mock(Container.class);\n        when(mcont1.getId()).thenReturn(\"1f12d3s23\");\n        when(mcont1.toString()).thenReturn(\"1f12d3s23\");\n        when(mcont1.getNames()).thenReturn(new String[] { \"jim\", \"/jim\" });\n        when(mcont1.getImage()).thenReturn(\"nginx\");\n        when(mcont1.getPorts())\n                .thenReturn(new ContainerPort[] { TCP_CONTAINER_PORT, UDP_CONTAINER_PORT, SCTP_CONTAINER_PORT });\n        when(mcont1.getState()).thenReturn(\"running\");\n        containerListmock.add(mcont1);\n\n        this.runningContainers = new String[] { mcont1.toString() };\n\n        // Build Respective CD's\n        ContainerInstanceDescriptor mcontCD1 = ContainerInstanceDescriptor.builder().setContainerID(mcont1.getId())\n                .setContainerName(mcont1.getNames()[0]).setContainerImage(mcont1.getImage()).build();\n\n        this.runningContainerDescriptor = new ContainerInstanceDescriptor[] { mcontCD1 };\n\n        this.mockedListContainersCmd = mock(ListContainersCmd.class, Mockito.RETURNS_DEEP_STUBS);\n        when(this.localDockerClient.listContainersCmd()).thenReturn(this.mockedListContainersCmd);\n        when(this.mockedListContainersCmd.withShowAll(true)).thenReturn(this.mockedListContainersCmd);\n        when(this.mockedListContainersCmd.exec()).thenReturn(containerListmock);\n    }\n\n    private void whenMockforContainerCreation() {\n\n        // Build Respective CD's\n        ContainerInstanceDescriptor mcontCD1 = ContainerInstanceDescriptor.builder().setContainerID(\"1d3dewf34r5\")\n                .setContainerName(CONTAINER_NAME_FRANK).setContainerImage(IMAGE_NAME_NGINX).build();\n\n        this.imageConfig = new ImageConfiguration.ImageConfigurationBuilder().setImageName(IMAGE_NAME_NGINX)\n                .setImageTag(IMAGE_TAG_LATEST).setImageDownloadTimeoutSeconds(0)\n                .setRegistryCredentials(Optional.of(new PasswordRegistryCredentials(Optional.of(REGISTRY_URL),\n                        REGISTRY_USERNAME, new Password(REGISTRY_PASSWORD))))\n                .build();\n\n        this.containerConfig1 = ContainerConfiguration.builder().setContainerName(CONTAINER_NAME_FRANK)\n                .setImageConfiguration(imageConfig).setVolumes(Collections.singletonMap(\"test\", \"~/test/test\"))\n                .setDeviceList(Arrays.asList(\"/dev/gpio1\", \"/dev/gpio2\"))\n                .setEnvVars(Arrays.asList(\"test=test\", \"test2=test2\")).build();\n\n        this.runningContainerDescriptor = new ContainerInstanceDescriptor[] { mcontCD1 };\n\n        CreateContainerCmd ccc = mock(CreateContainerCmd.class, Mockito.RETURNS_DEEP_STUBS);\n        when(this.localDockerClient.createContainerCmd(mcontCD1.getContainerImage())).thenReturn(ccc);\n        when(ccc.exec().getId()).thenReturn(mcontCD1.getContainerId());\n\n        List<Image> images = new LinkedList<>();\n        Image mockImage = mock(Image.class);\n\n        when(mockImage.getRepoTags()).thenReturn(new String[] { IMAGE_NAME_NGINX, IMAGE_TAG_LATEST, \"nginx:latest\" });\n\n        images.add(mockImage);\n\n        when(this.localDockerClient.listImagesCmd()).thenReturn(mock(ListImagesCmd.class));\n        when(this.localDockerClient.listImagesCmd().exec()).thenReturn(images);\n\n    }\n\n    private void whenMockForImageListing() {\n        this.imageConfig = new ImageConfiguration.ImageConfigurationBuilder().setImageName(IMAGE_NAME_NGINX)\n                .setImageTag(IMAGE_TAG_LATEST).setImageDownloadTimeoutSeconds(0)\n                .setRegistryCredentials(Optional.of(new PasswordRegistryCredentials(Optional.of(REGISTRY_URL),\n                        REGISTRY_USERNAME, new Password(REGISTRY_PASSWORD))))\n                .build();\n\n        List<Image> images = new LinkedList<>();\n        Image mockImage = mock(Image.class);\n\n        when(mockImage.getId()).thenReturn(\"ngnix\");\n        when(mockImage.getRepoTags()).thenReturn(new String[] { IMAGE_NAME_NGINX, IMAGE_TAG_LATEST, \"nginx:latest\" });\n        when(mockImage.getRepoDigests()).thenReturn(REPO_DIGESTS_ARRAY);\n        images.add(mockImage);\n\n        when(this.localDockerClient.listImagesCmd()).thenReturn(mock(ListImagesCmd.class));\n        when(this.localDockerClient.listImagesCmd().withShowAll(true)).thenReturn(mock(ListImagesCmd.class));\n        when(this.localDockerClient.listImagesCmd().withShowAll(true).exec()).thenReturn(images);\n\n    }\n\n    private void whenMockForImageDigestsListing() {\n        this.imageConfig = new ImageConfiguration.ImageConfigurationBuilder().setImageName(IMAGE_NAME_NGINX)\n                .setImageTag(IMAGE_TAG_LATEST).setImageDownloadTimeoutSeconds(0)\n                .setRegistryCredentials(Optional.of(new PasswordRegistryCredentials(Optional.of(REGISTRY_URL),\n                        REGISTRY_USERNAME, new Password(REGISTRY_PASSWORD))))\n                .build();\n\n        List<Image> images = new LinkedList<>();\n        Image mockImage = mock(Image.class);\n\n        when(mockImage.getId()).thenReturn(\"ngnix\");\n        when(mockImage.getRepoTags()).thenReturn(new String[] { IMAGE_NAME_NGINX, IMAGE_TAG_LATEST, \"nginx:latest\" });\n        when(mockImage.getRepoDigests()).thenReturn(REPO_DIGESTS_ARRAY);\n        images.add(mockImage);\n\n        when(this.localDockerClient.listImagesCmd()).thenReturn(mock(ListImagesCmd.class));\n        when(this.localDockerClient.listImagesCmd().withImageNameFilter(anyString()))\n                .thenReturn(mock(ListImagesCmd.class));\n        when(this.localDockerClient.listImagesCmd().withImageNameFilter(anyString()).exec()).thenReturn(images);\n\n    }\n\n    private void whenMockForContainerInstancesDigestAdding() {\n\n        // Build Respective CD's\n        ContainerInstanceDescriptor mcontCD1 = ContainerInstanceDescriptor.builder().setContainerID(\"1d3dewf34r5\")\n                .setContainerName(CONTAINER_NAME_FRANK).setContainerImage(IMAGE_NAME_NGINX).build();\n\n        this.imageConfig = new ImageConfiguration.ImageConfigurationBuilder().setImageName(IMAGE_NAME_NGINX)\n                .setImageTag(IMAGE_TAG_LATEST).setImageDownloadTimeoutSeconds(0)\n                .setRegistryCredentials(Optional.of(new PasswordRegistryCredentials(Optional.of(REGISTRY_URL),\n                        REGISTRY_USERNAME, new Password(REGISTRY_PASSWORD))))\n                .build();\n\n        org.eclipse.kura.container.orchestration.ContainerPort containerPort = new org.eclipse.kura.container.orchestration.ContainerPort(\n                TCP_CONTAINER_PORT.getPrivatePort(), TCP_CONTAINER_PORT.getPublicPort());\n\n        this.containerConfig1 = ContainerConfiguration.builder().setContainerName(CONTAINER_NAME_FRANK)\n                .setImageConfiguration(imageConfig).setVolumes(Collections.singletonMap(\"test\", \"~/test/test\"))\n                .setEnforcementDigest(Optional.of(CONTAINER_INSTANCE_DIGEST)).setLoggingType(\"NONE\")\n                .setContainerPorts(Arrays.asList(containerPort)).build();\n\n        this.runningContainerDescriptor = new ContainerInstanceDescriptor[] { mcontCD1 };\n\n    }\n\n    private void whenRunContainer() throws KuraException, InterruptedException {\n        this.containerId = this.dockerService.startContainer(this.containerConfig1);\n    }\n\n    private void whenStopContainer() throws KuraException {\n        this.dockerService.stopContainer(this.containerId);\n    }\n\n    private void whenDeleteContainer() throws KuraException {\n        this.dockerService.deleteContainer(this.containerId);\n    }\n\n    private void whenImageIsDeletedById(String imageId) throws KuraException {\n        this.dockerService.deleteImage(imageId);\n    }\n\n    private void whenImagesAreListed() {\n        this.dockerService.listImageInstanceDescriptors();\n    }\n\n    private void whenGetImageDigestsByContainerId(String containerName) {\n        this.digestsList = this.dockerService.getImageDigestsByContainerId(containerName);\n    }\n\n    /**\n     * then\n     */\n\n    private void thenNotStoppedMicroservice() {\n        verify(this.localDockerClient, times(0)).removeContainerCmd(any(String.class));\n    }\n\n    private void thenNotStartedMicroservice() {\n        verify(this.localDockerClient, times(0)).startContainerCmd(any(String.class));\n    }\n\n    private void thenContainerListEqualsExpectedStringArray() {\n        assertEquals(this.dockerService.listContainersIds(), Arrays.asList(this.runningContainers));\n    }\n\n    private void thenContainerListByIdEqualsExpectedStringArray() {\n        assertEquals(this.dockerService.listContainersIds(), Arrays.asList(this.runningContainers));\n    }\n\n    private void thenContainerListByContainerDescriptorEqualsExpectedStringArray() {\n        if (this.runningContainerDescriptor.length > 0) {\n            assertEquals(this.dockerService.listContainerDescriptors().size(), this.runningContainerDescriptor.length);\n        } else {\n            assertEquals(this.dockerService.listContainerDescriptors(), Arrays.asList(this.runningContainerDescriptor));\n        }\n    }\n\n    private void thenContainerPortsInfosArePresent() {\n\n        assertFalse(this.dockerService.listContainerDescriptors().isEmpty());\n        List<org.eclipse.kura.container.orchestration.ContainerPort> containerPorts = this.dockerService\n                .listContainerDescriptors().get(0).getContainerPorts();\n\n        List<ContainerPort> expectedContainerPorts = Arrays.asList(TCP_CONTAINER_PORT, UDP_CONTAINER_PORT,\n                SCTP_CONTAINER_PORT);\n        List<PortInternetProtocol> expectedInternetPortProtocols = Arrays.asList(PortInternetProtocol.TCP,\n                PortInternetProtocol.UDP, PortInternetProtocol.SCTP);\n        for (int i = 0; i < containerPorts.size(); i++) {\n            assertEquals((int) expectedContainerPorts.get(i).getPublicPort(), containerPorts.get(i).getExternalPort());\n            assertEquals((int) expectedContainerPorts.get(i).getPrivatePort(), containerPorts.get(i).getInternalPort());\n            assertEquals(expectedInternetPortProtocols.get(i), containerPorts.get(i).getInternetProtocol());\n        }\n\n    }\n\n    private void thenGetFirstContainerIDbyName() {\n        assertEquals(this.dockerService.getContainerIdByName(this.runningContainerDescriptor[0].getContainerName())\n                .orElse(\"\"), this.runningContainerDescriptor[0].getContainerId());\n    }\n\n    private void thenTestIfNewContainerExists() {\n        assertEquals(2, this.dockerService.listContainerDescriptors().size());\n    }\n\n    private void thenTestIfNewContainerDoesNotExists() {\n        assertEquals(2, this.dockerService.listContainerDescriptors().size());\n    }\n\n    private void thenCheckIfImageWasDeleted() {\n        verify(this.localDockerClient, times(1)).removeImageCmd(any(String.class));\n    }\n\n    private void thenCheckIfImagesWereListed() {\n        verify(this.localDockerClient, times(1)).inspectImageCmd(any(String.class));\n    }\n\n    private void thenDigestsListEqualsExpectedOne(String[] digestsArray) {\n        assertEquals(new HashSet<>(Arrays.asList(digestsArray)), this.digestsList);\n    }\n\n    private void thenContainerInstanceDigestIsAddedToAllowlist() {\n        assertFalse(this.dockerService.getContainerInstancesAllowlist().isEmpty());\n    }\n\n    private void thenContainerInstanceDigestIsNotInAllowlist() {\n        assertTrue(this.dockerService.getContainerInstancesAllowlist().isEmpty());\n    }\n\n    private void thenContainerInstanceDigestIsExpectedOne(String expected) {\n        List<String> actualDigests = new ArrayList<>(this.dockerService.getContainerInstancesAllowlist());\n        assertEquals(actualDigests.get(0), expected);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/src/test/java/org/eclipse/kura/container/orchestration/provider/ContainerOrchestrationServiceOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotEquals;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport org.eclipse.kura.container.orchestration.provider.impl.ContainerOrchestrationServiceOptions;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class ContainerOrchestrationServiceOptionsTest {\n\n    private static final String DOCKER_HOST_URL = \"container.engine.host\";\n    private static final String IS_ENABLED = \"enabled\";\n    private static final String ALLOWLIST_ENABLED = \"allowlist.enabled\";\n    private static final String ALLOWLIST_CONTENT = \"allowlist.content\";\n\n    private static final String DEFAULT_DOCKER_HOST_URL = \"unix:///var/run/docker.sock\";\n    private static final boolean DEFAULT_IS_ENABLED = false;\n    private static final String DEFAULT_ALLOWLIST_CONTENT = \"\";\n    private static final boolean DEFAULT_ALLOWLIST_ENABLED = false;\n\n    private static final String REPOSITORY_ENABLED = \"repository.enabled\";\n    private static final String REPOSITORY_URL = \"repository.hostname\";\n    private static final String REPOSITORY_USERNAME = \"repository.username\";\n    private static final String REPOSITORY_PASSWORD = \"repository.password\";\n\n    private static final boolean DEFAULT_REPOSITORY_ENABLED = false;\n    private static final String DEFAULT_REPOSITORY_URL = \"\";\n    private static final String DEFAULT_REPOSITORY_USERNAME = \"\";\n    private static final String DEFAULT_REPOSITORY_PASSWORD = \"\";\n\n    private String host_url = \"\";\n    private boolean is_enabled = false;\n    private String allowlist_content = \"\";\n    private boolean enforcement_enabled = false;\n\n    private int hash;\n\n    private Map<String, Object> properties = new HashMap<>();\n    private Map<String, Object> newProperties = new HashMap<>();\n    private ContainerOrchestrationServiceOptions dso = new ContainerOrchestrationServiceOptions(this.properties);\n    private ContainerOrchestrationServiceOptions ddso = new ContainerOrchestrationServiceOptions(this.properties);\n\n    @Before\n    public void setUp() throws Exception {\n    }\n\n    @After\n    public void tearDown() throws Exception {\n    }\n\n    @Test\n    public void testDisabledDefault() {\n        givenEmptyProperties();\n        givenDockerServiceOptions();\n\n        whenIsEnabled();\n\n        thenEnabledStateIs(false);\n    }\n\n    @Test\n    public void testEnabledDefault() {\n        givenEmptyProperties();\n        givenDockerServiceEnabled(true);\n        givenDockerServiceOptions();\n\n        whenIsEnabled();\n\n        thenEnabledStateIs(true);\n    }\n\n    @Test\n    public void testDefaultHostString() {\n        givenEmptyProperties();\n        givenDockerServiceOptions();\n\n        whenHostStringSet();\n\n        thenHostStringIs(DEFAULT_DOCKER_HOST_URL);\n    }\n\n    @Test\n    public void testCustomHostString() {\n        givenEmptyProperties();\n        givenDockerHostString(\"unix://Test/Docker\");\n        givenDockerServiceOptions();\n\n        whenHostStringSet();\n\n        thenHostStringIs(\"unix://Test/Docker\");\n    }\n\n    @Test\n    public void testHash() {\n        givenEmptyProperties();\n        givenDockerServiceOptions();\n\n        whenHostStringSet();\n        whenIsEnabled();\n        whenAllowlistContentSet();\n        whenIsEnforcementEnabled();\n\n        whenHashIsCalculated();\n\n        thenHashIsEqual();\n    }\n\n    @Test\n    public void testDockerServiceDoeNotEqual() {\n        givenEmptyProperties();\n        givenDockerServiceOptions();\n        givenDiffrentProperties();\n        givenDifferentDockerServiceOptions();\n\n        thenDockerServiceObjectDoesntEqualsDifferent();\n    }\n\n    @Test\n    public void testDockerServiceEquals() {\n        givenEmptyProperties();\n        givenDockerServiceOptions();\n\n        thenDockerServiceObjectEquals();\n    }\n\n    @Test\n    public void testDockerServiceEqualsWhenNull() {\n        givenEmptyProperties();\n        givenDockerServiceOptions();\n\n        thenDockerServiceObjectDoesntEqualsWhenNull();\n    }\n\n    @Test\n    public void testDockerServiceEqualsWhenWrongObjectPasssed() {\n        givenEmptyProperties();\n        givenDockerServiceOptions();\n\n        thenDockerServiceObjectDoesntEqualsWhenWrongComparison();\n    }\n\n    /**\n     * Givens\n     */\n    private void givenEmptyProperties() {\n        this.properties = new HashMap<>();\n        this.properties.put(DOCKER_HOST_URL, DEFAULT_DOCKER_HOST_URL);\n        this.properties.put(IS_ENABLED, DEFAULT_IS_ENABLED);\n        this.properties.put(ALLOWLIST_ENABLED, DEFAULT_ALLOWLIST_ENABLED);\n        this.properties.put(ALLOWLIST_CONTENT, DEFAULT_ALLOWLIST_CONTENT);\n        this.properties.put(REPOSITORY_ENABLED, DEFAULT_REPOSITORY_ENABLED);\n        this.properties.put(REPOSITORY_URL, DEFAULT_REPOSITORY_URL);\n        this.properties.put(REPOSITORY_USERNAME, DEFAULT_REPOSITORY_USERNAME);\n        this.properties.put(REPOSITORY_PASSWORD, DEFAULT_REPOSITORY_PASSWORD);\n    }\n\n    private void givenDiffrentProperties() {\n        this.newProperties = new HashMap<>();\n        this.newProperties.put(DOCKER_HOST_URL, \"http://docker.local\");\n        this.newProperties.put(IS_ENABLED, true);\n        this.properties.put(ALLOWLIST_ENABLED, DEFAULT_ALLOWLIST_ENABLED);\n        this.properties.put(ALLOWLIST_CONTENT, DEFAULT_ALLOWLIST_CONTENT);\n        this.properties.put(REPOSITORY_ENABLED, DEFAULT_REPOSITORY_ENABLED);\n        this.properties.put(REPOSITORY_URL, DEFAULT_REPOSITORY_URL);\n        this.properties.put(REPOSITORY_USERNAME, DEFAULT_REPOSITORY_USERNAME);\n        this.properties.put(REPOSITORY_PASSWORD, DEFAULT_REPOSITORY_PASSWORD);\n    }\n\n    private void givenDockerServiceOptions() {\n        this.dso = new ContainerOrchestrationServiceOptions(this.properties);\n    }\n\n    private void givenDifferentDockerServiceOptions() {\n        this.ddso = new ContainerOrchestrationServiceOptions(this.newProperties);\n    }\n\n    private void givenDockerServiceEnabled(boolean b) {\n        this.properties.put(IS_ENABLED, b);\n    }\n\n    private void givenDockerHostString(String s) {\n        this.properties.put(DOCKER_HOST_URL, s);\n    }\n\n    /**\n     * Whens\n     */\n\n    private void whenIsEnabled() {\n        this.is_enabled = this.dso.isEnabled();\n    }\n\n    private void whenHostStringSet() {\n        this.host_url = this.dso.getHostUrl();\n    }\n\n    private void whenAllowlistContentSet() {\n        this.allowlist_content = this.dso.getEnforcementAllowlist();\n    }\n\n    private void whenIsEnforcementEnabled() {\n        this.enforcement_enabled = this.dso.isEnforcementEnabled();\n    }\n\n    private void whenHashIsCalculated() {\n        this.hash = Objects.hash(this.allowlist_content, this.enforcement_enabled, this.is_enabled, this.host_url);\n    }\n\n    /**\n     * Then\n     */\n    private void thenEnabledStateIs(boolean b) {\n        assertEquals(b, this.is_enabled);\n    }\n\n    private void thenHostStringIs(String s) {\n        assertEquals(s, this.host_url);\n    }\n\n    private void thenHashIsEqual() {\n        assertEquals(this.hash, this.dso.hashCode());\n    }\n\n    private void thenDockerServiceObjectEquals() {\n        assertEquals(this.dso, this.dso);\n    }\n\n    private void thenDockerServiceObjectDoesntEqualsDifferent() {\n        assertNotEquals(this.dso, this.ddso);\n    }\n\n    private void thenDockerServiceObjectDoesntEqualsWhenNull() {\n        assertNotEquals(this.dso, null);\n    }\n\n    private void thenDockerServiceObjectDoesntEqualsWhenWrongComparison() {\n        assertNotEquals(this.dso, \"String that represents a wrong object passed\");\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/src/test/java/org/eclipse/kura/container/orchestration/provider/EnforcementSecurityTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration.provider;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.doNothing;\nimport static org.mockito.Mockito.doReturn;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.spy;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ContainerState;\nimport org.eclipse.kura.container.orchestration.ImageConfiguration;\nimport org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;\nimport org.eclipse.kura.container.orchestration.provider.impl.ContainerOrchestrationServiceImpl;\nimport org.eclipse.kura.container.orchestration.provider.impl.enforcement.AllowlistEnforcementMonitor;\nimport org.junit.Test;\nimport org.mockito.Mockito;\n\nimport com.github.dockerjava.api.DockerClient;\nimport com.github.dockerjava.api.model.Event;\n\npublic class EnforcementSecurityTest {\n\n    private static final String IMAGE_NAME = \"nginx\";\n    private static final String CONTAINER_NAME = \"frank\";\n    private static final String CONTAINER_ID = \"1d3dewf34r5\";\n\n    private static final String REGISTRY_URL = \"https://test\";\n    private static final String REGISTRY_USERNAME = \"test\";\n    private static final String REGISTRY_PASSWORD = \"test1\";\n\n    private static final String EMPTY_ALLOWLIST_CONTENT = \"\";\n    private static final String FILLED_ALLOWLIST_CONTENT_NO_SPACE = \"sha256:f9d633ff6640178c2d0525017174a688e2c1aef28f0a0130b26bd5554491f0da\\nsha256:c26ae7472d624ba1fafd296e73cecc4f93f853088e6a9c13c0d52f6ca5865107\";\n    private static final String FILLED_ALLOWLIST_CONTENT_WITH_SPACES = \" sha256:f9d633ff6640178c2d0525017174a688e2c1aef28f0a0130b26bd5554491f0da \\n sha256:c26ae7472d624ba1fafd296e73cecc4f93f853088e6a9c13c0d52f6ca5865107\";\n\n    private static final String CORRECT_DIGEST = \"sha256:c26ae7472d624ba1fafd296e73cecc4f93f853088e6a9c13c0d52f6ca5865107\";\n    private static final String WRONG_DIGEST = \"sha256:0000000000000000000000000000000000000000000000000000000000000000\";\n\n    private AllowlistEnforcementMonitor allowlistEnforcementMonitor;\n    private ContainerOrchestrationServiceImpl mockedContainerOrchestrationImpl;\n\n    ContainerConfiguration containerConfig;\n\n    private Map<String, Object> properties = new HashMap<>();\n\n    public EnforcementSecurityTest() {\n        this.properties.clear();\n    }\n\n    @Test\n    public void shouldAllowStartingWithCorrectAllowlistContent() throws KuraException, InterruptedException {\n\n        givenMockedContainerOrchestrationServiceWith(CONTAINER_ID, CONTAINER_NAME, IMAGE_NAME, ContainerState.ACTIVE,\n                CORRECT_DIGEST);\n        givenMockedDockerClient();\n        givenAllowlistEnforcement(FILLED_ALLOWLIST_CONTENT_NO_SPACE);\n\n        whenOnNext(CONTAINER_ID);\n\n        thenStopContainerWasNeverCalled();\n        thenDeleteContainerWasNeverCalled();\n    }\n\n    @Test\n    public void shouldAllowStartingWithCorrectAllowlistContentWithSpaces() throws KuraException, InterruptedException {\n\n        givenMockedContainerOrchestrationServiceWith(CONTAINER_ID, CONTAINER_NAME, IMAGE_NAME, ContainerState.ACTIVE,\n                CORRECT_DIGEST);\n        givenMockedDockerClient();\n        givenAllowlistEnforcement(FILLED_ALLOWLIST_CONTENT_WITH_SPACES);\n\n        whenOnNext(CONTAINER_ID);\n\n        thenStopContainerWasNeverCalled();\n        thenDeleteContainerWasNeverCalled();\n    }\n\n    @Test\n    public void shouldNotAllowStartingWithEmptyAllowlistContent() throws KuraException, InterruptedException {\n\n        givenMockedContainerOrchestrationServiceWith(CONTAINER_ID, CONTAINER_NAME, IMAGE_NAME, ContainerState.ACTIVE,\n                CORRECT_DIGEST);\n        givenMockedDockerClient();\n        givenAllowlistEnforcement(EMPTY_ALLOWLIST_CONTENT);\n\n        whenOnNext(CONTAINER_ID);\n\n        thenStopContainerWasCalledFor(CONTAINER_ID);\n        thenDeleteContainerWasCalledFor(CONTAINER_ID);\n    }\n\n    @Test\n    public void shouldNotAllowStartingWithWrongContainerDigest() throws KuraException, InterruptedException {\n\n        givenMockedContainerOrchestrationServiceWith(CONTAINER_ID, CONTAINER_NAME, IMAGE_NAME, ContainerState.ACTIVE,\n                WRONG_DIGEST);\n        givenMockedDockerClient();\n        givenAllowlistEnforcement(FILLED_ALLOWLIST_CONTENT_NO_SPACE);\n\n        whenOnNext(CONTAINER_ID);\n\n        thenStopContainerWasCalledFor(CONTAINER_ID);\n        thenDeleteContainerWasCalledFor(CONTAINER_ID);\n    }\n\n    @Test\n    public void shouldStopAndDeleteContainerWithWrongDigestAndActiveState() throws KuraException, InterruptedException {\n\n        givenMockedContainerOrchestrationServiceWith(CONTAINER_ID, CONTAINER_NAME, IMAGE_NAME, ContainerState.ACTIVE,\n                CORRECT_DIGEST);\n        givenMockedDockerClient();\n        givenAllowlistEnforcement(EMPTY_ALLOWLIST_CONTENT);\n\n        whenVerifyAlreadyRunningContainersDigests(this.mockedContainerOrchestrationImpl.listContainerDescriptors());\n\n        thenStopContainerWasCalledFor(CONTAINER_ID);\n        thenDeleteContainerWasCalledFor(CONTAINER_ID);\n    }\n\n    @Test\n    public void shouldOnlyDeleteContainerWithWrongDigestAndFailedState() throws KuraException, InterruptedException {\n\n        givenMockedContainerOrchestrationServiceWith(CONTAINER_ID, CONTAINER_NAME, IMAGE_NAME, ContainerState.FAILED,\n                CORRECT_DIGEST);\n        givenMockedDockerClient();\n        givenAllowlistEnforcement(EMPTY_ALLOWLIST_CONTENT);\n\n        whenVerifyAlreadyRunningContainersDigests(this.mockedContainerOrchestrationImpl.listContainerDescriptors());\n\n        thenStopContainerWasNeverCalled();\n        thenDeleteContainerWasCalledFor(CONTAINER_ID);\n    }\n\n    /*\n     * Given\n     */\n\n    ContainerInstanceDescriptor containerInstanceDescriptor;\n\n    private void givenMockedContainerOrchestrationServiceWith(String containerId, String containerName,\n            String imageName, ContainerState containerState, String digest) throws KuraException, InterruptedException {\n\n        this.mockedContainerOrchestrationImpl = spy(new ContainerOrchestrationServiceImpl());\n\n        this.containerInstanceDescriptor = ContainerInstanceDescriptor.builder().setContainerID(containerId)\n                .setContainerName(containerName).setContainerImage(imageName).setContainerState(containerState).build();\n        List<ContainerInstanceDescriptor> containerDescriptors = new ArrayList<>();\n        containerDescriptors.add(containerInstanceDescriptor);\n\n        ImageConfiguration imageConfig = new ImageConfiguration.ImageConfigurationBuilder().setImageName(imageName)\n                .setImageTag(\"latest\").setImageDownloadTimeoutSeconds(0)\n                .setRegistryCredentials(Optional.of(new PasswordRegistryCredentials(Optional.of(REGISTRY_URL),\n                        REGISTRY_USERNAME, new Password(REGISTRY_PASSWORD))))\n                .build();\n\n        this.containerConfig = ContainerConfiguration.builder().setContainerName(CONTAINER_NAME)\n                .setImageConfiguration(imageConfig).setVolumes(Collections.singletonMap(\"test\", \"~/test/test\"))\n                .setDeviceList(Arrays.asList(\"/dev/gpio1\", \"/dev/gpio2\"))\n                .setEnvVars(Arrays.asList(\"test=test\", \"test2=test2\")).build();\n\n        doReturn(containerDescriptors).when(this.mockedContainerOrchestrationImpl).listContainerDescriptors();\n        doNothing().when(this.mockedContainerOrchestrationImpl).pullImage(any(ImageConfiguration.class));\n        doNothing().when(this.mockedContainerOrchestrationImpl).stopContainer(anyString());\n        doNothing().when(this.mockedContainerOrchestrationImpl).deleteContainer(anyString());\n        doReturn(new HashSet<>(Arrays.asList(digest))).when(this.mockedContainerOrchestrationImpl)\n                .getImageDigestsByContainerId(containerId);\n    }\n\n    private void givenMockedDockerClient() {\n        DockerClient mockedDockerClient = mock(DockerClient.class, Mockito.RETURNS_DEEP_STUBS);\n        this.mockedContainerOrchestrationImpl.setDockerClient(mockedDockerClient);\n    }\n\n    private void givenAllowlistEnforcement(String rawAllowlistContent) {\n        this.allowlistEnforcementMonitor = new AllowlistEnforcementMonitor(rawAllowlistContent,\n                this.mockedContainerOrchestrationImpl);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenOnNext(String containerId) {\n        this.allowlistEnforcementMonitor.onNext(new Event(\"start\", containerId, \"nginx:latest\", 1708963202L));\n    }\n\n    private void whenVerifyAlreadyRunningContainersDigests(List<ContainerInstanceDescriptor> containerDescriptors) {\n        this.allowlistEnforcementMonitor.enforceAllowlistFor(containerDescriptors);\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenStopContainerWasNeverCalled() throws KuraException {\n        verify(this.mockedContainerOrchestrationImpl, never()).stopContainer(any(String.class));\n    }\n\n    private void thenStopContainerWasCalledFor(String containerId) throws KuraException {\n        verify(this.mockedContainerOrchestrationImpl, times(1)).stopContainer(containerId);\n    }\n\n    private void thenDeleteContainerWasNeverCalled() throws KuraException {\n        verify(this.mockedContainerOrchestrationImpl, never()).deleteContainer(any(String.class));\n    }\n\n    private void thenDeleteContainerWasCalledFor(String containerId) throws KuraException {\n        verify(this.mockedContainerOrchestrationImpl, times(1)).deleteContainer(containerId);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.orchestration.provider.test/src/test/java/org/eclipse/kura/container/orchestration/provider/ImageInstanceDescriptorTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.container.orchestration.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\n\nimport org.eclipse.kura.container.orchestration.ImageInstanceDescriptor;\nimport org.junit.Test;\n\npublic class ImageInstanceDescriptorTest {\n\n    private static final String IMAGE_NAME = \"nginx\";\n    private static final String IMAGE_TAG = \"latest\";\n    private static final String IMAGE_ARCH = \"ARM64\";\n    private static final String IMAGE_AUTHOR = \"Nginx\";\n    private static final String IMAGE_ID = \"f45f645f457uyrthjfghje4r6t\";\n    private static final long IMAGE_SIZE = 123123;\n\n    private ImageInstanceDescriptor firstImageConfig;\n    private ImageInstanceDescriptor seccondImageConfig;\n\n    @Test\n    public void testSupportOfBasicParameters() {\n        givenContainerOne();\n\n        thenCompareContainerOneToExpectedOutput();\n    }\n\n    @Test\n    public void testContainerDoesntEquals() {\n        givenContainerOne();\n        givenContainerTwoDiffrent();\n\n        thenFirstContainerDoesntEqualSeccond();\n    }\n\n    /**\n     * End Of Tests\n     */\n\n    // given\n    private void givenContainerOne() {\n\n        this.firstImageConfig = ImageInstanceDescriptor.builder().setImageName(IMAGE_NAME).setImageTag(IMAGE_TAG)\n                .setImageArch(IMAGE_ARCH).setImageAuthor(IMAGE_AUTHOR).setimageSize(IMAGE_SIZE).setImageId(IMAGE_ID)\n                .build();\n    }\n\n    private void givenContainerTwoDiffrent() {\n\n        this.seccondImageConfig = ImageInstanceDescriptor.builder().setImageName(\"NOT_\" + IMAGE_NAME)\n                .setImageTag(\"NOT_\" + IMAGE_TAG).setImageArch(\"NOT_\" + IMAGE_ARCH).setImageAuthor(IMAGE_AUTHOR)\n                .setimageSize(IMAGE_SIZE).setImageId(\"3rhf8943hf78934hf734t7r8fw38fy234897fh8\").build();\n    }\n\n    // then\n    private void thenCompareContainerOneToExpectedOutput() {\n        assertEquals(IMAGE_NAME, this.firstImageConfig.getImageName());\n        assertEquals(IMAGE_TAG, this.firstImageConfig.getImageTag());\n        assertEquals(IMAGE_ARCH, this.firstImageConfig.getImageArch());\n        assertEquals(IMAGE_AUTHOR, this.firstImageConfig.getImageAuthor());\n        assertEquals(IMAGE_ID, this.firstImageConfig.getImageId());\n        assertEquals(IMAGE_SIZE, this.firstImageConfig.getImageSize());\n\n    }\n\n    private void thenFirstContainerDoesntEqualSeccond() {\n        assertFalse(firstImageConfig.equals(this.seccondImageConfig));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.container.provider.test\nBundle-SymbolicName: org.eclipse.kura.container.provider.test\nBundle-Version: 2.0.0.qualifier\nBundle-Vendor: Eurotech\nFragment-Host: org.eclipse.kura.container.provider\nAutomatic-Module-Name: org.eclipse.kura.container.provider.test\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.eclipse.kura;version=\"1.6.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\"\nRequire-Bundle: org.eclipse.osgi\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2021 Eurotech and/or its affiliates. All rights reserved. \n#\nbin.includes = .,\\\n               META-INF/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n     Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n   \n     This program and the accompanying materials are made\n     available under the terms of the Eclipse Public License 2.0\n     which is available at https://www.eclipse.org/legal/epl-2.0/\n  \n \tSPDX-License-Identifier: EPL-2.0\n \t\n \tContributors:\n \t Eurotech\n -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.container.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n    <version>2.0.0-SNAPSHOT</version>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.provider.test/src/test/java/org/eclipse/kura/container/provider/ContainerIdentityIntegrationTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.container.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.time.Duration;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerOrchestrationService;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.Permission;\nimport org.eclipse.kura.identity.PasswordStrengthRequirements;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.net.IPAddress;\nimport org.eclipse.kura.net.NetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.eclipse.kura.net.NetworkService;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.mockito.Mockito;\n\n/**\n * Feature: Container instance identity integration with temporary identities enabled.\n */\npublic class ContainerIdentityIntegrationTest {\n\n    private static final String CONTAINER_NAME = \"kura-test-container\";\n    private static final String CONTAINER_IMAGE = \"nginx\";\n    private static final String CONTAINER_TAG = \"latest\";\n    private static final String PERMISSIONS = \"rest.read,rest.write\";\n    private static final String CONTAINER_ID = \"container-id\";\n    private static final String SECOND_CONTAINER_ID = \"container-id-2\";\n    private static final String UPDATED_CONTAINER_NAME = CONTAINER_NAME + \"-v2\";\n    private static final String INVALID_CONTAINER_NAME = \"....@@@....\";\n\n    private ContainerInstance containerInstance;\n    private ContainerOrchestrationService containerOrchestrationService;\n    private IdentityService identityService;\n    private PasswordStrengthVerificationService passwordStrengthVerificationService;\n    private ConfigurationService configurationService;\n    private Map<String, Object> properties;\n    private CountDownLatch startLatch;\n    private AtomicInteger createCount;\n    private AtomicInteger deleteCount;\n    private AtomicInteger startCount;\n    private ArgumentCaptor<ContainerConfiguration> configurationCaptor;\n    private ArgumentCaptor<String> identityNameCaptor;\n    private ArgumentCaptor<IdentityConfiguration> identityConfigCaptor;\n    private ArgumentCaptor<Duration> durationCaptor;\n    private List<String> capturedPasswords = new ArrayList<>();\n    private List<String> capturedIdentityNames = new ArrayList<>();\n    private char[] lastTemporaryPassword;\n\n    @Before\n    public void setUp() throws Exception {\n        this.containerInstance = new ContainerInstance();\n        this.containerOrchestrationService = Mockito.mock(ContainerOrchestrationService.class);\n        this.identityService = Mockito.mock(IdentityService.class);\n        this.passwordStrengthVerificationService = Mockito.mock(PasswordStrengthVerificationService.class);\n        this.configurationService = Mockito.mock(ConfigurationService.class);\n        this.properties = new HashMap<>();\n        this.startLatch = new CountDownLatch(1);\n        this.createCount = new AtomicInteger(0);\n        this.deleteCount = new AtomicInteger(0);\n        this.startCount = new AtomicInteger(0);\n        this.configurationCaptor = ArgumentCaptor.forClass(ContainerConfiguration.class);\n        this.identityNameCaptor = ArgumentCaptor.forClass(String.class);\n        this.identityConfigCaptor = ArgumentCaptor.forClass(IdentityConfiguration.class);\n        this.durationCaptor = ArgumentCaptor.forClass(Duration.class);\n\n        this.containerInstance.setContainerOrchestrationService(this.containerOrchestrationService);\n        this.containerInstance.setIdentityService(this.identityService);\n        this.containerInstance.setPasswordStrengthVerificationService(this.passwordStrengthVerificationService);\n        this.containerInstance.setConfigurationService(this.configurationService);\n\n        when(this.containerOrchestrationService.listContainerDescriptors()).thenReturn(Collections.emptyList());\n        Mockito.doReturn(new PasswordStrengthRequirements(12, true, true, true))\n                .when(this.passwordStrengthVerificationService).getPasswordStrengthRequirements();\n    }\n\n    @After\n    public void tearDown() {\n        this.containerInstance.deactivate();\n    }\n\n    @Test\n    public void createsTemporaryIdentityAndInjectsToken() throws Exception {\n        givenIdentityIntegrationIsEnabled();\n        givenTemporaryIdentityServiceProvidesPassword();\n        givenContainerOrchestratorStartsSuccessfully();\n\n        whenContainerInstanceIsActivated();\n\n        thenTemporaryIdentityIsCreatedWithPermissions();\n        thenStartContainerReceivesTokenEnvironment();\n    }\n\n    @Test\n    public void deletesTemporaryIdentityWhenContainerIsDisabled() throws Exception {\n        givenIdentityIntegrationIsEnabled();\n        givenTemporaryIdentityServiceProvidesPassword();\n        givenContainerOrchestratorStartsSuccessfully();\n\n        whenContainerInstanceIsActivatedUntilCreated();\n        whenContainerInstanceIsDisabled();\n\n        thenTemporaryIdentityIsDeleted();\n    }\n\n    @Test\n    public void recreatesTemporaryIdentityOnConfigurationChange() throws Exception {\n        givenIdentityIntegrationIsEnabled();\n        givenTemporaryIdentityServiceProvidesPassword();\n        givenContainerOrchestratorStartsSuccessfullyWithIds(CONTAINER_ID, SECOND_CONTAINER_ID);\n\n        whenContainerInstanceIsActivatedUntilCreated();\n        whenContainerConfigurationIsUpdatedWithNewName();\n\n        thenTemporaryIdentityIsRecreated();\n        thenLatestContainerStartReceivesRefreshedPassword();\n    }\n\n    @Test\n    public void cleansUpTemporaryIdentityOnceAcrossMultipleShutdowns() throws Exception {\n        givenIdentityIntegrationIsEnabled();\n        givenTemporaryIdentityServiceProvidesPassword();\n        givenContainerOrchestratorStartsSuccessfully();\n\n        whenContainerInstanceIsActivatedUntilCreated();\n        whenContainerInstanceIsDisabled();\n        whenContainerInstanceIsDeactivated();\n\n        thenTemporaryIdentityIsDeletedOnlyOnce();\n    }\n\n    @Test\n    public void clearsTemporaryPasswordArrayAndReference() throws Exception {\n        givenTemporaryPasswordIsSet();\n\n        whenTemporaryPasswordIsCleared();\n\n        thenTemporaryPasswordArrayIsCleared();\n        thenTemporaryPasswordIsCleared();\n    }\n\n    @Test\n    public void clearsTemporaryPasswordAfterContainerStarts() throws Exception {\n        givenIdentityIntegrationIsEnabled();\n        givenTemporaryIdentityServiceProvidesPassword();\n        givenContainerOrchestratorStartsSuccessfully();\n\n        whenContainerInstanceIsActivatedUntilCreated();\n\n        thenTemporaryPasswordIsCleared();\n    }\n\n    @Test\n    public void clearsTemporaryPasswordAfterStartupFailure() throws Exception {\n        givenIdentityIntegrationIsEnabled();\n        givenTemporaryIdentityServiceProvidesPassword();\n        givenContainerOrchestratorFailsToStart();\n        givenFastRetryConfiguration();\n\n        whenContainerInstanceIsActivatedUntilDisabled();\n\n        thenTemporaryPasswordIsCleared();\n    }\n\n    @Test\n    public void clearsTemporaryPasswordAfterCleanupTemporaryIdentity() throws Exception {\n        givenIdentityIntegrationIsEnabled();\n        givenTemporaryIdentityServiceProvidesPassword();\n        givenTemporaryIdentityNameIsSet();\n        givenTemporaryPasswordIsSet();\n\n        whenTemporaryIdentityIsCleanedUp();\n\n        thenTemporaryPasswordArrayIsCleared();\n        thenTemporaryPasswordIsCleared();\n    }\n\n    @Test\n    public void generatesValidTemporaryIdentityNameFromInvalidContainerName() throws Exception {\n        givenIdentityIntegrationIsEnabled(INVALID_CONTAINER_NAME);\n        givenTemporaryIdentityServiceProvidesPassword();\n        givenContainerOrchestratorStartsSuccessfully();\n\n        whenContainerInstanceIsActivated();\n\n        thenTemporaryIdentityUsesName(\"container_auto\");\n        thenStartContainerReceivesTokenEnvironment();\n    }\n\n    @Test\n    public void retriesTemporaryIdentityCreationWhenNameAlreadyExists() throws Exception {\n        givenIdentityIntegrationIsEnabled();\n        givenTemporaryIdentityServiceRetriesNameConflict();\n        givenContainerOrchestratorStartsSuccessfully();\n\n        whenContainerInstanceIsActivated();\n\n        thenTemporaryIdentityCreationIsRetriedWithSuffixedName();\n        thenStartContainerReceivesTokenEnvironment();\n    }\n\n    @Test\n    public void injectsUrlEncodedIpv6RestBaseUrlForDockerBridge() throws Exception {\n        givenIdentityIntegrationIsEnabled();\n        givenTemporaryIdentityServiceProvidesPassword();\n        givenContainerOrchestratorStartsSuccessfully();\n        givenHttpsServiceIsEnabledOnPort(443);\n        givenDockerBridgeAddressIs(\"fe80::7024:e3ff:feb9:997d%docker0\");\n\n        whenContainerInstanceIsActivated();\n\n        thenRestBaseUrlIs(\"https://[fe80::7024:e3ff:feb9:997d%25docker0]:443/services\");\n    }\n\n    /*\n     * GIVEN\n     */\n\n    private void givenIdentityIntegrationIsEnabled() {\n        givenIdentityIntegrationIsEnabled(CONTAINER_NAME);\n    }\n\n    private void givenIdentityIntegrationIsEnabled(final String containerName) {\n        this.properties.put(\"container.enabled\", true);\n        this.properties.put(\"container.name\", containerName);\n        this.properties.put(\"kura.service.pid\", containerName);\n        this.properties.put(\"container.image\", CONTAINER_IMAGE);\n        this.properties.put(\"container.image.tag\", CONTAINER_TAG);\n        this.properties.put(\"container.identity.enabled\", true);\n        this.properties.put(\"container.permissions\", PERMISSIONS);\n    }\n\n    private void givenTemporaryIdentityServiceProvidesPassword() throws Exception {\n        doAnswer(invocation -> {\n            this.createCount.incrementAndGet();\n\n            final String identityName = invocation.getArgument(0);\n            this.capturedIdentityNames.add(identityName);\n\n            return null; // API returns void\n        }).when(this.identityService).createTemporaryIdentity(\n                this.identityNameCaptor.capture(), this.durationCaptor.capture());\n\n        doAnswer(invocation -> {\n            final IdentityConfiguration config = invocation.getArgument(0);\n            final char[] newPassword = config.getComponent(PasswordConfiguration.class).orElseThrow()\n                    .getNewPassword().orElseThrow();\n            this.capturedPasswords.add(new String(newPassword));\n\n            return null;\n        }).when(this.identityService).updateIdentityConfiguration(this.identityConfigCaptor.capture());\n\n        doAnswer(invocation -> {\n            this.deleteCount.incrementAndGet();\n            return true; // New API returns boolean\n        }).when(this.identityService).deleteIdentity(anyString());\n    }\n\n    private void givenContainerOrchestratorStartsSuccessfully() throws Exception {\n        doAnswer(invocation -> {\n            this.startLatch.countDown();\n            this.startCount.incrementAndGet();\n            return CONTAINER_ID;\n        }).when(this.containerOrchestrationService).startContainer(this.configurationCaptor.capture());\n    }\n\n    private void givenContainerOrchestratorStartsSuccessfullyWithIds(final String... containerIds) throws Exception {\n        this.startLatch = new CountDownLatch(containerIds.length);\n        this.startCount.set(0);\n        final AtomicInteger index = new AtomicInteger(0);\n\n        doAnswer(invocation -> {\n            this.startLatch.countDown();\n            this.startCount.incrementAndGet();\n            final int current = Math.min(index.getAndIncrement(), containerIds.length - 1);\n            return containerIds[current];\n        }).when(this.containerOrchestrationService).startContainer(this.configurationCaptor.capture());\n    }\n\n    private void givenTemporaryIdentityServiceRetriesNameConflict() throws Exception {\n        final AtomicBoolean conflictRaised = new AtomicBoolean(false);\n\n        doAnswer(invocation -> {\n            this.createCount.incrementAndGet();\n\n            final String identityName = invocation.getArgument(0);\n            this.capturedIdentityNames.add(identityName);\n\n            final String expectedBaseName = \"container_\" + CONTAINER_NAME.replace(\"-\", \"_\");\n            if (!conflictRaised.get() && expectedBaseName.equals(identityName)) {\n                conflictRaised.set(true);\n                throw new KuraException(KuraErrorCode.INVALID_PARAMETER,\n                        \"An identity with name '\" + identityName + \"' already exists\");\n            }\n\n            return null;\n        }).when(this.identityService).createTemporaryIdentity(\n                this.identityNameCaptor.capture(), this.durationCaptor.capture());\n\n        doAnswer(invocation -> {\n            final IdentityConfiguration config = invocation.getArgument(0);\n            final char[] newPassword = config.getComponent(PasswordConfiguration.class).orElseThrow()\n                    .getNewPassword().orElseThrow();\n            this.capturedPasswords.add(new String(newPassword));\n            return null;\n        }).when(this.identityService).updateIdentityConfiguration(this.identityConfigCaptor.capture());\n\n        doAnswer(invocation -> {\n            this.deleteCount.incrementAndGet();\n            return true;\n        }).when(this.identityService).deleteIdentity(anyString());\n    }\n\n    private void givenTemporaryPasswordIsSet() throws Exception {\n        final Field field = ContainerInstance.class.getDeclaredField(\"currentTemporaryPassword\");\n        field.setAccessible(true);\n        @SuppressWarnings(\"unchecked\")\n        final AtomicReference<char[]> passwordRef = (AtomicReference<char[]>) field.get(this.containerInstance);\n        this.lastTemporaryPassword = \"temp-password\".toCharArray();\n        passwordRef.set(this.lastTemporaryPassword);\n    }\n\n    private void givenTemporaryIdentityNameIsSet() throws Exception {\n        final Field field = ContainerInstance.class.getDeclaredField(\"currentTemporaryIdentityName\");\n        field.setAccessible(true);\n        @SuppressWarnings(\"unchecked\")\n        final AtomicReference<String> identityRef = (AtomicReference<String>) field.get(this.containerInstance);\n        identityRef.set(\"temporary_identity\");\n    }\n\n    private void givenContainerOrchestratorFailsToStart() throws Exception {\n        doAnswer(invocation -> {\n            this.startCount.incrementAndGet();\n            throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE);\n        }).when(this.containerOrchestrationService).startContainer(this.configurationCaptor.capture());\n    }\n\n    private void givenFastRetryConfiguration() {\n        this.properties.put(\"container.image.download.retries\", 1);\n        this.properties.put(\"container.image.download.interval\", 0);\n    }\n\n    private void givenHttpsServiceIsEnabledOnPort(final int port) throws Exception {\n        final ComponentConfiguration componentConfiguration = Mockito.mock(ComponentConfiguration.class);\n        final Map<String, Object> properties = new HashMap<>();\n        properties.put(\"https.ports\", new Integer[] { port });\n        when(componentConfiguration.getConfigurationProperties()).thenReturn(properties);\n        when(this.configurationService.getComponentConfiguration(\"org.eclipse.kura.http.server.manager.HttpService\"))\n                .thenReturn(componentConfiguration);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void givenDockerBridgeAddressIs(final String address) throws Exception {\n        final NetworkService networkService = Mockito.mock(NetworkService.class);\n        final NetInterface<NetInterfaceAddress> docker0 = Mockito.mock(NetInterface.class);\n        final NetInterfaceAddress interfaceAddress = Mockito.mock(NetInterfaceAddress.class);\n        final IPAddress ipAddress = Mockito.mock(IPAddress.class);\n\n        when(docker0.getName()).thenReturn(\"docker0\");\n        when(docker0.getNetInterfaceAddresses()).thenReturn(Collections.singletonList(interfaceAddress));\n        when(interfaceAddress.getAddress()).thenReturn(ipAddress);\n        when(ipAddress.getHostAddress()).thenReturn(address);\n        when(networkService.getNetworkInterfaces()).thenReturn(Collections.singletonList(docker0));\n\n        this.containerInstance.setNetworkService(networkService);\n    }\n\n    /*\n     * WHEN\n     */\n\n    private void whenContainerInstanceIsActivated() {\n        this.containerInstance.activate(this.properties);\n    }\n\n    private void whenContainerInstanceIsActivatedUntilCreated() throws InterruptedException {\n        this.containerInstance.activate(this.properties);\n        thenWaitForContainerState(\"Created\");\n    }\n\n    private void whenContainerInstanceIsActivatedUntilDisabled() throws InterruptedException {\n        this.containerInstance.activate(this.properties);\n        thenWaitForContainerState(\"Disabled\");\n    }\n\n    private void whenTemporaryPasswordIsCleared() throws Exception {\n        final Method method = ContainerInstance.class.getDeclaredMethod(\"clearTemporaryPassword\");\n        method.setAccessible(true);\n        method.invoke(this.containerInstance);\n    }\n\n    private void whenTemporaryIdentityIsCleanedUp() throws Exception {\n        final Method method = ContainerInstance.class.getDeclaredMethod(\"cleanupTemporaryIdentity\");\n        method.setAccessible(true);\n        method.invoke(this.containerInstance);\n    }\n\n    private void whenContainerConfigurationIsUpdatedWithNewName() throws InterruptedException {\n        final Map<String, Object> updated = new HashMap<>(this.properties);\n        updated.put(\"container.name\", UPDATED_CONTAINER_NAME);\n        updated.put(\"kura.service.pid\", UPDATED_CONTAINER_NAME);\n\n        this.containerInstance.updated(updated);\n        thenWaitForContainerState(\"Created\");\n    }\n\n    private void whenContainerInstanceIsDisabled() {\n        final Map<String, Object> disabled = new HashMap<>(this.properties);\n        disabled.put(\"container.enabled\", false);\n\n        this.containerInstance.updated(disabled);\n    }\n\n    private void whenContainerInstanceIsDeactivated() {\n        this.containerInstance.deactivate();\n    }\n\n    /*\n     * THEN\n     */\n\n    private void thenTemporaryIdentityIsCreatedWithPermissions() throws Exception {\n        awaitCounterAtLeast(this.createCount, 1);\n\n        final String expectedIdentityName = \"container_\" + CONTAINER_NAME.replace(\"-\", \"_\");\n        verify(this.identityService).createTemporaryIdentity(\n                this.identityNameCaptor.capture(), this.durationCaptor.capture());\n\n        final String createdIdentityName = this.identityNameCaptor.getValue();\n        assertEquals(\"Identity name should match expected\", expectedIdentityName, createdIdentityName);\n\n        verify(this.identityService).updateIdentityConfiguration(this.identityConfigCaptor.capture());\n\n        // Verify identity name from configuration\n        IdentityConfiguration config = this.identityConfigCaptor.getValue();\n        assertEquals(\"Identity name should match expected\", expectedIdentityName, config.getName());\n\n        // Verify permissions from IdentityConfiguration\n        AssignedPermissions assignedPermissions = config.getComponent(AssignedPermissions.class).orElseThrow();\n        Set<Permission> permissions = assignedPermissions.getPermissions();\n\n        assertTrue(\"Expected rest.read permission\",\n                permissions.stream().anyMatch(permission -> \"rest.read\".equals(permission.getName())));\n        assertTrue(\"Expected rest.write permission\",\n                permissions.stream().anyMatch(permission -> \"rest.write\".equals(permission.getName())));\n    }\n\n    private void thenTemporaryIdentityUsesName(final String expectedIdentityName) throws Exception {\n        awaitCounterAtLeast(this.createCount, 1);\n\n        verify(this.identityService).createTemporaryIdentity(\n                this.identityNameCaptor.capture(), this.durationCaptor.capture());\n\n        assertEquals(\"Identity name should be normalized\", expectedIdentityName, this.identityNameCaptor.getValue());\n    }\n\n    private void thenStartContainerReceivesTokenEnvironment() throws Exception {\n        assertTrue(\"Container start was not invoked\", this.startLatch.await(2, TimeUnit.SECONDS));\n\n        final ContainerConfiguration configuration = this.configurationCaptor.getValue();\n        final List<String> envVars = configuration.getContainerEnvVars();\n        final String latestIdentityName = this.capturedIdentityNames.get(this.capturedIdentityNames.size() - 1);\n        final String latestPassword = this.capturedPasswords.get(this.capturedPasswords.size() - 1);\n\n        assertTrue(\"Identity name var missing\",\n                envVars.contains(\"KURA_IDENTITY_NAME=\" + latestIdentityName));\n        assertTrue(\"Password var missing\",\n                envVars.contains(\"KURA_IDENTITY_PASSWORD=\" + latestPassword));\n        // Check that KURA_REST_BASE_URL is set (now dynamic, not hardcoded to localhost:8080)\n        assertTrue(\"Base URL env var missing\",\n                envVars.stream().anyMatch(envVar -> envVar.startsWith(\"KURA_REST_BASE_URL=\")));\n    }\n\n    private void thenTemporaryIdentityIsDeleted() throws Exception {\n        awaitCounterAtLeast(this.deleteCount, 1);\n        assertEquals(\"Temporary identity was not deleted\", 1, this.deleteCount.get());\n        verify(this.identityService).deleteIdentity(this.capturedIdentityNames.get(0));\n    }\n\n    private void thenTemporaryIdentityIsDeletedOnlyOnce() throws Exception {\n        awaitCounterAtLeast(this.deleteCount, 1);\n        assertEquals(\"Temporary identity was not deleted\", 1, this.deleteCount.get());\n        verify(this.identityService, times(1)).deleteIdentity(this.capturedIdentityNames.get(0));\n    }\n\n    private void thenTemporaryIdentityIsRecreated() throws Exception {\n        awaitCounterAtLeast(this.createCount, 2);\n        awaitCounterAtLeast(this.deleteCount, 1);\n        awaitCounterAtLeast(this.startCount, 2);\n\n        assertEquals(\"Temporary identities were not created twice\", 2, this.createCount.get());\n        assertEquals(\"Original temporary identity was not cleaned up\", 1, this.deleteCount.get());\n        assertTrue(\"Container was not started twice\", this.startLatch.await(5, TimeUnit.SECONDS));\n    }\n\n    private void thenLatestContainerStartReceivesRefreshedPassword() {\n        // Extract the latest token from captured IdentityConfiguration\n        final String latestPassword = this.capturedPasswords.get(this.capturedPasswords.size() - 1);\n\n        // Verify the latest container start received this password\n        final List<ContainerConfiguration> configurations = this.configurationCaptor.getAllValues();\n        final ContainerConfiguration latestConfiguration = configurations.get(configurations.size() - 1);\n        final List<String> envVars = latestConfiguration.getContainerEnvVars();\n\n        assertTrue(\"Latest start should include refreshed token\",\n                envVars.contains(\"KURA_IDENTITY_PASSWORD=\" + latestPassword));\n    }\n\n    private void thenTemporaryIdentityCreationIsRetriedWithSuffixedName() throws Exception {\n        awaitCounterAtLeast(this.createCount, 2);\n\n        final String expectedBaseName = \"container_\" + CONTAINER_NAME.replace(\"-\", \"_\");\n        assertEquals(\"First identity creation should use base name\", expectedBaseName, this.capturedIdentityNames.get(0));\n        assertEquals(\"Second identity creation should use suffixed name\", expectedBaseName + \"_1\",\n                this.capturedIdentityNames.get(1));\n    }\n\n    private void thenRestBaseUrlIs(final String expectedBaseUrl) throws Exception {\n        assertTrue(\"Container start was not invoked\", this.startLatch.await(2, TimeUnit.SECONDS));\n\n        final ContainerConfiguration configuration = this.configurationCaptor.getValue();\n        final List<String> envVars = configuration.getContainerEnvVars();\n        final String expectedEnvVar = \"KURA_REST_BASE_URL=\" + expectedBaseUrl;\n\n        assertTrue(\"Base URL env var did not match expected value\", envVars.contains(expectedEnvVar));\n    }\n\n    private void thenTemporaryPasswordIsCleared() throws Exception {\n        final Field field = ContainerInstance.class.getDeclaredField(\"currentTemporaryPassword\");\n        field.setAccessible(true);\n        @SuppressWarnings(\"unchecked\")\n        final AtomicReference<char[]> passwordRef = (AtomicReference<char[]>) field.get(this.containerInstance);\n\n        assertTrue(\"Temporary password should be cleared\", passwordRef.get() == null);\n    }\n\n    private void thenTemporaryPasswordArrayIsCleared() throws Exception {\n        if (this.lastTemporaryPassword == null) {\n            return;\n        }\n\n        for (char value : this.lastTemporaryPassword) {\n            assertTrue(\"Temporary password array should be cleared\", value == '\\0');\n        }\n    }\n\n    private void thenWaitForContainerState(String expectedState) throws InterruptedException {\n        int attempts = 50;\n        while (!expectedState.equals(this.containerInstance.getState()) && attempts-- > 0) {\n            Thread.sleep(100);\n        }\n    }\n\n    private void awaitCounterAtLeast(final AtomicInteger counter, final int expected) throws InterruptedException {\n        int attempts = 50;\n        while (counter.get() < expected && attempts-- > 0) {\n            Thread.sleep(100);\n        }\n        assertTrue(\"Counter did not reach expected value\", counter.get() >= expected);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.provider.test/src/test/java/org/eclipse/kura/container/provider/ContainerInstanceOptionsTest.java",
    "content": "/*******************************************************************************\n  * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n  *\n  * This program and the accompanying materials are made\n  * available under the terms of the Eclipse Public License 2.0\n  * which is available at https://www.eclipse.org/legal/epl-2.0/\n  *\n  * SPDX-License-Identifier: EPL-2.0\n  *\n  * Contributors:\n  *  Eurotech\n  *******************************************************************************/\npackage org.eclipse.kura.container.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration;\nimport org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;\nimport org.junit.Test;\n\npublic class ContainerInstanceOptionsTest {\n\n    private static final boolean DEFAULT_ENABLED = false;\n    private static final String DEFAULT_PORTS_EXTERNAL = \"\";\n    private static final String DEFAULT_CONTAINER_NAME = \"kura_test_container\";\n    private static final String DEFAULT_IMAGE_TAG = \"latest\";\n    private static final String DEFAULT_IMAGE = \"hello-world\";\n    private static final String DEFAULT_PORTS_INTERNAL = \"\";\n    private static final String DEFAULT_CONTAINER_ENV = \"\";\n    private static final String DEFAULT_CONTAINER_PATH_DESTINATION = \"\";\n    private static final String DEFAULT_CONTAINER_PATH_FILE_PATH = \"\";\n    private static final String DEFAULT_CONTAINER_DEVICE = \"\";\n    private static final boolean DEFAULT_CCONTAINER_PRIVILEGED = false;\n    private static final int DEFAULT_CONTAINER_IMAGE_DOWNLOAD_RETRIES = 5;\n    private static final int DEFAULT_CONTAINER_IMAGE_DOWNLOAD_RETRY_INTERVAL = 30000;\n    private static final String DEFAULT_CONTAINER_LOGGER_PARAMETERS = \"\";\n    private static final String DEFAULT_CONTAINER_LOGGING_TYPE = \"default\";\n    private static final String DEFAULT_REGISTRY_URL = \"\";\n    private static final String DEFAULT_REGISTRY_USERNAME = \"\";\n    private static final String DEFAULT_REGISTRY_PASSWORD = \"\";\n    private static final int DEFAULT_IMAGES_DOWNLOAD_TIMEOUT = 500;\n    private static final String DEFAULT_CONTAINER_NETWORKING_MODE = \"\";\n    private static final String DEFAULT_CONTAINER_ENTRY_POINT = \"\";\n    private static final String DEFAULT_CONTAINER_MEMORY = \"\";\n    private static final String DEFAULT_CONTAINER_CPUS = \"\";\n    private static final String DEFAULT_CONTAINER_GPUS = \"\";\n    private static final String DEFAULT_CONTAINER_RUNTIME = \"\";\n    private static final String DEFAULT_ENFORCEMENT_DIGEST = \"\";\n\n    private static final String CONTAINER_ENV = \"container.env\";\n    private static final String CONTAINER_PORTS_INTERNAL = \"container.ports.internal\";\n    private static final String CONTAINER_PORTS_EXTERNAL = \"container.ports.external\";\n    private static final String CONTAINER_NAME = \"kura.service.pid\";\n    private static final String CONTAINER_IMAGE_TAG = \"container.image.tag\";\n    private static final String CONTAINER_IMAGE = \"container.image\";\n    private static final String CONTAINER_ENABLED = \"container.enabled\";\n    private static final String CONTAINER_DEVICE = \"container.device\";\n    private static final String CONTAINER_VOLUME = \"container.volume\";\n    private static final String CONTAINER_PRIVILEGED = \"container.privileged\";\n    private static final String CONTAINER_IMAGE_DOWNLOAD_RETRIES = \"container.image.download.retries\";\n    private static final String CONTAINER_IMAGE_DOWNLOAD_RETRY_INTERVAL = \"container.image.download.interval\";\n    private static final String CONTAINER_LOGGER_PARAMETERS = \"container.loggerParameters\";\n    private static final String CONTAINER_LOGGING_TYPE = \"container.loggingType\";\n    private static final String REGISTRY_URL = \"registry.hostname\";\n    private static final String REGISTRY_USERNAME = \"registry.username\";\n    private static final String REGISTRY_PASSWORD = \"registry.password\";\n    private static final String IMAGES_DOWNLOAD_TIMEOUT = \"container.image.download.timeout\";\n    private static final String CONTAINER_NETWORKING_MODE = \"container.networkMode\";\n    private static final String CONTAINER_ENTRY_POINT = \"container.entrypoint\";\n    private static final String CONTAINER_MEMORY = \"container.memory\";\n    private static final String CONTAINER_CPUS = \"container.cpus\";\n    private static final String CONTAINER_GPUS = \"container.gpus\";\n    private static final String CONTAINER_RUNTIME = \"container.runtime\";\n    private static final String ENFORCEMENT_DIGEST = \"container.signature.enforcement.digest\";\n\n    private Map<String, Object> properties;\n\n    private ContainerInstanceOptions cgdso;\n\n    private boolean enabled;\n    private String image;\n    private String imageTag;\n    private String containerName;\n    private List<String> containerEnv;\n    private Map<String, String> containerVolumes;\n    private List<String> containerDevice;\n    private List<Integer> portsAvailable;\n    private boolean equals;\n    private int hashCode;\n    private boolean privilegedMode;\n\n    private ContainerConfiguration containerDescriptor;\n\n    private Map<String, Object> newProperties;\n    private int imageDownloadRetries;\n    private int imageDownloadRetryInterval;\n    private boolean unlimitedRetries;\n\n    private Optional<String> registryURL;\n    private String registryUsername;\n    private String registryPassword;\n    private int imageDownloadTimeout;\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testNullProperties() {\n        givenNullProperties();\n\n        whenConfigurableGenericDockerServiceOptionsCreated();\n    }\n\n    @Test\n    public void testEnabledDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenIsEnabled();\n\n        thenEnabledStateIs(false);\n\n    }\n\n    @Test\n    public void testEnabled() {\n\n        givenDefaultProperties();\n        givenEnabled(true);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenIsEnabled();\n\n        thenEnabledStateIs(true);\n\n    }\n\n    @Test\n    public void testImageDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImage();\n\n        thenImage(DEFAULT_IMAGE);\n\n    }\n\n    @Test\n    public void testImage() {\n\n        givenDefaultProperties();\n        givenImage(\"test\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImage();\n\n        thenImage(\"test\");\n    }\n\n    @Test\n    public void testImageTagDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImageTag();\n\n        thenImageTag(DEFAULT_IMAGE_TAG);\n\n    }\n\n    @Test\n    public void testImageTag() {\n\n        givenDefaultProperties();\n        givenImageTag(\"test\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImageTag();\n\n        thenImageTag(\"test\");\n    }\n\n    @Test\n    public void testContainerNameDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerName();\n\n        thenContainerName(DEFAULT_CONTAINER_NAME);\n\n    }\n\n    @Test\n    public void testContainerName() {\n\n        givenDefaultProperties();\n        givenContainerName(\"test\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerName();\n\n        thenContainerName(\"test\");\n    }\n\n    @Test\n    public void testContainerEnvDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerEnv();\n\n        thenContainerEnvIsEmpty();\n\n    }\n\n    @Test\n    public void testContainerEnv() {\n\n        givenDefaultProperties();\n        givenContainerEnv(\"test=123\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerEnv();\n\n        thenContainerEnv(\"test=123\");\n    }\n\n    @Test\n    public void testContainerVolumeDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerVolume();\n\n        thenContainerVolumeIsEmpty();\n\n    }\n\n    @Test\n    public void testContainerVolume() {\n\n        givenDefaultProperties();\n        givenContainerVolume(\"test\", \"test\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerVolume();\n\n        thenContainerVolume(\"test\", \"test\");\n    }\n\n    @Test\n    public void testContainerDeviceDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDevice();\n\n        thenContainerDeviceIsEmpty();\n\n    }\n\n    @Test\n    public void testContainerDevice() {\n\n        givenDefaultProperties();\n        givenContainerDevice(\"test\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDevice();\n\n        thenContainerDevice(\"test\");\n    }\n\n    @Test\n    public void testPrivilegedModeDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetPrivilegedMode();\n\n        thenPrivilegedMode(DEFAULT_CCONTAINER_PRIVILEGED);\n\n    }\n\n    @Test\n    public void testPrivilegedMode() {\n\n        givenDefaultProperties();\n        givenPrivilegedMode(true);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetPrivilegedMode();\n\n        thenPrivilegedMode(true);\n    }\n\n    @Test\n    public void testImageDownloadRetriesDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImageDownloadRetries();\n\n        thenImageDownloadRetries(DEFAULT_CONTAINER_IMAGE_DOWNLOAD_RETRIES);\n\n    }\n\n    @Test\n    public void testImageDownloadRetries() {\n\n        givenDefaultProperties();\n        givenImageDownloadRetries(100);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImageDownloadRetries();\n\n        thenImageDownloadRetries(100);\n    }\n\n    @Test\n    public void testRegistryURLDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetRegistryURL();\n\n        thenRegistryURL(DEFAULT_REGISTRY_URL);\n\n    }\n\n    @Test\n    public void testRegistryURL() {\n\n        givenDefaultProperties();\n        givenRegistryURL(\"https://test\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetRegistryURL();\n\n        thenRegistryURL(\"https://test\");\n    }\n\n    @Test\n    public void testImageDownloadUnlimitedRetriesDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetIsUnlimitedRetries();\n\n        thenIsFalse(this.unlimitedRetries);\n\n    }\n\n    @Test\n    public void testImageDownloadUnlimitedRetries() {\n\n        givenDefaultProperties();\n        givenImageDownloadRetries(0);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetIsUnlimitedRetries();\n\n        thenIsTrue(this.unlimitedRetries);\n    }\n\n    @Test\n    public void testImageDownloadRetryIntervalDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImageDownloadRetryInterval();\n\n        thenImageDownloadRetryInterval(DEFAULT_CONTAINER_IMAGE_DOWNLOAD_RETRY_INTERVAL);\n\n    }\n\n    @Test\n    public void testImageDownloadRetryInterval() {\n\n        givenDefaultProperties();\n        givenImageDownloadRetryInterval(100);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImageDownloadRetryInterval();\n\n        thenImageDownloadRetryInterval(100);\n    }\n\n    @Test\n    public void testRegistryUsernameDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetRegistryUsername();\n\n        thenRegistryUsername(DEFAULT_REGISTRY_USERNAME);\n\n    }\n\n    @Test\n    public void testRegistryUsername() {\n\n        givenDefaultProperties();\n        givenRegistryUsername(\"test\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetRegistryUsername();\n\n        thenRegistryUsername(\"test\");\n    }\n\n    @Test\n    public void testRegistryPasswordDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetRegistryPassword();\n\n        thenRegistryPassword(DEFAULT_REGISTRY_PASSWORD);\n\n    }\n\n    @Test\n    public void testRegistryPassword() {\n\n        givenDefaultProperties();\n        givenRegistryPassword(\"test\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetRegistryPassword();\n\n        thenRegistryPassword(\"test\");\n    }\n\n    @Test\n    public void testImageDownloadTimeoutDefault() {\n\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImageDownloadTimeout();\n\n        thenImageDownloadTimeout(DEFAULT_IMAGES_DOWNLOAD_TIMEOUT);\n\n    }\n\n    @Test\n    public void testImageDownloadTimeout() {\n\n        givenDefaultProperties();\n        givenImageDownloadTimeout(100);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetImageDownloadTimeout();\n\n        thenImageDownloadTimeout(100);\n    }\n\n    @Test\n    public void shouldSupportMultipleExternalPortsInOneString() {\n\n        String ports = \"22, 56, 77, 567, 4455\";\n        List<Integer> portResult = new ArrayList<>(Arrays.asList(22, 56, 77, 567, 4455));\n\n        givenDefaultProperties();\n        givenPortsConfiguration(CONTAINER_PORTS_EXTERNAL, ports);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerPortsExternal();\n\n        thenPortResult(portResult);\n\n    }\n\n    @Test\n    public void shouldSupportSingleExternalPortsInOneString() {\n\n        String ports = \"22\";\n        List<Integer> portResult = new ArrayList<>(Arrays.asList(22));\n\n        givenDefaultProperties();\n        givenPortsConfiguration(CONTAINER_PORTS_EXTERNAL, ports);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerPortsExternal();\n\n        thenPortResult(portResult);\n\n    }\n\n    @Test\n    public void shouldSupportSingleBrokenExternalPortsInOneString() {\n\n        String ports = \"22,\";\n        List<Integer> portResult = new ArrayList<>(Arrays.asList(22));\n\n        givenDefaultProperties();\n        givenPortsConfiguration(CONTAINER_PORTS_EXTERNAL, ports);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerPortsExternal();\n\n        thenPortResult(portResult);\n\n    }\n\n    @Test\n    public void testMultipleInternalPortsInOneString() {\n        String ports = \"22, 56, 77, 567, 4455\";\n        List<Integer> portResult = new ArrayList<>(Arrays.asList(22, 56, 77, 567, 4455));\n\n        givenDefaultProperties();\n        givenPortsConfiguration(CONTAINER_PORTS_INTERNAL, ports);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerPortsInternal();\n\n        thenPortResult(portResult);\n    }\n\n    @Test\n    public void testMultipleBrokenInternalPortsInOneString() {\n        String ports = \"56 ,\";\n        List<Integer> portResult = new ArrayList<>(Arrays.asList(56));\n\n        givenDefaultProperties();\n        givenPortsConfiguration(CONTAINER_PORTS_INTERNAL, ports);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerPortsInternal();\n\n        thenPortResult(portResult);\n    }\n\n    @Test\n    public void testSingleInternalPortsInOneString() {\n        String ports = \"56\";\n        List<Integer> portResult = new ArrayList<>(Arrays.asList(56));\n\n        givenDefaultProperties();\n        givenPortsConfiguration(CONTAINER_PORTS_INTERNAL, ports);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerPortsInternal();\n\n        thenPortResult(portResult);\n    }\n\n    @Test\n    public void testOptionsEqualsSameObject() {\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetEquals(this.cgdso);\n        whenGetHashCode(this.cgdso);\n\n        thenIsEqual();\n        thenIsSameHashCode();\n    }\n\n    @Test\n    public void testOptionsEqualsNewSameObject() {\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetEquals(new ContainerInstanceOptions(this.properties));\n\n        thenIsEqual();\n        thenIsNotSameHashCode();\n    }\n\n    @Test\n    public void testOptionsEqualsDifferentObject() {\n        givenDefaultProperties();\n        givenDifferentProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetEquals(new ContainerInstanceOptions(this.newProperties));\n\n        thenIsNotEqual();\n        thenIsNotSameHashCode();\n    }\n\n    @Test\n    public void testOptionsDifferEmptyProperties() {\n        givenDefaultProperties();\n        givenEmptyNewProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetEquals(new ContainerInstanceOptions(this.newProperties));\n\n        thenIsNotEqual();\n        thenIsNotSameHashCode();\n    }\n\n    @Test\n    public void testGetContainerDescriptor() {\n        givenDefaultProperties();\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenIsNotNullContainerDescriptor();\n    }\n\n    @Test\n    public void testExtraCommaInEntryPointFeild() {\n        givenDifferentProperties();\n        givenDiffrentConfigurableGenericDockerServiceOptions();\n\n        thenCheckIfExtraCommasAreIgnored();\n    }\n\n    @Test\n    public void testMemoryOptionEmpty() {\n        givenDefaultProperties();\n        givenMemoryProperty(\"\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenContainerMemoryIsEmpty();\n    }\n\n    @Test\n    public void testMemoryOptionNoSuffix() {\n        testMemoryOption(\"1234\", 1234L);\n    }\n\n    @Test\n    public void testMemoryOptionByteSuffix() {\n        testMemoryOption(\"12345b\", 12345L);\n    }\n\n    @Test\n    public void testMemoryOptionKiloSuffix() {\n        testMemoryOption(\"1111k\", 1137664L);\n    }\n\n    @Test\n    public void testMemoryOptionMegaSuffix() {\n        testMemoryOption(\"2222m\", 2329935872L);\n    }\n\n    @Test\n    public void testMemoryOptionGigaSuffix() {\n        testMemoryOption(\"7g\", 7516192768L);\n    }\n\n    @Test\n    public void testCpusOptionEmpty() {\n        givenDefaultProperties();\n        givenCpusProperty(null);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenContainerCpusIsEmpty();\n    }\n\n    @Test\n    public void testCpusOption() {\n        givenDefaultProperties();\n        givenCpusProperty(1.78F);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenContainerCpusIsNotEmpty();\n        thenContainerCpusIs(1.78F);\n    }\n\n    @Test\n    public void testGpusOptionEmpty() {\n        givenDefaultProperties();\n        givenGpusProperty(null);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenContainerGpusIsEmpty();\n    }\n\n    @Test\n    public void testCpusOptionWithNumber() {\n        givenDefaultProperties();\n        givenGpusProperty(\"2\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenContainerGpusIsNotEmpty();\n        thenContainerGpusIs(\"2\");\n    }\n\n    @Test\n    public void testCpusOptionAll() {\n        givenDefaultProperties();\n        givenGpusProperty(\"all\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenContainerGpusIsNotEmpty();\n        thenContainerGpusIs(\"all\");\n    }\n\n    @Test\n    public void testRuntimeOptionEmpty() {\n        givenDefaultProperties();\n        givenRuntimeProperty(null);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenContainerRuntimeIsEmpty();\n    }\n\n    @Test\n    public void testRuntimeOptionIsSet() {\n        givenDefaultProperties();\n        givenRuntimeProperty(\"coolRuntime\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenContainerRuntimeIsNotEmpty();\n        thenContainerRuntimeIs(\"coolRuntime\");\n    }\n\n    @Test\n    public void testEnforcementDigest() {\n        givenDefaultProperties();\n        givenEnforcementDigestProperty(\"sha256:test\");\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenEnforcementDigestIsNotEmpty();\n        thenEnforcementDigestIs(\"sha256:test\");\n    }\n\n    private void testMemoryOption(String stringValue, Long longValue) {\n        givenDefaultProperties();\n        givenMemoryProperty(stringValue);\n        givenConfigurableGenericDockerServiceOptions();\n\n        whenGetContainerDescriptor();\n\n        thenContainerMemoryIsNotEmpty();\n        thenContainerMemoryIs(longValue);\n    }\n\n    private void givenNullProperties() {\n        this.properties = null;\n    }\n\n    private void givenEmptyNewProperties() {\n        this.newProperties = new HashMap<>();\n    }\n\n    private void givenDefaultProperties() {\n        this.properties = new HashMap<>();\n        this.properties.put(CONTAINER_ENABLED, DEFAULT_ENABLED);\n        this.properties.put(CONTAINER_IMAGE, DEFAULT_IMAGE);\n        this.properties.put(CONTAINER_IMAGE_TAG, DEFAULT_IMAGE_TAG);\n        this.properties.put(CONTAINER_NAME, DEFAULT_CONTAINER_NAME);\n        this.properties.put(CONTAINER_PORTS_EXTERNAL, DEFAULT_PORTS_EXTERNAL);\n        this.properties.put(CONTAINER_PORTS_INTERNAL, DEFAULT_PORTS_INTERNAL);\n        this.properties.put(CONTAINER_ENV, DEFAULT_CONTAINER_ENV);\n        this.properties.put(CONTAINER_VOLUME,\n                DEFAULT_CONTAINER_PATH_FILE_PATH + \":\" + DEFAULT_CONTAINER_PATH_DESTINATION);\n        this.properties.put(CONTAINER_DEVICE, DEFAULT_CONTAINER_DEVICE);\n        this.properties.put(CONTAINER_LOGGING_TYPE, DEFAULT_CONTAINER_LOGGING_TYPE);\n        this.properties.put(CONTAINER_LOGGER_PARAMETERS, DEFAULT_CONTAINER_LOGGER_PARAMETERS);\n        this.properties.put(REGISTRY_URL, DEFAULT_REGISTRY_URL);\n        this.properties.put(REGISTRY_USERNAME, DEFAULT_REGISTRY_USERNAME);\n        this.properties.put(REGISTRY_PASSWORD, DEFAULT_REGISTRY_PASSWORD);\n        this.properties.put(IMAGES_DOWNLOAD_TIMEOUT, DEFAULT_IMAGES_DOWNLOAD_TIMEOUT);\n        this.properties.put(CONTAINER_NETWORKING_MODE, DEFAULT_CONTAINER_NETWORKING_MODE);\n        this.properties.put(CONTAINER_ENTRY_POINT, DEFAULT_CONTAINER_ENTRY_POINT);\n        this.properties.put(CONTAINER_MEMORY, DEFAULT_CONTAINER_MEMORY);\n        this.properties.put(CONTAINER_CPUS, DEFAULT_CONTAINER_CPUS);\n        this.properties.put(CONTAINER_GPUS, DEFAULT_CONTAINER_GPUS);\n        this.properties.put(CONTAINER_RUNTIME, DEFAULT_CONTAINER_RUNTIME);\n        this.properties.put(ENFORCEMENT_DIGEST, DEFAULT_ENFORCEMENT_DIGEST);\n    }\n\n    private void givenDifferentProperties() {\n        this.newProperties = new HashMap<>();\n        this.newProperties.put(CONTAINER_ENABLED, true);\n        this.newProperties.put(CONTAINER_IMAGE, \"myimage\");\n        this.newProperties.put(CONTAINER_IMAGE_TAG, \"mytag\");\n        this.newProperties.put(CONTAINER_NAME, \"myname\");\n        this.newProperties.put(CONTAINER_PORTS_EXTERNAL, \"\");\n        this.newProperties.put(CONTAINER_PORTS_INTERNAL, \"\");\n        this.newProperties.put(CONTAINER_ENV, \"\");\n        this.newProperties.put(CONTAINER_VOLUME, \"diffrent:diffrent\");\n        this.newProperties.put(CONTAINER_DEVICE, \"\");\n        this.newProperties.put(CONTAINER_LOGGING_TYPE, \"JOURNALD\");\n        this.newProperties.put(CONTAINER_LOGGER_PARAMETERS, \"label=true\");\n\n        this.newProperties.put(REGISTRY_URL, \"https://something\");\n        this.newProperties.put(REGISTRY_USERNAME, \"test\");\n        this.newProperties.put(REGISTRY_PASSWORD, \"test\");\n        this.newProperties.put(IMAGES_DOWNLOAD_TIMEOUT, 100);\n        this.newProperties.put(CONTAINER_NETWORKING_MODE, \"none\");\n        this.newProperties.put(CONTAINER_ENTRY_POINT, \"./test.py,-v,-m,--human-readable,,,\");\n        this.newProperties.put(CONTAINER_MEMORY, \"100m\");\n        this.newProperties.put(CONTAINER_CPUS, \"1.5\");\n        this.newProperties.put(CONTAINER_RUNTIME, \"myRuntime\");\n        this.newProperties.put(ENFORCEMENT_DIGEST, \"\");\n    }\n\n    private void givenMemoryProperty(String memory) {\n        if (this.properties != null) {\n            this.properties.put(CONTAINER_MEMORY, memory);\n        }\n    }\n\n    private void givenCpusProperty(Float cpus) {\n        if (this.properties != null) {\n            this.properties.put(CONTAINER_CPUS, cpus);\n        }\n    }\n\n    private void givenGpusProperty(String gpus) {\n        if (this.properties != null) {\n            this.properties.put(CONTAINER_GPUS, gpus);\n        }\n    }\n\n    private void givenRuntimeProperty(String runtime) {\n        if (this.properties != null) {\n            this.properties.put(CONTAINER_RUNTIME, runtime);\n        }\n    }\n\n    private void givenEnforcementDigestProperty(String digest) {\n        if (this.properties != null) {\n            this.properties.put(ENFORCEMENT_DIGEST, digest);\n        }\n    }\n\n    private void givenConfigurableGenericDockerServiceOptions() {\n        this.cgdso = new ContainerInstanceOptions(this.properties);\n    }\n\n    private void givenDiffrentConfigurableGenericDockerServiceOptions() {\n        this.cgdso = new ContainerInstanceOptions(this.newProperties);\n    }\n\n    private void givenEnabled(boolean b) {\n        this.properties.put(CONTAINER_ENABLED, b);\n    }\n\n    private void givenImage(String value) {\n        this.properties.put(CONTAINER_IMAGE, value);\n    }\n\n    private void givenImageTag(String value) {\n        this.properties.put(CONTAINER_IMAGE_TAG, value);\n    }\n\n    private void givenContainerName(String value) {\n        this.properties.put(CONTAINER_NAME, value);\n    }\n\n    private void givenContainerEnv(String value) {\n        this.properties.put(CONTAINER_ENV, value);\n    }\n\n    private void givenPrivilegedMode(boolean value) {\n        this.properties.put(CONTAINER_PRIVILEGED, value);\n    }\n\n    private void givenImageDownloadRetries(int value) {\n        this.properties.put(CONTAINER_IMAGE_DOWNLOAD_RETRIES, value);\n    }\n\n    private void givenImageDownloadRetryInterval(int value) {\n        this.properties.put(CONTAINER_IMAGE_DOWNLOAD_RETRY_INTERVAL, value);\n    }\n\n    private void givenContainerVolume(String source, String dest) {\n        this.properties.put(CONTAINER_VOLUME, source + \":\" + dest);\n    }\n\n    private void givenContainerDevice(String value) {\n        this.properties.put(CONTAINER_DEVICE, value);\n    }\n\n    private void givenRegistryURL(String value) {\n        this.properties.put(REGISTRY_URL, value);\n    }\n\n    private void givenRegistryUsername(String username) {\n        this.properties.put(REGISTRY_USERNAME, username);\n    }\n\n    private void givenRegistryPassword(String password) {\n        this.properties.put(REGISTRY_PASSWORD, password);\n    }\n\n    private void givenImageDownloadTimeout(int value) {\n        this.properties.put(IMAGES_DOWNLOAD_TIMEOUT, value);\n    }\n\n    private void givenPortsConfiguration(String portProperty, String Ports) {\n        this.properties.put(portProperty, Ports);\n    }\n\n    private void whenConfigurableGenericDockerServiceOptionsCreated() {\n        this.cgdso = new ContainerInstanceOptions(this.properties);\n    }\n\n    private void whenIsEnabled() {\n        this.enabled = this.cgdso.isEnabled();\n    }\n\n    private void whenGetImage() {\n        this.image = this.cgdso.getContainerImage();\n    }\n\n    private void whenGetImageTag() {\n        this.imageTag = this.cgdso.getContainerImageTag();\n    }\n\n    private void whenGetContainerName() {\n        this.containerName = this.cgdso.getContainerName();\n    }\n\n    private void whenGetContainerEnv() {\n        this.containerEnv = this.cgdso.getContainerEnvList();\n    }\n\n    private void whenGetPrivilegedMode() {\n        this.privilegedMode = this.cgdso.getPrivilegedMode();\n    }\n\n    private void whenGetImageDownloadRetries() {\n        this.imageDownloadRetries = this.cgdso.getMaxDownloadRetries();\n    }\n\n    private void whenGetIsUnlimitedRetries() {\n        this.unlimitedRetries = this.cgdso.isUnlimitedRetries();\n    }\n\n    private void whenGetImageDownloadRetryInterval() {\n        this.imageDownloadRetryInterval = this.cgdso.getRetryInterval();\n    }\n\n    private void whenGetContainerVolume() {\n        this.containerVolumes = this.cgdso.getContainerVolumeList();\n    }\n\n    private void whenGetContainerDevice() {\n        this.containerDevice = this.cgdso.getContainerDeviceList();\n    }\n\n    private void whenGetContainerPortsExternal() {\n        this.portsAvailable = this.cgdso.getContainerPortsExternal();\n    }\n\n    private void whenGetContainerPortsInternal() {\n        this.portsAvailable = this.cgdso.getContainerPortsInternal();\n    }\n\n    private void whenGetRegistryURL() {\n        PasswordRegistryCredentials registryCredentials = (PasswordRegistryCredentials) this.cgdso\n                .getRegistryCredentials().get();\n        this.registryURL = registryCredentials.getUrl();\n    }\n\n    private void whenGetRegistryUsername() {\n        PasswordRegistryCredentials registryCredentials = (PasswordRegistryCredentials) this.cgdso\n                .getRegistryCredentials().get();\n        this.registryUsername = registryCredentials.getUsername();\n    }\n\n    private void whenGetRegistryPassword() {\n        PasswordRegistryCredentials registryCredentials = (PasswordRegistryCredentials) this.cgdso\n                .getRegistryCredentials().get();\n        this.registryPassword = new String(registryCredentials.getPassword().getPassword());\n    }\n\n    private void whenGetImageDownloadTimeout() {\n        this.imageDownloadTimeout = this.cgdso.getImageDownloadTimeout();\n    }\n\n    private void whenGetEquals(ContainerInstanceOptions options) {\n        this.equals = this.cgdso.equals(options);\n    }\n\n    private void whenGetHashCode(ContainerInstanceOptions options) {\n        this.hashCode = options.hashCode();\n    }\n\n    private void whenGetContainerDescriptor() {\n        this.containerDescriptor = this.cgdso.getContainerConfiguration();\n    }\n\n    private void thenEnabledStateIs(boolean b) {\n        assertEquals(b, this.enabled);\n    }\n\n    private void thenImage(String expectedValue) {\n        assertEquals(expectedValue, this.image);\n    }\n\n    private void thenImageTag(String expectedValue) {\n        assertEquals(expectedValue, this.imageTag);\n    }\n\n    private void thenContainerName(String expectedValue) {\n        assertEquals(expectedValue, this.containerName);\n    }\n\n    private void thenContainerEnv(String expectedValue) {\n        assertTrue(this.containerEnv.contains(expectedValue));\n    }\n\n    private void thenContainerEnvIsEmpty() {\n        assertTrue(this.containerEnv.isEmpty());\n    }\n\n    private void thenPrivilegedMode(boolean expectedValue) {\n        assertEquals(expectedValue, this.privilegedMode);\n    }\n\n    private void thenImageDownloadRetries(int expectedValue) {\n        assertEquals(expectedValue, this.imageDownloadRetries);\n    }\n\n    private void thenRegistryURL(String expectedValue) {\n        assertEquals(expectedValue, this.registryURL.get());\n    }\n\n    private void thenRegistryUsername(String expectedValue) {\n        assertEquals(expectedValue, this.registryUsername);\n    }\n\n    private void thenRegistryPassword(String expectedValue) {\n        assertEquals(expectedValue, this.registryPassword);\n    }\n\n    private void thenImageDownloadTimeout(int expectedValue) {\n        assertEquals(expectedValue, this.imageDownloadTimeout);\n    }\n\n    private void thenImageDownloadRetryInterval(int expectedValue) {\n        assertEquals(expectedValue, this.imageDownloadRetryInterval);\n    }\n\n    private void thenContainerVolume(String expectedSourceValue, String expectedDestinationValue) {\n        assertTrue(this.containerVolumes.containsKey(expectedSourceValue));\n        assertTrue(this.containerVolumes.containsValue(expectedDestinationValue));\n    }\n\n    private void thenContainerVolumeIsEmpty() {\n        assertTrue(this.containerVolumes.isEmpty());\n    }\n\n    private void thenContainerDevice(String expectedValue) {\n        assertTrue(this.containerDevice.contains(expectedValue));\n    }\n\n    private void thenContainerDeviceIsEmpty() {\n        assertTrue(this.containerDevice.isEmpty());\n    }\n\n    private void thenPortResult(List<Integer> portResult) {\n        assertEquals(portResult, this.portsAvailable);\n    }\n\n    private void thenIsEqual() {\n        assertTrue(this.equals);\n    }\n\n    private void thenIsNotEqual() {\n        assertFalse(this.equals);\n    }\n\n    private void thenIsTrue(boolean expectedValue) {\n        assertTrue(expectedValue);\n    }\n\n    private void thenIsFalse(boolean expectedValue) {\n        assertFalse(expectedValue);\n    }\n\n    private void thenIsSameHashCode() {\n        assertEquals(this.cgdso.hashCode(), this.hashCode);\n    }\n\n    private void thenIsNotSameHashCode() {\n        assertNotEquals(this.cgdso.hashCode(), this.hashCode);\n    }\n\n    private void thenIsNotNullContainerDescriptor() {\n        assertNotNull(this.containerDescriptor);\n    }\n\n    private void thenCheckIfExtraCommasAreIgnored() {\n        assertEquals(Arrays.asList(\"./test.py\", \"-v\", \"-m\", \"--human-readable\"), this.cgdso.getEntryPoint());\n    }\n\n    private void thenContainerMemoryIsEmpty() {\n        assertFalse(this.containerDescriptor.getMemory().isPresent());\n    }\n\n    private void thenContainerMemoryIsNotEmpty() {\n        assertTrue(this.containerDescriptor.getMemory().isPresent());\n    }\n\n    private void thenContainerMemoryIs(Long value) {\n        assertEquals(this.containerDescriptor.getMemory().get(), value);\n    }\n\n    private void thenContainerCpusIsEmpty() {\n        assertFalse(this.containerDescriptor.getCpus().isPresent());\n    }\n\n    private void thenContainerCpusIsNotEmpty() {\n        assertTrue(this.containerDescriptor.getCpus().isPresent());\n    }\n\n    private void thenContainerCpusIs(Float value) {\n        assertEquals(this.containerDescriptor.getCpus().get(), value);\n    }\n\n    private void thenContainerGpusIsEmpty() {\n        assertFalse(this.containerDescriptor.getGpus().isPresent());\n    }\n\n    private void thenContainerGpusIsNotEmpty() {\n        assertTrue(this.containerDescriptor.getGpus().isPresent());\n    }\n\n    private void thenContainerGpusIs(String value) {\n        assertEquals(this.containerDescriptor.getGpus().get(), value);\n    }\n\n    private void thenContainerRuntimeIsEmpty() {\n        assertFalse(this.containerDescriptor.getRuntime().isPresent());\n    }\n\n    private void thenContainerRuntimeIsNotEmpty() {\n        assertTrue(this.containerDescriptor.getRuntime().isPresent());\n    }\n\n    private void thenContainerRuntimeIs(String value) {\n        assertEquals(this.containerDescriptor.getRuntime().get(), value);\n    }\n\n    private void thenEnforcementDigestIsNotEmpty() {\n        assertTrue(this.containerDescriptor.getEnforcementDigest().isPresent());\n    }\n\n    private void thenEnforcementDigestIs(String value) {\n        assertEquals(this.containerDescriptor.getEnforcementDigest().get(), value);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.container.provider.test/src/test/java/org/eclipse/kura/container/provider/ContainerInstanceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.container.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyBoolean;\nimport static org.mockito.ArgumentMatchers.anyMap;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doNothing;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.never;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.container.orchestration.ContainerConfiguration;\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ContainerOrchestrationService;\nimport org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;\nimport org.eclipse.kura.container.orchestration.RegistryCredentials;\nimport org.eclipse.kura.container.signature.ContainerSignatureValidationService;\nimport org.eclipse.kura.container.signature.ValidationResult;\nimport org.junit.After;\nimport org.junit.Test;\n\npublic class ContainerInstanceTest {\n\n    private static final String CONTAINER_NAME = \"container.name\";\n    private static final String CONTAINER_IMAGE_TAG = \"container.image.tag\";\n    private static final String CONTAINER_IMAGE = \"container.image\";\n    private static final String CONTAINER_ENABLED = \"container.enabled\";\n    private static final String CONTAINER_TRUST_ANCHOR = \"container.signature.trust.anchor\";\n    private static final String CONTAINER_VERIFY_TLOG = \"container.signature.verify.transparency.log\";\n    private static final String CONTAINER_REGISTRY_USERNAME = \"registry.username\";\n    private static final String CONTAINER_REGISTRY_PASSWORD = \"registry.password\";\n    private static final String CONTAINER_ENFORCEMENT_DIGEST = \"container.signature.enforcement.digest\";\n\n    private static final ValidationResult FAILED_VALIDATION = new ValidationResult();\n\n    private static final String CONTAINER_STATE_CREATED = \"Created\";\n    private static final String CONTAINER_STATE_DISABLED = \"Disabled\";\n\n    private ContainerOrchestrationService mockContainerOrchestrationService = mock(ContainerOrchestrationService.class);\n    private ContainerSignatureValidationService mockContainerSignatureValidationService = mock(\n            ContainerSignatureValidationService.class);\n    private Map<String, Object> properties = new HashMap<>();\n    private Map<String, Object> newProperties = new HashMap<>();\n    private String signatureExtractedDigest;\n    private Map<String, Object> signatureUpdatedProperties;\n    private ContainerInstance containerInstance = new ContainerInstance();\n    private Exception occurredException;\n\n    @Test\n    public void activateContainerInstanceWithNullPropertiesThrows() {\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        whenActivateInstanceIsCalledWith(null);\n\n        thenExceptionOccurred(IllegalArgumentException.class);\n    }\n\n    @Test\n    public void activateContainerInstanceWithDisabledContainerWorks() throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, false);\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_DISABLED);\n        thenStartContainerWasNeverCalled();\n    }\n\n    @Test\n    public void activateContainerInstanceWithEnabledContainerWorks() throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"myContainer\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n        thenStopContainerWasNeverCalled();\n        thenStartContainerWasCalledWith(this.properties);\n    }\n\n    @Test\n    public void activateContainerInstanceWithDisconnectedContainerOrchestratorWorks()\n            throws KuraException, InterruptedException {\n        givenContainerOrchestratorIsNotConnected();\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"myContainer\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_DISABLED);\n        thenStartContainerWasNeverCalled();\n    }\n\n    @Test\n    public void activateContainerInstanceWithAreadyRunningContainerWorksWithDisabled()\n            throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithRunningContainer(\"myRunningContainer\", \"123456\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, false);\n        givenPropertiesWith(CONTAINER_NAME, \"myRunningContainer\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_DISABLED);\n\n        thenStartContainerWasNeverCalled();\n        thenStopContainerWasCalledFor(\"123456\");\n        thenDeleteContainerWasCalledFor(\"123456\");\n    }\n\n    @Test\n    public void activateContainerInstanceWithAreadyRunningContainerWorksWithEnabled()\n            throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithRunningContainer(\"myRunningContainer\", \"123456\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"myRunningContainer\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n\n        // Are we sure about this?\n        thenStartContainerWasCalledWith(this.properties);\n    }\n\n    @Test\n    public void updateContainerInstanceWithNullPropertiesThrows() throws KuraException, InterruptedException {\n        givenPropertiesWith(CONTAINER_ENABLED, false);\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n        givenContainerInstanceActivatedWith(this.properties);\n\n        whenUpdateInstanceIsCalledWith(null);\n\n        thenExceptionOccurred(IllegalArgumentException.class);\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_DISABLED);\n        thenStopContainerWasNeverCalled();\n        thenStartContainerWasNeverCalled();\n        thenDeleteContainerWasNeverCalled();\n    }\n\n    @Test\n    public void updateContainerInstanceWithSamePropertiesWorks() throws KuraException {\n        givenPropertiesWith(CONTAINER_ENABLED, false);\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n        givenContainerInstanceActivatedWith(this.properties);\n\n        whenUpdateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_DISABLED);\n        thenStopContainerWasNeverCalled();\n        thenDeleteContainerWasNeverCalled();\n    }\n\n    @Test\n    public void updateDisabledContainerInstanceWithEnabledContainerWorks() throws KuraException, InterruptedException {\n        givenPropertiesWith(CONTAINER_ENABLED, false);\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n        givenContainerInstanceActivatedWith(this.properties);\n\n        givenNewPropertiesWith(CONTAINER_ENABLED, true);\n        givenNewPropertiesWith(CONTAINER_NAME, \"myContainer\");\n        givenNewPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenNewPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n\n        whenUpdateInstanceIsCalledWith(this.newProperties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n        thenStartContainerWasCalledWith(this.newProperties);\n    }\n\n    @Test\n    public void updateEnabledContainerInstanceWithDisabledContainerWorks() throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"pippo\");\n        givenContainerInstanceActivatedWith(this.properties);\n        givenContainerStateIs(CONTAINER_STATE_CREATED);\n\n        givenContainerOrchestratorWithRunningContainer(\"pippo\", \"1234\");\n        givenNewPropertiesWith(CONTAINER_ENABLED, false);\n\n        whenUpdateInstanceIsCalledWith(this.newProperties);\n\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_DISABLED);\n        thenNoExceptionOccurred();\n        thenStopContainerWasCalledFor(\"1234\");\n        thenDeleteContainerWasCalledFor(\"1234\");\n    }\n\n    @Test\n    public void deactivateContainerInstanceWithDisabledContainerWorks() throws KuraException, InterruptedException {\n        givenPropertiesWith(CONTAINER_ENABLED, false);\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n        givenContainerInstanceActivatedWith(this.properties);\n\n        whenDeactivateInstanceIsCalled();\n\n        thenNoExceptionOccurred();\n        thenStartContainerWasNeverCalled();\n    }\n\n    @Test\n    public void deactivateContainerInstanceWithEnabledContainerWorks() throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"pippo\");\n        givenContainerInstanceActivatedWith(this.properties);\n        givenContainerStateIs(CONTAINER_STATE_CREATED);\n\n        givenContainerOrchestratorWithRunningContainer(\"pippo\", \"1234\");\n\n        whenDeactivateInstanceIsCalled();\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_DISABLED);\n        thenStopContainerWasCalledFor(\"1234\");\n        thenDeleteContainerWasCalledFor(\"1234\");\n    }\n\n    @Test\n    public void disabledInstanceDeletesAlreadyRunningContainerWithSameName()\n            throws KuraException, InterruptedException {\n\n        givenContainerOrchestratorWithRunningContainer(\"test-instance\", \"test-id\");\n\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, false);\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n        givenPropertiesWith(CONTAINER_NAME, \"test-instance\");\n        givenPropertiesWith(\"kura.service.pid\", \"test-instance\");\n        givenContainerInstanceActivatedWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_DISABLED);\n        thenStopContainerWasCalledFor(\"test-id\");\n        thenDeleteContainerWasCalledFor(\"test-id\");\n\n    }\n\n    @Test\n    public void signatureValidationDoesntGetCalledWithMissingTrustAnchor() throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenContainerSignatureValidationServiceReturningFailureFor(\"nginx\", \"latest\");\n        givenContainerInstanceWith(this.mockContainerSignatureValidationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"pippo\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n        givenPropertiesWith(CONTAINER_VERIFY_TLOG, true);\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n        thenStartContainerWasCalledWith(this.properties);\n        thenVerifySignatureWasNeverCalled();\n    }\n\n    @Test\n    public void signatureValidationDoesntGetCalledWithInvalidTrustAnchor() throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenContainerSignatureValidationServiceReturningFailureFor(\"nginx\", \"latest\");\n        givenContainerInstanceWith(this.mockContainerSignatureValidationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"pippo\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n        givenPropertiesWith(CONTAINER_TRUST_ANCHOR, \"\");\n        givenPropertiesWith(CONTAINER_VERIFY_TLOG, true);\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n        thenStartContainerWasCalledWith(this.properties);\n        thenVerifySignatureWasNeverCalled();\n    }\n\n    @Test\n    public void signatureValidationDoesntGetCalledWithMissingSignatureValidationService()\n            throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"pippo\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n        givenPropertiesWith(CONTAINER_TRUST_ANCHOR, \"anotherRealTrustAnchor ;)\");\n        givenPropertiesWith(CONTAINER_VERIFY_TLOG, true);\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n        thenStartContainerWasCalledWith(this.properties);\n        thenVerifySignatureWasNeverCalled();\n    }\n\n    @Test\n    public void signatureValidationWorks() throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n        givenMockedConfigurationService();\n\n        givenContainerSignatureValidationServiceReturningSuccessFor(\"nginx\", \"latest\");\n        givenContainerInstanceWith(this.mockContainerSignatureValidationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"pippo\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n        givenPropertiesWith(CONTAINER_TRUST_ANCHOR, \"aRealTrustAnchor ;)\");\n        givenPropertiesWith(CONTAINER_VERIFY_TLOG, true);\n\n        givenSignatureUpdatedProperties(CONTAINER_ENFORCEMENT_DIGEST, this.signatureExtractedDigest);\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n        thenStartContainerWasCalledWith(this.signatureUpdatedProperties);\n        thenVerifySignatureWasCalledFor(\"nginx\", \"latest\", \"aRealTrustAnchor ;)\", true);\n    }\n\n    @Test\n    public void signatureValidationWorksWithThrowingValidationService() throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenContainerSignatureValidationServiceThrows();\n        givenContainerInstanceWith(this.mockContainerSignatureValidationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"pippo\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n        givenPropertiesWith(CONTAINER_TRUST_ANCHOR, \"aRealTrustAnchor ;)\");\n        givenPropertiesWith(CONTAINER_VERIFY_TLOG, true);\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n        thenStartContainerWasCalledWith(this.properties);\n        thenVerifySignatureWasCalledFor(\"nginx\", \"latest\", \"aRealTrustAnchor ;)\", true);\n    }\n\n    @Test\n    public void signatureValidationWorksWithAuthenticationWhenNoDigestProvided()\n            throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n\n        givenContainerSignatureValidationServiceReturningFailureForAuthenticated(\"nginx\", \"latest\");\n        givenContainerInstanceWith(this.mockContainerSignatureValidationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"pippo\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n        givenPropertiesWith(CONTAINER_TRUST_ANCHOR, \"aRealTrustAnchor ;)\");\n        givenPropertiesWith(CONTAINER_VERIFY_TLOG, true);\n        givenPropertiesWith(CONTAINER_REGISTRY_USERNAME, \"username\");\n        givenPropertiesWith(CONTAINER_REGISTRY_PASSWORD, \"password\");\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n        thenStartContainerWasCalledWith(this.properties);\n        thenAuthenticatedVerifySignatureWasCalledFor(\"nginx\", \"latest\", \"aRealTrustAnchor ;)\", true,\n                new PasswordRegistryCredentials(Optional.empty(), \"username\", new Password(\"password\")));\n    }\n\n    @Test\n    public void signatureValidationNotCalledIfDigestProvided() throws KuraException, InterruptedException {\n        givenContainerOrchestratorWithNoRunningContainers();\n        givenContainerOrchestratorReturningOnStart(\"1234\");\n        givenContainerInstanceWith(this.mockContainerOrchestrationService);\n        givenMockedConfigurationService();\n\n        givenContainerSignatureValidationServiceReturningFailureForAuthenticated(\"nginx\", \"latest\");\n        givenContainerInstanceWith(this.mockContainerSignatureValidationService);\n\n        givenPropertiesWith(CONTAINER_ENABLED, true);\n        givenPropertiesWith(CONTAINER_NAME, \"pippo\");\n        givenPropertiesWith(CONTAINER_IMAGE, \"nginx\");\n        givenPropertiesWith(CONTAINER_IMAGE_TAG, \"latest\");\n        givenPropertiesWith(CONTAINER_TRUST_ANCHOR, \"aRealTrustAnchor ;)\");\n        givenPropertiesWith(CONTAINER_VERIFY_TLOG, true);\n        givenPropertiesWith(CONTAINER_REGISTRY_USERNAME, \"username\");\n        givenPropertiesWith(CONTAINER_REGISTRY_PASSWORD, \"password\");\n        givenPropertiesWith(CONTAINER_ENFORCEMENT_DIGEST, \"sha256:test\");\n\n        whenActivateInstanceIsCalledWith(this.properties);\n\n        thenNoExceptionOccurred();\n        thenWaitForContainerInstanceToBecome(CONTAINER_STATE_CREATED);\n        thenStartContainerWasCalledWith(this.properties);\n        thenVerifySignatureWasNeverCalled();\n    }\n\n    @After\n    public void tearDown() {\n        this.containerInstance.deactivate();\n    }\n\n    /*\n     * GIVEN\n     */\n\n    private void givenContainerInstanceWith(ContainerOrchestrationService cos) {\n        this.containerInstance.setContainerOrchestrationService(cos);\n    }\n\n    private void givenPropertiesWith(String key, Object value) {\n        this.properties.put(key, value);\n    }\n\n    private void givenNewPropertiesWith(String key, Object value) {\n        this.newProperties.put(key, value);\n    }\n\n    private void givenSignatureUpdatedProperties(String key, Object value) {\n        this.signatureUpdatedProperties = new HashMap<>(this.properties);\n        this.signatureUpdatedProperties.put(key, value);\n    }\n\n    private void givenContainerInstanceActivatedWith(Map<String, Object> configuration) {\n        try {\n            this.containerInstance.activate(configuration);\n        } catch (Exception e) {\n            fail(\"Failed to activate container instance. Caused by: \" + e.getMessage());\n        }\n    }\n\n    private void givenContainerStateIs(String expectedState) {\n        int count = 10;\n        do {\n            try {\n                Thread.sleep(100);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        } while (!expectedState.equals(this.containerInstance.getState()) && count-- > 0);\n\n        if (count <= 0) {\n            fail(String.format(\"Container instance state is not \\\"%s\\\" (currently \\\"%s\\\")\", expectedState,\n                    this.containerInstance.getState()));\n        }\n    }\n\n    private void givenContainerOrchestratorIsNotConnected() throws KuraException, InterruptedException {\n        when(this.mockContainerOrchestrationService.listContainerDescriptors())\n                .thenThrow(new IllegalStateException(\"Not connected\"));\n    }\n\n    private void givenContainerOrchestratorWithNoRunningContainers() {\n        when(this.mockContainerOrchestrationService.listContainerDescriptors()).thenReturn(Collections.emptyList());\n    }\n\n    private void givenContainerOrchestratorWithRunningContainer(String containerName, String containerId) {\n        List<ContainerInstanceDescriptor> runningContainers = Collections.singletonList(ContainerInstanceDescriptor\n                .builder().setContainerName(containerName).setContainerID(containerId).build());\n        when(this.mockContainerOrchestrationService.listContainerDescriptors()).thenReturn(runningContainers);\n    }\n\n    private void givenContainerOrchestratorReturningOnStart(String containerId)\n            throws KuraException, InterruptedException {\n        when(this.mockContainerOrchestrationService.startContainer(any(ContainerConfiguration.class)))\n                .thenReturn(containerId);\n    }\n\n    private void givenContainerSignatureValidationServiceReturningFailureFor(String imageName, String imageTag)\n            throws KuraException {\n        when(this.mockContainerSignatureValidationService.verify(eq(imageName), eq(imageTag), any(String.class),\n                any(Boolean.class))).thenReturn(FAILED_VALIDATION);\n    }\n\n    private void givenContainerSignatureValidationServiceReturningSuccessFor(String imageName, String imageTag)\n            throws KuraException {\n        // Generate random sha256 string\n        this.signatureExtractedDigest = \"sha256:\" + Long.toHexString(Double.doubleToLongBits(Math.random()));\n        when(this.mockContainerSignatureValidationService.verify(eq(imageName), eq(imageTag), any(String.class),\n                any(Boolean.class))).thenReturn(new ValidationResult(true, this.signatureExtractedDigest));\n    }\n\n    private void givenContainerSignatureValidationServiceReturningFailureForAuthenticated(String imageName,\n            String imageTag) throws KuraException {\n        when(this.mockContainerSignatureValidationService.verify(eq(imageName), eq(imageTag), any(String.class),\n                any(Boolean.class), any(RegistryCredentials.class))).thenReturn(FAILED_VALIDATION);\n    }\n\n    private void givenContainerSignatureValidationServiceThrows() throws KuraException {\n        when(this.mockContainerSignatureValidationService.verify(any(String.class), any(String.class),\n                any(String.class), any(Boolean.class))).thenThrow(new KuraException(KuraErrorCode.SECURITY_EXCEPTION));\n    }\n\n    private void givenContainerInstanceWith(ContainerSignatureValidationService signatureValidationService) {\n        this.containerInstance.setContainerSignatureValidationService(signatureValidationService);\n    }\n\n    private void givenMockedConfigurationService() throws KuraException {\n        ConfigurationService mockedConfigurationService = mock(ConfigurationService.class);\n        doNothing().when(mockedConfigurationService).updateConfiguration(anyString(), anyMap(), anyBoolean());\n        this.containerInstance.setConfigurationService(mockedConfigurationService);\n    }\n\n    /*\n     * WHEN\n     */\n\n    private void whenActivateInstanceIsCalledWith(Map<String, Object> configuration) {\n        try {\n            this.containerInstance.activate(configuration);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenUpdateInstanceIsCalledWith(Map<String, Object> configuration) {\n        try {\n            this.containerInstance.updated(configuration);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenDeactivateInstanceIsCalled() {\n        try {\n            this.containerInstance.deactivate();\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * THEN\n     */\n\n    private void thenWaitForContainerInstanceToBecome(String expectedState) {\n        int count = 10;\n        do {\n            try {\n                Thread.sleep(200);\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        } while (!expectedState.equals(this.containerInstance.getState()) && count-- > 0);\n\n        assertEquals(expectedState, this.containerInstance.getState());\n    }\n\n    private void thenStopContainerWasNeverCalled() throws KuraException {\n        verify(this.mockContainerOrchestrationService, never()).stopContainer(any(String.class));\n    }\n\n    private void thenStopContainerWasCalledFor(String containerId) throws KuraException {\n        verify(this.mockContainerOrchestrationService, times(1)).stopContainer(containerId);\n    }\n\n    private void thenStartContainerWasNeverCalled() throws KuraException, InterruptedException {\n        verify(this.mockContainerOrchestrationService, times(0)).startContainer(any(ContainerConfiguration.class));\n    }\n\n    private void thenStartContainerWasCalledWith(Map<String, Object> props) throws KuraException, InterruptedException {\n        ContainerInstanceOptions options = new ContainerInstanceOptions(props);\n        verify(this.mockContainerOrchestrationService, times(1)).startContainer(options.getContainerConfiguration());\n    }\n\n    private void thenDeleteContainerWasNeverCalled() throws KuraException {\n        verify(this.mockContainerOrchestrationService, never()).deleteContainer(any(String.class));\n    }\n\n    private void thenDeleteContainerWasCalledFor(String containerId) throws KuraException {\n        verify(this.mockContainerOrchestrationService, times(1)).deleteContainer(containerId);\n    }\n\n    private void thenVerifySignatureWasNeverCalled() throws KuraException {\n        verify(this.mockContainerSignatureValidationService, never()).verify(any(String.class), any(String.class),\n                any(String.class), any(Boolean.class));\n        verify(this.mockContainerSignatureValidationService, never()).verify(any(String.class), any(String.class),\n                any(String.class), any(Boolean.class), any(RegistryCredentials.class));\n    }\n\n    private void thenVerifySignatureWasCalledFor(String imageName, String imageTag, String trustAnchor,\n            boolean verifyTlog) throws KuraException {\n        verify(this.mockContainerSignatureValidationService, times(1)).verify(imageName, imageTag, trustAnchor,\n                verifyTlog);\n    }\n\n    private void thenAuthenticatedVerifySignatureWasCalledFor(String imageName, String imageTag, String trustAnchor,\n            boolean verifyTlog, PasswordRegistryCredentials passwordRegistryCredentials) throws KuraException {\n        verify(this.mockContainerSignatureValidationService, times(1)).verify(imageName, imageTag, trustAnchor,\n                verifyTlog, passwordRegistryCredentials);\n    }\n\n    private void thenNoExceptionOccurred() {\n        String errorMessage = \"Empty message\";\n        if (Objects.nonNull(this.occurredException)) {\n            StringWriter sw = new StringWriter();\n            this.occurredException.printStackTrace(new PrintWriter(sw));\n\n            errorMessage = String.format(\"No exception expected, \\\"%s\\\" found. Caused by: %s\",\n                    this.occurredException.getClass().getName(), sw.toString());\n        }\n\n        assertNull(errorMessage, this.occurredException);\n    }\n\n    private <E extends Exception> void thenExceptionOccurred(Class<E> expectedException) {\n        assertNotNull(this.occurredException);\n        assertEquals(expectedException.getName(), this.occurredException.getClass().getName());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.certificates.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.certificates.test\nBundle-SymbolicName: org.eclipse.kura.core.certificates.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.slf4j;version=\"1.6.4\",\n org.eclipse.kura.core.testutil,\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\"\nFragment-Host: org.eclipse.kura.core.certificates;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.certificates.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.certificates.test/build.properties",
    "content": "#\n# Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.certificates.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.certificates.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n    \n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.certificates.test/src/test/java/org/eclipse/kura/core/certificates/CertificatesManagerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.certificates;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.certificate.KuraCertificateEntry;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\npublic class CertificatesManagerTest {\n\n    private static String defaultKeystore;\n    private static String httpsKeystore;\n    private static String sslKeystore;\n    private static CertificatesManager certificatesManager;\n\n    @BeforeClass\n    public static void setup() throws NoSuchFieldException {\n        certificatesManager = new CertificatesManager();\n        defaultKeystore = (String) TestUtil.getFieldValue(certificatesManager, \"DEFAULT_KEYSTORE_SERVICE_PID\");\n        httpsKeystore = (String) TestUtil.getFieldValue(certificatesManager, \"LOGIN_KEYSTORE_SERVICE_PID\");\n        sslKeystore = (String) TestUtil.getFieldValue(certificatesManager, \"SSL_KEYSTORE_SERVICE_PID\");\n    }\n\n    @Test\n    public void returnCertificateTest()\n            throws NoSuchFieldException, KuraException, GeneralSecurityException, IOException {\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        when(ksMock.getEntry(\"certTest\")).thenReturn(new TrustedCertificateEntry(certMock));\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(\"keystoreTest\", ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        String id = \"keystoreTest:certTest\";\n        KuraCertificateEntry kuraCertificate = certificatesManager.getCertificateEntry(id);\n        assertEquals(\"keystoreTest\", kuraCertificate.getKeystoreId());\n        assertEquals(\"certTest\", kuraCertificate.getAlias());\n        assertNotNull(kuraCertificate.getCertificateEntry());\n    }\n\n    @Test\n    public void storeCertificateInDefaultKeystoreTest()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        String alias = \"dm_certTest\";\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        when(ksMock.getEntry(alias)).thenReturn(new TrustedCertificateEntry(certMock));\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(defaultKeystore, ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        KuraCertificateEntry kuraCertificate = new KuraCertificateEntry(defaultKeystore, alias, certMock);\n        certificatesManager.storeCertificate(certMock, alias);\n        kuraCertificate = certificatesManager.getCertificateEntry(defaultKeystore + \":\" + alias);\n        assertEquals(defaultKeystore, kuraCertificate.getKeystoreId());\n        assertEquals(alias, kuraCertificate.getAlias());\n        verify(ksMock).setEntry(eq(alias), any());\n    }\n\n    @Test\n    public void storeCertificateInHttpsKeystoreTest()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        String alias = \"login_certTest\";\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        when(ksMock.getEntry(alias)).thenReturn(new TrustedCertificateEntry(certMock));\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(httpsKeystore, ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        certificatesManager.storeCertificate(certMock, alias);\n        KuraCertificateEntry kuraCertificate = certificatesManager.getCertificateEntry(httpsKeystore + \":\" + alias);\n        assertEquals(httpsKeystore, kuraCertificate.getKeystoreId());\n        assertEquals(alias, kuraCertificate.getAlias());\n        verify(ksMock).setEntry(eq(alias), any());\n    }\n\n    @Test\n    public void listBundleCertificatesAliasesTest()\n            throws NoSuchFieldException, GeneralSecurityException, IOException, KuraException {\n        List<String> aliases = new ArrayList<>();\n        aliases.add(\"bundle_certTest1\");\n        aliases.add(\"bundle_certTest2\");\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        when(ksMock.getAliases()).thenReturn(aliases);\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(defaultKeystore, ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        aliases.stream().forEach(alias -> {\n            try {\n                certificatesManager.storeCertificate(certMock, alias);\n            } catch (KuraException e) {\n            }\n        });\n\n        List<String> aliasList = Collections.list(certificatesManager.listBundleCertificatesAliases());\n        assertEquals(aliases.size(), aliasList.size());\n        aliasList.stream().forEach(alias -> assertTrue(alias.startsWith(\"bundle_\")));\n    }\n\n    @Test\n    public void listDMCertificatesAliasesTest()\n            throws NoSuchFieldException, GeneralSecurityException, IOException, KuraException {\n        List<String> aliases = new ArrayList<>();\n        aliases.add(\"dm_certTest1\");\n        aliases.add(\"dm_certTest2\");\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        when(ksMock.getAliases()).thenReturn(aliases);\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(defaultKeystore, ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        aliases.stream().forEach(alias -> {\n            try {\n                certificatesManager.storeCertificate(certMock, alias);\n            } catch (KuraException e) {\n            }\n        });\n\n        List<String> aliasList = Collections.list(certificatesManager.listDMCertificatesAliases());\n        assertEquals(aliases.size(), aliasList.size());\n        aliasList.stream().forEach(alias -> assertTrue(alias.startsWith(\"dm_\")));\n    }\n\n    @Test\n    public void listSSLCertificatesAliasesTest()\n            throws NoSuchFieldException, GeneralSecurityException, IOException, KuraException {\n        List<String> aliases = new ArrayList<>();\n        aliases.add(\"certTest1\");\n        aliases.add(\"certTest2\");\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        when(ksMock.getAliases()).thenReturn(aliases);\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(sslKeystore, ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        aliases.stream().forEach(alias -> {\n            try {\n                certificatesManager.storeCertificate(certMock, alias);\n            } catch (KuraException e) {\n            }\n        });\n\n        List<String> aliasList = Collections.list(certificatesManager.listSSLCertificatesAliases());\n        assertEquals(aliases.size(), aliasList.size());\n        aliasList.stream().forEach(alias -> assertTrue(alias.startsWith(\"certTest\")));\n    }\n\n    @Test\n    public void removeCertificateTest()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(\"keystoreTest\", ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        String id = \"keystoreTest:certTest\";\n        certificatesManager.removeCertificate(\"certTest\");\n        verify(ksMock).deleteEntry(\"certTest\");\n    }\n\n    @Test\n    public void verifySignatureTest() {\n        // Not implemented, always returns true\n        CertificatesManager manager = new CertificatesManager();\n        assertTrue(manager.verifySignature(null, null));\n    }\n\n    @Test\n    public void getCertificatesTest()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        Map<String, java.security.KeyStore.Entry> entries = new HashMap<>();\n        entries.put(\"certTest1\", new TrustedCertificateEntry(certMock));\n        entries.put(\"certTest2\", new TrustedCertificateEntry(certMock));\n        when(ksMock.getEntries()).thenReturn(entries);\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(\"keystoreTest\", ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        List<KuraCertificateEntry> kuraCertificates = certificatesManager.getCertificates();\n        assertEquals(2, kuraCertificates.size());\n        assertEquals(\"keystoreTest\", kuraCertificates.get(0).getKeystoreId());\n        assertEquals(\"certTest2\", kuraCertificates.get(0).getAlias());\n    }\n\n    @Test\n    public void getCertificateTest() throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        when(ksMock.getEntry(\"certTest\")).thenReturn(new TrustedCertificateEntry(certMock));\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(\"keystoreTest\", ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        String id = \"keystoreTest:certTest\";\n        KuraCertificateEntry kuraCertificate = certificatesManager.getCertificateEntry(id);\n        assertEquals(\"keystoreTest\", kuraCertificate.getKeystoreId());\n        assertEquals(\"certTest\", kuraCertificate.getAlias());\n    }\n\n    @Test\n    public void addCertificateTest() throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        when(ksMock.getEntry(\"certTest\")).thenReturn(new TrustedCertificateEntry(certMock));\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(\"keystoreTest\", ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        String id = \"keystoreTest:certTest\";\n        KuraCertificateEntry kuraCertificate = new KuraCertificateEntry(\"keystoreTest\", \"certTest\", certMock);\n        certificatesManager.addCertificate(kuraCertificate);\n        kuraCertificate = certificatesManager.getCertificateEntry(id);\n        assertEquals(\"keystoreTest\", kuraCertificate.getKeystoreId());\n        assertEquals(\"certTest\", kuraCertificate.getAlias());\n        verify(ksMock).setEntry(eq(\"certTest\"), any());\n    }\n\n    @Test\n    public void updateCertificateTest()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        X509Certificate certMock = mock(X509Certificate.class);\n        KeystoreService ksMock = mock(KeystoreService.class);\n        when(ksMock.getEntry(\"certTest\")).thenReturn(new TrustedCertificateEntry(certMock));\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(\"keystoreTest\", ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        String id = \"keystoreTest:certTest\";\n        KuraCertificateEntry kuraCertificate = new KuraCertificateEntry(\"keystoreTest\", \"certTest\", certMock);\n        certificatesManager.updateCertificate(kuraCertificate);\n        kuraCertificate = certificatesManager.getCertificateEntry(id);\n        assertEquals(\"keystoreTest\", kuraCertificate.getKeystoreId());\n        assertEquals(\"certTest\", kuraCertificate.getAlias());\n        verify(ksMock).setEntry(eq(\"certTest\"), any());\n    }\n\n    @Test\n    public void deleteCertificateTest()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        Map<String, KeystoreService> keystoreServices = new HashMap<>();\n        keystoreServices.put(\"keystoreTest\", ksMock);\n        TestUtil.setFieldValue(certificatesManager, \"keystoreServices\", keystoreServices);\n\n        String id = \"keystoreTest:certTest\";\n        certificatesManager.deleteCertificate(id);\n        verify(ksMock).deleteEntry(\"certTest\");\n    }\n\n    String getDefaultKeyStore(CertificatesManager manager) throws NoSuchFieldException {\n        return (String) TestUtil.getFieldValue(manager, \"DEFAULT_KEYSTORE\");\n    }\n\n    CryptoService createMockCryptoService(String keyStorePath, String keyStorePassword) throws NoSuchFieldException {\n        CryptoService mockService = mock(CryptoService.class);\n        when(mockService.getKeyStorePassword(keyStorePath)).thenReturn(keyStorePassword.toCharArray());\n\n        return mockService;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.certificates.test/src/test/resources/log4j.properties",
    "content": "log4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.cloud.factory.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.cloud.factory.test\nBundle-SymbolicName: org.eclipse.kura.core.cloud.factory.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.core.testutil,\n org.eclipse.kura.data.transport.listener;version=\"1.0.1\",\n org.eclipse.kura.message;version=\"1.2.0\",\n org.eclipse.kura.test.annotation;version=\"1.0.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.service.cm;version=\"1.4.0\",\n org.slf4j;version=\"1.6.4\"\nFragment-Host: org.eclipse.kura.core.cloud.factory;bundle-version=\"1.1.0\"\n\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.cloud.factory.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.cloud.factory.test/build.properties",
    "content": "#\n# Copyright (c) 2021 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.cloud.factory.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n\tSPDX-License-Identifier: EPL-2.0\n\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.cloud.factory.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n    <build>\n    \t<plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.cloud.factory.test/src/test/java/org/eclipse/kura/core/cloud/factory/DefaultCloudServiceFactoryTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.cloud.factory;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.ArgumentMatchers.anyBoolean;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudConnectionManager;\nimport org.eclipse.kura.cloud.factory.CloudServiceFactory;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.junit.Test;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.component.ComponentContext;\n\npublic class DefaultCloudServiceFactoryTest {\n\n    private static final String CLOUD_SERVICE_FACTORY_PID = \"org.eclipse.kura.cloud.CloudService\";\n\n    @Test\n    public void testCreateConfigurationWrongPid() {\n        String pid = \"test.service.pid\";\n\n        DefaultCloudServiceFactory factory = new DefaultCloudServiceFactory();\n\n        try {\n            factory.createConfiguration(pid);\n            fail(\"Exception was expected\");\n        } catch (KuraException e) {\n            assertEquals(KuraErrorCode.INVALID_PARAMETER, e.getCode());\n        }\n    }\n\n    @Test\n    public void testCreateConfiguration() throws KuraException {\n        String pid = \"org.eclipse.kura.cloud.CloudService-1\";\n\n        ConfigurationService csMock = mock(ConfigurationService.class);\n\n        DefaultCloudServiceFactory factory = new DefaultCloudServiceFactory();\n        factory.setConfigurationService(csMock);\n\n        doAnswer(new Answer<Void>() {\n\n            @Override\n            public Void answer(InvocationOnMock invocation) throws Throwable {\n                Object[] args = invocation.getArguments();\n\n                assertTrue(args[0].equals(\"org.eclipse.kura.cloud.CloudService\")\n                        || args[0].equals(\"org.eclipse.kura.data.DataService\")\n                        || args[0].equals(\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\"));\n\n                if (args[0].equals(\"org.eclipse.kura.cloud.CloudService\")) {\n                    assertEquals(pid, args[1]);\n                    assertFalse((boolean) args[3]);\n                } else if (args[0].equals(\"org.eclipse.kura.data.DataService\")) {\n                    assertEquals(\"org.eclipse.kura.data.DataService-1\", args[1]);\n                    assertFalse((boolean) args[3]);\n                } else if (args[0].equals(\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\")) {\n                    assertEquals(\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-1\", args[1]);\n                    assertTrue((boolean) args[3]);\n                }\n\n                return null;\n            }\n        }).when(csMock).createFactoryConfiguration(anyString(), anyString(), any(), anyBoolean());\n\n        factory.createConfiguration(pid);\n\n        verify(csMock, times(3)).createFactoryConfiguration(anyString(), anyString(), any(), anyBoolean());\n    }\n\n    @Test\n    public void testDeleteConfigurationWrongPid() throws KuraException {\n        String pid = \"test.service.pid\";\n\n        ConfigurationService csMock = mock(ConfigurationService.class);\n\n        DefaultCloudServiceFactory factory = new DefaultCloudServiceFactory();\n        factory.setConfigurationService(csMock);\n\n        factory.deleteConfiguration(pid);\n\n        verify(csMock, times(0)).deleteFactoryConfiguration(anyString(), anyBoolean());\n    }\n\n    @Test\n    public void testDeleteConfiguration() throws KuraException {\n        String pid = \"org.eclipse.kura.cloud.CloudService-1\";\n\n        ConfigurationService csMock = mock(ConfigurationService.class);\n\n        DefaultCloudServiceFactory factory = new DefaultCloudServiceFactory();\n        factory.setConfigurationService(csMock);\n\n        factory.deleteConfiguration(pid);\n\n        verify(csMock, times(1)).deleteFactoryConfiguration(pid, false);\n        verify(csMock, times(1)).deleteFactoryConfiguration(\"org.eclipse.kura.data.DataService-1\", false);\n        verify(csMock, times(1))\n                .deleteFactoryConfiguration(\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-1\", true);\n    }\n\n    @Test\n    public void testGetStackComponentsPidsWrongPid() {\n        String pid = \"test.service.pid\";\n\n        DefaultCloudServiceFactory factory = new DefaultCloudServiceFactory();\n\n        try {\n            factory.getStackComponentsPids(pid);\n            fail(\"Exception was expected\");\n        } catch (KuraException e) {\n            assertEquals(KuraErrorCode.INVALID_PARAMETER, e.getCode());\n        }\n    }\n\n    @Test\n    public void testGetStackComponentsPids() throws KuraException {\n        String pid = \"org.eclipse.kura.cloud.CloudService-1\";\n\n        DefaultCloudServiceFactory factory = new DefaultCloudServiceFactory();\n\n        List<String> stackComponentsPids = factory.getStackComponentsPids(pid);\n\n        assertEquals(3, stackComponentsPids.size());\n        assertEquals(\"org.eclipse.kura.cloud.CloudService-1\", stackComponentsPids.get(0));\n        assertEquals(\"org.eclipse.kura.data.DataService-1\", stackComponentsPids.get(1));\n        assertEquals(\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-1\", stackComponentsPids.get(2));\n    }\n\n    @Test\n    public void testGetManagedCloudServicePidsEmpty() throws KuraException {\n        DefaultCloudServiceFactory factory = new DefaultCloudServiceFactory();\n\n        factory.activate(getMockComponentContext(Collections.emptyList()));\n\n        Set<String> pids = factory.getManagedCloudConnectionPids();\n\n        assertNotNull(pids);\n        assertEquals(0, pids.size());\n    }\n\n    private ComponentContext getMockComponentContext(Collection<ServiceReference<CloudConnectionManager>> refs) {\n        try {\n            final BundleContext context = mock(BundleContext.class);\n\n            when(context.getServiceReferences(CloudConnectionManager.class, null)).thenReturn(refs);\n\n            final ComponentContext componentContext = mock(ComponentContext.class);\n\n            when(componentContext.getBundleContext()).thenReturn(context);\n\n            return componentContext;\n        } catch (InvalidSyntaxException e) {\n            throw new IllegalStateException();\n        }\n    }\n\n    private ServiceReference<CloudConnectionManager> createMockReference(final String pid, final String factoryPid,\n            final Map<String, Object> properties) {\n\n        final Map<String, Object> refProperties = new HashMap<>();\n\n        if (properties != null) {\n            refProperties.putAll(properties);\n        }\n\n        refProperties.put(ConfigurationService.KURA_SERVICE_PID, pid);\n        refProperties.put(ConfigurationAdmin.SERVICE_FACTORYPID, factoryPid);\n\n        final ServiceReference<CloudConnectionManager> ref = mock(ServiceReference.class);\n        when(ref.getProperty(any())).thenAnswer(answer -> {\n            final String key = answer.getArgument(0, String.class);\n            return refProperties.get(key);\n        });\n\n        return ref;\n    }\n\n    @Test\n    public void testGetManagedCloudServicePids() throws KuraException {\n        DefaultCloudServiceFactory factory = new DefaultCloudServiceFactory();\n\n        List<ServiceReference<CloudConnectionManager>> list = new ArrayList<>();\n        list.add(createMockReference(CLOUD_SERVICE_FACTORY_PID + \"-FOO\", CLOUD_SERVICE_FACTORY_PID,\n                Collections.singletonMap(CloudServiceFactory.KURA_CLOUD_SERVICE_FACTORY_PID,\n                        DefaultCloudServiceFactory.class.getName())));\n\n        list.add(createMockReference(CLOUD_SERVICE_FACTORY_PID, CLOUD_SERVICE_FACTORY_PID, Collections.singletonMap(\n                CloudServiceFactory.KURA_CLOUD_SERVICE_FACTORY_PID, DefaultCloudServiceFactory.class.getName())));\n\n        factory.activate(getMockComponentContext(list));\n\n        Set<String> pids = factory.getManagedCloudConnectionPids();\n\n        assertNotNull(pids);\n        assertEquals(2, pids.size());\n        assertTrue(pids.contains(CLOUD_SERVICE_FACTORY_PID));\n        assertTrue(pids.contains(CLOUD_SERVICE_FACTORY_PID + \"-FOO\"));\n    }\n\n    @Test\n    public void testGetManagedCloudServiceShouldOnlyReturnManagedEntries() throws KuraException {\n        DefaultCloudServiceFactory factory = new DefaultCloudServiceFactory();\n\n        List<ServiceReference<CloudConnectionManager>> list = new ArrayList<>();\n        list.add(createMockReference(CLOUD_SERVICE_FACTORY_PID + \"-OK\", CLOUD_SERVICE_FACTORY_PID,\n                Collections.singletonMap(CloudServiceFactory.KURA_CLOUD_SERVICE_FACTORY_PID,\n                        DefaultCloudServiceFactory.class.getName())));\n\n        list.add(createMockReference(CLOUD_SERVICE_FACTORY_PID + \"-OK2\", CLOUD_SERVICE_FACTORY_PID,\n                Collections.singletonMap(CloudServiceFactory.KURA_CLOUD_SERVICE_FACTORY_PID,\n                        DefaultCloudServiceFactory.class.getName())));\n\n        list.add(createMockReference(CLOUD_SERVICE_FACTORY_PID + \"-BAR\", CLOUD_SERVICE_FACTORY_PID, Collections\n                .singletonMap(CloudServiceFactory.KURA_CLOUD_SERVICE_FACTORY_PID, \"OtherCloudServiceFactory\")));\n\n        list.add(createMockReference(CLOUD_SERVICE_FACTORY_PID, CLOUD_SERVICE_FACTORY_PID, Collections.singletonMap(\n                CloudServiceFactory.KURA_CLOUD_SERVICE_FACTORY_PID, DefaultCloudServiceFactory.class.getName())));\n\n        list.add(createMockReference(\"CloudServiceBaz\", CLOUD_SERVICE_FACTORY_PID, Collections.emptyMap()));\n        list.add(createMockReference(\"OtherCloudService\", CLOUD_SERVICE_FACTORY_PID,\n                Collections.singletonMap(CloudServiceFactory.KURA_CLOUD_SERVICE_FACTORY_PID, null)));\n\n        list.add(createMockReference(\"foo\", \"bar\", Collections.emptyMap()));\n\n        factory.activate(getMockComponentContext(list));\n\n        Set<String> pids = factory.getManagedCloudConnectionPids();\n\n        assertNotNull(pids);\n        assertEquals(3, pids.size());\n        assertTrue(pids.contains(CLOUD_SERVICE_FACTORY_PID + \"-OK\"));\n        assertTrue(pids.contains(CLOUD_SERVICE_FACTORY_PID + \"-OK2\"));\n        assertTrue(pids.contains(CLOUD_SERVICE_FACTORY_PID));\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.comm.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.comm.test\nBundle-SymbolicName: org.eclipse.kura.core.comm.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.slf4j;version=\"1.6.4\"\nFragment-Host: org.eclipse.kura.core.comm;bundle-version=\"1.0.100\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.comm.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.comm.test/build.properties",
    "content": "#\n# Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.comm.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.comm.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n    \n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.comm.test/src/test/java/org/eclipse/kura/core/comm/CommConnectionImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.comm;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\n\npublic class CommConnectionImplTest {\n\n    @Test\n    public void testGetBytesAsStringNull() {\n        assertNull(CommConnectionImpl.getBytesAsString(null));\n    }\n\n    @Test\n    public void testGetBytesAsStringEmpty() {\n        byte[] data = {};\n        String stringData = CommConnectionImpl.getBytesAsString(data);\n\n        assertEquals(\"\", stringData);\n    }\n\n    @Test\n    public void testGetBytesAsStringSingle() {\n        byte[] data = { 0x42 };\n        String stringData = CommConnectionImpl.getBytesAsString(data);\n\n        assertEquals(\"42\", stringData);\n    }\n\n    @Test\n    public void testGetBytesAsStringMultiple() {\n        byte[] data = { 0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, (byte) 0xCD, (byte) 0xEF };\n        String stringData = CommConnectionImpl.getBytesAsString(data);\n\n        assertEquals(\"01 23 45 67 89 AB CD EF\", stringData);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.comm.test/src/test/resources/log4j.properties",
    "content": "log4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.configuration.test\nBundle-SymbolicName: org.eclipse.kura.core.configuration.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.core.configuration\nImport-Package: org.apache.commons.io;version=\"[2.18,3.0)\",\n org.eclipse.kura;version=\"[1.2,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.2,2.0)\",\n org.eclipse.kura.internal.xml.marshaller.unmarshaller;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.1,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.7\",\n org.osgi.service.cm;version=\"1.4\",\n org.osgi.service.component;version=\"1.2\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/OSGI-INF/CfgSvcTestComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n    name=\"org.eclipse.kura.core.configuration.CfgSvcTestComponent\"\n    modified=\"updated\"\n    enabled=\"true\"\n    immediate=\"true\"\n    configuration-policy=\"require\">\n    <implementation class=\"org.eclipse.kura.core.configuration.CfgSvcTestComponent\"/>\n\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.core.configuration.CfgSvcTestComponent\"/>\n   <service>\n       <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/OSGI-INF/CfgSvcTestSelfComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n  Copyright (c) 2022 Eurotech and/or its affiliates and others\n  \n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n    name=\"org.eclipse.kura.core.configuration.CfgSvcTestSelfComponent\"\n    modified=\"updated\"\n    enabled=\"true\"\n    immediate=\"true\"\n    configuration-policy=\"optional\">\n    <implementation class=\"org.eclipse.kura.core.configuration.CfgSvcTestSelfComponent\"/>\n\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.core.configuration.CfgSvcTestSelfComponent\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.configuration.SelfConfiguringComponent\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/OSGI-INF/ConfigurationServiceTest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n  Copyright (c) 2017, 2022 Eurotech and/or its affiliates and others\n  \n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"ConfigurationServiceTest\">\n   <implementation class=\"org.eclipse.kura.core.configuration.ConfigurationServiceTest\"/>\n   <reference bind=\"bindConfigService\"\n              unbind=\"unbindConfigService\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.configuration.ConfigurationService\"\n              name=\"ConfigurationService\"\n              policy=\"static\"/>\n   <reference bind=\"bindOcdService\"\n              unbind=\"unbindOcdService\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.configuration.metatype.OCDService\"\n              name=\"OCDService\"\n              policy=\"static\"/>\n   <reference bind=\"bindSystemService\"\n              unbind=\"unbindSystemService\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.system.SystemService\"\n              name=\"SystemService\"\n              policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/OSGI-INF/metatype/org.eclipse.kura.core.configuration.CfgSvcTestComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.core.configuration.CfgSvcTestComponent\"\n         name=\"CfgSvcTestComponent\"\n         description=\"Component for testing Configuration Service.\">\n\n        <AD id=\"field.test\"\n            name=\"field.test\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"1\"\n            min=\"1\"\n            max=\"20\"\n            description=\"Field for test\"/>\n\n        <AD id=\"password.test\"\n            name=\"password.test\"\n            type=\"Password\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"foobar\"\n            description=\"Password for test\"/>\n\n    </OCD>\n    <Designate pid=\"org.eclipse.kura.core.configuration.CfgSvcTestComponent\">\n        <Object ocdref=\"org.eclipse.kura.core.configuration.CfgSvcTestComponent\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/OSGI-INF/metatype/org.eclipse.kura.core.configuration.TestFactoryComponent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.core.configuration.TestFactoryComponent\"\n         name=\"TestFactoryComponent\"\n         description=\"Component for testing Configuration Service factory.\">\n\n        <AD id=\"field.test\"\n            name=\"field.test\"\n            type=\"Integer\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"1\"\n            min=\"1\"\n            max=\"20\"\n            description=\"Field for test\"/>\n        \n        <AD id=\"password.test\"\n            name=\"password.test\"\n            type=\"Password\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"foobar\"\n            description=\"Password for test\"/>\n\n    </OCD>\n    <Designate pid=\"org.eclipse.kura.core.configuration.TestFactoryComponent\"\n            factoryPid=\"org.eclipse.kura.core.configuration.TestFactoryComponent\">\n        <Object ocdref=\"org.eclipse.kura.core.configuration.TestFactoryComponent\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/build.properties",
    "content": "#\n# Copyright (c) 2016, 2025 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/test/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2016, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.core.configuration.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/src/main/java/org/eclipse/kura/core/configuration/CfgSvcTestComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class CfgSvcTestComponent implements ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(CfgSvcTestComponent.class);\n\n    private void updated(Map<String, Object> properties) {\n        if (logger.isDebugEnabled()) {\n            StringBuilder sb = new StringBuilder();\n            for (Entry<String, Object> entry : properties.entrySet()) {\n                sb.append(\"[\").append(entry.getKey()).append(\"=\").append(entry.getValue()).append(\"], \");\n            }\n\n            logger.debug(\"Properties after update: \" + sb.toString());\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/src/main/java/org/eclipse/kura/core/configuration/CfgSvcTestSelfComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID;\nimport static org.osgi.framework.Constants.SERVICE_PID;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.SelfConfiguringComponent;\nimport org.eclipse.kura.core.configuration.metatype.ObjectFactory;\nimport org.eclipse.kura.core.configuration.metatype.Tad;\nimport org.eclipse.kura.core.configuration.metatype.Tocd;\nimport org.eclipse.kura.core.configuration.metatype.Tscalar;\n\npublic class CfgSvcTestSelfComponent implements SelfConfiguringComponent {\n\n    public static final String PID = \"org.eclipse.kura.core.configuration.CfgSvcTestSelfComponent\";\n\n    @Override\n    public ComponentConfiguration getConfiguration() throws KuraException {\n        try {\n            Map<String, Object> componentConfigurationProperties = new HashMap<>();\n            componentConfigurationProperties.put(KURA_SERVICE_PID, PID);\n            componentConfigurationProperties.put(SERVICE_PID, PID);\n            return new ComponentConfigurationImpl(PID, getDefinition(), componentConfigurationProperties);\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e);\n        }\n    }\n\n    private Tocd getDefinition() throws KuraException {\n\n        ObjectFactory objectFactory = new ObjectFactory();\n        Tocd tocd = objectFactory.createTocd();\n\n        tocd.setName(\"CfgSvcTestSelfComponent\");\n        tocd.setId(PID);\n        tocd.setDescription(\"Self Configuring Component Test\");\n\n        Tad tad = objectFactory.createTad();\n        tad.setId(\"TestADId\");\n        tad.setName(\"TestADName\");\n        tad.setType(Tscalar.STRING);\n        tad.setCardinality(1);\n        tad.setRequired(true);\n        tad.setDefault(\"TestADDefaultValue\");\n        tad.setDescription(\"This is only a test parameter.\");\n        tocd.addAD(tad);\n\n        return tocd;\n    }\n\n    public void updated(Map<String, Object> properties) {\n\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID;\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.osgi.framework.Constants.SERVICE_PID;\n\nimport org.eclipse.kura.configuration.Password;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.util.ArrayList;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraPartialSuccessException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.SelfConfiguringComponent;\nimport org.eclipse.kura.configuration.metatype.OCDService;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\n\npublic class ConfigurationServiceTest {\n\n    private static final String DATA_SERVICE_FACTORY_PID = \"org.eclipse.kura.data.DataService\";\n    private static final String TEST_COMPONENT_PID = \"org.eclipse.kura.core.configuration.CfgSvcTestComponent\";\n    private static final String TEST_SELF_COMPONENT_PID = \"org.eclipse.kura.core.configuration.CfgSvcTestSelfComponent\";\n    private static final String TEST_COMPONENT_FPID = \"org.eclipse.kura.core.configuration.TestFactoryComponent\";\n    private static final String TEST_COMPONENT_PROPERTY_KEY = \"field.test\";\n    private static final String TEST_COMPONENT_PASSWORD_PROPERTY_KEY = \"password.test\";\n    private static final int TEST_COMPONENT_PROPERTY_VALUE = 1;\n    private static final String TEST_COMPONENT_PASSWORD_PROPERTY_DEFAULT = \"foobar\";\n    private static final String TEST_SELF_COMPONENT_PROPERTY_KEY = \"TestADId\";\n    private static final String TEST_SELF_COMPONENT_PROPERTY_VALUE = \"TestADDefaultValue\";\n    private static final String KURA_SNAPSHOTS_DIR = \"/tmp/kura/snapshots\";\n\n    /*\n     * OSGi dependencies\n     */\n\n    private static CountDownLatch dependencyLatch = new CountDownLatch(3);\n    private static ConfigurationService configurationService;\n    private static OCDService ocdService;\n    private static SystemService systemService;\n\n    protected void bindConfigService(final ConfigurationService configService) {\n        if (ConfigurationServiceTest.configurationService == null) {\n            ConfigurationServiceTest.configurationService = configService;\n            dependencyLatch.countDown();\n        }\n    }\n\n    protected void unbindConfigService(final ConfigurationService configService) {\n        if (ConfigurationServiceTest.configurationService == configService) {\n            ConfigurationServiceTest.configurationService = null;\n        }\n    }\n\n    protected void bindOcdService(final OCDService ocdService) {\n        if (ConfigurationServiceTest.ocdService == null) {\n            ConfigurationServiceTest.ocdService = ocdService;\n            dependencyLatch.countDown();\n        }\n    }\n\n    protected void unbindOcdService(final OCDService ocdService) {\n        if (ConfigurationServiceTest.ocdService == ocdService) {\n            ConfigurationServiceTest.ocdService = null;\n        }\n    }\n\n    protected void bindSystemService(final SystemService sysService) {\n        if (ConfigurationServiceTest.systemService == null) {\n            ConfigurationServiceTest.systemService = sysService;\n            dependencyLatch.countDown();\n        }\n    }\n\n    protected void unbindSystemService(final SystemService sysService) {\n        if (ConfigurationServiceTest.systemService == sysService) {\n            ConfigurationServiceTest.systemService = null;\n        }\n    }\n\n    @BeforeClass\n    public static void awaitDependencies() throws Exception {\n        try {\n            boolean ok = dependencyLatch.await(10, TimeUnit.SECONDS);\n\n            assertTrue(\"Dependencies OK.\", ok);\n        } catch (final InterruptedException e) {\n            Thread.currentThread().interrupt();\n            fail(\"OSGi dependencies unfulfilled.\");\n        }\n    }\n\n    /*\n     * Gherkin-style tests\n     */\n\n    private int kuraSnapshotsCount = 10;\n    private String kuraSnapshotsDir = KURA_SNAPSHOTS_DIR;\n\n    private Optional<Exception> exceptionOccurred;\n\n    private Set<String> factoryComponentPids;\n    private Map<String, Object> exampleProperties = map(\"key1\", \"value1\", \"key2\", \"value2\");\n\n    private Map<String, Object> defaultProperties = map(\"field.test\", 1, \"password.test\",\n            new Password(TEST_COMPONENT_PASSWORD_PROPERTY_DEFAULT.toCharArray()));\n\n    private Set<Long> snapshotsBefore;\n    private Set<Long> snapshotsAfter;\n    private Set<String> configurableComponentPids;\n    private List<ComponentConfiguration> configurations;\n    private List<ComponentConfiguration> inputConfigurations;\n    private ComponentConfiguration configuration;\n    private ComponentConfiguration defaultConfiguration;\n    private ComponentConfiguration updatedConfiguration;\n    private long rollbackID;\n    private List<ComponentConfiguration> factoryComponentOCDs;\n    private List<ComponentConfiguration> serviceProviderOCDs;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void testGetFactoryComponentPids() {\n        // positive test; test component pid should be contained in the factory pids\n\n        whenGetFactoryComponentPids();\n\n        thenFactoryComponentPidsAreMoreThan(1);\n        thenFactoryComponentPidsContain(TEST_COMPONENT_FPID);\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testCreateFactoryConfigurationNulls() {\n        // negative test; cannot create a component with a null factory\n\n        whenCreateFactoryConfiguration(null, \"testPid\", null, false);\n\n        thenIllegalArgumentExceptionOccurred();\n    }\n\n    @Test\n    public void testCreateFactoryExistingPid() {\n        // negative test; cannot create a factory comp. with an already existing pid\n\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"existingPid\", null, false);\n\n        whenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"existingPid\", null, false);\n\n        thenKuraExceptionOccurred();\n    }\n\n    @Test\n    public void testCreateFactoryConfigurationMergePropertiesAndSnapshot() {\n        // positive test; the created snapshot contains the properties\n\n        whenCreateFactoryConfiguration(TEST_COMPONENT_FPID, \"cfcmp_pid_1\", this.exampleProperties, true);\n\n        thenSnapshotsIncreasedBy(1);\n        thenLastSnapshotContainsProperties(\"cfcmp_pid_1\", this.exampleProperties);\n    }\n\n    @Test\n    public void testCreateFactoryConfigurationWithDefaultPassword() {\n        // positive test; the created snapshot contains the properties\n\n        whenCreateFactoryConfiguration(TEST_COMPONENT_FPID, \"cfcmp_pid_2\", null, true);\n\n        thenSnapshotsIncreasedBy(1);\n        thenLastSnapshotContainsProperties(\"cfcmp_pid_2\", this.defaultProperties);\n    }\n\n    @Test\n    public void testCreateFactoryConfigurationWithCustomPassword() {\n        // positive test; the created snapshot contains the properties\n\n        whenCreateFactoryConfiguration(TEST_COMPONENT_FPID, \"cfcmp_pid_3\",\n                map(TEST_COMPONENT_PASSWORD_PROPERTY_KEY, new Password(\"bar\".toCharArray())), true);\n\n        thenSnapshotsIncreasedBy(1);\n        thenLastSnapshotContainsProperties(\"cfcmp_pid_3\",\n                map(TEST_COMPONENT_PASSWORD_PROPERTY_KEY, new Password(\"bar\".toCharArray())));\n    }\n\n    @Test\n    public void testDeleteFactoryConfigurationNulls() {\n        // negative test; null is given as pid\n\n        whenDeleteFactoryConfiguration(null, false);\n\n        thenKuraExceptionOccurred();\n    }\n\n    @Test\n    public void testDeleteFactoryConfigurationNonExistingFactoryPid() {\n        // negative test; pid not registered\n\n        whenDeleteFactoryConfiguration(\"pid_non_existent\", false);\n\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testDeleteFactoryConfigurationWithSnapshot() {\n        // positive test; pid registered in factory and service pids, configuration delete is expected, with snapshots\n\n        givenCreateFactoryConfiguration(\"fpid_\" + System.currentTimeMillis(), \"spid-test1\", this.exampleProperties,\n                true);\n\n        whenDeleteFactoryConfiguration(\"spid-test1\", true);\n\n        thenSnapshotsIncreasedBy(1);\n        thenLastSnapshotNotContainsProperties(\"spid-test1\", this.exampleProperties);\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetConfigurableComponentPids() {\n        // positive test: get pids, assert they are not modifiable outside\n\n        whenGetConfigurableComponentPids();\n\n        thenConfigurableComponentPidsNotAssignable();\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetConfigurableComponentPidsAdd() {\n        // positive test: add a new configuration and find it later\n\n        givenGetConfigurableComponentPids();\n\n        whenCreateFactoryConfiguration(\"fpid_test\", \"spid_ccpa_1234\", null, true);\n\n        thenConfigurableComponentPidsContainPid(\"spid_ccpa_1234\");\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetComponentConfigurations() {\n        // positive test; new pid registered => new configuration\n\n        whenCreateFactoryConfiguration(\"fpid_gcc_11\" + System.currentTimeMillis(), \"spid_gcc_111\", null, true);\n\n        thenSnapshotsIncreasedBy(1);\n        thenLastSnapshotContainsProperties(\"spid_gcc_111\", null);\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetComponentConfigurationsFilterNonExistentPid() {\n\n        whenGetComponentConfigurations(\"foo\");\n\n        thenConfigurationsSizeIs(0);\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetComponentConfigurationsFilterCofServicePid() {\n\n        whenGetComponentConfigurations(\"org.eclipse.kura.configuration.ConfigurationService\");\n\n        thenConfigurationsSizeIs(0);\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetComponentConfigurationsFilterExistentPid() {\n\n        whenGetComponentConfigurations(TEST_COMPONENT_PID);\n\n        thenConfigurationsContains(TEST_COMPONENT_PID);\n        thenConfigurationsSizeIs(1);\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetComponentConfigurationNull() {\n\n        whenGetComponentConfiguration(null);\n\n        thenConfigurationIsNull();\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetComponentConfiguration() {\n        givenCreateFactoryConfiguration(\"test-factory\", \"cc-test-pid\", null, false);\n\n        whenGetComponentConfiguration(\"cc-test-pid\");\n\n        thenConfigurationHasPid(\"cc-test-pid\");\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetDefaultComponentConfigurationNull() {\n        // default configuration of null is empty, with no PID set\n\n        whenGetDefaultComponentConfiguration(null);\n\n        thenDefaultConfigurationIs(null, true, true);\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetDefaultComponentConfigurationNonExisting() {\n        // default configuration of a non-existing service is empty\n\n        whenGetDefaultComponentConfiguration(\"spid_gdccne_90\");\n\n        thenDefaultConfigurationIs(\"spid_gdccne_90\", true, true);\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetDefaultComponentConfiguration() {\n        // default configuration of a new service is empty\n\n        givenCreateFactoryConfiguration(\"example-factory\", \"example-pid\", null, false);\n\n        whenGetDefaultComponentConfiguration(\"example-pid\");\n\n        thenDefaultConfigurationIs(\"example-pid\", true, true);\n    }\n\n    @Test\n    public void testGetDefaultComponentConfigurationExisting() {\n        // default configuration of an existing service is ...\n\n        whenGetDefaultComponentConfiguration(TEST_COMPONENT_PID);\n\n        thenDefaultConfigurationIs(TEST_COMPONENT_PID, false, false);\n        thenDefaultConfigurationPropertiesHas(2, TEST_COMPONENT_PROPERTY_KEY, TEST_COMPONENT_PROPERTY_VALUE);\n        thenDefaultConfigurationPropertiesHas(2, TEST_COMPONENT_PASSWORD_PROPERTY_KEY,\n                new Password(TEST_COMPONENT_PASSWORD_PROPERTY_DEFAULT.toCharArray()));\n        thenDefaultConfigurationDefinitionIsPopulated();\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testGetDefaultSelfConfiguringComponentConfigurationExisting() {\n        givenSelfConfiguringComponentConfiguration(TEST_SELF_COMPONENT_PID, TEST_SELF_COMPONENT_PID);\n\n        whenGetDefaultComponentConfiguration(TEST_SELF_COMPONENT_PID);\n\n        thenDefaultConfigurationIs(TEST_SELF_COMPONENT_PID, false, false);\n        thenDefaultConfigurationPropertiesHas(1, TEST_SELF_COMPONENT_PROPERTY_KEY, TEST_SELF_COMPONENT_PROPERTY_VALUE);\n        thenDefaultConfigurationDefinitionIsPopulated();\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testUpdateConfigurationPidPropertiesNull() {\n        whenUpdateConfiguration(null, null);\n\n        thenNPExceptionOccurred();\n    }\n\n    @Test\n    public void testUpdateConfigurationPidPropertiesNullProps() {\n        givenUpdateConfiguration(\"abcdefg\", null);\n\n        whenGetComponentConfiguration(\"abcdefg\");\n\n        thenConfigurationIsNull();\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testUpdateConfigurationPidPropertiesEmptyProps() {\n        // try it with a registered component and an existing PID with empty properties\n        givenGetComponentConfiguration(TEST_COMPONENT_PID);\n\n        whenUpdateConfiguration(TEST_COMPONENT_PID, new HashMap<>());\n\n        thenConfigurationPropertiesHaveNotChanged();\n    }\n\n    @Test\n    public void testUpdateConfigurationPidPropertiesValid() {\n        // try it with a registered component and an existing PID with invalid properties\n        whenUpdateConfiguration(TEST_COMPONENT_PID, new HashMap<String, Object>() {\n\n            private static final long serialVersionUID = 7567583973175478794L;\n\n            {\n                put(\"unknownProperty\", 123);\n                put(TEST_COMPONENT_PROPERTY_KEY, 2);\n            }\n        });\n\n        thenUpdatedConfigurationPropertiesContains(new HashMap<String, Object>() {\n\n            private static final long serialVersionUID = -7139379355635306015L;\n\n            {\n                put(\"unknownProperty\", 123);\n                put(TEST_COMPONENT_PROPERTY_KEY, 2);\n            }\n        });\n        thenSnapshotsIncreasedBy(1);\n        thenNoExceptionOccurred();\n        thenLastSnapshotContainsProperties(TEST_COMPONENT_PID, new HashMap<String, Object>() {\n\n            private static final long serialVersionUID = -4728655312644177496L;\n\n            {\n                put(\"unknownProperty\", 123);\n                put(TEST_COMPONENT_PROPERTY_KEY, 2);\n            }\n        });\n    }\n\n    @Test\n    public void testUpdateConfigurationPidPropertiesInvalid() {\n        // try it with a registered component and an existing PID with invalid properties\n        whenUpdateConfiguration(TEST_COMPONENT_PID, new HashMap<String, Object>() {\n\n            private static final long serialVersionUID = 7567583973175478794L;\n\n            {\n                put(\"unknown property\", 123);\n                put(TEST_COMPONENT_PROPERTY_KEY, 9999);\n            }\n        });\n\n        thenKuraPartialSuccessExceptionOccurred();\n    }\n\n    @Test\n    public void testUpdateConfigurationPidPropertiesNoSnapshot() {\n        // existing component PID and takeSnapshot == false\n\n        whenUpdateConfiguration(TEST_COMPONENT_PID, new HashMap<String, Object>() {\n\n            private static final long serialVersionUID = 7567583973175478794L;\n\n            {\n                put(\"unknown property\", 123);\n                put(TEST_COMPONENT_PROPERTY_KEY, 10);\n            }\n        }, false);\n\n        thenSnapshotsIncreasedBy(0);\n        thenUpdatedConfigurationPropertiesContains(new HashMap<String, Object>() {\n\n            private static final long serialVersionUID = 7567583973175478794L;\n\n            {\n                put(\"unknown property\", 123);\n                put(TEST_COMPONENT_PROPERTY_KEY, 10);\n            }\n        });\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testUpdateConfigurationsConfigs() {\n        givenInputConfigurationsWithExampleProperties(\"ex1\", \"ex2\", \"ex3\");\n\n        whenUpdateConfigurations();\n\n        thenComponentConfigurationsContainPidsWithExampleProperties(\"ex1\", \"ex2\", \"ex3\");\n        thenSnapshotsIncreasedBy(1);\n        thenLastSnapshotNotContainsProperties(\"ex1\", this.exampleProperties);\n        thenLastSnapshotNotContainsProperties(\"ex2\", this.exampleProperties);\n        thenLastSnapshotNotContainsProperties(\"ex3\", this.exampleProperties);\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testSnapshot() {\n        givenSnapshotBefore();\n\n        whenSnapshot();\n\n        thenLastSnapshotHasNotChanged();\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testRollbackEmpty() {\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_rollback_dontsave_\", null, false);\n        givenNoSnapshotsInKuraDir();\n\n        whenRollback();\n\n        thenKuraExceptionOccurred(KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND);\n    }\n\n    @Test\n    public void testRollbackNotSaved() {\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_rollback_1\", null, true);\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_rollback_2\", null, true);\n        givenSnapshotBefore();\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_rollback_dontsave_2\", null, false);\n\n        whenRollback();\n\n        thenRollbackIdIsLessThanPrevious();\n        thenLastSnapshotNotContainsProperties(\"pid_rollback_dontsave_2\", null);\n    }\n\n    @Test\n    public void testRollback() {\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_rollback_1\", null, true);\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_rollback_2\", null, true);\n        givenSnapshotBefore();\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_rollback_3\", null, true);\n\n        whenRollback();\n\n        thenRollbackIdIsGreaterThanPrevious();\n    }\n\n    @Test\n    public void testRollbackId() {\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_rollback_\", this.exampleProperties, true);\n\n        whenRollback();\n\n        thenLastSnapshotContainsProperties(\"pid_rollback_\", this.exampleProperties);\n        thenSnapshotsIncreasedBy(-1);\n    }\n\n    @Test\n    public void testRollbackShouldDeleteFactoryComponent() throws KuraException {\n        givenSnapshotBefore();\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_fc_rollback_create\", null, true);\n\n        whenRollback();\n\n        thenFactoryComponentHasBeenDeleted(\"pid_fc_rollback_create\");\n    }\n\n    @Test\n    public void testRollbackShouldCreateFactoryComponent() throws KuraException {\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_fc_rollback_delete\", null, true);\n        givenDeleteFactoryConfiguration(\"pid_fc_rollback_delete\", true);\n\n        whenRollback();\n\n        thenFactoryComponentHasBeenCreated(\"pid_fc_rollback_delete\");\n    }\n\n    @Test\n    public void testEncryptSnapshots() {\n        givenCreateFactoryConfiguration(DATA_SERVICE_FACTORY_PID, \"pid_rollback_1\", null, true);\n\n        whenSnapshot();\n\n        thenLastSnapshotIsEncrypted();\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void testShouldGetFactoryComponentDefinitions() {\n        whenGetFactoryComponentOCDs();\n\n        thenContainsWireComponentsDefinitions(this.factoryComponentOCDs, false);\n    }\n\n    @Test\n    public void testShouldGetServiceProviderDefinitions() {\n        whenGetServiceProviderOCDs();\n\n        thenContainsWireComponentsDefinitions(this.serviceProviderOCDs, true);\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenCreateFactoryConfiguration(String factoryPid, String pid, Map<String, Object> properties,\n            boolean takeSnapshot) {\n        try {\n            ConfigurationServiceTest.configurationService.createFactoryConfiguration(factoryPid, pid, properties,\n                    takeSnapshot);\n\n            if (takeSnapshot) {\n                this.snapshotsBefore = ConfigurationServiceTest.configurationService.getSnapshots();\n            }\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void givenDeleteFactoryConfiguration(String pid, boolean takeSnapshot) {\n        try {\n            ConfigurationServiceTest.configurationService.deleteFactoryConfiguration(pid, takeSnapshot);\n\n            if (takeSnapshot) {\n                this.snapshotsBefore = ConfigurationServiceTest.configurationService.getSnapshots();\n            }\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void givenSelfConfiguringComponentConfiguration(String pid, String servicePid) {\n        try {\n            Dictionary<String, Object> componentConfigurationProperties = new Hashtable<>();\n            componentConfigurationProperties.put(KURA_SERVICE_PID, pid);\n            componentConfigurationProperties.put(SERVICE_PID, servicePid);\n            BundleContext bundleContext = FrameworkUtil.getBundle(ConfigurationServiceTest.class).getBundleContext();\n            bundleContext.registerService(SelfConfiguringComponent.class, new CfgSvcTestSelfComponent(),\n                    componentConfigurationProperties);\n\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void givenGetConfigurableComponentPids() {\n        this.configurableComponentPids = ConfigurationServiceTest.configurationService.getConfigurableComponentPids();\n    }\n\n    private void givenUpdateConfiguration(String pid, Map<String, Object> properties) {\n        try {\n            ConfigurationServiceTest.configurationService.updateConfiguration(pid, properties);\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void givenGetComponentConfiguration(String pid) {\n        try {\n            this.configuration = ConfigurationServiceTest.configurationService.getComponentConfiguration(pid);\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void givenInputConfigurationsWithExampleProperties(String... pids) {\n        this.inputConfigurations = new ArrayList<ComponentConfiguration>();\n\n        for (String pid : pids) {\n            ComponentConfiguration conf = new ComponentConfigurationImpl(pid, null, this.exampleProperties);\n            this.inputConfigurations.add(conf);\n        }\n    }\n\n    private void givenSnapshotBefore() {\n        try {\n            this.snapshotsBefore.clear();\n            this.snapshotsBefore.add(configurationService.snapshot());\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void givenNoSnapshotsInKuraDir() {\n        cleanSnapshots();\n    }\n\n    /*\n     * When\n     */\n\n    private void whenGetFactoryComponentPids() {\n        this.factoryComponentPids = ConfigurationServiceTest.configurationService.getFactoryComponentPids();\n    }\n\n    private void whenCreateFactoryConfiguration(String factoryPid, String pid, Map<String, Object> properties,\n            boolean takeSnapshot) {\n        try {\n            ConfigurationServiceTest.configurationService.createFactoryConfiguration(factoryPid, pid, properties,\n                    takeSnapshot);\n\n            if (takeSnapshot) {\n                this.snapshotsAfter = ConfigurationServiceTest.configurationService.getSnapshots();\n            }\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void whenDeleteFactoryConfiguration(String pid, boolean takeSnapshot) {\n        try {\n            ConfigurationServiceTest.configurationService.deleteFactoryConfiguration(pid, takeSnapshot);\n\n            if (takeSnapshot) {\n                this.snapshotsAfter = ConfigurationServiceTest.configurationService.getSnapshots();\n            }\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void whenGetConfigurableComponentPids() {\n        this.configurableComponentPids = ConfigurationServiceTest.configurationService.getConfigurableComponentPids();\n    }\n\n    private void whenGetComponentConfigurations(String searchedPid) {\n        try {\n            this.configurations = configurationService\n                    .getComponentConfigurations(FrameworkUtil.createFilter(\"(kura.service.pid=\" + searchedPid + \")\"));\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void whenGetComponentConfiguration(String searchedPid) {\n        try {\n            this.configuration = configurationService.getComponentConfiguration(searchedPid);\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void whenGetDefaultComponentConfiguration(String searchedPid) {\n        try {\n            this.defaultConfiguration = configurationService.getDefaultComponentConfiguration(searchedPid);\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void whenUpdateConfiguration(String pid, Map<String, Object> properties) {\n        try {\n            ConfigurationServiceTest.configurationService.updateConfiguration(pid, properties);\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n\n        try {\n            this.snapshotsAfter = ConfigurationServiceTest.configurationService.getSnapshots();\n            this.updatedConfiguration = ConfigurationServiceTest.configurationService.getComponentConfiguration(pid);\n        } catch (Exception e) {\n            // ignore\n        }\n    }\n\n    private void whenUpdateConfiguration(String pid, Map<String, Object> properties, boolean takeSnapshot) {\n        try {\n            ConfigurationServiceTest.configurationService.updateConfiguration(pid, properties, takeSnapshot);\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n\n        try {\n            this.snapshotsAfter = ConfigurationServiceTest.configurationService.getSnapshots();\n            this.updatedConfiguration = ConfigurationServiceTest.configurationService.getComponentConfiguration(pid);\n        } catch (Exception e) {\n            // ignore\n        }\n    }\n\n    private void whenUpdateConfigurations() {\n        try {\n            ConfigurationServiceTest.configurationService.updateConfigurations(this.inputConfigurations);\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n\n        try {\n            this.snapshotsAfter = ConfigurationServiceTest.configurationService.getSnapshots();\n        } catch (Exception e) {\n            // ignore\n        }\n    }\n\n    private void whenSnapshot() {\n        try {\n            ConfigurationServiceTest.configurationService.snapshot();\n            this.snapshotsAfter = ConfigurationServiceTest.configurationService.getSnapshots();\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void whenRollback() {\n        try {\n            this.rollbackID = ConfigurationServiceTest.configurationService.rollback();\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void whenGetFactoryComponentOCDs() {\n        try {\n            this.factoryComponentOCDs = ocdService.getFactoryComponentOCDs();\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void whenGetServiceProviderOCDs() {\n        this.serviceProviderOCDs = ocdService.getServiceProviderOCDs(\"org.eclipse.kura.wire.WireEmitter\",\n                \"org.eclipse.kura.wire.WireReceiver\", \"org.eclipse.kura.wire.WireComponent\");\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenFactoryComponentPidsAreMoreThan(int minPidsAmount) {\n        assertTrue(this.factoryComponentPids.size() >= minPidsAmount);\n    }\n\n    private void thenFactoryComponentPidsContain(String pid) {\n        assertTrue(this.factoryComponentPids.contains(pid));\n    }\n\n    private void thenKuraExceptionOccurred() {\n        assertTrue(this.exceptionOccurred.isPresent());\n        assertTrue(this.exceptionOccurred.get() instanceof KuraException);\n    }\n\n    private void thenKuraExceptionOccurred(KuraErrorCode code) {\n        assertTrue(this.exceptionOccurred.isPresent());\n        assertTrue(this.exceptionOccurred.get() instanceof KuraException);\n        assertEquals(code, ((KuraException) this.exceptionOccurred.get()).getCode());\n    }\n\n    private void thenIllegalArgumentExceptionOccurred() {\n        assertTrue(this.exceptionOccurred.isPresent());\n        assertTrue(this.exceptionOccurred.get() instanceof IllegalArgumentException);\n    }\n\n    private void thenNPExceptionOccurred() {\n        assertTrue(this.exceptionOccurred.isPresent());\n        assertTrue(this.exceptionOccurred.get() instanceof NullPointerException);\n    }\n\n    private void thenKuraPartialSuccessExceptionOccurred() {\n        assertTrue(this.exceptionOccurred.isPresent());\n        assertTrue(this.exceptionOccurred.get() instanceof KuraPartialSuccessException);\n    }\n\n    private void thenNoExceptionOccurred() {\n        assertFalse(this.exceptionOccurred.isPresent());\n    }\n\n    private void thenSnapshotsIncreasedBy(int amount) {\n        assertEquals(Math.min(this.kuraSnapshotsCount, this.snapshotsBefore.size() + amount),\n                this.snapshotsAfter.size());\n    }\n\n    private void thenLastSnapshotContainsProperties(String pid, Map<String, Object> expectedProperties) {\n        try {\n            if (this.snapshotsAfter == null) {\n                this.snapshotsAfter = configurationService.getSnapshots();\n            }\n        } catch (KuraException e) {\n            // ignore\n        }\n\n        Set<Long> before = this.snapshotsBefore;\n        Set<Long> after = this.snapshotsAfter;\n\n        after.removeAll(before);\n\n        try {\n            List<ComponentConfiguration> lastSnapshot = ConfigurationServiceTest.configurationService\n                    .getSnapshot(after.iterator().next().longValue());\n            assertSnapshotContains(lastSnapshot, pid, expectedProperties);\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void thenLastSnapshotNotContainsProperties(String pid, Map<String, Object> expectedProperties) {\n        try {\n            if (this.snapshotsAfter == null) {\n                this.snapshotsAfter = configurationService.getSnapshots();\n            }\n        } catch (KuraException e) {\n            // ignore\n        }\n\n        Set<Long> before = this.snapshotsBefore;\n        Set<Long> after = this.snapshotsAfter;\n\n        after.removeAll(before);\n\n        try {\n            List<ComponentConfiguration> lastSnapshot = ConfigurationServiceTest.configurationService\n                    .getSnapshot(after.iterator().next().longValue());\n            assertFalse(snapshotContains(lastSnapshot, pid, expectedProperties));\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void thenLastSnapshotHasNotChanged() {\n        Set<Long> before = this.snapshotsBefore;\n        Set<Long> after = this.snapshotsAfter;\n\n        after.removeAll(before);\n\n        try {\n            List<ComponentConfiguration> previousSnapshot = ConfigurationServiceTest.configurationService\n                    .getSnapshot(before.iterator().next().longValue());\n\n            List<ComponentConfiguration> lastSnapshot = ConfigurationServiceTest.configurationService\n                    .getSnapshot(after.iterator().next().longValue());\n\n            assertTrue(snapshotsEqual(previousSnapshot, lastSnapshot));\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void thenFactoryComponentHasBeenDeleted(String pid) throws KuraException {\n        Long lastSnapshotId = ((TreeSet<Long>) ConfigurationServiceTest.configurationService.getSnapshots()).last();\n        List<ComponentConfiguration> lastSnapshot = ConfigurationServiceTest.configurationService\n                .getSnapshot(lastSnapshotId);\n\n        assertEquals(0, lastSnapshot.stream().filter(cc -> cc.getPid().equals(pid)).count());\n    }\n\n    private void thenFactoryComponentHasBeenCreated(String pid) throws KuraException {\n        Long lastSnapshotId = ((TreeSet<Long>) ConfigurationServiceTest.configurationService.getSnapshots()).last();\n        List<ComponentConfiguration> lastSnapshot = ConfigurationServiceTest.configurationService\n                .getSnapshot(lastSnapshotId);\n\n        assertEquals(1, lastSnapshot.stream().filter(cc -> cc.getPid().equals(pid)).count());\n    }\n\n    private void thenConfigurableComponentPidsNotAssignable() {\n        try {\n            this.configurableComponentPids.add(\"should-be-unsupported\");\n            fail(\"Updating PIDs should not be possible.\");\n        } catch (UnsupportedOperationException e) {\n            assertTrue(true);\n        }\n    }\n\n    private void thenConfigurableComponentPidsContainPid(String... pids) {\n        Set<String> ccPids = configurationService.getConfigurableComponentPids();\n\n        for (String pid : pids) {\n            assertTrue(ccPids.contains(pid));\n        }\n    }\n\n    private void thenConfigurationsContains(String pid) {\n        assertTrue(this.configurations.stream().anyMatch(conf -> conf.getPid().equals(pid)));\n    }\n\n    private void thenConfigurationsSizeIs(int expectedSize) {\n        assertEquals(expectedSize, this.configurations.size());\n    }\n\n    private void thenConfigurationIsNull() {\n        assertNull(this.configuration);\n    }\n\n    private void thenConfigurationHasPid(String expectedPid) {\n        assertEquals(expectedPid, this.configuration.getPid());\n    }\n\n    private void thenDefaultConfigurationIs(String expectedPid, boolean emptyProperties, boolean emptyDefinition) {\n        assertNotNull(\"Configuration should not be null\", this.defaultConfiguration);\n        assertEquals(expectedPid, this.defaultConfiguration.getPid());\n        assertEquals(this.defaultConfiguration.getConfigurationProperties().isEmpty(), emptyProperties);\n        if (emptyDefinition) {\n            assertNull(\"Should not be any definition\", this.defaultConfiguration.getDefinition());\n        } else {\n            assertNotNull(\"Definition should not be empty\", this.defaultConfiguration.getDefinition());\n        }\n    }\n\n    private void thenDefaultConfigurationPropertiesHas(int size, String expectedKey, Object expectedValue) {\n        assertNotNull(this.defaultConfiguration.getConfigurationProperties());\n        assertEquals(size, this.defaultConfiguration.getConfigurationProperties().size());\n        assertPropertyEquals(expectedKey, expectedValue,\n                this.defaultConfiguration.getConfigurationProperties().get(expectedKey));\n    }\n\n    private void thenDefaultConfigurationDefinitionIsPopulated() {\n        assertNotNull(\"Definition should exist\", this.defaultConfiguration.getDefinition());\n        assertNotNull(\"ID should exist\", this.defaultConfiguration.getDefinition().getId());\n        assertNotNull(\"Name should exist\", this.defaultConfiguration.getDefinition().getName());\n        assertNotNull(\"Description should exist\", this.defaultConfiguration.getDefinition().getDescription());\n        assertNotNull(\"Icon should exist\", this.defaultConfiguration.getDefinition().getIcon());\n        assertNotNull(\"AD should exist\", this.defaultConfiguration.getDefinition().getAD());\n        assertFalse(\"AD is not empty\", this.defaultConfiguration.getDefinition().getAD().isEmpty());\n    }\n\n    private void thenConfigurationPropertiesHaveNotChanged() {\n        assertPropertiesContain(this.configuration.getConfigurationProperties(),\n                this.updatedConfiguration.getConfigurationProperties());\n    }\n\n    private void thenUpdatedConfigurationPropertiesContains(Map<String, Object> expectedProps) {\n        assertPropertiesContain(expectedProps, this.updatedConfiguration.getConfigurationProperties());\n    }\n\n    private void thenComponentConfigurationsContainPidsWithExampleProperties(String... pids) {\n        for (String pid : pids) {\n            try {\n\n                ComponentConfiguration cc = ConfigurationServiceTest.configurationService\n                        .getComponentConfiguration(pid);\n\n                assertPropertiesContain(this.exampleProperties, cc.getConfigurationProperties());\n\n            } catch (Exception e) {\n                // ignore\n            }\n        }\n    }\n\n    private void thenRollbackIdIsLessThanPrevious() {\n        assertTrue(this.snapshotsBefore.iterator().next().longValue() > this.rollbackID);\n    }\n\n    private void thenRollbackIdIsGreaterThanPrevious() {\n        assertTrue(this.snapshotsBefore.iterator().next().longValue() < this.rollbackID);\n    }\n\n    private void thenLastSnapshotIsEncrypted() {\n        Set<Long> before = this.snapshotsBefore;\n        Set<Long> after = this.snapshotsAfter;\n\n        after.removeAll(before);\n\n        long snapshotID = after.iterator().next().longValue();\n        File file = new File(this.kuraSnapshotsDir, \"snapshot_\" + snapshotID + \".xml\");\n\n        try (FileReader fr = new FileReader(file)) {\n            char[] chars = new char[100];\n            fr.read(chars);\n\n            String s = new String(chars);\n            assertFalse(\"Snapshot should be encrypted\", s.contains(\"kura.service.pid=\"));\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private void thenContainsWireComponentsDefinitions(List<ComponentConfiguration> configs, boolean includesAsset) {\n        final String[] pids = { \"org.eclipse.kura.wire.CloudPublisher\", \"org.eclipse.kura.wire.CloudSubscriber\",\n                \"org.eclipse.kura.wire.Fifo\", \"org.eclipse.kura.wire.Logger\", \"org.eclipse.kura.wire.RegexFilter\",\n                \"org.eclipse.kura.wire.Timer\" };\n        for (final String pid : pids) {\n            assertTrue(configs.stream()\n                    .filter(config -> config.getPid().equals(pid) && config.getDefinition().getId().equals(pid))\n                    .findAny().isPresent());\n        }\n        boolean wireAssetFound = configs.stream().filter(\n                config -> config.getPid().equals(\"org.eclipse.kura.wire.WireAsset\") && config.getDefinition() == null)\n                .findAny().isPresent();\n        assertEquals(includesAsset, wireAssetFound);\n    }\n\n    /*\n     * Utilities\n     */\n\n    @Before\n    public void cleanUp() {\n        this.exceptionOccurred = Optional.empty();\n\n        try {\n            cleanSnapshots();\n\n            this.snapshotsBefore = ConfigurationServiceTest.configurationService.getSnapshots();\n        } catch (Exception e) {\n            this.exceptionOccurred = Optional.of(e);\n        }\n    }\n\n    private boolean snapshotContains(List<ComponentConfiguration> snapshot, String pid,\n            Map<String, Object> expectedProperties) {\n        boolean found = false;\n\n        for (ComponentConfiguration cc : snapshot) {\n            if (pid.equals(cc.getPid())) {\n                if (expectedProperties == null) {\n                    return true;\n                }\n\n                for (Entry<String, Object> e : expectedProperties.entrySet()) {\n                    String key = e.getKey();\n                    Object value = e.getValue();\n\n                    if (cc.getConfigurationProperties().containsKey(key)\n                            && value.equals(cc.getConfigurationProperties().get(key))) {\n                        found = true;\n                    }\n                }\n            }\n        }\n\n        return found;\n    }\n\n    private void assertSnapshotContains(List<ComponentConfiguration> snapshot, String pid,\n            Map<String, Object> expectedProperties) throws KuraException {\n        for (ComponentConfiguration cc : snapshot) {\n            if (pid.equals(cc.getPid())) {\n                if (expectedProperties == null) {\n                    return;\n                }\n\n                assertPropertiesContain(expectedProperties, cc.getConfigurationProperties());\n            }\n        }\n    }\n\n    private void cleanSnapshots() {\n        if (systemService != null) {\n            this.kuraSnapshotsCount = systemService.getKuraSnapshotsCount();\n            this.kuraSnapshotsDir = systemService.getKuraSnapshotsDirectory();\n        }\n\n        // remove all other snapshots\n        File dir = new File(this.kuraSnapshotsDir);\n        dir.mkdirs();\n        File[] snapshots = dir.listFiles();\n        if (snapshots != null) {\n            for (File f : snapshots) {\n                f.delete();\n            }\n        }\n    }\n\n    private boolean snapshotsEqual(List<ComponentConfiguration> snap1, List<ComponentConfiguration> snap2) {\n        List<String> pids1 = snap1.stream().flatMap(cc -> Stream.of(cc.getPid())).collect(Collectors.toList());\n        List<String> pids2 = snap2.stream().flatMap(cc -> Stream.of(cc.getPid())).collect(Collectors.toList());\n\n        return pids1.containsAll(pids2) && pids2.containsAll(pids1);\n    }\n\n    private void assertPropertiesContain(Map<String, Object> contained, Map<String, Object> container) {\n        for (Entry<String, Object> e1 : contained.entrySet()) {\n\n            final Object expected = e1.getValue();\n            final Object value = container.get(e1.getKey());\n\n            assertPropertyEquals(e1.getKey(), expected, value);\n        }\n    }\n\n    private void assertPropertyEquals(final String key, final Object expected, final Object actual) {\n        if (expected instanceof Password && actual instanceof Password) {\n            assertArrayEquals(\"property \" + key + \" does not match\", ((Password) expected).getPassword(),\n                    ((Password) actual).getPassword());\n        } else {\n            assertEquals(\"property \" + key + \" does not match\", expected, actual);\n        }\n    }\n\n    private static Map<String, Object> map(final Object... values) {\n        final Map<String, Object> result = new HashMap<>();\n\n        for (int i = 0; i < values.length; i += 2) {\n            result.put((String) values[i], values[i + 1]);\n        }\n\n        return result;\n    }\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/src/test/java/org/eclipse/kura/core/configuration/ConfigurationServiceJunitTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.configuration;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.attribute.PosixFilePermission;\nimport java.nio.file.attribute.PosixFilePermissions;\nimport java.nio.file.Files;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeSet;\n\nimport org.apache.commons.io.FileUtils;\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraPartialSuccessException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.configuration.metatype.OCDService;\nimport org.eclipse.kura.core.configuration.metatype.Tocd;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.internal.xml.marshaller.unmarshaller.XmlMarshallUnmarshallImpl;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mockito;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.component.runtime.ServiceComponentRuntime;\nimport org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;\n\npublic class ConfigurationServiceJunitTest {\n\n    @Test\n    public void testGetFactoryComponentPids() throws KuraException {\n        // test that the returned PIDs are the same as in the service and that they cannot be modified\n\n        String[] expectedPIDs = { \"pid1\", \"pid2\", \"pid3\" };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        for (final String pid : expectedPIDs) {\n            cs.registerComponentOCD(pid, null, true, null);\n        }\n\n        Set<String> factoryComponentPids = cs.getFactoryComponentPids();\n\n        assertEquals(\"same length\", 3, factoryComponentPids.size());\n\n        Object[] pidsArray = factoryComponentPids.toArray();\n        Arrays.sort(pidsArray);\n\n        for (int i = 0; i < pidsArray.length; i++) {\n            assertEquals(expectedPIDs[i], expectedPIDs[i], pidsArray[i]);\n        }\n\n        try {\n            factoryComponentPids.add(\"unsupported\");\n            fail(\"Updating PIDs should not be possible.\");\n        } catch (UnsupportedOperationException e) {\n            // OK\n        }\n    }\n\n    @Test\n    public void testCreateFactoryConfigurationNulls() {\n        // negative test; how null values are handled\n\n        ConfigurationService cs = new ConfigurationServiceImpl();\n\n        String factoryPid = null;\n        String pid = null;\n        Map<String, Object> properties = null;\n        boolean takeSnapshot = false;\n\n        try {\n            cs.createFactoryConfiguration(factoryPid, pid, properties, takeSnapshot);\n\n            fail(\"Exception expected with null pid value.\");\n        } catch (Exception e) {\n            // OK, probably\n        }\n    }\n\n    @Test\n    public void testCreateFactoryExistingPid() throws KuraException, NoSuchFieldException {\n        // negative test; what if existing PID is used\n\n        final String factoryPid = \"fpid\";\n        final String pid = \"mypid\";\n        Map<String, Object> properties = null;\n        final boolean takeSnapshot = false;\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        Map<String, String> pids = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        pids.put(pid, pid);\n\n        try {\n            cs.createFactoryConfiguration(factoryPid, pid, properties, takeSnapshot);\n\n            fail(\"Exception expected with existing pid value.\");\n        } catch (Exception e) {\n            // OK, probably\n        }\n    }\n\n    @Test\n    public void testCreateFactoryConfigurationConfigException() throws KuraException, IOException {\n        // negative test; invalid configuration exception\n\n        final String factoryPid = \"fpid\";\n        final String pid = \"mypid\";\n        Map<String, Object> properties = null;\n        final boolean takeSnapshot = false;\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        IOException ioe = new IOException(\"test\");\n        when(configAdminMock.createFactoryConfiguration(factoryPid, null)).thenThrow(ioe);\n\n        try {\n            cs.createFactoryConfiguration(factoryPid, pid, properties, takeSnapshot);\n\n            fail(\"Exception expected\");\n        } catch (KuraException e) {\n            // OK\n            assertTrue(e.getCause() instanceof IOException);\n        }\n    }\n\n    @Test\n    public void testCreateFactoryConfigurationNoSnapshot() throws KuraException, IOException {\n        // a positive test, without snapshot creation\n\n        final String factoryPid = \"fpid\";\n        final String pid = \"mypid\";\n        Map<String, Object> properties = null;\n        final boolean takeSnapshot = false;\n        final String caPid = \"caPid\";\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            // test that protected component registration was called with the proper parameters\n            @Override\n            synchronized void registerComponentConfiguration(String pid1, String servicePid, String factoryPid1) {\n                assertEquals(\"PIDs match\", pid, pid1);\n                assertEquals(\"Service PIDs match\", caPid, servicePid);\n                assertEquals(\"PIDs match\", factoryPid, factoryPid1);\n            }\n\n            // test that snapshot is not made if not configured so\n            @Override\n            public long snapshot() throws KuraException {\n                if (!takeSnapshot) {\n                    fail(\"Snapshot is turned off.\");\n                }\n                return super.snapshot();\n            }\n        };\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        Configuration cfgMock = mock(Configuration.class);\n        when(configAdminMock.createFactoryConfiguration(factoryPid, null)).thenReturn(cfgMock);\n\n        when(cfgMock.getPid()).thenReturn(caPid);\n\n        Configuration cfgMock2 = mock(Configuration.class);\n        when(configAdminMock.getConfiguration(caPid, \"?\")).thenReturn(cfgMock2);\n\n        doAnswer(invocation -> {\n            Dictionary<String, Object> dict = (Dictionary<String, Object>) invocation.getArguments()[0];\n\n            assertNotNull(dict);\n\n            assertEquals(\"one element in properties list - pid\", 1, dict.size());\n\n            assertEquals(\"expected configuration update PID\", pid, dict.elements().nextElement());\n\n            return null;\n        }).when(cfgMock2).update((Dictionary<String, Object>) any());\n\n        cs.createFactoryConfiguration(factoryPid, pid, properties, takeSnapshot);\n\n        verify(cfgMock2, times(1)).update((Dictionary<String, Object>) any());\n    }\n\n    @Test\n    public void testCreateFactoryConfigurationMergeProperties() throws KuraException, IOException {\n        // a positive test, take passed properties into account, without snapshot creation\n\n        final String factoryPid = \"fpid\";\n        final String pid = \"mypid\";\n        Map<String, Object> properties = new HashMap<>();\n        final boolean takeSnapshot = false;\n        final String caPid = \"caPid\";\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            synchronized void registerComponentConfiguration(String pid1, String servicePid, String factoryPid1) {\n                // skip this method call\n            }\n        };\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        Configuration cfgMock = mock(Configuration.class);\n        when(configAdminMock.createFactoryConfiguration(factoryPid, null)).thenReturn(cfgMock);\n\n        when(cfgMock.getPid()).thenReturn(caPid);\n\n        Configuration cfgMock2 = mock(Configuration.class);\n        when(configAdminMock.getConfiguration(caPid, \"?\")).thenReturn(cfgMock2);\n\n        properties.put(\"key1\", \"val1\");\n        properties.put(\"key2\", \"val2\");\n\n        Mockito.doAnswer(invocation -> {\n            Dictionary<String, Object> dict = (Dictionary<String, Object>) invocation.getArguments()[0];\n\n            assertNotNull(dict);\n\n            assertEquals(\"3 elements in properties list\", 3, dict.size());\n\n            assertEquals(\"additional key\", \"val1\", dict.get(\"key1\"));\n            assertEquals(\"additional key\", \"val2\", dict.get(\"key2\"));\n\n            return null;\n        }).when(cfgMock2).update((Dictionary<String, Object>) ArgumentMatchers.any());\n\n        cs.createFactoryConfiguration(factoryPid, pid, properties, takeSnapshot);\n\n        verify(cfgMock2, Mockito.times(1)).update((Dictionary<String, Object>) ArgumentMatchers.any());\n    }\n\n    @Test\n    public void testCreateFactoryConfigurationWithSnapshot() throws KuraException, IOException {\n        // a positive test, check only snapshot creation\n\n        final String factoryPid = \"fpid\";\n        final String pid = \"mypid\";\n        Map<String, Object> properties = null;\n        final boolean takeSnapshot = true;\n        final String caPid = \"caPid\";\n\n        final boolean[] snapshots = { false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            // test that protected component registration was called with the proper parameters\n            @Override\n            synchronized void registerComponentConfiguration(String pid1, String servicePid, String factoryPid1) {\n                // skip this method call\n            }\n\n            // test that snapshot is not made if not configured so\n            @Override\n            public long snapshot() throws KuraException {\n                snapshots[0] = true;\n\n                return 1L;\n            }\n        };\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        Configuration cfgMock = mock(Configuration.class);\n        when(configAdminMock.createFactoryConfiguration(factoryPid, null)).thenReturn(cfgMock);\n\n        when(cfgMock.getPid()).thenReturn(caPid);\n\n        Configuration cfgMock2 = mock(Configuration.class);\n        when(configAdminMock.getConfiguration(caPid, \"?\")).thenReturn(cfgMock2);\n\n        assertFalse(\"snapshots init OK\", snapshots[0]);\n\n        cs.createFactoryConfiguration(factoryPid, pid, properties, takeSnapshot);\n\n        assertTrue(\"snapshot() called\", snapshots[0]);\n    }\n\n    @Test\n    public void testDeleteFactoryConfigurationNulls() throws KuraException {\n        // negative test; null pid\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = null;\n        boolean takeSnapshot = false;\n\n        try {\n            cs.deleteFactoryConfiguration(pid, takeSnapshot);\n\n            fail(\"Null parameter - exception expected.\");\n        } catch (KuraException e) {\n            assertTrue(e.getMessage().contains(\"Invalid parameter\"));\n        }\n    }\n\n    @Test\n    public void testDeleteFactoryConfigurationNonFactoryComponent()\n            throws KuraException, IOException, InvalidSyntaxException {\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"pid\";\n        boolean takeSnapshot = false;\n\n        final Configuration configMock = prepareConfigForDeleteFactoryConfigTests(pid, null);\n        final ConfigurationAdmin configAdmin = prepareConfigAdminForDeleteFactoryConfigTests(configMock);\n\n        cs.setConfigurationAdmin(configAdmin);\n\n        try {\n            cs.deleteFactoryConfiguration(pid, takeSnapshot);\n        } catch (Exception e) {\n            fail(\"Exception not expected.\");\n        }\n\n        verify(configMock, Mockito.times(0)).delete();\n    }\n\n    @Test\n    public void testDeleteFactoryConfigurationNonExistingServicePid() throws KuraException {\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n        cs.setConfigurationAdmin(mock(ConfigurationAdmin.class));\n\n        String pid = \"pid\";\n        boolean takeSnapshot = false;\n\n        try {\n            cs.deleteFactoryConfiguration(pid, takeSnapshot);\n        } catch (Exception e) {\n            fail(\"Exception not expected.\");\n        }\n    }\n\n    private Configuration prepareConfigForDeleteFactoryConfigTests(final String configPid,\n            final String configFactoryPid) {\n        if (configPid == null) {\n            return null;\n        }\n\n        final Dictionary<String, Object> properties = new Hashtable<>();\n        properties.put(ConfigurationService.KURA_SERVICE_PID, configPid);\n        Configuration configMock = mock(Configuration.class);\n        if (configFactoryPid != null) {\n            properties.put(ConfigurationAdmin.SERVICE_FACTORYPID, configFactoryPid);\n            when(configMock.getFactoryPid()).thenReturn(configFactoryPid);\n        }\n\n        when(configMock.getProperties()).thenReturn(properties);\n\n        when(configMock.getPid()).thenReturn(configPid);\n\n        return configMock;\n    }\n\n    private ConfigurationAdmin prepareConfigAdminForDeleteFactoryConfigTests(Configuration config)\n            throws IOException, InvalidSyntaxException {\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n\n        if (config != null) {\n            when(configAdminMock.listConfigurations(any())).thenReturn(new Configuration[] { config });\n        }\n\n        return configAdminMock;\n    }\n\n    @Test\n    public void testDeleteFactoryConfigurationNoSnapshot() throws KuraException, IOException, InvalidSyntaxException {\n        // positive test; pid registered in factory and service pids, configuration delete is expected, no snapshot\n\n        String factoryPid = \"fpid\";\n        final String servicePid = \"spid\";\n        final boolean takeSnapshot = false;\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            synchronized void unregisterComponentConfiguration(String pid) {\n                assertEquals(\"service pid to unregister\", servicePid, pid);\n            }\n\n            @Override\n            public long snapshot() throws KuraException {\n                if (!takeSnapshot) {\n                    fail(\"Snapshot is turned off.\");\n                }\n\n                return 1L;\n            }\n        };\n\n        final Configuration configMock = prepareConfigForDeleteFactoryConfigTests(servicePid, factoryPid);\n        final ConfigurationAdmin configAdmin = prepareConfigAdminForDeleteFactoryConfigTests(configMock);\n\n        cs.setConfigurationAdmin(configAdmin);\n\n        cs.deleteFactoryConfiguration(servicePid, takeSnapshot);\n\n        verify(configMock, Mockito.times(1)).delete();\n    }\n\n    @Test\n    public void testDeleteFactoryConfigurationWithSnapshot() throws KuraException, IOException, InvalidSyntaxException {\n        // positive test; pid registered in factory and service pids, configuration delete is expected, take a snapshot\n\n        String factoryPid = \"fpid\";\n        final String servicePid = \"spid\";\n        final boolean takeSnapshot = true;\n\n        final boolean[] snapshots = { false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            synchronized void unregisterComponentConfiguration(String pid) {\n                assertEquals(\"service pid to unregister\", servicePid, pid);\n            }\n\n            @Override\n            public long snapshot() throws KuraException {\n                snapshots[0] = true;\n\n                return 1L;\n            }\n        };\n\n        final Configuration configMock = prepareConfigForDeleteFactoryConfigTests(servicePid, factoryPid);\n        final ConfigurationAdmin configAdmin = prepareConfigAdminForDeleteFactoryConfigTests(configMock);\n\n        cs.setConfigurationAdmin(configAdmin);\n\n        assertFalse(\"snapshot still untouched\", snapshots[0]);\n\n        cs.deleteFactoryConfiguration(servicePid, takeSnapshot);\n\n        verify(configMock, Mockito.times(1)).delete();\n        assertTrue(\"snapshot taken\", snapshots[0]);\n    }\n\n    @Test\n    public void testGetConfigurableComponentPidsEmpty() {\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        Set<String> configurableComponentPids = cs.getConfigurableComponentPids();\n\n        assertEquals(\"same length\", 0, configurableComponentPids.size());\n\n        try {\n            configurableComponentPids.add(\"unsupported\");\n            fail(\"Updating PIDs should not be possible.\");\n        } catch (UnsupportedOperationException e) {\n            // OK\n        }\n    }\n\n    @Test\n    public void testGetConfigurableComponentPids() throws NoSuchFieldException {\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String[] expectedPIDs = { \"pid1\", \"pid2\", \"pid3\" };\n\n        Set<String> s = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        s.addAll(Arrays.asList(expectedPIDs));\n\n        Set<String> configurableComponentPids = cs.getConfigurableComponentPids();\n\n        assertEquals(\"same length\", 3, configurableComponentPids.size());\n\n        Object[] pidsArray = configurableComponentPids.toArray();\n        Arrays.sort(pidsArray);\n\n        for (int i = 0; i < pidsArray.length; i++) {\n            assertEquals(expectedPIDs[i], expectedPIDs[i], pidsArray[i]);\n        }\n\n        try {\n            configurableComponentPids.add(\"unsupported\");\n            fail(\"Updating PIDs should not be possible.\");\n        } catch (UnsupportedOperationException e) {\n            // OK\n        }\n    }\n\n    @Test\n    public void testDecryptPasswords() throws KuraException {\n        // test password decryption\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        ComponentConfigurationImpl config = new ComponentConfigurationImpl();\n        Map<String, Object> props = new HashMap<>();\n        config.setProperties(props);\n        String passStr = \"passval1\";\n        Password pass = new Password(passStr);\n        String passKey = \"pass1\";\n        props.put(passKey, pass);\n        props.put(\"k2\", \"val2\");\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        char[] decpass = \"decpass\".toCharArray();\n        when(cryptoServiceMock.decryptAes(passStr.toCharArray())).thenReturn(decpass);\n\n        assertEquals(\"config size\", 2, props.size());\n\n        cs.decryptConfigurationProperties(config.getConfigurationProperties());\n\n        verify(cryptoServiceMock, times(1)).decryptAes(passStr.toCharArray());\n\n        Map<String, Object> result = config.getConfigurationProperties();\n        assertNotNull(\"properties not null\", result);\n        assertEquals(\"config properties size\", 2, result.size());\n        assertTrue(\"contains password\", result.containsKey(passKey));\n        assertArrayEquals(\"decrypted pass OK\", decpass, ((Password) result.get(passKey)).getPassword());\n        assertArrayEquals(\"decrypted pass OK - reference\", decpass, ((Password) props.get(passKey)).getPassword());\n    }\n\n    @Test\n    public void testDecryptPasswordsException() throws KuraException {\n        // test error in password decryption\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        ComponentConfigurationImpl config = new ComponentConfigurationImpl();\n        Map<String, Object> props = new HashMap<>();\n        config.setProperties(props);\n        Password pass = new Password(\"passval1\");\n        String passKey = \"pass1\";\n        props.put(passKey, pass);\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        KuraException exc = new KuraException(KuraErrorCode.STORE_ERROR);\n        when(cryptoServiceMock.decryptAes((char[]) ArgumentMatchers.any())).thenThrow(exc);\n\n        assertEquals(\"config size before decryption\", 1, props.size());\n\n        cs.decryptConfigurationProperties(config.getConfigurationProperties());\n\n        verify(cryptoServiceMock, times(1)).decryptAes((char[]) ArgumentMatchers.any());\n\n        assertEquals(\"config size after decryption\", 1, props.size());\n    }\n\n    @Test(expected = NullPointerException.class)\n    public void testMergeWithDefaultsNulls() {\n        // test with null parameters - null properties means error and NPE is expected\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        OCD ocd = null;\n        Map<String, Object> properties = null;\n\n        cs.mergeWithDefaults(ocd, properties);\n    }\n\n    @Test\n    public void testMergeWithDefaultsEmpty() {\n        // empty input\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        OCD ocd = new Tocd();\n        Map<String, Object> properties = new HashMap<>();\n\n        boolean merged = cs.mergeWithDefaults(ocd, properties);\n\n        assertFalse(\"nothing to merge\", merged);\n        assertEquals(\"still empty\", 0, properties.size());\n    }\n\n    @Test\n    public void testMergeWithDefaults() {\n        // a few default values, a few overrides, one ovelap\n\n        final Map<String, Object> props = new HashMap<>();\n        String prop1Key = \"prop1\";\n        String prop1DefValue = \"prop1DefValue\";\n        props.put(prop1Key, prop1DefValue);\n        props.put(\"defKey2\", \"defValue2\");\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            Map<String, Object> getDefaultProperties(OCD ocd) {\n                return props;\n            }\n        };\n\n        Tocd ocd = new Tocd();\n        Map<String, Object> properties = new HashMap<>();\n        String prop1Value = \"value1\";\n        properties.put(prop1Key, prop1Value);\n        properties.put(\"key2\", \"value2\");\n\n        assertNotEquals(prop1Value, prop1DefValue);\n\n        boolean merged = cs.mergeWithDefaults(ocd, properties);\n\n        assertTrue(\"properties merged\", merged);\n        assertEquals(\"added a property\", 3, properties.size());\n        assertEquals(\"value override OK\", prop1Value, properties.get(prop1Key));\n        assertTrue(\"value override only\", properties.containsKey(\"key2\"));\n        assertTrue(\"default value only\", properties.containsKey(\"defKey2\"));\n    }\n\n    @Test\n    public void testRegisterSelfConfiguringComponentNull() throws NoSuchFieldException {\n        // test behavior with null - just abort\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        Set<String> allPidsMock = mock(Set.class);\n        TestUtil.setFieldValue(cs, \"allActivatedPids\", allPidsMock);\n\n        String pid = null;\n\n        when(allPidsMock.contains(ArgumentMatchers.any())).thenThrow(new RuntimeException());\n\n        cs.registerSelfConfiguringComponent(pid, pid);\n\n        verify(allPidsMock, times(0)).contains(ArgumentMatchers.any());\n    }\n\n    @Test\n    public void testRegisterSelfConfiguringComponentNonExistingPID() throws NoSuchFieldException {\n        // test behavior with non-existing pid\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        Set<String> allPidsMock = mock(Set.class);\n        TestUtil.setFieldValue(cs, \"allActivatedPids\", allPidsMock);\n\n        String pid = \"pid\";\n\n        when(allPidsMock.contains(pid)).thenReturn(false);\n        when(allPidsMock.add(pid)).thenReturn(true);\n\n        Map<String, String> spbp = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        Set<String> asc = (Set<String>) TestUtil.getFieldValue(cs, \"activatedSelfConfigComponents\");\n\n        assertEquals(\"empty service pids\", 0, spbp.size());\n        assertEquals(\"empty activated configured components\", 0, asc.size());\n\n        cs.registerSelfConfiguringComponent(pid, pid);\n\n        verify(allPidsMock, times(1)).contains(pid);\n        verify(allPidsMock, times(1)).add(pid);\n\n        assertEquals(\"added pid to service pids\", 1, spbp.size());\n        assertEquals(\"added pid to activated configured components\", 1, asc.size());\n    }\n\n    @Test\n    public void testRegisterSelfConfiguringComponentExistingPID() throws NoSuchFieldException {\n        // test behavior with existing pid\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        Set<String> allPidsMock = mock(Set.class);\n        TestUtil.setFieldValue(cs, \"allActivatedPids\", allPidsMock);\n\n        String pid = \"pid\";\n\n        when(allPidsMock.contains(pid)).thenReturn(true);\n        when(allPidsMock.add(pid)).thenThrow(new RuntimeException());\n\n        Map<String, String> spbp = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        Set<String> asc = (Set<String>) TestUtil.getFieldValue(cs, \"activatedSelfConfigComponents\");\n\n        assertEquals(\"empty service pids\", 0, spbp.size());\n        assertEquals(\"empty activated configured components\", 0, asc.size());\n\n        cs.registerSelfConfiguringComponent(pid, pid);\n\n        verify(allPidsMock, times(1)).contains(pid);\n        verify(allPidsMock, times(0)).add(pid);\n\n        assertEquals(\"not added pid to service pids\", 1, spbp.size());\n        assertEquals(\"not added pid to activated configured components\", 1, asc.size());\n    }\n\n    @Test\n    public void testUnregisterComponentConfigurationNull() throws NoSuchFieldException {\n        // test behavior with null - just abort\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        Set<String> allPidsMock = mock(Set.class);\n        TestUtil.setFieldValue(cs, \"allActivatedPids\", allPidsMock);\n\n        String pid = null;\n\n        when(allPidsMock.contains(ArgumentMatchers.any())).thenThrow(new RuntimeException());\n\n        cs.unregisterComponentConfiguration(pid);\n\n        verify(allPidsMock, times(0)).contains(ArgumentMatchers.any());\n    }\n\n    @Test\n    public void testUnregisterComponentConfiguration() throws NoSuchFieldException {\n        // test behavior with non-existing pid\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"pid\";\n\n        Set<String> allPids = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        allPids.add(pid + \"1\");\n        Map<String, String> spbp = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        spbp.put(pid + \"1\", pid);\n        Set<String> asc = (Set<String>) TestUtil.getFieldValue(cs, \"activatedSelfConfigComponents\");\n        asc.add(pid + \"1\");\n\n        assertEquals(\"all pids size\", 1, allPids.size());\n        assertEquals(\"service pids size\", 1, spbp.size());\n        assertEquals(\"activated pids size\", 1, asc.size());\n\n        assertFalse(\"all pids don't contain pid\", allPids.contains(pid));\n        assertFalse(\"service pids don't contain pid\", spbp.containsKey(pid));\n        assertFalse(\"activated pids don't contain pid\", asc.contains(pid));\n\n        cs.unregisterComponentConfiguration(pid);\n\n        // no change\n        assertEquals(\"all pids size\", 1, allPids.size());\n        assertEquals(\"service pids size\", 1, spbp.size());\n        assertEquals(\"activated pids size\", 1, asc.size());\n\n        assertFalse(\"all pids don't contain pid\", allPids.contains(pid));\n        assertFalse(\"service pids don't contain pid\", spbp.containsKey(pid));\n        assertFalse(\"activated pids don't contain pid\", asc.contains(pid));\n    }\n\n    @Test\n    public void testUpdateConfigurationStringMapOfStringObject() throws Throwable {\n        // test delegation\n\n        final String pid = \"pid\";\n        final Map<String, Object> properties = new HashMap<>();\n\n        final boolean[] calls = { false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public synchronized void updateConfiguration(String pidToUpdate,\n                    java.util.Map<String, Object> propertiesToUpdate, boolean takeSnapshot) throws KuraException {\n\n                calls[0] = true;\n\n                assertEquals(\"pid matches\", pid, pidToUpdate);\n                assertEquals(\"properties match\", properties, propertiesToUpdate);\n            }\n        };\n\n        cs.updateConfiguration(pid, properties);\n\n        assertTrue(\"method called\", calls[0]);\n    }\n\n    @Test\n    public void testUpdateConfigurationStringMapOfStringObjectBoolean() throws Throwable {\n        // test delegation\n\n        final String pid = \"pid\";\n        final Map<String, Object> propertiesToUpdate = new HashMap<>();\n\n        final boolean[] calls = { false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public synchronized void updateConfigurations(List<ComponentConfiguration> configsToUpdate,\n                    boolean takeSnapshot) throws KuraException {\n\n                calls[0] = true;\n\n                assertEquals(\"one configuration added\", 1, configsToUpdate.size());\n\n                ComponentConfiguration cfg = configsToUpdate.get(0);\n                assertNotNull(\"new config initialized\", cfg);\n                assertEquals(\"pid matches\", pid, cfg.getPid());\n                assertEquals(\"properties match\", propertiesToUpdate, cfg.getConfigurationProperties());\n\n                assertTrue(\"take snapshot - true\", takeSnapshot);\n            }\n        };\n\n        cs.updateConfiguration(pid, propertiesToUpdate, true);\n\n        assertTrue(\"method called\", calls[0]);\n    }\n\n    @Test\n    public void testUpdateConfigurationsListOfComponentConfiguration() throws KuraException {\n        // test delegation\n\n        final List<ComponentConfiguration> configs = new ArrayList<>();\n\n        final boolean[] calls = { false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public synchronized void updateConfigurations(List<ComponentConfiguration> configsToUpdate,\n                    boolean takeSnapshot) throws KuraException {\n\n                calls[0] = true;\n\n                assertEquals(\"list\", configs, configsToUpdate);\n\n                assertTrue(\"take snapshot - true\", takeSnapshot);\n            }\n        };\n\n        cs.updateConfigurations(configs);\n\n        assertTrue(\"method called\", calls[0]);\n    }\n\n    @Test\n    public void testUpdateConfigurationsListOfComponentConfigurationBoolean()\n            throws KuraException, NoSuchFieldException {\n        // test that password encryption is attempted (but decrypt doesn't fail, which is OK) and some other calls are\n        // made - stop with usage of allActivatedPids in getComponentConfigurationsInternal\n\n        boolean takeSnapshot = false;\n        final List<ComponentConfiguration> configs = new ArrayList<>();\n        configs.add(null);\n        ComponentConfigurationImpl cfg = new ComponentConfigurationImpl();\n        Map<String, Object> props = new HashMap<>();\n        cfg.setProperties(props);\n        props.put(\"pass\", new Password(\"pass\"));\n        configs.add(cfg);\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        when(cryptoServiceMock.decryptAes((char[]) any())).thenReturn(\"dec\".toCharArray());\n\n        // make updateConfigurationsInternal fail with NPE\n        TestUtil.setFieldValue(cs, \"allActivatedPids\", null);\n\n        try {\n            cs.updateConfigurations(configs, takeSnapshot);\n            fail(\"Exception expected\");\n        } catch (NullPointerException e) {\n            // OK\n        }\n\n        verify(cryptoServiceMock, times(1)).decryptAes((char[]) any());\n    }\n\n    @Test\n    public void testGetSnapshots() throws KuraException {\n        // test that lower-level method (getSnapshotsInternal) is called; with no/null snapshot directory\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        Set<Long> snapshots = cs.getSnapshots();\n\n        assertNotNull(\"list is initialized\", snapshots);\n        assertEquals(\"list is empty\", 0, snapshots.size());\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsDirectory();\n    }\n\n    @Test\n    public void testGetSnapshotsInternalNullDir() throws Throwable {\n        // test with no/null snapshot directory\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        Set<Long> snapshots = (Set<Long>) TestUtil.invokePrivate(cs, \"getSnapshotsInternal\");\n\n        assertNotNull(\"list is initialized\", snapshots);\n        assertEquals(\"list is empty\", 0, snapshots.size());\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsDirectory();\n    }\n\n    @Test\n    public void testGetSnapshotsInternalNotDir() throws Throwable {\n        // test with non-existing snapshot directory\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsDirectory()).thenReturn(\"nonExistingDir\");\n\n        Set<Long> snapshots = (Set<Long>) TestUtil.invokePrivate(cs, \"getSnapshotsInternal\");\n\n        assertNotNull(\"list is initialized\", snapshots);\n        assertEquals(\"list is empty\", 0, snapshots.size());\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsDirectory();\n    }\n\n    @Test\n    public void testGetSnapshotsInternal() throws Throwable {\n        // test with existing and full snapshot directory\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        String dir = \"existingDirGSI\";\n        when(systemServiceMock.getKuraSnapshotsDirectory()).thenReturn(dir);\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f1 = new File(dir, \"f1.xml\");\n        File f2 = new File(dir, \"snapshot2.xml\");\n        File f3 = new File(dir, \"snapshot_3.xml\");\n        File f4 = new File(dir, \"snapshot_4_.xml\");\n        File f5 = new File(dir, \"Snapshot_5.XML\");\n\n        f1.createNewFile();\n        f2.createNewFile();\n        f3.createNewFile();\n        f4.createNewFile();\n        f5.createNewFile();\n\n        f1.deleteOnExit();\n        f2.deleteOnExit();\n        f3.deleteOnExit();\n        f4.deleteOnExit();\n        f5.deleteOnExit();\n\n        Set<Long> snapshots = (Set<Long>) TestUtil.invokePrivate(cs, \"getSnapshotsInternal\");\n\n        f1.delete();\n        f2.delete();\n        f3.delete();\n        f4.delete();\n        f5.delete();\n        d1.delete();\n\n        assertNotNull(\"list is initialized\", snapshots);\n        assertEquals(\"list has only so many pids\", 1, snapshots.size());\n        assertEquals(\"expected pid\", 3, (long) snapshots.iterator().next());\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsDirectory();\n    }\n\n    @Test\n    public void testGetSnapshotFileNull() throws Throwable {\n        // test if it works with null directory\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        try {\n            Object obj = TestUtil.invokePrivate(cs, \"getSnapshotFile\", 123);\n            assertNull(\"Null expected to produce null\", obj);\n        } catch (NullPointerException e) {\n            fail(\"Method result not checked.\");\n        }\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsDirectory();\n    }\n\n    @Test\n    public void testGetSnapshotFile() throws Throwable {\n        // verify that the file path and name are OK\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        String dir = \"dirGSF\";\n        when(systemServiceMock.getKuraSnapshotsDirectory()).thenReturn(dir);\n\n        File file = (File) TestUtil.invokePrivate(cs, \"getSnapshotFile\", 123);\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsDirectory();\n\n        assertTrue(\"path pattern matches\", file.getAbsolutePath().matches(\".*dirGSF[/\\\\\\\\]snapshot_123.xml$\"));\n    }\n\n    @Test\n    public void testGetSnapshotNullXmlCfgs() throws KuraException {\n        // test calling with null configurations list\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            XmlComponentConfigurations loadEncryptedSnapshotFileContent(long snapshotID) throws KuraException {\n                return null;\n            }\n        };\n\n        long sid = 0;\n        try {\n            List<ComponentConfiguration> snapshot = cs.getSnapshot(sid);\n            assertNotNull(\"Null not expected\", snapshot);\n            assertTrue(\"Should be empty\", snapshot.isEmpty());\n        } catch (Exception e) {\n            fail(\"Method result not checked.\");\n        }\n    }\n\n    @Test\n    public void testGetSnapshotPasswordDecryptionException() throws KuraException {\n        // test password decryption failure - log only\n        final boolean[] calls = { false, false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            XmlComponentConfigurations loadEncryptedSnapshotFileContent(long snapshotID) throws KuraException {\n                XmlComponentConfigurations cfgs = new XmlComponentConfigurations();\n                List<ComponentConfiguration> configurations = new ArrayList<>();\n                cfgs.setConfigurations(configurations);\n\n                configurations.add(null);\n                ComponentConfigurationImpl cfg = new ComponentConfigurationImpl();\n                configurations.add(cfg);\n\n                calls[0] = true;\n\n                return cfgs;\n            }\n\n            @Override\n            void decryptConfigurationProperties(Map<String, Object> configProps) {\n                calls[1] = true;\n\n                throw new RuntimeException(\"test\");\n            }\n        };\n\n        long sid = 0;\n        List<ComponentConfiguration> configs = null;\n        try {\n            configs = cs.getSnapshot(sid);\n        } catch (Exception e) {\n            fail(\"Exception not expected.\");\n        }\n\n        assertTrue(\"config loaded\", calls[0]);\n        assertTrue(\"passwords decrypted\", calls[1]);\n        assertNotNull(\"configurations list exists\", configs);\n        assertEquals(\"configurations list filled\", 2, configs.size());\n        assertNull(configs.get(0));\n        assertNotNull(configs.get(1));\n    }\n\n    @Test\n    public void testGetSnapshot() throws KuraException {\n        // test successful run\n\n        final boolean[] calls = { false, false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            XmlComponentConfigurations loadEncryptedSnapshotFileContent(long snapshotID) throws KuraException {\n                XmlComponentConfigurations cfgs = new XmlComponentConfigurations();\n                List<ComponentConfiguration> configurations = new ArrayList<>();\n                cfgs.setConfigurations(configurations);\n\n                configurations.add(null);\n                ComponentConfigurationImpl cfg = new ComponentConfigurationImpl();\n                configurations.add(cfg);\n\n                calls[0] = true;\n\n                return cfgs;\n            }\n\n            @Override\n            void decryptConfigurationProperties(Map<String, Object> configProps) {\n                calls[1] = true;\n            }\n        };\n\n        long sid = 0;\n        List<ComponentConfiguration> configs = cs.getSnapshot(sid);\n\n        assertTrue(\"config loaded\", calls[0]);\n        assertTrue(\"passwords decrypted\", calls[1]);\n        assertNotNull(\"configurations list exists\", configs);\n        assertEquals(\"configurations list filled\", 2, configs.size());\n        assertNull(configs.get(0));\n        assertNotNull(configs.get(1));\n    }\n\n    @Test\n    public void testLoadEncryptedSnapshotFileContentNoFile() throws KuraException {\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        long snapshotID = 123;\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        String dir = \"someDir\";\n        when(systemServiceMock.getKuraSnapshotsDirectory()).thenReturn(dir);\n\n        try {\n            cs.loadEncryptedSnapshotFileContent(snapshotID);\n\n            fail(\"Expected exception: file not found\");\n        } catch (KuraException e) {\n            assertEquals(\"correct code\", KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND, e.getCode());\n        }\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsDirectory();\n    }\n\n    @Test\n    public void testLoadEncryptedSnapshotFileContentNullDecrypt() throws KuraException, IOException {\n        // test decryption failure while loading an encrypted snapshot\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        long snapshotID = 123;\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        String dir = \"someDir\";\n        when(systemServiceMock.getKuraSnapshotsDirectory()).thenReturn(dir);\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f1 = new File(dir, \"snapshot_\" + snapshotID + \".xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        when(cryptoServiceMock.decryptAes((char[]) any())).thenReturn(null);\n\n        try {\n            cs.loadEncryptedSnapshotFileContent(snapshotID);\n        } catch (NullPointerException e) {\n            fail(\"Decryption result not checked for null value.\");\n        } catch (KuraException e) {\n            assertEquals(KuraErrorCode.DECODER_ERROR, e.getCode());\n        }\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsDirectory();\n\n        f1.delete();\n        d1.delete();\n    }\n\n    @Test\n    public void testLoadEncryptedSnapshotFileContent() throws Exception {\n        // load an 'encrypted' snapshot file\n\n        String decrypted = prepareSnapshotXML();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n\n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n\n        long snapshotID = 123;\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        String dir = \"someDir\";\n        when(systemServiceMock.getKuraSnapshotsDirectory()).thenReturn(dir);\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f1 = new File(dir, \"snapshot_\" + snapshotID + \".xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n\n        FileWriter fw = new FileWriter(f1);\n        fw.append(IOUtils.toString(\n                ConfigurationServiceJunitTest.class.getResourceAsStream(\"/expected_snapshot_with_description.xml\"),\n                StandardCharsets.UTF_8.name()));\n        fw.close();\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        // ensure the proper file is read\n        when(cryptoServiceMock.aesDecryptingStream((InputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, InputStream.class);\n        });\n\n        XmlComponentConfigurations configurations = cs.loadEncryptedSnapshotFileContent(snapshotID);\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsDirectory();\n        verify(cryptoServiceMock, times(1)).aesDecryptingStream((InputStream) ArgumentMatchers.any());\n\n        f1.delete();\n        d1.delete();\n\n        assertNotNull(\"configurations object is returned\", configurations);\n        assertNotNull(\"configurations list is returned\", configurations.getConfigurations());\n        assertEquals(\"configurations list is not empty\", 1, configurations.getConfigurations().size());\n\n        ComponentConfiguration cfg1 = configurations.getConfigurations().get(0);\n        assertEquals(\"correct snapshot\", \"123\", cfg1.getPid());\n        assertNotNull(\"configuration properties map is returned\", cfg1.getConfigurationProperties());\n        assertEquals(\"configuration properties map is not empty\", 1, cfg1.getConfigurationProperties().size());\n    }\n\n    @Test\n    public void testLoadLatestSnapshotConfigurationsNullSnapshots() throws Throwable {\n        // test null snapshot pids list\n\n        final Set<Long> snapshotList = null;\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return snapshotList;\n            }\n        };\n\n        List<ComponentConfigurationImpl> result = (List<ComponentConfigurationImpl>) TestUtil.invokePrivate(cs,\n                \"loadLatestSnapshotConfigurations\");\n\n        assertTrue(\"empty result\", result.isEmpty());\n    }\n\n    @Test\n    public void testLoadLatestSnapshotConfigurationsEmptySnapshots() throws Throwable {\n        // test empty snapshot pids list\n\n        final Set<Long> snapshotList = new TreeSet<>();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return snapshotList;\n            }\n        };\n\n        List<ComponentConfigurationImpl> result = (List<ComponentConfigurationImpl>) TestUtil.invokePrivate(cs,\n                \"loadLatestSnapshotConfigurations\");\n\n        assertTrue(\"empty result\", result.isEmpty());\n    }\n\n    @Test\n    public void testLoadLatestSnapshotConfigurationsNullXML() throws Throwable {\n        // test no XML being returned\n\n        final Set<Long> snapshotList = new TreeSet<>();\n        snapshotList.add(123L);\n        snapshotList.add(1234L);\n\n        final boolean[] calls = { false, false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                calls[0] = true;\n                return snapshotList;\n            }\n\n            @Override\n            XmlComponentConfigurations loadEncryptedSnapshotFileContent(long snapshotID) throws KuraException {\n                calls[1] = true;\n\n                assertEquals(1234L, snapshotID);\n\n                return null;\n            }\n        };\n\n        List<ComponentConfigurationImpl> result = (List<ComponentConfigurationImpl>) TestUtil.invokePrivate(cs,\n                \"loadLatestSnapshotConfigurations\");\n\n        assertNull(\"null result\", result);\n\n        assertTrue(\"call snapshots\", calls[0]);\n        assertTrue(\"call load xml\", calls[1]);\n    }\n\n    @Test\n    public void testLoadLatestSnapshotConfigurationsXmlLoads() throws Throwable {\n        // test scenario where XML is actually loaded from encrypted file\n\n        final Set<Long> snapshotList = new TreeSet<>();\n        snapshotList.add(123L);\n        snapshotList.add(1234L);\n\n        final XmlComponentConfigurations xmlComponentConfigurations = new XmlComponentConfigurations();\n        List<ComponentConfiguration> configurations = new ArrayList<>();\n        xmlComponentConfigurations.setConfigurations(configurations);\n\n        final boolean[] calls = { false, false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                calls[0] = true;\n                return snapshotList;\n            }\n\n            @Override\n            XmlComponentConfigurations loadEncryptedSnapshotFileContent(long snapshotID) throws KuraException {\n                calls[1] = true;\n\n                assertEquals(1234L, snapshotID);\n\n                return xmlComponentConfigurations;\n            }\n        };\n\n        List<ComponentConfigurationImpl> result = (List<ComponentConfigurationImpl>) TestUtil.invokePrivate(cs,\n                \"loadLatestSnapshotConfigurations\");\n\n        assertNotNull(\"xml config not null\", result);\n\n        assertTrue(\"call snapshots\", calls[0]);\n        assertTrue(\"call load xml\", calls[1]);\n    }\n\n    @Test\n    public void testLoadLatestSnapshotConfigurationsRecursiveAfterEncryption() throws Throwable {\n        // test scenario where latest snapshot is not encrypted and all snapshots are encrypted before being loaded\n\n        final Set<Long> snapshotList = new TreeSet<>();\n        snapshotList.add(123L);\n        snapshotList.add(1234L);\n\n        final XmlComponentConfigurations xmlComponentConfigurations = new XmlComponentConfigurations();\n        List<ComponentConfiguration> configurations = new ArrayList<>();\n        xmlComponentConfigurations.setConfigurations(configurations);\n\n        final String dir = \"snapDir\";\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f1 = new File(d1, \"snapshot_123.xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n        File f2 = new File(d1, \"snapshot_1234.xml\");\n        f2.createNewFile();\n        f2.deleteOnExit();\n\n        final int[] calls = { 0, 0 };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                calls[0]++;\n                if (calls[0] < 3) {\n                    return snapshotList;\n                } else {\n                    return null;\n                }\n            }\n\n            @Override\n            XmlComponentConfigurations loadEncryptedSnapshotFileContent(long snapshotID) throws KuraException {\n                calls[1]++;\n                throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR);\n            }\n        };\n\n        List<ComponentConfigurationImpl> result = (List<ComponentConfigurationImpl>) TestUtil.invokePrivate(cs,\n                \"loadLatestSnapshotConfigurations\");\n\n        assertTrue(\"xml config empty\", result.isEmpty());\n\n        assertEquals(\"call snapshots\", 4, calls[0]);\n        assertEquals(\"call load xml\", 3, calls[1]);\n    }\n\n    @Test\n    public void testEncryptPlainSnapshotsNoFile() throws Throwable {\n        // snapshot file doesn't exist\n\n        final Set<Long> snapshotList = new TreeSet<>();\n        snapshotList.add(234L);\n\n        final String dir = \"snapshotDirEPSNF\";\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return snapshotList;\n            }\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n        };\n\n        try {\n            TestUtil.invokePrivate(cs, \"encryptPlainSnapshots\");\n            fail(\"Exception expected.\");\n        } catch (KuraException e) {\n            assertEquals(\"exception code OK\", KuraErrorCode.CONFIGURATION_ERROR, e.getCode());\n        }\n    }\n\n    @Test\n    public void testEncryptPlainSnapshots() throws Throwable {\n        // test that everything works\n\n        final Set<Long> snapshotList = new TreeSet<>();\n        snapshotList.add(223L);\n\n        // prepare a valid snapshot_123.xml\n        String cfgxml = prepareSnapshotXML();\n\n        final String dir = \"snapshotDirEPS\";\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f1 = new File(dir, \"snapshot_223.xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n\n        FileWriter fw = new FileWriter(f1);\n        fw.append(cfgxml);\n        fw.close();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return snapshotList;\n            }\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n\n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n\n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        when(cryptoServiceMock.aesEncryptingStream((OutputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, OutputStream.class);\n        });\n\n        BundleContext bundleContext = mock(BundleContext.class);\n        TestUtil.setFieldValue(cs, \"bundleContext\", bundleContext);\n\n        TestUtil.invokePrivate(cs, \"encryptPlainSnapshots\");\n\n        verify(cryptoServiceMock, times(1)).aesEncryptingStream((OutputStream) ArgumentMatchers.any());\n\n        FileReader fr = new FileReader(f1);\n        assertTrue(\"snapshot file was created\", f1.exists());\n\n        String expectedXml = IOUtils.toString(\n                ConfigurationServiceJunitTest.class.getResourceAsStream(\"/expected_snapshot_without_description.xml\"),\n                StandardCharsets.UTF_8.name());\n        String actualXml = FileUtils.readFileToString(f1, StandardCharsets.UTF_8);\n\n        assertEquals(expectedXml, actualXml);\n\n        f1.delete();\n        d1.delete();\n    }\n\n    private String prepareSnapshotXml(final XmlComponentConfigurations configs) throws KuraException {\n        XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n        return xmlMarshaller.marshal(configs);\n    }\n\n    private String prepareSnapshotXML() throws Exception {\n        return prepareSnapshotXml(prepareSnapshot());\n    }\n\n    private XmlComponentConfigurations prepareSnapshot(final Map<String, Object> configProps) {\n        XmlComponentConfigurations cfgs = new XmlComponentConfigurations();\n\n        List<ComponentConfiguration> cfglist = new ArrayList<>();\n        ComponentConfigurationImpl cfg = new ComponentConfigurationImpl();\n        cfg.setPid(\"123\");\n        cfg.setProperties(configProps);\n        Tocd definition = new Tocd();\n        definition.setDescription(\"description\");\n        cfg.setDefinition(definition);\n        cfglist.add(cfg);\n        cfgs.setConfigurations(cfglist);\n\n        return cfgs;\n    }\n\n    private XmlComponentConfigurations prepareSnapshot() {\n        return prepareSnapshot(Collections.singletonMap(\"pass\", \"pass\"));\n    }\n\n    @Test\n    public void testWriteSnapshotFileNotFile() throws Throwable {\n        // force a FileNotFound exception resulting in internal error KuraException\n\n        long sid = 323L;\n\n        XmlComponentConfigurations cfg = prepareSnapshot();\n\n        final String dir = \"snapshotDirWSFNF\";\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File d2 = new File(d1, \"snapshot_\" + sid + \".xml\");\n        d2.mkdirs();\n        d2.deleteOnExit();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n\n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n\n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        when(cryptoServiceMock.aesEncryptingStream((OutputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, OutputStream.class);\n        });\n\n        try {\n            TestUtil.invokePrivate(cs, \"writeSnapshot\", sid, cfg);\n            fail(\"Exception expected due to 'file' being directory.\");\n        } catch (KuraException e) {\n            assertEquals(\"Error code.\", KuraErrorCode.IO_ERROR, e.getCode());\n        }\n\n        verify(cryptoServiceMock, times(1)).aesEncryptingStream((OutputStream) ArgumentMatchers.any());\n\n        d1.delete();\n        d2.delete();\n    }\n\n    @Test\n    public void testWriteSnapshot() throws Throwable {\n        // test the normal flow\n\n        long sid = 323L;\n\n        XmlComponentConfigurations cfg = prepareSnapshot();\n\n        final String dir = \"snapshotDirWS\";\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n\n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n\n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n\n        cs.setCryptoService(cryptoServiceMock);\n\n        when(cryptoServiceMock.aesEncryptingStream((OutputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, OutputStream.class);\n        });\n\n        BundleContext bundleContext = mock(BundleContext.class);\n        TestUtil.setFieldValue(cs, \"bundleContext\", bundleContext);\n\n        TestUtil.invokePrivate(cs, \"writeSnapshot\", sid, cfg);\n\n        verify(cryptoServiceMock, times(1)).aesEncryptingStream((OutputStream) ArgumentMatchers.any());\n\n        File f1 = new File(d1, \"snapshot_\" + sid + \".xml\");\n        f1.deleteOnExit();\n        assertTrue(\"snapshot file was created\", f1.exists());\n\n        String expectedXml = IOUtils.toString(\n                ConfigurationServiceJunitTest.class.getResourceAsStream(\"/expected_snapshot_with_description.xml\"),\n                StandardCharsets.UTF_8.name());\n        String actualXml = FileUtils.readFileToString(f1, StandardCharsets.UTF_8);\n\n        assertEquals(expectedXml, actualXml);\n\n        f1.delete();\n        d1.delete();\n    }\n\n    @Test\n    public void testGarbageCollectionOldSnapshotsZero() throws Throwable {\n        // test scenario where 0 snapshots are configured to remain, but snapshot_0.xml prevents deletion of all of them\n        final String dir = \"gcosDir0\";\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f0 = new File(dir, \"snapshot_0.xml\"); // special snapshot file\n        f0.createNewFile();\n        f0.deleteOnExit();\n        File f1 = new File(dir, \"snapshot_121.xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n        };\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        // API doesn't state 0 snapshots is illegal return value\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(0);\n\n        try {\n            TestUtil.invokePrivate(cs, \"garbageCollectionOldSnapshots\");\n        } catch (NullPointerException e) {\n            fail(\"Exception not expected.\");\n        }\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        assertTrue(\"file not deleted\", f0.exists());\n        assertFalse(\"file deleted\", f1.exists());\n\n        f0.delete();\n        d1.delete();\n    }\n\n    @Test\n    public void testGarbageCollectionOldSnapshotsZeroNoZero() throws Throwable {\n        // test scenario where 0 snapshots are configured to remain, but snapshot_0.xml is not present\n        final String dir = \"gcosDir00\";\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f0 = new File(dir, \"snapshot_1.xml\");\n        f0.createNewFile();\n        f0.deleteOnExit();\n        File f1 = new File(dir, \"snapshot_121.xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n        };\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(0);\n\n        TestUtil.invokePrivate(cs, \"garbageCollectionOldSnapshots\");\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        assertFalse(\"file deleted\", f0.exists());\n        assertFalse(\"file deleted\", f1.exists());\n\n        d1.delete();\n    }\n\n    @Test\n    public void testGarbageCollectionOldSnapshotsZeroOnly() throws Throwable {\n        // test that 0 is left, even if not newest\n        final String dir = \"gcosDir01\";\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f0 = new File(dir, \"snapshot_0.xml\"); // special snapshot file\n        f0.createNewFile();\n        f0.deleteOnExit();\n        File f1 = new File(dir, \"snapshot_121.xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n        File f2 = new File(dir, \"snapshot_122.xml\");\n        f2.createNewFile();\n        f2.deleteOnExit();\n        File f3 = new File(dir, \"snapshot_123.xml\");\n        f3.createNewFile();\n        f3.deleteOnExit();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n        };\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(1);\n\n        TestUtil.invokePrivate(cs, \"garbageCollectionOldSnapshots\");\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        assertTrue(\"file not deleted\", f0.exists());\n        assertFalse(\"file deleted\", f1.exists());\n        assertFalse(\"file deleted\", f2.exists());\n        assertFalse(\"file deleted\", f3.exists());\n\n        f3.delete();\n        d1.delete();\n    }\n\n    @Test\n    public void testGarbageCollectionOldSnapshotsNoZero1() throws Throwable {\n        // no zero => newest is left\n\n        final String dir = \"gcosDir\";\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f1 = new File(dir, \"snapshot_121.xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n        File f2 = new File(dir, \"snapshot_122.xml\");\n        f2.createNewFile();\n        f2.deleteOnExit();\n        File f3 = new File(dir, \"snapshot_123.xml\");\n        f3.createNewFile();\n        f3.deleteOnExit();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n        };\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(1);\n\n        TestUtil.invokePrivate(cs, \"garbageCollectionOldSnapshots\");\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        assertFalse(\"file deleted\", f1.exists());\n        assertFalse(\"file deleted\", f2.exists());\n        assertTrue(\"file not deleted\", f3.exists());\n\n        f3.delete();\n        d1.delete();\n    }\n\n    @Test\n    public void testGarbageCollectionOldSnapshots2() throws Throwable {\n        // zero and more than one to live => 0 and newest are left\n        final String dir = \"gcosDir\";\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f0 = new File(dir, \"snapshot_0.xml\"); // special snapshot file\n        f0.createNewFile();\n        f0.deleteOnExit();\n        File f1 = new File(dir, \"snapshot_121.xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n        File f2 = new File(dir, \"snapshot_122.xml\");\n        f2.createNewFile();\n        f2.deleteOnExit();\n        File f3 = new File(dir, \"snapshot_123.xml\");\n        f3.createNewFile();\n        f3.deleteOnExit();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n        };\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(2);\n\n        TestUtil.invokePrivate(cs, \"garbageCollectionOldSnapshots\");\n\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        assertTrue(\"file not deleted\", f0.exists());\n        assertFalse(\"file deleted\", f1.exists());\n        assertFalse(\"file deleted\", f2.exists());\n        assertTrue(\"file not deleted\", f3.exists());\n\n        f0.delete();\n        f3.delete();\n        d1.delete();\n    }\n\n    @Test\n    public void testSaveSnapshotNulls() throws Throwable {\n        // test new snapshot creation - no old ones\n\n        final String dir = \"dirSSN\";\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return null;\n            }\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n\n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n\n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        when(cryptoServiceMock.aesEncryptingStream((OutputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, OutputStream.class);\n        });\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(1);\n\n        XmlComponentConfigurations snapshot = prepareSnapshot();\n        List<ComponentConfiguration> configs = snapshot.getConfigurations();\n\n        Long sid = (Long) TestUtil.invokePrivate(cs, \"saveSnapshot\", configs);\n\n        verify(cryptoServiceMock, times(1)).aesEncryptingStream((OutputStream) ArgumentMatchers.any());\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        assertNotNull(sid);\n\n        File f1 = new File(d1, \"snapshot_\" + sid + \".xml\");\n        assertTrue(\"snapshot file created\", f1.exists());\n\n        String expectedXml = IOUtils.toString(\n                ConfigurationServiceJunitTest.class.getResourceAsStream(\"/expected_snapshot_without_description.xml\"),\n                StandardCharsets.UTF_8.name());\n        String actualXml = FileUtils.readFileToString(f1, StandardCharsets.UTF_8);\n\n        assertEquals(expectedXml, actualXml);\n\n        f1.delete();\n        d1.delete();\n    }\n\n    @Test\n    public void testSaveSnapshotNewerLastPid() throws Throwable {\n        // new snapshot, too recent old PID => predictable SID\n\n        final String dir = \"dirSSNLP\";\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        final Set<Long> snapshotList = new TreeSet<>();\n        snapshotList.add(123L);\n        long lastSid = System.currentTimeMillis() + 1000;\n        snapshotList.add(lastSid);\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return snapshotList;\n            }\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n\n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n\n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        when(cryptoServiceMock.aesEncryptingStream((OutputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, OutputStream.class);\n        });\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(1);\n\n        XmlComponentConfigurations snapshot = prepareSnapshot();\n        List<ComponentConfiguration> configs = snapshot.getConfigurations();\n\n        BundleContext bundleContext = mock(BundleContext.class);\n        TestUtil.setFieldValue(cs, \"bundleContext\", bundleContext);\n\n        Long sid = (Long) TestUtil.invokePrivate(cs, \"saveSnapshot\", configs);\n\n        verify(cryptoServiceMock, times(1)).aesEncryptingStream((OutputStream) ArgumentMatchers.any());\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        assertNotNull(sid);\n        assertEquals(\"sid as expected\", lastSid + 1, sid.longValue());\n\n        File f1 = new File(d1, \"snapshot_\" + sid + \".xml\");\n        assertTrue(\"snapshot file created\", f1.exists());\n\n        String expectedXml = IOUtils.toString(\n                ConfigurationServiceJunitTest.class.getResourceAsStream(\"/expected_snapshot_without_description.xml\"),\n                StandardCharsets.UTF_8.name());\n        String actualXml = FileUtils.readFileToString(f1, StandardCharsets.UTF_8);\n\n        assertEquals(expectedXml, actualXml);\n\n        f1.delete();\n        d1.delete();\n    }\n\n    @Test\n    public void testSaveSnapshot() throws Throwable {\n        // new snapshot, old last PID => take SID from current time\n\n        final String dir = \"dirSS\";\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        final Set<Long> snapshotList = new TreeSet<>();\n        snapshotList.add(123L);\n        long lastSid = 1234;\n        snapshotList.add(lastSid);\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return snapshotList;\n            }\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n\n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n\n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        when(cryptoServiceMock.aesEncryptingStream((OutputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, OutputStream.class);\n        });\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(1);\n\n        XmlComponentConfigurations snapshot = prepareSnapshot();\n        List<ComponentConfiguration> configs = snapshot.getConfigurations();\n\n        Long sid = (Long) TestUtil.invokePrivate(cs, \"saveSnapshot\", configs);\n\n        verify(cryptoServiceMock, times(1)).aesEncryptingStream((OutputStream) ArgumentMatchers.any());\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        assertNotNull(sid);\n        assertTrue(\"Expected higher sid\", sid.longValue() > lastSid + 1);\n        assertTrue(\"Expected sid <= current time\", sid.longValue() <= System.currentTimeMillis());\n\n        File f1 = new File(d1, \"snapshot_\" + sid + \".xml\");\n        assertTrue(\"Expected snapshot file to be created\", f1.exists());\n\n        String expectedXml = IOUtils.toString(\n                ConfigurationServiceJunitTest.class.getResourceAsStream(\"/expected_snapshot_without_description.xml\"),\n                StandardCharsets.UTF_8.name());\n        String actualXml = FileUtils.readFileToString(f1, StandardCharsets.UTF_8);\n\n        assertEquals(expectedXml, actualXml);\n\n        f1.delete();\n        d1.delete();\n    }\n\n    @Test\n    public void testLineBreakHandling() throws KuraException, IOException {\n        final CryptoService csMock = mock(CryptoService.class);\n\n        when(csMock.encryptAes(ArgumentMatchers.any(char[].class))).thenAnswer(invocation -> {\n            return invocation.getArgument(0, char[].class);\n        });\n\n        when(csMock.decryptAes(ArgumentMatchers.any(char[].class))).thenAnswer(invocation -> {\n            return invocation.getArgument(0, char[].class);\n        });\n\n        final File snapshotsDir = new File(\"/tmp/snapshot_test_dir_\" + System.currentTimeMillis());\n        snapshotsDir.mkdir();\n        snapshotsDir.deleteOnExit();\n\n        final SystemService ssMock = mock(SystemService.class);\n        when(ssMock.getKuraSnapshotsDirectory()).thenReturn(snapshotsDir.getAbsolutePath());\n\n        final Map<String, Object> expectedConfig = Collections.singletonMap(\"prop\", \"contains\\nline\\nbreaks\\n\");\n\n        final String snapshot = prepareSnapshotXml(prepareSnapshot(expectedConfig));\n\n        final File snapshotFile = new File(snapshotsDir, \"snapshot_0.xml\");\n        snapshotFile.deleteOnExit();\n\n        try (final FileWriter fw = new FileWriter(snapshotFile)) {\n            fw.write(snapshot);\n            fw.flush();\n        }\n\n        ConfigurationServiceImpl configurationService = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return Collections.singleton(0L);\n            }\n\n            @Override\n            String getSnapshotsDirectory() {\n                return snapshotsDir.getAbsolutePath();\n            }\n\n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n\n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n\n        when(csMock.aesDecryptingStream((InputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, InputStream.class);\n        });\n\n        configurationService.setCryptoService(csMock);\n\n        final List<ComponentConfiguration> loadedSnapshot = configurationService.getSnapshot(0);\n\n        assertEquals(expectedConfig.get(\"prop\"), loadedSnapshot.get(0).getConfigurationProperties().get(\"prop\"));\n\n    }\n\n    @Test\n    public void testUpdateWithDefaultConfigurationPidsNull() throws Throwable {\n        // test null values\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = null;\n        Tocd ocd = null;\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        String caPid = pid;\n        when(configAdminMock.getConfiguration(caPid, \"?\")).thenReturn(null);\n\n        TestUtil.invokePrivate(cs, \"updateWithDefaultConfiguration\", pid, ocd);\n\n        verify(configAdminMock, times(1)).getConfiguration(caPid, \"?\");\n    }\n\n    @Test\n    public void testUpdateWithDefaultConfigurationParamPidOverride() throws Throwable {\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"123\";\n        Tocd ocd = null;\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        String caPid = pid;\n        when(configAdminMock.getConfiguration(caPid, \"?\")).thenReturn(null);\n\n        TestUtil.invokePrivate(cs, \"updateWithDefaultConfiguration\", pid, ocd);\n\n        verify(configAdminMock, times(1)).getConfiguration(caPid, \"?\");\n    }\n\n    @Test\n    public void testUpdateWithDefaultConfigurationsServicePidNull() throws Throwable {\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"123\";\n        Tocd ocd = null;\n\n        Map<String, String> pids = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        pids.put(pid, null);\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        String caPid = pid;\n        when(configAdminMock.getConfiguration(caPid, \"?\")).thenReturn(null);\n\n        TestUtil.invokePrivate(cs, \"updateWithDefaultConfiguration\", pid, ocd);\n\n        verify(configAdminMock, times(1)).getConfiguration(caPid, \"?\");\n    }\n\n    @Test\n    public void testUpdateWithDefaultConfigurationsServicePid() throws Throwable {\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"123\";\n        Tocd ocd = null;\n\n        String sPid = \"1234\";\n        Map<String, String> pids = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        pids.put(pid, sPid);\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        String caPid = sPid;\n        when(configAdminMock.getConfiguration(caPid, \"?\")).thenReturn(null);\n\n        TestUtil.invokePrivate(cs, \"updateWithDefaultConfiguration\", pid, ocd);\n\n        verify(configAdminMock, times(1)).getConfiguration(caPid, \"?\");\n    }\n\n    @Test\n    public void testUpdateWithDefaultConfigurationServicePidExists() throws Throwable {\n        final String spid = \"1234\";\n\n        String pid = \"123\";\n        Tocd ocd = null;\n\n        final boolean[] calls = { false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            boolean mergeWithDefaults(OCD ocd, Map<String, Object> properties) {\n                assertEquals(\"size\", 2, properties.size());\n                assertTrue(\"new property\", properties.containsKey(ConfigurationService.KURA_SERVICE_PID));\n                assertEquals(\"property value\", spid, properties.get(ConfigurationService.KURA_SERVICE_PID));\n\n                calls[0] = true;\n                return true;\n            }\n        };\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        Configuration cfgMock = mock(Configuration.class);\n        String caPid = pid;\n        when(configAdminMock.getConfiguration(caPid, \"?\")).thenReturn(cfgMock);\n\n        Dictionary<String, Object> props = new Hashtable<>();\n        props.put(ConfigurationService.KURA_SERVICE_PID, spid);\n        props.put(\"test\", \"test\");\n        when(cfgMock.getProperties()).thenReturn(props);\n\n        TestUtil.invokePrivate(cs, \"updateWithDefaultConfiguration\", pid, ocd);\n\n        assertTrue(\"method called\", calls[0]);\n\n        verify(cfgMock, times(1)).update((Dictionary<String, ?>) any());\n    }\n\n    @Test\n    public void testUpdateWithDefaultConfiguration() throws Throwable {\n        final String pid = \"123\";\n        Tocd ocd = null;\n\n        final boolean[] calls = { false };\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            boolean mergeWithDefaults(OCD ocd, Map<String, Object> properties) {\n                assertEquals(\"size\", 1, properties.size());\n                assertTrue(\"new property\", properties.containsKey(ConfigurationService.KURA_SERVICE_PID));\n                assertEquals(\"property value\", pid, properties.get(ConfigurationService.KURA_SERVICE_PID));\n\n                calls[0] = true;\n                return true;\n            }\n        };\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        Configuration cfgMock = mock(Configuration.class);\n        String caPid = pid;\n        when(configAdminMock.getConfiguration(caPid, \"?\")).thenReturn(cfgMock);\n\n        when(cfgMock.getProperties()).thenReturn(null);\n\n        Mockito.doAnswer(invocation -> {\n            Dictionary<String, Object> dict = (Dictionary<String, Object>) invocation.getArguments()[0];\n\n            assertNotNull(dict);\n\n            assertEquals(\"one element in properties list - pid\", 1, dict.size());\n\n            assertEquals(\"expected configuration update PID\", pid, dict.elements().nextElement());\n\n            return null;\n        }).when(cfgMock).update((Dictionary<String, ?>) any());\n\n        TestUtil.invokePrivate(cs, \"updateWithDefaultConfiguration\", pid, ocd);\n\n        assertTrue(\"method called\", calls[0]);\n\n        verify(cfgMock, times(1)).update((Dictionary<String, ?>) any());\n    }\n\n    @Test\n    public void testRegisterComponentConfigurationPreActivated() throws NoSuchFieldException {\n        // pid is already activated, so it's not added to service pids\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"pid\";\n        String servicePid = \"spid\";\n        String factoryPid = null;\n\n        Set<String> allPids = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        allPids.add(pid);\n\n        Map<String, String> sPids = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        assertEquals(\"spid size OK\", 0, sPids.size());\n\n        cs.registerComponentConfiguration(pid, servicePid, factoryPid);\n\n        assertEquals(\"size still OK\", 0, sPids.size());\n    }\n\n    @Test\n    public void testRegisterComponentConfigurationActivateNoFactory() throws NoSuchFieldException {\n        // not activated, but no factory pid available => add to service and activated pids\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"pid\";\n        String servicePid = \"spid\";\n        String factoryPid = null;\n\n        Set<String> allPids = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        assertEquals(\"active pids size OK\", 0, allPids.size());\n\n        Map<String, String> sPids = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        assertEquals(\"spid size OK\", 0, sPids.size());\n\n        cs.registerComponentConfiguration(pid, servicePid, factoryPid);\n\n        assertEquals(\"size still OK\", 1, sPids.size());\n        assertEquals(\"spid in there\", servicePid, sPids.get(pid));\n\n        assertEquals(\"active size increased\", 1, allPids.size());\n        assertTrue(\"spid active\", allPids.contains(pid));\n    }\n\n    @Test\n    public void testRegisterComponentConfigurationWithFactoryPid() throws NoSuchFieldException {\n        // add also factory PID, but no OCD mapped\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"pid\";\n        String servicePid = \"spid\";\n        String factoryPid = \"fpid\";\n\n        Set<String> allPids = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        assertEquals(\"active pids size OK\", 0, allPids.size());\n\n        Map<String, String> sPids = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        assertEquals(\"spid size OK\", 0, sPids.size());\n\n        Map<String, String> fPids = (Map<String, String>) TestUtil.getFieldValue(cs, \"factoryPidByPid\");\n        assertEquals(\"fpid size OK\", 0, fPids.size());\n\n        cs.registerComponentConfiguration(pid, servicePid, factoryPid);\n\n        assertEquals(\"size still OK\", 1, sPids.size());\n        assertEquals(\"spid in there\", servicePid, sPids.get(pid));\n\n        assertEquals(\"active size increased\", 1, allPids.size());\n        assertTrue(\"spid active\", allPids.contains(pid));\n\n        assertEquals(\"factory size increased\", 1, fPids.size());\n        assertEquals(\"fpid in there\", factoryPid, fPids.get(pid));\n    }\n\n    @Test\n    public void testRegisterComponentConfigurationConfigException() throws IOException, NoSuchFieldException {\n        // test exception in cfgadmin\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"pid\";\n        String servicePid = \"spid\";\n        String factoryPid = \"fpid\";\n\n        Set<String> allPids = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        assertEquals(\"active pids size OK\", 0, allPids.size());\n\n        Map<String, String> sPids = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        assertEquals(\"spid size OK\", 0, sPids.size());\n\n        Map<String, String> fPids = (Map<String, String>) TestUtil.getFieldValue(cs, \"factoryPidByPid\");\n        assertEquals(\"fpid size OK\", 0, fPids.size());\n\n        Map<String, Tocd> ocds = (Map<String, Tocd>) TestUtil.getFieldValue(cs, \"ocds\");\n        Tocd ocd = new Tocd();\n        ocds.put(factoryPid, ocd);\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        when(configAdminMock.getConfiguration(servicePid, \"?\")).thenThrow(new IOException(\"test\"));\n\n        cs.registerComponentConfiguration(pid, servicePid, factoryPid);\n\n        verify(configAdminMock, times(1)).getConfiguration(servicePid, \"?\");\n\n        assertEquals(\"size still OK\", 1, sPids.size());\n        assertEquals(\"spid in there\", servicePid, sPids.get(pid));\n\n        assertEquals(\"active size increased\", 1, allPids.size());\n        assertTrue(\"spid active\", allPids.contains(pid));\n\n        assertEquals(\"factory size increased\", 1, fPids.size());\n        assertEquals(\"fpid in there\", factoryPid, fPids.get(pid));\n    }\n\n    @Test\n    public void testRegisterComponentConfiguration() throws IOException, NoSuchFieldException {\n        // check that updateWithDefaultConfiguration is called successfully\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl();\n\n        String pid = \"pid\";\n        String servicePid = \"spid\";\n        String factoryPid = \"fpid\";\n\n        Set<String> allPids = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        assertEquals(\"active pids size OK\", 0, allPids.size());\n\n        Map<String, String> sPids = (Map<String, String>) TestUtil.getFieldValue(cs, \"servicePidByPid\");\n        assertEquals(\"spid size OK\", 0, sPids.size());\n\n        Map<String, String> fPids = (Map<String, String>) TestUtil.getFieldValue(cs, \"factoryPidByPid\");\n        assertEquals(\"fpid size OK\", 0, fPids.size());\n\n        Map<String, Tocd> ocds = (Map<String, Tocd>) TestUtil.getFieldValue(cs, \"ocds\");\n        Tocd ocd = new Tocd();\n        ocds.put(factoryPid, ocd);\n\n        ConfigurationAdmin configAdminMock = mock(ConfigurationAdmin.class);\n        cs.setConfigurationAdmin(configAdminMock);\n\n        when(configAdminMock.getConfiguration(servicePid, \"?\")).thenReturn(null);\n\n        cs.registerComponentConfiguration(pid, servicePid, factoryPid);\n\n        verify(configAdminMock, times(1)).getConfiguration(servicePid, \"?\");\n\n        assertEquals(\"size still OK\", 1, sPids.size());\n        assertEquals(\"spid in there\", servicePid, sPids.get(pid));\n\n        assertEquals(\"active size increased\", 1, allPids.size());\n        assertTrue(\"spid active\", allPids.contains(pid));\n\n        assertEquals(\"factory size increased\", 1, fPids.size());\n        assertEquals(\"fpid in there\", factoryPid, fPids.get(pid));\n    }\n\n    @Test\n    public void testRollbackNoPids() throws KuraException {\n        // test rollback with no available shapshots - failure\n\n        final boolean[] calls = { false };\n        final Set<Long> pids = new HashSet<>();\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return pids;\n            }\n\n            @Override\n            public synchronized void rollback(long id) throws KuraException {\n                calls[0] = true;\n            }\n        };\n\n        try {\n            cs.rollback();\n            fail(\"Exception expected with < 2 pids.\");\n        } catch (KuraException e) {\n            assertEquals(\"code matches\", KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND, e.getCode());\n        }\n    }\n\n    @Test\n    public void testRollbackOnePid() throws KuraException {\n        // test rollback with one available shapshot - failure\n\n        final boolean[] calls = { false };\n        final Set<Long> pids = new HashSet<>();\n        pids.add(123L);\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return pids;\n            }\n\n            @Override\n            public synchronized void rollback(long id) throws KuraException {\n                calls[0] = true;\n            }\n        };\n\n        try {\n            cs.rollback();\n            fail(\"Exception expected with < 2 pids.\");\n        } catch (KuraException e) {\n            assertEquals(\"code matches\", KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND, e.getCode());\n        }\n    }\n\n    @Test\n    public void testRollbackTwoPids() throws KuraException {\n        // test rollback with 2 pids - OK\n        final boolean[] calls = { false };\n        final long pid = 123;\n        final Set<Long> pids = new HashSet<>();\n        pids.add(pid);\n        pids.add(124L);\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return pids;\n            }\n\n            @Override\n            public synchronized void rollback(long id) throws KuraException {\n                calls[0] = true;\n\n                assertEquals(\"correct pid\", pid, id);\n            }\n        };\n\n        cs.rollback();\n\n        assertTrue(\"delegated\", calls[0]);\n    }\n\n    @Test\n    public void testRollback() throws KuraException {\n        // test rollback with more than 2 pids\n\n        final boolean[] calls = { false };\n        final long pid = 123;\n        final Set<Long> pids = new HashSet<>();\n        pids.add(121L);\n        pids.add(122L);\n        pids.add(pid);\n        pids.add(124L);\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            public Set<Long> getSnapshots() throws KuraException {\n                return pids;\n            }\n\n            @Override\n            public synchronized void rollback(long id) throws KuraException {\n                calls[0] = true;\n\n                assertEquals(\"correct pid\", pid, id);\n            }\n        };\n\n        cs.rollback();\n\n        assertTrue(\"delegated\", calls[0]);\n    }\n\n    public void testRollbackIdPartialSvcRef() throws Exception {\n        long id = 123;\n        final String dir = \"dirRIPSR\";\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n        };\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f1 = new File(dir, \"snapshot_\" + id + \".xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n\n        FileWriter fw = new FileWriter(f1);\n        fw.append(\"test\");\n        fw.close();\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        String decrypted = prepareSnapshotXML();\n        when(cryptoServiceMock.decryptAes(\"test\".toCharArray())).thenReturn(decrypted.toCharArray());\n\n        when(cryptoServiceMock.encryptAes((char[]) any())).thenReturn(\"encrypted\".toCharArray());\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(5);\n\n        String pid = \"pid\";\n        Set<String> allPids = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        allPids.add(pid);\n\n        ComponentContext componentCtxMock = mock(ComponentContext.class);\n        TestUtil.setFieldValue(cs, \"ctx\", componentCtxMock);\n\n        BundleContext bundleCtxMock = mock(BundleContext.class);\n        when(componentCtxMock.getBundleContext()).thenReturn(bundleCtxMock);\n\n        when(bundleCtxMock.getServiceReferences((String) null, null))\n                .thenThrow(new InvalidSyntaxException(\"test\", null));\n\n        cs.rollback(id);\n\n        verify(cryptoServiceMock, times(1)).decryptAes(\"test\".toCharArray());\n        verify(cryptoServiceMock, times(1)).encryptAes((char[]) any());\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        File[] files = d1.listFiles();\n\n        assertEquals(2, files.length);\n\n        for (File f : files) {\n            f.deleteOnExit();\n        }\n        String expect = \"test\";\n\n        FileReader fr = new FileReader(files[0]);\n        char[] chars = new char[expect.length()];\n        fr.read(chars);\n        fr.close();\n\n        assertEquals(expect, new String(chars));\n\n        expect = \"encrypted\";\n\n        fr = new FileReader(files[1]);\n        chars = new char[expect.length()];\n        fr.read(chars);\n        fr.close();\n\n        assertEquals(expect, new String(chars));\n    }\n\n    @Test\n    public void testRollbackIdPartial() throws Exception {\n        long id = 123;\n        final String dir = \"dirRIP\";\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n\n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n\n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f1 = new File(dir, \"snapshot_\" + id + \".xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n\n        FileWriter fw = new FileWriter(f1);\n        fw.append(IOUtils.toString(\n                ConfigurationServiceJunitTest.class.getResourceAsStream(\"/expected_snapshot_with_description.xml\"),\n                StandardCharsets.UTF_8.name()));\n        fw.close();\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        when(cryptoServiceMock.aesDecryptingStream((InputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, InputStream.class);\n        });\n\n        when(cryptoServiceMock.aesEncryptingStream((OutputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, OutputStream.class);\n        });\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(5);\n\n        String pid = \"123\";\n        Set<String> allPids = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        allPids.add(pid);\n\n        Map<String, String> factoryPidByPid = new HashMap<>(); // will cause exception in deleteFactoryConfiguration\n        factoryPidByPid.put(\"key\", null);\n        TestUtil.setFieldValue(cs, \"factoryPidByPid\", factoryPidByPid);\n\n        Map<String, Tocd> ocds = new HashMap<>(); // for getRegisteredOCD in rollbackConfigurationInternal\n        Tocd ocd = new Tocd();\n        ocds.put(pid, ocd);\n        TestUtil.setFieldValue(cs, \"ocds\", ocds);\n\n        ComponentContext componentCtxMock = mock(ComponentContext.class);\n        TestUtil.setFieldValue(cs, \"ctx\", componentCtxMock);\n\n        BundleContext bundleCtxMock = mock(BundleContext.class);\n        when(componentCtxMock.getBundleContext()).thenReturn(bundleCtxMock);\n\n        ServiceReference svcRefMock = mock(ServiceReference.class);\n        ServiceReference[] svcReferences = { svcRefMock };\n        when(bundleCtxMock.getServiceReferences((String) null, null)).thenReturn(svcReferences);\n\n        String ppid = pid;\n        when(svcRefMock.getProperty(Constants.SERVICE_PID)).thenReturn(ppid);\n\n        Bundle bundleMock = mock(Bundle.class);\n        when(svcRefMock.getBundle()).thenReturn(bundleMock);\n\n        when(bundleMock.getResource(ArgumentMatchers.anyString())).thenThrow(new NullPointerException(\"test\"));\n\n        Configuration[] configurations = new Configuration[] {};\n        ConfigurationAdmin cfgAdminMock = mock(ConfigurationAdmin.class);\n        when(cfgAdminMock.listConfigurations(null)).thenReturn(configurations);\n        when(cfgAdminMock.getConfiguration(ppid)).thenThrow(IOException.class);\n        cs.setConfigurationAdmin(cfgAdminMock);\n\n        try {\n            cs.rollback(id);\n            fail(\"Rigged for exception.\");\n        } catch (KuraPartialSuccessException e) {\n            // OK\n        }\n\n        verify(cryptoServiceMock, times(1)).aesDecryptingStream(((InputStream) ArgumentMatchers.any()));\n\n        File[] files = d1.listFiles();\n\n        assertEquals(1, files.length);\n\n        for (File f : files) {\n            f.deleteOnExit();\n        }\n\n        File file = files[0];\n        String expectedXml = IOUtils.toString(\n                ConfigurationServiceJunitTest.class.getResourceAsStream(\"/expected_snapshot_with_description.xml\"),\n                StandardCharsets.UTF_8.name());\n        String actualXml = FileUtils.readFileToString(file, StandardCharsets.UTF_8);\n\n        assertEquals(expectedXml, actualXml);\n    }\n\n    public void testRollbackId() throws Exception {\n        long id = 123;\n        final String dir = \"dirRI\";\n\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n        };\n\n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n\n        File f1 = new File(dir, \"snapshot_\" + id + \".xml\");\n        f1.createNewFile();\n        f1.deleteOnExit();\n\n        FileWriter fw = new FileWriter(f1);\n        fw.append(\"test\");\n        fw.close();\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n\n        String decrypted = prepareSnapshotXML();\n        when(cryptoServiceMock.decryptAes(\"test\".toCharArray())).thenReturn(decrypted.toCharArray());\n\n        when(cryptoServiceMock.encryptAes((char[]) any())).thenReturn(\"encrypted\".toCharArray());\n\n        SystemService systemServiceMock = mock(SystemService.class);\n        cs.setSystemService(systemServiceMock);\n\n        when(systemServiceMock.getKuraSnapshotsCount()).thenReturn(5);\n\n        String pid = \"pid\";\n        Set<String> allPids = (Set<String>) TestUtil.getFieldValue(cs, \"allActivatedPids\");\n        allPids.add(pid);\n\n        ComponentContext componentCtxMock = mock(ComponentContext.class);\n        TestUtil.setFieldValue(cs, \"ctx\", componentCtxMock);\n\n        BundleContext bundleCtxMock = mock(BundleContext.class);\n        when(componentCtxMock.getBundleContext()).thenReturn(bundleCtxMock);\n\n        ServiceReference svcRefMock = mock(ServiceReference.class);\n        ServiceReference[] svcReferences = { svcRefMock };\n        when(bundleCtxMock.getServiceReferences((String) null, null)).thenReturn(svcReferences);\n\n        String ppid = pid;\n        when(svcRefMock.getProperty(Constants.SERVICE_PID)).thenReturn(ppid);\n\n        Bundle bundleMock = mock(Bundle.class);\n        when(svcRefMock.getBundle()).thenReturn(bundleMock);\n\n        when(bundleMock.getResource(ArgumentMatchers.anyString())).thenReturn(null);\n\n        cs.rollback(id);\n\n        verify(cryptoServiceMock, times(1)).decryptAes(\"test\".toCharArray());\n        verify(cryptoServiceMock, times(1)).encryptAes((char[]) any());\n        verify(systemServiceMock, times(1)).getKuraSnapshotsCount();\n\n        File[] files = d1.listFiles();\n\n        assertEquals(2, files.length);\n\n        for (File f : files) {\n            f.deleteOnExit();\n        }\n        String expect = \"test\";\n\n        FileReader fr = new FileReader(files[0]);\n        char[] chars = new char[expect.length()];\n        fr.read(chars);\n        fr.close();\n\n        assertEquals(expect, new String(chars));\n\n        expect = \"encrypted\";\n\n        fr = new FileReader(files[1]);\n        chars = new char[expect.length()];\n        fr.read(chars);\n        fr.close();\n\n        assertEquals(expect, new String(chars));\n    }\n\n    private ComponentDescriptionDTO createMockComponent(final String pid, final String... implementedServices) {\n        final ComponentDescriptionDTO result = mock(ComponentDescriptionDTO.class);\n        result.name = pid;\n        result.serviceInterfaces = implementedServices;\n\n        return result;\n    }\n\n    private OCDService createMockConfigurationServiceForOCDTests(List<String> registeredFactories,\n            List<Tocd> registeredOcds, List<ComponentDescriptionDTO> registeredComponents) throws KuraException {\n\n        assertEquals(registeredFactories.size(), registeredOcds.size());\n        ServiceComponentRuntime scrService = mock(ServiceComponentRuntime.class);\n        when(scrService.getComponentDescriptionDTOs()).thenReturn(registeredComponents);\n\n        final ConfigurationServiceImpl result = new ConfigurationServiceImpl();\n        result.setScrService(scrService);\n        for (int i = 0; i < registeredOcds.size(); i++) {\n            result.registerComponentOCD(registeredFactories.get(i), registeredOcds.get(i), true, null);\n        }\n\n        return result;\n    }\n\n    private boolean isOCDFor(ComponentConfiguration config, String factoryPid, Tocd ocd) {\n        return config.getPid().equals(factoryPid) && config.getDefinition() == ocd;\n    }\n\n    @Test\n    public void testShouldReturnEmptyFactoryOCDList() throws KuraException {\n        final OCDService ocdService = createMockConfigurationServiceForOCDTests(Arrays.asList(), Arrays.asList(),\n                Arrays.asList());\n        final List<ComponentConfiguration> configs = ocdService.getFactoryComponentOCDs();\n        assertTrue(configs.isEmpty());\n    }\n\n    @Test\n    public void testShouldGetFactoryOCDList() throws KuraException {\n        final Tocd ocd1 = mock(Tocd.class);\n        final Tocd ocd2 = mock(Tocd.class);\n        final Tocd ocd3 = mock(Tocd.class);\n        final OCDService ocdService = createMockConfigurationServiceForOCDTests(Arrays.asList(\"foo\", \"bar\", \"baz\"),\n                Arrays.asList(ocd1, ocd2, ocd3), Arrays.asList());\n        final List<ComponentConfiguration> configs = ocdService.getFactoryComponentOCDs();\n        assertEquals(3, configs.size());\n        assertTrue(configs.stream().filter(config -> isOCDFor(config, \"foo\", ocd1)).findAny().isPresent());\n        assertTrue(configs.stream().filter(config -> isOCDFor(config, \"bar\", ocd2)).findAny().isPresent());\n        assertTrue(configs.stream().filter(config -> isOCDFor(config, \"baz\", ocd3)).findAny().isPresent());\n    }\n\n    @Test\n    public void testShouldReturnNullFactoryOCD() throws KuraException {\n        final OCDService ocdService = createMockConfigurationServiceForOCDTests(Arrays.asList(), Arrays.asList(),\n                Arrays.asList());\n        assertNull(ocdService.getFactoryComponentOCD(\"bar\"));\n        assertNull(ocdService.getFactoryComponentOCD(null));\n    }\n\n    @Test\n    public void testShouldGetSingleFactoryOCD() throws KuraException {\n        final Tocd ocd1 = mock(Tocd.class);\n        final Tocd ocd2 = mock(Tocd.class);\n        final Tocd ocd3 = mock(Tocd.class);\n        final OCDService ocdService = createMockConfigurationServiceForOCDTests(Arrays.asList(\"foo\", \"bar\", \"baz\"),\n                Arrays.asList(ocd1, ocd2, ocd3), Arrays.asList());\n        assertTrue(isOCDFor(ocdService.getFactoryComponentOCD(\"foo\"), \"foo\", ocd1));\n        assertTrue(isOCDFor(ocdService.getFactoryComponentOCD(\"bar\"), \"bar\", ocd2));\n        assertTrue(isOCDFor(ocdService.getFactoryComponentOCD(\"baz\"), \"baz\", ocd3));\n        assertNull(ocdService.getFactoryComponentOCD(\"nonExisting\"));\n        assertNull(ocdService.getFactoryComponentOCD(null));\n    }\n\n    @Test\n    public void testShouldReturnEmptyFactoryOCDListForServiceProvider() throws KuraException {\n        final OCDService ocdService = createMockConfigurationServiceForOCDTests(Arrays.asList(), Arrays.asList(),\n                Arrays.asList());\n        assertTrue(ocdService.getServiceProviderOCDs(new Class<?>[0]).isEmpty());\n        assertTrue(ocdService.getServiceProviderOCDs(String.class).isEmpty());\n    }\n\n    @Test\n    public void testShouldReturnFactoryOCDListForServiceProvider() throws KuraException {\n        final Tocd fooOcd = mock(Tocd.class);\n        final Tocd barOcd = mock(Tocd.class);\n        final Tocd bazOcd = mock(Tocd.class);\n        final Tocd otherOcd = mock(Tocd.class);\n\n        final ComponentDescriptionDTO comp1 = createMockComponent(\"foo\", \"java.lang.String\", \"java.lang.Integer\");\n        final ComponentDescriptionDTO comp2 = createMockComponent(\"bar\", \"java.lang.Double\", \"java.lang.Long\");\n        final ComponentDescriptionDTO comp3 = createMockComponent(\"baz\", \"java.lang.Double\", \"java.lang.Integer\");\n        final ComponentDescriptionDTO comp4 = createMockComponent(\"other\");\n\n        final OCDService ocdService = createMockConfigurationServiceForOCDTests(\n                Arrays.asList(\"foo\", \"bar\", \"baz\", \"other\"), Arrays.asList(fooOcd, barOcd, bazOcd, otherOcd),\n                Arrays.asList(comp1, comp2, comp3, comp4));\n\n        assertTrue(ocdService.getServiceProviderOCDs(new Class<?>[0]).isEmpty());\n\n        final List<ComponentConfiguration> implementingString = ocdService.getServiceProviderOCDs(String.class);\n        assertEquals(1, implementingString.size());\n        assertTrue(implementingString.stream().filter(config -> isOCDFor(config, \"foo\", fooOcd)).findAny().isPresent());\n\n        final List<ComponentConfiguration> implementingStringOrInteger = ocdService.getServiceProviderOCDs(String.class,\n                Integer.class);\n        assertEquals(2, implementingStringOrInteger.size());\n        assertTrue(implementingStringOrInteger.stream().filter(config -> isOCDFor(config, \"foo\", fooOcd)).findAny()\n                .isPresent());\n        assertTrue(implementingStringOrInteger.stream().filter(config -> isOCDFor(config, \"baz\", bazOcd)).findAny()\n                .isPresent());\n\n        final List<ComponentConfiguration> implementingLongOrBoolean = ocdService.getServiceProviderOCDs(Long.class,\n                Boolean.class);\n        assertEquals(1, implementingLongOrBoolean.size());\n        assertTrue(implementingLongOrBoolean.stream().filter(config -> isOCDFor(config, \"bar\", barOcd)).findAny()\n                .isPresent());\n\n        final List<ComponentConfiguration> implementingBoolean = ocdService.getServiceProviderOCDs(Boolean.class);\n        assertTrue(implementingBoolean.isEmpty());\n\n        final List<ComponentConfiguration> implementingLong = ocdService.getServiceProviderOCDs(Long.class);\n        assertEquals(1, implementingLong.size());\n        assertTrue(implementingLong.stream().filter(config -> isOCDFor(config, \"bar\", barOcd)).findAny().isPresent());\n\n        final List<ComponentConfiguration> implementingDouble = ocdService.getServiceProviderOCDs(Double.class);\n        assertEquals(2, implementingDouble.size());\n        assertTrue(implementingDouble.stream().filter(config -> isOCDFor(config, \"bar\", barOcd)).findAny().isPresent());\n        assertTrue(implementingDouble.stream().filter(config -> isOCDFor(config, \"baz\", bazOcd)).findAny().isPresent());\n    }\n\n    @Test\n    public void testWriteSnapshotFilePermissions() throws Throwable {\n        // Test that snapshot files are created with secure 600 permissions (owner read/write only)\n        \n        long sid = 424L;\n        XmlComponentConfigurations cfg = prepareSnapshot();\n        final String dir = \"snapshotDirPermissions\";\n        \n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n        \n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n            \n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n            \n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n        \n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n        \n        when(cryptoServiceMock.aesEncryptingStream((OutputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, OutputStream.class);\n        });\n        \n        BundleContext bundleContext = mock(BundleContext.class);\n        TestUtil.setFieldValue(cs, \"bundleContext\", bundleContext);\n        \n        // Execute the writeSnapshot method\n        TestUtil.invokePrivate(cs, \"writeSnapshot\", sid, cfg);\n        \n        File f1 = new File(d1, \"snapshot_\" + sid + \".xml\");\n        f1.deleteOnExit();\n        assertTrue(\"snapshot file was created\", f1.exists());\n        \n        try {\n            // Verify file permissions are set to 600 (owner read/write only) on POSIX systems\n            Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(f1.toPath());\n            Set<PosixFilePermission> expectedPerms = PosixFilePermissions.fromString(\"rw-------\");\n            \n            assertEquals(\"File permissions should be 600 (owner read/write only)\", expectedPerms, permissions);\n            \n            // Verify that group and others don't have any permissions\n            assertFalse(\"Group should not have read permission\", permissions.contains(PosixFilePermission.GROUP_READ));\n            assertFalse(\"Group should not have write permission\", permissions.contains(PosixFilePermission.GROUP_WRITE));\n            assertFalse(\"Others should not have read permission\", permissions.contains(PosixFilePermission.OTHERS_READ));\n            assertFalse(\"Others should not have write permission\", permissions.contains(PosixFilePermission.OTHERS_WRITE));\n            \n            // Verify that owner has both read and write permissions\n            assertTrue(\"Owner should have read permission\", permissions.contains(PosixFilePermission.OWNER_READ));\n            assertTrue(\"Owner should have write permission\", permissions.contains(PosixFilePermission.OWNER_WRITE));\n            assertFalse(\"Owner should not have execute permission\", permissions.contains(PosixFilePermission.OWNER_EXECUTE));\n            \n        } catch (UnsupportedOperationException e) {\n            // This test is running on a non-POSIX filesystem (like Windows)\n            // In this case, we can't test the permissions, but we can verify the file was created\n            System.out.println(\"POSIX file permissions not supported on this filesystem - skipping permission verification\");\n        }\n        \n        f1.delete();\n        d1.delete();\n    }\n    \n    @Test\n    public void testWriteSnapshotNonPosixFilesystem() throws Throwable {\n        // Test behavior on non-POSIX filesystems where setPosixFilePermissions is not supported\n        \n        long sid = 525L;\n        XmlComponentConfigurations cfg = prepareSnapshot();\n        final String dir = \"snapshotDirNonPosix\";\n        \n        File d1 = new File(dir);\n        d1.mkdirs();\n        d1.deleteOnExit();\n        \n        // Mock ConfigurationServiceImpl to simulate non-POSIX filesystem behavior\n        ConfigurationServiceImpl cs = new ConfigurationServiceImpl() {\n            @Override\n            String getSnapshotsDirectory() {\n                return dir;\n            }\n            \n            @Override\n            protected <T> T unmarshal(InputStream xmlStream, Class<T> clazz) throws KuraException {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                return xmlMarshaller.unmarshal(xmlStream, clazz);\n            }\n            \n            @Override\n            protected void marshal(OutputStream outStream, Object object) {\n                XmlMarshallUnmarshallImpl xmlMarshaller = new XmlMarshallUnmarshallImpl();\n                try {\n                    xmlMarshaller.marshal(outStream, object);\n                } catch (KuraException e) {\n                    // Do nothing...\n                }\n            }\n        };\n        \n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        cs.setCryptoService(cryptoServiceMock);\n        \n        when(cryptoServiceMock.aesEncryptingStream((OutputStream) ArgumentMatchers.any())).thenAnswer(answer -> {\n            return answer.getArgument(0, OutputStream.class);\n        });\n        \n        BundleContext bundleContext = mock(BundleContext.class);\n        TestUtil.setFieldValue(cs, \"bundleContext\", bundleContext);\n        \n        // Execute the writeSnapshot method - should not throw exception even on non-POSIX systems\n        TestUtil.invokePrivate(cs, \"writeSnapshot\", sid, cfg);\n        \n        File f1 = new File(d1, \"snapshot_\" + sid + \".xml\");\n        f1.deleteOnExit();\n        assertTrue(\"snapshot file was created\", f1.exists());\n        \n        // On non-POSIX systems, the method should complete successfully even if permissions can't be set\n        // We can't easily mock the UnsupportedOperationException here, but this test verifies the method completes\n        \n        f1.delete();\n        d1.delete();\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/src/test/java/org/eclipse/kura/core/configuration/util/ComponentUtilTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.configuration.util;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.core.configuration.ComponentConfigurationImpl;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatchers;\n\npublic class ComponentUtilTest {\n\n    @Test\n    public void testEncryptConfigsNull() throws NoSuchMethodException { // move\n        // test with null parameter\n        try {\n            ComponentUtil.encryptConfigs(null, null);\n        } catch (Throwable e) {\n            fail(\"Parameters not checked.\");\n        }\n\n    }\n\n    @Test\n    public void testEncryptConfigsNoConfigs() { // move\n        // empty list\n        boolean exceptionCaught = false;\n\n        try {\n            ComponentUtil.encryptConfigs(new ArrayList<>(), null);\n        } catch (Throwable t) {\n            exceptionCaught = true;\n        }\n        assertFalse(exceptionCaught);\n    }\n\n    @Test\n    public void testEncryptConfigsEncryptionException() throws Throwable { // move\n        // test failed encryption of a password: add a password and run; fail\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n\n        // first decryption must fail\n        when(cryptoServiceMock.decryptAes(\"pass\".toCharArray()))\n                .thenThrow(new KuraException(KuraErrorCode.DECODER_ERROR, \"password\"));\n        // then also encryption can fail\n        when(cryptoServiceMock.encryptAes(\"pass\".toCharArray()))\n                .thenThrow(new KuraException(KuraErrorCode.ENCODE_ERROR, \"password\"));\n\n        List<ComponentConfiguration> configs = new ArrayList<>();\n\n        ComponentConfigurationImpl cfg = new ComponentConfigurationImpl();\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"key1\", new Password(\"pass\"));\n        cfg.setProperties(props);\n\n        configs.add(cfg);\n\n        ComponentUtil.encryptConfigs(configs, cryptoServiceMock);\n\n        verify(cryptoServiceMock, times(1)).decryptAes(\"pass\".toCharArray());\n        verify(cryptoServiceMock, times(1)).encryptAes(\"pass\".toCharArray());\n\n        assertEquals(\"property was deleted\", 0, props.size());\n    }\n\n    @Test\n    public void testEncryptConfigs() throws Throwable { // move\n        // test encrypting a password: add a password and run\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n\n        // first decryption must fail\n        when(cryptoServiceMock.decryptAes(\"pass\".toCharArray()))\n                .thenThrow(new KuraException(KuraErrorCode.DECODER_ERROR, \"configuration\"));\n        // so that encryption is attempted at all\n        when(cryptoServiceMock.encryptAes(\"pass\".toCharArray())).thenReturn(\"encrypted\".toCharArray());\n\n        List<ComponentConfiguration> configs = new ArrayList<>();\n\n        ComponentConfigurationImpl cfg = new ComponentConfigurationImpl();\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"key1\", new Password(\"pass\"));\n        cfg.setProperties(props);\n\n        configs.add(cfg);\n\n        ComponentUtil.encryptConfigs(configs, cryptoServiceMock);\n\n        verify(cryptoServiceMock, times(1)).decryptAes(\"pass\".toCharArray());\n        verify(cryptoServiceMock, times(1)).encryptAes(\"pass\".toCharArray());\n\n        assertEquals(\"property was updated\", 1, props.size());\n        assertTrue(\"key still exists\", props.containsKey(\"key1\"));\n        assertArrayEquals(\"key is encrypted\", \"encrypted\".toCharArray(), ((Password) props.get(\"key1\")).getPassword());\n    }\n\n    @Test\n    public void testEncryptConfigsPreencryptedPassword() throws Throwable {\n        // test encrypting a password when the password is already encrypted\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n\n        // decryption succeeds this time\n        when(cryptoServiceMock.decryptAes(\"pass\".toCharArray())).thenReturn(\"pass\".toCharArray());\n\n        List<ComponentConfiguration> configs = new ArrayList<>();\n\n        ComponentConfigurationImpl cfg = new ComponentConfigurationImpl();\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"key1\", new Password(\"pass\"));\n        cfg.setProperties(props);\n\n        configs.add(cfg);\n\n        ComponentUtil.encryptConfigs(configs, cryptoServiceMock);\n\n        verify(cryptoServiceMock, times(1)).decryptAes(\"pass\".toCharArray());\n        verify(cryptoServiceMock, times(0)).encryptAes((char[]) ArgumentMatchers.any());\n\n        assertEquals(\"property remains\", 1, props.size());\n        assertTrue(\"key still exists\", props.containsKey(\"key1\"));\n        assertArrayEquals(\"key is already encrypted\", \"pass\".toCharArray(),\n                ((Password) props.get(\"key1\")).getPassword());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/src/test/resources/expected_snapshot_with_description.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n    <esf:configuration pid=\"123\">\n        <ocd:OCD description=\"description\"/>\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"pass\" type=\"String\">\n                <esf:value>pass</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n</esf:configurations>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/src/test/resources/expected_snapshot_without_description.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><esf:configurations xmlns:esf=\"http://eurotech.com/esf/2.0\" xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n    <esf:configuration pid=\"123\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"pass\" type=\"String\">\n                <esf:value>pass</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n</esf:configurations>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.configuration.test/src/test/resources/log4j.properties",
    "content": "################################################################################\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n################################################################################\n\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.crypto.test/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.crypto.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Unit tests for 'org.eclipse.kura.core.crypto'\nBundle-SymbolicName: org.eclipse.kura.core.crypto.test\nBundle-Version: 6.0.0.qualifier\nFragment-Host: org.eclipse.kura.core.crypto\nImport-Package: org.apache.commons.io;version=\"2.18.0\",\n  org.mockito;version=\"5.0.0\",\n  org.mockito.invocation;version=\"5.0.0\",\n  org.mockito.stubbing;version=\"5.0.0\"\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nRequire-Bundle: org.junit;bundle-version=\"4.10.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.crypto.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.crypto.test/build.properties",
    "content": "# Copyright (c) 2016, 2023 Red Hat Inc and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Red Hat Inc\n#  Eurotech\n\nsource.. = src/main/java/\noutput.. = target/classes\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.crypto.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- \n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Eurotech\n     \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.crypto.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.crypto.test/src/main/java/org/eclipse/kura/core/crypto/Base64Test.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\npackage org.eclipse.kura.core.crypto;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class Base64Test {\n    private CryptoServiceImpl cryptoService;\n\n    @Before\n    public void setup() {\n        this.cryptoService = new CryptoServiceImpl();\n    }\n\n    @Test\n    public void testEncode1() throws Exception {\n        final String result = this.cryptoService.encodeBase64(\"foo-bar\");\n        assertEquals(\"Zm9vLWJhcg==\", result);\n    }\n\n    @Test\n    public void testDecode1() throws Exception {\n        final String result = this.cryptoService.decodeBase64(\"Zm9vLWJhcg==\");\n        assertEquals(\"foo-bar\", result);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.crypto.test/src/main/java/org/eclipse/kura/core/crypto/CryptoServiceImplCustomKeyTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.core.crypto;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.fail;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Base64;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.TemporaryFolder;\nimport org.mockito.Mockito;\n\npublic class CryptoServiceImplCustomKeyTest {\n\n    @Rule\n    public TemporaryFolder tempFolder = new TemporaryFolder();\n\n    private CryptoServiceImpl cryptoService;\n    private SystemService mockSystemService;\n    private Path credentialDirectory;\n    private String testPlaintext;\n    private char[] encryptedData;\n    private char[] decryptedData;\n\n    @Before\n    public void setup() {\n        this.mockSystemService = Mockito.mock(SystemService.class);\n        try {\n            Mockito.when(this.mockSystemService.getKuraDataDirectory())\n                    .thenReturn(Files.createTempDirectory(null).toString());\n        } catch (IOException e) {\n            throw new IllegalStateException(\"cannot create temporary directory\");\n        }\n        this.cryptoService = new CryptoServiceImpl();\n        this.cryptoService.setSystemService(this.mockSystemService);\n    }\n\n    @After\n    public void cleanup() {\n        System.clearProperty(\"org.eclipse.kura.crypto.secretKey\");\n        System.clearProperty(\"CREDENTIALS_DIRECTORY\");\n    }\n\n    @Test\n    public void loadKeyFromSystemdCredential16Bytes() {\n        given16ByteCustomKey();\n        givenSystemdCredentialFile(\"kura-encryption-secret-key\");\n\n        whenActivatingCryptoService();\n\n        thenServiceIsActivated();\n    }\n\n    @Test\n    public void loadKeyFromSystemdCredential24Bytes() {\n        given24ByteCustomKey();\n        givenSystemdCredentialFile(\"kura-encryption-secret-key\");\n\n        whenActivatingCryptoService();\n\n        thenServiceIsActivated();\n    }\n\n    @Test\n    public void loadKeyFromSystemdCredential32Bytes() {\n        given32ByteCustomKey();\n        givenSystemdCredentialFile(\"kura-encryption-secret-key\");\n\n        whenActivatingCryptoService();\n\n        thenServiceIsActivated();\n    }\n\n    @Test\n    public void loadKeyFromSystemProperty16Bytes() {\n        given16ByteCustomKey();\n        givenSystemPropertyKey();\n\n        whenActivatingCryptoService();\n\n        thenServiceIsActivated();\n    }\n\n    @Test\n    public void loadKeyFromSystemProperty24Bytes() {\n        given24ByteCustomKey();\n        givenSystemPropertyKey();\n\n        whenActivatingCryptoService();\n\n        thenServiceIsActivated();\n    }\n\n    @Test\n    public void loadKeyFromSystemProperty32Bytes() {\n        given32ByteCustomKey();\n        givenSystemPropertyKey();\n\n        whenActivatingCryptoService();\n\n        thenServiceIsActivated();\n    }\n\n    @Test\n    public void rejectDefaultKey() {\n        givenDefaultKey();\n        givenSystemPropertyKey();\n\n        whenActivatingCryptoService();\n\n        thenServiceFallsBackToDefaultKey();\n    }\n\n    @Test\n    public void rejectInvalidKeyLength15Bytes() {\n        givenCustomKeyWithLength(15);\n        givenSystemPropertyKey();\n\n        whenActivatingCryptoService();\n\n        thenServiceFallsBackToDefaultKey();\n    }\n\n    @Test\n    public void rejectInvalidKeyLength17Bytes() {\n        givenCustomKeyWithLength(17);\n        givenSystemPropertyKey();\n\n        whenActivatingCryptoService();\n\n        thenServiceFallsBackToDefaultKey();\n    }\n\n    @Test\n    public void rejectInvalidKeyLength20Bytes() {\n        givenCustomKeyWithLength(20);\n        givenSystemPropertyKey();\n\n        whenActivatingCryptoService();\n\n        thenServiceFallsBackToDefaultKey();\n    }\n\n    @Test\n    public void rejectInvalidKeyLength31Bytes() {\n        givenCustomKeyWithLength(31);\n        givenSystemPropertyKey();\n\n        whenActivatingCryptoService();\n\n        thenServiceFallsBackToDefaultKey();\n    }\n\n    @Test\n    public void useDefaultKeyWhenNoCustomKeyProvided() {\n        whenActivatingCryptoService();\n\n        thenServiceIsActivated();\n    }\n\n    @Test\n    public void encryptWithSystemdCredentialKey() {\n        given32ByteCustomKey();\n        givenSystemdCredentialFile(\"kura-encryption-secret-key\");\n        givenPlaintext(\"test-data\");\n\n        whenActivatingCryptoService();\n        whenEncryptingData();\n\n        thenDataIsEncrypted();\n    }\n\n    @Test\n    public void encryptAndDecryptWithCustomKey() {\n        given32ByteCustomKey();\n        givenSystemPropertyKey();\n        givenPlaintext(\"test-data-to-encrypt\");\n\n        whenActivatingCryptoService();\n        whenEncryptingData();\n        whenDecryptingData();\n\n        thenDecryptedDataMatchesPlaintext();\n    }\n\n    @Test\n    public void systemdCredentialTakesPrecedenceOverSystemProperty() {\n        given32ByteCustomKey();\n        givenSystemdCredentialFile(\"kura-encryption-secret-key\");\n        givenDifferentSystemPropertyKey();\n\n        whenActivatingCryptoService();\n\n        thenServiceIsActivated();\n    }\n\n    private void given16ByteCustomKey() {\n        this.testPlaintext = Base64.getEncoder().encodeToString(\"1234567890123456\".getBytes(StandardCharsets.UTF_8));\n    }\n\n    private void given24ByteCustomKey() {\n        this.testPlaintext = Base64.getEncoder()\n                .encodeToString(\"123456789012345678901234\".getBytes(StandardCharsets.UTF_8));\n    }\n\n    private void given32ByteCustomKey() {\n        this.testPlaintext = Base64.getEncoder()\n                .encodeToString(\"12345678901234567890123456789012\".getBytes(StandardCharsets.UTF_8));\n    }\n\n    private void givenDefaultKey() {\n        this.testPlaintext = \"rv;ipse329183!@#\";\n    }\n\n    private void givenCustomKeyWithLength(int length) {\n        byte[] keyBytes = new byte[length];\n        for (int i = 0; i < length; i++) {\n            keyBytes[i] = (byte) i;\n        }\n        this.testPlaintext = Base64.getEncoder().encodeToString(keyBytes);\n    }\n\n    private void givenPlaintext(String plaintext) {\n        this.testPlaintext = plaintext;\n    }\n\n    private void givenSystemdCredentialFile(String credentialName) {\n        try {\n            this.credentialDirectory = tempFolder.newFolder().toPath();\n            Path credFile = this.credentialDirectory.resolve(credentialName);\n            Files.write(credFile, this.testPlaintext.getBytes(StandardCharsets.UTF_8));\n            System.setProperty(\"CREDENTIALS_DIRECTORY\", this.credentialDirectory.toString());\n        } catch (IOException e) {\n            fail(\"Failed to create systemd credential file\");\n        }\n    }\n\n    private void givenSystemPropertyKey() {\n        System.setProperty(\"org.eclipse.kura.crypto.secretKey\", this.testPlaintext);\n    }\n\n    private void givenDifferentSystemPropertyKey() {\n        String differentKey = Base64.getEncoder()\n                .encodeToString(\"different-key-32-bytes-long!\".getBytes(StandardCharsets.UTF_8));\n        System.setProperty(\"org.eclipse.kura.crypto.secretKey\", differentKey);\n    }\n\n    private void whenActivatingCryptoService() {\n        this.cryptoService.activate();\n    }\n\n    private void whenEncryptingData() {\n        try {\n            this.encryptedData = this.cryptoService.encryptAes(this.testPlaintext.toCharArray());\n        } catch (KuraException e) {\n            fail(\"Encryption failed: \" + e.getMessage());\n        }\n    }\n\n    private void whenDecryptingData() {\n        try {\n            this.decryptedData = this.cryptoService.decryptAes(this.encryptedData);\n        } catch (KuraException e) {\n            fail(\"Decryption failed: \" + e.getMessage());\n        }\n    }\n\n    private void thenServiceIsActivated() {\n        assertNotNull(this.cryptoService);\n    }\n\n    private void thenServiceFallsBackToDefaultKey() {\n        assertNotNull(this.cryptoService);\n    }\n\n    private void thenDataIsEncrypted() {\n        assertNotNull(this.encryptedData);\n    }\n\n    private void thenDecryptedDataMatchesPlaintext() {\n        assertNotNull(this.decryptedData);\n        assertArrayEquals(this.testPlaintext.toCharArray(), this.decryptedData);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.crypto.test/src/main/java/org/eclipse/kura/core/crypto/EncryptDecryptTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.crypto;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\n\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mockito;\n\npublic class EncryptDecryptTest {\n\n    private CryptoServiceImpl cryptoService;\n\n    @Before\n    public void setup() {\n        final SystemService mockSystemService = Mockito.mock(SystemService.class);\n        try {\n            Mockito.when(mockSystemService.getKuraDataDirectory()).thenReturn(Files.createTempDirectory(null).toString());\n        } catch (IOException e) {\n            throw new IllegalStateException(\"cannot create temporary directory\");\n        }\n\nthis.cryptoService = new CryptoServiceImpl();\n        this.cryptoService.setSystemService(mockSystemService);\n        this.cryptoService.activate();\n    }\n\n    @Test\n    public void shouldStreamEncodeAndStreamDecodeCorrectly() throws KuraException, IOException {\n\n        String dataToEncrypt = \"testingcrypto\";\n\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        try (OutputStream cryptoOut = this.cryptoService.aesEncryptingStream(out);) {\n\n            cryptoOut.write(dataToEncrypt.getBytes(StandardCharsets.UTF_8));\n            cryptoOut.flush();\n            out.flush();\n        }\n\n        try (ByteArrayInputStream input = new ByteArrayInputStream(out.toByteArray());\n                InputStream cryptoInput = this.cryptoService.aesDecryptingStream(input);) {\n            String dataDecrypted = IOUtils.toString(cryptoInput, StandardCharsets.UTF_8);\n\n            assertEquals(dataToEncrypt, dataDecrypted);\n        }\n\n    }\n\n    @Test\n    public void shouldReturnSameDecodingOutputWithStreamAndChars() throws KuraException, IOException {\n\n        String dataToEncrypt = \"testingcrypto\";\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n\n        try (OutputStream cryptoOut = this.cryptoService.aesEncryptingStream(out);) {\n\n            cryptoOut.write(dataToEncrypt.getBytes(StandardCharsets.UTF_8));\n            cryptoOut.flush();\n            out.flush();\n        }\n\n        char[] charEncryptedData = this.cryptoService.encryptAes(dataToEncrypt.toCharArray());\n\n        try (ByteArrayInputStream input = new ByteArrayInputStream(out.toByteArray());\n                InputStream cryptoInput = this.cryptoService.aesDecryptingStream(input);) {\n\n            assertEquals(new String(this.cryptoService.decryptAes(charEncryptedData)),\n                    IOUtils.toString(cryptoInput, StandardCharsets.UTF_8));\n        }\n    }\n\n    @Test\n    public void shouldStramEncryptAndCharDecryptCorrectly() throws KuraException, IOException {\n        String dataToEncrypt = \"testingcrypto\";\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n\n        try (OutputStream cryptoOut = this.cryptoService.aesEncryptingStream(out);) {\n\n            cryptoOut.write(dataToEncrypt.getBytes(StandardCharsets.UTF_8));\n            cryptoOut.flush();\n            out.flush();\n        }\n\n        try (ByteArrayInputStream input = new ByteArrayInputStream(out.toByteArray())) {\n            String cryptedData = IOUtils.toString(input, StandardCharsets.UTF_8);\n            String decryptedData = new String(this.cryptoService.decryptAes(cryptedData.toCharArray()));\n\n            assertEquals(dataToEncrypt, decryptedData);\n        }\n    }\n\n    @Test\n    public void shouldCharEncryptAndStreamDecryptCorrectly() throws KuraException, IOException {\n        String dataToEncrypt = \"testingcrypto\";\n\n        char[] cryptedData = this.cryptoService.encryptAes(dataToEncrypt.toCharArray());\n\n        try (ByteArrayInputStream input = new ByteArrayInputStream(\n                new String(cryptedData).getBytes(StandardCharsets.UTF_8));\n                InputStream cryptoInput = this.cryptoService.aesDecryptingStream(input);) {\n\n            String decryptedData = IOUtils.toString(cryptoInput, StandardCharsets.UTF_8);\n            assertEquals(dataToEncrypt, decryptedData);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.crypto.test/src/main/java/org/eclipse/kura/core/crypto/SystemdCredentialLoaderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.core.crypto;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Optional;\n\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.TemporaryFolder;\n\npublic class SystemdCredentialLoaderTest {\n\n    @Rule\n    public TemporaryFolder tempFolder = new TemporaryFolder();\n\n    private Path credentialRootDirectory;\n    private SystemdCredentialLoader loader;\n    private Optional<SystemdCredentialLoader> result;\n    private byte[] credentialData;\n    @Test\n    public void createFromEnvironmentVariableSuccess() {\n        givenCredentialRootDirectory();\n\n        whenCreatingLoaderFromEnv();\n\n        thenLoaderMayOrMayNotBePresent();\n    }\n\n    @Test\n    public void createFromEnvironmentVariableNotSet() {\n        givenNoEnvironmentVariable();\n\n        whenCreatingLoaderFromEnv();\n\n        thenLoaderIsNotPresent();\n    }\n\n    @Test\n    public void loadExistingCredential() {\n        givenCredentialRootDirectory();\n        givenCredentialFile(\"test-credential\", \"secret-value\");\n        givenLoader();\n\n        whenLoadingCredential(\"test-credential\");\n\n        thenCredentialDataEquals(\"secret-value\");\n    }\n\n    @Test\n    public void loadCredentialWithBinaryData() {\n        givenCredentialRootDirectory();\n        givenCredentialFileWithBytes(\"binary-cred\", new byte[]{0x01, 0x02, 0x03, 0x04});\n        givenLoader();\n\n        whenLoadingCredential(\"binary-cred\");\n\n        thenCredentialDataEquals(new byte[]{0x01, 0x02, 0x03, 0x04});\n    }\n\n    @Test\n    public void loadNonExistentCredential() {\n        givenCredentialRootDirectory();\n        givenLoader();\n\n        whenLoadingCredential(\"non-existent\");\n\n        thenCredentialIsNotPresent();\n    }\n\n    @Test\n    public void loadCredentialFromInvalidDirectory() {\n        givenNonExistentCredentialDirectory();\n        givenLoader();\n\n        whenLoadingCredential(\"any-credential\");\n\n        thenCredentialIsNotPresent();\n    }\n\n    @Test\n    public void loadEmptyCredential() {\n        givenCredentialRootDirectory();\n        givenCredentialFile(\"empty-cred\", \"\");\n        givenLoader();\n\n        whenLoadingCredential(\"empty-cred\");\n\n        thenCredentialDataIsEmpty();\n    }\n\n    private void givenCredentialRootDirectory() {\n        try {\n            this.credentialRootDirectory = tempFolder.newFolder().toPath();\n        } catch (IOException e) {\n            fail(\"Failed to create temporary directory\");\n        }\n    }\n\n    private void givenNonExistentCredentialDirectory() {\n        this.credentialRootDirectory = tempFolder.getRoot().toPath().resolve(\"non-existent\");\n    }\n\n    private void givenNoEnvironmentVariable() {\n        // Environment variables cannot be set in Java tests, so this is a no-op\n    }\n\n    private void givenCredentialFile(String name, String content) {\n        try {\n            Path credFile = this.credentialRootDirectory.resolve(name);\n            Files.write(credFile, content.getBytes(StandardCharsets.UTF_8));\n        } catch (IOException e) {\n            fail(\"Failed to create credential file\");\n        }\n    }\n\n    private void givenCredentialFileWithBytes(String name, byte[] content) {\n        try {\n            Path credFile = this.credentialRootDirectory.resolve(name);\n            Files.write(credFile, content);\n        } catch (IOException e) {\n            fail(\"Failed to create credential file\");\n        }\n    }\n\n    private void givenLoader() {\n        this.loader = new SystemdCredentialLoader(this.credentialRootDirectory.toFile());\n    }\n\n    private void whenCreatingLoaderFromEnv() {\n        this.result = SystemdCredentialLoader.fromEnv();\n    }\n\n    private void whenLoadingCredential(String name) {\n        try {\n            this.credentialData = this.loader.loadCredential(name).orElse(null);\n        } catch (IOException e) {\n            fail(\"Unexpected exception: \" + e.getMessage());\n        }\n    }\n\n    private void thenLoaderIsPresent() {\n        assertNotNull(this.result);\n        assertTrue(this.result.isPresent());\n    }\n\n    private void thenLoaderIsNotPresent() {\n        assertNotNull(this.result);\n        assertFalse(this.result.isPresent());\n    }\n\n    private void thenLoaderMayOrMayNotBePresent() {\n        assertNotNull(this.result);\n    }\n\n    private void thenCredentialIsNotPresent() {\n        assertTrue(\"Expected credential data to be null for non-existent credentials\", this.credentialData == null);\n    }\n\n    private void thenCredentialDataEquals(String expected) {\n        assertNotNull(this.credentialData);\n        assertArrayEquals(expected.getBytes(StandardCharsets.UTF_8), this.credentialData);\n    }\n\n    private void thenCredentialDataEquals(byte[] expected) {\n        assertNotNull(this.credentialData);\n        assertArrayEquals(expected, this.credentialData);\n    }\n\n    private void thenCredentialDataIsEmpty() {\n        assertNotNull(this.credentialData);\n        assertEquals(0, this.credentialData.length);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.identity.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.identity.test\nBundle-SymbolicName: org.eclipse.kura.core.identity.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nImport-Package: org.eclipse.kura;version=\"1.7.0\",\n org.eclipse.kura.configuration,\n org.eclipse.kura.configuration.metatype;version=\"1.1.0\",\n org.eclipse.kura.core.configuration.metatype;version=\"1.0.0\",\n org.eclipse.kura.core.testutil.service;version=\"1.0.0\",\n org.eclipse.kura.crypto;version=\"1.3.0\",\n org.eclipse.kura.identity;version=\"1.1.0\",\n org.eclipse.kura.identity.configuration.extension;version=\"1.0.0\",\n org.junit;version=\"4.12.0\",\n org.mockito;version=\"4.8.1\",\n org.mockito.invocation;version=\"4.8.1\",\n org.mockito.stubbing;version=\"4.8.1\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.useradmin;version=\"1.1.0\"\nRequire-Bundle: org.eclipse.kura.core.identity;bundle-version=\"2.0.0\"\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.identity.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.identity.test/build.properties",
    "content": "#\n# Copyright (c) 2024 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.identity.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.core.identity.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.identity.test/src/main/java/org/eclipse/kura/core/identity/test/IdentityServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.core.identity.test;\n\nimport static java.util.Collections.singletonList;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.time.Duration;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.identity.AdditionalConfigurations;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityConfigurationComponent;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.PasswordHash;\nimport org.eclipse.kura.identity.Permission;\nimport org.eclipse.kura.identity.configuration.extension.IdentityConfigurationExtension;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mockito;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\n\npublic class IdentityServiceImplTest extends IdentityServiceTestBase {\n\n    @Test\n    public void shouldCreateIdentity() {\n        givenNoUserAdminRoleWithName(\"kura.user.foo\");\n        whenIdentityIsCreated(\"foo\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsUserCreated(true);\n\n        thenUserAdminRoleExists(\"kura.user.foo\", Role.USER);\n    }\n\n    @Test\n    public void shouldCreateIdentityWithDotsInName() {\n        givenNoUserAdminRoleWithName(\"kura.user.foo.bar_baz\");\n        whenIdentityIsCreated(\"foo.bar_baz\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsPermissionCreated(true);\n\n        thenUserAdminRoleExists(\"kura.user.foo.bar_baz\", Role.USER);\n    }\n\n    @Test\n    public void shouldCreateIdentityWithBothCasesInName() {\n        givenNoUserAdminRoleWithName(\"kura.user.foO_bAr.Baz\");\n        whenIdentityIsCreated(\"foO_bAr.Baz\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsPermissionCreated(true);\n\n        thenUserAdminRoleExists(\"kura.user.foO_bAr.Baz\", Role.USER);\n    }\n\n    @Test\n    public void shouldCreateIdentityWithNameContainingNumbers() {\n        givenNoUserAdminRoleWithName(\"kura.user.fo1_ba2_ba3\");\n        whenIdentityIsCreated(\"fo1_ba2_ba3\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsPermissionCreated(true);\n\n        thenUserAdminRoleExists(\"kura.user.fo1_ba2_ba3\", Role.USER);\n    }\n\n    @Test\n    public void shouldReportIdentityAlreadyExistingOnCreation() {\n        givenUserAdminRole(\"kura.user.foo\", Role.USER);\n        whenIdentityIsCreated(\"foo\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsUserCreated(false);\n        thenUserAdminRoleExists(\"kura.user.foo\", Role.USER);\n    }\n\n    @Test\n    public void shouldCreateIdentityFromConfiguration() {\n        givenNoUserAdminRoleWithName(\"kura.user.foo\");\n        givenUserAdminGroups(\"kura.permission.foo\");\n\n        whenIdentityIsCreated(new IdentityConfiguration(\"foo\", Arrays.asList(\n                new AssignedPermissions(set(new Permission(\"foo\"))),\n                new PasswordConfiguration(false, true, Optional.of(\"adminadmin\".toCharArray()), Optional.empty()))));\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsUserCreated(true);\n        thenUserAdminRoleExists(\"kura.user.foo\", Role.USER);\n        thenUserAdminGroupContainsMember(\"kura.permission.foo\", \"kura.user.foo\");\n        thenUserAdminCredentialIs(\"kura.user.foo\", \"kura.password\", sha256(\"adminadmin\"));\n    }\n\n    @Test\n    public void shouldReportIdentityAlreadyExistingOnConfigurationCreationWhenTemporaryExists() {\n        givenTemporaryIdentity(\"foo\");\n\n        whenIdentityIsCreated(new IdentityConfiguration(\"foo\", Collections.emptyList()));\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsUserCreated(false);\n        thenUserAdminRoleDoesNotExists(\"kura.user.foo\");\n    }\n\n    @Test\n    public void shouldDeleteIdentity() {\n        givenUserAdminRole(\"kura.user.foo\", Role.USER);\n\n        whenIdentityIsDeleted(\"foo\");\n\n        thenIdentityServiceReportsUserDeleted(true);\n        thenNoExceptionIsThrown();\n        thenUserAdminRoleDoesNotExists(\"kura.user.foo\");\n    }\n\n    @Test\n    public void shouldReportIdentityNotExistingOnDeletion() {\n        givenNoUserAdminRoleWithName(\"kura.user.foo\");\n\n        whenIdentityIsDeleted(\"foo\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsUserDeleted(false);\n        thenUserAdminRoleDoesNotExists(\"kura.user.foo\");\n    }\n\n    @Test\n    public void shouldCreatePermission() {\n        givenNoUserAdminRoleWithName(\"kura.permission.foo\");\n        whenPermissionIsCreated(\"foo\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsPermissionCreated(true);\n\n        thenUserAdminRoleExists(\"kura.permission.foo\", Role.GROUP);\n    }\n\n    @Test\n    public void shouldCreatePermissionWithDotsInName() {\n        givenNoUserAdminRoleWithName(\"kura.permission.foo.bar.baz\");\n        whenPermissionIsCreated(\"foo.bar.baz\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsPermissionCreated(true);\n\n        thenUserAdminRoleExists(\"kura.permission.foo.bar.baz\", Role.GROUP);\n    }\n\n    @Test\n    public void shouldCreatePermissionWithBothCasesInName() {\n        givenNoUserAdminRoleWithName(\"kura.permission.foO.bAr.Baz\");\n        whenPermissionIsCreated(\"foO.bAr.Baz\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsPermissionCreated(true);\n\n        thenUserAdminRoleExists(\"kura.permission.foO.bAr.Baz\", Role.GROUP);\n    }\n\n    @Test\n    public void shouldCreatePermissionWithNameContainingNumbers() {\n        givenNoUserAdminRoleWithName(\"kura.permission.fo1.ba2.ba3\");\n        whenPermissionIsCreated(\"fo1.ba2.ba3\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsPermissionCreated(true);\n\n        thenUserAdminRoleExists(\"kura.permission.fo1.ba2.ba3\", Role.GROUP);\n    }\n\n    @Test\n    public void shouldReportPermissionAlreadyExistingOnCreation() {\n        givenUserAdminRole(\"kura.permission.foo\", Role.GROUP);\n        whenPermissionIsCreated(\"foo\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsPermissionCreated(false);\n        thenUserAdminRoleExists(\"kura.permission.foo\", Role.GROUP);\n    }\n\n    @Test\n    public void shouldDeletePermission() {\n        givenUserAdminRole(\"kura.permission.foo\", Role.GROUP);\n\n        whenPermissionIsDeleted(\"foo\");\n\n        thenIdentityServiceReportsPermissionDeleted(true);\n        thenNoExceptionIsThrown();\n        thenUserAdminRoleDoesNotExists(\"kura.permission.foo\");\n    }\n\n    @Test\n    public void shouldReportPermissionNotExistingOnDeletion() {\n        givenNoUserAdminRoleWithName(\"kura.permission.foo\");\n\n        whenPermissionIsDeleted(\"foo\");\n\n        thenNoExceptionIsThrown();\n        thenIdentityServiceReportsPermissionDeleted(false);\n        thenUserAdminRoleDoesNotExists(\"kura.permission.foo\");\n    }\n\n    @Test\n    public void shouldListExistingIdentityNames() {\n        givenUserAdminUsers(\"kura.user.foo\", \"kura.user.bar\", \"other\");\n        givenUserAdminGroups(\"kura.permission.foo\", \"kura.permission.baz\", \"othergroup\");\n\n        whenIdentityNamesAreRetrieved();\n\n        thenNoExceptionIsThrown();\n        thenReturnedIdentityNamesAre(\"foo\", \"bar\");\n    }\n\n    @Test\n    public void shouldListExistingPermissionNames() {\n        givenUserAdminUsers(\"kura.user.foo\", \"kura.user.bar\", \"other\");\n        givenUserAdminGroups(\"kura.permission.foo\", \"kura.permission.baz\", \"othergroup\");\n\n        whenPermissionNamesAreRetrieved();\n\n        thenNoExceptionIsThrown();\n        thenReturnedPermissionNamesAre(\"foo\", \"baz\");\n    }\n\n    @Test\n    public void shouldSetPermissions() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminGroups(\"kura.permission.foo\", \"kura.permission.bar\", \"kura.permission.baz\",\n                \"kura.permission.other\", \"other\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\",\n                singletonList(new AssignedPermissions(set(new Permission(\"foo\"), new Permission(\"bar\"))))));\n\n        thenNoExceptionIsThrown();\n        thenUserAdminGroupContainsMember(\"kura.permission.foo\", \"kura.user.foo\");\n        thenUserAdminGroupContainsMember(\"kura.permission.bar\", \"kura.user.foo\");\n        thenUserAdminGroupDoesNotContainMember(\"kura.permission.baz\", \"kura.user.foo\");\n        thenUserAdminGroupDoesNotContainMember(\"kura.permission.other\", \"kura.user.foo\");\n    }\n\n    @Test\n    public void shouldFailToSetPermissionsIfPermissionDoesNotExist() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminGroups(\"kura.permission.foo\", \"kura.permission.bar\", \"kura.permission.baz\",\n                \"kura.permission.other\", \"other\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\",\n                singletonList(new AssignedPermissions(set(new Permission(\"foo\"), new Permission(\"notexisting\"))))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldConsiderConfigurationInvalidIfPermissionDoesNotExist() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminGroups(\"kura.permission.foo\", \"kura.permission.bar\", \"kura.permission.baz\",\n                \"kura.permission.other\", \"other\");\n\n        whenIdentityConfigurationIsValidated(new IdentityConfiguration(\"foo\",\n                singletonList(new AssignedPermissions(set(new Permission(\"foo\"), new Permission(\"notexisting\"))))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldRemovePermissions() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminGroups(\"kura.permission.foo\", \"kura.permission.bar\", \"kura.permission.baz\",\n                \"kura.permission.other\", \"other\");\n        givenUserAdminBasicMember(\"kura.permission.baz\", \"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\",\n                singletonList(new AssignedPermissions(set(new Permission(\"foo\"), new Permission(\"bar\"))))));\n\n        thenNoExceptionIsThrown();\n        thenUserAdminGroupContainsMember(\"kura.permission.foo\", \"kura.user.foo\");\n        thenUserAdminGroupContainsMember(\"kura.permission.bar\", \"kura.user.foo\");\n        thenUserAdminGroupDoesNotContainMember(\"kura.permission.baz\", \"kura.user.foo\");\n        thenUserAdminGroupDoesNotContainMember(\"kura.permission.other\", \"kura.user.foo\");\n    }\n\n    @Test\n    public void shouldReturnAssignedPermissions() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminGroups(\"kura.permission.foo\", \"kura.permission.bar\", \"kura.permission.baz\",\n                \"kura.permission.other\", \"other\");\n        givenUserAdminBasicMember(\"kura.permission.foo\", \"kura.user.foo\");\n        givenUserAdminBasicMember(\"kura.permission.bar\", \"kura.user.foo\");\n\n        whenIdentityConfigurationIsRetrieved(\"foo\", set(AssignedPermissions.class));\n\n        thenNoExceptionIsThrown();\n        thenIdentityConfigurationEquals(new IdentityConfiguration(\"foo\",\n                singletonList(new AssignedPermissions(set(new Permission(\"foo\"), new Permission(\"bar\"))))));\n    }\n\n    @Test\n    public void shouldSetUserPassword() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(\"adminadmin\".toCharArray()), Optional.empty()))));\n\n        thenNoExceptionIsThrown();\n        thenUserAdminCredentialIs(\"kura.user.foo\", \"kura.password\", sha256(\"adminadmin\"));\n    }\n\n    @Test\n    public void shouldNotChangeUserPassword() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminCredential(\"kura.user.foo\", \"kura.password\", sha256(\"foobar\"));\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\",\n                singletonList(new PasswordConfiguration(false, true, Optional.empty(), Optional.empty()))));\n\n        thenNoExceptionIsThrown();\n        thenUserAdminCredentialIs(\"kura.user.foo\", \"kura.password\", sha256(\"foobar\"));\n    }\n\n    @Test\n    public void shouldRemoveUserPassword() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminCredential(\"kura.user.foo\", \"kura.password\", sha256(\"foobar\"));\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\",\n                singletonList(new PasswordConfiguration(false, false, Optional.empty(), Optional.empty()))));\n\n        thenNoExceptionIsThrown();\n        thenUserAdminCredentialIsNotSet(\"kura.user.foo\", \"kura.password\");\n    }\n\n    @Test\n    public void shouldSetNeedPasswordChange() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 8, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(true, true, Optional.of(\"adminadmin\".toCharArray()), Optional.empty()))));\n\n        thenNoExceptionIsThrown();\n        thenUserAdminCredentialIs(\"kura.user.foo\", \"kura.password\", sha256(\"adminadmin\"));\n        thenUserAdminPropertyIs(\"kura.user.foo\", \"kura.need.password.change\", \"true\");\n    }\n\n    @Test\n    public void shouldUnsetNeedPasswordChange() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminProperty(\"kura.user.foo\", \"kura.need.password.change\", \"true\");\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 8, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(\"adminadmin\".toCharArray()), Optional.empty()))));\n\n        thenNoExceptionIsThrown();\n        thenUserAdminCredentialIs(\"kura.user.foo\", \"kura.password\", sha256(\"adminadmin\"));\n        thenUserAdminPropertyIsNotSet(\"kura.user.foo\", \"kura.need.password.change\");\n    }\n\n    @Test\n    public void shouldReturnNeedPasswordChangeTrue() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminProperty(\"kura.user.foo\", \"kura.need.password.change\", \"true\");\n\n        whenIdentityConfigurationIsRetrieved(\"foo\", set(PasswordConfiguration.class));\n\n        thenNoExceptionIsThrown();\n        thenIdentityConfigurationEquals(new IdentityConfiguration(\"foo\",\n                singletonList(new PasswordConfiguration(true, false, Optional.empty(), Optional.empty()))));\n    }\n\n    @Test\n    public void shouldReturnNeedPasswordChangeFalse() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsRetrieved(\"foo\", set(PasswordConfiguration.class));\n\n        thenNoExceptionIsThrown();\n        thenIdentityConfigurationEquals(new IdentityConfiguration(\"foo\",\n                singletonList(new PasswordConfiguration(false, false, Optional.empty(), Optional.empty()))));\n    }\n\n    @Test\n    public void shouldReturnPasswordHash() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenUserAdminCredential(\"kura.user.foo\", \"kura.password\", sha256(\"foobar\"));\n        givenPasswordHash(\"foobar\");\n\n        whenIdentityConfigurationIsRetrieved(\"foo\", set(PasswordConfiguration.class));\n\n        thenNoExceptionIsThrown();\n        thenIdentityConfigurationEquals(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.empty(), Optional.of(lastPasswordHash())))));\n    }\n\n    @Test\n    public void shouldReturnDefaultConfiguationFromExtension() {\n        givenMockIdentityConfigurationExtension(\"test.extension\");\n        givenExtensionDefaultConfiguration(\"test.extension\", \"foo\",\n                TestComponentConfiguration.forPid(\"test.extension\"));\n\n        whenIdentityDefaultConfigurationIsRetrieved(\"foo\", set(AdditionalConfigurations.class));\n\n        thenNoExceptionIsThrown();\n        thenIdentityDefaultConfigurationEquals(new IdentityConfiguration(\"foo\", singletonList(\n                new AdditionalConfigurations(singletonList(TestComponentConfiguration.forPid(\"test.extension\"))))));\n    }\n\n    @Test\n    public void shouldReturnConfiguationFromExtension() {\n        givenMockIdentityConfigurationExtension(\"test.extension\");\n        givenExtensionConfiguration(\"test.extension\", \"foo\", TestComponentConfiguration.forPid(\"test.extension\"));\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsRetrieved(\"foo\", set(AdditionalConfigurations.class));\n\n        thenNoExceptionIsThrown();\n        thenIdentityConfigurationEquals(new IdentityConfiguration(\"foo\", singletonList(\n                new AdditionalConfigurations(singletonList(TestComponentConfiguration.forPid(\"test.extension\"))))));\n    }\n\n    @Test\n    public void shouldConsiderConfigurationInvalidIfExtensionIsNotRegistered() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsValidated(new IdentityConfiguration(\"foo\", singletonList(\n                new AdditionalConfigurations(singletonList(TestComponentConfiguration.forPid(\"nonexisting\"))))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotAllowEmptyPassword() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(\"\".toCharArray()), Optional.empty()))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotAllowPasswordWithOnlySpaces() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(\n                new IdentityConfiguration(\"foo\", singletonList(new PasswordConfiguration(false, true,\n                        Optional.of(\"                  \".toCharArray()), Optional.empty()))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotAllowPasswordBeginningWithSpaces() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(\" adminadmin\".toCharArray()), Optional.empty()))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotAllowPasswordEndingWithSpaces() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(\"adminadmin \".toCharArray()), Optional.empty()))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotAllowPasswordContainingSpaces() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(\"admin admin \".toCharArray()), Optional.empty()))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotAllowPasswordContainingTab() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(\"admin\\tadmin \".toCharArray()), Optional.empty()))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotAllowPasswordEqualsToIdentityName() {\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(\"foo\".toCharArray()), Optional.empty()))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldAllow255CharsPassword() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 8, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(repeat('a', 255)), Optional.empty()))));\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldNotAllowTooLongPassword() {\n        givenUserAdminUsers(\"kura.user.foo\");\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 8, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(repeat('a', 256)), Optional.empty()))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotAllowPasswordNotSatisfyingPasswordStrengthRequirements() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new PasswordConfiguration(false, true, Optional.of(\"a\".toCharArray()), Optional.empty()))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotCreateIdentityWithEmptyName() {\n        givenNoUserAdminRoleWithName(\"kura.user.\");\n        whenIdentityIsCreated(\"\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityWithTooShortName() {\n        givenNoUserAdminRoleWithName(\"kura.user.ab\");\n        whenIdentityIsCreated(\"ab\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.ab\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityWithNameContainingOnlySpaces() {\n        givenNoUserAdminRoleWithName(\"kura.user.         \");\n        whenIdentityIsCreated(\"         \");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.         \");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityWithNameBeginningWithSpaces() {\n        givenNoUserAdminRoleWithName(\"kura.user. foo\");\n        whenIdentityIsCreated(\" foo\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user. foo\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityWithNameEndingWithSpaces() {\n        givenNoUserAdminRoleWithName(\"kura.user.foo \");\n        whenIdentityIsCreated(\"foo \");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.foo \");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityWithNameContainingSpaces() {\n        givenNoUserAdminRoleWithName(\"kura.user.foo bar\");\n        whenIdentityIsCreated(\"foo bar\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.foo bar\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityWithNameContainingTab() {\n        givenNoUserAdminRoleWithName(\"kura.user.foo\\tbar\");\n        whenIdentityIsCreated(\"foo\\tbar\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.foo\\tbar\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityNameStartingWithDot() {\n        givenNoUserAdminRoleWithName(\"kura.user..foobar\");\n        whenIdentityIsCreated(\".foobar\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user..foobar\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityNameEndingWithDot() {\n        givenNoUserAdminRoleWithName(\"kura.user.foobar.\");\n        whenIdentityIsCreated(\"foobar.\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.foobar.\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityContainingASequenceOfTwoDots() {\n        givenNoUserAdminRoleWithName(\"kura.user.foobar..baz\");\n        whenIdentityIsCreated(\"foobar..baz\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.foobar..baz\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityNameStartingWithUnderscore() {\n        givenNoUserAdminRoleWithName(\"kura.user._foobar\");\n        whenIdentityIsCreated(\"_foobar\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user._foobar\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityNameEndingWithUnderscore() {\n        givenNoUserAdminRoleWithName(\"kura.user.foobar_\");\n        whenIdentityIsCreated(\"foobar_\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.foobar_\");\n    }\n\n    @Test\n    public void shouldNotCreateIdentityContainingASequenceOfTwoUnderscores() {\n        givenNoUserAdminRoleWithName(\"kura.user.foobar__baz\");\n        whenIdentityIsCreated(\"foobar__baz\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.foobar__baz\");\n    }\n\n    @Test\n    public void shouldAllow255CharactersIdentityName() {\n        givenNoUserAdminRoleWithName(\"kura.user.\" + new String(repeat('a', 255)));\n        whenIdentityIsCreated(new String(repeat('a', 255)));\n\n        thenNoExceptionIsThrown();\n\n        thenUserAdminRoleExists(\"kura.user.\" + new String(repeat('a', 255)), Role.USER);\n    }\n\n    @Test\n    public void shouldNotCreateIdentityWithTooLongName() {\n        givenNoUserAdminRoleWithName(\"kura.user.\" + new String(repeat('a', 256)));\n        whenIdentityIsCreated(\"         \");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.user.\" + new String(repeat('a', 256)));\n    }\n\n    @Test\n    public void shouldConsiderConfigurationInvalidIfExtensionValidationFails() {\n        givenMockIdentityConfigurationExtension(\"test.extension\");\n        givenExtensionReturningValidationFailure(\"test.extension\", \"foobar\");\n\n        whenIdentityConfigurationIsValidated(new IdentityConfiguration(\"foobar\", singletonList(\n                new AdditionalConfigurations(singletonList(TestComponentConfiguration.forPid(\"test.extension\"))))));\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldNotCreatePermissionWithEmptyName() {\n        givenNoUserAdminRoleWithName(\"kura.permission.\");\n        whenPermissionIsCreated(\"\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission.\");\n    }\n\n    @Test\n    public void shouldNotCreatePermissionWithTooShortName() {\n        givenNoUserAdminRoleWithName(\"kura.permission.ab\");\n        whenPermissionIsCreated(\"ab\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission.ab\");\n    }\n\n    @Test\n    public void shouldNotCreatePermissionWithOnlySpaces() {\n        givenNoUserAdminRoleWithName(\"kura.permission.              \");\n        whenPermissionIsCreated(\"              \");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission.              \");\n    }\n\n    @Test\n    public void shouldNotCreatePermissionBeginningWithSpaces() {\n        givenNoUserAdminRoleWithName(\"kura.permission. foo\");\n        whenPermissionIsCreated(\" foo\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission. foo\");\n    }\n\n    @Test\n    public void shouldNotCreatePermissionEndingWithSpaces() {\n        givenNoUserAdminRoleWithName(\"kura.permission.foo \");\n        whenPermissionIsCreated(\"foo \");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission.foo \");\n    }\n\n    @Test\n    public void shouldNotCreatePermissionContainingSpaces() {\n        givenNoUserAdminRoleWithName(\"kura.permission.foo bar\");\n        whenPermissionIsCreated(\"foo bar\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission.foo bar\");\n    }\n\n    @Test\n    public void shouldNotCreatePermissionContainingTab() {\n        givenNoUserAdminRoleWithName(\"kura.permission.foo\\tbar\");\n        whenPermissionIsCreated(\"foo\\tbar\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission.foo\\tbar\");\n    }\n\n    @Test\n    public void shouldNotCreatePermissionStartingWithDot() {\n        givenNoUserAdminRoleWithName(\"kura.permission..foobar\");\n        whenPermissionIsCreated(\".foobar\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission..foobar\");\n    }\n\n    @Test\n    public void shouldNotCreatePermissionEndingWithDot() {\n        givenNoUserAdminRoleWithName(\"kura.permission.foobar.\");\n        whenPermissionIsCreated(\"foobar.\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission.foobar.\");\n    }\n\n    @Test\n    public void shouldNotCreatePermissionContainingASequenceOfTwoDots() {\n        givenNoUserAdminRoleWithName(\"kura.permission.foobar..baz\");\n        whenPermissionIsCreated(\"foobar..baz\");\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission.foobar..baz\");\n    }\n\n    @Test\n    public void shouldAllow255CharsPermission() {\n        givenNoUserAdminRoleWithName(\"kura.permission.\" + new String(repeat('a', 255)));\n        whenPermissionIsCreated(new String(repeat('a', 255)));\n\n        thenNoExceptionIsThrown();\n\n        thenUserAdminRoleExists(\"kura.permission.\" + new String(repeat('a', 255)), Role.GROUP);\n    }\n\n    @Test\n    public void shouldNotAllowTooLongPermissionName() {\n        givenNoUserAdminRoleWithName(\"kura.permission.\" + new String(repeat('a', 256)));\n        whenPermissionIsCreated(new String(repeat('a', 256)));\n\n        thenExceptionIsThrown(KuraException.class);\n\n        thenUserAdminRoleDoesNotExists(\"kura.permission.\" + new String(repeat('a', 256)));\n    }\n\n    @Test\n    public void shouldSupportUpdatingAdditionalConfiguration() {\n        givenMockIdentityConfigurationExtension(\"test.extension\");\n        givenUserAdminUsers(\"kura.user.foo\");\n\n        whenIdentityConfigurationIsUpdated(new IdentityConfiguration(\"foo\", singletonList(\n                new AdditionalConfigurations(singletonList(TestComponentConfiguration.forPid(\"test.extension\"))))));\n        whenIdentityConfigurationIsRetrieved(\"foo\", set(AdditionalConfigurations.class));\n\n        thenNoExceptionIsThrown();\n        thenIdentityConfigurationEquals(new IdentityConfiguration(\"foo\", singletonList(\n                new AdditionalConfigurations(singletonList(TestComponentConfiguration.forPid(\"test.extension\"))))));\n    }\n\n    private final UserAdmin userAdmin;\n    private final CryptoService cryptoService;\n    private final IdentityService identityService;\n\n    private Optional<Exception> exception = Optional.empty();\n    private Optional<Object> result = Optional.empty();\n    private Optional<PasswordHash> passwordHash = Optional.empty();\n    private final Map<String, MockExtensionHolder> extensions = new HashMap<>();\n\n    public IdentityServiceImplTest() {\n        super();\n        try {\n            this.userAdmin = ServiceUtil.trackService(UserAdmin.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n            this.cryptoService = ServiceUtil.trackService(CryptoService.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n            this.identityService = ServiceUtil.trackService(IdentityService.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n\n            givenNoUserAdminRoles();\n        } catch (Exception e) {\n            fail(\"failed to setup test environment\");\n            throw new IllegalStateException(\"unreachable\");\n        }\n    }\n\n    @After\n    public void cleanup() {\n        for (final MockExtensionHolder reg : this.extensions.values()) {\n            reg.registration.unregister();\n        }\n    }\n\n    private void givenMockIdentityConfigurationExtension(final String pid) {\n        this.extensions.put(pid, new MockExtensionHolder(pid));\n    }\n\n    private void givenExtensionConfiguration(final String extensionPid, final String identity,\n            final ComponentConfiguration config) {\n        this.extensions.get(extensionPid).configurations.put(identity, config);\n    }\n\n    private void givenExtensionDefaultConfiguration(final String extensionPid, final String identity,\n            final ComponentConfiguration config) {\n        this.extensions.get(extensionPid).defaultConfigurations.put(identity, config);\n    }\n\n    private void givenExtensionReturningValidationFailure(final String extensionPid, final String identity) {\n        this.extensions.get(extensionPid).throwOnIdentityValidation(identity);\n    }\n\n    private void givenUserAdminProperty(final String role, final String key, final String value) {\n        this.userAdmin.getRole(role).getProperties().put(key, value);\n    }\n\n    private void givenUserAdminCredential(final String user, final String key, final String value) {\n        ((User) this.userAdmin.getRole(user)).getCredentials().put(key, value);\n    }\n\n    private void givenUserAdminBasicMember(final String group, final String member) {\n        ((Group) this.userAdmin.getRole(group)).addMember(this.userAdmin.getRole(member));\n    }\n\n    private void givenNoUserAdminRoleWithName(final String name) {\n        this.userAdmin.removeRole(name);\n    }\n\n    private void givenUserAdminRole(final String name, final int type) {\n        this.userAdmin.createRole(name, type);\n    }\n\n    private void givenNoUserAdminRoles() {\n        try {\n            final Role[] roles = this.userAdmin.getRoles(null);\n\n            if (roles != null) {\n                for (final Role role : roles) {\n                    this.userAdmin.removeRole(role.getName());\n                }\n            }\n        } catch (InvalidSyntaxException e) {\n            fail(\"failed to get existing roles\");\n        }\n    }\n\n    private void givenUserAdminUsers(final String... users) {\n        for (final String user : users) {\n            this.userAdmin.createRole(user, Role.USER);\n        }\n    }\n\n    private void givenUserAdminGroups(final String... users) {\n        for (final String user : users) {\n            this.userAdmin.createRole(user, Role.GROUP);\n        }\n    }\n\n    private void givenPasswordHash(final String password) {\n        try {\n            this.passwordHash = Optional.of(this.identityService.computePasswordHash(password.toCharArray()));\n        } catch (Exception e) {\n            fail(\"failed to compute password hash\");\n        }\n    }\n\n    private void whenIdentityIsCreated(final String name) {\n        call(() -> this.identityService.createIdentity(name));\n    }\n\n    private void whenIdentityIsCreated(final IdentityConfiguration configuration) {\n        call(() -> this.identityService.createIdentity(configuration));\n    }\n\n    private void givenTemporaryIdentity(final String name) {\n        callVoid(() -> {\n            this.identityService.createTemporaryIdentity(name, Duration.ofHours(1));\n            return null;\n        });\n    }\n\n    private void whenIdentityIsDeleted(final String name) {\n        call(() -> this.identityService.deleteIdentity(name));\n    }\n\n    private void whenPermissionIsCreated(final String name) {\n        call(() -> this.identityService.createPermission(new Permission(name)));\n    }\n\n    private void whenPermissionIsDeleted(final String name) {\n        call(() -> this.identityService.deletePermission(new Permission(name)));\n    }\n\n    private void whenIdentityNamesAreRetrieved() {\n        call(() -> this.identityService.getIdentitiesConfiguration(Collections.emptySet()));\n    }\n\n    private void whenPermissionNamesAreRetrieved() {\n        call(() -> this.identityService.getPermissions());\n    }\n\n    private void whenIdentityConfigurationIsUpdated(final IdentityConfiguration identityConfiguration) {\n        callVoid(() -> {\n            this.identityService.updateIdentityConfiguration(identityConfiguration);\n            return null;\n        });\n    }\n\n    private void whenIdentityConfigurationIsValidated(final IdentityConfiguration identityConfiguration) {\n        callVoid(() -> {\n            this.identityService.validateIdentityConfiguration(identityConfiguration);\n            return null;\n        });\n    }\n\n    private void whenIdentityConfigurationIsRetrieved(final String identity,\n            final Set<Class<? extends IdentityConfigurationComponent>> components) {\n        call(() -> this.identityService.getIdentityConfiguration(identity, components));\n    }\n\n    private void whenIdentityDefaultConfigurationIsRetrieved(final String identity,\n            final Set<Class<? extends IdentityConfigurationComponent>> components) {\n        call(() -> this.identityService.getIdentityDefaultConfiguration(identity, components));\n    }\n\n    private void thenUserAdminPropertyIs(final String role, final String key, final String value) {\n        assertEquals(value, this.userAdmin.getRole(role).getProperties().get(key));\n    }\n\n    private void thenUserAdminPropertyIsNotSet(final String role, final String key) {\n        assertNull(this.userAdmin.getRole(role).getProperties().get(key));\n    }\n\n    private void thenUserAdminCredentialIs(final String user, final String key, final String value) {\n        assertEquals(value, ((User) this.userAdmin.getRole(user)).getCredentials().get(key));\n    }\n\n    private void thenUserAdminCredentialIsNotSet(final String user, final String key) {\n        assertNull(((User) this.userAdmin.getRole(user)).getCredentials().get(key));\n    }\n\n    private void thenUserAdminGroupContainsMember(final String group, final String member) {\n        final List<Role> members = getBasicMembers(group);\n\n        assertTrue(members.stream().filter(m -> Objects.equals(member, m.getName())).findAny().isPresent());\n    }\n\n    private void thenUserAdminGroupDoesNotContainMember(final String group, final String member) {\n        final List<Role> members = getBasicMembers(group);\n\n        assertFalse(members.stream().filter(m -> Objects.equals(member, m.getName())).findAny().isPresent());\n    }\n\n    private void thenIdentityServiceReportsUserDeleted(final boolean deleted) {\n        assertEquals(Optional.of(deleted), this.result);\n    }\n\n    private void thenIdentityServiceReportsPermissionDeleted(final boolean deleted) {\n        assertEquals(Optional.of(deleted), this.result);\n    }\n\n    private void thenIdentityServiceReportsUserCreated(final boolean created) {\n        assertEquals(Optional.of(created), this.result);\n    }\n\n    private void thenIdentityServiceReportsPermissionCreated(final boolean created) {\n        assertEquals(Optional.of(created), this.result);\n    }\n\n    private void thenIdentityConfigurationEquals(final IdentityConfiguration identityConfiguration) {\n        assertEquals(Optional.of(identityConfiguration), expectResult(Optional.class));\n    }\n\n    private void thenIdentityDefaultConfigurationEquals(final IdentityConfiguration identityConfiguration) {\n        assertEquals(identityConfiguration, expectResult(IdentityConfiguration.class));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void thenReturnedIdentityNamesAre(final String... names) {\n        assertEquals(Arrays.stream(names).collect(Collectors.toSet()),\n                ((List<IdentityConfiguration>) expectResult(List.class)).stream().map(IdentityConfiguration::getName)\n                        .collect(Collectors.toSet()));\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void thenReturnedPermissionNamesAre(final String... names) {\n        assertEquals(Arrays.stream(names).collect(Collectors.toSet()), ((Set<Permission>) expectResult(Set.class))\n                .stream().map(Permission::getName).collect(Collectors.toSet()));\n    }\n\n    private void thenUserAdminRoleExists(final String name, final int type) {\n        assertNotNull(\"role \" + name + \" does not exist\", this.userAdmin.getRole(name));\n        assertEquals(type, this.userAdmin.getRole(name).getType());\n    }\n\n    private void thenUserAdminRoleDoesNotExists(final String name) {\n        assertNull(\"user \" + name + \" does exists\", this.userAdmin.getRole(name));\n    }\n\n    private void thenNoExceptionIsThrown() {\n        assertEquals(Optional.empty(), this.exception);\n    }\n\n    private void thenExceptionIsThrown(final Class<? extends Exception> clazz) {\n        assertEquals(Optional.of(clazz), this.exception.map(Object::getClass));\n    }\n\n    public <T> T expectResult(final Class<T> ty) {\n        return this.result.filter(ty::isInstance).map(ty::cast)\n                .orElseThrow(() -> new IllegalStateException(\"unexpected return type\"));\n    }\n\n    private List<Role> getBasicMembers(final String group) {\n        return Optional.ofNullable(((Group) this.userAdmin.getRole(group)).getMembers()).map(Arrays::asList)\n                .orElseGet(Collections::emptyList);\n    }\n\n    private char[] repeat(final char c, final int times) {\n        final char[] result = new char[times];\n\n        for (int i = 0; i < times; i++) {\n            result[i] = c;\n        }\n\n        return result;\n    }\n\n    private PasswordHash lastPasswordHash() {\n        return this.passwordHash.orElseThrow(() -> new IllegalStateException(\"no password hash has been computed\"));\n    }\n\n    private String sha256(final String key) {\n        try {\n            return this.cryptoService.sha256Hash(key);\n        } catch (Exception e) {\n            fail(\"cannot compute sha256 with cryptoservice\");\n            throw new IllegalStateException(\"unreachable\");\n        }\n    }\n\n    @SafeVarargs\n    private final <T> Set<T> set(final T... items) {\n        return new HashSet<>(Arrays.asList(items));\n    }\n\n    private void call(final Callable<?> callable) {\n        try {\n            this.result = Optional.of(callable.call());\n        } catch (Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void callVoid(final Callable<Void> callable) {\n        try {\n            callable.call();\n        } catch (Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private static class MockExtensionHolder {\n\n        private final ServiceRegistration<IdentityConfigurationExtension> registration;\n        private final IdentityConfigurationExtension extension;\n\n        private final Map<String, ComponentConfiguration> defaultConfigurations = new HashMap<>();\n        private final Map<String, ComponentConfiguration> configurations = new HashMap<>();\n\n        public MockExtensionHolder(final String pid) {\n            this.extension = Mockito.mock(IdentityConfigurationExtension.class);\n\n            try {\n                Mockito.when(this.extension.getConfiguration(ArgumentMatchers.anyString())).thenAnswer(a -> {\n                    final String name = a.getArgument(0, String.class);\n\n                    return Optional.ofNullable(this.configurations.get(name));\n                });\n\n                Mockito.when(this.extension.getDefaultConfiguration(ArgumentMatchers.anyString())).thenAnswer(a -> {\n                    final String name = a.getArgument(0, String.class);\n\n                    return Optional.ofNullable(this.defaultConfigurations.get(name));\n                });\n\n                Mockito.doAnswer(i -> {\n                    final String identityName = i.getArgument(0, String.class);\n                    final ComponentConfiguration connfig = i.getArgument(1, ComponentConfiguration.class);\n\n                    this.configurations.put(identityName, connfig);\n\n                    return (Void) null;\n                }).when(this.extension).updateConfiguration(ArgumentMatchers.anyString(), ArgumentMatchers.any());\n\n            } catch (KuraException e) {\n                // no need\n            }\n\n            final Dictionary<String, Object> properties = new Hashtable<>();\n            properties.put(\"kura.service.pid\", pid);\n\n            this.registration = FrameworkUtil.getBundle(IdentityServiceImplTest.class).getBundleContext()\n                    .registerService(IdentityConfigurationExtension.class, this.extension, properties);\n        }\n\n        void throwOnIdentityValidation(final String identityName) {\n            try {\n                Mockito.doThrow(new KuraException(KuraErrorCode.INVALID_PARAMETER)).when(this.extension)\n                        .validateConfiguration(ArgumentMatchers.eq(identityName), ArgumentMatchers.any());\n            } catch (KuraException e) {\n                // no need\n            }\n        }\n    }\n\n    private static class TestComponentConfiguration implements ComponentConfiguration {\n\n        private final String pid;\n        private final OCD ocd;\n        private final Map<String, Object> properties;\n\n        public TestComponentConfiguration(String pid, OCD ocd, Map<String, Object> properties) {\n            this.pid = pid;\n            this.ocd = ocd;\n            this.properties = properties;\n        }\n\n        @Override\n        public String getPid() {\n            return this.pid;\n        }\n\n        @Override\n        public OCD getDefinition() {\n            return this.ocd;\n        }\n\n        @Override\n        public Map<String, Object> getConfigurationProperties() {\n            return this.properties;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(this.ocd, this.pid, this.properties);\n        }\n\n        static TestComponentConfiguration forPid(final String pid) {\n            return new TestComponentConfiguration(pid, null, Collections.singletonMap(\"foo\", \"bar\"));\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (obj == null || getClass() != obj.getClass()) {\n                return false;\n            }\n            TestComponentConfiguration other = (TestComponentConfiguration) obj;\n            return Objects.equals(this.ocd, other.ocd) && Objects.equals(this.pid, other.pid)\n                    && Objects.equals(this.properties, other.properties);\n        }\n\n        @Override\n        public String toString() {\n            return \"TestComponentConfiguration [pid=\" + this.pid + \", ocd=\" + this.ocd + \", properties=\"\n                    + this.properties + \"]\";\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.identity.test/src/main/java/org/eclipse/kura/core/identity/test/IdentityServiceTestBase.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.core.identity.test;\n\nimport static org.junit.Assert.fail;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.Permission;\nimport org.junit.After;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\n\npublic abstract class IdentityServiceTestBase {\n\n    private static final String PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID = \"org.eclipse.kura.identity.PasswordStrengthVerificationService\";\n    private static final Pattern KURA_IDENTITY_ROLE_PATTERN = Pattern.compile(\"^kura\\\\.(user|permission)\\\\..+\");\n\n    private final ConfigurationService configurationService;\n    private final IdentityService identityService;\n    private final UserAdmin userAdmin;\n\n    protected void givenPasswordStrengthVerificationOptions(final Object... values) {\n\n        final Iterator<Object> iter = Arrays.asList(values).iterator();\n\n        final Map<String, Object> properties = new HashMap<>();\n\n        while (iter.hasNext()) {\n            properties.put((String) iter.next(), iter.next());\n        }\n\n        try {\n            ServiceUtil.updateComponentConfiguration(configurationService, PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID,\n                    properties).get(30, TimeUnit.SECONDS);\n        } catch (final Exception e) {\n            fail(\"failed to update authentication settings\");\n            throw new IllegalStateException(\"unreachable\");\n        }\n    }\n\n    public IdentityServiceTestBase() {\n        try {\n            this.configurationService = ServiceUtil.trackService(ConfigurationService.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n            this.identityService = ServiceUtil.trackService(IdentityService.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n            this.userAdmin = ServiceUtil.trackService(UserAdmin.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n\n            ServiceUtil\n                    .trackService(ConfigurableComponent.class,\n                            Optional.of(\"(kura.service.pid=\" + PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID + \")\"))\n                    .get(30, TimeUnit.SECONDS);\n        } catch (final Exception e) {\n            fail(\"failed to track ConfigurationService\");\n            throw new IllegalStateException(\"unreachable\");\n        }\n    }\n\n    @After\n    public void cleanupIdentityState() {\n        try {\n            for (final IdentityConfiguration identity : this.identityService\n                    .getIdentitiesConfiguration(Collections.emptySet())) {\n                this.identityService.deleteIdentity(identity.getName());\n            }\n        } catch (final Exception e) {\n        }\n\n        try {\n            for (final Permission permission : this.identityService.getPermissions()) {\n                this.identityService.deletePermission(permission);\n            }\n        } catch (final Exception e) {\n        }\n\n        try {\n            final Role[] roles = this.userAdmin.getRoles(null);\n            if (roles != null) {\n                for (final Role role : roles) {\n                    if (KURA_IDENTITY_ROLE_PATTERN.matcher(role.getName()).matches()) {\n                        this.userAdmin.removeRole(role.getName());\n                    }\n                }\n            }\n        } catch (final InvalidSyntaxException e) {\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.identity.test/src/main/java/org/eclipse/kura/core/identity/test/PasswordStrengthVerificationServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.identity.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.identity.PasswordStrengthRequirements;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.junit.Test;\n\npublic class PasswordStrengthVerificationServiceImplTest extends IdentityServiceTestBase {\n\n    @Test\n    public void shouldRejectTooShortPassword() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 5, \"new.password.require.digits\", true,\n                \"new.password.require.special.characters\", true, \"new.password.require.both.cases\", true);\n\n        whenPasswordIsValidated(\"As#1\");\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldAcceptPasswordLongEnough() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenPasswordIsValidated(\"abcd\");\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldRejectPasswordWithoutDigits() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", true,\n                \"new.password.require.special.characters\", true, \"new.password.require.both.cases\", true);\n\n        whenPasswordIsValidated(\"Abc#\");\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldRejectPasswordEqualsToIdentityName() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", true);\n\n        whenPasswordIsValidatedAgainstIdentityName(\"Admin\", \"Admin\");\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldRejectPasswordEqualsToIdentityNameDifferentCase() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", true);\n\n        whenPasswordIsValidatedAgainstIdentityName(\"Admin\", \"AdMIn\");\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldAcceptPasswordWithDigits() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenPasswordIsValidated(\"abc1\");\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldRejectPasswordWithoutSpecialCharacters() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", true,\n                \"new.password.require.special.characters\", true, \"new.password.require.both.cases\", true);\n\n        whenPasswordIsValidated(\"Abc1\");\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldAcceptPasswordWitSpecialCharacters() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", true, \"new.password.require.both.cases\", false);\n\n        whenPasswordIsValidated(\"abc@\");\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldRejectPasswordWithoutBothCases() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", true,\n                \"new.password.require.special.characters\", true, \"new.password.require.both.cases\", true);\n\n        whenPasswordIsValidated(\"ab#1\");\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldAcceptPasswordWithBothCases() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", true);\n\n        whenPasswordIsValidated(\"aBcD\");\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldAcceptPasswordSatisfyingAllRequirements() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 4, \"new.password.require.digits\", true,\n                \"new.password.require.special.characters\", true, \"new.password.require.both.cases\", true);\n\n        whenPasswordIsValidated(\"aBcD1#\");\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldReturnMinimumPasswordLength() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenPasswordRequirementsAreObtained();\n\n        thenNoExceptionIsThrown();\n        thenMinimumPasswordLengthIs(3);\n    }\n\n    @Test\n    public void shouldReturnRequireDigitsTrue() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", true,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenPasswordRequirementsAreObtained();\n\n        thenNoExceptionIsThrown();\n        thenDigitsAreRequired(true);\n    }\n\n    @Test\n    public void shouldReturnRequireDigitsFalse() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenPasswordRequirementsAreObtained();\n\n        thenNoExceptionIsThrown();\n        thenDigitsAreRequired(false);\n    }\n\n    @Test\n    public void shouldReturnRequireSpecialCharactersTrue() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", true, \"new.password.require.both.cases\", false);\n\n        whenPasswordRequirementsAreObtained();\n\n        thenNoExceptionIsThrown();\n        thenSpecialCharactersAreRequired(true);\n    }\n\n    @Test\n    public void shouldReturnRequireSpecialCharactersFalse() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenPasswordRequirementsAreObtained();\n\n        thenNoExceptionIsThrown();\n        thenSpecialCharactersAreRequired(false);\n    }\n\n    @Test\n    public void shouldReturnRequireBothCasesTrue() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", true);\n\n        whenPasswordRequirementsAreObtained();\n\n        thenNoExceptionIsThrown();\n        thenBothCasesAreRequired(true);\n    }\n\n    @Test\n    public void shouldReturnRequireBothCasesFalse() {\n        givenPasswordStrengthVerificationOptions(\"new.password.min.length\", 3, \"new.password.require.digits\", false,\n                \"new.password.require.special.characters\", false, \"new.password.require.both.cases\", false);\n\n        whenPasswordRequirementsAreObtained();\n\n        thenNoExceptionIsThrown();\n        thenBothCasesAreRequired(false);\n    }\n\n    private final PasswordStrengthVerificationService passwordStrengthVerificationService;\n\n    private Optional<Exception> exception = Optional.empty();\n    private Optional<PasswordStrengthRequirements> requirements = Optional.empty();\n\n    public PasswordStrengthVerificationServiceImplTest() {\n        super();\n        try {\n\n            this.passwordStrengthVerificationService = ServiceUtil\n                    .trackService(PasswordStrengthVerificationService.class, Optional.empty())\n                    .get(30, TimeUnit.SECONDS);\n\n        } catch (final Exception e) {\n            fail(\"failed to track ConfigurationService\");\n            throw new IllegalStateException(\"unreachable\");\n        }\n    }\n\n    private void whenPasswordIsValidated(final String password) {\n        try {\n            this.passwordStrengthVerificationService.checkPasswordStrength(password.toCharArray());\n        } catch (KuraException e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void whenPasswordIsValidatedAgainstIdentityName(final String identityName, final String password) {\n        try {\n            this.passwordStrengthVerificationService.checkPasswordStrength(identityName, password.toCharArray());\n        } catch (KuraException e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void whenPasswordRequirementsAreObtained() {\n        try {\n            this.requirements = Optional.of(this.passwordStrengthVerificationService.getPasswordStrengthRequirements());\n        } catch (KuraException e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void thenMinimumPasswordLengthIs(final int length) {\n        assertEquals(Optional.of(length),\n                this.requirements.map(PasswordStrengthRequirements::getPasswordMinimumLength));\n    }\n\n    private void thenDigitsAreRequired(final boolean required) {\n        assertEquals(Optional.of(required), this.requirements.map(PasswordStrengthRequirements::digitsRequired));\n    }\n\n    private void thenSpecialCharactersAreRequired(final boolean required) {\n        assertEquals(Optional.of(required),\n                this.requirements.map(PasswordStrengthRequirements::specialCharactersRequired));\n    }\n\n    private void thenBothCasesAreRequired(final boolean required) {\n        assertEquals(Optional.of(required), this.requirements.map(PasswordStrengthRequirements::bothCasesRequired));\n    }\n\n    private void thenNoExceptionIsThrown() {\n        assertEquals(Optional.empty(), this.exception);\n    }\n\n    private void thenExceptionIsThrown(final Class<? extends Exception> claszz) {\n        assertEquals(Optional.of(claszz), this.exception.map(Object::getClass));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.identity.test/src/main/java/org/eclipse/kura/core/identity/test/TemporaryIdentityServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.core.identity.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.time.Duration;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.PasswordConfiguration;\nimport org.eclipse.kura.identity.Permission;\nimport org.junit.After;\nimport org.junit.Test;\n\n/**\n * Feature: Manage temporary identities.\n */\npublic class TemporaryIdentityServiceTest extends IdentityServiceTestBase {\n\n    private final IdentityService identityService;\n\n    private Optional<Exception> exception = Optional.empty();\n    private Optional<Object> result = Optional.empty();\n\n    private String identityName;\n    private String password;\n    private Set<String> permissions;\n    private final Set<String> createdPermissions = new HashSet<>();\n    private final Set<String> createdIdentities = new HashSet<>();\n\n    public TemporaryIdentityServiceTest() {\n        super();\n        try {\n            this.identityService = ServiceUtil.trackService(IdentityService.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n        } catch (Exception e) {\n            fail(\"failed to setup test environment\");\n            throw new IllegalStateException(\"unreachable\");\n        }\n    }\n\n    @After\n    public void cleanup() {\n        for (final String identity : this.createdIdentities) {\n            try {\n                this.identityService.deleteIdentity(identity);\n            } catch (Exception e) {\n                // no need\n            }\n        }\n        this.createdIdentities.clear();\n\n        for (final String permission : this.createdPermissions) {\n            try {\n                this.identityService.deletePermission(new Permission(permission));\n            } catch (Exception e) {\n                // no need\n            }\n        }\n        this.createdPermissions.clear();\n    }\n\n    @Test\n    public void shouldCreateTemporaryIdentity() {\n        givenIdentityName(\"container_test\");\n        givenPermissions(\"rest.asset.read\", \"rest.configuration.write\");\n        givenExistingPermissions(\"rest.asset.read\", \"rest.configuration.write\");\n\n        whenTemporaryIdentityIsCreated();\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldCheckTemporaryPermission() {\n        givenIdentityName(\"container_test\");\n        givenPermissions(\"rest.asset.read\");\n        givenExistingPermissions(\"rest.asset.read\");\n        givenExistingTemporaryIdentity();\n\n        whenPermissionIsChecked(\"rest.asset.read\");\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldFailToCheckNonAssignedPermission() {\n        givenIdentityName(\"container_test\");\n        givenPermissions(\"rest.asset.read\");\n        givenExistingPermissions(\"rest.asset.read\", \"rest.configuration.write\");\n        givenExistingTemporaryIdentity();\n\n        whenPermissionIsChecked(\"rest.configuration.write\");\n\n        thenSecurityExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldDeleteTemporaryIdentity() {\n        givenIdentityName(\"container_test\");\n        givenPermissions(\"rest.asset.read\");\n        givenExistingPermissions(\"rest.asset.read\");\n        givenExistingTemporaryIdentity();\n\n        whenTemporaryIdentityIsDeleted();\n\n        thenNoExceptionIsThrown();\n        thenTemporaryIdentityServiceReportsDeleted(true);\n    }\n\n    @Test\n    public void shouldReturnFalseWhenDeletingNonExistentTemporaryIdentity() {\n        whenTemporaryIdentityIsDeleted(\"invalid-token\");\n\n        thenNoExceptionIsThrown();\n        thenTemporaryIdentityServiceReportsDeleted(false);\n    }\n\n    @Test\n    public void shouldDeleteRegularAndTemporaryIdentityWithUnifiedDelete() {\n        givenIdentityName(\"regular_identity\");\n        givenExistingIdentity();\n\n        whenIdentityIsDeleted();\n\n        thenNoExceptionIsThrown();\n        thenTemporaryIdentityServiceReportsDeleted(true);\n\n        givenIdentityName(\"temporary_identity\");\n        givenPermissions(\"rest.asset.read\");\n        givenExistingPermissions(\"rest.asset.read\");\n        givenExistingTemporaryIdentity();\n\n        whenIdentityIsDeleted();\n\n        thenNoExceptionIsThrown();\n        thenTemporaryIdentityServiceReportsDeleted(true);\n    }\n\n    @Test\n    public void shouldFailToCreateTemporaryIdentityWithNonexistentPermission() {\n        givenIdentityName(\"container_test\");\n        givenPermissions(\"nonexistent.permission\");\n\n        whenTemporaryIdentityIsCreated();\n\n        thenExceptionIsThrown(KuraException.class);\n    }\n\n    @Test\n    public void shouldAuthenticateWithPasswordForTemporaryIdentity() {\n        givenIdentityName(\"container_test_password\");\n        givenPermissions(\"rest.asset.read\");\n        givenExistingPermissions(\"rest.asset.read\");\n        givenPassword(\"SecurePassword123!\");\n        givenExistingTemporaryIdentityWithPassword();\n\n        whenPasswordIsChecked(\"SecurePassword123!\");\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldFailAuthenticationWithWrongPassword() {\n        givenIdentityName(\"container_test_password\");\n        givenPermissions(\"rest.asset.read\");\n        givenExistingPermissions(\"rest.asset.read\");\n        givenPassword(\"SecurePassword123!\");\n        givenExistingTemporaryIdentityWithPassword();\n\n        whenPasswordIsChecked(\"WrongPassword123!\");\n\n        thenSecurityExceptionIsThrown();\n    }\n\n    // Given methods\n    private void givenIdentityName(final String name) {\n        this.identityName = name;\n    }\n\n    private void givenPermissions(final String... permissionNames) {\n        this.permissions = new HashSet<>(Set.of(permissionNames));\n    }\n\n    private void givenExistingPermissions(final String... permissionNames) {\n        for (String permissionName : permissionNames) {\n            try {\n                this.identityService.createPermission(new Permission(permissionName));\n                this.createdPermissions.add(permissionName);\n            } catch (Exception e) {\n                fail(\"failed to create permission\");\n            }\n        }\n    }\n\n    private void givenExistingIdentity() {\n        try {\n            this.identityService.createIdentity(this.identityName);\n            this.createdIdentities.add(this.identityName);\n        } catch (Exception e) {\n            fail(\"Failed to create identity for test setup\");\n        }\n    }\n\n    private void givenExistingTemporaryIdentity() {\n        try {\n            final AssignedPermissions assignedPermissions = new AssignedPermissions(\n                    this.permissions.stream().map(Permission::new).collect(Collectors.toSet()));\n            final IdentityConfiguration identityConfiguration = new IdentityConfiguration(this.identityName,\n                    List.of(assignedPermissions));\n\n            this.identityService.createTemporaryIdentity(this.identityName, Duration.ofHours(1));\n            this.identityService.updateIdentityConfiguration(identityConfiguration);\n            this.createdIdentities.add(this.identityName);\n        } catch (KuraException e) {\n            fail(\"Failed to create temporary identity for test setup\");\n        }\n    }\n\n    private void givenPassword(final String pwd) {\n        this.password = pwd;\n    }\n\n    private void givenExistingTemporaryIdentityWithPassword() {\n        try {\n            final AssignedPermissions assignedPermissions = new AssignedPermissions(\n                    this.permissions.stream().map(Permission::new).collect(Collectors.toSet()));\n            final PasswordConfiguration passwordConfiguration = new PasswordConfiguration(\n                    false, true, Optional.of(this.password.toCharArray()), Optional.empty());\n            final IdentityConfiguration identityConfiguration = new IdentityConfiguration(this.identityName,\n                    List.of(assignedPermissions, passwordConfiguration));\n\n            this.identityService.createTemporaryIdentity(this.identityName, Duration.ofHours(1));\n            this.identityService.updateIdentityConfiguration(identityConfiguration);\n            this.createdIdentities.add(this.identityName);\n        } catch (KuraException e) {\n            fail(\"Failed to create temporary identity for test setup: \" + e.getMessage());\n        }\n    }\n\n    // When methods\n    private void whenTemporaryIdentityIsCreated() {\n        call(() -> {\n            final AssignedPermissions assignedPermissions = new AssignedPermissions(\n                    this.permissions.stream().map(Permission::new).collect(Collectors.toSet()));\n            final IdentityConfiguration identityConfiguration = new IdentityConfiguration(this.identityName,\n                    List.of(assignedPermissions));\n\n            this.identityService.createTemporaryIdentity(this.identityName, Duration.ofHours(1));\n            this.identityService.updateIdentityConfiguration(identityConfiguration);\n            this.createdIdentities.add(this.identityName);\n            return null;\n        });\n    }\n\n    private void whenTemporaryIdentityIsDeleted() {\n        call(() -> this.identityService.deleteIdentity(this.identityName));\n    }\n\n    private void whenTemporaryIdentityIsDeleted(final String token) {\n        call(() -> this.identityService.deleteIdentity(token));\n    }\n\n    private void whenIdentityIsDeleted() {\n        call(() -> this.identityService.deleteIdentity(this.identityName));\n    }\n\n    private void whenPermissionIsChecked(final String permissionName) {\n        callVoid(() -> {\n            this.identityService.checkPermission(this.identityName, new Permission(permissionName));\n            return null;\n        });\n    }\n\n    private void whenPasswordIsChecked(final String pwd) {\n        callVoid(() -> {\n            this.identityService.checkPassword(this.identityName, pwd.toCharArray());\n            return null;\n        });\n    }\n\n    // Then methods\n    private void thenNoExceptionIsThrown() {\n        assertEquals(Optional.empty(), this.exception);\n    }\n\n    private void thenExceptionIsThrown(final Class<? extends Exception> clazz) {\n        assertEquals(Optional.of(clazz), this.exception.map(Object::getClass));\n    }\n\n    private void thenTemporaryIdentityServiceReportsDeleted(final boolean deleted) {\n        assertEquals(Optional.of(deleted), this.result);\n    }\n\n    private void thenSecurityExceptionIsThrown() {\n        assertEquals(Optional.of(KuraException.class), this.exception.map(Object::getClass));\n        final KuraException ex = (KuraException) this.exception.get();\n        assertEquals(KuraErrorCode.SECURITY_EXCEPTION, ex.getCode());\n    }\n\n    private void call(final Callable<?> callable) {\n        try {\n            this.exception = Optional.empty();\n            this.result = Optional.ofNullable(callable.call());\n        } catch (Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void callVoid(final Callable<Void> callable) {\n        try {\n            this.exception = Optional.empty();\n            this.result = Optional.empty();\n            callable.call();\n        } catch (Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.inventory.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.inventory.test\nBundle-SymbolicName: org.eclipse.kura.core.inventory.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.core.inventory\nImport-Package: org.eclipse.kura;version=\"[1.2,2.0)\",\n org.eclipse.kura.container.orchestration;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.linux.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.data;version=\"1.1.2\",\n org.eclipse.kura.internal.xml.marshaller.unmarshaller;version=\"1.0.0\",\n org.eclipse.kura.system;version=\"[1.1,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.7\",\n org.osgi.service.cm;version=\"1.4\",\n org.osgi.service.component;version=\"1.2\"\nBundle-ActivationPolicy: lazy\nRequire-Bundle: org.eclipse.kura.json.marshaller.unmarshaller.provider;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.inventory.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.inventory.test/build.properties",
    "content": "#\n# Copyright (c) 2021 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.inventory.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.core.inventory.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.inventory.test/src/test/java/org/eclipse/kura/core/inventory/InventoryHandlerV1Test.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.inventory;\n\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.doReturn;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.when;\n\nimport java.math.BigInteger;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.NoSuchProviderException;\nimport java.security.Principal;\nimport java.security.PublicKey;\nimport java.security.SignatureException;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateExpiredException;\nimport java.security.cert.CertificateNotYetValidException;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.KuraProcessExecutionErrorException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerContext;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.ContainerOrchestrationService;\nimport org.eclipse.kura.container.orchestration.ImageConfiguration;\nimport org.eclipse.kura.container.orchestration.ImageInstanceDescriptor;\nimport org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;\nimport org.eclipse.kura.core.inventory.resources.ContainerImage;\nimport org.eclipse.kura.core.inventory.resources.ContainerImages;\nimport org.eclipse.kura.core.inventory.resources.DockerContainer;\nimport org.eclipse.kura.core.inventory.resources.DockerContainers;\nimport org.eclipse.kura.core.inventory.resources.SystemBundle;\nimport org.eclipse.kura.core.inventory.resources.SystemBundles;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemResourcesInfo;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.JsonMarshallUnmarshallImpl;\nimport org.eclipse.kura.internal.xml.marshaller.unmarshaller.XmlMarshallUnmarshallImpl;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.message.KuraRequestPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mockito;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.BundleException;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.framework.Version;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.deploymentadmin.BundleInfo;\nimport org.osgi.service.deploymentadmin.DeploymentAdmin;\nimport org.osgi.service.deploymentadmin.DeploymentPackage;\n\npublic class InventoryHandlerV1Test {\n\n    public static final String RESOURCE_DEPLOYMENT_PACKAGES = \"deploymentPackages\";\n    public static final String RESOURCE_BUNDLES = \"bundles\";\n    public static final String RESOURCE_SYSTEM_PACKAGES = \"systemPackages\";\n    public static final String RESOURCE_DOCKER_CONTAINERS = \"containers\";\n    public static final String RESOURCE_CONTAINER_IMAGES = \"images\";\n    public static final String INVENTORY = \"inventory\";\n    private static final String START = \"_start\";\n    private static final String STOP = \"_stop\";\n    private static final String DELETE = \"_delete\";\n\n    private static final List<String> START_CONTAINER = Arrays.asList(RESOURCE_DOCKER_CONTAINERS, START);\n    private static final List<String> STOP_CONTAINER = Arrays.asList(RESOURCE_DOCKER_CONTAINERS, STOP);\n\n    private static final List<String> DELETE_IMAGE = Arrays.asList(RESOURCE_CONTAINER_IMAGES, DELETE);\n\n    private static String TEST_JSON = \"testJson\";\n    private static String TEST_XML = \"testXML\";\n\n    private static final String REGISTRY_URL = \"https://test\";\n    private static final String REGISTRY_USERNAME = \"test\";\n    private static final String REGISTRY_PASSWORD = \"test1\";\n\n    private ContainerInstanceDescriptor dockerContainer1;\n    private ContainerInstanceDescriptor dockerContainer2;\n\n    private ImageConfiguration containerImage1;\n    private ImageInstanceDescriptor containerInstanceImage1;\n    private ImageConfiguration containerImage2;\n    private ImageInstanceDescriptor containerInstanceImage2;\n\n    private ContainerOrchestrationService mockContainerOrchestrationService;\n\n    private DockerContainer dockerContainerObject;\n    private DockerContainers dockerContainersObject;\n\n    private ContainerImage containerImageObject;\n    private ContainerImages containerImagesObject;\n\n    @Test(expected = KuraException.class)\n    public void testDoGetNoResources() throws KuraException, NoSuchFieldException {\n        InventoryHandlerV1 handler = new InventoryHandlerV1();\n\n        List<String> resourcesList = Collections.emptyList();\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n        KuraRequestPayload reqPayload = new KuraRequestPayload();\n\n        KuraMessage message = new KuraMessage(reqPayload, reqResources);\n\n        handler.doGet(null, message);\n    }\n\n    @Test(expected = KuraException.class)\n    public void testDoGetOtherwise() throws KuraException, NoSuchFieldException {\n        InventoryHandlerV1 handler = new InventoryHandlerV1();\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"test\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload reqPayload = new KuraRequestPayload();\n\n        KuraMessage message = new KuraMessage(reqPayload, reqResources);\n\n        handler.doGet(null, message);\n    }\n\n    @Test\n    public void testDoGetPackagesEmptyList() throws KuraException, NoSuchFieldException {\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemDeploymentPackages packages = (SystemDeploymentPackages) object;\n                SystemDeploymentPackage[] packagesArray = packages.getDeploymentPackages();\n\n                assertEquals(0, packagesArray.length);\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"deploymentPackages\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        DeploymentAdmin deploymentAdmin = mock(DeploymentAdmin.class);\n        DeploymentPackage[] deployedPackages = new DeploymentPackage[0];\n\n        TestUtil.setFieldValue(inventory, \"deploymentAdmin\", deploymentAdmin);\n        when(deploymentAdmin.listDeploymentPackages()).thenReturn(deployedPackages);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetPackagesOneElementListNoBundleInfos() throws KuraException, NoSuchFieldException {\n        DeploymentAdmin deploymentAdmin = mock(DeploymentAdmin.class);\n        DeploymentPackage[] deployedPackages = new DeploymentPackage[1];\n        DeploymentPackage dp = mock(DeploymentPackage.class);\n        deployedPackages[0] = dp;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemDeploymentPackages packages = (SystemDeploymentPackages) object;\n                SystemDeploymentPackage[] packagesArray = packages.getDeploymentPackages();\n\n                assertEquals(1, packagesArray.length);\n                assertEquals(dp.getName(), packagesArray[0].getName());\n                assertEquals(dp.getVersion().toString(), packagesArray[0].getVersion());\n\n                assertEquals(0, packagesArray[0].getBundleInfos().length);\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"deploymentPackages\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        TestUtil.setFieldValue(inventory, \"deploymentAdmin\", deploymentAdmin);\n\n        when(deploymentAdmin.listDeploymentPackages()).thenReturn(deployedPackages);\n        when(dp.getName()).thenReturn(\"heater\");\n        when(dp.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(dp.getBundleInfos()).thenReturn(new BundleInfo[0]);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetPackagesOneElementListNotSigned() throws KuraException, NoSuchFieldException {\n        DeploymentAdmin deploymentAdmin = mock(DeploymentAdmin.class);\n        DeploymentPackage[] deployedPackages = new DeploymentPackage[1];\n        DeploymentPackage dp = mock(DeploymentPackage.class);\n        deployedPackages[0] = dp;\n\n        BundleInfo[] bundleInfos = new BundleInfo[1];\n        BundleInfo bundleInfo = mock(BundleInfo.class);\n        bundleInfos[0] = bundleInfo;\n\n        Bundle[] bundles = new Bundle[1];\n        Bundle bundle = mock(Bundle.class);\n        bundles[0] = bundle;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemDeploymentPackages packages = (SystemDeploymentPackages) object;\n                SystemDeploymentPackage[] packagesArray = packages.getDeploymentPackages();\n\n                assertEquals(1, packagesArray.length);\n                assertEquals(dp.getName(), packagesArray[0].getName());\n                assertEquals(dp.getVersion().toString(), packagesArray[0].getVersion());\n                assertEquals(false, packagesArray[0].isSigned());\n\n                SystemBundle[] bis = packagesArray[0].getBundleInfos();\n                assertEquals(1, bis.length);\n                assertEquals(bundleInfo.getSymbolicName(), bis[0].getName());\n                assertEquals(bundleInfo.getVersion().toString(), bis[0].getVersion());\n                assertEquals(false, bis[0].isSigned());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"deploymentPackages\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        TestUtil.setFieldValue(inventory, \"deploymentAdmin\", deploymentAdmin);\n\n        when(deploymentAdmin.listDeploymentPackages()).thenReturn(deployedPackages);\n        when(dp.getName()).thenReturn(\"heater\");\n        when(dp.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(dp.getBundleInfos()).thenReturn(bundleInfos);\n        when(bundleInfo.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundleInfo.getVersion()).thenReturn(new Version(\"1.0.0\"));\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundle.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.UNINSTALLED);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n    \n    @Test\n    public void testDoGetPackagesTwoElementsListPartiallySigned() throws KuraException, NoSuchFieldException {\n        DeploymentAdmin deploymentAdmin = mock(DeploymentAdmin.class);\n        DeploymentPackage[] deployedPackages = new DeploymentPackage[1];\n        DeploymentPackage dp = mock(DeploymentPackage.class);\n        deployedPackages[0] = dp;\n\n        BundleInfo[] bundleInfos = new BundleInfo[2];\n        BundleInfo bundleInfo = mock(BundleInfo.class);\n        bundleInfos[0] = bundleInfo;\n        \n        BundleInfo bundleInfo2 = mock(BundleInfo.class);\n        bundleInfos[1] = bundleInfo2;\n\n        Bundle[] bundles = new Bundle[2];\n        Bundle bundle = mock(Bundle.class);\n        Bundle bundle2 = mock(Bundle.class);\n        bundles[0] = bundle;\n        bundles[1] = bundle2;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemDeploymentPackages packages = (SystemDeploymentPackages) object;\n                SystemDeploymentPackage[] packagesArray = packages.getDeploymentPackages();\n\n                assertEquals(1, packagesArray.length);\n                assertEquals(dp.getName(), packagesArray[0].getName());\n                assertEquals(dp.getVersion().toString(), packagesArray[0].getVersion());\n                assertEquals(false, packagesArray[0].isSigned());\n\n                SystemBundle[] bis = packagesArray[0].getBundleInfos();\n                assertEquals(2, bis.length);\n                assertEquals(bundleInfo.getSymbolicName(), bis[0].getName());\n                assertEquals(bundleInfo.getVersion().toString(), bis[0].getVersion());\n                assertEquals(false, bis[0].isSigned());\n                assertEquals(bundleInfo2.getSymbolicName(), bis[1].getName());\n                assertEquals(bundleInfo2.getVersion().toString(), bis[1].getVersion());\n                assertEquals(true, bis[1].isSigned());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"deploymentPackages\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        TestUtil.setFieldValue(inventory, \"deploymentAdmin\", deploymentAdmin);\n\n        when(deploymentAdmin.listDeploymentPackages()).thenReturn(deployedPackages);\n        when(dp.getName()).thenReturn(\"heater\");\n        when(dp.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(dp.getBundleInfos()).thenReturn(bundleInfos);\n        when(bundleInfo.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundleInfo.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundleInfo2.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater2\");\n        when(bundleInfo2.getVersion()).thenReturn(new Version(\"2.0.0\"));\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundle.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.INSTALLED);\n        \n        when(bundle2.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater2\");\n        when(bundle2.getVersion()).thenReturn(new Version(\"2.0.0\"));\n        when(bundle2.getBundleId()).thenReturn(2L);\n        when(bundle2.getState()).thenReturn(Bundle.ACTIVE);\n        Map<X509Certificate, List<X509Certificate>> signingCerts = new HashMap<>();\n        signingCerts.put(getEmptyX509Cert(), null);\n        when(bundle2.getSignerCertificates(Bundle.SIGNERS_ALL)).thenReturn(signingCerts);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetPackagesOneElementListSigned() throws KuraException, NoSuchFieldException {\n        DeploymentAdmin deploymentAdmin = mock(DeploymentAdmin.class);\n        DeploymentPackage[] deployedPackages = new DeploymentPackage[1];\n        DeploymentPackage dp = mock(DeploymentPackage.class);\n        deployedPackages[0] = dp;\n\n        BundleInfo[] bundleInfos = new BundleInfo[1];\n        BundleInfo bundleInfo = mock(BundleInfo.class);\n        bundleInfos[0] = bundleInfo;\n\n        Bundle[] bundles = new Bundle[1];\n        Bundle bundle = mock(Bundle.class);\n        bundles[0] = bundle;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemDeploymentPackages packages = (SystemDeploymentPackages) object;\n                SystemDeploymentPackage[] packagesArray = packages.getDeploymentPackages();\n\n                assertEquals(1, packagesArray.length);\n                assertEquals(dp.getName(), packagesArray[0].getName());\n                assertEquals(dp.getVersion().toString(), packagesArray[0].getVersion());\n                assertEquals(true, packagesArray[0].isSigned());\n\n                SystemBundle[] bis = packagesArray[0].getBundleInfos();\n                assertEquals(1, bis.length);\n                assertEquals(bundleInfo.getSymbolicName(), bis[0].getName());\n                assertEquals(bundleInfo.getVersion().toString(), bis[0].getVersion());\n                assertEquals(true, bis[0].isSigned());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"deploymentPackages\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        TestUtil.setFieldValue(inventory, \"deploymentAdmin\", deploymentAdmin);\n\n        when(deploymentAdmin.listDeploymentPackages()).thenReturn(deployedPackages);\n        when(dp.getName()).thenReturn(\"heater\");\n        when(dp.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(dp.getBundleInfos()).thenReturn(bundleInfos);\n        when(bundleInfo.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundleInfo.getVersion()).thenReturn(new Version(\"1.0.0\"));\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundle.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.UNINSTALLED);\n        \n        Map<X509Certificate, List<X509Certificate>> signingCerts = new HashMap<>();\n        signingCerts.put(getEmptyX509Cert(), null);\n        when(bundle.getSignerCertificates(Bundle.SIGNERS_ALL)).thenReturn(signingCerts);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetBundlesNoBundleInstalled() throws KuraException, NoSuchFieldException {\n        String xml = TEST_JSON;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemBundles bundles = (SystemBundles) object;\n                SystemBundle[] bundleArray = bundles.getBundles();\n                assertEquals(0, bundleArray.length);\n\n                return xml;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"bundles\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(new Bundle[0]);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(xml, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetBundlesBundleUninstalled() throws KuraException, NoSuchFieldException {\n        Bundle[] bundles = new Bundle[1];\n        Bundle bundle = mock(Bundle.class);\n        bundles[0] = bundle;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemBundles bundles = (SystemBundles) object;\n                SystemBundle[] bundleArray = bundles.getBundles();\n                assertEquals(1, bundleArray.length);\n\n                assertEquals(bundle.getSymbolicName(), bundleArray[0].getName());\n                assertEquals(bundle.getVersion().toString(), bundleArray[0].getVersion());\n                assertEquals(bundle.getBundleId(), bundleArray[0].getId());\n                assertEquals(\"UNINSTALLED\", bundleArray[0].getState());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"bundles\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundle.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.UNINSTALLED);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetBundlesBundleInstalled() throws KuraException, NoSuchFieldException {\n        Bundle[] bundles = new Bundle[1];\n        Bundle bundle = mock(Bundle.class);\n        bundles[0] = bundle;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemBundles bundles = (SystemBundles) object;\n                SystemBundle[] bundleArray = bundles.getBundles();\n                assertEquals(1, bundleArray.length);\n\n                assertEquals(bundle.getSymbolicName(), bundleArray[0].getName());\n                assertEquals(bundle.getVersion().toString(), bundleArray[0].getVersion());\n                assertEquals(bundle.getBundleId(), bundleArray[0].getId());\n                assertEquals(\"INSTALLED\", bundleArray[0].getState());\n                assertEquals(true, bundleArray[0].isSigned());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"bundles\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundle.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.INSTALLED);\n        \n        Map<X509Certificate, List<X509Certificate>> signingCerts = new HashMap<>();\n        signingCerts.put(getEmptyX509Cert(), null);\n        when(bundle.getSignerCertificates(Bundle.SIGNERS_ALL)).thenReturn(signingCerts);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetBundlesBundleResolved() throws KuraException, NoSuchFieldException {\n        Bundle[] bundles = new Bundle[1];\n        Bundle bundle = mock(Bundle.class);\n        bundles[0] = bundle;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemBundles bundles = (SystemBundles) object;\n                SystemBundle[] bundleArray = bundles.getBundles();\n                assertEquals(1, bundleArray.length);\n\n                assertEquals(bundle.getSymbolicName(), bundleArray[0].getName());\n                assertEquals(bundle.getVersion().toString(), bundleArray[0].getVersion());\n                assertEquals(bundle.getBundleId(), bundleArray[0].getId());\n                assertEquals(\"RESOLVED\", bundleArray[0].getState());\n                assertEquals(false, bundleArray[0].isSigned());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"bundles\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundle.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.RESOLVED);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetBundlesBundleStarting() throws KuraException, NoSuchFieldException {\n        Bundle[] bundles = new Bundle[1];\n        Bundle bundle = mock(Bundle.class);\n        bundles[0] = bundle;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemBundles bundles = (SystemBundles) object;\n                SystemBundle[] bundleArray = bundles.getBundles();\n                assertEquals(1, bundleArray.length);\n\n                assertEquals(bundle.getSymbolicName(), bundleArray[0].getName());\n                assertEquals(bundle.getVersion().toString(), bundleArray[0].getVersion());\n                assertEquals(bundle.getBundleId(), bundleArray[0].getId());\n                assertEquals(\"STARTING\", bundleArray[0].getState());\n                assertEquals(false, bundleArray[0].isSigned());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"bundles\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundle.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.STARTING);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetBundlesBundleStopping() throws KuraException, NoSuchFieldException {\n        Bundle[] bundles = new Bundle[1];\n        Bundle bundle = mock(Bundle.class);\n        bundles[0] = bundle;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemBundles bundles = (SystemBundles) object;\n                SystemBundle[] bundleArray = bundles.getBundles();\n                assertEquals(1, bundleArray.length);\n\n                assertEquals(bundle.getSymbolicName(), bundleArray[0].getName());\n                assertEquals(bundle.getVersion().toString(), bundleArray[0].getVersion());\n                assertEquals(bundle.getBundleId(), bundleArray[0].getId());\n                assertEquals(\"STOPPING\", bundleArray[0].getState());\n                assertEquals(false, bundleArray[0].isSigned());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"bundles\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundle.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.STOPPING);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void testDoGetBundlesBundleActive() throws KuraException, NoSuchFieldException {\n        Bundle[] bundles = new Bundle[1];\n        Bundle bundle = mock(Bundle.class);\n        bundles[0] = bundle;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemBundles bundles = (SystemBundles) object;\n                SystemBundle[] bundleArray = bundles.getBundles();\n                assertEquals(1, bundleArray.length);\n\n                assertEquals(bundle.getSymbolicName(), bundleArray[0].getName());\n                assertEquals(bundle.getVersion().toString(), bundleArray[0].getVersion());\n                assertEquals(bundle.getBundleId(), bundleArray[0].getId());\n                assertEquals(\"ACTIVE\", bundleArray[0].getState());\n                assertEquals(true, bundleArray[0].isSigned());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"bundles\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"org.eclipse.kura.demo.heater\");\n        when(bundle.getVersion()).thenReturn(new Version(\"1.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.ACTIVE);\n        \n        Map<X509Certificate, List<X509Certificate>> signingCerts = new HashMap<>();\n        signingCerts.put(getEmptyX509Cert(), null);\n        when(bundle.getSignerCertificates(Bundle.SIGNERS_ALL)).thenReturn(signingCerts);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void doGetSystemPackagesEmpty() throws KuraException {\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemPackages packages = (SystemPackages) object;\n                List<SystemPackage> packageList = packages.getSystemPackages();\n                assertTrue(packageList.isEmpty());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"systemPackages\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        SystemService ssMock = mock(SystemService.class);\n        inventory.setSystemService(ssMock);\n\n        List<SystemResourceInfo> packages = new ArrayList<>();\n        when(ssMock.getSystemPackages()).thenReturn(packages);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void doGetSystemPackagesFailed() throws KuraException {\n        InventoryHandlerV1 inventory = new InventoryHandlerV1();\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"systemPackages\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        SystemService ssMock = mock(SystemService.class);\n        inventory.setSystemService(ssMock);\n        when(ssMock.getSystemPackages())\n                .thenThrow(new KuraProcessExecutionErrorException(\"Failed to retrieve system packages.\"));\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_ERROR, resPayload.getResponseCode());\n    }\n\n    @Test\n    public void doGetSystemPackages() throws KuraException {\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemPackages packages = (SystemPackages) object;\n                List<SystemPackage> packageList = packages.getSystemPackages();\n                assertEquals(1, packageList.size());\n                assertEquals(\"package1\", packageList.get(0).getName());\n                assertEquals(\"1.0.0\", packageList.get(0).getVersion());\n                assertEquals(\"DEB\", packageList.get(0).getTypeString());\n\n                return TEST_JSON;\n            }\n        };\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"systemPackages\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        SystemService ssMock = mock(SystemService.class);\n        inventory.setSystemService(ssMock);\n        List<SystemResourceInfo> packages = new ArrayList<>();\n        packages.add(new SystemResourceInfo(\"package1\", \"1.0.0\", SystemResourceType.DEB));\n        when(ssMock.getSystemPackages()).thenReturn(packages);\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test\n    public void doGetInventory() throws KuraException, NoSuchFieldException {\n        givenTwoDockerContainers();\n\n        this.mockContainerOrchestrationService = mock(ContainerOrchestrationService.class, Mockito.RETURNS_DEEP_STUBS);\n\n        when(this.mockContainerOrchestrationService.listContainerDescriptors())\n                .thenReturn(Arrays.asList(this.dockerContainer1, this.dockerContainer2));\n\n        when(this.mockContainerOrchestrationService.listImageInstanceDescriptors())\n                .thenReturn(Arrays.asList(this.containerInstanceImage1, this.containerInstanceImage2));\n\n        Bundle[] bundles = new Bundle[1];\n        Bundle bundle = mock(Bundle.class);\n        bundles[0] = bundle;\n\n        DeploymentAdmin deploymentAdmin = mock(DeploymentAdmin.class);\n        DeploymentPackage[] deployedPackages = new DeploymentPackage[1];\n        DeploymentPackage dp = mock(DeploymentPackage.class);\n        deployedPackages[0] = dp;\n\n        BundleInfo[] bundleInfos = new BundleInfo[1];\n        BundleInfo bundleInfo = mock(BundleInfo.class);\n        bundleInfos[0] = bundleInfo;\n\n        InventoryHandlerV1 inventory = new InventoryHandlerV1() {\n\n            @Override\n            protected String marshal(Object object) {\n                SystemResourcesInfo resources = (SystemResourcesInfo) object;\n                List<SystemResourceInfo> resourceList = resources.getSystemResources();\n                assertEquals(7, resourceList.size());\n                assertEquals(\"bundle1\", resourceList.get(0).getName());\n                assertEquals(\"2.0.0\", resourceList.get(0).getVersion());\n                assertEquals(\"BUNDLE\", resourceList.get(0).getTypeString());\n                assertEquals(\"dockerContainer1\", resourceList.get(1).getName());\n                assertEquals(\"nginx:latest\", resourceList.get(1).getVersion());\n                assertEquals(\"DOCKER\", resourceList.get(1).getTypeString());\n                assertEquals(\"dockerContainer2\", resourceList.get(2).getName());\n                assertEquals(\"nginx:latest\", resourceList.get(2).getVersion());\n                assertEquals(\"DOCKER\", resourceList.get(2).getTypeString());\n                assertEquals(\"dp1\", resourceList.get(3).getName());\n                assertEquals(\"3.0.0\", resourceList.get(3).getVersion());\n                assertEquals(\"DP\", resourceList.get(3).getTypeString());\n                assertEquals(\"nginx\", resourceList.get(4).getName());\n                assertEquals(\"latest\", resourceList.get(4).getVersion());\n                assertEquals(\"CONTAINER_IMAGE\", resourceList.get(4).getTypeString());\n                assertEquals(\"nginx\", resourceList.get(5).getName());\n                assertEquals(\"alpine\", resourceList.get(5).getVersion());\n                assertEquals(\"CONTAINER_IMAGE\", resourceList.get(5).getTypeString());\n                assertEquals(\"package1\", resourceList.get(6).getName());\n                assertEquals(\"1.0.0\", resourceList.get(6).getVersion());\n                assertEquals(\"DEB\", resourceList.get(6).getTypeString());\n\n                return TEST_JSON;\n            }\n        };\n\n        inventory.setContainerOrchestrationService(this.mockContainerOrchestrationService);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"inventory\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        SystemService ssMock = mock(SystemService.class);\n        inventory.setSystemService(ssMock);\n        List<SystemResourceInfo> packages = new ArrayList<>();\n        packages.add(new SystemResourceInfo(\"package1\", \"1.0.0\", SystemResourceType.DEB));\n        when(ssMock.getSystemPackages()).thenReturn(packages);\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(inventory, \"bundleContext\", context);\n        when(context.getBundles()).thenReturn(bundles);\n        when(bundle.getSymbolicName()).thenReturn(\"bundle1\");\n        when(bundle.getVersion()).thenReturn(new Version(\"2.0.0\"));\n        when(bundle.getBundleId()).thenReturn(1L);\n        when(bundle.getState()).thenReturn(Bundle.ACTIVE);\n\n        TestUtil.setFieldValue(inventory, \"deploymentAdmin\", deploymentAdmin);\n\n        when(deploymentAdmin.listDeploymentPackages()).thenReturn(deployedPackages);\n        when(dp.getName()).thenReturn(\"dp1\");\n        when(dp.getVersion()).thenReturn(new Version(\"3.0.0\"));\n        when(dp.getBundleInfos()).thenReturn(bundleInfos);\n        when(bundleInfo.getSymbolicName()).thenReturn(\"bundle2\");\n        when(bundleInfo.getVersion()).thenReturn(new Version(\"4.0.0\"));\n\n        KuraMessage resMessage = inventory.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertEquals(TEST_JSON, new String(resPayload.getBody(), Charset.forName(\"UTF-8\")));\n    }\n\n    @Test(expected = KuraException.class)\n    public void testDoDel() throws Exception {\n        InventoryHandlerV1 handler = new InventoryHandlerV1();\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"test\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload reqPayload = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(reqPayload, reqResources);\n\n        handler.doDel(null, message);\n    }\n\n    @Test(expected = KuraException.class)\n    public void testDoExec() throws Exception {\n        InventoryHandlerV1 handler = new InventoryHandlerV1();\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"test\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload reqPayload = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(reqPayload, reqResources);\n\n        handler.doExec(null, message);\n    }\n\n    @Test\n    public void testBundleStartStopNotFound() throws BundleException {\n        final List<Bundle> bundles = Arrays.asList(mockBundle(\"foo\", \"1.0\"), mockBundle(\"bar\", \"2.0\"));\n\n        InventoryHandlerV1 handler = new InventoryHandlerV1();\n        handler.activate(mockComponentContext(bundles));\n\n        try {\n            handler.doExec(mock(RequestHandlerContext.class),\n                    requestMessage(Arrays.asList(\"bundles\", \"_start\"), \"{\\\"name\\\":\\\"baz\\\"}\"));\n            fail(\"should have failed\");\n        } catch (final KuraException e) {\n            assertEquals(KuraErrorCode.NOT_FOUND, e.getCode());\n        }\n\n        try {\n            handler.doExec(mock(RequestHandlerContext.class),\n                    requestMessage(Arrays.asList(\"bundles\", \"_stop\"), \"{\\\"name\\\":\\\"baz\\\"}\"));\n            fail(\"should have failed\");\n        } catch (final KuraException e) {\n            assertEquals(KuraErrorCode.NOT_FOUND, e.getCode());\n        }\n\n        try {\n            handler.doExec(mock(RequestHandlerContext.class),\n                    requestMessage(Arrays.asList(\"bundles\", \"_start\"), \"{\\\"name\\\":\\\"baz\\\",\\\"version\\\":\\\"1.0\\\"}\"));\n            fail(\"should have failed\");\n        } catch (final KuraException e) {\n            assertEquals(KuraErrorCode.NOT_FOUND, e.getCode());\n        }\n\n        try {\n            handler.doExec(mock(RequestHandlerContext.class),\n                    requestMessage(Arrays.asList(\"bundles\", \"_stop\"), \"{\\\"name\\\":\\\"baz\\\",\\\"version\\\":\\\"1.0\\\"}\"));\n            fail(\"should have failed\");\n        } catch (final KuraException e) {\n            assertEquals(KuraErrorCode.NOT_FOUND, e.getCode());\n        }\n\n        try {\n            handler.doExec(mock(RequestHandlerContext.class),\n                    requestMessage(Arrays.asList(\"bundles\", \"_start\"), \"{\\\"name\\\":\\\"foo\\\",\\\"version\\\":\\\"2.0\\\"}\"));\n            fail(\"should have failed\");\n        } catch (final KuraException e) {\n            assertEquals(KuraErrorCode.NOT_FOUND, e.getCode());\n        }\n\n        try {\n            handler.doExec(mock(RequestHandlerContext.class),\n                    requestMessage(Arrays.asList(\"bundles\", \"_stop\"), \"{\\\"name\\\":\\\"bar\\\",\\\"version\\\":\\\"3.0\\\"}\"));\n            fail(\"should have failed\");\n        } catch (final KuraException e) {\n            assertEquals(KuraErrorCode.NOT_FOUND, e.getCode());\n        }\n\n        for (final Bundle bundle : bundles) {\n            Mockito.verify(bundle, times(0)).start();\n            Mockito.verify(bundle, times(0)).stop();\n        }\n    }\n\n    @Test\n    public void testStartBundleWithVersion() throws BundleException, KuraException {\n        final Bundle foo = mockBundle(\"foo\", \"1.0\");\n        final Bundle bar = mockBundle(\"bar\", \"2.0\");\n\n        InventoryHandlerV1 handler = new InventoryHandlerV1();\n        handler.activate(mockComponentContext(Arrays.asList(foo, bar)));\n\n        final KuraMessage response = handler.doExec(mock(RequestHandlerContext.class),\n                requestMessage(Arrays.asList(\"bundles\", \"_start\"), \"{\\\"name\\\":\\\"foo\\\",\\\"version\\\":\\\"1.0.0\\\"}\"));\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK,\n                ((KuraResponsePayload) response.getPayload()).getResponseCode());\n\n        Mockito.verify(foo, times(1)).start();\n        Mockito.verify(foo, times(0)).stop();\n        Mockito.verify(bar, times(0)).start();\n        Mockito.verify(bar, times(0)).stop();\n    }\n\n    @Test\n    public void testStartBundleWithoutVersion() throws BundleException, KuraException {\n        final Bundle foo = mockBundle(\"foo\", \"1.0\");\n        final Bundle bar = mockBundle(\"bar\", \"2.0\");\n\n        InventoryHandlerV1 handler = new InventoryHandlerV1();\n        handler.activate(mockComponentContext(Arrays.asList(foo, bar)));\n\n        final KuraMessage response = handler.doExec(mock(RequestHandlerContext.class),\n                requestMessage(Arrays.asList(\"bundles\", \"_start\"), \"{\\\"name\\\":\\\"foo\\\"}\"));\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK,\n                ((KuraResponsePayload) response.getPayload()).getResponseCode());\n\n        Mockito.verify(foo, times(1)).start();\n        Mockito.verify(foo, times(0)).stop();\n        Mockito.verify(bar, times(0)).start();\n        Mockito.verify(bar, times(0)).stop();\n    }\n\n    @Test\n    public void testStopBundleWithVersion() throws BundleException, KuraException {\n        final Bundle foo = mockBundle(\"foo\", \"1.0\");\n        final Bundle bar = mockBundle(\"bar\", \"2.0\");\n\n        InventoryHandlerV1 handler = new InventoryHandlerV1();\n        handler.activate(mockComponentContext(Arrays.asList(foo, bar)));\n\n        final KuraMessage response = handler.doExec(mock(RequestHandlerContext.class),\n                requestMessage(Arrays.asList(\"bundles\", \"_stop\"), \"{\\\"name\\\":\\\"foo\\\",\\\"version\\\":\\\"1.0.0\\\"}\"));\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK,\n                ((KuraResponsePayload) response.getPayload()).getResponseCode());\n\n        Mockito.verify(foo, times(0)).start();\n        Mockito.verify(foo, times(1)).stop();\n        Mockito.verify(bar, times(0)).start();\n        Mockito.verify(bar, times(0)).stop();\n    }\n\n    @Test\n    public void testStopBundleWithoutVersion() throws BundleException, KuraException {\n        final Bundle foo = mockBundle(\"foo\", \"1.0\");\n        final Bundle bar = mockBundle(\"bar\", \"2.0\");\n\n        InventoryHandlerV1 handler = new InventoryHandlerV1();\n        handler.activate(mockComponentContext(Arrays.asList(foo, bar)));\n\n        final KuraMessage response = handler.doExec(mock(RequestHandlerContext.class),\n                requestMessage(Arrays.asList(\"bundles\", \"_stop\"), \"{\\\"name\\\":\\\"foo\\\"}\"));\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK,\n                ((KuraResponsePayload) response.getPayload()).getResponseCode());\n\n        Mockito.verify(foo, times(0)).start();\n        Mockito.verify(foo, times(1)).stop();\n        Mockito.verify(bar, times(0)).start();\n        Mockito.verify(bar, times(0)).stop();\n    }\n\n    private KuraMessage requestMessage(final List<String> resources, final String body) {\n\n        KuraRequestPayload reqPayload = new KuraRequestPayload();\n        reqPayload.setBody(body.getBytes(StandardCharsets.UTF_8));\n        KuraMessage message = new KuraMessage(reqPayload, Collections.singletonMap(ARGS_KEY.value(), resources));\n\n        return message;\n    }\n\n    // region Container Related Tests\n\n    @Test\n    public void testContainerMarshalingJSON() throws BundleException, KuraException {\n        givenTwoDockerContainers();\n        giventheFollowingContainerSetupToMarshal();\n\n        whenContainersArePassedToMarshaler();\n\n        thenCheckIfContainerMatchesJSON();\n    }\n\n    @Test\n    public void testContainerUnMarshalingJSON() throws BundleException, KuraException {\n        givenTheFollowingContainerJson();\n\n        whenAContainerJsonIsPassedToMarshaler();\n\n        thenCheckIfJsonMatchesContainer();\n    }\n\n    @Test\n    public void testContainerMarshalingXML() throws BundleException, KuraException {\n        givenTwoDockerContainers();\n        giventheFollowingContainerSetupToMarshal();\n\n        whenContainersArePassedToMarshalerXML();\n\n        thenCheckIfContainerMatchesXML();\n    }\n\n    @Test\n    public void testListContainerDoGet() throws BundleException, KuraException {\n        givenTwoDockerContainers();\n\n        whenTheFollowingJsonKuraPayloadDoGet(Arrays.asList(RESOURCE_DOCKER_CONTAINERS), \"\");\n\n        thenCheckIfContainerWereListed();\n    }\n\n    @Test\n    public void testStartContainerWithoutVersion() throws BundleException, KuraException, InterruptedException {\n        givenTwoDockerContainers();\n\n        whenTheFollowingJsonKuraPayloadDoExec(START_CONTAINER, \"{\\\"name\\\":\\\"dockerContainer1\\\"}\");\n\n        thenCheckIfContainerOneHasStarted();\n    }\n\n    @Test\n    public void testStopContainerWithoutVersion() throws BundleException, KuraException, InterruptedException {\n        givenTwoDockerContainers();\n\n        whenTheFollowingJsonKuraPayloadDoExec(STOP_CONTAINER, \"{\\\"name\\\":\\\"dockerContainer1\\\"}\");\n\n        thenCheckIfContainerOneHasStopped();\n\n    }\n\n    // endregion\n\n    // region Image Related Tests\n\n    @Test\n    public void testContainerImageMarshalingJSON() throws BundleException, KuraException {\n        givenTwoDockerContainers();\n        giventheFollowingImagesSetupToMarshal();\n\n        whenImagesArePassedToMarshaler();\n\n        thenCheckIfImageMatchesJSON();\n    }\n\n    @Test\n    public void testContainerImageUnMarshalingJSON() throws BundleException, KuraException {\n        givenTheFollowingImageJson();\n\n        whenAImageJsonIsPassedToMarshaler();\n\n        thenCheckIfJsonMatchesImage();\n    }\n\n    @Test\n    public void testContainerImageMarshalingXML() throws BundleException, KuraException {\n        givenTwoDockerContainers();\n        giventheFollowingImagesSetupToMarshal();\n\n        whenImagesArePassedToMarshalerXML();\n\n        thenCheckIfImageMatchesXML();\n    }\n\n    @Test\n    public void testListImageDoGet() throws BundleException, KuraException {\n        givenTwoDockerContainers();\n\n        whenTheFollowingJsonKuraPayloadDoGet(Arrays.asList(RESOURCE_CONTAINER_IMAGES), \"\");\n\n        thenCheckIfImagesHaveBeenListed();\n    }\n\n    @Test\n    public void testDeleteImage() throws BundleException, KuraException, InterruptedException {\n        givenTwoDockerContainers();\n\n        whenTheFollowingJsonContainerImageKuraPayloadDoExec(DELETE_IMAGE,\n                \"{\\\"name\\\":\\\"nginx\\\",\\\"version\\\":\\\"latest\\\"}\");\n        thenCheckIfImageHasDelete();\n    }\n\n    @Test\n    public void testContainerImageDataStuct() throws BundleException, KuraException, InterruptedException {\n        thenCompareOutputOfContainerImage();\n    }\n\n    // endregion\n\n    /**\n     * given\n     */\n\n    private void giventheFollowingContainerSetupToMarshal() {\n\n        this.dockerContainerObject = new DockerContainer(this.dockerContainer1);\n\n        this.dockerContainersObject = new DockerContainers(Arrays.asList(this.dockerContainerObject));\n    }\n\n    private void giventheFollowingImagesSetupToMarshal() {\n\n        this.containerImageObject = new ContainerImage(this.containerInstanceImage1);\n\n        this.containerImagesObject = new ContainerImages(Arrays.asList(this.containerImageObject));\n    }\n\n    private void givenTwoDockerContainers() {\n        this.dockerContainer1 = ContainerInstanceDescriptor.builder().setContainerName(\"dockerContainer1\")\n                .setContainerImage(\"nginx\").setContainerImageTag(\"latest\").setContainerID(\"1234\").build();\n        this.dockerContainer2 = ContainerInstanceDescriptor.builder().setContainerName(\"dockerContainer2\")\n                .setContainerImage(\"nginx\").setContainerID(\"124344\").build();\n\n        this.containerImage1 = new ImageConfiguration.ImageConfigurationBuilder().setImageName(\"nginx\")\n                .setImageTag(\"latest\").setImageDownloadTimeoutSeconds(200)\n                .setRegistryCredentials(Optional.of(new PasswordRegistryCredentials(Optional.of(REGISTRY_URL),\n                        REGISTRY_USERNAME, new Password(REGISTRY_PASSWORD))))\n                .build();\n        this.containerInstanceImage1 = new ImageInstanceDescriptor.ImageInstanceDescriptorBuilder()\n                .setImageName(this.containerImage1.getImageName()).setImageTag(this.containerImage1.getImageTag())\n                .setImageId(\"SHA256:3h278f34yhufy3h\").build();\n        this.containerImage2 = new ImageConfiguration.ImageConfigurationBuilder().setImageName(\"nginx\")\n                .setImageTag(\"alpine\").setImageDownloadTimeoutSeconds(200)\n                .setRegistryCredentials(Optional.of(new PasswordRegistryCredentials(Optional.of(REGISTRY_URL),\n                        REGISTRY_USERNAME, new Password(REGISTRY_PASSWORD))))\n                .build();\n        this.containerInstanceImage2 = new ImageInstanceDescriptor.ImageInstanceDescriptorBuilder()\n                .setImageName(this.containerImage2.getImageName()).setImageTag(this.containerImage2.getImageTag())\n                .setImageId(\"SHA256:dfiyegfyuwehf978ew4hu\").build();\n    }\n\n    private void givenTheFollowingContainerJson() {\n        TEST_JSON = \"{\\\"name\\\":\\\"test\\\",\\\"version\\\":\\\"nginx:latest\\\"}\";\n    }\n\n    private void givenTheFollowingImageJson() {\n\n        TEST_JSON = \"{\\\"name\\\":\\\"nginx\\\",\\\"version\\\":\\\"latest\\\"}\";\n    }\n\n    /**\n     * when\n     */\n    private void whenContainersArePassedToMarshaler() throws BundleException, KuraException {\n        JsonMarshallUnmarshallImpl marsh = new JsonMarshallUnmarshallImpl();\n        TEST_JSON = marsh.marshal(this.dockerContainersObject);\n    }\n\n    private void whenImagesArePassedToMarshaler() throws BundleException, KuraException {\n        JsonMarshallUnmarshallImpl marsh = new JsonMarshallUnmarshallImpl();\n        TEST_JSON = marsh.marshal(this.containerImagesObject);\n    }\n\n    private void whenContainersArePassedToMarshalerXML() throws BundleException, KuraException {\n        XmlMarshallUnmarshallImpl marsh = new XmlMarshallUnmarshallImpl();\n        TEST_XML = marsh.marshal(this.dockerContainersObject);\n    }\n\n    private void whenImagesArePassedToMarshalerXML() throws BundleException, KuraException {\n        XmlMarshallUnmarshallImpl marsh = new XmlMarshallUnmarshallImpl();\n        TEST_XML = marsh.marshal(this.containerImagesObject);\n    }\n\n    private void whenAContainerJsonIsPassedToMarshaler() throws BundleException, KuraException {\n        JsonMarshallUnmarshallImpl marsh = new JsonMarshallUnmarshallImpl();\n        this.dockerContainerObject = marsh.unmarshal(TEST_JSON, DockerContainer.class);\n    }\n\n    private void whenAImageJsonIsPassedToMarshaler() throws BundleException, KuraException {\n        JsonMarshallUnmarshallImpl marsh = new JsonMarshallUnmarshallImpl();\n        this.containerImageObject = marsh.unmarshal(TEST_JSON, ContainerImage.class);\n    }\n\n    private void whenTheFollowingJsonKuraPayloadDoExec(List<String> request, String payload)\n            throws BundleException, KuraException {\n\n        InventoryHandlerV1 handler = Mockito.spy(new InventoryHandlerV1());\n\n        this.mockContainerOrchestrationService = mock(ContainerOrchestrationService.class, Mockito.RETURNS_DEEP_STUBS);\n\n        when(this.mockContainerOrchestrationService.listContainerDescriptors())\n                .thenReturn(Arrays.asList(this.dockerContainer1, this.dockerContainer2));\n\n        KuraMessage theMessage = requestMessage(request, payload);\n\n        handler.setContainerOrchestrationService(this.mockContainerOrchestrationService);\n        handler.activate(mock(ComponentContext.class, Mockito.RETURNS_MOCKS));\n\n        // convert ContainerDescriptor to a DockerContainer\n        DockerContainer testContainer = new DockerContainer(this.dockerContainer1);\n\n        doReturn(testContainer).when(handler).unmarshal(payload, DockerContainer.class);\n\n        final KuraMessage response = handler.doExec(mock(RequestHandlerContext.class, Mockito.RETURNS_DEEP_STUBS),\n                theMessage);\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK,\n                ((KuraResponsePayload) response.getPayload()).getResponseCode());\n    }\n\n    private void whenTheFollowingJsonContainerImageKuraPayloadDoExec(List<String> request, String payload)\n            throws BundleException, KuraException {\n\n        InventoryHandlerV1 handler = Mockito.spy(new InventoryHandlerV1());\n\n        this.mockContainerOrchestrationService = mock(ContainerOrchestrationService.class, Mockito.RETURNS_DEEP_STUBS);\n\n        when(this.mockContainerOrchestrationService.listImageInstanceDescriptors())\n                .thenReturn(Arrays.asList(this.containerInstanceImage1, this.containerInstanceImage2));\n\n        KuraMessage theMessage = requestMessage(request, payload);\n\n        handler.setContainerOrchestrationService(this.mockContainerOrchestrationService);\n        handler.activate(mock(ComponentContext.class, Mockito.RETURNS_MOCKS));\n\n        // convert ContainerDescriptor to a DockerContainer\n        ContainerImage testImageInstance = new ContainerImage(this.containerInstanceImage1);\n\n        doReturn(testImageInstance).when(handler).unmarshal(payload, ContainerImage.class);\n\n        final KuraMessage response = handler.doExec(mock(RequestHandlerContext.class, Mockito.RETURNS_DEEP_STUBS),\n                theMessage);\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK,\n                ((KuraResponsePayload) response.getPayload()).getResponseCode());\n    }\n\n    private void whenTheFollowingJsonKuraPayloadDoGet(List<String> request, String payload)\n            throws BundleException, KuraException {\n\n        InventoryHandlerV1 handler = Mockito.spy(new InventoryHandlerV1());\n\n        this.mockContainerOrchestrationService = mock(ContainerOrchestrationService.class, Mockito.RETURNS_DEEP_STUBS);\n\n        when(this.mockContainerOrchestrationService.listContainerDescriptors())\n                .thenReturn(Arrays.asList(this.dockerContainer1, this.dockerContainer2));\n\n        KuraMessage theMessage = requestMessage(request, payload);\n\n        handler.setContainerOrchestrationService(this.mockContainerOrchestrationService);\n        handler.activate(mock(ComponentContext.class, Mockito.RETURNS_MOCKS));\n\n        // convert ContainerDescriptor to a DockerContainer\n        DockerContainer testContainer = new DockerContainer(this.dockerContainer1);\n\n        doReturn(testContainer).when(handler).unmarshal(payload, DockerContainer.class);\n\n        handler.doGet(null, theMessage);\n    }\n\n    /**\n     * then\n     *\n     * @throws KuraException\n     */\n\n    private void thenCheckIfContainerMatchesJSON() {\n        assertEquals(\n                \"{\\\"containers\\\":[{\\\"name\\\":\\\"dockerContainer1\\\",\\\"version\\\":\\\"nginx:latest\\\",\\\"type\\\":\\\"DOCKER\\\",\\\"state\\\":\\\"uninstalled\\\"}]}\",\n                TEST_JSON);\n    }\n\n    private void thenCheckIfImageMatchesJSON() {\n        assertEquals(\"{\\\"images\\\":[{\\\"name\\\":\\\"nginx\\\",\\\"version\\\":\\\"latest\\\",\\\"type\\\":\\\"CONTAINER_IMAGE\\\"}]}\",\n                TEST_JSON);\n    }\n\n    private void thenCheckIfContainerMatchesXML() {\n        /**\n         * <[<?xml version=\"1.0\" encoding=\"UTF-8\"?> <containers> <container>\n         * <name>dockerContainer1</name> <version>nginx:latest</version>\n         * <state>uninstalled</state> </container>\n         * </containers> ]>\n         */\n        String containerXMLExpected = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><containers><container><name>dockerContainer1</name><version>nginx:latest</version><state>uninstalled</state></container></containers>\";\n        assertEquals(containerXMLExpected.replaceAll(\"\\\\s+\", \"\"), TEST_XML.replaceAll(\"\\\\s+\", \"\"));\n    }\n\n    private void thenCheckIfImageMatchesXML() {\n        /**\n         * <[<?xml version=\"1.0\" encoding=\"UTF-8\"?> <containers> <container>\n         * <name>dockerContainer1</name> <version>nginx:latest</version> </container>\n         * </containers> ]>\n         */\n        String containerXMLExpected = \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?><images><image><name>nginx</name><version>latest</version></image></images>\";\n        assertEquals(containerXMLExpected.replaceAll(\"\\\\s+\", \"\"), TEST_XML.replaceAll(\"\\\\s+\", \"\"));\n    }\n\n    private void thenCheckIfJsonMatchesContainer() {\n        assertEquals(\"test\", this.dockerContainerObject.getContainerName());\n\n    }\n\n    private void thenCheckIfJsonMatchesImage() {\n        assertEquals(\"nginx\", this.containerImageObject.getName());\n\n    }\n\n    private void thenCheckIfContainerWereListed() throws KuraException {\n        Mockito.verify(this.mockContainerOrchestrationService, times(1)).listContainerDescriptors();\n    }\n\n    private void thenCheckIfImagesHaveBeenListed() throws KuraException {\n        Mockito.verify(this.mockContainerOrchestrationService, times(1)).listImageInstanceDescriptors();\n    }\n\n    private void thenCheckIfContainerOneHasStarted() throws KuraException, InterruptedException {\n        Mockito.verify(this.mockContainerOrchestrationService, times(1))\n                .startContainer(this.dockerContainer1.getContainerId());\n        Mockito.verify(this.mockContainerOrchestrationService, times(0))\n                .stopContainer(this.dockerContainer1.getContainerId());\n        Mockito.verify(this.mockContainerOrchestrationService, times(0))\n                .startContainer(this.dockerContainer2.getContainerId());\n        Mockito.verify(this.mockContainerOrchestrationService, times(0))\n                .stopContainer(this.dockerContainer2.getContainerId());\n    }\n\n    private void thenCheckIfContainerOneHasStopped() throws KuraException, InterruptedException {\n        Mockito.verify(this.mockContainerOrchestrationService, times(0))\n                .startContainer(this.dockerContainer1.getContainerId());\n        Mockito.verify(this.mockContainerOrchestrationService, times(1))\n                .stopContainer(this.dockerContainer1.getContainerId());\n        Mockito.verify(this.mockContainerOrchestrationService, times(0))\n                .startContainer(this.dockerContainer2.getContainerId());\n        Mockito.verify(this.mockContainerOrchestrationService, times(0))\n                .stopContainer(this.dockerContainer2.getContainerId());\n    }\n\n    private void thenCheckIfImageHasDelete() throws KuraException, InterruptedException {\n        Mockito.verify(this.mockContainerOrchestrationService, times(1))\n                .deleteImage(this.containerInstanceImage1.getImageId());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private ComponentContext mockComponentContext(final List<Bundle> bundles) {\n        final Bundle[] asArray = bundles.toArray(new Bundle[bundles.size()]);\n\n        final BundleContext bundleContext = mock(BundleContext.class);\n        when(bundleContext.getBundles()).thenReturn(asArray);\n\n        final JsonMarshallUnmarshallImpl jsonMarshaller = new JsonMarshallUnmarshallImpl();\n\n        final ServiceReference<Unmarshaller> ref = Mockito.mock(ServiceReference.class);\n\n        when(bundleContext.getService(ref)).thenReturn(jsonMarshaller);\n        try {\n            when(bundleContext.getServiceReferences(ArgumentMatchers.eq(Unmarshaller.class),\n                    ArgumentMatchers.anyString())).thenReturn(Arrays.asList(ref));\n        } catch (InvalidSyntaxException e) {\n            throw new IllegalStateException(e);\n        }\n\n        final ComponentContext componentContext = mock(ComponentContext.class);\n        when(componentContext.getBundleContext()).thenReturn(bundleContext);\n\n        return componentContext;\n    }\n\n    private Bundle mockBundle(final String symbolicName, final String version) {\n        final Bundle result = mock(Bundle.class);\n\n        when(result.getSymbolicName()).thenReturn(symbolicName);\n        when(result.getVersion()).thenReturn(new Version(version));\n\n        return result;\n    }\n\n    private void thenCompareOutputOfContainerImage() {\n        this.containerImageObject = new ContainerImage(\"test\", \"latest\");\n\n        String imageName = \"test\";\n        String imageTag = \"latest\";\n        String imageId = \"3e3rf32e2wsd2f\";\n        String imageAuthor = \"Greg\";\n        String imageArch = \"ARM64\";\n        long imageSize = 9883829;\n\n        this.containerImageObject.setImageName(imageName);\n        this.containerImageObject.setImageTag(imageTag);\n        this.containerImageObject.setImageId(imageId);\n        this.containerImageObject.setImageAuthor(imageAuthor);\n        this.containerImageObject.setImageArch(imageArch);\n        this.containerImageObject.setImageSize(imageSize);\n\n        this.containerImagesObject = new ContainerImages(new LinkedList<ContainerImage>());\n        this.containerImagesObject.setContainerImages(Arrays.asList(this.containerImageObject));\n\n        assertEquals(this.containerImageObject.getImageName(), imageName);\n        assertEquals(this.containerImageObject.getImageTag(), imageTag);\n        assertEquals(this.containerImageObject.getImageId(), imageId);\n        assertEquals(this.containerImageObject.getImageAuthor(), imageAuthor);\n        assertEquals(this.containerImageObject.getImageArch(), imageArch);\n        assertEquals(this.containerImageObject.getImageSize(), imageSize);\n        assertEquals(this.containerImagesObject.getContainerImages().get(0).getName(), imageName);\n    }\n    \n    private X509Certificate getEmptyX509Cert() {\n        return new X509Certificate() {\n            \n            @Override\n            public boolean hasUnsupportedCriticalExtension() {\n                // TODO Auto-generated method stub\n                return false;\n            }\n            \n            @Override\n            public Set<String> getNonCriticalExtensionOIDs() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public byte[] getExtensionValue(String arg0) {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public Set<String> getCriticalExtensionOIDs() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public void verify(PublicKey arg0, String arg1) throws CertificateException, NoSuchAlgorithmException,\n                    InvalidKeyException, NoSuchProviderException, SignatureException {\n                // TODO Auto-generated method stub\n                \n            }\n            \n            @Override\n            public void verify(PublicKey arg0) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,\n                    NoSuchProviderException, SignatureException {\n                // TODO Auto-generated method stub\n                \n            }\n            \n            @Override\n            public String toString() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public PublicKey getPublicKey() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public byte[] getEncoded() throws CertificateEncodingException {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public int getVersion() {\n                // TODO Auto-generated method stub\n                return 0;\n            }\n            \n            @Override\n            public byte[] getTBSCertificate() throws CertificateEncodingException {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public boolean[] getSubjectUniqueID() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public Principal getSubjectDN() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public byte[] getSignature() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public byte[] getSigAlgParams() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public String getSigAlgOID() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public String getSigAlgName() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public BigInteger getSerialNumber() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public Date getNotBefore() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public Date getNotAfter() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public boolean[] getKeyUsage() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public boolean[] getIssuerUniqueID() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public Principal getIssuerDN() {\n                // TODO Auto-generated method stub\n                return null;\n            }\n            \n            @Override\n            public int getBasicConstraints() {\n                // TODO Auto-generated method stub\n                return 0;\n            }\n            \n            @Override\n            public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException {\n                // TODO Auto-generated method stub\n                \n            }\n            \n            @Override\n            public void checkValidity() throws CertificateExpiredException, CertificateNotYetValidException {\n                // TODO Auto-generated method stub\n                \n            }\n        };\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.keystore.test\nBundle-SymbolicName: org.eclipse.kura.core.keystore.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: javax.servlet;version=\"3.1.0\",\n javax.servlet.http;version=\"3.1.0\",\n org.apache.commons.io;version=\"2.11.0\",\n org.eclipse.kura.core.crypto,\n org.eclipse.kura.core.keystore.util;version=\"1.0.0\",\n org.eclipse.kura.core.testutil;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.http;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.pki;version=\"[1.1.0,2.0.0)\",\n org.eclipse.kura.core.testutil.requesthandler;version=\"1.2.0\",\n org.eclipse.kura.core.testutil.service;version=\"1.0.0\",\n org.eclipse.kura.security.keystore;version=\"[1.0,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.slf4j;version=\"1.6.4\"\nFragment-Host: org.eclipse.kura.core.keystore;bundle-version=\"1.1.0\"\nRequire-Bundle: org.eclipse.kura.http.server.manager;bundle-version=\"1.4.0\",\n org.junit\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.keystore.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n    \n    <build>\n       <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/src/test/java/org/eclipse/kura/core/keystore/FilesystemKeystoreServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.security.GeneralSecurityException;\nimport java.security.Key;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.KeyStore;\nimport java.security.KeyStore.Entry;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.NoSuchProviderException;\nimport java.security.PrivateKey;\nimport java.security.SecureRandom;\nimport java.security.Security;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.spec.ECGenParameterSpec;\nimport java.security.spec.RSAKeyGenParameterSpec;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.security.auth.x500.X500Principal;\n\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.mockito.AdditionalMatchers;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mockito;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.EventAdmin;\n\npublic class FilesystemKeystoreServiceImplTest {\n\n    private static final String DEFAULT_KEY_ALIAS = \"alias\";\n    private static final String CERT_FILE_PATH = \"target/test-classes/cert\";\n    private static final String KEY_KEYSTORE_PATH = \"keystore.path\";\n    private static final String KEY_KEYSTORE_PASSWORD = \"keystore.password\";\n    private static final String KEY_RANDOMIZE_PASSWORD = \"randomize.password\";\n\n    private static final String STORE_PATH = \"target/key.store\";\n    private static final String NEW_STORE_PATH = \"target/newKey.store\";\n    private static final String UPDATED_NEW_STORE_PATH = \"target/updatedNewKey.store\";\n    private static final String STORE_PASS = \"pass\";\n\n    private KeyStore store;\n\n    @BeforeClass\n    public static void setupProvider() {\n        Security.addProvider(new BouncyCastleProvider());\n    }\n\n    @Before\n    public void setupDefaultKeystore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException,\n            IOException, NoSuchProviderException {\n\n        // create a new keystore each time the tests should run\n\n        this.store = KeyStore.getInstance(\"jks\");\n\n        this.store.load(null, null);\n\n        KeyPairGenerator gen = KeyPairGenerator.getInstance(\"DSA\", \"BC\");\n        gen.initialize(1024);\n        KeyPair pair = gen.generateKeyPair();\n        Key key = pair.getPrivate();\n\n        InputStream is = new FileInputStream(CERT_FILE_PATH);\n        Certificate certificate = CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        is.close();\n\n        Certificate[] chain = { certificate };\n\n        this.store.setKeyEntry(DEFAULT_KEY_ALIAS, key, STORE_PASS.toCharArray(), chain);\n\n        try (OutputStream os = new FileOutputStream(STORE_PATH)) {\n            this.store.store(os, STORE_PASS.toCharArray());\n        }\n\n        // clean test keystores\n        Files.deleteIfExists(Paths.get(NEW_STORE_PATH));\n        Files.deleteIfExists(Paths.get(UPDATED_NEW_STORE_PATH));\n    }\n\n    @Test\n    public void testGetKeyStore() throws KuraException, KeyStoreException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        KeyStore keystore = keystoreService.getKeyStore();\n\n        assertNotNull(keystore);\n        assertEquals(Collections.list(this.store.aliases()), Collections.list(keystore.aliases()));\n    }\n\n    @Test\n    public void testCheckKeystoreFileCreation() throws KuraException, KeyStoreException {\n        assertFalse(new File(NEW_STORE_PATH).isFile());\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, NEW_STORE_PATH);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        assertTrue(new File(NEW_STORE_PATH).isFile());\n\n    }\n\n    @Test\n    public void testCheckKeystoreFileCreationWithUpdate() throws KuraException, KeyStoreException {\n        assertFalse(new File(NEW_STORE_PATH).isFile());\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, NEW_STORE_PATH);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        properties.put(KEY_KEYSTORE_PATH, UPDATED_NEW_STORE_PATH);\n\n        keystoreService.updated(properties);\n\n        assertTrue(new File(NEW_STORE_PATH).isFile());\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testGetEntryNullAlias() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.getEntry(null);\n    }\n\n    @Test\n    public void testGetEntryEmptyAlias() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        Entry entry = keystoreService.getEntry(\"\");\n        assertNull(entry);\n    }\n\n    @Test\n    public void testGetEntry() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        Entry entry = keystoreService.getEntry(DEFAULT_KEY_ALIAS);\n        assertNotNull(entry);\n        assertTrue(entry instanceof PrivateKeyEntry);\n        PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) entry;\n        assertNotNull(privateKeyEntry.getCertificateChain());\n        assertNotNull(privateKeyEntry.getPrivateKey());\n    }\n\n    @Test\n    public void testGetEntries() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        Map<String, Entry> entries = keystoreService.getEntries();\n        assertNotNull(entries);\n        assertFalse(entries.isEmpty());\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testDeleteEntryNullAlias() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.deleteEntry(null);\n    }\n\n    @Test\n    public void testDeleteEntryEmptyAlias() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.deleteEntry(\"\");\n\n        Map<String, Entry> entries = keystoreService.getEntries();\n        assertNotNull(entries);\n        assertFalse(entries.isEmpty());\n    }\n\n    @Test\n    public void testDeleteEntry() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.deleteEntry(DEFAULT_KEY_ALIAS);\n\n        Map<String, Entry> entries = keystoreService.getEntries();\n        assertNotNull(entries);\n        assertTrue(entries.isEmpty());\n    }\n\n    @Test\n    public void testDeleteEntryEvent() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        EventAdmin eventAdmin = Mockito.mock(EventAdmin.class);\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n        keystoreService.setEventAdmin(eventAdmin);\n\n        keystoreService.deleteEntry(DEFAULT_KEY_ALIAS);\n\n        Map<String, Entry> entries = keystoreService.getEntries();\n        assertNotNull(entries);\n        assertTrue(entries.isEmpty());\n        Mockito.verify(eventAdmin, Mockito.times(1)).postEvent(Mockito.any());\n    }\n\n    @Test\n    public void testDeleteEntryNonExistingEntryNoEvent() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        EventAdmin eventAdmin = Mockito.mock(EventAdmin.class);\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n        keystoreService.setEventAdmin(eventAdmin);\n\n        keystoreService.deleteEntry(\"nonexistingalias\");\n\n        Map<String, Entry> entries = keystoreService.getEntries();\n        assertNotNull(entries);\n        assertFalse(entries.isEmpty());\n        Mockito.verify(eventAdmin, Mockito.times(0)).postEvent(Mockito.any());\n    }\n\n    @Test\n    public void testGetAliases() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        List<String> aliases = keystoreService.getAliases();\n        assertNotNull(aliases);\n        assertFalse(aliases.isEmpty());\n        assertEquals(DEFAULT_KEY_ALIAS, aliases.get(0));\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testSetEntryNullAliasEntry() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.setEntry(null, null);\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testSetEntryNullEntry() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.setEntry(DEFAULT_KEY_ALIAS + \"1\", null);\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testSetEntryNullAlias() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.setEntry(DEFAULT_KEY_ALIAS + \"1\", null);\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testSetEntryEmptyAlias() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.setEntry(\"\", null);\n    }\n\n    @Test\n    public void testSetEntry() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        KeyPairGenerator gen = KeyPairGenerator.getInstance(\"DSA\", \"BC\");\n        gen.initialize(2048);\n        KeyPair pair = gen.generateKeyPair();\n        PrivateKey key = pair.getPrivate();\n\n        InputStream is = new FileInputStream(CERT_FILE_PATH);\n        Certificate certificate = CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        is.close();\n\n        Certificate[] chain = { certificate };\n\n        PrivateKeyEntry privateKeyEntry = new PrivateKeyEntry(key, chain);\n\n        keystoreService.setEntry(DEFAULT_KEY_ALIAS + \"1\", privateKeyEntry);\n\n        List<String> aliases = keystoreService.getAliases();\n        assertNotNull(aliases);\n        assertFalse(aliases.isEmpty());\n        assertEquals(2, aliases.size());\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testGetKeyManagersNullAlg() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.getKeyManagers(null);\n    }\n\n    @Test\n    public void testGetKeyManagersEmptyAlg() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        List<KeyManager> keyManagers = keystoreService.getKeyManagers(KeyManagerFactory.getDefaultAlgorithm());\n        assertNotNull(keyManagers);\n    }\n\n    @Test\n    public void testGetKeyManagersPKIXSunJSSE() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        List<KeyManager> keyManagers = keystoreService.getKeyManagers(\"PKIX\", \"SunJSSE\");\n        assertNotNull(keyManagers);\n    }\n\n    @Test(expected = KuraException.class)\n    public void testGetKeyManagersNonExistingProvider() throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.getKeyManagers(\"PKIX\", \"nonexisting\");\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testGetKeyManagersWithProvideNullAlgorithm()\n            throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.getKeyManagers(null, \"SunJSSE\");\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testGetKeyManagersWithProvideNullProvider()\n            throws GeneralSecurityException, IOException, KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.getKeyManagers(\"PKIX\", null);\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testCreateKeyPairNullAlg() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", null, 1024, \"SHA256WithDSA\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testCreateKeyPairEmptyAlg() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", \"\", 1024, \"SHA256WithDSA\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testCreateKeyPairZeroKeyLength() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", \"DSA\", 0, \"SHA256WithDSA\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n    }\n\n    @Test(expected = KuraException.class)\n    public void testCreateKeyPairWrongAlg() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", \"KSA\", 1024, \"SHA256WithDSA\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testCreateKeyPairEmptyAlias() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"\", \"DSA\", 1024, \"SHA256WithDSA\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testCreateKeyPairEmptyAttributes() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", \"DSA\", 1024, \"SHA256WithDSA\", \"\");\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testCreateKeyPairEmptySigAlg() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", \"DSA\", 0, \"\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n    }\n\n    @Test\n    public void testCreateKeyPair()\n            throws KuraException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        createEmptyKeystore(STORE_PATH, STORE_PASS);\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", \"DSA\", 1024, \"SHA256WithDSA\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n\n        Entry entry = keystoreService.getEntry(\"alias\");\n        assertNotNull(entry);\n        assertTrue(entry instanceof PrivateKeyEntry);\n        assertNotNull(((PrivateKeyEntry) entry).getPrivateKey());\n        assertNotNull(((PrivateKeyEntry) entry).getCertificate().getPublicKey());\n        assertEquals(\"DSA\", ((PrivateKeyEntry) entry).getPrivateKey().getAlgorithm());\n        assertEquals(\"DSA\", ((PrivateKeyEntry) entry).getCertificate().getPublicKey().getAlgorithm());\n    }\n\n    @Test\n    public void testCreateKeyPairWithEC()\n            throws KuraException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        createEmptyKeystore(STORE_PATH, STORE_PASS);\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", \"EC\", new ECGenParameterSpec(\"prime256v1\"), \"SHA256WithECDSA\",\n                \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n\n        Entry entry = keystoreService.getEntry(\"alias\");\n        assertNotNull(entry);\n        assertTrue(entry instanceof PrivateKeyEntry);\n        assertNotNull(((PrivateKeyEntry) entry).getPrivateKey());\n        assertNotNull(((PrivateKeyEntry) entry).getCertificate().getPublicKey());\n        assertEquals(\"EC\", ((PrivateKeyEntry) entry).getPrivateKey().getAlgorithm());\n        assertEquals(\"EC\", ((PrivateKeyEntry) entry).getCertificate().getPublicKey().getAlgorithm());\n    }\n\n    @Test\n    public void testCreateKeyPairWithRSA()\n            throws KuraException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        createEmptyKeystore(STORE_PATH, STORE_PASS);\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", \"RSA\", new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4),\n                \"SHA256WithRSA\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n\n        Entry entry = keystoreService.getEntry(\"alias\");\n        assertNotNull(entry);\n        assertTrue(entry instanceof PrivateKeyEntry);\n        assertNotNull(((PrivateKeyEntry) entry).getPrivateKey());\n        assertNotNull(((PrivateKeyEntry) entry).getCertificate().getPublicKey());\n        assertEquals(\"RSA\", ((PrivateKeyEntry) entry).getPrivateKey().getAlgorithm());\n        assertEquals(\"RSA\", ((PrivateKeyEntry) entry).getCertificate().getPublicKey().getAlgorithm());\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testCreateCSRNullPrincipal() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.getCSR(\"alias\", null, \"alg\");\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testCreateCSRNullSignerAlg() throws KuraException, NoSuchAlgorithmException, NoSuchProviderException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        X500Principal principal = new X500Principal(\"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n        KeyPairGenerator keyGen = KeyPairGenerator.getInstance(\"DSA\", \"BC\");\n        keyGen.initialize(1024, new SecureRandom());\n        KeyPair keyPair = keyGen.generateKeyPair();\n\n        keystoreService.getCSR(keyPair, principal, null);\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testCreateCSREmptyAlg() throws KuraException, NoSuchAlgorithmException, NoSuchProviderException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        X500Principal principal = new X500Principal(\"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n        KeyPairGenerator keyGen = KeyPairGenerator.getInstance(\"DSA\", \"BC\");\n        keyGen.initialize(1024, new SecureRandom());\n        KeyPair keyPair = keyGen.generateKeyPair();\n\n        keystoreService.getCSR(keyPair, principal, \"\");\n    }\n\n    @Test\n    public void testCreateCSRWithKeyPair() throws KuraException, NoSuchAlgorithmException, NoSuchProviderException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        X500Principal principal = new X500Principal(\"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n        KeyPairGenerator keyGen = KeyPairGenerator.getInstance(\"RSA\", \"BC\");\n        keyGen.initialize(1024, new SecureRandom());\n        KeyPair keyPair = keyGen.generateKeyPair();\n\n        String csr = keystoreService.getCSR(keyPair, principal, \"SHA256withRSA\");\n        assertNotNull(csr);\n        assertTrue(csr.startsWith(\"-----BEGIN CERTIFICATE REQUEST-----\"));\n    }\n\n    @Test\n    public void testCreateCSRWithAlias()\n            throws KuraException, NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        createEmptyKeystore(STORE_PATH, STORE_PASS);\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.createKeyPair(\"alias\", \"RSA\", 2048, \"SHA256withRSA\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n        X500Principal principal = new X500Principal(\"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n\n        String csr = keystoreService.getCSR(\"alias\", principal, \"SHA256withRSA\");\n        assertNotNull(csr);\n        assertTrue(csr.startsWith(\"-----BEGIN CERTIFICATE REQUEST-----\"));\n    }\n\n    @Test(expected = IOException.class)\n    public void testPasswordChange() throws KuraException, GeneralSecurityException, IOException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n        properties.put(KEY_RANDOMIZE_PASSWORD, true);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.decryptAes(STORE_PASS.toCharArray())).thenReturn(STORE_PASS.toCharArray());\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        try (InputStream tsReadStream = new FileInputStream(STORE_PATH);) {\n            this.store.load(tsReadStream, STORE_PASS.toCharArray());\n        }\n\n    }\n\n    @Test\n    public void testUpdatePassword() throws KuraException, GeneralSecurityException, IOException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n        properties.put(KEY_RANDOMIZE_PASSWORD, true);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.decryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        keystoreService.updated(properties);\n\n        try (InputStream tsReadStream = new FileInputStream(STORE_PATH);) {\n            this.store.load(tsReadStream, STORE_PASS.toCharArray());\n        }\n\n        assertNotNull(keystoreService.getKeyStore());\n    }\n\n    @Test\n    public void testUpdatePathNotExisting() throws KuraException, GeneralSecurityException, IOException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n        properties.put(KEY_RANDOMIZE_PASSWORD, true);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.decryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        Map<String, Object> newProps = new HashMap<>();\n        newProps.put(KEY_KEYSTORE_PATH, \"target/key2.store\");\n        newProps.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n        newProps.put(KEY_RANDOMIZE_PASSWORD, false);\n        keystoreService.updated(newProps);\n\n        keystoreService.getKeyStore();\n    }\n\n    @Test\n    public void testUpdatePathExisting() throws KuraException, GeneralSecurityException, IOException {\n        try (OutputStream os = new FileOutputStream(NEW_STORE_PATH)) {\n            this.store.store(os, STORE_PASS.toCharArray());\n        }\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n        properties.put(KEY_RANDOMIZE_PASSWORD, true);\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.decryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        Map<String, Object> newProps = new HashMap<>();\n        newProps.put(KEY_KEYSTORE_PATH, NEW_STORE_PATH);\n        newProps.put(KEY_KEYSTORE_PASSWORD, STORE_PASS);\n        newProps.put(KEY_RANDOMIZE_PASSWORD, false);\n        keystoreService.updated(newProps);\n\n        assertNotNull(keystoreService.getKeyStore());\n    }\n\n    @Test\n    public void testActivateWithPasswordInCrypto()\n            throws KuraException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, \"a wrong password\");\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.decryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        KeyStore keystore = keystoreService.getKeyStore();\n\n        assertNotNull(keystore);\n        assertEquals(Collections.list(this.store.aliases()), Collections.list(keystore.aliases()));\n\n        assertKeystoreIsLoadable(STORE_PATH, STORE_PASS);\n    }\n\n    @Test\n    public void testActivateWithPasswordInCryptoAndSpuriousUpdate()\n            throws KuraException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, \"a wrong password\");\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.decryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        KeyStore keystore = keystoreService.getKeyStore();\n\n        assertNotNull(keystore);\n        assertEquals(Collections.list(this.store.aliases()), Collections.list(keystore.aliases()));\n\n        assertKeystoreIsLoadable(STORE_PATH, STORE_PASS);\n\n        keystoreService.updated(properties);\n\n        assertKeystoreIsLoadable(STORE_PATH, STORE_PASS);\n    }\n\n    @Test\n    public void testActivateWithPasswordInCryptoAndChangePassword()\n            throws KuraException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(KEY_KEYSTORE_PATH, STORE_PATH);\n        properties.put(KEY_KEYSTORE_PASSWORD, \"a wrong password\");\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.decryptAes((char[]) ArgumentMatchers.any())).thenAnswer(i -> i.getArgument(0, char[].class));\n        when(cryptoService.getKeyStorePassword(STORE_PATH)).thenReturn(STORE_PASS.toCharArray());\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n\n        keystoreService.setEventAdmin(mock(EventAdmin.class));\n        keystoreService.setCryptoService(cryptoService);\n        keystoreService.activate(componentContext, properties);\n\n        KeyStore keystore = keystoreService.getKeyStore();\n\n        assertNotNull(keystore);\n        assertEquals(Collections.list(this.store.aliases()), Collections.list(keystore.aliases()));\n\n        assertKeystoreIsLoadable(STORE_PATH, STORE_PASS);\n\n        properties.put(KEY_KEYSTORE_PASSWORD, \"foo\");\n        keystoreService.updated(properties);\n\n        assertKeystoreIsLoadable(STORE_PATH, \"foo\");\n        Mockito.verify(cryptoService).setKeyStorePassword(Mockito.eq(STORE_PATH),\n                AdditionalMatchers.aryEq(\"foo\".toCharArray()));\n    }\n\n    private void assertKeystoreIsLoadable(final String path, final String password)\n            throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {\n        final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n\n        try (final FileInputStream in = new FileInputStream(path)) {\n            ks.load(in, password.toCharArray());\n        }\n    }\n\n    private KeyStore createEmptyKeystore(final String path, final String password)\n            throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] passwordChars = password.toCharArray();\n        ks.load(null, passwordChars);\n\n        try (final FileOutputStream out = new FileOutputStream(path)) {\n            ks.store(out, passwordChars);\n        }\n\n        return ks;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/src/test/java/org/eclipse/kura/core/keystore/FilesystemKeystoreServiceOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.junit.Test;\n\npublic class FilesystemKeystoreServiceOptionsTest {\n\n    private static final String CHANGEIT_PASSWORD = \"changeit\";\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testNullPropertiesCrypto() {\n        new FilesystemKeystoreServiceOptions(null, null);\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testNullCrypto() {\n        Map<String, Object> properties = new HashMap<>();\n        new FilesystemKeystoreServiceOptions(properties, null);\n    }\n\n    @Test\n    public void testConstructorMissingProps() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes(CHANGEIT_PASSWORD.toCharArray())).thenReturn(\"encrypted\".toCharArray());\n        when(cryptoService.decryptAes(\"encrypted\".toCharArray())).thenReturn(CHANGEIT_PASSWORD.toCharArray());\n        when(cryptoService.getKeyStorePassword(any(String.class))).thenReturn(CHANGEIT_PASSWORD.toCharArray());\n\n        FilesystemKeystoreServiceOptions FilesystemKeystoreServiceOptions = new FilesystemKeystoreServiceOptions(\n                properties, cryptoService);\n\n        assertEquals(\"/tmp/keystore.ks\", FilesystemKeystoreServiceOptions.getKeystorePath());\n        assertArrayEquals(CHANGEIT_PASSWORD.toCharArray(),\n                FilesystemKeystoreServiceOptions.getKeystorePassword(cryptoService));\n    }\n\n    @Test\n    public void testConstructor() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"keystore.path\", \"/abc\");\n        properties.put(\"keystore.password\", \"testPassword\");\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes(\"testPassword\".toCharArray())).thenReturn(\"encrypted\".toCharArray());\n        when(cryptoService.decryptAes(\"encrypted\".toCharArray())).thenReturn(\"testPassword\".toCharArray());\n        when(cryptoService.decryptAes(\"testPassword\".toCharArray())).thenReturn(\"testPassword\".toCharArray());\n        when(cryptoService.getKeyStorePassword(any(String.class))).thenReturn(\"testPassword\".toCharArray());\n\n        FilesystemKeystoreServiceOptions FilesystemKeystoreServiceOptions = new FilesystemKeystoreServiceOptions(\n                properties, cryptoService);\n\n        assertEquals(\"/abc\", FilesystemKeystoreServiceOptions.getKeystorePath());\n        assertArrayEquals(\"testPassword\".toCharArray(),\n                FilesystemKeystoreServiceOptions.getKeystorePassword(cryptoService));\n    }\n\n    @Test\n    public void testCompareSame() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"keystore.path\", \"/abc\");\n        properties.put(\"keystore.password\", \"testPassword\");\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes(\"testPassword\".toCharArray())).thenReturn(\"encrypted\".toCharArray());\n        when(cryptoService.decryptAes(\"encrypted\".toCharArray())).thenReturn(\"testPassword\".toCharArray());\n\n        FilesystemKeystoreServiceOptions FilesystemKeystoreServiceOptions1 = new FilesystemKeystoreServiceOptions(\n                properties, cryptoService);\n\n        FilesystemKeystoreServiceOptions FilesystemKeystoreServiceOptions2 = new FilesystemKeystoreServiceOptions(\n                properties, cryptoService);\n\n        assertEquals(FilesystemKeystoreServiceOptions1, FilesystemKeystoreServiceOptions2);\n    }\n\n    @Test\n    public void testCompareDifferent() throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"keystore.path\", \"/abc\");\n        properties.put(\"keystore.password\", \"testPassword\");\n\n        CryptoService cryptoService = mock(CryptoService.class);\n        when(cryptoService.encryptAes(\"testPassword\".toCharArray())).thenReturn(\"encrypted\".toCharArray());\n        when(cryptoService.encryptAes(\"testPassword1\".toCharArray())).thenReturn(\"encrypted1\".toCharArray());\n        when(cryptoService.decryptAes(\"encrypted\".toCharArray())).thenReturn(\"testPassword\".toCharArray());\n        when(cryptoService.decryptAes(\"encrypted1\".toCharArray())).thenReturn(\"testPassword1\".toCharArray());\n\n        FilesystemKeystoreServiceOptions FilesystemKeystoreServiceOptions1 = new FilesystemKeystoreServiceOptions(\n                properties, cryptoService);\n\n        Map<String, Object> properties2 = new HashMap<>();\n        properties2.put(\"keystore.path\", \"/abc1\");\n        properties2.put(\"keystore.password\", \"testPassword1\");\n        FilesystemKeystoreServiceOptions FilesystemKeystoreServiceOptions2 = new FilesystemKeystoreServiceOptions(\n                properties2, cryptoService);\n\n        assertNotEquals(FilesystemKeystoreServiceOptions1, FilesystemKeystoreServiceOptions2);\n\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/src/test/java/org/eclipse/kura/core/keystore/crl/test/FilesystemKeystoreServiceImplCrlTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.crl.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.URI;\nimport java.nio.file.Files;\nimport java.security.KeyStore;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509CRL;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\n\nimport org.bouncycastle.asn1.x500.X500Name;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl;\nimport org.eclipse.kura.core.testutil.http.TestServer;\nimport org.eclipse.kura.core.testutil.pki.TestCA;\nimport org.eclipse.kura.core.testutil.pki.TestCA.CRLCreationOptions;\nimport org.eclipse.kura.core.testutil.pki.TestCA.CertificateCreationOptions;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.security.keystore.KeystoreChangedEvent;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mockito;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventAdmin;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FilesystemKeystoreServiceImplCrlTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(FilesystemKeystoreServiceImplCrlTest.class);\n\n    private static final String DEFAULT_KEYSTORE_PASSWORD = \"foo\";\n    private static final String DEFAULT_KEYSTORE_PID = \"foo\";\n\n    private static int jettyPort = 8085;\n\n    @Test\n    public void shouldDownloadCRLFromConfig() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        final TestCA ca = new TestCA(CertificateCreationOptions.builder(name).build());\n\n        try (final Fixture fixture = new Fixture()) {\n            final CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            fixture.update(fixture.getOptions().setCrlManagerEnabled(true)\n                    .setCrlUrls(Collections.singletonList(fixture.getCrlDownloadURL(\"/foo.crl\"))));\n\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n\n            Thread.sleep(6000);\n\n            assertTrue(new File(fixture.getKeystoreFile().getAbsolutePath() + \".crl\").exists());\n        }\n    }\n\n    @Test\n    public void shouldSupportChangingStoreFile() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        final TestCA ca = new TestCA(CertificateCreationOptions.builder(name).build());\n\n        try (final Fixture fixture = new Fixture()) {\n            final CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            final File file = Files.createTempFile(null, null).toFile();\n\n            assertTrue(file.delete());\n            assertFalse(file.exists());\n\n            fixture.update(fixture.getOptions().setCrlManagerEnabled(true)\n                    .setCrlUrls(Collections.singletonList(fixture.getCrlDownloadURL(\"/foo.crl\")))\n                    .setCrlStoreFile(Optional.of(file)));\n\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n\n            Thread.sleep(6000);\n            assertTrue(file.exists());\n        }\n    }\n\n    @Test\n    public void shouldDownloadCrlFromCertificateDistributionPoint() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        try (final Fixture fixture = new Fixture()) {\n\n            final TestCA ca = new TestCA(CertificateCreationOptions.builder(name)\n                    .withCRLDownloadURI(new URI(fixture.getCrlDownloadURL(\"/foo.crl\"))).build());\n\n            final CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            fixture.update(fixture.getOptions().setCrlManagerEnabled(true));\n\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n        }\n    }\n\n    @Test\n    public void shouldMergeDistributionPoints() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        try (final Fixture fixture = new Fixture()) {\n\n            final TestCA ca = new TestCA(CertificateCreationOptions.builder(name)\n                    .withCRLDownloadURI(new URI(fixture.getCrlDownloadURL(\"/foo.crl\"))).build());\n\n            final List<String> downloads = fixture.collectDownloadRelativeURIs();\n            final List<Event> eventAdminEvents = fixture.collectEventAdminEvents();\n\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            fixture.update(fixture.getOptions().setCrlManagerEnabled(true)\n                    .setCrlUrls(Collections.singletonList(fixture.getCrlDownloadURL(\"/foo.crl\"))));\n\n            Thread.sleep(10000);\n\n            assertEquals(1, downloads.size());\n            assertEquals(2, eventAdminEvents.size());\n        }\n    }\n\n    @Test\n    public void shouldSupportLoad() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        File keystoreFile;\n\n        try (final Fixture fixture = new Fixture()) {\n\n            keystoreFile = fixture.getKeystoreFile();\n\n            final TestCA ca = new TestCA(CertificateCreationOptions.builder(name).build());\n\n            final CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            fixture.update(fixture.getOptions().setCrlManagerEnabled(true)\n                    .setCrlUrls(Collections.singletonList(fixture.getCrlDownloadURL(\"/foo.crl\"))));\n\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n\n            Thread.sleep(10000);\n        }\n\n        try (final Fixture fixture = new Fixture(Optional.of(keystoreFile))) {\n\n            fixture.setOptions(fixture.getOptions().setCrlManagerEnabled(true)\n                    .setCrlUrls(Collections.singletonList(fixture.getCrlDownloadURL(\"/foo.crl\"))));\n\n            fixture.activate();\n\n            assertEquals(1, fixture.keystoreService.getCRLs().size());\n        }\n    }\n\n    @Test\n    public void shouldDownloadCRLAgainOnNextUpdate() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        final TestCA ca = new TestCA(CertificateCreationOptions.builder(name).build());\n\n        try (final Fixture fixture = new Fixture()) {\n            CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(\n                    CRLCreationOptions.builder().withEndDate(Date.from(Instant.now().plusMillis(5000))).build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            fixture.update(fixture.getOptions().setCrlManagerEnabled(true)\n                    .setCrlUrls(Collections.singletonList(fixture.getCrlDownloadURL(\"/foo.crl\"))));\n\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n            nextDownload = fixture.nextDownloadRelativeURI();\n\n            final X509CRL newCrl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", newCrl);\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n        }\n    }\n\n    @Test\n    public void shouldSupportCertificateRemoval() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        try (final Fixture fixture = new Fixture()) {\n\n            final TestCA ca = new TestCA(CertificateCreationOptions.builder(name)\n                    .withCRLDownloadURI(new URI(fixture.getCrlDownloadURL(\"/toBeRemoved.crl\"))).build());\n\n            final CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.setOptions(fixture.getOptions().setCrlManagerEnabled(true));\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/toBeRemoved.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"toBeRemoved\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            assertEquals(\"/toBeRemoved.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n\n            assertEquals(1, fixture.keystoreService.getCRLs().size());\n\n            fixture.keystoreService.deleteEntry(\"toBeRemoved\");\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n\n            assertEquals(0, fixture.keystoreService.getCRLs().size());\n        }\n    }\n\n    @Test\n    public void shouldRejectUpdateIfIssuerNameDiffers() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        try (final Fixture fixture = new Fixture()) {\n\n            final TestCA ca = new TestCA(CertificateCreationOptions.builder(name)\n                    .withCRLDownloadURI(new URI(fixture.getCrlDownloadURL(\"/foo.crl\"))).build());\n\n            CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.setOptions(fixture.getOptions().setCrlManagerEnabled(true).setCrlUpdateInterval(1)\n                    .setCrlUpdateIntervalTimeUnit(TimeUnit.SECONDS));\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n\n            final TestCA otherCA = new TestCA(\n                    CertificateCreationOptions.builder(new X500Name(\"cn=Other CA, dc=baz.org\")).build());\n            fixture.setCrl(\"/foo.crl\", otherCA.generateCRL(CRLCreationOptions.builder().build()));\n\n            nextDownload = fixture.nextDownloadRelativeURI();\n            nextDownload.get(1, TimeUnit.MINUTES);\n\n            nextDownload = fixture.nextDownloadRelativeURI();\n            nextDownload.get(1, TimeUnit.MINUTES);\n\n            assertEquals(false, fixture.nextEventAdminEvent(10, TimeUnit.SECONDS).isPresent());\n\n        }\n    }\n\n    @Test\n    public void shouldRejectUpdateIfNotSignedByTrustedCert() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        try (final Fixture fixture = new Fixture()) {\n\n            final TestCA ca = new TestCA(CertificateCreationOptions.builder(name)\n                    .withCRLDownloadURI(new URI(fixture.getCrlDownloadURL(\"/foo.crl\"))).build());\n\n            CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.setOptions(fixture.getOptions().setCrlManagerEnabled(true).setCrlUpdateInterval(1)\n                    .setCrlUpdateIntervalTimeUnit(TimeUnit.SECONDS));\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n\n            final TestCA otherCA = new TestCA(CertificateCreationOptions.builder(name).build());\n            fixture.setCrl(\"/foo.crl\", otherCA.generateCRL(CRLCreationOptions.builder().build()));\n\n            nextDownload = fixture.nextDownloadRelativeURI();\n            nextDownload.get(1, TimeUnit.MINUTES);\n\n            nextDownload = fixture.nextDownloadRelativeURI();\n            nextDownload.get(1, TimeUnit.MINUTES);\n\n            assertEquals(false, fixture.nextEventAdminEvent(10, TimeUnit.SECONDS).isPresent());\n\n        }\n    }\n\n    @Test\n    public void shouldAcceptUpdateIfNotSignedByTrustedCertAndVerificationDisabled() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        try (final Fixture fixture = new Fixture()) {\n\n            final TestCA ca = new TestCA(CertificateCreationOptions.builder(name)\n                    .withCRLDownloadURI(new URI(fixture.getCrlDownloadURL(\"/foo.crl\"))).build());\n\n            CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.setOptions(fixture.getOptions().setCrlManagerEnabled(true).setCrlUpdateInterval(1)\n                    .setCrlVerificationEnabled(false).setCrlUpdateIntervalTimeUnit(TimeUnit.SECONDS));\n            fixture.activate();\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n\n            final TestCA otherCA = new TestCA(CertificateCreationOptions.builder(name).build());\n            fixture.setCrl(\"/foo.crl\", otherCA.generateCRL(CRLCreationOptions.builder().build()));\n\n            nextDownload = fixture.nextDownloadRelativeURI();\n            nextDownload.get(1, TimeUnit.MINUTES);\n\n            nextDownload = fixture.nextDownloadRelativeURI();\n            nextDownload.get(1, TimeUnit.MINUTES);\n\n            assertEquals(true, fixture.nextEventAdminEvent(10, TimeUnit.SECONDS).isPresent());\n\n        }\n    }\n\n    @Test\n    public void shouldSupportDisablingCRLVerificationWithUpdate() throws Exception {\n        final X500Name name = new X500Name(\"cn=Test CA, dc=bar.com\");\n\n        try (final Fixture fixture = new Fixture()) {\n\n            final TestCA ca = new TestCA(CertificateCreationOptions.builder(name)\n                    .withCRLDownloadURI(new URI(fixture.getCrlDownloadURL(\"/foo.crl\"))).build());\n\n            CompletableFuture<String> nextDownload = fixture.nextDownloadRelativeURI();\n\n            fixture.setOptions(fixture.getOptions().setCrlManagerEnabled(true).setCrlUpdateInterval(1)\n                    .setCrlUpdateIntervalTimeUnit(TimeUnit.SECONDS));\n            fixture.activate();\n            fixture.update(fixture.getOptions().setCrlVerificationEnabled(false));\n\n            final X509CRL crl = ca.generateCRL(CRLCreationOptions.builder().build());\n            fixture.setCrl(\"/foo.crl\", crl);\n\n            fixture.keystoreService.setEntry(\"foo\", new TrustedCertificateEntry(ca.getCertificate()));\n\n            assertEquals(\"/foo.crl\", nextDownload.get(1, TimeUnit.MINUTES));\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n            assertEquals(DEFAULT_KEYSTORE_PID,\n                    ((KeystoreChangedEvent) fixture.expectNextEventAdminEvent(1, TimeUnit.MINUTES)).getSenderPid());\n\n            final TestCA otherCA = new TestCA(CertificateCreationOptions.builder(name).build());\n            fixture.setCrl(\"/foo.crl\", otherCA.generateCRL(CRLCreationOptions.builder().build()));\n\n            nextDownload = fixture.nextDownloadRelativeURI();\n            nextDownload.get(1, TimeUnit.MINUTES);\n\n            nextDownload = fixture.nextDownloadRelativeURI();\n            nextDownload.get(1, TimeUnit.MINUTES);\n\n            assertEquals(true, fixture.nextEventAdminEvent(10, TimeUnit.SECONDS).isPresent());\n\n        }\n    }\n\n    private static class Fixture implements AutoCloseable {\n\n        private final FilesystemKeystoreServiceImpl keystoreService = new FilesystemKeystoreServiceImpl();\n        private TestServer server;\n        private final EventAdmin eventAdmin = Mockito.mock(EventAdmin.class);\n        private final ConfigurationService configurationService = Mockito.mock(ConfigurationService.class);\n        private final CryptoService cryptoService = Mockito.mock(CryptoService.class);\n        private final ComponentContext componentContext = Mockito.mock(ComponentContext.class);\n        private Options options;\n\n        private Optional<Consumer<String>> downloadListener = Optional.empty();\n        private BlockingQueue<Event> eventAdminEventQueue = new ArrayBlockingQueue<>(20);\n        private List<Event> eventAdminEventList = new ArrayList<>();\n\n        private final int currentPort;\n        private final File keystoreFile;\n\n        Fixture() throws Exception {\n            this(Optional.empty());\n        }\n\n        Fixture(final Optional<File> keystoreFile) throws Exception {\n            this.currentPort = jettyPort++;\n\n            if (keystoreFile.isPresent()) {\n                this.keystoreFile = keystoreFile.get();\n            } else {\n                this.keystoreFile = Files.createTempFile(null, null).toFile();\n            }\n\n            initializeKeystore(this.keystoreFile);\n\n            this.options = new Options(this.keystoreFile);\n\n            Mockito.when(this.cryptoService.encryptAes((char[]) ArgumentMatchers.any()))\n                    .thenAnswer(i -> i.getArgument(0, char[].class));\n            Mockito.when(this.cryptoService.decryptAes((char[]) ArgumentMatchers.any()))\n                    .thenAnswer(i -> i.getArgument(0, char[].class));\n            Mockito.when(this.cryptoService.getKeyStorePassword(ArgumentMatchers.any(String.class)))\n                    .thenReturn(DEFAULT_KEYSTORE_PASSWORD.toCharArray());\n            Mockito.doAnswer(i -> {\n                final Event event = i.getArgument(0, Event.class);\n\n                this.eventAdminEventQueue.offer(event);\n                this.eventAdminEventList.add(event);\n                return (Void) null;\n            }).when(this.eventAdmin).postEvent(ArgumentMatchers.any());\n\n            this.keystoreService.setConfigurationService(this.configurationService);\n            this.keystoreService.setEventAdmin(this.eventAdmin);\n            this.keystoreService.setCryptoService(this.cryptoService);\n\n            this.server = new TestServer(this.currentPort, Optional.of(s -> {\n                this.downloadListener.ifPresent(l -> l.accept(s));\n            }));\n        }\n\n        public File getKeystoreFile() {\n            return this.keystoreFile;\n        }\n\n        public String getCrlDownloadURL(final String relativeUrl) {\n            return \"http://localhost:\" + this.currentPort + relativeUrl;\n        }\n\n        Options getOptions() {\n            return this.options;\n        }\n\n        void setCrl(final String relativeURI, final X509CRL crl) throws IOException {\n            try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {\n                TestCA.encodeToPEM(crl, out);\n                this.server.setResource(relativeURI, out.toByteArray());\n            }\n        }\n\n        void setOptions(final Options options) {\n            this.options = options;\n        }\n\n        void update(final Options options) {\n            this.options = options;\n            this.keystoreService.updated(options.toProperties());\n        }\n\n        void activate() {\n            this.keystoreService.activate(this.componentContext, this.options.toProperties());\n        }\n\n        public void setDownloadListener(final Consumer<String> listener) {\n            this.downloadListener = Optional.of(listener);\n        }\n\n        public CompletableFuture<String> nextDownloadRelativeURI() {\n            final CompletableFuture<String> result = new CompletableFuture<>();\n            setDownloadListener(result::complete);\n            return result.whenComplete((ok, ex) -> this.downloadListener = Optional.empty());\n        }\n\n        public List<String> collectDownloadRelativeURIs() {\n            final List<String> result = new ArrayList<>();\n            setDownloadListener(result::add);\n            return result;\n        }\n\n        public Optional<Event> nextEventAdminEvent(final long timeout, final TimeUnit timeUnit)\n                throws InterruptedException {\n            return Optional.ofNullable(this.eventAdminEventQueue.poll(timeout, timeUnit));\n        }\n\n        public Event expectNextEventAdminEvent(final long timeout, final TimeUnit timeUnit)\n                throws IllegalStateException, InterruptedException {\n            return nextEventAdminEvent(timeout, timeUnit).orElseThrow(() -> new IllegalStateException(\n                    \"expected some EventAdmin event but none received after \" + timeout + \" \" + timeUnit));\n        }\n\n        public List<Event> collectEventAdminEvents() {\n            return this.eventAdminEventList;\n        }\n\n        @Override\n        public void close() throws Exception {\n            this.keystoreService.deactivate();\n            this.server.close();\n        }\n\n        private void initializeKeystore(final File file)\n                throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {\n            final KeyStore keystore = KeyStore.getInstance(\"jks\");\n            keystore.load(null, null);\n\n            try (final FileOutputStream out = new FileOutputStream(file)) {\n                keystore.store(out, DEFAULT_KEYSTORE_PASSWORD.toCharArray());\n            }\n        }\n    }\n\n    private static class Options {\n\n        private final File keystorePath;\n        private String keystorePassword = DEFAULT_KEYSTORE_PASSWORD;\n        private boolean crlManagerEnabled = false;\n        private long crlUpdateInterval = 1;\n        private TimeUnit crlUpdateIntervalTimeUnit = TimeUnit.DAYS;\n        private long crlCheckInterval = 1;\n        private TimeUnit crlCheckIntervalTimeUnit = TimeUnit.SECONDS;\n        private Optional<File> crlStoreFile = Optional.empty();\n        private List<String> crlUrls = Collections.emptyList();\n        private boolean crlVerificationEnabled = true;\n        private String ownPid = \"foo\";\n\n        Options(final File keystorePath) {\n            this.keystorePath = keystorePath;\n        }\n\n        Options setKeystorePassword(String keyStorePassword) {\n            this.keystorePassword = keyStorePassword;\n            return this;\n        }\n\n        Options setCrlManagerEnabled(boolean crlManagerEnabled) {\n            this.crlManagerEnabled = crlManagerEnabled;\n            return this;\n        }\n\n        Options setCrlUpdateInterval(long crlUpdateInterval) {\n            this.crlUpdateInterval = crlUpdateInterval;\n            return this;\n        }\n\n        Options setCrlUpdateIntervalTimeUnit(TimeUnit crlUpdateIntervalTimeUnit) {\n            this.crlUpdateIntervalTimeUnit = crlUpdateIntervalTimeUnit;\n            return this;\n        }\n\n        Options setCrlCheckInterval(long crlCheckInterval) {\n            this.crlCheckInterval = crlCheckInterval;\n            return this;\n        }\n\n        Options setCrlCheckIntervalTimeUnit(TimeUnit crlCheckIntervalTimeUnit) {\n            this.crlCheckIntervalTimeUnit = crlCheckIntervalTimeUnit;\n            return this;\n        }\n\n        Options setCrlStoreFile(Optional<File> crlStoreFile) {\n            this.crlStoreFile = crlStoreFile;\n            return this;\n        }\n\n        Options setCrlUrls(List<String> crlUrls) {\n            this.crlUrls = crlUrls;\n            return this;\n        }\n\n        Options setCrlVerificationEnabled(boolean crlVerificationEnabled) {\n            this.crlVerificationEnabled = crlVerificationEnabled;\n            return this;\n        }\n\n        Options setOwnPid(final String ownPid) {\n            this.ownPid = ownPid;\n            return this;\n        }\n\n        Map<String, Object> toProperties() {\n            final Map<String, Object> result = new HashMap<>();\n\n            result.put(\"keystore.path\", this.keystorePath.toString());\n            result.put(\"keystore.password\", this.keystorePassword);\n            result.put(\"crl.management.enabled\", this.crlManagerEnabled);\n            result.put(\"crl.update.interval\", this.crlUpdateInterval);\n            result.put(\"crl.update.interval.time.unit\", this.crlUpdateIntervalTimeUnit.name());\n            result.put(\"crl.check.interval\", this.crlCheckInterval);\n            result.put(\"crl.check.interval.time.unit\", this.crlCheckIntervalTimeUnit.name());\n            result.put(\"crl.urls\", this.crlUrls.toArray(new String[this.crlUrls.size()]));\n            this.crlStoreFile.ifPresent(p -> result.put(\"crl.store.path\", p.getAbsolutePath()));\n            result.put(\"verify.crl\", this.crlVerificationEnabled);\n            result.put(ConfigurationService.KURA_SERVICE_PID, this.ownPid);\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/src/test/java/org/eclipse/kura/core/keystore/util/CertificateUtilTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n * Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.core.keystore.util;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.NoSuchProviderException;\nimport java.security.SecureRandom;\nimport java.security.Security;\nimport java.security.cert.CertificateException;\nimport java.security.cert.TrustAnchor;\nimport java.security.cert.X509Certificate;\nimport java.security.spec.AlgorithmParameterSpec;\nimport java.security.spec.RSAKeyGenParameterSpec;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Set;\n\nimport org.apache.commons.io.IOUtils;\nimport org.bouncycastle.cert.X509CertificateHolder;\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\nimport org.bouncycastle.openssl.PEMParser;\nimport org.bouncycastle.operator.OperatorCreationException;\nimport org.bouncycastle.util.Store;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\npublic class CertificateUtilTest {\n\n    private static final String CERT_FILE_PATH = \"target/test-classes/cert\";\n\n    private Object pemObject;\n    private X509Certificate x509Certificate;\n    private List<X509Certificate> x509certificates;\n    private Set<TrustAnchor> trustAnchors;\n\n    private String pemString = \"\";\n\n    private Store<X509CertificateHolder> certHolderStore;\n\n    private KeyPair keyPair;\n\n    private X509Certificate[] certificateChain;\n\n    @BeforeClass\n    public static void initSecurity() {\n        Security.addProvider(new BouncyCastleProvider());\n    }\n\n    @Before\n    public void cleanUp() {\n        this.pemObject = null;\n        this.x509Certificate = null;\n        this.x509certificates = null;\n        this.trustAnchors = null;\n        this.pemString = \"\";\n        this.certHolderStore = null;\n        this.certificateChain = null;\n    }\n\n    @Test\n    public void shouldConvertPEMCertToX509Cert() {\n        givenCertificateInPEMObject(CERT_FILE_PATH);\n\n        whenIsConcertedToJavaX509();\n\n        thenIsX509Certificate();\n    }\n\n    @Test\n    public void shouldConvertCertificateToTrustAnchor() {\n        givenCertificateInPEMObject(CERT_FILE_PATH);\n        givenCertificateListWithSize(2);\n\n        whenIsConvertedToTrustAnchor();\n\n        thenTrusAnchorSetSizeIs(2);\n    }\n\n    @Test\n    public void shouldConvertPEMStringtoCertHolderStore() {\n        givenCertificateInPEMString(CERT_FILE_PATH);\n\n        whenIsConvertedToX509CertificateHolderStore();\n\n        thenStoreContainsCert();\n    }\n\n    @Test\n    public void shouldConvertX509CertificatetoPemString() {\n        givenCertificateInX509Format(CERT_FILE_PATH);\n\n        whenIsConvertedToPemString();\n\n        thenPemStringIsNotEmpty();\n    }\n\n    @Test\n    public void shouldGenerateCertificate() {\n\n        givenKeyPair(\"RSA\", new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4));\n\n        whenCertificateChainIsGeneratedWith(\"SHA256WITHRSA\", \"CN=foo\", getNotBeforeYesterday(), getNotAfterTomorrow());\n\n        thenCertificainChainIsNotEmpty();\n    }\n\n    private void thenCertificainChainIsNotEmpty() {\n        assertTrue(this.certificateChain.length > 0);\n    }\n\n    private void whenCertificateChainIsGeneratedWith(String signatureAlgorithm, String attributes, Date startDate,\n            Date endDate) {\n        try {\n            this.certificateChain = CertificateUtil.generateCertificateChain(this.keyPair, signatureAlgorithm,\n                    attributes, startDate, endDate);\n        } catch (OperatorCreationException | CertificateException e) {\n            e.printStackTrace();\n            fail();\n        }\n    }\n\n    private Date getNotBeforeYesterday() {\n        Calendar calendar = Calendar.getInstance();\n        calendar.add(Calendar.DATE, -1);\n\n        return calendar.getTime();\n    }\n\n    private Date getNotAfterTomorrow() {\n        Calendar calendar = Calendar.getInstance();\n\n        calendar.add(Calendar.DATE, +1);\n        return calendar.getTime();\n    }\n\n    private void givenKeyPair(String algorithm, AlgorithmParameterSpec spec) {\n        try {\n            KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm, \"BC\");\n            keyGen.initialize(spec, new SecureRandom());\n            this.keyPair = keyGen.generateKeyPair();\n        } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchProviderException e) {\n            e.printStackTrace();\n            fail();\n        }\n\n    }\n\n    private void thenPemStringIsNotEmpty() {\n        assertNotEquals(\"\", this.pemString);\n    }\n\n    private void whenIsConvertedToPemString() {\n        try {\n            this.pemString = CertificateUtil.x509CertificateToPem(x509Certificate);\n        } catch (IOException e) {\n            e.printStackTrace();\n            fail();\n        }\n    }\n\n    private void givenCertificateInX509Format(String certFilePath) {\n        try (InputStream is = new FileInputStream(certFilePath);\n                Reader r = new StringReader(IOUtils.toString(is, StandardCharsets.UTF_8));\n                PEMParser pemParser = new PEMParser(r);) {\n            this.pemObject = pemParser.readObject();\n            this.x509Certificate = CertificateUtil.toJavaX509Certificate(this.pemObject);\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail();\n        }\n\n    }\n\n    private void thenStoreContainsCert() {\n        assertTrue(this.certHolderStore.getMatches(null).size() > 0);\n    }\n\n    private void whenIsConvertedToX509CertificateHolderStore() {\n        try {\n            this.certHolderStore = CertificateUtil.toX509CertificateHolderStore(this.pemString);\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail();\n        }\n\n    }\n\n    private void thenTrusAnchorSetSizeIs(int size) {\n        assertEquals(size, trustAnchors.size());\n    }\n\n    private void whenIsConvertedToTrustAnchor() {\n        try {\n            this.trustAnchors = CertificateUtil.toTrustAnchor(this.x509certificates);\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail();\n        }\n    }\n\n    private void givenCertificateListWithSize(int size) {\n        this.x509certificates = new ArrayList<X509Certificate>();\n\n        for (int i = 0; i < size; ++i) {\n            try {\n                this.x509certificates.add(CertificateUtil.toJavaX509Certificate(this.pemObject));\n            } catch (Exception e) {\n                e.printStackTrace();\n                fail();\n            }\n        }\n    }\n\n    private void thenIsX509Certificate() {\n        assertTrue(this.x509Certificate instanceof java.security.cert.X509Certificate);\n    }\n\n    private void whenIsConcertedToJavaX509() {\n        try {\n            this.x509Certificate = CertificateUtil.toJavaX509Certificate(this.pemObject);\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail();\n        }\n    }\n\n    private void givenCertificateInPEMString(String filepath) {\n\n        try (InputStream is = new FileInputStream(filepath)) {\n            this.pemString = IOUtils.toString(is, StandardCharsets.UTF_8);\n        } catch (IOException e) {\n            e.printStackTrace();\n            fail();\n        }\n    }\n\n    private void givenCertificateInPEMObject(String filepath) {\n\n        try (InputStream is = new FileInputStream(filepath);\n                Reader r = new StringReader(IOUtils.toString(is, StandardCharsets.UTF_8));\n                PEMParser pemParser = new PEMParser(r);) {\n            this.pemObject = pemParser.readObject();\n        } catch (IOException e) {\n            e.printStackTrace();\n            fail();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/src/test/java/org/eclipse/kura/core/keystore/util/KeystoreUtilsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.keystore.util;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\nimport java.security.interfaces.DSAPublicKey;\nimport java.security.interfaces.ECPublicKey;\nimport java.security.interfaces.RSAPublicKey;\n\nimport org.bouncycastle.openssl.jcajce.JcaPEMWriter;\nimport org.junit.Test;\n\npublic class KeystoreUtilsTest {\n\n    private final String publicKeyDSA = \"-----BEGIN CERTIFICATE-----\\n\"\n            + \"MIIEjjCCBDmgAwIBAgIED6yGqzANBglghkgBZQMEAwIFADBJMQswCQYDVQQGEwJm\\n\"\n            + \"ZzEKMAgGA1UECBMBZTEKMAgGA1UEBxMBZDEKMAgGA1UEChMBYzEKMAgGA1UECxMB\\n\"\n            + \"YjEKMAgGA1UEAxMBYTAeFw0yMTA0MTkxNTAwMjVaFw0yMTA3MTgxNTAwMjVaMEkx\\n\"\n            + \"CzAJBgNVBAYTAmZnMQowCAYDVQQIEwFlMQowCAYDVQQHEwFkMQowCAYDVQQKEwFj\\n\"\n            + \"MQowCAYDVQQLEwFiMQowCAYDVQQDEwFhMIIDQjCCAjUGByqGSM44BAEwggIoAoIB\\n\"\n            + \"AQCPeTXZuarpv6vtiHrPSVG28y7FnjuvNxjo6sSWHz79NgbnQ1GpxBgzObgJ58Ku\\n\"\n            + \"HFObp0dbhdARrbi0eYd1SYRpXKwOjxSzNggooi/6JxEKPWKpk0U0CaD+aWxGWPhL\\n\"\n            + \"3SCBnDcJoBBXsZWtzQAjPbpUhLYpH51kjviDRIZ3l5zsBLQ0pqwudemYXeI9sCkv\\n\"\n            + \"wRGMn/qdgYHnM423krcw17njSVkvaAmYchU5Feo9a4tGU8YzRY+AOzKkwuDycpAl\\n\"\n            + \"bk4/ijsIOKHEUOThjBopo33fXqFD3ktm/wSQPtXPFiPhWNSHxgjpfyEc2B3KI8tu\\n\"\n            + \"OAdl+CLjQr5ITAV2OTlgHNZnAh0AuvaWpoV499/e5/pnyXfHhe8ysjO65YDAvNVp\\n\"\n            + \"XQKCAQAWplxYIEhQcE51AqOXVwQNNNo6NHjBVNTkpcAtJC7gT5bmHkvQkEq9rI83\\n\"\n            + \"7rHgnzGC0jyQQ8tkL4gAQWDt+coJsyB2p5wypifyRz6Rh5uixOdEvSCBVEy1W4As\\n\"\n            + \"No0fqD7UielOD6BojjJCilx4xHjGjQUntxyaOrsLC+EsRGiWOefTznTbEBplqiuH\\n\"\n            + \"9kxoJts+xy9LVZmDS7TtsC98kOmkltOlXVNb6/xF1PYZ9j897buHOSXC8iTgdzEp\\n\"\n            + \"baiH7B5HSPh++1/et1SEMWsiMt7lU92vAhErDR8C2jCXMiT+J67ai51LKSLZuovj\\n\"\n            + \"ntnhA6Y8UoELxoi34u1DFuHvF9veA4IBBQACggEAbsIJCF7b7OvHijStKh0/8yFd\\n\"\n            + \"sxCmqIM2h7jfShrbHaJiyCIjuW1HzuCovFKMM+2yoKu+Hi7FsGxW/bkxZ/aY1KFO\\n\"\n            + \"yliphnEvO70l5tKvbJEhIc6Sp1RxC/w8mX1nuzEt0DQdUXsp6Hpi2WB/onvreFZL\\n\"\n            + \"+Utq4wYgxWaG+2UvYTHDk4lGPpSoFJI6SosUK8WnxLXgZ13N0ayZA5bsaI8taMOV\\n\"\n            + \"ypbmX+iJvsITKnuxXNV2g49Huy2XDSwNn3l1x8hGH8Eici8IXT1l4zo5JDqWmC1E\\n\"\n            + \"3YtdEcVbgGnIvOqWdyZbbeIL/qVBAb8yK+V9HrPvx27A9wMnDSJczPq4PwKpOaMh\\n\"\n            + \"MB8wHQYDVR0OBBYEFLEqPO2kZodX+JknKTLcZ1uSE+fLMA0GCWCGSAFlAwQDAgUA\\n\"\n            + \"A0AAMD0CHGVZgxZ1FdxwlavGNeEi/y6QzgcN11t0JM8biJQCHQCIV3ovl7ZAo8jU\\n\" + \"35V0srUI0ojei0AXCR9+2IH5\\n\"\n            + \"-----END CERTIFICATE-----\";\n    private static String privateKeyDSA = \"-----BEGIN PRIVATE KEY-----\\n\"\n            + \"MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdS\\n\"\n            + \"PO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVCl\\n\"\n            + \"pJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith\\n\"\n            + \"1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7L\\n\"\n            + \"vKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3\\n\"\n            + \"zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImo\\n\"\n            + \"g9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUaS0Ob0O61UNMULqh2sm52UN4X8g=\\n\" + \"-----END PRIVATE KEY-----\";\n    private static String publicKeyRSA = \"-----BEGIN CERTIFICATE-----\\n\"\n            + \"MIICLDCCAZWgAwIBAgIEE9H3JDANBgkqhkiG9w0BAQsFADBJMQswCQYDVQQGEwI1\\n\"\n            + \"NjEKMAgGA1UECBMBNTEKMAgGA1UEBxMBNDEKMAgGA1UEChMBMzEKMAgGA1UECxMB\\n\"\n            + \"MjEKMAgGA1UEAxMBMTAeFw0yMTA0MTkxNTA2MzZaFw0yMTA3MTgxNTA2MzZaMEkx\\n\"\n            + \"CzAJBgNVBAYTAjU2MQowCAYDVQQIEwE1MQowCAYDVQQHEwE0MQowCAYDVQQKEwEz\\n\"\n            + \"MQowCAYDVQQLEwEyMQowCAYDVQQDEwExMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\\n\"\n            + \"iQKBgQCD5T+X1VcCJ7U3UEfFXqmB8RUOhgqvEaZZBa+nf444S0J1HM08AZ3NOOPK\\n\"\n            + \"Bj/imA0EDGWSuoB+1MahaCl0zYrxshFTOajngcEfndGs4L0IkBuavGtfMtASyOTb\\n\"\n            + \"dKcYGL+OQWaQ/+k7HwDye+TLKJWBMHxxQcvYUF6tyYoUUf43hQIDAQABoyEwHzAd\\n\"\n            + \"BgNVHQ4EFgQUxmYO2XPbCCi9OjzFSuJdgcVNgEowDQYJKoZIhvcNAQELBQADgYEA\\n\"\n            + \"CETsKRd5/MdrnCqBskN865hdgCLlCxrE1Jw+R9VFThlbfhc4As7Luj5deDO9Usvg\\n\"\n            + \"SpVEVljt+AdBm1kp04Ai8PW+UoFJqrfH9jkvGsr2N20eQxomrEnLKXeLlcU/meNf\\n\"\n            + \"rV5gD25tKr0nNVToIzjQV5bQmmsZQx5XnAuLzYTsRjw=\\n\" + \"-----END CERTIFICATE-----\";\n    private static String privateKeyRSA = \"-----BEGIN PRIVATE KEY-----\\n\"\n            + \"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCCcZ1Nu9AVYKJd\\n\"\n            + \"p6gcdObxCiofeOVbJv3Ws19JVa6PGTSgREFy5c97/k+SsSBhHAFp1n3738E2gdxD\\n\"\n            + \"auftKpmV3ZZ93rEQQ+Db71PiyFlrEEtcDE//14EH2jaHBIghxqWmgvWu0e8pca4u\\n\"\n            + \"xnmOOJAPCabNYLLs4pnTh9xJn+B+Mdz+/NNj/C7BV53W2nAcsdVqpbmLjfCrDSd/\\n\"\n            + \"hgel8AoAbdjiRGkYHkgvEuztjx01pO2iGAgpkctigdxF/ygwwOOxcPASw/55ZjSE\\n\"\n            + \"gMZx7PMyxEiIL7jgt/cgG68QhlQ3neYfJ9cd+gLvn1g1fwsGtGpw3Mh3dgs6DQkr\\n\"\n            + \"8HMQW0bpAgMBAAECggEAL2IR3/C/L2TA1gBWwq98TEaC8pe5yJirUFgr3rmvBPAE\\n\"\n            + \"+8qPc6si6UmBoimRN3Uy1j1B2kJ3LtORLTQiNzZoP9YUGnjQHLZrcbjH4fMg+BEd\\n\"\n            + \"LrySOr8PccjEUdtFj+9WsNuVXwGHPKi8uuUBtrW5Lp006BmeJQpTElGhpWTb6Tqy\\n\"\n            + \"OcNceNz+oP1N3AZ3Mnf6Aq6GuvD4QeGMVEiosHPxMqY0eddNK672zq3A0o1NPA9z\\n\"\n            + \"yaVt9UK7SZ6/yOKYrAAM/2iLHmNbrYRer567hgg2B1LGJCRSdB/c34u6lTnPo+Ai\\n\"\n            + \"olQahQNFhiJKTXr2kK9WgS6tWXhqUqsVLUCug4mDAQKBgQDKLbhidAYClyOKJW7U\\n\"\n            + \"GsbM5dmQV80NsnsN3qphKZDTEMinhs3N4oknhi+mZPeyge4MY73BiHXhnMcUkfhw\\n\"\n            + \"nbhRNhrkZTt18S6rTzEp/vDDx+ZosxRKYXmPyuDDWDmvG6ocRyOLIgoYhT0kPQ7a\\n\"\n            + \"oXQkpFPjBq1UmqNOcUwEpNG2sQKBgQClKzyAopsjWNptBQPo/j/PN24uThpdd3yX\\n\"\n            + \"NenmLZsYJyloKDbOGzEXpuyzdtNAiIVDsQ8RzN5lkF6xVvXnOlSA2gmEc8KJmRl8\\n\"\n            + \"/gWzPRHHHNR7QUiGmg9QThrUp2l6DiAm/IcuL0btj99kQa2XcLGlTohwWpdVySSx\\n\"\n            + \"abDX7pSRuQKBgH/jy+77VZHt6R1J8IFbLsYN30HfSGaRsCVl5IDxuhrJUyQlsam6\\n\"\n            + \"0uediibHV6gjaGGN9kql92tvsL7iVzVlj2JPx1MSdjp1BgB3Z7IZAlPV73nrTbp/\\n\"\n            + \"TlYXD3aCKHsMFN8uYN1x+tDn93Uk6nCCEOXczPOfFaWe7A6CvINzfvUBAoGAUJEm\\n\"\n            + \"khi/VB6jbUpk/eIHfiyrsiqm8bC3NYs27PCSFtYDfKshEKhy6faiv2fW5EOzvbFA\\n\"\n            + \"iI5GbYRerGKe0IvDbJbuzY0p97SWmkHOxf+kDFwjyXuuxPmhPqraq6B98uuxA1Nr\\n\"\n            + \"HTwyfO8RKPZglt6ByQDlzOhjqZTUMTY87ReToQECgYBKdX3Idr4zvODkXIlG852C\\n\"\n            + \"o135W+7AWr+dYRLx1FcvgMU9SbF9cwUU5Zutbrv+Kl8xGPyfx09MJ6BNxTkkr09J\\n\"\n            + \"BpbrbOZsUDjMjojyQYL4Ll9rLohk+Pq73xXJjtTRIXZVXJg27pEEqzcVB4o9vgli\\n\" + \"yzOqhyTKM9JP7Uda6Fv6DA==\\n\"\n            + \"-----END PRIVATE KEY-----\";\n    private static String publicKeyEC = \"-----BEGIN CERTIFICATE-----\\n\"\n            + \"MIIBqjCCAU2gAwIBAgIELVNe7DAMBggqhkjOPQQDAgUAMEkxCzAJBgNVBAYTAnRy\\n\"\n            + \"MQowCAYDVQQIEwE1MQowCAYDVQQHEwE0MQowCAYDVQQKEwEzMQowCAYDVQQLEwEy\\n\"\n            + \"MQowCAYDVQQDEwExMB4XDTIxMDQxOTE1MDM0M1oXDTIxMDcxODE1MDM0M1owSTEL\\n\"\n            + \"MAkGA1UEBhMCdHIxCjAIBgNVBAgTATUxCjAIBgNVBAcTATQxCjAIBgNVBAoTATMx\\n\"\n            + \"CjAIBgNVBAsTATIxCjAIBgNVBAMTATEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC\\n\"\n            + \"AARdxv7a46GcCcGrbbl9EolhfvKPJN4q8vfX8soAMFQ/7AOuKkz/2voFJ5kMK+gK\\n\"\n            + \"31kbILrPnZa8IFmOB0d6qwLToyEwHzAdBgNVHQ4EFgQU0K3b/8VqxtBxW2dD81CB\\n\"\n            + \"x9PyGUcwDAYIKoZIzj0EAwIFAANJADBGAiEAwN0V4/m/MAtEModdE27xB2bMC13i\\n\"\n            + \"7KN7y088ENIykpICIQCjE9XItmBa405Bki9xe+n7T0eFhoCzAPk6lceZLzeFTQ==\\n\" + \"-----END CERTIFICATE-----\";\n\n    @Test\n    public void createCertificateDSAEntryTest() throws CertificateException {\n        TrustedCertificateEntry entry = KeystoreUtils.createCertificateEntry(publicKeyDSA);\n\n        assertNotNull(entry);\n        assertEquals(\"DSA\", entry.getTrustedCertificate().getPublicKey().getAlgorithm());\n        assertEquals(2048,\n                ((DSAPublicKey) entry.getTrustedCertificate().getPublicKey()).getParams().getP().bitLength());\n        assertEquals(\"X.509\", entry.getTrustedCertificate().getType());\n\n    }\n\n    @Test\n    public void createCertificateRSAEntryTest() throws CertificateException {\n        TrustedCertificateEntry entry = KeystoreUtils.createCertificateEntry(publicKeyRSA);\n\n        assertNotNull(entry);\n        assertEquals(\"RSA\", entry.getTrustedCertificate().getPublicKey().getAlgorithm());\n        assertEquals(1024, ((RSAPublicKey) entry.getTrustedCertificate().getPublicKey()).getModulus().bitLength());\n        assertEquals(\"X.509\", entry.getTrustedCertificate().getType());\n\n    }\n\n    @Test\n    public void createCertificateECEntryTest() throws CertificateException {\n        TrustedCertificateEntry entry = KeystoreUtils.createCertificateEntry(publicKeyEC);\n\n        assertNotNull(entry);\n        assertEquals(\"EC\", entry.getTrustedCertificate().getPublicKey().getAlgorithm());\n        assertEquals(256,\n                ((ECPublicKey) entry.getTrustedCertificate().getPublicKey()).getParams().getOrder().bitLength());\n        assertEquals(\"X.509\", entry.getTrustedCertificate().getType());\n\n    }\n\n    @Test\n    public void createPrivateKeyDSAEntryTest() throws IOException, GeneralSecurityException {\n        PrivateKeyEntry entry = KeystoreUtils.createPrivateKey(privateKeyDSA, publicKeyDSA);\n\n        assertNotNull(entry);\n        assertEquals(\"DSA\", entry.getCertificate().getPublicKey().getAlgorithm());\n        assertEquals(2048, ((DSAPublicKey) entry.getCertificate().getPublicKey()).getParams().getP().bitLength());\n        assertEquals(\"X.509\", entry.getCertificate().getType());\n        assertEquals(\"DSA\", entry.getPrivateKey().getAlgorithm());\n    }\n\n    @Test\n    public void createPrivateKeyRSAEntryTest() throws IOException, GeneralSecurityException {\n        PrivateKeyEntry entry = KeystoreUtils.createPrivateKey(privateKeyRSA, publicKeyRSA);\n\n        assertNotNull(entry);\n        assertEquals(\"RSA\", entry.getCertificate().getPublicKey().getAlgorithm());\n        assertEquals(1024, ((RSAPublicKey) entry.getCertificate().getPublicKey()).getModulus().bitLength());\n        assertEquals(\"X.509\", entry.getCertificate().getType());\n        assertEquals(\"RSA\", entry.getPrivateKey().getAlgorithm());\n    }\n\n    @Test\n    public void shouldDecodeSingleCertificate() throws CertificateException, IOException {\n        givenCertificateToBeDecoded(publicKeyDSA);\n\n        whenCertificatesAreDecoded();\n\n        thenDecodedCertificateCountIs(1);\n        thenDecodedCertPEMEncodeingEquals(0, publicKeyDSA);\n    }\n\n    @Test\n    public void shouldDecodeMultipleCertificate() throws CertificateException, IOException {\n        givenCertificateToBeDecoded(publicKeyDSA);\n        givenCertificateToBeDecoded(publicKeyRSA);\n        givenCertificateToBeDecoded(publicKeyEC);\n\n        whenCertificatesAreDecoded();\n\n        thenDecodedCertificateCountIs(3);\n        thenDecodedCertPEMEncodeingEquals(0, publicKeyDSA);\n        thenDecodedCertPEMEncodeingEquals(1, publicKeyRSA);\n        thenDecodedCertPEMEncodeingEquals(2, publicKeyEC);\n    }\n\n    private String toBeDecoded = \"\";\n    private X509Certificate[] result;\n\n    private void givenCertificateToBeDecoded(final String cert) {\n        toBeDecoded += cert + '\\n';\n    }\n\n    private void whenCertificatesAreDecoded() throws CertificateException {\n        this.result = KeystoreUtils.parsePublicCertificates(toBeDecoded);\n    }\n\n    private void thenDecodedCertificateCountIs(final int expectedCount) {\n        assertEquals(expectedCount, result.length);\n    }\n\n    private void thenDecodedCertPEMEncodeingEquals(final int index, final String encoded) throws IOException {\n        final String resultPEM;\n\n        try (final StringWriter stringWriter = new StringWriter();\n                final JcaPEMWriter writer = new JcaPEMWriter(stringWriter);) {\n            writer.writeObject(result[index]);\n            writer.flush();\n            resultPEM = stringWriter.toString();\n        }\n\n        assertEquals(encoded + '\\n', resultPEM);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/src/test/resources/cert",
    "content": "-----BEGIN CERTIFICATE-----\nMIICezCCAjigAwIBAgIESvucGTALBgcqhkjOOAQDBQAwDzENMAsGA1UEAxMEa3Vy\nYTAeFw0xNzA4MjQxNDMxMjNaFw0zMTA1MDMxNDMxMjNaMA8xDTALBgNVBAMTBGt1\ncmEwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I8\n70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk\nn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX\nKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgQD34aCF1ps93su8\nq1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fP\nCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD\n3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhAACgYAaqPBZ1sLviuLYcBbVYhtJRUB1\nFBrCxMut8sWDAFCEaZ/gLuOZP7Odw9ifuDLkfF9iDi20MNUbojgFLg1u71IOLUtW\n6+0vICqfZRai7i2kNHM82J1TLaS4QYQzTDGUxs0xAOSaidyBlGPvwrzTQixIK5Ph\nH0VBeEr9a2RIbaHgOKMhMB8wHQYDVR0OBBYEFJe86lxIv5UYsZ/uGcIdewCPUeaj\nMAsGByqGSM44BAMFAAMwADAtAhUAiw2QQPqB75io+p1cxQfMQW4Z/6oCFEA7AGYv\nkLQlC6I0o6bJqtKRlwar\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.keystore.test/src/test/resources/log4j.properties",
    "content": "log4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.ssl.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.ssl.test\nBundle-SymbolicName: org.eclipse.kura.core.ssl.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.core.crypto,\n org.eclipse.kura.core.testutil,\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.slf4j;version=\"1.6.4\"\nFragment-Host: org.eclipse.kura.core;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.ssl.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.ssl.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.ssl.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.ssl.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n    \n    <build>\n       <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.ssl.test/src/test/java/org/eclipse/kura/core/ssl/ConnectionSslOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport static org.junit.Assert.*;\nimport static org.mockito.Mockito.*;\n\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimport org.junit.runners.MethodSorters;\n\n@FixMethodOrder(MethodSorters.NAME_ASCENDING)\npublic class ConnectionSslOptionsTest {\n\n    @Test\n    public void testConnectionSslOptions() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        assertEquals(serviceOptions, sslOptions.getSslManagerOpts());\n    }\n\n    @Test\n    public void testSetProtocolNull() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        when(serviceOptions.getSslProtocol()).thenReturn(\"p1\");\n        sslOptions.setProtocol(null);\n        assertEquals(\"p1\", sslOptions.getProtocol());\n    }\n\n    @Test\n    public void testSetProtocolEmpty() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        when(serviceOptions.getSslProtocol()).thenReturn(\"p2\");\n        sslOptions.setProtocol(\"\");\n        assertEquals(\"p2\", sslOptions.getProtocol());\n    }\n\n    @Test\n    public void testSetProtocolWhitespace() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        when(serviceOptions.getSslProtocol()).thenReturn(\"p3\");\n        sslOptions.setProtocol(\" \\t\\r\\b\\f\");\n        assertEquals(\"p3\", sslOptions.getProtocol());\n    }\n\n    @Test\n    public void testSetProtocolNonEmpty() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        sslOptions.setProtocol(\"p4\");\n        assertEquals(\"p4\", sslOptions.getProtocol());\n    }\n\n    @Test\n    public void testSetCiphersNull() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        when(serviceOptions.getSslCiphers()).thenReturn(\"c1\");\n        sslOptions.setCiphers(null);\n        assertEquals(\"c1\", sslOptions.getCiphers());\n    }\n\n    @Test\n    public void testSetCiphersEmpty() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        when(serviceOptions.getSslCiphers()).thenReturn(\"c2\");\n        sslOptions.setCiphers(\"\");\n        assertEquals(\"c2\", sslOptions.getCiphers());\n    }\n\n    @Test\n    public void testSetCiphersWhitespace() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        when(serviceOptions.getSslCiphers()).thenReturn(\"c3\");\n        sslOptions.setCiphers(\" \\t\\r\\b\\f\");\n        assertEquals(\"c3\", sslOptions.getCiphers());\n    }\n\n    @Test\n    public void testSetCiphersNonEmpty() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        sslOptions.setCiphers(\"c4\");\n\n        assertEquals(\"c4\", sslOptions.getCiphers());\n    }\n\n    @Test\n    public void testSetTrustStoreNonEmpty() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        sslOptions.setTrustStore(\"ts4\");\n        assertEquals(\"ts4\", sslOptions.getTrustStore());\n    }\n\n    @Test\n    public void testSetKeyStoreNonEmpty() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        sslOptions.setKeyStore(\"ks4\");\n        assertEquals(\"ks4\", sslOptions.getKeyStore());\n    }\n\n    @Test\n    public void testSetKeyStorePassword() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        char[] password = \"keyStorePassword\".toCharArray();\n        sslOptions.setKeyStorePassword(password);\n        assertArrayEquals(password, sslOptions.getKeyStorePassword());\n    }\n\n    @Test\n    public void testSetAlias() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        sslOptions.setAlias(\"alias\");\n        assertEquals(\"alias\", sslOptions.getAlias());\n    }\n\n    @Test\n    public void testSetHostnameVerification() {\n        SslManagerServiceOptions serviceOptions = mock(SslManagerServiceOptions.class);\n        ConnectionSslOptions sslOptions = new ConnectionSslOptions(serviceOptions);\n\n        sslOptions.setHostnameVerification(true);\n        assertEquals(true, sslOptions.getHostnameVerification());\n\n        sslOptions.setHostnameVerification(false);\n        assertEquals(false, sslOptions.getHostnameVerification());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.ssl.test/src/test/java/org/eclipse/kura/core/ssl/SSLSocketFactoryWrapperTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.net.InetAddress;\nimport java.net.Socket;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLParameters;\nimport javax.net.ssl.SSLSocket;\nimport javax.net.ssl.SSLSocketFactory;\n\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimport org.junit.runners.MethodSorters;\n\n@FixMethodOrder(MethodSorters.NAME_ASCENDING)\npublic class SSLSocketFactoryWrapperTest {\n\n    @Test\n    public void testSSLSocketFactoryWrapper() throws NoSuchFieldException {\n        SSLSocketFactory factory = mock(SSLSocketFactory.class);\n        SSLSocketFactoryWrapper wrapper = new SSLSocketFactoryWrapper(factory, \"ciphers\", false);\n\n        assertEquals(factory, TestUtil.getFieldValue(wrapper, \"sslsf\"));\n        assertEquals(\"ciphers\", TestUtil.getFieldValue(wrapper, \"ciphers\"));\n        assertEquals(false, TestUtil.getFieldValue(wrapper, \"hostnameVerification\"));\n    }\n\n    @Test\n    public void testGetDefaultCipherSuites() {\n        SSLSocketFactory factory = mock(SSLSocketFactory.class);\n        SSLSocketFactoryWrapper wrapper = new SSLSocketFactoryWrapper(factory, \"ciphers\", false);\n\n        String[] defaultCipherSuites = { \"cipher1\", \"cipher2\" };\n        when(factory.getDefaultCipherSuites()).thenReturn(defaultCipherSuites);\n\n        assertArrayEquals(defaultCipherSuites, wrapper.getDefaultCipherSuites());\n    }\n\n    @Test\n    public void testGetSupportedCipherSuites() {\n        SSLSocketFactory factory = mock(SSLSocketFactory.class);\n        SSLSocketFactoryWrapper wrapper = new SSLSocketFactoryWrapper(factory, \"ciphers\", false);\n\n        String[] sSupportedCipherSuites = { \"cipher1\", \"cipher2\" };\n        when(factory.getSupportedCipherSuites()).thenReturn(sSupportedCipherSuites);\n\n        assertArrayEquals(sSupportedCipherSuites, wrapper.getSupportedCipherSuites());\n    }\n\n    @Test\n    public void testCreateSocket() throws IOException {\n        SSLSocketFactory factory = mock(SSLSocketFactory.class);\n        SSLSocketFactoryWrapper wrapper = new SSLSocketFactoryWrapper(factory,\n                \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\", true);\n\n        SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();\n        socket.setEnabledProtocols(new String[] { \"TLSv1.1\", \"SSLv2Hello\", \"TLSv1.2\" });\n        when(factory.createSocket()).thenReturn(socket);\n\n        Socket resultSocket = wrapper.createSocket();\n        assertTrue(resultSocket instanceof SSLSocket);\n\n        SSLParameters resultParameters = ((SSLSocket) resultSocket).getSSLParameters();\n        String[] expectedProtocols = { \"TLSv1.1\", \"TLSv1.2\" };\n        String[] expectedCiphers = { \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\",\n                \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\" };\n        assertArrayEquals(expectedProtocols, resultParameters.getProtocols());\n        assertEquals(\"HTTPS\", resultParameters.getEndpointIdentificationAlgorithm());\n        assertArrayEquals(expectedCiphers, resultParameters.getCipherSuites());\n\n        assertTrue(resultSocket.getTcpNoDelay());\n    }\n\n    @Test\n    public void testCreateSocketByHostAndPort() throws IOException, NoSuchAlgorithmException {\n        SSLContext sslCtx = SSLContext.getDefault();\n        SSLSocketFactory factory = sslCtx.getSocketFactory();\n        SSLSocketFactoryWrapper wrapper = new SSLSocketFactoryWrapper(factory,\n                \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\", true);\n\n        InetAddress address = InetAddress.getByName(\"google.com\");\n        Socket resultSocket = wrapper.createSocket(address, 443);\n        assertTrue(resultSocket instanceof SSLSocket);\n\n        SSLParameters resultParameters = ((SSLSocket) resultSocket).getSSLParameters();\n\n        String[] expectedCiphers = { \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\",\n                \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\" };\n        List<String> expectedProtocols = Arrays.asList(new String[] { \"TLSv1.3\", \"TLSv1.2\", \"TLSv1.1\", \"TLSv1\" });\n        List<String> resultProtocols = Arrays.asList(resultParameters.getProtocols());\n        assertTrue(expectedProtocols.size() >= resultProtocols.size() && expectedProtocols.containsAll(resultProtocols));\n        assertEquals(\"HTTPS\", resultParameters.getEndpointIdentificationAlgorithm());\n        assertArrayEquals(expectedCiphers, resultParameters.getCipherSuites());\n\n        assertTrue(resultSocket.getTcpNoDelay());\n\n        resultSocket.close();\n    }\n\n    @Test\n    public void testCreateSocketNoHostnameVerification() throws IOException, NoSuchAlgorithmException {\n        SSLContext sslCtx = SSLContext.getDefault();\n        SSLSocketFactory factory = sslCtx.getSocketFactory();\n        SSLSocketFactoryWrapper wrapper = new SSLSocketFactoryWrapper(factory,\n                \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\", false);\n\n        Socket resultSocket = wrapper.createSocket();\n        assertTrue(resultSocket instanceof SSLSocket);\n\n        SSLParameters resultParameters = ((SSLSocket) resultSocket).getSSLParameters();\n\n        String[] expectedCiphers = { \"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256\",\n                \"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256\" };\n\n        List<String> expectedProtocols = Arrays.asList(new String[] { \"TLSv1.3\", \"TLSv1.2\", \"TLSv1.1\", \"TLSv1\" });\n        List<String> resultProtocols = Arrays.asList(resultParameters.getProtocols());\n        assertTrue(expectedProtocols.size() >= resultProtocols.size() && expectedProtocols.containsAll(resultProtocols));\n        assertNotEquals(\"HTTPS\", resultParameters.getEndpointIdentificationAlgorithm());\n        assertArrayEquals(expectedCiphers, resultParameters.getCipherSuites());\n\n        assertTrue(resultSocket.getTcpNoDelay());\n    }\n\n    @Test\n    public void testCreateSocketNullCyphers() throws IOException, NoSuchAlgorithmException {\n        SSLContext sslCtx = SSLContext.getDefault();\n        SSLSocketFactory factory = sslCtx.getSocketFactory();\n        SSLSocketFactoryWrapper wrapper = new SSLSocketFactoryWrapper(factory, null, true);\n\n        Socket resultSocket = wrapper.createSocket();\n        assertTrue(resultSocket instanceof SSLSocket);\n\n        SSLParameters resultParameters = ((SSLSocket) resultSocket).getSSLParameters();\n        List<String> expectedProtocols = Arrays.asList(new String[] { \"TLSv1.3\", \"TLSv1.2\", \"TLSv1.1\", \"TLSv1\" });\n        List<String> resultProtocols = Arrays.asList(resultParameters.getProtocols());\n        assertTrue(expectedProtocols.size() >= resultProtocols.size() && expectedProtocols.containsAll(resultProtocols));\n        assertEquals(\"HTTPS\", resultParameters.getEndpointIdentificationAlgorithm());\n        assertNotEquals(0, resultParameters.getCipherSuites().length);\n\n        assertTrue(resultSocket.getTcpNoDelay());\n    }\n\n    @Test\n    public void testCreateSocketEmptyCyphers() throws IOException, NoSuchAlgorithmException {\n        SSLContext sslCtx = SSLContext.getDefault();\n        SSLSocketFactory factory = sslCtx.getSocketFactory();\n        SSLSocketFactoryWrapper wrapper = new SSLSocketFactoryWrapper(factory, \"\", true);\n\n        Socket resultSocket = wrapper.createSocket();\n        assertTrue(resultSocket instanceof SSLSocket);\n\n        SSLParameters resultParameters = ((SSLSocket) resultSocket).getSSLParameters();\n        List<String> expectedProtocols = Arrays.asList(new String[] { \"TLSv1.3\", \"TLSv1.2\", \"TLSv1.1\", \"TLSv1\" });\n        List<String> resultProtocols = Arrays.asList(resultParameters.getProtocols());\n        assertTrue(expectedProtocols.size() >= resultProtocols.size() && expectedProtocols.containsAll(resultProtocols));\n        assertEquals(\"HTTPS\", resultParameters.getEndpointIdentificationAlgorithm());\n        assertNotEquals(0, resultParameters.getCipherSuites().length);\n\n        assertTrue(resultSocket.getTcpNoDelay());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.ssl.test/src/test/java/org/eclipse/kura/core/ssl/SslManagerServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.ssl;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.math.BigInteger;\nimport java.security.GeneralSecurityException;\nimport java.security.Key;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLSocketFactory;\nimport javax.security.auth.x500.X500Principal;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.security.keystore.KeystoreChangedEvent;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.eclipse.kura.ssl.SslServiceListener;\nimport org.junit.Before;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.service.component.ComponentContext;\n\npublic class SslManagerServiceImplTest {\n\n    private static final String CERT_FILE_PATH = \"target/test-classes/cert\";\n    private static final String STORE_PATH = \"target/key.store\";\n    private static final String STORE_PASS = \"pass\";\n\n    private KeyStore store;\n\n    @Before\n    public void setupDefaultKeystore()\n            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {\n        // create a new keystore each time the tests should run\n\n        this.store = KeyStore.getInstance(\"jks\");\n\n        this.store.load(null, null);\n\n        // KeyPairGenerator gen = KeyPairGenerator.getInstance(\"DSA\");\n        // gen.initialize(1024);\n        // KeyPair pair = gen.generateKeyPair();\n        // Key key = pair.getPrivate();\n        //\n        // InputStream is = new FileInputStream(CERT_FILE_PATH);\n        // Certificate certificate = CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        // is.close();\n        //\n        // Certificate[] chain = { certificate };\n        //\n        // this.store.setKeyEntry(DEFAULT_KEY_ALIAS, key, STORE_PASS.toCharArray(), chain);\n\n        try (OutputStream os = new FileOutputStream(STORE_PATH)) {\n            this.store.store(os, STORE_PASS.toCharArray());\n        }\n    }\n\n    // @Test(expected = KeyStoreException.class)\n    // public void testActivateNoKeystore()\n    // throws InterruptedException, NoSuchFieldException, GeneralSecurityException, IOException {\n    // SslManagerServiceImpl svc = new SslManagerServiceImpl();\n    //\n    // ComponentContext ccMock = mock(ComponentContext.class);\n    //\n    // BundleContext bcMock = mock(BundleContext.class);\n    // when(ccMock.getBundleContext()).thenReturn(bcMock);\n    //\n    // Map<String, Object> properties = new HashMap<>();\n    // properties.put(\"ssl.default.protocol\", \"TLSv1\");\n    // properties.put(\"ssl.default.trustStore\", \"target/key1.store\");\n    // properties.put(\"ssl.hostname.verification\", \"true\");\n    // properties.put(\"ssl.keystore.password\", \"changeit\");\n    //\n    // svc.activate(ccMock, properties);\n    //\n    // verify(cs, times(0)).getKeyStorePassword(\"target/key1.store\");\n    //\n    // svc.getSSLSocketFactory();\n    // }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void testGetSSLSocketFactory()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        // test preparation of an SslSocketFactory\n        setupDefaultKeystore();\n\n        SslServiceListeners listener = new SslServiceListeners(null) {\n\n            @Override\n            public void onConfigurationUpdated() {\n                // OK\n            }\n        };\n\n        ComponentContext ccMock = mock(ComponentContext.class);\n\n        BundleContext bcMock = mock(BundleContext.class);\n        when(ccMock.getBundleContext()).thenReturn(bcMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"ssl.default.protocol\", \"TLSv1\");\n        properties.put(\"ssl.hostname.verification\", \"true\");\n\n        KeystoreService keystoreService = mock(KeystoreService.class);\n        when(keystoreService.getKeyStore()).thenReturn(store);\n\n        SslManagerServiceImpl svc = new SslManagerServiceImpl(ccMock, properties);\n        svc.setKeystoreService(keystoreService, Collections.singletonMap(\"kura.service.pid\", \"foo\"));\n\n        TestUtil.setFieldValue(svc, \"sslServiceListeners\", listener);\n\n        SSLSocketFactory factory = svc.getSSLSocketFactory();\n\n        Map<ConnectionSslOptions, SSLContext> sslContexts = (Map<ConnectionSslOptions, SSLContext>) TestUtil\n                .getFieldValue(svc, \"sslContexts\");\n\n        assertNotNull(factory);\n        assertEquals(1, sslContexts.size());\n        assertEquals(factory, sslContexts.values().iterator().next().getSocketFactory());\n\n        svc.updated(properties);\n\n        Map<ConnectionSslOptions, SSLContext> updatedSslContexts = (Map<ConnectionSslOptions, SSLContext>) TestUtil\n                .getFieldValue(svc, \"sslContexts\");\n        assertNotNull(updatedSslContexts);\n        assertEquals(0, updatedSslContexts.size());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void testSSLSocketFactoryCacheCleanedAfterSet()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        // test preparation of an SslSocketFactory\n        setupDefaultKeystore();\n\n        SslServiceListener listener = () -> {\n        };\n\n        ComponentContext ccMock = mock(ComponentContext.class);\n\n        BundleContext bcMock = mock(BundleContext.class);\n        when(ccMock.getBundleContext()).thenReturn(bcMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"ssl.default.protocol\", \"TLSv1\");\n        properties.put(\"ssl.hostname.verification\", \"true\");\n\n        KeystoreService keystoreService = mock(KeystoreService.class);\n        when(keystoreService.getKeyStore()).thenReturn(store);\n\n        SslManagerServiceImpl svc = new SslManagerServiceImpl(ccMock, properties);\n        svc.setKeystoreService(keystoreService, Collections.singletonMap(\"kura.service.pid\", \"foo\"));\n\n        TestUtil.setFieldValue(svc, \"sslServiceListeners\", listener);\n\n        SSLSocketFactory factory = svc.getSSLSocketFactory();\n\n        Map<ConnectionSslOptions, SSLContext> sslContexts = (Map<ConnectionSslOptions, SSLContext>) TestUtil\n                .getFieldValue(svc, \"sslContexts\");\n\n        assertNotNull(factory);\n        assertEquals(1, sslContexts.size());\n        assertEquals(factory, sslContexts.values().iterator().next().getSocketFactory());\n\n        svc.setKeystoreService(keystoreService, Collections.singletonMap(\"kura.service.pid\", \"foo\"));\n\n        Map<ConnectionSslOptions, SSLContext> updatedSslContexts = (Map<ConnectionSslOptions, SSLContext>) TestUtil\n                .getFieldValue(svc, \"sslContexts\");\n\n        assertEquals(0, updatedSslContexts.size());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void testSSLSocketFactoryCacheCleanedAfterUnset()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        // test preparation of an SslSocketFactory\n        setupDefaultKeystore();\n\n        SslServiceListener listener = () -> {\n        };\n\n        ComponentContext ccMock = mock(ComponentContext.class);\n\n        BundleContext bcMock = mock(BundleContext.class);\n        when(ccMock.getBundleContext()).thenReturn(bcMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"ssl.default.protocol\", \"TLSv1\");\n        properties.put(\"ssl.hostname.verification\", \"true\");\n\n        KeystoreService keystoreService = mock(KeystoreService.class);\n        when(keystoreService.getKeyStore()).thenReturn(store);\n\n        SslManagerServiceImpl svc = new SslManagerServiceImpl(ccMock, properties);\n        svc.setKeystoreService(keystoreService, Collections.singletonMap(\"kura.service.pid\", \"foo\"));\n\n        TestUtil.setFieldValue(svc, \"sslServiceListeners\", listener);\n\n        SSLSocketFactory factory = svc.getSSLSocketFactory();\n\n        Map<ConnectionSslOptions, SSLContext> sslContexts = (Map<ConnectionSslOptions, SSLContext>) TestUtil\n                .getFieldValue(svc, \"sslContexts\");\n\n        assertNotNull(factory);\n        assertEquals(1, sslContexts.size());\n        assertEquals(factory, sslContexts.values().iterator().next().getSocketFactory());\n\n        svc.unsetKeystoreService(keystoreService);\n\n        Map<ConnectionSslOptions, SSLContext> updatedSslContexts = (Map<ConnectionSslOptions, SSLContext>) TestUtil\n                .getFieldValue(svc, \"sslContexts\");\n\n        assertEquals(0, updatedSslContexts.size());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void testSSLSocketFactoryCacheCleanedAfterEvent()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        // test preparation of an SslSocketFactory\n        setupDefaultKeystore();\n\n        SslServiceListener listener = () -> {\n        };\n\n        ComponentContext ccMock = mock(ComponentContext.class);\n\n        BundleContext bcMock = mock(BundleContext.class);\n        when(ccMock.getBundleContext()).thenReturn(bcMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"ssl.default.protocol\", \"TLSv1\");\n        properties.put(\"ssl.hostname.verification\", \"true\");\n\n        KeystoreService keystoreService = mock(KeystoreService.class);\n        when(keystoreService.getKeyStore()).thenReturn(store);\n\n        SslManagerServiceImpl svc = new SslManagerServiceImpl(ccMock, properties);\n        svc.setKeystoreService(keystoreService, Collections.singletonMap(\"kura.service.pid\", \"foo\"));\n\n        TestUtil.setFieldValue(svc, \"sslServiceListeners\", listener);\n\n        SSLSocketFactory factory = svc.getSSLSocketFactory();\n\n        Map<ConnectionSslOptions, SSLContext> sslContexts = (Map<ConnectionSslOptions, SSLContext>) TestUtil\n                .getFieldValue(svc, \"sslContexts\");\n\n        assertNotNull(factory);\n        assertEquals(1, sslContexts.size());\n        assertEquals(factory, sslContexts.values().iterator().next().getSocketFactory());\n\n        svc.handleEvent(new KeystoreChangedEvent(\"foo\"));\n\n        Map<ConnectionSslOptions, SSLContext> updatedSslContexts = (Map<ConnectionSslOptions, SSLContext>) TestUtil\n                .getFieldValue(svc, \"sslContexts\");\n\n        assertEquals(0, updatedSslContexts.size());\n    }\n\n    @Test\n    @Ignore\n    public void testPrivateKey() throws Throwable {\n        // test key installation\n        setupDefaultKeystore();\n\n        SslServiceListeners listener = new SslServiceListeners(null) {\n\n            @Override\n            public void onConfigurationUpdated() {\n                // OK\n            }\n        };\n\n        ComponentContext ccMock = mock(ComponentContext.class);\n\n        BundleContext bcMock = mock(BundleContext.class);\n        when(ccMock.getBundleContext()).thenReturn(bcMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"ssl.default.protocol\", \"TLSv1\");\n        properties.put(\"ssl.hostname.verification\", \"true\");\n\n        SslManagerServiceImpl svc = new SslManagerServiceImpl(ccMock, properties);\n\n        TestUtil.setFieldValue(svc, \"sslServiceListeners\", listener);\n\n        Map<ConnectionSslOptions, SSLContext> sslContexts = new ConcurrentHashMap<>();\n        TestUtil.setFieldValue(svc, \"sslContexts\", sslContexts);\n\n        KeystoreService keystoreService = mock(KeystoreService.class);\n        when(keystoreService.getKeyStore()).thenReturn(store);\n\n        svc.setKeystoreService(keystoreService, Collections.singletonMap(\"kura.service.pid\", \"foo\"));\n\n        svc.updated(properties);\n\n        // install a new private key and check it's really there\n\n        KeyPairGenerator gen = KeyPairGenerator.getInstance(\"DSA\");\n        gen.initialize(1024);\n        KeyPair pair = gen.generateKeyPair();\n        Key key = pair.getPrivate();\n\n        InputStream is = new FileInputStream(CERT_FILE_PATH);\n        Certificate certificate = CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        is.close();\n\n        Certificate[] chain = { certificate };\n\n        String alias = \"kuraTestAlias\";\n        svc.installPrivateKey(alias, (PrivateKey) key, STORE_PASS.toCharArray(), chain);\n\n        KeyStore store = KeyStore.getInstance(\"jks\");\n\n        is = new FileInputStream(STORE_PATH);\n        store.load(is, STORE_PASS.toCharArray());\n        is.close();\n\n        assertTrue(store.isKeyEntry(alias));\n\n        // install another private key and check that getKeyStore only returns one, if alias is specified\n\n        pair = gen.generateKeyPair();\n        key = pair.getPrivate();\n\n        svc.installPrivateKey(\"secondKey\", (PrivateKey) key, STORE_PASS.toCharArray(), chain);\n\n        KeyStore ks = (KeyStore) TestUtil.invokePrivate(svc, \"getKeyStore\", STORE_PATH, STORE_PASS.toCharArray(),\n                alias);\n\n        assertNotNull(ks);\n        assertTrue(ks.containsAlias(alias));\n\n        Enumeration<String> aliases = ks.aliases(); // all lowercase aliases???\n        assertNotNull(aliases);\n\n        List<String> aliasList = new ArrayList<>(); // only for size\n        while (aliases.hasMoreElements()) {\n            aliasList.add(aliases.nextElement());\n        }\n        assertEquals(1, aliasList.size());\n    }\n\n    @Test\n    @Ignore\n    public void testCertificates() throws NoSuchFieldException, GeneralSecurityException, IOException, KuraException {\n        // test working with certificates\n        setupDefaultKeystore();\n\n        String alias = \"kura\";\n\n        KeystoreService keystoreService = mock(KeystoreService.class);\n        when(keystoreService.getKeyStore()).thenReturn(store);\n\n        SslServiceListeners listener = new SslServiceListeners(null) {\n\n            @Override\n            public void onConfigurationUpdated() {\n                // OK\n            }\n        };\n\n        ComponentContext ccMock = mock(ComponentContext.class);\n\n        BundleContext bcMock = mock(BundleContext.class);\n        when(ccMock.getBundleContext()).thenReturn(bcMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"ssl.default.protocol\", \"TLSv1\");\n        properties.put(\"ssl.hostname.verification\", \"true\");\n\n        SslManagerServiceImpl svc = new SslManagerServiceImpl(ccMock, properties);\n        svc.setKeystoreService(keystoreService, Collections.singletonMap(\"kura.service.pid\", \"foo\"));\n\n        TestUtil.setFieldValue(svc, \"sslServiceListeners\", listener);\n\n        Map<ConnectionSslOptions, SSLContext> sslContexts = new ConcurrentHashMap<>();\n        TestUtil.setFieldValue(svc, \"sslContexts\", sslContexts);\n\n        svc.updated(properties);\n\n        KeyStore store = KeyStore.getInstance(\"jks\");\n\n        InputStream is = new FileInputStream(STORE_PATH);\n        store.load(is, STORE_PASS.toCharArray());\n        is.close();\n\n        // add a certificate\n        X509Certificate[] certificates = svc.getTrustCertificates();\n\n        assertEquals(0, certificates.length);\n\n        is = new FileInputStream(CERT_FILE_PATH);\n        Certificate certificate = CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        is.close();\n\n        svc.installTrustCertificate(alias, (X509Certificate) certificate);\n\n        // does service return the new cert?\n        X509Certificate[] tcs = svc.getTrustCertificates();\n        assertEquals(1, tcs.length);\n        X509Certificate cert = tcs[0];\n        assertEquals(BigInteger.valueOf(0x4afb9c19), cert.getSerialNumber());\n\n        // is it really in the keystore as well\n        is = new FileInputStream(STORE_PATH);\n        store.load(is, STORE_PASS.toCharArray());\n        is.close();\n\n        cert = (X509Certificate) store.getCertificate(alias);\n\n        assertNotNull(cert);\n        assertEquals(BigInteger.valueOf(0x4afb9c19), cert.getSerialNumber());\n        X500Principal issuer = cert.getIssuerX500Principal();\n        String rfcNames = issuer.getName();\n        assertEquals(\"CN=kura\", rfcNames);\n\n        // delete the certificate\n        svc.deleteTrustCertificate(alias);\n\n        // does service stil return the deleted cert?\n        tcs = svc.getTrustCertificates();\n        assertEquals(0, tcs.length);\n\n        // is it really not in the keystore enymore\n        is = new FileInputStream(STORE_PATH);\n        store.load(is, STORE_PASS.toCharArray());\n        is.close();\n\n        assertFalse(store.isCertificateEntry(alias));\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.ssl.test/src/test/resources/cert",
    "content": "-----BEGIN CERTIFICATE-----\nMIICezCCAjigAwIBAgIESvucGTALBgcqhkjOOAQDBQAwDzENMAsGA1UEAxMEa3Vy\nYTAeFw0xNzA4MjQxNDMxMjNaFw0zMTA1MDMxNDMxMjNaMA8xDTALBgNVBAMTBGt1\ncmEwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I8\n70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk\nn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX\nKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgQD34aCF1ps93su8\nq1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fP\nCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD\n3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhAACgYAaqPBZ1sLviuLYcBbVYhtJRUB1\nFBrCxMut8sWDAFCEaZ/gLuOZP7Odw9ifuDLkfF9iDi20MNUbojgFLg1u71IOLUtW\n6+0vICqfZRai7i2kNHM82J1TLaS4QYQzTDGUxs0xAOSaidyBlGPvwrzTQixIK5Ph\nH0VBeEr9a2RIbaHgOKMhMB8wHQYDVR0OBBYEFJe86lxIv5UYsZ/uGcIdewCPUeaj\nMAsGByqGSM44BAMFAAMwADAtAhUAiw2QQPqB75io+p1cxQfMQW4Z/6oCFEA7AGYv\nkLQlC6I0o6bJqtKRlwar\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.ssl.test/src/test/resources/log4j.properties",
    "content": "log4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.status.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.status.test\nBundle-SymbolicName: org.eclipse.kura.core.status.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.slf4j;version=\"1.6.4\",\n org.eclipse.kura.core.testutil,\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\"\nFragment-Host: org.eclipse.kura.core.status;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.status.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.status.test/build.properties",
    "content": "#\n# Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.status.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.status.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n    \n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.status.test/src/test/java/org/eclipse/kura/core/status/CloudConnectionStatusServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.status;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.HashSet;\nimport java.util.Properties;\nimport java.util.concurrent.ExecutorService;\n\nimport org.eclipse.kura.core.status.runnables.BlinkStatusRunnable;\nimport org.eclipse.kura.core.status.runnables.HeartbeatStatusRunnable;\nimport org.eclipse.kura.core.status.runnables.LogStatusRunnable;\nimport org.eclipse.kura.core.status.runnables.OnOffStatusRunnable;\nimport org.eclipse.kura.core.status.runnables.StatusRunnable;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.gpio.GPIOService;\nimport org.eclipse.kura.status.CloudConnectionStatusComponent;\nimport org.eclipse.kura.status.CloudConnectionStatusEnum;\nimport org.eclipse.kura.status.CloudConnectionStatusService;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.osgi.service.component.ComponentContext;\n\npublic class CloudConnectionStatusServiceImplTest {\n\n    private static final String STATUS_NOTIFICATION_URL = \"ccs.status.notification.url\";\n\n    @Test\n    public void testActivateEmptyProperty() throws NoSuchFieldException {\n        CloudConnectionStatusServiceImpl service = initCloudConnectionStatusService(\"\");\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        service.activate(componentContext);\n\n        assertNotNull(TestUtil.getFieldValue(service, \"properties\"));\n        assertNotNull(TestUtil.getFieldValue(service, \"idleComponent\"));\n        HashSet<CloudConnectionStatusComponent> componentRegistry = (HashSet) TestUtil.getFieldValue(service,\n                \"componentRegistry\");\n        assertEquals(1, componentRegistry.size());\n    }\n\n    @Test\n    public void testActivateInvalidProperty() throws NoSuchFieldException {\n        CloudConnectionStatusServiceImpl service = initCloudConnectionStatusService(\"ccs:foo\");\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        service.activate(componentContext);\n\n        assertNotNull(TestUtil.getFieldValue(service, \"properties\"));\n        assertNotNull(TestUtil.getFieldValue(service, \"idleComponent\"));\n        HashSet<CloudConnectionStatusComponent> componentRegistry = (HashSet) TestUtil.getFieldValue(service,\n                \"componentRegistry\");\n        assertEquals(1, componentRegistry.size());\n    }\n\n    @Test\n    public void testActivateNone() throws NoSuchFieldException {\n        CloudConnectionStatusServiceImpl service = initCloudConnectionStatusService(\"ccs:none\");\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        service.activate(componentContext);\n\n        assertNotNull(TestUtil.getFieldValue(service, \"properties\"));\n        assertNotNull(TestUtil.getFieldValue(service, \"idleComponent\"));\n        HashSet<CloudConnectionStatusComponent> componentRegistry = (HashSet) TestUtil.getFieldValue(service,\n                \"componentRegistry\");\n        assertEquals(1, componentRegistry.size());\n    }\n\n    @Test\n    public void testActivateLog() throws NoSuchFieldException {\n        CloudConnectionStatusServiceImpl service = initCloudConnectionStatusService(\"ccs:log\");\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        service.activate(componentContext);\n\n        assertNotNull(TestUtil.getFieldValue(service, \"properties\"));\n        assertNotNull(TestUtil.getFieldValue(service, \"idleComponent\"));\n        HashSet<CloudConnectionStatusComponent> componentRegistry = (HashSet) TestUtil.getFieldValue(service,\n                \"componentRegistry\");\n        assertEquals(1, componentRegistry.size());\n    }\n\n    @Test\n    public void testActivateGpioLed() throws NoSuchFieldException {\n        CloudConnectionStatusServiceImpl service = initCloudConnectionStatusService(\"ccs:led:44\");\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        service.activate(componentContext);\n\n        assertNotNull(TestUtil.getFieldValue(service, \"properties\"));\n        assertNotNull(TestUtil.getFieldValue(service, \"idleComponent\"));\n        HashSet<CloudConnectionStatusComponent> componentRegistry = (HashSet) TestUtil.getFieldValue(service,\n                \"componentRegistry\");\n        assertEquals(1, componentRegistry.size());\n    }\n\n    @Test\n    public void testActivateLinuxGpioLed() throws NoSuchFieldException {\n        CloudConnectionStatusServiceImpl service = initCloudConnectionStatusService(\n                \"ccs:linux_led:/sys/class/led/led1_green\" + \";\" + \"ccs:led:44\");\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        service.activate(componentContext);\n\n        assertNotNull(TestUtil.getFieldValue(service, \"properties\"));\n        assertNotNull(TestUtil.getFieldValue(service, \"idleComponent\"));\n        HashSet<CloudConnectionStatusComponent> componentRegistry = (HashSet) TestUtil.getFieldValue(service,\n                \"componentRegistry\");\n        assertEquals(1, componentRegistry.size());\n    }\n\n    @Test\n    public void testDeactivate() throws NoSuchFieldException {\n        CloudConnectionStatusServiceImpl service = initCloudConnectionStatusService(\"ccs:log\");\n\n        ComponentContext componentContext = mock(ComponentContext.class);\n        service.activate(componentContext);\n\n        service.deactivate(componentContext);\n        ExecutorService executorservice = (ExecutorService) TestUtil.getFieldValue(service, \"notificationExecutor\");\n\n        assertTrue(executorservice.isShutdown());\n\n        HashSet<CloudConnectionStatusComponent> componentRegistry = (HashSet) TestUtil.getFieldValue(service,\n                \"componentRegistry\");\n        assertEquals(0, componentRegistry.size());\n    }\n\n    @Test\n    public void testRegisterMinPriority() throws NoSuchFieldException {\n        // Prepare mock component with min priority\n        CloudConnectionStatusComponent mockComponent = createMockComponent(CloudConnectionStatusService.PRIORITY_MIN,\n                CloudConnectionStatusEnum.ON);\n\n        // Create service\n        CloudConnectionStatusServiceImpl service = createCloudConnStatusServiceImplLog();\n\n        // Make sure mockComponent is initially not in componentRegistry\n        assertFalse(isInComponentRegistry(service, mockComponent));\n\n        // Register component\n        service.register(mockComponent);\n\n        // Check if mockComponent is now in componentRegistry\n        assertTrue(isInComponentRegistry(service, mockComponent));\n\n        // Check if currentStatus is set correctly (status from idle component is used)\n        assertEquals(CloudConnectionStatusEnum.OFF, getStatus(service));\n    }\n\n    @Test\n    public void testRegisterMaxPriority() throws NoSuchFieldException {\n        // Prepare mock component with max priority\n        CloudConnectionStatusComponent mockComponent = createMockComponent(CloudConnectionStatusService.PRIORITY_MAX,\n                CloudConnectionStatusEnum.ON);\n\n        CloudConnectionStatusServiceImpl service = createCloudConnStatusServiceImplLog();\n\n        // Make sure mockComponent is initially not in componentRegistry\n        assertFalse(isInComponentRegistry(service, mockComponent));\n\n        // Register component\n        service.register(mockComponent);\n\n        // Check if mockComponent is now in componentRegistry\n        assertTrue(isInComponentRegistry(service, mockComponent));\n\n        // Check if currentStatus is set correctly\n        assertEquals(CloudConnectionStatusEnum.ON, getStatus(service));\n    }\n\n    @Test\n    public void testRegisterNullStatus() throws NoSuchFieldException {\n        // Prepare mock component with max priority with status set to \"null\"\n        CloudConnectionStatusComponent mockComponent = createMockComponent(CloudConnectionStatusService.PRIORITY_MAX,\n                null);\n\n        // Create service\n        CloudConnectionStatusServiceImpl service = createCloudConnStatusServiceImplLog();\n\n        // Make sure mockComponent is initially not in componentRegistry\n        assertFalse(isInComponentRegistry(service, mockComponent));\n\n        // Register component\n        service.register(mockComponent);\n\n        // Check if mockComponent is now in componentRegistry\n        assertTrue(isInComponentRegistry(service, mockComponent));\n\n        // Check if currentStatus is set correctly\n        assertEquals(CloudConnectionStatusEnum.OFF, getStatus(service));\n    }\n\n    @Test\n    public void testRegisterStatusesLog() throws NoSuchFieldException {\n        CloudConnectionStatusEnum[] statuses = { CloudConnectionStatusEnum.OFF, CloudConnectionStatusEnum.FAST_BLINKING,\n                CloudConnectionStatusEnum.SLOW_BLINKING, CloudConnectionStatusEnum.HEARTBEAT,\n                CloudConnectionStatusEnum.ON };\n\n        for (CloudConnectionStatusEnum selectedStatus : statuses) {\n            // Prepare mock component with max priority with selected status\n            CloudConnectionStatusComponent mockComponent = createMockComponent(\n                    CloudConnectionStatusService.PRIORITY_MAX, selectedStatus);\n\n            // Create service\n            CloudConnectionStatusServiceImpl service = createCloudConnStatusServiceImplLog();\n\n            // Make sure mockComponent is initially not in componentRegistry\n            assertFalse(isInComponentRegistry(service, mockComponent));\n\n            // Register component\n            service.register(mockComponent);\n\n            // Check if mockComponent is now in componentRegistry\n            assertTrue(isInComponentRegistry(service, mockComponent));\n\n            // Check if currentStatus is set correctly\n            assertEquals(selectedStatus, getStatus(service));\n\n            // Check if the log statusRunnable is correctly selected\n            checkLogStatusRunnables(service);\n        }\n    }\n\n    @Test\n    public void testRegisterStatusesGpio() throws NoSuchFieldException {\n        CloudConnectionStatusEnum[] statuses = { CloudConnectionStatusEnum.OFF, CloudConnectionStatusEnum.FAST_BLINKING,\n                CloudConnectionStatusEnum.SLOW_BLINKING, CloudConnectionStatusEnum.HEARTBEAT,\n                CloudConnectionStatusEnum.ON };\n\n        for (CloudConnectionStatusEnum selectedStatus : statuses) {\n            // Prepare mock component with max priority with selected status\n            CloudConnectionStatusComponent mockComponent = createMockComponent(\n                    CloudConnectionStatusService.PRIORITY_MAX, selectedStatus);\n\n            // Create service\n            CloudConnectionStatusServiceImpl service = initCloudConnectionStatusService(\"ccs:led:44\");\n            GPIOService gpioService = mock(GPIOService.class);\n            service.setGPIOService(gpioService);\n\n            ComponentContext componentContext = mock(ComponentContext.class);\n            service.activate(componentContext);\n\n            // Make sure mockComponent is initially not in componentRegistry\n            assertFalse(isInComponentRegistry(service, mockComponent));\n\n            // Register component\n            service.register(mockComponent);\n\n            // Check if mockComponent is now in componentRegistry\n            assertTrue(isInComponentRegistry(service, mockComponent));\n\n            // Check if currentStatus is set correctly\n            assertEquals(selectedStatus, getStatus(service));\n\n            // Check if the gpio statusRunnable is correctly selected\n            checkLedStatusRunnables(service);\n        }\n    }\n\n    @Test\n    public void testRegisterStatusesGpioWithoutGPIOService() throws NoSuchFieldException {\n        CloudConnectionStatusEnum[] statuses = { CloudConnectionStatusEnum.OFF, CloudConnectionStatusEnum.FAST_BLINKING,\n                CloudConnectionStatusEnum.SLOW_BLINKING, CloudConnectionStatusEnum.HEARTBEAT,\n                CloudConnectionStatusEnum.ON };\n\n        for (CloudConnectionStatusEnum selectedStatus : statuses) {\n            // Prepare mock component with max priority with selected status\n            CloudConnectionStatusComponent mockComponent = createMockComponent(\n                    CloudConnectionStatusService.PRIORITY_MAX, selectedStatus);\n\n            // Create service\n            CloudConnectionStatusServiceImpl service = initCloudConnectionStatusService(\"ccs:led:44\");\n\n            ComponentContext componentContext = mock(ComponentContext.class);\n            service.activate(componentContext);\n\n            // Make sure mockComponent is initially not in componentRegistry\n            assertFalse(isInComponentRegistry(service, mockComponent));\n\n            // Register component\n            service.register(mockComponent);\n\n            // Check if mockComponent is now in componentRegistry\n            assertTrue(isInComponentRegistry(service, mockComponent));\n\n            // Check if currentStatus is set correctly\n            assertEquals(selectedStatus, getStatus(service));\n\n            // Check if the log statusRunnable is correctly selected\n            checkLogStatusRunnables(service);\n        }\n    }\n\n    @Test\n    public void testUnregister() throws NoSuchFieldException {\n        // Prepare mock component with max priority with status set to \"ON\"\n        CloudConnectionStatusComponent mockComponent = createMockComponent(CloudConnectionStatusService.PRIORITY_MAX,\n                CloudConnectionStatusEnum.ON);\n\n        // Create service\n        CloudConnectionStatusServiceImpl service = createCloudConnStatusServiceImplLog();\n\n        // Make sure mockComponent is initially not in componentRegistry\n        assertFalse(isInComponentRegistry(service, mockComponent));\n\n        // Check if currentStatus is set correctly\n        assertNotEquals(CloudConnectionStatusEnum.ON, getStatus(service));\n\n        // Register component\n        service.register(mockComponent);\n\n        // Check if mockComponent is now in componentRegistry\n        assertTrue(isInComponentRegistry(service, mockComponent));\n\n        // Check if currentStatus is set correctly\n        assertEquals(CloudConnectionStatusEnum.ON, getStatus(service));\n\n        // Now unregister the service\n        service.unregister(mockComponent);\n\n        // Make sure mockComponent is no longer in componentRegistry\n        assertFalse(isInComponentRegistry(service, mockComponent));\n\n        // Check if currentStatus is set correctly\n        assertEquals(CloudConnectionStatusEnum.OFF, getStatus(service));\n    }\n\n    @Test\n    public void testUpdateStatus() throws NoSuchFieldException {\n        // Prepare mock component with max priority with status set to \"ON\"\n        CloudConnectionStatusComponent mockComponent = createMockComponent(CloudConnectionStatusService.PRIORITY_MAX,\n                CloudConnectionStatusEnum.ON);\n\n        // Create service\n        CloudConnectionStatusServiceImpl service = createCloudConnStatusServiceImplLog();\n\n        // Make sure mockComponent is initially not in componentRegistry\n        assertFalse(isInComponentRegistry(service, mockComponent));\n\n        // Register component\n        service.register(mockComponent);\n\n        // Check if mockComponent is now in componentRegistry\n        assertTrue(isInComponentRegistry(service, mockComponent));\n\n        // Check if currentStatus is set correctly\n        assertEquals(CloudConnectionStatusEnum.ON, getStatus(service));\n\n        // Update the status to \"fast blinking\"\n        Mockito.doNothing().when(mockComponent).setNotificationStatus(CloudConnectionStatusEnum.FAST_BLINKING);\n        Mockito.doReturn(CloudConnectionStatusEnum.FAST_BLINKING).when(mockComponent).getNotificationStatus();\n\n        assertTrue(service.updateStatus(mockComponent, CloudConnectionStatusEnum.FAST_BLINKING));\n\n        // Check that notification status was really set\n        Mockito.verify(mockComponent).setNotificationStatus(CloudConnectionStatusEnum.FAST_BLINKING);\n\n        // Check if currentStatus is set correctly\n        assertEquals(CloudConnectionStatusEnum.FAST_BLINKING, getStatus(service));\n    }\n\n    CloudConnectionStatusComponent createMockComponent(int priority, CloudConnectionStatusEnum status)\n            throws NoSuchFieldException {\n        CloudConnectionStatusComponent mockComponent = mock(CloudConnectionStatusComponent.class);\n        Mockito.doReturn(priority).when(mockComponent).getNotificationPriority();\n        Mockito.doReturn(status).when(mockComponent).getNotificationStatus();\n\n        return mockComponent;\n    }\n\n    private CloudConnectionStatusServiceImpl initCloudConnectionStatusService(String type) throws NoSuchFieldException {\n        CloudConnectionStatusServiceImpl service = new CloudConnectionStatusServiceImpl();\n\n        SystemService systemService = mock(SystemService.class);\n\n        Properties systemServiceProps = new Properties();\n        systemServiceProps.setProperty(STATUS_NOTIFICATION_URL, type);\n\n        TestUtil.setFieldValue(service, \"systemService\", systemService);\n        when(systemService.getProperties()).thenReturn(systemServiceProps);\n\n        return service;\n    }\n\n    private CloudConnectionStatusServiceImpl createCloudConnStatusServiceImplLog() throws NoSuchFieldException {\n        // Create service\n        CloudConnectionStatusServiceImpl service = new CloudConnectionStatusServiceImpl();\n\n        Properties properties = new Properties();\n        properties.put(CloudConnectionStatusURL.NOTIFICATION_TYPE, StatusNotificationTypeEnum.LOG);\n        TestUtil.setFieldValue(service, \"properties\", properties);\n        return service;\n    }\n\n    boolean isInComponentRegistry(CloudConnectionStatusServiceImpl service, CloudConnectionStatusComponent component)\n            throws NoSuchFieldException {\n        HashSet<CloudConnectionStatusComponent> componentRegistry = (HashSet<CloudConnectionStatusComponent>) TestUtil\n                .getFieldValue(service, \"componentRegistry\");\n\n        return componentRegistry.contains(component);\n    }\n\n    CloudConnectionStatusEnum getStatus(CloudConnectionStatusServiceImpl service) throws NoSuchFieldException {\n        return (CloudConnectionStatusEnum) TestUtil.getFieldValue(service, \"currentStatus\");\n    }\n\n    private StatusRunnable getStatusRunnable(CloudConnectionStatusServiceImpl service) throws NoSuchFieldException {\n        return (StatusRunnable) TestUtil.getFieldValue(service, \"statusRunnable\");\n    }\n\n    private void checkLedStatusRunnables(CloudConnectionStatusServiceImpl service) throws NoSuchFieldException {\n        assertTrue(getStatusRunnable(service) instanceof OnOffStatusRunnable\n                || getStatusRunnable(service) instanceof BlinkStatusRunnable\n                || getStatusRunnable(service) instanceof HeartbeatStatusRunnable);\n    }\n\n    private void checkLogStatusRunnables(CloudConnectionStatusServiceImpl service) throws NoSuchFieldException {\n        assertTrue(getStatusRunnable(service) instanceof LogStatusRunnable);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.status.test/src/test/java/org/eclipse/kura/core/status/CloudConnectionStatusURLTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.status;\n\nimport static org.eclipse.kura.core.status.CloudConnectionStatusURL.NOTIFICATION_TYPE;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\n\nimport java.util.Properties;\n\nimport org.eclipse.kura.core.status.GpioLedManager.GpioName;\nimport org.eclipse.kura.core.status.GpioLedManager.GpioTerminal;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class CloudConnectionStatusURLTest {\n\n    private static final String LINUX_LED_TEST_UPPER_CASE_PATH = \"/sys/class/led/UPPER_CASE\";\n    private static final String LINUX_LED_TEST_UPPER_CASE = \"linux_led:\" + LINUX_LED_TEST_UPPER_CASE_PATH;\n    private static final String LINUX_LED_LED1_GREEN_PATH = \"/sys/class/led/led1_green\";\n    private static final String LINUX_LED_LED1_GREEN = \"linux_led:\" + LINUX_LED_LED1_GREEN_PATH;\n    private static final String LED_44 = \"led:44\";\n    private static final String CCS_PREFIX = \"ccs:\";\n    private static final String INVERTED = \":inverted\";\n\n    @Before\n    public void setUp() throws Exception {\n    }\n\n    @Test(expected = NullPointerException.class)\n    public void testParseUrlNullUrl() {\n        CloudConnectionStatusURL.parseURL(null);\n    }\n\n    @Test\n    public void testParseUrlEmptyUrl() {\n        Properties props = CloudConnectionStatusURL.parseURL(\"\");\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.NONE, props.get(NOTIFICATION_TYPE));\n    }\n\n    @Test\n    public void testParseNonCCSStartingUrl() {\n        Properties props = CloudConnectionStatusURL.parseURL(\"ppp\");\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.NONE, props.get(NOTIFICATION_TYPE));\n    }\n\n    @Test\n    public void testParseUrlCcsNone() {\n        Properties props = CloudConnectionStatusURL.parseURL(\"ccs:none\");\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.NONE, props.get(NOTIFICATION_TYPE));\n    }\n\n    @Test\n    public void testParseUrlCcsLog() {\n        Properties props = CloudConnectionStatusURL.parseURL(\"ccs:log\");\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LOG, props.get(NOTIFICATION_TYPE));\n    }\n\n    @Test\n    public void testParseUrlCcsGpioLed() {\n        Properties props = CloudConnectionStatusURL.parseURL(CCS_PREFIX + LED_44);\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LED, props.get(NOTIFICATION_TYPE));\n        assertEquals(new GpioTerminal(44), props.get(\"led\"));\n        assertEquals(false, props.get(\"inverted\"));\n        assertEquals(4, props.size());\n    }\n\n    @Test\n    public void testParseUrlCcsGpioLedInverted() {\n        Properties props = CloudConnectionStatusURL.parseURL(CCS_PREFIX + LED_44 + INVERTED);\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LED, props.get(NOTIFICATION_TYPE));\n        assertEquals(new GpioTerminal(44), props.get(\"led\"));\n        assertEquals(4, props.size());\n        assertEquals(true, props.get(\"inverted\"));\n    }\n\n    @Test\n    public void testParseUrlCcsLinuxLed() {\n        Properties props = CloudConnectionStatusURL.parseURL(CCS_PREFIX + LINUX_LED_LED1_GREEN);\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LED, props.get(NOTIFICATION_TYPE));\n        assertNull(props.get(\"led\"));\n        assertEquals(LINUX_LED_LED1_GREEN_PATH, props.get(\"linux_led\"));\n        assertEquals(3, props.size());\n    }\n\n    @Test\n    public void testParseUrlCcsLinuxGpioLed() {\n        Properties props = CloudConnectionStatusURL\n                .parseURL(CCS_PREFIX + LINUX_LED_LED1_GREEN + \";\" + CCS_PREFIX + LED_44);\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LED, props.get(NOTIFICATION_TYPE));\n        assertEquals(new GpioTerminal(44), props.get(\"led\"));\n        assertEquals(LINUX_LED_LED1_GREEN_PATH, props.get(\"linux_led\"));\n        assertEquals(false, props.get(\"inverted\"));\n        assertEquals(5, props.size());\n    }\n\n    @Test\n    public void testParseUrlCcsLinuxWrongGpioLed() {\n        Properties props = CloudConnectionStatusURL\n                .parseURL(CCS_PREFIX + LINUX_LED_LED1_GREEN + \";\" + CCS_PREFIX + \"led:test\");\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LED, props.get(NOTIFICATION_TYPE));\n        assertEquals(LINUX_LED_LED1_GREEN_PATH, props.get(\"linux_led\"));\n        assertEquals(4, props.size());\n    }\n\n    @Test\n    public void testParseUrlCcsGpioLedName() {\n        Properties props = CloudConnectionStatusURL\n                .parseURL(CCS_PREFIX + LINUX_LED_LED1_GREEN + \";\" + CCS_PREFIX + \"led:name:test\");\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LED, props.get(NOTIFICATION_TYPE));\n        assertEquals(LINUX_LED_LED1_GREEN_PATH, props.get(\"linux_led\"));\n        assertEquals(new GpioName(\"test\"), props.get(\"led\"));\n        assertEquals(5, props.size());\n    }\n\n    @Test\n    public void testParseUrlCcsGpioLedWithTerminalPrefix() {\n        Properties props = CloudConnectionStatusURL\n                .parseURL(CCS_PREFIX + LINUX_LED_LED1_GREEN + \";\" + CCS_PREFIX + \"led:terminal:12\");\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LED, props.get(NOTIFICATION_TYPE));\n        assertEquals(LINUX_LED_LED1_GREEN_PATH, props.get(\"linux_led\"));\n        assertEquals(new GpioTerminal(12), props.get(\"led\"));\n        assertEquals(5, props.size());\n    }\n\n    @Test\n    public void testParseUrlCcsGpioLinuxLed() {\n        Properties props = CloudConnectionStatusURL\n                .parseURL(CCS_PREFIX + LED_44 + \";\" + CCS_PREFIX + LINUX_LED_LED1_GREEN);\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LED, props.get(NOTIFICATION_TYPE));\n        assertEquals(new GpioTerminal(44), props.get(\"led\"));\n        assertEquals(LINUX_LED_LED1_GREEN_PATH, props.get(\"linux_led\"));\n        assertEquals(false, props.get(\"inverted\"));\n        assertEquals(5, props.size());\n    }\n\n    @Test\n    public void testParseUrlCcsLinuxLedUpperCasePath() {\n        Properties props = CloudConnectionStatusURL.parseURL(CCS_PREFIX + LINUX_LED_TEST_UPPER_CASE);\n        assertNotNull(props);\n        assertEquals(StatusNotificationTypeEnum.LED, props.get(NOTIFICATION_TYPE));\n        assertNull(props.get(\"led\"));\n        assertEquals(LINUX_LED_TEST_UPPER_CASE_PATH, props.get(\"linux_led\"));\n        assertEquals(3, props.size());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.status.test/src/test/resources/log4j.properties",
    "content": "log4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.system.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.system.test\nBundle-SymbolicName: org.eclipse.kura.core.system.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.core.system\nImport-Package: org.eclipse.kura;version=\"[1.2,2.0)\",\n org.eclipse.kura.core.linux.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil,\n org.eclipse.kura.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.system;version=\"[1.4,2.0)\",\n org.eclipse.kura.test.annotation;version=\"1.0.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.system.test/OSGI-INF/system-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n  \n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"SystemTest\">\n   <implementation class=\"org.eclipse.kura.core.system.test.SystemServiceTest\"/>\n   <reference bind=\"setSystemService\"\n              cardinality=\"1..1\"\n              interface=\"org.eclipse.kura.system.SystemService\"\n              name=\"SystemService\"\n              policy=\"static\"/>\n   <reference bind=\"setExecutorService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.executor.PrivilegedExecutorService\" name=\"PrivilegedExecutorService\" policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.system.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.system.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.system.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.core.system.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.system.test/src/main/java/org/eclipse/kura/core/system/test/SystemServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.system.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.system.InternetConnectionStatus;\nimport org.eclipse.kura.system.SystemService;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\npublic class SystemServiceTest {\n\n    private static final String UNKNOWN = \"UNKNOWN\";\n    private static final String LINUX = \"Linux\"; // Ubuntu\n    private static SystemService systemService = null;\n    private static CommandExecutorService executorService = null;\n    private static CountDownLatch dependencyLatch = new CountDownLatch(2);    // initialize with number of dependencies\n    private boolean onCloudbees = false;\n\n    @BeforeClass\n    public static void setUp() {\n        // Wait for OSGi dependencies\n        try {\n            if (!dependencyLatch.await(10, TimeUnit.SECONDS)) {\n                fail(\"OSGi dependencies unfulfilled\");\n            }\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            fail(\"OSGi dependencies unfulfilled\");\n        }\n    }\n\n    protected void setExecutorService(CommandExecutorService ces) {\n        executorService = ces;\n        dependencyLatch.countDown();\n    }\n\n    protected void setSystemService(SystemService sms) {\n        systemService = sms;\n        onCloudbees = systemService.getOsName().contains(\"Cloudbees\");\n        dependencyLatch.countDown();\n    }\n\n    @Test\n    public void testDummy() {\n        assertTrue(true);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testServiceExists() {\n        assertNotNull(systemService);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetPrimaryMacAddress() {\n\n        String actual = systemService.getPrimaryMacAddress();\n\n        if (actual != null && !actual.isEmpty()) {\n            Pattern regex = Pattern.compile(\"[0-9a-fA-F:]{12}\");\n            Matcher match = regex.matcher(actual);\n\n            assertEquals(\"getPrimaryMacAddress() length\", 17, actual.length());\n            assertTrue(\"getPrimaryMacAddress() is string with colons\", match.find());\n        }\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetPlatform() {\n        String[] expected = { \"DevPlatform\", // emulated\n                \"Ubuntu\",                    // Ubuntu\n                \"BeagleBone\"                 // BeagleBone\n        };\n\n        try {\n            boolean foundMatch = false;\n            for (String possibility : expected) {\n                if (systemService.getPlatform().equals(possibility)) {\n                    foundMatch = true;\n                    break;\n                }\n            }\n            assertTrue(foundMatch);\n        } catch (Exception e) {\n            fail(\"getPlatform() failed: \" + e.getMessage());\n        }\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetOsDistro() {\n        String[] expected = { \"DevOsDitribution\",            // emulated\n                LINUX };\n\n        try {\n            boolean foundMatch = false;\n            for (String possibility : expected) {\n                if (systemService.getOsDistro().equals(possibility)) {\n                    foundMatch = true;\n                    break;\n                }\n            }\n            assertTrue(foundMatch);\n        } catch (Exception e) {\n            fail(\"getOsDistro() failed: \" + e.getMessage());\n        }\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetOsDistroVersion() {\n        String[] expected = { \"DevOsDitributionVersion\",    // emulated\n                \"N/A\"                                        // Ubuntu\n        };\n\n        try {\n            boolean foundMatch = false;\n            for (String possibility : expected) {\n                if (systemService.getOsDistroVersion().equals(possibility)) {\n                    foundMatch = true;\n                    break;\n                }\n            }\n            assertTrue(foundMatch);\n        } catch (Exception e) {\n            fail(\"getOsDistroVersion() failed: \" + e.getMessage());\n        }\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetOsArch() {\n        String expected = System.getProperty(\"os.arch\");\n        String actual = systemService.getOsArch();\n\n        assertNotNull(\"getOsArch() not null\", actual);\n        assertEquals(\"getOsArch() value\", expected, actual);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetOsName() {\n        String expected = System.getProperty(\"os.name\");\n        if (onCloudbees) {\n            expected = \"Linux (Cloudbees)\";\n        }\n\n        String actual = systemService.getOsName();\n\n        assertNotNull(\"getOsName() not null\", actual);\n        assertEquals(\"getOsName() value\", expected, actual);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetOsVersion() throws IOException {\n        String osVersion = System.getProperty(\"os.version\");\n        StringBuilder sbOsVersion = new StringBuilder();\n        sbOsVersion.append(osVersion);\n\n        File linuxKernelVersion = null;\n        linuxKernelVersion = new File(\"/proc/sys/kernel/version\");\n        if (linuxKernelVersion.exists()) {\n            StringBuilder kernelVersionData = new StringBuilder();\n            try (FileReader fr = new FileReader(linuxKernelVersion); BufferedReader in = new BufferedReader(fr)) {\n                String tempLine = null;\n                while ((tempLine = in.readLine()) != null) {\n                    kernelVersionData.append(\" \");\n                    kernelVersionData.append(tempLine);\n                }\n                sbOsVersion.append(kernelVersionData.toString());\n            }\n        }\n\n        String expected = sbOsVersion.toString();\n        String actual = systemService.getOsVersion();\n\n        assertNotNull(\"getOsVersion() not null\", actual);\n        assertEquals(\"getOsVersion() value\", expected, actual);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetJavaVersion() {\n        String expected = System.getProperty(\"java.runtime.version\");\n        String actual = systemService.getJavaVersion();\n\n        assertNotNull(\"getJavaVersion() not null\", actual);\n        assertEquals(\"getJavaVersion() value\", expected, actual);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetJavaVmName() {\n        String expected = System.getProperty(\"java.vm.name\");\n        String actual = systemService.getJavaVmName();\n\n        assertNotNull(\"getJavaVmName() not null\", actual);\n        assertEquals(\"getJavaVmName() value\", expected, actual);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetJavaVmVersion() {\n        String expected = System.getProperty(\"java.vm.version\");\n        String actual = systemService.getJavaVmVersion();\n\n        assertNotNull(\"getJavaVmVersion() not null\", actual);\n        assertEquals(\"getJavaVmVersion() value\", expected, actual);\n    }\n\n    @Test\n    public void shouldReturnJavaVmVendor() {\n        assertNotNull(systemService.getJavaVmVendor());\n    }\n\n    @Test\n    public void shouldReturnJdkVendorVersion() {\n        assertNull(systemService.getJdkVendorVersion());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetFileSeparator() {\n        String expected = System.getProperty(\"file.separator\");\n        String actual = systemService.getFileSeparator();\n\n        assertNotNull(\"getFileSeparator() not null\", actual);\n        assertEquals(\"getFileSeparator() value\", expected, actual);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testJavaHome() {\n        String actual = systemService.getJavaHome();\n        assertNotNull(\"getJavaHome() not null\", actual);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetProductVersion() {\n        assertTrue(true);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testKuraTemporaryConfigDirectory() {\n        assertNotNull(systemService.getKuraTemporaryConfigDirectory());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetBiosVersion() {\n        assertNotNull(systemService.getBiosVersion());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void getDeviceName() {\n        assertNotNull(systemService.getDeviceName());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void getFirmwareVersion() {\n        assertNotNull(systemService.getFirmwareVersion());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void getModelId() {\n        assertNotNull(systemService.getModelId());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void getPartNumber() {\n        assertNotNull(systemService.getPartNumber());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void shouldGetDefaultLogManagerProperty() {\n        assertFalse(systemService.getDefaultLogManager().isPresent());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void shouldGetDefaultWPA3WifiSecuritySupportProperty() {\n        assertFalse(systemService.isWPA3WifiSecurityEnabled());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void shouldGetDefaultNetworkConfigurationTimeoutProperty() {\n        assertEquals(30, systemService.getNetworkConfigurationTimeout());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void shouldNotBeConnectedToInternet() {\n        assertEquals(InternetConnectionStatus.UNAVAILABLE, systemService.getInternetConnectionStatus());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void shouldGetDefaultInternetConnectionStatusCheckHost() {\n        assertEquals(\"eclipse.org\", systemService.getInternetConnectionStatusCheckHost());\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void shouldGetDefaultInternetConnectionStatusCheckIp() {\n        assertEquals(\"198.41.30.198\", systemService.getInternetConnectionStatusCheckIp());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.system.test/src/test/java/org/eclipse/kura/core/system/SystemServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.system;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Properties;\n\nimport org.eclipse.kura.KuraProcessExecutionErrorException;\nimport org.eclipse.kura.core.linux.executor.LinuxExitStatus;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Test;\nimport org.osgi.service.component.ComponentContext;\n\npublic class SystemServiceTest {\n\n    @Test\n    public void testActivateRelativeConfigFilePathsUpdate() {\n        // verify the part of the code that replaces config file property values\n\n        SystemServiceImpl systemService = new SystemServiceImpl();\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n\n        System.setProperty(SystemService.KURA_CONFIG, \"file:kura/kura.properties\");\n        System.setProperty(\"dpa.configuration\", \"kura/dpa.properties\");\n        System.setProperty(\"log4j.configuration\", \"file:kura/log4j.properties\");\n\n        System.setProperty(SystemService.KURA_CUSTOM_CONFIG, \"file:/opt/eclipse/kura/framework/kura.properties\");\n\n        systemService.activate(ctxMock);\n\n        assertEquals(\"file:/opt/eclipse/kura/framework/kura.properties\", System.getProperty(SystemService.KURA_CONFIG));\n        assertEquals(\"/opt/eclipse/kura/packages/dpa.properties\", System.getProperty(\"dpa.configuration\"));\n        assertEquals(\"file:/opt/eclipse/kura/user/log4j.properties\", System.getProperty(\"log4j.configuration\"));\n    }\n\n    @Test\n    public void testActivateWithExplicitPropertyFiles() throws IOException {\n        // check that values are read from 'default' and custom files\n\n        SystemServiceImpl systemService = new SystemServiceImpl() {\n\n            // make sure not to read e.g. kura.properties from the classpath\n            @Override\n            protected String readResource(String resource) throws IOException {\n                return null;\n            }\n        };\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n\n        String props = \"/tmp/ssact_kura.properties\";\n        String customProps = \"/tmp/ssact_kura_custom.properties\";\n\n        System.setProperty(SystemService.KURA_CONFIG, \"file:\" + props);\n        System.setProperty(SystemService.KURA_CUSTOM_CONFIG, \"file:\" + customProps);\n        System.clearProperty(SystemService.KEY_KURA_HOME_DIR);\n\n        String key_proper = \"property.proper\";\n        String val_proper = \"proper property value\";\n        File f1 = writeFile(props,\n                String.format(\"%s = %s\\n%s = test ver\", key_proper, val_proper, SystemService.KEY_KURA_VERSION));\n        String key_custom = \"property.custom\";\n        String val_custom = \"custom property value\";\n        String val_test = \"test ver override\";\n        File f2 = writeFile(customProps,\n                String.format(\"%s = %s\\n%s = %s\", key_custom, val_custom, SystemService.KEY_KURA_VERSION, val_test));\n\n        systemService.activate(ctxMock);\n\n        f1.delete();\n        f2.delete();\n\n        // check that the defults are properly set\n        Properties properties = systemService.getProperties();\n        assertFalse(properties.containsKey(key_proper));\n        assertFalse(properties.containsKey(key_custom));\n        assertEquals(val_proper, properties.getProperty(key_proper));\n        assertEquals(val_custom, properties.getProperty(key_custom));\n        assertEquals(val_test, properties.getProperty(SystemService.KEY_KURA_VERSION));\n    }\n\n    @Test\n    public void testActivateWithHomePropertyValues() throws IOException {\n        // verify that fallback to kura's home directory works\n\n        SystemServiceImpl systemService = new SystemServiceImpl() {\n\n            // make sure not to read e.g. kura.properties from the classpath\n            @Override\n            protected String readResource(String resource) throws IOException {\n                return null;\n            }\n        };\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n\n        String props = \"/tmp/framework/kura.properties\";\n        String customProps = \"/tmp/user/kura_custom.properties\";\n\n        System.clearProperty(SystemService.KURA_CONFIG);\n        System.clearProperty(SystemService.KURA_CUSTOM_CONFIG);\n        System.setProperty(SystemService.KEY_KURA_HOME_DIR, \"/tmp\");\n        System.setProperty(SystemService.KEY_KURA_FRAMEWORK_CONFIG_DIR, \"/tmp/framework\");\n        System.setProperty(SystemService.KEY_KURA_USER_CONFIG_DIR, \"/tmp/user\");\n\n        String key_proper = \"property.proper\";\n        String val_proper = \"proper property value\";\n        File f1 = writeFile(props,\n                String.format(\"%s = %s\\n%s = test ver\", key_proper, val_proper, SystemService.KEY_KURA_VERSION));\n        String key_custom = \"property.custom\";\n        String val_custom = \"custom property value\";\n        String val_test = \"test ver override\";\n        File f2 = writeFile(customProps,\n                String.format(\"%s = %s\\n%s = %s\", key_custom, val_custom, SystemService.KEY_KURA_VERSION, val_test));\n\n        systemService.activate(ctxMock);\n\n        f1.delete();\n        f2.delete();\n\n        // check that the defults are properly set\n        Properties properties = systemService.getProperties();\n        assertFalse(properties.containsKey(key_proper));\n        assertFalse(properties.containsKey(key_custom));\n        assertEquals(val_proper, properties.getProperty(key_proper));\n        assertEquals(val_custom, properties.getProperty(key_custom));\n        assertEquals(val_test, properties.getProperty(SystemService.KEY_KURA_VERSION));\n    }\n\n    @Test\n    public void testActivateWithUpdatedDefaults() throws IOException {\n        // verify that update of certain default values works\n\n        File dir = new File(\"/opt\");\n        if (!dir.canWrite()) {\n            // cannot test in this case\n            return;\n        }\n\n        SystemServiceImpl systemService = new SystemServiceImpl() {\n\n            // make sure not to read e.g. kura.properties from the classpath\n            @Override\n            protected String readResource(String resource) throws IOException {\n                return null;\n            }\n        };\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n\n        String props = \"/tmp/kura.properties\";\n\n        System.setProperty(SystemService.KURA_CONFIG, \"file:\" + props);\n        System.clearProperty(SystemService.KURA_CUSTOM_CONFIG);\n        System.clearProperty(SystemService.KEY_KURA_HOME_DIR);\n\n        File f1 = writeFile(props,\n                String.format(\"%s = kura\\n%s = kura/plugins\\n%s = kura/packages\", SystemService.KEY_KURA_HOME_DIR,\n                        SystemService.KEY_KURA_PLUGINS_DIR, SystemService.KEY_KURA_PACKAGES_DIR));\n\n        systemService.activate(ctxMock);\n\n        f1.delete();\n\n        // check that the defaults are properly set\n        Properties properties = systemService.getProperties();\n        assertEquals(\"/opt/eclipse/kura\", properties.getProperty(SystemService.KEY_KURA_HOME_DIR));\n        assertEquals(\"/opt/eclipse/kura/plugins\", properties.getProperty(SystemService.KEY_KURA_PLUGINS_DIR));\n        assertEquals(\"/opt/eclipse/kura/data/packages\", properties.getProperty(SystemService.KEY_KURA_PACKAGES_DIR));\n    }\n\n    @Test\n    public void testActivateAllProperties() throws IOException {\n        // verify that certain system properties are actually used as kura's property overrides\n\n        System.setProperty(SystemService.KEY_KURA_HOME_DIR, \"/tmp\");\n        System.setProperty(SystemService.KEY_KURA_FRAMEWORK_CONFIG_DIR, \"/tmp/framework\");\n        System.setProperty(SystemService.KEY_KURA_USER_CONFIG_DIR, \"/tmp/user\");\n        System.setProperty(SystemService.KEY_KURA_NAME, \"KEY_KURA_NAME\");\n        System.setProperty(SystemService.KEY_DEVICE_NAME, \"KEY_DEVICE_NAME\");\n        System.setProperty(SystemService.KEY_PLATFORM, \"KEY_PLATFORM\");\n        System.setProperty(SystemService.KEY_MODEL_ID, \"KEY_MODEL_ID\");\n        System.setProperty(SystemService.KEY_MODEL_NAME, \"KEY_MODEL_NAME\");\n        System.setProperty(SystemService.KEY_PART_NUMBER, \"KEY_PART_NUMBER\");\n        System.setProperty(SystemService.KEY_SERIAL_NUM, \"KEY_SERIAL_NUM\");\n        System.setProperty(SystemService.KEY_BIOS_VERSION, \"KEY_BIOS_VERSION\");\n        System.setProperty(SystemService.KEY_FIRMWARE_VERSION, \"KEY_FIRMWARE_VERSION\");\n        System.setProperty(SystemService.KEY_PRIMARY_NET_IFACE, \"KEY_PRIMARY_NET_IFACE\");\n        System.setProperty(SystemService.KEY_KURA_DATA_DIR, \"KEY_KURA_DATA_DIR\");\n        System.setProperty(SystemService.KEY_KURA_SNAPSHOTS_COUNT, \"KEY_KURA_SNAPSHOTS_COUNT\");\n        System.setProperty(SystemService.KEY_KURA_HAVE_NET_ADMIN, \"KEY_KURA_HAVE_NET_ADMIN\");\n        System.setProperty(SystemService.KEY_KURA_HAVE_WEB_INTER, \"KEY_KURA_HAVE_WEB_INTER\");\n        System.setProperty(SystemService.KEY_KURA_STYLE_DIR, \"KEY_KURA_STYLE_DIR\");\n        System.setProperty(SystemService.KEY_KURA_WIFI_TOP_CHANNEL, \"KEY_KURA_WIFI_TOP_CHANNEL\");\n        System.setProperty(SystemService.KEY_KURA_KEY_STORE_PWD, \"KEY_KURA_KEY_STORE_PWD\");\n        System.setProperty(SystemService.KEY_KURA_TRUST_STORE_PWD, \"KEY_KURA_TRUST_STORE_PWD\");\n        System.setProperty(SystemService.KEY_FILE_COMMAND_ZIP_MAX_SIZE, \"KEY_FILE_COMMAND_ZIP_MAX_SIZE\");\n        System.setProperty(SystemService.KEY_FILE_COMMAND_ZIP_MAX_NUMBER, \"KEY_FILE_COMMAND_ZIP_MAX_NUMBER\");\n        System.setProperty(SystemService.KEY_OS_DISTRO, \"KEY_OS_DISTRO\");\n        System.setProperty(SystemService.KEY_OS_DISTRO_VER, \"KEY_OS_DISTRO_VER\");\n        System.setProperty(SystemService.CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE,\n                \"CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE\");\n        System.setProperty(SystemService.DB_URL_PROPNAME, \"DB_URL_PROPNAME\");\n        System.setProperty(SystemService.DB_CACHE_ROWS_PROPNAME, \"DB_CACHE_ROWS_PROPNAME\");\n        System.setProperty(SystemService.DB_LOB_FILE_PROPNAME, \"DB_LOB_FILE_PROPNAME\");\n        System.setProperty(SystemService.DB_DEFRAG_LIMIT_PROPNAME, \"DB_DEFRAG_LIMIT_PROPNAME\");\n        System.setProperty(SystemService.DB_LOG_DATA_PROPNAME, \"DB_LOG_DATA_PROPNAME\");\n        System.setProperty(SystemService.DB_LOG_SIZE_PROPNAME, \"DB_LOG_SIZE_PROPNAME\");\n        System.setProperty(SystemService.DB_NIO_PROPNAME, \"DB_NIO_PROPNAME\");\n        System.setProperty(SystemService.DB_WRITE_DELAY_MILLIES_PROPNAME, \"DB_WRITE_DELAY_MILLIES_PROPNAME\");\n\n        SystemServiceImpl systemService = new SystemServiceImpl() {\n\n            // make sure not to read e.g. kura.properties from the classpath\n            @Override\n            protected String readResource(String resource) throws IOException {\n                return null;\n            }\n        };\n\n        ComponentContext ctxMock = mock(ComponentContext.class);\n\n        systemService.activate(ctxMock);\n\n        Properties props = systemService.getProperties();\n        assertEquals(\"KEY_KURA_NAME\", props.getProperty(SystemService.KEY_KURA_NAME));\n        assertEquals(\"KEY_DEVICE_NAME\", props.getProperty(SystemService.KEY_DEVICE_NAME));\n        assertEquals(\"KEY_PLATFORM\", props.getProperty(SystemService.KEY_PLATFORM));\n        assertEquals(\"KEY_MODEL_ID\", props.getProperty(SystemService.KEY_MODEL_ID));\n        assertEquals(\"KEY_MODEL_NAME\", props.getProperty(SystemService.KEY_MODEL_NAME));\n        assertEquals(\"KEY_PART_NUMBER\", props.getProperty(SystemService.KEY_PART_NUMBER));\n        assertEquals(\"KEY_SERIAL_NUM\", props.getProperty(SystemService.KEY_SERIAL_NUM));\n        assertEquals(\"KEY_BIOS_VERSION\", props.getProperty(SystemService.KEY_BIOS_VERSION));\n        assertEquals(\"KEY_FIRMWARE_VERSION\", props.getProperty(SystemService.KEY_FIRMWARE_VERSION));\n        assertEquals(\"KEY_PRIMARY_NET_IFACE\", props.getProperty(SystemService.KEY_PRIMARY_NET_IFACE));\n        assertEquals(\"KEY_KURA_DATA_DIR\", props.getProperty(SystemService.KEY_KURA_DATA_DIR));\n        assertEquals(\"KEY_KURA_SNAPSHOTS_COUNT\", props.getProperty(SystemService.KEY_KURA_SNAPSHOTS_COUNT));\n        assertEquals(\"KEY_KURA_HAVE_NET_ADMIN\", props.getProperty(SystemService.KEY_KURA_HAVE_NET_ADMIN));\n        assertEquals(\"KEY_KURA_HAVE_WEB_INTER\", props.getProperty(SystemService.KEY_KURA_HAVE_WEB_INTER));\n        assertEquals(\"KEY_KURA_STYLE_DIR\", props.getProperty(SystemService.KEY_KURA_STYLE_DIR));\n        assertEquals(\"KEY_KURA_WIFI_TOP_CHANNEL\", props.getProperty(SystemService.KEY_KURA_WIFI_TOP_CHANNEL));\n        assertEquals(\"KEY_KURA_KEY_STORE_PWD\", props.getProperty(SystemService.KEY_KURA_KEY_STORE_PWD));\n        assertEquals(\"KEY_KURA_TRUST_STORE_PWD\", props.getProperty(SystemService.KEY_KURA_TRUST_STORE_PWD));\n        assertEquals(\"KEY_FILE_COMMAND_ZIP_MAX_SIZE\", props.getProperty(SystemService.KEY_FILE_COMMAND_ZIP_MAX_SIZE));\n        assertEquals(\"KEY_FILE_COMMAND_ZIP_MAX_NUMBER\",\n                props.getProperty(SystemService.KEY_FILE_COMMAND_ZIP_MAX_NUMBER));\n        assertEquals(\"KEY_OS_DISTRO\", props.getProperty(SystemService.KEY_OS_DISTRO));\n        assertEquals(\"KEY_OS_DISTRO_VER\", props.getProperty(SystemService.KEY_OS_DISTRO_VER));\n        assertEquals(\"CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE\",\n                props.getProperty(SystemService.CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE));\n        assertEquals(\"DB_URL_PROPNAME\", props.getProperty(SystemService.DB_URL_PROPNAME));\n        assertEquals(\"DB_CACHE_ROWS_PROPNAME\", props.getProperty(SystemService.DB_CACHE_ROWS_PROPNAME));\n        assertEquals(\"DB_LOB_FILE_PROPNAME\", props.getProperty(SystemService.DB_LOB_FILE_PROPNAME));\n        assertEquals(\"DB_DEFRAG_LIMIT_PROPNAME\", props.getProperty(SystemService.DB_DEFRAG_LIMIT_PROPNAME));\n        assertEquals(\"DB_LOG_DATA_PROPNAME\", props.getProperty(SystemService.DB_LOG_DATA_PROPNAME));\n        assertEquals(\"DB_LOG_SIZE_PROPNAME\", props.getProperty(SystemService.DB_LOG_SIZE_PROPNAME));\n        assertEquals(\"DB_NIO_PROPNAME\", props.getProperty(SystemService.DB_NIO_PROPNAME));\n        assertEquals(\"DB_WRITE_DELAY_MILLIES_PROPNAME\",\n                props.getProperty(SystemService.DB_WRITE_DELAY_MILLIES_PROPNAME));\n    }\n\n    @Test\n    public void testGetSystemPackages() throws IOException, KuraProcessExecutionErrorException {\n        CommandExecutorService cesMock = mock(CommandExecutorService.class);\n\n        Command dpkgCommand = new Command(new String[] { \"dpkg-query\", \"-W\" });\n        dpkgCommand.setExecuteInAShell(true);\n        CommandStatus dpkgSuccessfulStatus = new CommandStatus(dpkgCommand, new LinuxExitStatus(0));\n        dpkgSuccessfulStatus.setOutputStream(writeToOutputStream(\"package1 1.0.0\\npackage2\"));\n        when(cesMock.execute(dpkgCommand)).thenReturn(dpkgSuccessfulStatus);\n\n        Command rpmCommand = new Command(\n                new String[] { \"rpm\", \"-qa\", \"--queryformat\", \"'%{NAME} %{VERSION}-%{RELEASE}\\n'\" });\n        rpmCommand.setExecuteInAShell(true);\n        CommandStatus rpmSuccessfulStatus = new CommandStatus(dpkgCommand, new LinuxExitStatus(0));\n        rpmSuccessfulStatus.setOutputStream(writeToOutputStream(\"package3 2.0.0\\npackage4\"));\n        when(cesMock.execute(rpmCommand)).thenReturn(rpmSuccessfulStatus);\n\n        Command apkCommand = new Command(new String[] { \"apk\", \"list\", \"-I\", \"|\", \"awk\", \"'{ print $1 }'\" });\n        apkCommand.setExecuteInAShell(true);\n        CommandStatus apkSuccessfulStatus = new CommandStatus(apkCommand, new LinuxExitStatus(0));\n        apkSuccessfulStatus.setOutputStream(writeToOutputStream(\"dos2unix-7.4.1-r0\\nkmod-26-r0\"));\n        when(cesMock.execute(apkCommand)).thenReturn(apkSuccessfulStatus);\n\n        SystemServiceImpl systemService = new SystemServiceImpl();\n        systemService.setExecutorService(cesMock);\n\n        List<SystemResourceInfo> packages = systemService.getSystemPackages();\n        assertFalse(packages.isEmpty());\n        assertEquals(6, packages.size());\n        assertEquals(\"package1\", packages.get(0).getName());\n        assertEquals(\"1.0.0\", packages.get(0).getVersion());\n        assertEquals(SystemResourceType.DEB, packages.get(0).getType());\n        assertEquals(\"package2\", packages.get(1).getName());\n        assertEquals(SystemResourceType.DEB, packages.get(1).getType());\n        assertEquals(\"package3\", packages.get(2).getName());\n        assertEquals(\"2.0.0\", packages.get(2).getVersion());\n        assertEquals(SystemResourceType.RPM, packages.get(2).getType());\n        assertEquals(\"package4\", packages.get(3).getName());\n        assertEquals(SystemResourceType.RPM, packages.get(3).getType());\n        assertEquals(SystemResourceType.APK, packages.get(4).getType());\n        assertEquals(\"dos2unix\", packages.get(4).getName());\n        assertEquals(\"7.4.1-r0\", packages.get(4).getVersion());\n        assertEquals(\"kmod\", packages.get(5).getName());\n        assertEquals(\"26-r0\", packages.get(5).getVersion());\n    }\n\n    @Test(expected = KuraProcessExecutionErrorException.class)\n    public void testgGetSystemPackagesFailed() throws KuraProcessExecutionErrorException {\n\n        CommandExecutorService cesMock = mock(CommandExecutorService.class);\n\n        Command dpkgCommand = new Command(new String[] { \"dpkg-query\", \"-W\" });\n        dpkgCommand.setExecuteInAShell(true);\n        CommandStatus unSuccessfulStatus = new CommandStatus(dpkgCommand, new LinuxExitStatus(1));\n        when(cesMock.execute(dpkgCommand)).thenReturn(unSuccessfulStatus);\n\n        Command rpmCommand = new Command(\n                new String[] { \"rpm\", \"-qa\", \"--queryformat\", \"'%{NAME} %{VERSION}-%{RELEASE}\\n'\" });\n        rpmCommand.setExecuteInAShell(true);\n        when(cesMock.execute(rpmCommand)).thenReturn(unSuccessfulStatus);\n\n        Command apkCommand = new Command(new String[] { \"apk\", \"list\", \"-I\", \"|\", \"awk\", \"'{ print $1 }'\" });\n        apkCommand.setExecuteInAShell(true);\n        when(cesMock.execute(apkCommand)).thenReturn(unSuccessfulStatus);\n\n        SystemServiceImpl systemService = new SystemServiceImpl();\n        systemService.setExecutorService(cesMock);\n\n        @SuppressWarnings(\"unused\")\n        List<SystemResourceInfo> packages = systemService.getSystemPackages();\n    }\n\n    private ByteArrayOutputStream writeToOutputStream(String data) throws IOException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);\n\n        dataOutputStream.write(data.getBytes());\n        byteArrayOutputStream.flush();\n        byteArrayOutputStream.close();\n\n        return byteArrayOutputStream;\n    }\n\n    private File writeFile(String path, String content) throws IOException {\n        File file = new File(path);\n        file.createNewFile();\n        file.deleteOnExit();\n\n        FileWriter fw = new FileWriter(file);\n        fw.append(content);\n        fw.close();\n\n        return file;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.system.test/src/test/resources/log4j.properties",
    "content": "################################################################################\n#  Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n################################################################################\n\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.test\nBundle-SymbolicName: org.eclipse.kura.core.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: javax.comm,\n javax.xml.parsers,\n javax.xml.stream,\n junit.framework,\n org.eclipse.kura.cloud;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection;version=\"[1.0,2.0]\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0]\",\n org.eclipse.kura.comm;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.configuration;version=\"[2.0,3.0)\",\n org.eclipse.kura.core.configuration.metatype;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.configuration.util;version=\"[2.0,3.0)\",\n org.eclipse.kura.core.inventory;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.inventory.resources;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.core.testutil.event;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.http;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.pki;version=\"[1.0,2.0)\",\n org.eclipse.kura.data;version=\"[1.1,2.0)\",\n org.eclipse.kura.data.listener;version=\"[1.0,2.0]\",\n org.eclipse.kura.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.marshalling;version=\"1.0.0\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.service;version=\"1.0.0\",\n org.eclipse.kura.util.wire.test;version=\"1.1.0\",\n org.eclipse.kura.watchdog;version=\"[1.0,2.0)\",\n org.h2;version=\"2.1.210\",\n org.h2.api;version=\"2.1.210\",\n org.h2.jdbcx;version=\"2.1.210\",\n org.h2.tools;version=\"2.1.210\",\n org.junit,\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.mockito.verification;version=\"4.8.1\",\n org.osgi.framework,\n org.osgi.service.cm,\n org.osgi.service.component,\n org.osgi.service.deploymentadmin;version=\"1.0.0\",\n org.osgi.service.event,\n org.osgi.service.io;version=\"1.0.0\",\n org.slf4j;version=\"1.6.4\",\n org.w3c.dom,\n org.xml.sax\nFragment-Host: org.eclipse.kura.core\nBundle-ActivationPolicy: lazy\nComment: org.eclipse.kura.emulator is needed as we need to start-up the emulator to run the tests!!\nRequire-Bundle: org.eclipse.equinox.io,\n org.junit,\n org.eclipse.kura.test,\n org.eclipse.kura.emulator,\n moquette-broker\nComment2: require moquette-broker. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=485926\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/OSGI-INF/InventoryHandler-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"InventoryHandlerTest\">\n    <implementation class=\"org.eclipse.kura.core.test.InventoryHandlerTest\" />\n    <reference bind=\"setDeploymentAdmin\" cardinality=\"1..1\"\n        interface=\"org.osgi.service.deploymentadmin.DeploymentAdmin\" name=\"DeploymentAdmin\"\n        policy=\"static\" unbind=\"unsetDeploymentAdmin\" />\n    <reference bind=\"setCloudEndpoint\" cardinality=\"1..1\"\n        interface=\"org.eclipse.kura.cloudconnection.CloudEndpoint\" name=\"CloudEndpoint\"\n        policy=\"static\" />\n    <reference bind=\"setDataService\" cardinality=\"1..1\"\n        interface=\"org.eclipse.kura.data.DataService\" name=\"DataService\" policy=\"static\" />\n</scr:component>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/OSGI-INF/all-core-tests.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" \n               name=\"org.eclipse.kura.core.test.AllCoreTests\">\n   <implementation class=\"org.eclipse.kura.core.test.AllCoreTests\"/>\n   <reference bind=\"setDataService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.data.DataService\" name=\"CloudService\" policy=\"static\" unbind=\"unsetDataService\"/>\n   <reference bind=\"setSystemService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.system.SystemService\" name=\"SystemService\" policy=\"static\" unbind=\"unsetSystemService\"/>\n   <reference bind=\"setConfigService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\" policy=\"static\" unbind=\"unsetConfigService\"/>\n      \n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/OSGI-INF/cloudDeploymentHandler-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"CloudDeploymentHandlerTest\">\n    <implementation class=\"org.eclipse.kura.core.test.CloudDeploymentHandlerTest\" />\n    <reference bind=\"setDeploymentAdmin\" cardinality=\"1..1\"\n        interface=\"org.osgi.service.deploymentadmin.DeploymentAdmin\" name=\"DeploymentAdmin\"\n        policy=\"static\" unbind=\"unsetDeploymentAdmin\" />\n    <reference bind=\"setCloudEndpoint\" cardinality=\"1..1\"\n        interface=\"org.eclipse.kura.cloudconnection.CloudEndpoint\" name=\"CloudEndpoint\"\n        policy=\"static\" />\n    <reference bind=\"setDataService\" cardinality=\"1..1\"\n        interface=\"org.eclipse.kura.data.DataService\" name=\"DataService\" policy=\"static\" />\n</scr:component>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/OSGI-INF/comm-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"CommTest\">\n   <implementation class=\"org.eclipse.kura.core.test.hw.CommTest\"/>\n   <reference bind=\"setConnectionFactory\" \n              cardinality=\"1..n\" \n              interface=\"org.osgi.service.io.ConnectionFactory\" \n              name=\"ConnectionFactory\" \n              policy=\"dynamic\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/OSGI-INF/configuration-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n     RedHat Inc\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" configuration-policy=\"require\"\n    immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.core.test.IConfigurationServiceTest\">\n    <implementation class=\"org.eclipse.kura.core.test.ConfigurationServiceTest\" />\n    <service>\n        <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\" />\n    </service>\n    <property name=\"service.pid\" value=\"org.eclipse.kura.core.test.IConfigurationServiceTest\" />\n    <reference bind=\"setConfigurationService\" cardinality=\"1..1\"\n        interface=\"org.eclipse.kura.configuration.ConfigurationService\" name=\"ConfigurationService\"\n        policy=\"static\" unbind=\"unsetConfigurationService\" />\n    <reference bind=\"setSystemService\" cardinality=\"1..1\"\n        interface=\"org.eclipse.kura.system.SystemService\" name=\"SystemService\" policy=\"static\"\n        unbind=\"unsetSystemService\" />\n    <reference bind=\"setDataService\" cardinality=\"1..1\"\n        interface=\"org.eclipse.kura.data.DataService\" name=\"DataService\" policy=\"static\"\n        unbind=\"unsetDataService\" />\n    <reference bind=\"setCloudEndpoint\" cardinality=\"1..1\"\n        interface=\"org.eclipse.kura.cloudconnection.CloudEndpoint\" name=\"CloudEndpoint\"\n        policy=\"static\" />\n</scr:component>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/OSGI-INF/example-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"ExampleTest\">\n   <implementation class=\"org.eclipse.kura.core.test.ExampleTest\"/>\n   <reference bind=\"setDataService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.data.DataService\" name=\"DataService\" policy=\"static\" unbind=\"unsetDataService\"/>\n   <service>\n      <provide interface=\"org.eclipse.kura.data.DataServiceListener\"/>\n   </service>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/OSGI-INF/metatype/org.eclipse.kura.core.test.IConfigurationServiceTest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\">\n    <OCD id=\"org.eclipse.kura.core.test.IConfigurationServiceTest\" \n         name=\"ConfigurationServiceTest\" \n         description=\"ConfigurationServiceTest Configuration\">\n\n        <AD id=\"prop.string\"\n            name=\"prop.string\"\n            type=\"String\"\n            cardinality=\"0\" \n            required=\"true\"\n            default=\"prop.string.value\" \n            description=\"prop.string.value\"/>\n\n        <AD id=\"prop.long\"  \n            name=\"prop.long\"\n            type=\"Long\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"1351589588\" \n            description=\"prop.long.value\"/>\n\n        <AD id=\"prop.double\"  \n            name=\"prop.double\"\n            type=\"Double\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"13515895.9999988\" \n            description=\"prop.double.value\"/>\n\n        <AD id=\"prop.float\"  \n            name=\"prop.float\"\n            type=\"Float\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"3.14\" \n            description=\"prop.float.value\"/>\n\n        <AD id=\"prop.integer\"  \n            name=\"prop.integer\"\n            type=\"Integer\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"314\" \n            description=\"prop.integer.value\"/>\n\n        <AD id=\"prop.byte\"  \n            name=\"prop.byte\"\n            type=\"Byte\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"7\" \n            description=\"prop.byte.value\"/>\n        \n        <AD id=\"prop.character\"  \n            name=\"prop.character\"\n            type=\"Char\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"c\" \n            description=\"prop.character.value\"/>\n\n        <AD id=\"prop.boolean\"  \n            name=\"prop.boolean\"\n            type=\"Boolean\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"true\" \n            description=\"prop.boolean.value\"/>\n\n        <AD id=\"prop.short\"  \n            name=\"prop.short\"\n            type=\"Short\"\n            cardinality=\"0\" \n            required=\"false\"\n            default=\"255\" \n            description=\"prop.short.value\"/>\n\n        <AD id=\"prop.string.array\"\n            name=\"prop.string.array\"\n            type=\"String\"\n            cardinality=\"3\" \n            required=\"false\"\n            default=\"value1, value2, value3\" \n            description=\"prop.string.value\"/>\n\n        <AD id=\"prop.long.array\"  \n            name=\"prop.long.array\"\n            type=\"Long\"\n            cardinality=\"3\" \n            required=\"false\"\n            default=\"1351589588, 1351589589, 1351589590\" \n            description=\"prop.long.value\"/>\n\n        <AD id=\"prop.double.array\"  \n            name=\"prop.double.array\"\n            type=\"Double\"\n            cardinality=\"3\" \n            required=\"false\"\n            default=\"13515895.88, 13515895.89, 13515895.90\" \n            description=\"prop.double.value\"/>\n\n        <AD id=\"prop.float.array\"  \n            name=\"prop.float.array\"\n            type=\"Float\"\n            cardinality=\"3\" \n            required=\"false\"\n            default=\"3.14, 3.15, 3.16\" \n            description=\"prop.float.value\"/>\n\n        <AD id=\"prop.integer.array\"  \n            name=\"prop.integer.array\"\n            type=\"Integer\"\n            cardinality=\"3\" \n            required=\"false\"\n            default=\"314, 315, 316\" \n            description=\"prop.integer.value\"/>\n\n        <AD id=\"prop.byte.array\"  \n            name=\"prop.byte.array\"\n            type=\"Byte\"\n            cardinality=\"3\" \n            required=\"false\"\n            default=\"7, 8, 9\" \n            description=\"prop.byte.value\"/>\n        \n        <AD id=\"prop.character.array\"  \n            name=\"prop.character.array\"\n            type=\"Char\"\n            cardinality=\"3\" \n            required=\"false\"\n            default=\"c, d, e\" \n            description=\"prop.character.value\"/>\n\n        <AD id=\"prop.boolean.array\"  \n            name=\"prop.boolean.array\"\n            type=\"Boolean\"\n            cardinality=\"3\" \n            required=\"false\"\n            default=\"true, false, true\" \n            description=\"prop.boolean.value\"/>\n\n        <AD id=\"prop.short.array\"  \n            name=\"prop.short.array\"\n            type=\"Short\"\n            cardinality=\"3\" \n            required=\"false\"\n            default=\"253, 254, 255\" \n            description=\"prop.short.value\"/>\n        \n    </OCD>\n    <Designate pid=\"org.eclipse.kura.core.test.IConfigurationServiceTest\">\n        <Object ocdref=\"org.eclipse.kura.core.test.IConfigurationServiceTest\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/OSGI-INF/network-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"NetworkServiceTest\">\n   <implementation class=\"org.eclipse.kura.core.test.NetworkServiceTest\"/>\n   <reference bind=\"setNetworkService\" \n              cardinality=\"1..1\" \n              interface=\"org.eclipse.kura.net.NetworkService\" \n              name=\"NetworkService\" \n              policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/OSGI-INF/systemAdmin-test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"SystemAdminTest\">\n   <implementation class=\"org.eclipse.kura.core.test.SystemAdminServiceTest\"/>\n   <reference bind=\"setSystemAdminService\" \n              cardinality=\"1..1\" \n              interface=\"org.eclipse.kura.system.SystemAdminService\" \n              name=\"SystemAdminService\" \n              policy=\"static\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\noutput.. = target/classes/\nsource.. = src/test/java/,\\\n           src/main/java\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about_files/,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.eclipse.kura.test,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.core.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <moquette.path>${project.basedir}/src/main/resources/moquette/config</moquette.path>\n        <moquette.vm.args>\n            -server -XX:+HeapDumpOnOutOfMemoryError -Djava.awt.headless=true\n            -Dmoquette.path=${moquette.path}\n        </moquette.vm.args>\n        <kura.vm.args>\n            -Dkura.home=${project.basedir}/target/kura\n            -Dkura.plugins=${project.basedir}/target/kura/plugins\n            -Dkura.packages=${project.basedir}/target/kura/data/packages\n            -Dkura.data=${project.basedir}/target/kura/data\n            -Dkura.tmp=${project.basedir}/target/kura/tmp\n            -Dkura.snapshots=${project.basedir}/target/kura/user/snapshots\n            -Dorg.eclipse.kura.mode=emulator\n            -Dkura.configuration=file:${project.basedir}/src/main/resources/kura.properties\n            -Ddpa.configuration=${project.basedir}/target/kura/dpa.properties\n        </kura.vm.args>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n                <version>${tycho-version}</version>\n                <configuration>\n                    <providerHint>junit4</providerHint>\n                    <redirectTestOutputToFile>true</redirectTestOutputToFile>\n                    <testSuite>org.eclipse.kura.core.test</testSuite>\n                    <testClass>org.eclipse.kura.core.test.AllCoreTests</testClass>\n                    <!--\n                    <testClass>org.eclipse.kura.core.test.CloudDeploymentHandlerTest</testClass>\n                        <testClass>org.eclipse.kura.core.test.CloudServiceTest</testClass>\n                    <testClass>org.eclipse.kura.core.test.CommURITest</testClass>\n                        <testClass>org.eclipse.kura.core.test.ComponentConfigurationImplTest</testClass>\n                        <testClass>org.eclipse.kura.core.test.ConfigurationServiceTest</testClass>\n                        <testClass>org.eclipse.kura.core.test.NetUtilTest</testClass>\n                    <testClass>org.eclipse.kura.core.test.NetworkServiceTest</testClass>\n                        <testClass>org.eclipse.kura.core.test.SystemAdminServiceTest</testClass>\n                        <testClass>org.eclipse.kura.core.test.SystemServiceTest</testClass> -->\n                    <!-- Don't run tests in parallel because it breaks them\n                        <parallel>both</parallel> -->\n\n                    <useUnlimitedThreads>true</useUnlimitedThreads>\n                    <argLine>${tycho.testArgLine}\n                        -DbuildingWithTycho=true -Dosgi.locking=none\n                        -Dds.showtrace=true -Djava.io.tmpdir=/tmp\n                        -Dlog4j.configurationFile=file:${kura.basedir}/emulator/org.eclipse.kura.emulator/src/main/resources/log4j.xml\n                        ${kura.vm.args}\n                        ${moquette.vm.args}\n                    </argLine>\n\n                    <!-- This can be uncommented to debug the test in the\n                        event of a failure by telneting to port 5002 and seeing the state of the\n                        OSGi runtime -->\n                    <!-- <appArgLine>-consoleLog -console 5002 -noExit</appArgLine> -->\n\n                    <showEclipseLog>true</showEclipseLog>\n\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/AllCoreTests.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Suite;\nimport org.junit.runners.Suite.SuiteClasses;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.moquette.broker.Server;\nimport io.moquette.broker.config.FileResourceLoader;\nimport io.moquette.broker.config.IConfig;\nimport io.moquette.broker.config.IResourceLoader;\nimport io.moquette.broker.config.ResourceLoaderConfig;\n\n@RunWith(Suite.class)\n@SuiteClasses({ InventoryHandlerTest.class, CommURITest.class, ComponentConfigurationImplTest.class,\n        ConfigurationServiceTest.class, NetUtilTest.class, NetworkServiceTest.class, SystemAdminServiceTest.class })\npublic class AllCoreTests {\n\n    private static final Logger logger = LoggerFactory.getLogger(AllCoreTests.class);\n\n    /** A latch to be initialized with the no of OSGi dependencies needed */\n    private static CountDownLatch dependencyLatch = new CountDownLatch(3);\n\n    private static ConfigurationService configService;\n    private static DataService dataService;\n    private static SystemService sysService;\n\n    static Server mqttBroker;\n\n    public void setConfigService(ConfigurationService configService) {\n        AllCoreTests.configService = configService;\n        dependencyLatch.countDown();\n    }\n\n    public void unsetConfigService(ConfigurationService configService) {\n        AllCoreTests.configService = configService;\n    }\n\n    public void setDataService(DataService dataService) {\n        AllCoreTests.dataService = dataService;\n        dependencyLatch.countDown();\n    }\n\n    public void unsetDataService(DataService dataService) {\n        AllCoreTests.dataService = dataService;\n    }\n\n    public void setSystemService(SystemService sysService) {\n        AllCoreTests.sysService = sysService;\n        dependencyLatch.countDown();\n    }\n\n    public void unsetSystemService(SystemService sysService) {\n        AllCoreTests.sysService = sysService;\n    }\n\n    @BeforeClass\n    public static void setUpClass() throws Exception {\n        logger.info(\"setUpClass...\");\n\n        // start Moquette\n        startMqttBroker();\n\n        // Wait for OSGi dependencies\n        logger.info(\"Setting Up The Testcase....\");\n        try {\n            dependencyLatch.await(10, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new Exception(\"OSGi dependencies unfulfilled\", e);\n        }\n\n        try {\n            // update the settings\n            ComponentConfiguration mqttConfig = configService\n                    .getComponentConfiguration(\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\");\n            Map<String, Object> mqttProps = mqttConfig.getConfigurationProperties();\n\n            logger.info(\"Changing cloud credentials...\");\n            mqttProps.put(\"broker-url\", \"mqtt://localhost:1883/\");\n            mqttProps.put(\"topic.context.account-name\", \"ethdev\");\n            mqttProps.put(\"username\", \"\");\n            mqttProps.put(\"password\", \"\");\n\n            // cloudbees fails in getting the primary MAC address\n            // we need to compensate for it.\n            String clientId = null;\n            try {\n                clientId = sysService.getPrimaryMacAddress();\n            } catch (Exception t) {\n                // ignore.\n            }\n            if (clientId == null || clientId.isEmpty()) {\n                clientId = \"cloudbees-kura\";\n            }\n            mqttProps.put(\"client-id\", clientId);\n            configService.updateConfiguration(\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\", mqttProps);\n\n            ComponentConfiguration dataConfig = configService\n                    .getComponentConfiguration(\"org.eclipse.kura.data.DataService\");\n            Map<String, Object> dataProps = dataConfig.getConfigurationProperties();\n            dataProps.put(\"connect.auto-on-startup\", false);\n            dataProps.put(\"enable.rate.limit\", false);\n            configService.updateConfiguration(\"org.eclipse.kura.data.DataService\", dataProps);\n\n            Map<String, Object> cloudProps = new HashMap<>();\n            cloudProps.put(\"topic.control-prefix\", \"EDC\");\n            configService.updateConfiguration(\"org.eclipse.kura.cloud.CloudService\", cloudProps);\n\n            // waiting for the configuration to be applied\n            try {\n                Thread.sleep(1000);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        } catch (Exception e) {\n            throw new Exception(\"Failed to reconfigure the broker settings - failing out\", e);\n        }\n\n        // connect\n        if (!dataService.isConnected()) {\n            dataService.connect();\n        }\n    }\n\n    public static void startMqttBroker() throws Exception {\n\n        logger.info(\"Starting Moquette MQTT broker... with path: {}\", \"moquette.conf\");\n        IResourceLoader fileLoader = new FileResourceLoader();\n        IConfig classPathConfig = new ResourceLoaderConfig(fileLoader, \"moquette.conf\");\n\n        mqttBroker = new Server();\n        mqttBroker.startServer(classPathConfig);\n        logger.info(\"Moquette MQTT broker started\");\n\n        Runtime.getRuntime().addShutdownHook(new Thread(() -> stopBroker()));\n    }\n\n    public static void stopBroker() {\n        if (mqttBroker != null) {\n            mqttBroker.stopServer();\n        }\n        logger.info(\"Moquette MQTT broker stopped\");\n    }\n\n    @AfterClass\n    public static void tearDownClass() throws Exception {\n        logger.info(\"tearDownClass...\");\n        if (dataService != null && dataService.isConnected()) {\n            dataService.disconnect(0);\n        }\n        stopBroker();\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/CloudEndpointPublisher.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudPayloadProtoBufDecoder;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.listener.DataServiceListener;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraRequestPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\n\npublic class CloudEndpointPublisher implements DataServiceListener {\n\n    private static RequestIdGenerator generator = RequestIdGenerator.getInstance();\n\n    private static final int DFLT_PUB_QOS = 0;\n    private static final boolean DFLT_RETAIN = false;\n    private static final int DFLT_PRIORITY = 1;\n\n    private static final String ACCOUNT_NAME_VAR_NAME = \"#account-name\";\n    private static final String CLIENT_ID_VAR_NAME = \"#client-id\";\n\n    private CloudEndpoint cloudEndpoint;\n    private CloudPayloadProtoBufDecoder cloudPayloadProtoBufDecoder;\n    private DataService dataService;\n\n    private Map<String, CompletableFuture<KuraResponsePayload>> callFutures = new ConcurrentHashMap<>();\n\n    public CloudEndpointPublisher(CloudEndpoint cloudEndpoint, DataService dataService) {\n        this.cloudEndpoint = cloudEndpoint;\n        this.cloudPayloadProtoBufDecoder = (CloudPayloadProtoBufDecoder) cloudEndpoint;\n        this.dataService = dataService;\n        dataService.addDataServiceListener(this);\n    }\n\n    public synchronized KuraResponsePayload call(String appId, String appTopic, KuraPayload appPayload, int timeout)\n            throws KuraException {\n        return call(CLIENT_ID_VAR_NAME, appId, appTopic, appPayload, timeout);\n    }\n\n    public KuraResponsePayload call(String deviceId, String appId, String appTopic, KuraPayload appPayload, int timeout)\n            throws KuraException {\n\n        String requestId = generator.next();\n\n        String sbReqTopic = new StringBuilder(\"EDC\").append(\"/\").append(ACCOUNT_NAME_VAR_NAME).append(\"/\")\n                .append(deviceId).append(\"/\").append(appId).append(\"/\").append(appTopic).toString();\n\n        String sbRespTopic = new StringBuilder(\"EDC\").append(\"/\").append(ACCOUNT_NAME_VAR_NAME).append(\"/\")\n                .append(CLIENT_ID_VAR_NAME).append(\"/\").append(appId).append(\"/\").append(\"REPLY\").append(\"/\")\n                .append(requestId).toString();\n\n        KuraRequestPayload req = null;\n        if (appPayload != null) {\n            // Construct a request payload\n            req = new KuraRequestPayload(appPayload);\n        } else {\n            req = new KuraRequestPayload();\n        }\n\n        req.setRequestId(requestId);\n        req.setRequesterClientId(CLIENT_ID_VAR_NAME);\n\n        Map<String, Object> publishMessageProps = new HashMap<>();\n        publishMessageProps.put(\"FULL_TOPIC\", sbReqTopic);\n        publishMessageProps.put(\"QOS\", DFLT_PUB_QOS);\n        publishMessageProps.put(\"RETAIN\", DFLT_RETAIN);\n        publishMessageProps.put(\"PRIORITY\", DFLT_PRIORITY);\n\n        KuraMessage kuraMessage = new KuraMessage(req, publishMessageProps);\n\n        CompletableFuture<KuraResponsePayload> cf = new CompletableFuture<>();\n        callFutures.put(requestId, cf);\n\n        this.dataService.subscribe(sbRespTopic, 0);\n\n        try {\n            this.cloudEndpoint.publish(kuraMessage);\n            return cf.get(timeout, TimeUnit.MILLISECONDS);\n        } catch (Exception e) {\n            throw new KuraException(KuraErrorCode.BAD_REQUEST);\n        } finally {\n            try {\n                dataService.unsubscribe(sbRespTopic);\n            } catch (KuraException e) {\n                // s_logger.error(\"Cannot unsubscribe\");\n            }\n\n            callFutures.remove(requestId);\n        }\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n\n        CompletableFuture<KuraResponsePayload> future = callFutures.remove(getLastPartAfterSlash(topic));\n\n        if (future != null) {\n\n            try {\n                KuraPayload kuraPayload = cloudPayloadProtoBufDecoder.buildFromByteArray(payload);\n                future.complete(new KuraResponsePayload(kuraPayload));\n            } catch (Exception e) {\n                future.completeExceptionally(e);\n            }\n\n        }\n    }\n\n    @Override\n    public void onConnectionEstablished() {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onDisconnecting() {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onDisconnected() {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        // TODO Auto-generated method stub\n\n    }\n\n    public static String getLastPartAfterSlash(String input) {\n        if (input == null || input.isEmpty()) {\n            return \"\";\n        }\n\n        int lastSlashIndex = input.lastIndexOf('/');\n        if (lastSlashIndex == -1) {\n            // No slash found in the string\n            return input;\n        } else if (lastSlashIndex == input.length() - 1) {\n            // Input ends with a slash, return empty string\n            return \"\";\n        } else {\n            // Return everything after the last slash\n            return input.substring(lastSlashIndex + 1);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/CommURITest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport org.eclipse.kura.comm.CommURI;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.Test;\n\nimport junit.framework.TestCase;\n\npublic class CommURITest extends TestCase {\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testSyntax() throws Exception {\n        CommURI commUri = new CommURI.Builder(\"/dev/ttyUSB0\").withBaudRate(4800).build();\n        System.out.println(commUri);\n\n        CommURI commUri1 = CommURI.parseString(commUri.toString());\n        System.out.println(commUri1);\n\n        assertEquals(commUri1.toString(), commUri.toString());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/ComponentConfigurationImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport org.eclipse.kura.core.configuration.util.StringUtil;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.Test;\n\nimport junit.framework.TestCase;\n\npublic class ComponentConfigurationImplTest extends TestCase {\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testSplitDefaultValues() throws Exception {\n        String defaultString = \"abc, def, 124  , qwer\\\\, ty , ed, \\\\ \\\\ spa ce\\\\ , 789\";\n        String[] defaultValues = StringUtil.splitValues(defaultString);\n        for (String s : defaultValues) {\n            System.err.println(s);\n        }\n        assertEquals(7, defaultValues.length);\n        assertEquals(\"abc\", defaultValues[0]);\n        assertEquals(\"def\", defaultValues[1]);\n        assertEquals(\"124\", defaultValues[2]);\n        assertEquals(\"qwer, ty\", defaultValues[3]);\n        assertEquals(\"ed\", defaultValues[4]);\n        assertEquals(\"  spa ce \", defaultValues[5]);\n        assertEquals(\"789\", defaultValues[6]);\n\n        String expected = \"abc,def,124,qwer\\\\,\\\\ ty,ed,\\\\ \\\\ spa\\\\ ce\\\\ ,789\";\n        String joined = StringUtil.valueToString(defaultValues);\n        assertEquals(expected, joined);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testSplitDefaultValues2() throws Exception {\n        String defaultString = \"  a\\\\,b,b\\\\,c,\\\\ c\\\\\\\\,d   \";\n        String[] defaultValues = StringUtil.splitValues(defaultString);\n\n        assertEquals(4, defaultValues.length);\n        assertEquals(\"a,b\", defaultValues[0]);\n        assertEquals(\"b,c\", defaultValues[1]);\n        assertEquals(\" c\\\\\", defaultValues[2]);\n        assertEquals(\"d\", defaultValues[3]);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/ConfigurationServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport java.io.StringReader;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudletTopic;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.configuration.CloudConfigurationHandler;\nimport org.eclipse.kura.core.configuration.ComponentConfigurationImpl;\nimport org.eclipse.kura.core.configuration.XmlComponentConfigurations;\nimport org.eclipse.kura.core.configuration.XmlSnapshotIdResult;\nimport org.eclipse.kura.core.test.util.CoreTestXmlUtil;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.eclipse.kura.system.SystemService;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.eclipse.kura.util.service.ServiceUtil;\nimport org.junit.Test;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport junit.framework.TestCase;\n\npublic class ConfigurationServiceTest extends TestCase implements IConfigurationServiceTest, ConfigurableComponent {\n\n    private static final Logger s_logger = LoggerFactory.getLogger(ConfigurationServiceTest.class);\n\n    private static CountDownLatch dependencyLatch = new CountDownLatch(4);\t// initialize with number of dependencies\n    private static Object lock = new Object(); // initialize with number of dependencies\n    private static ConfigurationService configService;\n    private static SystemService systemService;\n    private static CloudEndpointPublisher cloudEndpointPublisher;\n    private static CloudEndpoint cloudEndpoint;\n    private static DataService dataService;\n\n    @SuppressWarnings(\"unused\")\n    private static ComponentContext componentContext;\n\n    private static Map<String, Object> properties;\n\n    private static long updateTime = 0;\n\n    @Override\n    public void setUp() {\n        // Wait for OSGi dependencies\n        try {\n            boolean ok = dependencyLatch.await(10, TimeUnit.SECONDS);\n            if (!ok) {\n                fail(\"Dependencies not resolved!\");\n            }\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            fail(\"OSGi dependencies unfulfilled\");\n        }\n        cloudEndpointPublisher = new CloudEndpointPublisher(cloudEndpoint, dataService);\n    }\n\n    public void setConfigurationService(ConfigurationService configurationService) {\n        ConfigurationServiceTest.configService = configurationService;\n        dependencyLatch.countDown();\n    }\n\n    public void setSystemService(SystemService systemService) {\n        ConfigurationServiceTest.systemService = systemService;\n        dependencyLatch.countDown();\n    }\n\n    public void setCloudEndpoint(CloudEndpoint cloudEndpoint) {\n        ConfigurationServiceTest.cloudEndpoint = cloudEndpoint;\n        dependencyLatch.countDown();\n    }\n\n    public void setDataService(DataService dataService) {\n        ConfigurationServiceTest.dataService = dataService;\n        dependencyLatch.countDown();\n    }\n\n    public void unsetConfigurationService(ConfigurationService configurationService) {\n        ConfigurationServiceTest.configService = null;\n    }\n\n    public void unsetSystemService(SystemService systemService) {\n        ConfigurationServiceTest.systemService = null;\n    }\n\n    public void unsetDataService(DataService dataService) {\n        ConfigurationServiceTest.dataService = null;\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testServiceExists() {\n        assertNotNull(ConfigurationServiceTest.configService);\n    }\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        s_logger.info(\"ConfigurationServiceTest.activate...\");\n        ConfigurationServiceTest.componentContext = componentContext;\n        ConfigurationServiceTest.properties = properties;\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        s_logger.info(\"ConfigurationServiceTest.deactivate...\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        s_logger.info(\"Updated called: \" + properties);\n\n        Set<Entry<String, Object>> entries = properties.entrySet();\n        for (Map.Entry<String, Object> entry : entries) {\n            System.err.println(\"\\t\\t\" + entry.getKey() + \" = \" + entry.getValue());\n        }\n\n        ConfigurationServiceTest.properties = properties;\n        updateTime = System.currentTimeMillis();\n        synchronized (lock) {\n            lock.notifyAll();\n        }\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testLocalConfiguration() throws Exception {\n        String pid = \"org.eclipse.kura.core.test.IConfigurationServiceTest\";\n        s_logger.info(\"configService 1:\" + ConfigurationServiceTest.configService);\n        synchronized (lock) {\n            lock.wait(5000);\n        }\n\n        s_logger.info(\"Asserting default values...\");\n\n        //\n        // test the default properties\n        assertDefaultValues(properties);\n\n        //\n        // take a snapshot\n        s_logger.info(\"configService 2:\" + ConfigurationServiceTest.configService);\n        s_logger.info(\"Taking snapshot...\");\n\n        long sid;\n        sid = ConfigurationServiceTest.configService.snapshot();\n\n        //\n        // test a positive update flow\n        Hashtable<String, Object> props = new Hashtable<String, Object>();\n        Set<String> keys = properties.keySet();\n        for (String key : keys) {\n            props.put(key, properties.get(key));\n        }\n        props.put(\"prop.string\", \"string_prop\");\n        props.put(\"prop.long\", 9999L);\n        props.put(\"prop.double\", 99.99D);\n        props.put(\"prop.float\", 99.99F);\n        props.put(\"prop.integer\", 99999);\n        props.put(\"prop.character\", '9');\n        props.put(\"prop.boolean\", false);\n\n        short s9 = (short) 9;\n        props.put(\"prop.short\", s9);\n\n        byte b9 = (byte) 9;\n        props.put(\"prop.byte\", b9);\n\n        s_logger.info(\"configService 3:\" + ConfigurationServiceTest.configService);\n        s_logger.info(\"Updating configuration with new values for \" + pid + \" with props: \" + props);\n        long previousUpdateTime = System.currentTimeMillis();\n        ConfigurationServiceTest.configService.updateConfiguration(pid, props);\n        assertTrue(waitForConfigurationUpdate(previousUpdateTime));\n\n        s_logger.info(\"Asserting values...\");\n        assertEquals(\"string_prop\", properties.get(\"prop.string\"));\n        assertEquals(9999L, properties.get(\"prop.long\"));\n        assertEquals(99.99D, properties.get(\"prop.double\"));\n        assertEquals(99.99F, properties.get(\"prop.float\"));\n        assertEquals(99999, properties.get(\"prop.integer\"));\n        assertEquals('9', properties.get(\"prop.character\"));\n        assertEquals(false, properties.get(\"prop.boolean\"));\n        assertEquals(s9, properties.get(\"prop.short\"));\n        assertEquals(b9, properties.get(\"prop.byte\"));\n\n        // test a negative update flow\n        props.clear();\n        keys = properties.keySet();\n        for (String key : keys) {\n            props.put(key, properties.get(key));\n        }\n        props.put(\"prop.long\", \"AAAA\");\n        try {\n            ConfigurationServiceTest.configService.updateConfiguration(pid, props);\n            assertFalse(\"Configuration update should have failed\", false);\n        } catch (KuraException e) {\n            assertTrue(\"Configuration update has failed as expected\", true);\n            assertEquals(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, e.getCode());\n        }\n\n        // test a negative update flow\n        props.clear();\n        keys = properties.keySet();\n        for (String key : keys) {\n            props.put(key, properties.get(key));\n        }\n        props.remove(\"prop.string\");\n        try {\n            ConfigurationServiceTest.configService.updateConfiguration(pid, props);\n            assertFalse(\"Configuration update should have failed\", false);\n        } catch (KuraException e) {\n            assertTrue(\"Configuration update has failed as expected\", true);\n            assertEquals(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, e.getCode());\n        }\n\n        //\n        // restore a snapshot\n        previousUpdateTime = System.currentTimeMillis();\n\n        s_logger.info(\"Rolling back...\");\n        ConfigurationServiceTest.configService.rollback(sid);\n\n        // Wait for a configuration update\n        assertTrue(waitForConfigurationUpdate(previousUpdateTime));\n        assertDefaultValues(properties);\n    }\n\n    private boolean waitForConnection() throws InterruptedException {\n        int attempts = 10;\n        while (attempts > 0) {\n            if (dataService.isConnected()) {\n                return true;\n            }\n            Thread.sleep(1000);\n            attempts--;\n        }\n        return false;\n    }\n\n    private boolean waitForConfigurationUpdate(long previousUpdateTime) throws InterruptedException {\n        synchronized (lock) {\n            if (previousUpdateTime < updateTime) {\n                return true;\n            }\n            lock.wait(30000);\n            return previousUpdateTime < updateTime;\n        }\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testRemoteConfiguration() throws Exception {\n        if (!dataService.isConnected()) {\n            dataService.connect();\n        }\n        assertTrue(dataService.isConnected());\n        assertDefaultValues(properties);\n\n        s_logger.info(\"Starting testRemoteConfiguration\");\n\n        String pid = \"org.eclipse.kura.core.test.IConfigurationServiceTest\";\n\n        // load the current configuration\n        s_logger.info(\"loading the current configuration\");\n\n        StringBuilder sb = new StringBuilder(CloudletTopic.Method.GET.toString()).append(\"/\")\n                .append(CloudConfigurationHandler.RESOURCE_CONFIGURATIONS).append(\"/\").append(pid);\n\n        KuraResponsePayload resp = cloudEndpointPublisher.call(CloudConfigurationHandler.APP_ID, sb.toString(), null,\n                10000);\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resp.getResponseCode());\n        assertNotNull(resp.getBody());\n\n        // unmarshall the response\n        String s = new String(resp.getBody(), \"UTF-8\");\n        XmlComponentConfigurations xmlConfigs = unmarshalXml(s, XmlComponentConfigurations.class);\n\n        System.err.println(\"Checking current configuration\");\n        List<ComponentConfiguration> configs = xmlConfigs.getConfigurations();\n        assertDefaultValues(configs.get(0).getConfigurationProperties());\n\n        // take a snapshot\n        System.err.println(\"taking a snapshot\");\n\n        sb = new StringBuilder(CloudletTopic.Method.EXEC.toString()).append(\"/\")\n                .append(CloudConfigurationHandler.RESOURCE_SNAPSHOT);\n\n        resp = cloudEndpointPublisher.call(CloudConfigurationHandler.APP_ID, sb.toString(), null, 10000);\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resp.getResponseCode());\n        assertNotNull(resp.getBody());\n\n        // unmarshall the response\n        s = new String(resp.getBody(), \"UTF-8\");\n        StringReader sr = new StringReader(s);\n        // XmlSnapshotIdResult snapshotIds = XmlUtil.unmarshal(sr, XmlSnapshotIdResult.class);\n        XmlSnapshotIdResult snapshotIds = CoreTestXmlUtil.unmarshal(sr, XmlSnapshotIdResult.class);\n\n        s_logger.info(\"validating configuration\");\n        assertNotNull(snapshotIds);\n        assertEquals(1, snapshotIds.getSnapshotIds().size());\n\n        long sid = snapshotIds.getSnapshotIds().get(0);\n\n        // modify the configuration\n        s_logger.info(\"modifying configuration\");\n        ComponentConfigurationImpl ccnew = new ComponentConfigurationImpl();\n        ccnew.setPid(pid);\n        Hashtable<String, Object> propsnew = new Hashtable<String, Object>();\n        propsnew.put(\"prop.string\", \"modified_value\");\n        ccnew.setProperties(propsnew);\n\n        XmlComponentConfigurations newConfigs = new XmlComponentConfigurations();\n        List<ComponentConfiguration> newccs = new ArrayList<ComponentConfiguration>();\n        newccs.add(ccnew);\n        newConfigs.setConfigurations(newccs);\n\n        // TODO: solve this\n        String result = marshalXml(newConfigs);\n\n        KuraPayload payload = new KuraPayload();\n        if (result != null) {\n            payload.setBody(result.getBytes());\n        }\n\n        sb = new StringBuilder(CloudletTopic.Method.PUT.toString()).append(\"/\")\n                .append(CloudConfigurationHandler.RESOURCE_CONFIGURATIONS).append(\"/\").append(pid);\n\n        long previousUpdateTime = this.updateTime;\n\n        resp = cloudEndpointPublisher.call(CloudConfigurationHandler.APP_ID, sb.toString(), payload, 10000);\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resp.getResponseCode());\n\n        assertTrue(waitForConfigurationUpdate(previousUpdateTime));\n\n        s_logger.info(\"validating modified configuration\");\n        s_logger.info(\"Checking these are equal: \" + properties.get(\"prop.string\") + \" AND \" + \"modified_value\");\n        assertEquals(\"modified_value\", properties.get(\"prop.string\"));\n\n        // reload the current configuration\n        s_logger.info(\"reloading the current configuration\");\n\n        sb = new StringBuilder(CloudletTopic.Method.GET.toString()).append(\"/\")\n                .append(CloudConfigurationHandler.RESOURCE_CONFIGURATIONS).append(\"/\").append(pid);\n\n        resp = cloudEndpointPublisher.call(CloudConfigurationHandler.APP_ID, sb.toString(), null, 10000);\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resp.getResponseCode());\n        assertNotNull(resp.getBody());\n\n        // unmarshall the response\n        s = new String(resp.getBody(), \"UTF-8\");\n        System.err.println(s);\n\n        xmlConfigs = unmarshalXml(s, XmlComponentConfigurations.class);\n\n        s_logger.info(\"validating modified configuration\");\n        assertNotNull(xmlConfigs);\n        ComponentConfiguration ccmod = xmlConfigs.getConfigurations().get(0);\n        s_logger.info(\"Checking these are equal: \" + ccmod.getConfigurationProperties().get(\"prop.string\") + \" AND \"\n                + \"modified_value\");\n        assertEquals(\"modified_value\", ccmod.getConfigurationProperties().get(\"prop.string\"));\n\n        // rollback\n        sb = new StringBuilder(CloudletTopic.Method.EXEC.toString()).append(\"/\")\n                .append(CloudConfigurationHandler.RESOURCE_ROLLBACK).append(\"/\").append(sid);\n\n        previousUpdateTime = System.currentTimeMillis();\n\n        resp = cloudEndpointPublisher.call(CloudConfigurationHandler.APP_ID, sb.toString(), null, 10000);\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resp.getResponseCode());\n\n        // Wait for everything to get stable\n        assertTrue(waitForConfigurationUpdate(previousUpdateTime));\n        assertDefaultValues(properties);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testSnapshotsMaxCount() throws Exception {\n        int maxCount = ConfigurationServiceTest.systemService.getKuraSnapshotsCount();\n        for (int i = 0; i < maxCount * 2; i++) {\n            ConfigurationServiceTest.configService.snapshot();\n        }\n\n        Set<Long> sids = ConfigurationServiceTest.configService.getSnapshots();\n        assertEquals(maxCount, sids.size());\n    }\n\n    private void assertDefaultValues(Map<String, Object> properties) {\n        // scalar properties\n        assertEquals(\"prop.string.value\", properties.get(\"prop.string\"));\n        assertEquals(1351589588L, properties.get(\"prop.long\"));\n        assertEquals(13515895.9999988, properties.get(\"prop.double\"));\n        assertEquals(3.14F, properties.get(\"prop.float\"));\n        assertEquals(314, properties.get(\"prop.integer\"));\n        assertEquals('c', properties.get(\"prop.character\"));\n        assertEquals(true, properties.get(\"prop.boolean\"));\n\n        short s = (short) 255;\n        assertEquals(s, properties.get(\"prop.short\"));\n\n        byte b = (byte) 7;\n        assertEquals(b, properties.get(\"prop.byte\"));\n\n        // array properties\n        String[] stringValues = new String[] { \"value1\", \"value2\", \"value3\" };\n        assertTrue(Arrays.equals(stringValues, (String[]) properties.get(\"prop.string.array\")));\n\n        Long[] longValues = new Long[] { 1351589588L, 1351589589L, 1351589590L };\n        assertTrue(Arrays.equals(longValues, (Long[]) properties.get(\"prop.long.array\")));\n\n        Double[] doubleValues = new Double[] { 13515895.88, 13515895.89, 13515895.90 };\n        assertTrue(Arrays.equals(doubleValues, (Double[]) properties.get(\"prop.double.array\")));\n\n        Float[] floatValues = new Float[] { 3.14F, 3.15F, 3.16F };\n        assertTrue(Arrays.equals(floatValues, (Float[]) properties.get(\"prop.float.array\")));\n\n        Integer[] intValues = new Integer[] { 314, 315, 316 };\n        assertTrue(Arrays.equals(intValues, (Integer[]) properties.get(\"prop.integer.array\")));\n\n        Character[] charValues = new Character[] { 'c', 'd', 'e' };\n        assertTrue(Arrays.equals(charValues, (Character[]) properties.get(\"prop.character.array\")));\n\n        Boolean[] boolValues = new Boolean[] { true, false, true };\n        assertTrue(Arrays.equals(boolValues, (Boolean[]) properties.get(\"prop.boolean.array\")));\n\n        Short[] shortValues = new Short[] { (short) 253, (short) 254, (short) 255 };\n        assertTrue(Arrays.equals(shortValues, (Short[]) properties.get(\"prop.short.array\")));\n\n        Byte[] byteValues = new Byte[] { (byte) 7, (byte) 8, (byte) 9 };\n        assertTrue(Arrays.equals(byteValues, (Byte[]) properties.get(\"prop.byte.array\")));\n    }\n\n    private ServiceReference<Marshaller>[] getXmlMarshallers() {\n        String filterString = String.format(\"(&(kura.service.pid=%s))\",\n                \"org.eclipse.kura.xml.marshaller.unmarshaller.provider\");\n        return ServiceUtil.getServiceReferences(componentContext.getBundleContext(), Marshaller.class, filterString);\n    }\n\n    private ServiceReference<Unmarshaller>[] getXmlUnmarshallers() {\n        String filterString = String.format(\"(&(kura.service.pid=%s))\",\n                \"org.eclipse.kura.xml.marshaller.unmarshaller.provider\");\n        return ServiceUtil.getServiceReferences(componentContext.getBundleContext(), Unmarshaller.class, filterString);\n    }\n\n    private void ungetServiceReferences(final ServiceReference<?>[] refs) {\n        ServiceUtil.ungetServiceReferences(componentContext.getBundleContext(), refs);\n    }\n\n    private <T> T unmarshalXml(String xmlString, Class<T> clazz) throws KuraException {\n        T result = null;\n        ServiceReference<Unmarshaller>[] unmarshallerSRs = getXmlUnmarshallers();\n        try {\n            for (final ServiceReference<Unmarshaller> unmarshallerSR : unmarshallerSRs) {\n                Unmarshaller unmarshaller = componentContext.getBundleContext().getService(unmarshallerSR);\n                result = unmarshaller.unmarshal(xmlString, clazz);\n            }\n        } catch (Exception e) {\n            s_logger.warn(\"Failed to extract persisted configuration.\");\n        } finally {\n            ungetServiceReferences(unmarshallerSRs);\n        }\n        if (result == null) {\n            throw new KuraException(KuraErrorCode.DECODER_ERROR, \"configuration\");\n        }\n        return result;\n    }\n\n    private String marshalXml(Object object) {\n        String result = null;\n        ServiceReference<Marshaller>[] marshallerSRs = getXmlMarshallers();\n        try {\n            for (final ServiceReference<Marshaller> marshallerSR : marshallerSRs) {\n                Marshaller marshaller = componentContext.getBundleContext().getService(marshallerSR);\n                result = marshaller.marshal(object);\n            }\n        } catch (Exception e) {\n            s_logger.warn(\"Failed to marshal configuration.\");\n        } finally {\n            ungetServiceReferences(marshallerSRs);\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/ExampleTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *  Red Hat Inc \n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.Condition;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport org.eclipse.kura.KuraConnectException;\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.data.DataServiceListener;\nimport org.junit.After;\nimport org.junit.AfterClass;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.osgi.service.component.ComponentContext;\n\n@SuppressWarnings(\"deprecation\")\npublic class ExampleTest implements DataServiceListener {\n\n    // If you wonder why we need to use static members is our test cases, keep reading.\n    // Two instances of the ExampleTest gets created during the test run:\n    // * by the OSGi framework (this is a declarative service component)\n    // * by the JUnit framework. This instance needs to access the OSGi service we want to test (the dependency).\n    // The service being tested is provided by the OSGi framework through the setXxxService bind method.\n    // Thus the service need to be shared across the two ExampleTest instances\n    // through a static class member.\n    //\n    // The CountDownLatch instance need to be shared too because it's checked by the\n    // ExampleTest instance created by JUnit but decremented by the instance\n    // created by OSGi.\n    //\n    // In the example below the service under test (the dependency) is the DataService.\n    // The DataService notifies some events to interested client components, the ExampleTest\n    // class in this example, through the DataServiceListener interface.\n    // The ExampleTest does not register itself as a listener explicitly calling a register method of the\n    // DataService. Instead, it registers the DataServiceListener as a provided service in its component definition.\n    // The DataService will dynamically discover from the OSGi service registry the registered DataServiceListeners.\n    //\n    // The important thing to note here is that, while the ExampleTest instance created by OSGi is registered\n    // to the OSGi framework as a DataServiceListener, the one created by JUnit is not.\n    // When JUnit runs a test, it uses the DataService through its instance of ExampleTest.\n    // Since this instance is not registered in the OSGi framework, the DataService will not find it and\n    // will not call it.\n    // This is a problem if a JUnit test needs to synchronize with a callback because the synchronization\n    // cannot happen through instance members (e.g. a Lock).\n    // The easiest think is to share everything is needed through static members.\n    //\n    // See also:\n    // http://stackoverflow.com/questions/7161338/using-osgi-declarative-services-in-the-context-of-a-junit-test\n    private static DataService s_dataService;\n    private static CountDownLatch s_dependencyLatch = new CountDownLatch(1);\t// initialize with number of\n    // dependencies\n\n    private static Lock s_lock = new ReentrantLock();\n    private static Condition s_condition = s_lock.newCondition();\n    private static Set<Integer> s_messageIds = new HashSet<Integer>();\n\n    public ExampleTest() {\n        super();\n        System.err.println(\"New instance created\");\n    }\n\n    //\n    // OSGi activation methods. These methods are called only once.\n    // There is only a single instance of this class created by the OSGi framework.\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        System.err.println(\"ExampleTest instance :\" + System.identityHashCode(this) + \": activated\");\n    }\n\n    public void updated(Map<String, Object> properties) {\n        System.err.println(\"ExampleTest instance :\" + System.identityHashCode(this) + \": updated\");\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        System.err.println(\"ExampleTest instance :\" + System.identityHashCode(this) + \": deactivated\");\n    }\n\n    public void setDataService(DataService dataService) {\n        System.err.println(\"ExampleTest instance :\" + System.identityHashCode(this) + \": setXxxService\");\n        s_dataService = dataService;\n        s_dependencyLatch.countDown();\n    }\n\n    public void unsetDataService(DataService dataService) {\n        System.err.println(\"ExampleTest instance :\" + System.identityHashCode(this) + \": unsetDataService\");\n        s_dataService = null;\n    }\n\n    //\n    // JUnit 4 stuff\n    @BeforeClass\n    public static void setUpOnce() {\n        System.err.println(\"Setup test preconditions. This static method is called once\");\n        // Wait for OSGi dependencies\n        try {\n            s_dependencyLatch.await(5, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            fail(\"OSGi dependencies unfulfilled\");\n        }\n    }\n\n    @Before\n    public void setUp() throws KuraConnectException {\n        System.err.println(\"ExampleTest instance :\" + System.identityHashCode(this)\n                + \": setup test preconditions. This is method is called before every @Test method like the JUnit 3 setUp method\");\n        if (!s_dataService.isConnected()) {\n            s_dataService.connect();\n        }\n    }\n\n    @Test\n    public void Test() throws InterruptedException, KuraStoreException {\n        System.err.println(\"ExampleTest instance :\" + System.identityHashCode(this) + \": test\");\n\n        s_lock.lock();\n        try {\n            Integer messageId = s_dataService.publish(\"#account-name/#client-id/a/b/c\", \"Hello!\".getBytes(), 1, false,\n                    5);\n            s_messageIds.add(messageId);\n            boolean confirmed = s_condition.await(5, TimeUnit.SECONDS);\n            assertTrue(confirmed);\n        } catch (KuraStoreException e) {\n            throw e;\n        } catch (InterruptedException e) {\n            throw e;\n        } finally {\n            s_lock.unlock();\n        }\n    }\n\n    @After\n    public void tearDown() {\n        System.err.println(\"ExampleTest instance :\" + System.identityHashCode(this)\n                + \": release resources that might have been allocated by the @Before method. This is method is called after every @Test method like the JUnit 3 tearDown method\");\n    }\n\n    @AfterClass\n    public static void tearDownOnce() {\n        System.err.println(\n                \"Release resources that might have been allocated by the @BeforeClass method. This static method is called once\");\n    }\n\n    //\n    // DataServiceListener\n    @Override\n    public void onConnectionEstablished() {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onDisconnecting() {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onDisconnected() {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onConnectionLost(Throwable cause) {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onMessagePublished(int messageId, String topic) {\n        // TODO Auto-generated method stub\n\n    }\n\n    @Override\n    public void onMessageConfirmed(int messageId, String topic) {\n        System.err.println(\"ExampleTest instance :\" + System.identityHashCode(this) + \": onMessageConfirmed\");\n        s_lock.lock();\n        s_messageIds.remove(messageId);\n        if (s_messageIds.isEmpty()) {\n            s_condition.signal();\n        }\n        s_lock.unlock();\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/IConfigurationServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\npublic interface IConfigurationServiceTest {\n\n    // DO NOT REMOVE - used by the ConfigurationServiceTest\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/InventoryHandlerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.cloud.CloudletTopic;\nimport org.eclipse.kura.core.inventory.InventoryHandlerV1;\nimport org.eclipse.kura.data.DataService;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.service.deploymentadmin.DeploymentAdmin;\nimport org.osgi.service.deploymentadmin.DeploymentException;\nimport org.osgi.service.deploymentadmin.DeploymentPackage;\n\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\n\nimport junit.framework.TestCase;\n\npublic class InventoryHandlerTest extends TestCase {\n\n    private static CountDownLatch dependencyLatch = new CountDownLatch(3);\n    private static CloudEndpointPublisher cloudEndpointPublisher;\n    private static DeploymentAdmin deploymentAdmin;\n    private static CloudEndpoint cloudEndpoint;\n    private static DataService dataService;\n\n    private static final String REMOTE_BUNDLE_NAME = \"org.eclipse.kura.demo.heater\";\n    private static final String LOCAL_DP_NAME = \"org.eclipse.kura.test.helloworld\";\n    private static final String LOCAL_BUNDLE_NAME = \"org.eclipse.kura.test.helloworld\";\n\n    private URL getTestDpUrl() {\n        BundleContext ctx = FrameworkUtil.getBundle(this.getClass()).getBundleContext();\n\n        URL packageUrl = ctx.getBundle().getResource(\"src/main/resources/\" + LOCAL_DP_NAME + \".dp\");\n        if (packageUrl == null) {\n            // handle case where running from a jar on a real target\n            packageUrl = ctx.getBundle().getResource(LOCAL_DP_NAME + \".dp\");\n        }\n\n        return packageUrl;\n    }\n\n    @Override\n    public void setUp() throws DeploymentException {\n        // Wait for OSGi dependencies\n        try {\n            boolean ok = dependencyLatch.await(10, TimeUnit.SECONDS);\n            if (!ok) {\n                fail(\"Dependencies not resolved!\");\n            }\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            fail(\"OSGi dependencies unfulfilled\");\n        }\n\n        DeploymentPackage localDp = deploymentAdmin.getDeploymentPackage(LOCAL_BUNDLE_NAME);\n        if (localDp != null) {\n            localDp.uninstall();\n        }\n\n        DeploymentPackage remoteDp = deploymentAdmin.getDeploymentPackage(REMOTE_BUNDLE_NAME);\n        if (remoteDp != null) {\n            remoteDp.uninstall();\n        }\n\n        cloudEndpointPublisher = new CloudEndpointPublisher(cloudEndpoint, dataService);\n    }\n\n    public void setDeploymentAdmin(DeploymentAdmin deploymentAdmin) {\n        InventoryHandlerTest.deploymentAdmin = deploymentAdmin;\n        dependencyLatch.countDown();\n    }\n\n    public void unsetDeploymentAdmin(DeploymentAdmin deploymentAdmin) {\n        InventoryHandlerTest.deploymentAdmin = null;\n    }\n\n    public void setCloudEndpoint(CloudEndpoint cloudEndpoint) {\n        this.cloudEndpoint = cloudEndpoint;\n        dependencyLatch.countDown();\n    }\n\n    public void setDataService(DataService dataService) {\n        this.dataService = dataService;\n        dependencyLatch.countDown();\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetPackages() throws Exception {\n        StringBuilder sb = init();\n        sb.append(InventoryHandlerV1.RESOURCE_DEPLOYMENT_PACKAGES);\n\n        KuraResponsePayload resp = cloudEndpointPublisher.call(InventoryHandlerV1.APP_ID, sb.toString(), null, 5000);\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resp.getResponseCode());\n\n        String body = new String(resp.getBody());\n        assertTrue(body.contains(\n                \"{\\\"deploymentPackages\\\":[{\\\"name\\\":\\\"org.eclipse.kura.test.helloworld\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"bundles\\\":[{\\\"name\\\":\\\"org.eclipse.kura.test.helloworld\\\",\\\"version\\\":\\\"1.0.0.201407161421\\\"\"));\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetBundles() throws Exception {\n        StringBuilder sb = init();\n        sb.append(InventoryHandlerV1.RESOURCE_BUNDLES);\n\n        KuraResponsePayload resp = cloudEndpointPublisher.call(InventoryHandlerV1.APP_ID, sb.toString(), null, 5000);\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resp.getResponseCode());\n\n        String body = new String(resp.getBody());\n        assertTrue(body.contains(\"{\\\"name\\\":\\\"org.eclipse.kura.test.helloworld\\\",\\\"version\\\":\\\"1.0.0.201407161421\\\"\"));\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetInventory() throws Exception {\n        StringBuilder sb = init();\n        sb.append(InventoryHandlerV1.INVENTORY);\n\n        KuraResponsePayload resp = cloudEndpointPublisher.call(InventoryHandlerV1.APP_ID, sb.toString(), null, 5000);\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resp.getResponseCode());\n\n        String body = new String(resp.getBody());\n        assertTrue(body.startsWith(\"{\\\"inventory\\\":\"));\n        assertTrue(body.contains(\n                \"{\\\"name\\\":\\\"org.eclipse.kura.test.helloworld\\\",\\\"version\\\":\\\"1.0.0.201407161421\\\",\\\"type\\\":\\\"BUNDLE\\\"},{\\\"name\\\":\\\"org.eclipse.kura.test.helloworld\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"type\\\":\\\"DP\\\"}\"));\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetSystemPackages() throws Exception {\n        StringBuilder sb = init();\n        sb.append(InventoryHandlerV1.RESOURCE_SYSTEM_PACKAGES);\n\n        KuraResponsePayload resp = cloudEndpointPublisher.call(InventoryHandlerV1.APP_ID, sb.toString(), null, 5000);\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resp.getResponseCode());\n\n        String body = new String(resp.getBody());\n        assertTrue(body.startsWith(\"{\\\"systemPackages\\\":[\"));\n    }\n\n    private StringBuilder init() throws IOException, DeploymentException {\n        assertTrue(dataService.isConnected());\n\n        DeploymentPackage dp = deploymentAdmin.getDeploymentPackage(LOCAL_DP_NAME);\n        if (dp == null) {\n            InputStream is = getTestDpUrl().openStream();\n            dp = deploymentAdmin.installDeploymentPackage(is);\n        }\n\n        return new StringBuilder(CloudletTopic.Method.GET.toString()).append(\"/\");\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/NetUtilTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport org.eclipse.kura.core.util.NetUtil;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.Test;\n\nimport junit.framework.TestCase;\n\npublic class NetUtilTest extends TestCase {\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetPrimaryMacAddress() {\n        assertNotNull(NetUtil.getPrimaryMacAddress());\n        assertFalse(\"UNKNOWN\".equals(NetUtil.getPrimaryMacAddress()));\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/NetworkServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.net.NetInterface;\nimport org.eclipse.kura.net.NetInterfaceAddress;\nimport org.eclipse.kura.net.NetworkService;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\nimport junit.framework.TestCase;\n\npublic class NetworkServiceTest extends TestCase {\n\n    private static CountDownLatch dependencyLatch = new CountDownLatch(1);\t// initialize with number of dependencies\n    private static final String MAC_DELIM = \":\";\n\n    private static NetworkService networkService;\n\n    @Override\n    @BeforeClass\n    public void setUp() {\n        // Wait for OSGi dependencies\n        try {\n            dependencyLatch.await(5, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            fail(\"OSGi dependencies unfulfilled\");\n        }\n    }\n\n    public void setNetworkService(NetworkService networkService) {\n        NetworkServiceTest.networkService = networkService;\n        dependencyLatch.countDown();\n    }\n\n    @Test\n    public void testDummy() {\n        assertTrue(true);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testServiceExists() {\n        assertNotNull(NetworkServiceTest.networkService);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testInterfaceNamesList() throws Exception {\n        List<String> interfaces = networkService.getAllNetworkInterfaceNames();\n        System.out.println(\"network interface names: \" + interfaces);\n        assertNotNull(interfaces);\n        assertTrue(interfaces.size() > 0);\n        for (String interfaceName : interfaces) {\n            assertFalse(interfaceName.isEmpty());\n        }\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testAllInterfaces() throws Exception {\n        List<NetInterface<? extends NetInterfaceAddress>> interfaces = networkService.getNetworkInterfaces();\n        assertNotNull(interfaces);\n        System.out.println(\"number of interfaces: \" + interfaces.size());\n        assertTrue(interfaces.size() > 0);\n\n        for (NetInterface<? extends NetInterfaceAddress> ni : interfaces) {\n            System.out.println(\"network interface name: \" + ni.getName());\n            System.out.println(\"network interface type: \" + ni.getType());\n            System.out.println(\"network interface mac: \" + getMacFromHwAddress(ni.getHardwareAddress()));\n            System.out.println(\"network interface state: \" + ni.getState());\n\n            assertNotNull(ni.getName());\n            assertFalse(ni.getName().isEmpty());\n            assertNotNull(ni.getType());\n            assertNotNull(ni.getState());\n            assertNotNull(ni.getNetInterfaceAddresses());\n\n            for (NetInterfaceAddress ia : ni.getNetInterfaceAddresses()) {\n                if (ia.getAddress() != null) {\n                    System.out.println(\"   network interface address: \" + ia.getAddress().getHostAddress());\n                }\n            }\n        }\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testActiveInterfaces() throws Exception {\n        List<NetInterface<? extends NetInterfaceAddress>> interfaces = networkService.getActiveNetworkInterfaces();\n        assertNotNull(interfaces);\n        System.out.println(\"number of active interfaces: \" + interfaces.size());\n        assertTrue(interfaces.size() > 0);\n\n        for (NetInterface<? extends NetInterfaceAddress> ni : interfaces) {\n            System.out.println(\"network interface name: \" + ni.getName());\n            System.out.println(\"network interface type: \" + ni.getType());\n            System.out.println(\"network interface mac: \" + getMacFromHwAddress(ni.getHardwareAddress()));\n            System.out.println(\"network interface state: \" + ni.getState());\n\n            assertNotNull(ni.getName());\n            assertFalse(ni.getName().isEmpty());\n            assertNotNull(ni.getType());\n            assertNotNull(ni.getState());\n            assertNotNull(ni.getNetInterfaceAddresses());\n\n            for (NetInterfaceAddress ia : ni.getNetInterfaceAddresses()) {\n                if (ia.getAddress() != null) {\n                    System.out.println(\"   network interface address: \" + ia.getAddress().getHostAddress());\n                }\n            }\n        }\n    }\n\n    private String getMacFromHwAddress(byte[] hwAddr) {\n        StringBuilder sb = new StringBuilder();\n        if (hwAddr != null) {\n            for (int i = 0; i < hwAddr.length; i++) {\n                if (i > 0) {\n                    sb.append(MAC_DELIM);\n                }\n                sb.append(String.format(\"%1X\", hwAddr[i]));\n            }\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/RequestIdGenerator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport java.util.Random;\n\npublic class RequestIdGenerator {\n\n    private static RequestIdGenerator instance = new RequestIdGenerator();\n\n    private final Random random;\n\n    private RequestIdGenerator() {\n        super();\n        this.random = new Random();\n    }\n\n    public static RequestIdGenerator getInstance() {\n        return instance;\n    }\n\n    public String next() {\n        long timestamp = System.currentTimeMillis();\n\n        long tempRandom;\n        synchronized (this.random) {\n            tempRandom = this.random.nextLong();\n        }\n\n        return timestamp + \"-\" + tempRandom;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/SystemAdminServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test;\n\nimport org.eclipse.kura.system.SystemAdminService;\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\n\nimport junit.framework.TestCase;\n\npublic class SystemAdminServiceTest extends TestCase {\n\n    private static SystemAdminService sysAdminService = null;\n\n    @Override\n    @BeforeClass\n    public void setUp() {\n    }\n\n    protected void setSystemAdminService(SystemAdminService sas) {\n        sysAdminService = sas;\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testServiceExists() {\n        assertNotNull(sysAdminService);\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testGetUptime() {\n        String actual = sysAdminService.getUptime();\n        assertTrue(Long.parseLong(actual) > 0);\n    }\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/hw/CommTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test.hw;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.osgi.service.io.ConnectionFactory;\n\nimport junit.framework.TestCase;\n\npublic class CommTest extends TestCase {\n\n    private static CountDownLatch dependencyLatch = new CountDownLatch(1);\t// initialize with number of dependencies\n    private static ConnectionFactory connectionFactory;\n    // private static String SERIAL_PORT_NAME =\"/dev/tty.PL2303-00001004\";\n    private static String SERIAL_PORT_NAME = \"/dev/ttyUSB0\";\n\n    @Override\n    @BeforeClass\n    public void setUp() {\n        // Wait for OSGi dependencies\n        try {\n            dependencyLatch.await(5, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            fail(\"OSGi dependencies unfulfilled\");\n        }\n    }\n\n    public void setConnectionFactory(ConnectionFactory connectionFactory) {\n        CommTest.connectionFactory = connectionFactory;\n        dependencyLatch.countDown();\n    }\n\n    @TestTarget(targetPlatforms = { TestTarget.PLATFORM_ALL })\n    @Test\n    public void testServiceExists() {\n        assertNotNull(CommTest.connectionFactory);\n    }\n\n    // Dont run these hardware tests in CloudBees!!!\n    /*\n     * @Test\n     * public void testCommConnection()\n     * throws Exception\n     * {\n     * String uri = new CommURI.Builder(SERIAL_PORT_NAME)\n     * .withBaudRate(19200)\n     * .withDataBits(8)\n     * .withStopBits(1)\n     * .withParity(0)\n     * .withTimeout(2000)\n     * .build().toString();\n     *\n     * CommConnection conn = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);\n     * assertNotNull(conn);\n     *\n     * OutputStream os = conn.openOutputStream();\n     * os.write(10);\n     * os.write(\"hello\".getBytes(), 0, \"hello\".getBytes().length);\n     * os.flush();\n     *\n     * os.close();\n     * os = null;\n     * conn.close();\n     * conn = null;\n     * }\n     *\n     * @Test\n     * public void testOpenSerialPort() {\n     * try {\n     * String uri = new CommURI.Builder(SERIAL_PORT_NAME)\n     * .withBaudRate(19200)\n     * .withDataBits(8)\n     * .withStopBits(1)\n     * .withParity(0)\n     * .withTimeout(2000)\n     * .build().toString();\n     * CommConnection conn = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);\n     * assertNotNull(conn);\n     *\n     * InputStream is = conn.openInputStream();\n     * OutputStream os = conn.openOutputStream();\n     *\n     * assertNotNull(is);\n     * assertNotNull(os);\n     *\n     * is.close();\n     * os.close();\n     * is = null;\n     * os = null;\n     * conn.close();\n     * conn = null;\n     * } catch (Exception e) {\n     * e.printStackTrace();\n     * }\n     * }\n     *\n     * @Test\n     * public void testWriteToPort() {\n     * try {\n     * String uri = new CommURI.Builder(SERIAL_PORT_NAME)\n     * .withBaudRate(19200)\n     * .withDataBits(8)\n     * .withStopBits(1)\n     * .withParity(0)\n     * .withTimeout(2000)\n     * .build().toString();\n     * CommConnection conn = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);\n     * assertNotNull(conn);\n     *\n     * OutputStream os = conn.openOutputStream();\n     *\n     * assertNotNull(os);\n     *\n     * os.write(\"this is a set of test data coming from a junit test in Kura\\r\\n\".getBytes());\n     * os.flush();\n     *\n     * os.close();\n     * os = null;\n     * conn.close();\n     * conn = null;\n     * } catch (Exception e) {\n     * e.printStackTrace();\n     * }\n     * }\n     */\n\n    // CAN'T READ IN AUTOMATED TEST\n    /*\n     * @Test\n     * public void testReadFromPort() {\n     * try {\n     * String uri = new CommURI.Builder(SERIAL_PORT_NAME)\n     * .withBaudRate(19200)\n     * .withDataBits(8)\n     * .withStopBits(1)\n     * .withParity(0)\n     * .withTimeout(2000)\n     * .build().toString();\n     * CommConnection conn = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);\n     * assertNotNull(conn);\n     *\n     * InputStream is = conn.openInputStream();\n     *\n     * assertNotNull(is);\n     *\n     * System.out.println(\"waiting for serial port input - make sure to end this with a <ENTER>...\");\n     * StringBuffer sb = new StringBuffer();\n     * int c;\n     * while((c = is.read()) != 0xd) {\n     * System.out.println(\"read byte: 0x\" + Integer.toHexString(c) + \" -> \" + (char)c);\n     * sb.append((char)c);\n     * }\n     *\n     * System.out.println(\"Read from serial port: \" + sb.toString());\n     *\n     * is.close();\n     * is = null;\n     * conn.close();\n     * conn = null;\n     * } catch (Exception e) {\n     * e.printStackTrace();\n     * }\n     * }\n     */\n\n    /*\n     * @Test\n     * public void testTwoPorts() {\n     * try {\n     * String uri = new CommURI.Builder(SERIAL_PORT_NAME)\n     * .withBaudRate(19200)\n     * .withDataBits(8)\n     * .withStopBits(1)\n     * .withParity(0)\n     * .withTimeout(2000)\n     * .build().toString();\n     * CommConnection connOne = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);\n     * assertNotNull(connOne);\n     * uri = new CommURI.Builder(SERIAL_PORT_NAME)\n     * .withBaudRate(19200)\n     * .withDataBits(8)\n     * .withStopBits(1)\n     * .withParity(0)\n     * .withTimeout(2000)\n     * .build().toString();\n     * CommConnection connTwo = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);\n     * assertNotNull(connTwo);\n     *\n     * InputStream isOne = connOne.openInputStream();\n     * OutputStream osOne = connOne.openOutputStream();\n     * InputStream isTwo = connTwo.openInputStream();\n     * OutputStream osTwo = connTwo.openOutputStream();\n     *\n     * assertNotNull(isOne);\n     * assertNotNull(osOne);\n     * assertNotNull(isTwo);\n     * assertNotNull(osTwo);\n     *\n     * //write from one to two\n     * byte[] array = \"this is a message from one to two\\n\".getBytes();\n     * osOne.write(array);\n     * StringBuffer sb = new StringBuffer();\n     * int c;\n     * while((c = isTwo.read()) != 0xa) {\n     * System.out.println(\"port 2: read byte: 0x\" + Integer.toHexString(c) + \" -> \" + (char)c);\n     * sb.append((char)c);\n     * }\n     * System.out.println(\"Port 2: Read from serial port two: \" + sb.toString());\n     *\n     * array = \"this is a message from two to one\\n\".getBytes();\n     * osTwo.write(array);\n     * sb = new StringBuffer();\n     * while((c = isOne.read()) != 0xa) {\n     * System.out.println(\"port 1: read byte: 0x\" + Integer.toHexString(c) + \" -> \" + (char)c);\n     * sb.append((char)c);\n     * }\n     * System.out.println(\"Port 1: Read from serial port: \" + sb.toString());\n     *\n     * isOne.close();\n     * osOne.close();\n     * isOne = null;\n     * osOne = null;\n     * isTwo.close();\n     * osTwo.close();\n     * isTwo = null;\n     * osTwo = null;\n     * connOne.close();\n     * connOne = null;\n     * connTwo.close();\n     * connTwo = null;\n     * } catch (Exception e) {\n     * e.printStackTrace();\n     * }\n     * }\n     */\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/hw/RxTxTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test.hw;\n\npublic class RxTxTest {\n\n    /**\n     * For this to work on a MAC you must have enabled serial support:\n     * Install this driver if using a PL2303 USB to Serial device: http://sourceforge.net/projects/osx-pl2303/\n     * Run these commands to enable locking for RXTX:\n     * sudo mkdir /var/lock\n     * sudo chmod 777 /var/lock\n     * Find your device node with 'ls -l /dev/*PL*' and replace it as needed below in the com port identifier call\n     * This is commented out because it will not work on cloudbees (or anything without a physical comm port)\n     */\n    /*\n     * @Test\n     * public void serialTest() {\n     *\n     * try {\n     * Enumeration ports = CommPortIdentifier.getPortIdentifiers();\n     * while (ports.hasMoreElements()) {\n     * CommPortIdentifier port = (CommPortIdentifier)ports.nextElement();\n     * String type;\n     * switch (port.getPortType()) {\n     * case CommPortIdentifier.PORT_PARALLEL:\n     * type = \"Parallel\";\n     * break;\n     * case CommPortIdentifier.PORT_SERIAL:\n     * type = \"Serial\";\n     * break;\n     * default: /// Shouldn't happen\n     * type = \"Unknown\";\n     * break;\n     * }\n     * System.out.println(port.getName() + \": \" + type);\n     * }\n     * } catch(Exception e) {\n     * e.printStackTrace();\n     * }\n     *\n     * CommPortIdentifier portIdentifier = null;\n     * InputStream in = null;\n     * OutputStream out = null;\n     *\n     * try {\n     * portIdentifier = CommPortIdentifier.getPortIdentifier(\"/dev/ttyUSB0\");\n     * } catch (NoSuchPortException e) {\n     * e.printStackTrace();\n     * }\n     * if ( portIdentifier.isCurrentlyOwned() ) {\n     * System.out.println(\"Error: Port is currently in use\");\n     * }\n     * else {\n     * CommPort commPort = null;\n     * try {\n     * commPort = portIdentifier.open(this.getClass().getName(),2000);\n     * } catch (PortInUseException e) {\n     * e.printStackTrace();\n     * }\n     *\n     * if ( commPort instanceof SerialPort ) {\n     * SerialPort serialPort = (SerialPort) commPort;\n     * try {\n     * serialPort.setSerialPortParams(57600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);\n     * } catch (UnsupportedCommOperationException e) {\n     * e.printStackTrace();\n     * }\n     *\n     * try {\n     * in = serialPort.getInputStream();\n     * } catch (IOException e) {\n     * e.printStackTrace();\n     * }\n     * try {\n     * out = serialPort.getOutputStream();\n     * } catch (IOException e) {\n     * e.printStackTrace();\n     * }\n     *\n     * Assert.assertNotNull(in);\n     * Assert.assertNotNull(out);\n     *\n     * try {\n     * in.close();\n     * out.close();\n     * in = null;\n     * out = null;\n     * serialPort.close();\n     * serialPort = null;\n     * } catch (IOException e) {\n     * e.printStackTrace();\n     * }\n     * }\n     * else {\n     * System.out.println(\"Error: Only serial ports are handled by this example.\");\n     * }\n     * }\n     * }\n     */\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/java/org/eclipse/kura/core/test/util/CoreTestXmlUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.test.util;\n\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.stream.FactoryConfigurationError;\nimport javax.xml.stream.XMLStreamException;\n\nimport org.eclipse.kura.core.configuration.XmlSnapshotIdResult;\nimport org.eclipse.kura.core.inventory.resources.SystemBundle;\nimport org.eclipse.kura.core.inventory.resources.SystemBundles;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\npublic class CoreTestXmlUtil {\n\n    /*\n     * The following methods are for Java XML objects that don't need an\n     * unmarshal method during normal operation. The below methods are only\n     * needed for testing purposes.\n     *\n     */\n    public static <T> T unmarshal(String s, Class<T> clazz) throws XMLStreamException, FactoryConfigurationError {\n        StringReader sr = new StringReader(s);\n        System.out.println(\"CoreTestXmlUtil: 30\");\n        return unmarshal(sr, clazz);\n    }\n\n    public static <T> T unmarshal(Reader r, Class<T> clazz) throws XMLStreamException, FactoryConfigurationError {\n        DocumentBuilderFactory factory = null;\n        DocumentBuilder parser = null;\n\n        try {\n            factory = DocumentBuilderFactory.newInstance();\n            parser = factory.newDocumentBuilder();\n        } catch (FactoryConfigurationError fce) {\n            // The implementation is not available or cannot be instantiated\n            System.out.println(\"Parser Factory configuration Error\");\n            throw fce;\n        } catch (ParserConfigurationException pce) {\n            // the parser cannot be created with the specified configuration\n            System.out.println(\"Parser configuration exception\");\n            throw new FactoryConfigurationError(pce);\n        }\n\n        // parse the document\n        Document doc = null;\n        try {\n            InputSource is = new InputSource(r);\n            doc = parser.parse(is);\n            doc.getDocumentElement().normalize();\n\n            // Select the correct unmarshal method\n            if (clazz.equals(SystemDeploymentPackages.class)) {\n                return unmarshalSystemDeploymentPackages(doc);\n            } else if (clazz.equals(SystemBundles.class)) {\n                return unmarshalXmlBundles(doc);\n            } else if (clazz.equals(XmlSnapshotIdResult.class)) {\n                return unmarshalXmlSnapshotIdResult(doc);\n            }\n        } catch (SAXException se) {\n            throw new XMLStreamException(se.getMessage());\n        } catch (IOException ioe) {\n            throw new XMLStreamException(ioe.getMessage());\n        } catch (IllegalArgumentException iae) {\n            throw new XMLStreamException(iae.getMessage());\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    // unmarshal SystemDeploymentPackages\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T unmarshalSystemDeploymentPackages(Document doc) throws Exception {\n        // Java objects for unmarshal\n        SystemDeploymentPackages systemDeploymentPackages = new SystemDeploymentPackages();\n        List<SystemDeploymentPackage> systemDeploymentPackageList = new ArrayList<>();\n\n        // XML elements\n        Element packages = doc.getDocumentElement();\n        NodeList packagesChildren = packages.getChildNodes();\n\n        // Collect all packages\n        for (int propIndex = 0; propIndex < packagesChildren.getLength(); propIndex++) {\n            Node currentNode = packagesChildren.item(propIndex);\n            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {\n                Element el = (Element) currentNode;\n                if (el.getNodeName().equals(\"package\")) {\n                    String name = \"\";\n                    String version = \"\";\n                    SystemBundle[] bundleInfos = new SystemBundle[0];\n\n                    NodeList nodeList = el.getChildNodes();\n                    for (int i = 0; i < nodeList.getLength(); i++) {\n                        Node tmpNode = nodeList.item(i);\n\n                        // Set package name\n                        if (tmpNode.getNodeName().equals(\"name\")) {\n                            name = tmpNode.getTextContent();\n                        } else if (tmpNode.getNodeName().equals(\"version\")) {\n                            version = tmpNode.getTextContent();\n                        } else if (tmpNode.getNodeName().equals(\"bundles\")) {\n                            bundleInfos = parseBundles(tmpNode);\n                        }\n                    }\n                    SystemDeploymentPackage xdp = new SystemDeploymentPackage(name, version);\n                    xdp.setBundleInfos(bundleInfos);\n\n                    systemDeploymentPackageList.add(xdp);\n                }\n            }\n        }\n\n        // Add packages\n        systemDeploymentPackages.setDeploymentPackages(\n                systemDeploymentPackageList.toArray(new SystemDeploymentPackage[systemDeploymentPackageList.size()]));\n\n        return (T) systemDeploymentPackages;\n    }\n\n    // unmarshal SystemBundles\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T unmarshalXmlBundles(Document doc) throws Exception {\n        SystemBundles systemBundles = new SystemBundles();\n        List<SystemBundle> systemBundleList = new ArrayList<>();\n\n        // XML elements\n        Element bundles = doc.getDocumentElement();\n        NodeList bundlesChildren = bundles.getChildNodes();\n\n        // Collect all bundles\n        for (int propIndex = 0; propIndex < bundlesChildren.getLength(); propIndex++) {\n            Node currentNode = bundlesChildren.item(propIndex);\n            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {\n                String name = \"\";\n                String version = \"\";\n                long id = -1;\n                String state = \"\";\n\n                Element el = (Element) currentNode;\n                if (el.getNodeName().equals(\"bundle\")) {\n                    NodeList nodeList = el.getChildNodes();\n                    for (int i = 0; i < nodeList.getLength(); i++) {\n                        Node tmpNode = nodeList.item(i);\n\n                        // Set bundle name\n                        if (tmpNode.getNodeName().equals(\"name\")) {\n                            name = tmpNode.getTextContent();\n                        }\n\n                        // Set bundle version\n                        if (tmpNode.getNodeName().equals(\"version\")) {\n                            version = tmpNode.getTextContent();\n                        }\n\n                        // Set bundle ID\n                        if (tmpNode.getNodeName().equals(\"id\")) {\n                            id = Long.parseLong(tmpNode.getTextContent());\n                        }\n\n                        // Set bundle state\n                        if (tmpNode.getNodeName().equals(\"state\")) {\n                            state = tmpNode.getTextContent();\n                        }\n                    }\n                    SystemBundle xb = new SystemBundle(name, version);\n                    xb.setId(id);\n                    xb.setState(state);\n\n                    // Add bundle to list\n                    systemBundleList.add(xb);\n                }\n            }\n        }\n\n        // Add bundles\n        systemBundles.setBundles(systemBundleList.toArray(new SystemBundle[systemBundleList.size()]));\n\n        return (T) systemBundles;\n    }\n\n    // unmarshal XmlSnapshotIdResult\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T unmarshalXmlSnapshotIdResult(Document doc) throws Exception {\n        XmlSnapshotIdResult xmlSnapshotIdResult = new XmlSnapshotIdResult();\n        List<Long> idList = new ArrayList<>();\n\n        // XML elements\n        Element snapshotIds = doc.getDocumentElement();\n        NodeList snapshotIdsChildren = snapshotIds.getChildNodes();\n\n        // Collect all bundles\n        for (int propIndex = 0; propIndex < snapshotIdsChildren.getLength(); propIndex++) {\n            Node currentNode = snapshotIdsChildren.item(propIndex);\n            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {\n                Element el = (Element) currentNode;\n                if (el.getNodeName().equals(\"esf:snapshotIds\")) {\n                    // Add ID to list\n                    idList.add(Long.parseLong(el.getTextContent()));\n                }\n            }\n        }\n\n        // Add IDs\n        xmlSnapshotIdResult.setSnapshotIds(idList);\n\n        return (T) xmlSnapshotIdResult;\n    }\n\n    private static SystemBundle[] parseBundles(Node node) {\n        List<SystemBundle> bundleInfos = new ArrayList<>();\n        NodeList nodeList = node.getChildNodes();\n\n        // Get information for each bundle\n        for (int i = 0; i < nodeList.getLength(); i++) {\n            Node bundleNode = nodeList.item(i);\n            if (bundleNode.getNodeType() == Node.ELEMENT_NODE) {\n                String name = \"\";\n                String version = \"\";\n\n                NodeList infoList = bundleNode.getChildNodes();\n                for (int j = 0; j < infoList.getLength(); j++) {\n                    Node tmpNode = infoList.item(j);\n\n                    // Set Bundle Name\n                    if (tmpNode.getNodeName().equals(\"name\")) {\n                        name = tmpNode.getTextContent();\n                    } else if (tmpNode.getNodeName().equals(\"version\")) {\n                        version = tmpNode.getTextContent();\n                    }\n                }\n\n                SystemBundle xbi = new SystemBundle(name, version);\n                // Add bundle to array\n                bundleInfos.add(xbi);\n            }\n        }\n\n        return bundleInfos.toArray(new SystemBundle[bundleInfos.size()]);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/resources/artemis_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\t\n\tCopyright (c) 2017, 2020 Red Hat Inc and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Red Hat Inc\n\t \n -->\n\n<configuration\n\txmlns=\"urn:activemq\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\t>\n\n\t<core xmlns=\"urn:activemq:core\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\n\t\t<name></name>\n\n\t\t<persistence-enabled>false</persistence-enabled>\n\n\t\t<acceptors>\n   <acceptor name=\"mqtt\">tcp://0.0.0.0:1889?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT</acceptor>\n<acceptor name=\"mqtts\">tcp://0.0.0.0:8888?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;sslEnabled=true;keyStorePath=$keyStorePath;keyStorePassword=changeit;needClientAuth=false</acceptor>\n<acceptor name=\"mqttsClientAuth\">tcp://0.0.0.0:8889?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;sslEnabled=true;keyStorePath=$keyStorePath;keyStorePassword=changeit;trustStorePath=$trustStorePath;trustStorePassword=changeit;needClientAuth=true</acceptor>\n</acceptors>\n\n\t\t<security-settings>\n\t\t\t<security-setting match=\"#\">\n\t\t\t\t<permission type=\"createNonDurableQueue\" roles=\"amq\" />\n\t\t\t\t<permission type=\"deleteNonDurableQueue\" roles=\"amq\" />\n\t\t\t\t<permission type=\"createDurableQueue\" roles=\"amq\" />\n\t\t\t\t<permission type=\"deleteDurableQueue\" roles=\"amq\" />\n\t\t\t\t<permission type=\"createAddress\" roles=\"amq\" />\n\t\t\t\t<permission type=\"deleteAddress\" roles=\"amq\" />\n\t\t\t\t<permission type=\"consume\" roles=\"amq\" />\n\t\t\t\t<permission type=\"browse\" roles=\"amq\" />\n\t\t\t\t<permission type=\"send\" roles=\"amq\" />\n\t\t\t</security-setting>\n\t\t</security-settings>\n\n\t\t<address-settings>\n\t\t\t<address-setting match=\"activemq.management#\">\n\t\t\t\t<dead-letter-address>DLQ</dead-letter-address>\n\t\t\t\t<expiry-address>ExpiryQueue</expiry-address>\n\t\t\t\t<redelivery-delay>0</redelivery-delay>\n\t\t\t\t<max-size-bytes>-1</max-size-bytes>\n\t\t\t\t<message-counter-history-day-limit>10</message-counter-history-day-limit>\n\t\t\t\t<address-full-policy>DROP</address-full-policy>\n\t\t\t\t<auto-create-queues>true</auto-create-queues>\n\t\t\t\t<auto-create-addresses>true</auto-create-addresses>\n\t\t\t\t<auto-create-jms-queues>true</auto-create-jms-queues>\n\t\t\t\t<auto-create-jms-topics>true</auto-create-jms-topics>\n\t\t\t</address-setting>\n\t\t\t<address-setting match=\"#\">\n\t\t\t\t<dead-letter-address>DLQ</dead-letter-address>\n\t\t\t\t<expiry-address>ExpiryQueue</expiry-address>\n\t\t\t\t<redelivery-delay>0</redelivery-delay>\n\t\t\t\t<max-size-bytes>-1</max-size-bytes>\n\t\t\t\t<message-counter-history-day-limit>10</message-counter-history-day-limit>\n\t\t\t\t<address-full-policy>DROP</address-full-policy>\n\t\t\t\t<auto-create-queues>true</auto-create-queues>\n\t\t\t\t<auto-create-addresses>true</auto-create-addresses>\n\t\t\t\t<auto-create-jms-queues>true</auto-create-jms-queues>\n\t\t\t\t<auto-create-jms-topics>true</auto-create-jms-topics>\n\t\t\t</address-setting>\n\t\t</address-settings>\n\n\t\t<addresses>\n\t\t\t<address name=\"DLQ\">\n\t\t\t\t<anycast>\n\t\t\t\t\t<queue name=\"DLQ\" />\n\t\t\t\t</anycast>\n\t\t\t</address>\n\t\t\t<address name=\"ExpiryQueue\">\n\t\t\t\t<anycast>\n\t\t\t\t\t<queue name=\"ExpiryQueue\" />\n\t\t\t\t</anycast>\n\t\t\t</address>\n\t\t</addresses>\n\n\t</core>\n</configuration>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/resources/kura.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\n## -----------------------------------------------------------------------------\n##  Kura Properties\n## -----------------------------------------------------------------------------\nkura.name=Kura\nkura.version=kura_emulator\nkura.company=Eclipse\nkura.project=Dev\nkura.platform=dynacor\nkura.device.name=DevEmulator\nkura.model.id=DevModelId\nkura.model.name=DevModelName\nkura.partNumber=DevPartNumber\nkura.serialNumber=DevSerialNumber\nkura.bios.version=DevBiosVersion\nkura.firmware.version=DevFirmwareVersion\n# kura.mac.address= Fetch from Java\nkura.home=/tmp/kura\nkura.framework.config=/tmp/kura/framework\nkura.user.config=/tmp/kura/user\nkura.plugins=/tmp/kura/plugins\nkura.packages=/tmp/kura/data/packages\nkura.data=/tmp/kura/data\nkura.tmp=/tmp/kura/tmp\nkura.snapshots=/tmp/kura/user/snapshots\nkura.snapshots.count=10\nkura.have.net.admin=false\n# os.arch= Fetch from Java\n# os.name= Fetch from Java\n# os.version= Fetch from Java\nos.distribution=DevOsDitribution\nos.distribution.version=DevOsDitributionVersion\n# java.version= Fetch from Java\n# java.vendor= Fetch from Java\n# java.vm.name= Fetch from Java\n# java.vm.version= Fetch from Java\n# java.home= Fetch from Java\n# file.separator= Fetch from Java\n\n\n## -----------------------------------------------------------------------------\n## Java Key Store Settings\n## -----------------------------------------------------------------------------\nkura.ssl.keyStorePassword=everyware\nkura.ssl.trustStorePassword=everyware\n\n\n## -----------------------------------------------------------------------------\n## File upload settings\n## -----------------------------------------------------------------------------\n# default 10240\nfile.upload.in.memory.size.threshold=10240\n# -1: unlimited (default)\nfile.upload.size.max=-1\n\n\n## -----------------------------------------------------------------------------\n## Deployment Agent settings\n## -----------------------------------------------------------------------------\n# see copyURLToFile() http://commons.apache.org/proper/commons-io/javadocs/api-2.4/index.html\ndpa.connection.timeout = 60000\ndpa.read.timeout = 60000\n\n\n## -----------------------------------------------------------------------------\n## Cloud Connection Status settings\n## -----------------------------------------------------------------------------\n\n#1. Cloud Connection Status on system log\n#The Cloud Connection Status will be indicated in the log files, and nowere else\n#ccs.status.notification.url=ccs:log\n\n#2. Cloud Connection Status on LED\n#The Cloud Connection Status will be indicated by a blinking LED connected to the system GPIOs\n#The URL should identify the GPIO to be used, either by name or by terminal index as defined by Kura GpioService.\n# Syntax for using GPIO terminal index:\n#ccs.status.notification.url=ccs:led:16\n#ccs.status.notification.url=ccs:led:terminal:16\n# Syntax for using GPIO name:\n#ccs.status.notification.url=ccs:led:name:LED_1\nccs.status.notification.url=ccs:led:16\n\n#3. Cloud Connection Status disabled\n#Disables the Cloud Connection Status service\n#ccs.status.notification.urs=ccs:none\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/resources/log4j.properties",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\n### direct log messages to stdout ###\nlog4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L %X{username} - %m%n\n\n### set log levels - for more verbose logging change 'info' to 'debug' ###\nlog4j.rootLogger=INFO,stdout\n\n## eclipse\nlog4j.logger.org.eclipse=INFO\nlog4j.logger.org.eclipse.kura.core.data.DataServiceImpl=WARN\nlog4j.logger.org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport=WARN\n\n## Moquette\nlog4j.logger.io.moquette=INFO\nlog4j.logger.io.moquette.spi.impl.ProtocolProcessor=INFO\nlog4j.logger.io.moquette.spi.impl.SimpleMessaging=WARN\n\n#Protocol parsing\nlog4j.logger.io.moquette.server.netty.NettyMQTTHandler=WARN\n#log4j.logger.io.moquette.server.netty.NettyMQTTHandler=DEBUG\nlog4j.logger.io.moquette.parser.netty=WARN\n#Storage server\n#log4j.logger.io.moquette.spi.impl.subscriptions.SubscriptionsStore=DEBUG\n#log4j.logger.io.moquette.spi.impl.HawtDBStorageService=DEBUG\n\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/resources/moquette/config/moquette.conf",
    "content": "#\n# Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nport 1883\n\nwebsocket_port 8080\n\nhost 0.0.0.0\n\npassword_file config/password_file.conf\n\nallow_anonymous true\npersistence_enabled false\n\nnetty.mqtt.message_size 16777216"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/main/resources/moquette/config/password_file.conf",
    "content": "#\n#  Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\n#*********************************************\n# Each line define a user login in the format\n#   <username>:sha256(<password>)\n#*********************************************\n#NB this password is sha256(passwd)\ntestuser:36767030e79073783c8e9b299d9f8f1d4cd66baa82cd8869caad8dbb55204099\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/test/java/org/eclipse/kura/core/internal/linux/executor/CommandLineMatcher.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.internal.linux.executor;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.apache.commons.exec.CommandLine;\nimport org.mockito.ArgumentMatcher;\n\npublic class CommandLineMatcher implements ArgumentMatcher<CommandLine> {\n\n    String executable;\n    List<String> arguments;\n\n    CommandLineMatcher(String executable, String[] arguments) {\n        this.executable = executable;\n        this.arguments = new ArrayList<>();\n        Arrays.asList(arguments).forEach(this.arguments::add);\n    }\n\n    @Override\n    public String toString() {\n        return executable + \" \" + String.join(\" \", arguments);\n    }\n\n    @Override\n    public boolean matches(CommandLine argument) {\n        boolean matched = false;\n        if (argument instanceof CommandLine) {\n            CommandLine cl = (CommandLine) argument;\n            if (this.executable.equals(cl.getExecutable()) && this.arguments.size() == cl.getArguments().length\n                    && this.arguments.containsAll(Arrays.asList(cl.getArguments()))) {\n                matched = true;\n            }\n        }\n        return matched;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/test/java/org/eclipse/kura/core/internal/linux/executor/ExecutorUtilExecutionTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.internal.linux.executor;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.mockito.ArgumentMatchers.anyMap;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.exec.CommandLine;\nimport org.apache.commons.exec.DefaultExecutor;\nimport org.apache.commons.exec.ExecuteWatchdog;\nimport org.apache.commons.exec.Executor;\nimport org.eclipse.kura.core.linux.executor.LinuxExitStatus;\nimport org.eclipse.kura.core.linux.executor.LinuxSignal;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.junit.Test;\nimport org.mockito.ArgumentMatcher;\n\npublic class ExecutorUtilExecutionTest {\n\n    private static final String COMMAND_STRING = \"ls -all\";\n    private static final Map<String, String> ENV = Collections.singletonMap(\"ENV1\", \"VALUE1\");\n\n    private ExecutorUtil executorUtil;\n    private Command command;\n    private CommandStatus status;\n    private Consumer<CommandStatus> callback = cs -> this.status = cs;\n\n    @Test\n    public void shouldReturnErrorOnUnprivilegedSyncExecution() {\n        givenExecutor();\n        givenCommand(COMMAND_STRING);\n\n        whenCommandIsUnprivilegedExecuted();\n\n        thenReturnExitValue(1);\n    }\n\n    @Test\n    public void shouldReturnSuccessOnPrivilegedSyncExecution() {\n        givenExecutor();\n        givenCommand(COMMAND_STRING);\n\n        whenCommandIsPrivilegedExecuted();\n\n        thenReturnExitValue(0);\n    }\n\n    @Test\n    public void shouldAcceptErrorOnUnprivilegedAsyncExecution() {\n        givenExecutor();\n        givenCommand(COMMAND_STRING);\n\n        whenCommandIsUnprivilegedAsyncExecuted(this.callback);\n\n        thenReturnExitValue(1);\n    }\n\n    @Test\n    public void shouldAcceptSuccessOnPrivilegedAsyncExecution() {\n        givenExecutor();\n        givenCommand(COMMAND_STRING);\n\n        whenCommandIsPrivilegedAsyncExecuted(this.callback);\n\n        thenReturnExitValue(0);\n    }\n\n    private void givenExecutor() {\n        DefaultExecutor deMock = mock(DefaultExecutor.class);\n        this.executorUtil = new ExecutorUtil() {\n\n            @Override\n            protected Executor getExecutor() {\n                return deMock;\n            }\n        };\n        configureMock(deMock);\n    }\n\n    private void givenCommand(String commandLine) {\n        this.command = new Command(commandLine.split(\" \"));\n        this.command.setOutputStream(new ByteArrayOutputStream());\n        this.command.setErrorStream(new ByteArrayOutputStream());\n        this.command.setEnvironment(ENV);\n        this.command.setTimeout(1000);\n        this.command.setSignal(LinuxSignal.SIGHUP);\n        this.command.setExecuteInAShell(true);\n        this.command.setDirectory(\"/var\");\n    }\n\n    private void whenCommandIsUnprivilegedExecuted() {\n        this.status = this.executorUtil.executeUnprivileged(this.command);\n    }\n\n    private void whenCommandIsUnprivilegedAsyncExecuted(Consumer<CommandStatus> callback) {\n        this.executorUtil.executeUnprivileged(this.command, callback);\n    }\n\n    private void whenCommandIsPrivilegedExecuted() {\n        this.status = this.executorUtil.executePrivileged(this.command);\n    }\n\n    private void whenCommandIsPrivilegedAsyncExecuted(Consumer<CommandStatus> callback) {\n        this.executorUtil.executePrivileged(this.command, callback);\n    }\n\n    private void thenReturnExitValue(int expectedExitValue) {\n        assertEquals(expectedExitValue, this.status.getExitStatus().getExitCode());\n    }\n\n    private void configureMock(DefaultExecutor deMock) {\n        CommandStatus csSuccess = new CommandStatus(this.command, new LinuxExitStatus(0));\n        CommandStatus csFailure = new CommandStatus(this.command, new LinuxExitStatus(1));\n        String executableUnprivileged = \"su\";\n        String[] argumentsUnprivileged = { \"kura\", \"-c\", \"ENV1=VALUE1 timeout -s SIGHUP 1000 \" + COMMAND_STRING };\n        String executablePrivileged = \"/bin/sh\";\n        String[] argumentsPrivileged = { \"-c\", COMMAND_STRING };\n        try {\n            when(deMock.execute(argThat(new CommandLineMatcher(executableUnprivileged, argumentsUnprivileged)),\n                    anyMap())).thenReturn(1);\n            when(deMock.execute(argThat(new CommandLineMatcher(executablePrivileged, argumentsPrivileged)), anyMap()))\n                    .thenReturn(0);\n            doAnswer(invocation -> {\n                this.callback.accept(csFailure);\n                return null;\n            }).when(deMock).execute(argThat(new CommandLineMatcher(executableUnprivileged, argumentsUnprivileged)),\n                    anyMap(), any());\n            doAnswer(invocation -> {\n                this.callback.accept(csSuccess);\n                return null;\n            }).when(deMock).execute(argThat(new CommandLineMatcher(executablePrivileged, argumentsPrivileged)),\n                    anyMap(), any());\n        } catch (IOException e) {\n            // Do nothing...\n        }\n        when(deMock.getWatchdog()).thenReturn(new ExecuteWatchdog(1));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/test/java/org/eclipse/kura/core/internal/linux/executor/ExecutorUtilRunningTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.internal.linux.executor;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.apache.commons.exec.DefaultExecutor;\nimport org.apache.commons.exec.Executor;\nimport org.eclipse.kura.core.linux.executor.LinuxPid;\nimport org.eclipse.kura.executor.Pid;\nimport org.junit.Test;\n\npublic class ExecutorUtilRunningTest {\n\n    private static String[] commandLine1 = { \"find\", \"/\", \"-name\", \"foo\" };\n    private static String[] commandLine2 = { \"find\", \"/\", \"-name\", \"bar\" };\n    private static ByteArrayOutputStream out = new ByteArrayOutputStream();\n    private ExecutorUtil executorUtil;\n    private boolean isRunning;\n    private Map<String, Pid> pids = new HashMap<>();\n\n    @Test\n    public void shouldNotBeRunningPid() {\n        givenExecutor();\n\n        whenCheckIfRunning(new LinuxPid(1234));\n\n        thenCommandIsNotRunning();\n    }\n\n    @Test\n    public void shouldBeRunningPid() {\n        givenExecutor();\n\n        whenCheckIfRunning(new LinuxPid(12345));\n\n        thenCommandIsRunning();\n    }\n\n    @Test\n    public void shouldNotBeRunningCommandLine() {\n        givenExecutor();\n\n        whenCheckIfRunning(commandLine1);\n\n        thenCommandIsNotRunning();\n    }\n\n    @Test\n    public void shouldBeRunningCommandLine() {\n        givenExecutor();\n\n        whenCheckIfRunning(commandLine2);\n\n        thenCommandIsRunning();\n    }\n\n    @Test\n    public void shouldNotRetrievePids() {\n        givenExecutor();\n\n        whenRetrievePid(commandLine1);\n\n        thenPidIsNotFound();\n    }\n\n    @Test\n    public void shouldRetrievePids() {\n        givenExecutor();\n\n        whenRetrievePid(commandLine2);\n\n        thenPidIsFound();\n    }\n\n    private void givenExecutor() {\n        DefaultExecutor deMock = mock(DefaultExecutor.class);\n        this.executorUtil = new ExecutorUtil() {\n\n            @Override\n            protected Executor getExecutor() {\n                return deMock;\n            }\n\n            @Override\n            protected ByteArrayOutputStream createStream() {\n                return ExecutorUtilRunningTest.out;\n            }\n        };\n        configureMock(deMock);\n    }\n\n    private void whenCheckIfRunning(Pid pid) {\n        this.isRunning = this.executorUtil.isRunning(pid);\n    }\n\n    private void whenCheckIfRunning(String[] commandLine) {\n        this.isRunning = this.executorUtil.isRunning(commandLine);\n    }\n\n    private void whenRetrievePid(String[] commandLine) {\n        this.pids = this.executorUtil.getPids(commandLine);\n    }\n\n    private void thenCommandIsRunning() {\n        assertTrue(this.isRunning);\n    }\n\n    private void thenCommandIsNotRunning() {\n        assertFalse(this.isRunning);\n    }\n\n    private void thenPidIsFound() {\n        assertFalse(this.pids.isEmpty());\n    }\n\n    private void thenPidIsNotFound() {\n        assertTrue(this.pids.isEmpty());\n    }\n\n    private void configureMock(DefaultExecutor deMock) {\n        String executablePs = \"ps\";\n        String[] argumentsPs1 = { \"-p\", \"1234\" };\n        String[] argumentsPs2 = { \"-p\", \"12345\" };\n        String[] argumentsPsAx = { \"-ax\" };\n        try {\n            when(deMock.execute(argThat(new CommandLineMatcher(executablePs, argumentsPs1)))).thenReturn(1);\n            doAnswer(invocation -> {\n                out.reset();\n                PrintWriter pw = new PrintWriter(out);\n                pw.println(12345);\n                pw.flush();\n                pw.close();\n                return 0;\n            }).when(deMock).execute(argThat(new CommandLineMatcher(executablePs, argumentsPs2)));\n            doAnswer(invocation -> {\n                out.reset();\n                PrintWriter pw = new PrintWriter(out);\n                pw.println(\" 4333 pts/0    R+     0:00 find / -name bar\");\n                pw.flush();\n                pw.close();\n                return 0;\n            }).when(deMock).execute(argThat(new CommandLineMatcher(executablePs, argumentsPsAx)));\n        } catch (IOException e) {\n            // Do nothing...\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/test/java/org/eclipse/kura/core/internal/linux/executor/ExecutorUtilTerminationTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.internal.linux.executor;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.argThat;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\nimport org.apache.commons.exec.DefaultExecutor;\nimport org.apache.commons.exec.ExecuteWatchdog;\nimport org.apache.commons.exec.Executor;\nimport org.eclipse.kura.core.linux.executor.LinuxPid;\nimport org.eclipse.kura.core.linux.executor.LinuxSignal;\nimport org.eclipse.kura.executor.Pid;\nimport org.junit.Test;\n\npublic class ExecutorUtilTerminationTest {\n\n    private static Pid pid = new LinuxPid(1234);\n    private static String[] commandLine = { \"find\", \"/\", \"-name\", \"foo\" };\n    private static ByteArrayOutputStream out = new ByteArrayOutputStream();\n    private ExecutorUtil executorUtil;\n    private boolean isStopped;\n    private boolean isKilled;\n\n    @Test\n    public void shouldNotStopUnprivilegedCommand() {\n        givenExecutor();\n\n        whenStopUnprivilegedCommand(pid, LinuxSignal.SIGTERM);\n\n        thenCommandIsNotStopped();\n    }\n\n    @Test\n    public void shouldStopPrivilegedCommand() {\n        givenExecutor();\n\n        whenStopPrivilegedCommand(pid, LinuxSignal.SIGKILL);\n\n        thenCommandIsStopped();\n    }\n\n    @Test\n    public void shouldNotKillUnprivilegedCommand() {\n        givenExecutor();\n\n        whenKillUnprivilegedCommand(commandLine, LinuxSignal.SIGTERM);\n\n        thenCommandIsNotKilled();\n    }\n\n    @Test\n    public void shouldKillPrivilegedCommand() {\n        givenExecutor();\n\n        whenKillPrivilegedCommand(commandLine, LinuxSignal.SIGKILL);\n\n        thenCommandIsKilled();\n    }\n\n    private void givenExecutor() {\n        DefaultExecutor deMock = mock(DefaultExecutor.class);\n        this.executorUtil = new ExecutorUtil() {\n\n            @Override\n            protected Executor getExecutor() {\n                return deMock;\n            }\n\n            @Override\n            protected ByteArrayOutputStream createStream() {\n                return ExecutorUtilTerminationTest.out;\n            }\n        };\n        configureMock(deMock);\n    }\n\n    private void whenStopUnprivilegedCommand(Pid pid, LinuxSignal signal) {\n        this.isStopped = this.executorUtil.stopUnprivileged(pid, signal);\n    }\n\n    private void whenStopPrivilegedCommand(Pid pid, LinuxSignal signal) {\n        this.isStopped = this.executorUtil.stopPrivileged(pid, signal);\n    }\n\n    private void whenKillUnprivilegedCommand(String[] commandLine, LinuxSignal signal) {\n        this.isKilled = this.executorUtil.killUnprivileged(commandLine, signal);\n    }\n\n    private void whenKillPrivilegedCommand(String[] commandLine, LinuxSignal signal) {\n        this.isKilled = this.executorUtil.killPrivileged(commandLine, signal);\n    }\n\n    private void thenCommandIsStopped() {\n        assertTrue(this.isStopped);\n    }\n\n    private void thenCommandIsNotStopped() {\n        assertFalse(this.isStopped);\n    }\n\n    private void thenCommandIsKilled() {\n        assertTrue(this.isKilled);\n    }\n\n    private void thenCommandIsNotKilled() {\n        assertFalse(this.isKilled);\n    }\n\n    private void configureMock(DefaultExecutor deMock) {\n        String executablePs = \"ps\";\n        String[] argumentsPs1 = { \"-p\", \"1234\" };\n        String[] argumentsPsAx = { \"-ax\" };\n        String executableUnprivileged = \"su\";\n        String[] argumentsKill1 = { \"kura\", \"-c\", \"timeout -s SIGTERM 60 kill -15 1234\" };\n        String[] argumentsKill2 = { \"kill\", \"-9\", \"1234\" };\n        try {\n            when(deMock.execute(argThat(new CommandLineMatcher(executableUnprivileged, argumentsKill1)))).thenReturn(1);\n            when(deMock.execute(argThat(new CommandLineMatcher(executableUnprivileged, argumentsKill2)))).thenReturn(0);\n            doAnswer(invocation -> {\n                out.reset();\n                PrintWriter pw = new PrintWriter(out);\n                pw.println(1234);\n                pw.flush();\n                pw.close();\n                return 0;\n            }).when(deMock).execute(argThat(new CommandLineMatcher(executablePs, argumentsPs1)));\n            doAnswer(invocation -> {\n                out.reset();\n                PrintWriter pw = new PrintWriter(out);\n                pw.println(\" 1234 pts/0    R+     0:00 find / -name foo\");\n                pw.flush();\n                pw.close();\n                return 0;\n            }).when(deMock).execute(argThat(new CommandLineMatcher(executablePs, argumentsPsAx)));\n        } catch (IOException e) {\n            // Do nothing...\n        }\n        when(deMock.getWatchdog()).thenReturn(new ExecuteWatchdog(1));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/test/java/org/eclipse/kura/core/linux/executor/CommandExecutionTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.linux.executor;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.ByteArrayOutputStream;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.function.Consumer;\n\nimport org.apache.commons.io.Charsets;\nimport org.eclipse.kura.core.internal.linux.executor.ExecutorUtil;\nimport org.eclipse.kura.core.linux.executor.privileged.PrivilegedExecutorServiceImpl;\nimport org.eclipse.kura.core.linux.executor.unprivileged.UnprivilegedExecutorServiceImpl;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\n\n@RunWith(Parameterized.class)\npublic class CommandExecutionTest {\n\n    private static CommandExecutorService executor;\n\n    public CommandExecutionTest(CommandExecutorService executor) {\n        CommandExecutionTest.executor = executor;\n    }\n\n    @Parameterized.Parameters\n    public static Collection<CommandExecutorService> getExecutors() {\n        return Arrays.asList(new UnprivilegedExecutorServiceImpl(mock(SystemService.class)),\n                new PrivilegedExecutorServiceImpl());\n    }\n\n    private Command command;\n    private CommandStatus status;\n    private Consumer<CommandStatus> callback = cs -> {\n        this.status = cs;\n    };\n\n    @Test\n    public void shouldReturnErrorOnEmptyCommand() {\n        givenCommand(\" \");\n        givenCommandExecutor();\n\n        whenCommandSyncExecuted();\n\n        thenReturnExitValue(1);\n        thenReturnErrorMessage(\"The commandLine cannot be empty or not defined\");\n    }\n\n    @Test\n    public void shouldReturnSuccess() {\n        givenCommand(\"ls -all\");\n        givenCommandExecutor();\n\n        whenCommandSyncExecuted();\n\n        thenReturnExitValue(0);\n    }\n\n    @Test\n    public void shouldAcceptErrorOnEmptyCommand() {\n        givenCommand(\" \");\n        givenCommandExecutor();\n\n        whenCommandAsyncExecuted(this.callback);\n\n        thenReturnExitValue(1);\n    }\n\n    @Test\n    public void shouldAcceptSuccess() {\n        givenCommand(\"ls -all\");\n        givenCommandExecutor();\n\n        whenCommandAsyncExecuted(this.callback);\n\n        thenReturnExitValue(0);\n    }\n\n    private void givenCommandExecutor() {\n        ExecutorUtil euMock = mock(ExecutorUtil.class);\n        CommandStatus cs = new CommandStatus(this.command, new LinuxExitStatus(0));\n        when(euMock.executePrivileged(this.command)).thenReturn(cs);\n        when(euMock.executeUnprivileged(this.command)).thenReturn(cs);\n        doAnswer(invocation -> {\n            this.callback.accept(cs);\n            return null;\n        }).when(euMock).executePrivileged(this.command, this.callback);\n        doAnswer(invocation -> {\n            this.callback.accept(cs);\n            return null;\n        }).when(euMock).executeUnprivileged(this.command, this.callback);\n        try {\n            TestUtil.setFieldValue(executor, \"executorUtil\", euMock);\n        } catch (NoSuchFieldException e) {\n            // Do nothing...\n        }\n    }\n\n    private void givenCommand(String commandLine) {\n        this.command = new Command(commandLine.split(\" \"));\n        this.command.setOutputStream(new ByteArrayOutputStream());\n        this.command.setErrorStream(new ByteArrayOutputStream());\n    }\n\n    private void whenCommandSyncExecuted() {\n        this.status = executor.execute(this.command);\n    }\n\n    private void whenCommandAsyncExecuted(Consumer<CommandStatus> callback) {\n        executor.execute(this.command, callback);\n    }\n\n    private void thenReturnExitValue(int expectedExitValue) {\n        assertEquals(expectedExitValue, this.status.getExitStatus().getExitCode());\n    }\n\n    private void thenReturnErrorMessage(String expectedErrorMessage) {\n        assertEquals(expectedErrorMessage,\n                new String(((ByteArrayOutputStream) this.status.getErrorStream()).toByteArray(), Charsets.UTF_8));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/test/java/org/eclipse/kura/core/linux/executor/CommandPidTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.linux.executor;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.core.internal.linux.executor.ExecutorUtil;\nimport org.eclipse.kura.core.linux.executor.privileged.PrivilegedExecutorServiceImpl;\nimport org.eclipse.kura.core.linux.executor.unprivileged.UnprivilegedExecutorServiceImpl;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.Pid;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\n\n@RunWith(Parameterized.class)\npublic class CommandPidTest {\n\n    private static CommandExecutorService executor;\n    private static String[] commandLine = { \"find\", \"/\", \"-name\", \"foo\" };\n    private Map<String, Pid> pids = new HashMap<>();\n\n    public CommandPidTest(CommandExecutorService executor) {\n        CommandPidTest.executor = executor;\n    }\n\n    @Parameterized.Parameters\n    public static Collection<CommandExecutorService> getExecutors() {\n        return Arrays.asList(new UnprivilegedExecutorServiceImpl(mock(SystemService.class)),\n                new PrivilegedExecutorServiceImpl());\n    }\n\n    @Test\n    public void shouldRetrievePidsFromCommandLine() {\n        givenCommandExecutor();\n\n        whenRetrievePids(commandLine);\n\n        thenPidsAreNotEmpty();\n    }\n\n    private void givenCommandExecutor() {\n        Map<String, Pid> p = new HashMap<>();\n        p.put(String.join(\" \", commandLine), new LinuxPid(1234));\n        ExecutorUtil euMock = mock(ExecutorUtil.class);\n        when(euMock.getPids(commandLine)).thenReturn(p);\n        try {\n            TestUtil.setFieldValue(executor, \"executorUtil\", euMock);\n        } catch (NoSuchFieldException e) {\n            // Do nothing...\n        }\n    }\n\n    private void whenRetrievePids(String[] commandLine) {\n        this.pids = executor.getPids(commandLine);\n    }\n\n    private void thenPidsAreNotEmpty() {\n        assertFalse(this.pids.isEmpty());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/test/java/org/eclipse/kura/core/linux/executor/CommandRunningTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.linux.executor;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport org.eclipse.kura.core.internal.linux.executor.ExecutorUtil;\nimport org.eclipse.kura.core.linux.executor.privileged.PrivilegedExecutorServiceImpl;\nimport org.eclipse.kura.core.linux.executor.unprivileged.UnprivilegedExecutorServiceImpl;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.Pid;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\n\n@RunWith(Parameterized.class)\npublic class CommandRunningTest {\n\n    private static CommandExecutorService executor;\n    private static Pid pid = new LinuxPid(1234);\n    private static String[] commandLine = { \"find\", \"/\", \"-name\", \"foo\" };\n    private boolean isRunning;\n\n    public CommandRunningTest(CommandExecutorService executor) {\n        CommandRunningTest.executor = executor;\n    }\n\n    @Parameterized.Parameters\n    public static Collection<CommandExecutorService> getExecutors() {\n        return Arrays.asList(new UnprivilegedExecutorServiceImpl(mock(SystemService.class)),\n                new PrivilegedExecutorServiceImpl());\n    }\n\n    @Test\n    public void shouldBeRunningPid() {\n        givenCommandExecutor();\n\n        whenCheckIfRunning(pid);\n\n        thenCommandIsRunning();\n    }\n\n    @Test\n    public void shouldNotBeRunningCommandLine() {\n        givenCommandExecutor();\n\n        whenCheckIfRunning(commandLine);\n\n        thenCommandIsNotRunning();\n    }\n\n    private void givenCommandExecutor() {\n        ExecutorUtil euMock = mock(ExecutorUtil.class);\n        when(euMock.isRunning(pid)).thenReturn(true);\n        when(euMock.isRunning(commandLine)).thenReturn(false);\n        try {\n            TestUtil.setFieldValue(executor, \"executorUtil\", euMock);\n        } catch (NoSuchFieldException e) {\n            // Do nothing...\n        }\n    }\n\n    private void whenCheckIfRunning(Pid pid) {\n        this.isRunning = executor.isRunning(pid);\n    }\n\n    private void whenCheckIfRunning(String[] commandLine) {\n        this.isRunning = executor.isRunning(commandLine);\n    }\n\n    private void thenCommandIsRunning() {\n        assertTrue(this.isRunning);\n    }\n\n    private void thenCommandIsNotRunning() {\n        assertFalse(this.isRunning);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.test/src/test/java/org/eclipse/kura/core/linux/executor/CommandTerminationTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.linux.executor;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.Arrays;\nimport java.util.Collection;\n\nimport org.eclipse.kura.core.internal.linux.executor.ExecutorUtil;\nimport org.eclipse.kura.core.linux.executor.privileged.PrivilegedExecutorServiceImpl;\nimport org.eclipse.kura.core.linux.executor.unprivileged.UnprivilegedExecutorServiceImpl;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.Pid;\nimport org.eclipse.kura.system.SystemService;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\n\n@RunWith(Parameterized.class)\npublic class CommandTerminationTest {\n\n    private static CommandExecutorService executor;\n    private static Pid pid = new LinuxPid(1234);\n    private static String[] commandLine = { \"find\", \"/\", \"-name\", \"foo\" };\n    private boolean isStopped;\n    private boolean isKilled;\n\n    public CommandTerminationTest(CommandExecutorService executor) {\n        CommandTerminationTest.executor = executor;\n    }\n\n    @Parameterized.Parameters\n    public static Collection<CommandExecutorService> getExecutors() {\n        return Arrays.asList(new UnprivilegedExecutorServiceImpl(mock(SystemService.class)),\n                new PrivilegedExecutorServiceImpl());\n    }\n\n    @Test\n    public void shouldStopCommand() {\n        givenCommandExecutor();\n\n        whenStopCommand(pid, null);\n\n        thenCommandIsStopped();\n    }\n\n    @Test\n    public void shouldNotStopCommandWithSignal() {\n        givenCommandExecutor();\n\n        whenStopCommand(pid, LinuxSignal.SIGHUP);\n\n        thenCommandIsNotStopped();\n    }\n\n    @Test\n    public void shouldKillCommand() {\n        givenCommandExecutor();\n\n        whenKillCommand(commandLine, null);\n\n        thenCommandIsKilled();\n    }\n\n    @Test\n    public void shouldNotKillCommandWithSignal() {\n        givenCommandExecutor();\n\n        whenKillCommand(commandLine, LinuxSignal.SIGHUP);\n\n        thenCommandIsNotKilled();\n    }\n\n    private void givenCommandExecutor() {\n        ExecutorUtil euMock = mock(ExecutorUtil.class);\n        when(euMock.stopPrivileged(pid, LinuxSignal.SIGTERM)).thenReturn(true);\n        when(euMock.stopPrivileged(pid, LinuxSignal.SIGHUP)).thenReturn(false);\n        when(euMock.killPrivileged(commandLine, LinuxSignal.SIGTERM)).thenReturn(true);\n        when(euMock.killPrivileged(commandLine, LinuxSignal.SIGHUP)).thenReturn(false);\n        when(euMock.stopUnprivileged(pid, LinuxSignal.SIGTERM)).thenReturn(true);\n        when(euMock.stopUnprivileged(pid, LinuxSignal.SIGHUP)).thenReturn(false);\n        when(euMock.killUnprivileged(commandLine, LinuxSignal.SIGTERM)).thenReturn(true);\n        when(euMock.killUnprivileged(commandLine, LinuxSignal.SIGHUP)).thenReturn(false);\n        try {\n            TestUtil.setFieldValue(executor, \"executorUtil\", euMock);\n        } catch (NoSuchFieldException e) {\n            // Do nothing...\n        }\n    }\n\n    private void whenStopCommand(Pid pid, LinuxSignal signal) {\n        this.isStopped = executor.stop(pid, signal);\n    }\n\n    private void whenKillCommand(String[] commandLine, LinuxSignal signal) {\n        this.isKilled = executor.kill(commandLine, signal);\n    }\n\n    private void thenCommandIsStopped() {\n        assertTrue(this.isStopped);\n    }\n\n    private void thenCommandIsNotStopped() {\n        assertFalse(this.isStopped);\n    }\n\n    private void thenCommandIsKilled() {\n        assertTrue(this.isKilled);\n    }\n\n    private void thenCommandIsNotKilled() {\n        assertFalse(this.isKilled);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.util.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.util.test\nBundle-SymbolicName: org.eclipse.kura.core.util.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.slf4j;version=\"1.6.4\",\n org.eclipse.kura.core.testutil,\n org.apache.commons.io;version=\"[2.4.0,3.0.0)\"\nFragment-Host: org.eclipse.kura.core;bundle-version=\"1.0.100\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.util.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.util.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.util.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.core.util.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n    \n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.util.test/src/test/java/org/eclipse/kura/core/util/NetUtilTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimport org.junit.runners.MethodSorters;\n\n@FixMethodOrder(MethodSorters.NAME_ASCENDING)\npublic class NetUtilTest {\n\n\t@Test\n\tpublic void testHardwareAddressToString() {\n\t\tbyte[] input = {0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB};\n\t\tString result = NetUtil.hardwareAddressToString(input);\n\t\tassertEquals(\"01:23:45:67:89:AB\", result);\n\t}\n\n\t@Test\n\tpublic void testHardwareAddressToStringNull() {\n\t\tbyte[] input = null;\n\t\tString result = NetUtil.hardwareAddressToString(input);\n\t\tassertEquals(\"N/A\", result);\n\t}\n\n\t@Test(expected = IllegalArgumentException.class)\n\tpublic void testHardwareAddressToStringEmptyValue() {\n\t\tNetUtil.hardwareAddressToString(new byte[]{});\n\t}\n\n\t@Test(expected = IllegalArgumentException.class)\n\tpublic void testHardwareAddressToStringNotEnoughElements() {\n\t\tbyte[] input = {0x01, 0x23, 0x45, 0x67, (byte) 0x89};\n\t\tNetUtil.hardwareAddressToString(input);\n\t}\n\n\t@Test(expected = IllegalArgumentException.class)\n\tpublic void testHardwareAddressToStringTooManyElements() {\n\t\tbyte[] input = {0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB, 0x42};\n\t\tNetUtil.hardwareAddressToString(input);\n\t}\n\n\t@Test\n\tpublic void testHardwareAddressToBytes() {\n\t\tbyte[] result = NetUtil.hardwareAddressToBytes(\"01:23:45:67:89:AB\");\n\t\tbyte[] expected = {0x01, 0x23, 0x45, 0x67, (byte) 0x89, (byte) 0xAB};\n\t\tassertArrayEquals(expected, result);\n\t}\n\n\t@Test\n\tpublic void testHardwareAddressToBytesNullOrEmpty() {\n\t\tbyte[] expected = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};\n\n\t\tbyte[] result = NetUtil.hardwareAddressToBytes(null);\n\t\tassertArrayEquals(expected, result);\n\n\t\tresult = NetUtil.hardwareAddressToBytes(\"\");\n\t\tassertArrayEquals(expected, result);\n\t}\n\n\t@Test(expected = IllegalArgumentException.class)\n\tpublic void testHardwareAddressToBytesInvalidValue1() {\n\t\tNetUtil.hardwareAddressToBytes(\"g1:23:45:67:89:AB\");\n\t}\n\n\t@Test(expected = IllegalArgumentException.class)\n\tpublic void testHardwareAddressToBytesInvalidValue2() {\n\t\tNetUtil.hardwareAddressToBytes(\"01::45:67:89:AB\");\n\t}\n\n\t@Test(expected = IllegalArgumentException.class)\n\tpublic void testHardwareAddressToBytesInvalidValueNotEnoughElements() {\n\t\tNetUtil.hardwareAddressToBytes(\"01:23:45:67:89\");\n\t}\n\n\t@Test(expected = IllegalArgumentException.class)\n\tpublic void testHardwareAddressToBytesTooManyElements() {\n\t\tNetUtil.hardwareAddressToBytes(\"01:23:45:67:89:AB:42\");\n\t}\n\n\t@Test(expected = IllegalArgumentException.class)\n\tpublic void testHardwareAddressToBytesOutOfRangeValue() {\n\t\tNetUtil.hardwareAddressToBytes(\"101:23:45:67:89:AB\");\n\t}\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.util.test/src/test/java/org/eclipse/kura/core/util/ProcessUtilTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\nimport java.io.File;\nimport java.io.PrintWriter;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.junit.BeforeClass;\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimport org.junit.runners.MethodSorters;\n\n@FixMethodOrder(MethodSorters.NAME_ASCENDING)\npublic class ProcessUtilTest {\n\n    private static String TEMP_SCRIPT_FILE_PATH = \"/tmp/kura_test_script_ProcessUtilTest\";\n\n    private static boolean win = System.getProperty(\"os.name\").contains(\"indows\");\n\n    @BeforeClass\n    public static void setup() {\n        if (win) {\n            TEMP_SCRIPT_FILE_PATH += \".bat\";\n\n            File f = new File(\"/tmp\");\n            if (!f.exists()) {\n                f.mkdirs();\n                f.deleteOnExit();\n            }\n        }\n    }\n\n    @Test\n    public void testExecString() throws Exception {\n        int[] values = new int[] { 0, 1, 2 };\n        String command = \"/bin/sh \" + TEMP_SCRIPT_FILE_PATH;\n        if (win) {\n            command = TEMP_SCRIPT_FILE_PATH;\n        }\n        File file = new File(TEMP_SCRIPT_FILE_PATH);\n        file.deleteOnExit();\n\n        for (int value : values) {\n            String stdout;\n            String stderr;\n            int errorCode = -1;\n\n            try {\n                try (PrintWriter out = new PrintWriter(file)) {\n                    if (win) {\n                        out.println(\"@echo off\");\n                    }\n                    out.println(\"echo stdout\");\n                    out.println(\"echo stderr 1>&2\");\n                    out.println(\"exit \" + value);\n                }\n\n                SafeProcess process = ProcessUtil.exec(command);\n\n                errorCode = process.exitValue();\n                stdout = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8);\n                stderr = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8);\n            } catch (Exception e) {\n                throw e;\n            } finally {\n                file.delete();\n            }\n\n            assertEquals(value, errorCode);\n            assertEquals(\"stdout\", stdout.trim());\n            assertEquals(\"stderr\", stderr.trim());\n        }\n    }\n\n    @Test\n    public void testExecStringArray() throws Exception {\n        int[] values = new int[] { 0, 1, 2 };\n        String[] commandArray = { \"/bin/sh\", TEMP_SCRIPT_FILE_PATH };\n        if (win) {\n            commandArray = new String[] { TEMP_SCRIPT_FILE_PATH };\n        }\n        File file = new File(TEMP_SCRIPT_FILE_PATH);\n        file.deleteOnExit();\n\n        for (int value : values) {\n            String stdout;\n            String stderr;\n            int errorCode = -1;\n\n            try {\n                try (PrintWriter out = new PrintWriter(file)) {\n                    if (win) {\n                        out.println(\"@echo off\");\n                    }\n                    out.println(\"echo stdout\");\n                    out.println(\"echo stderr 1>&2\");\n                    out.println(\"exit \" + value);\n                }\n\n                SafeProcess process = ProcessUtil.exec(commandArray);\n\n                errorCode = process.exitValue();\n                stdout = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8);\n                stderr = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8);\n            } catch (Exception e) {\n                throw e;\n            } finally {\n                file.delete();\n            }\n\n            assertEquals(value, errorCode);\n            assertEquals(\"stdout\", stdout.trim());\n            assertEquals(\"stderr\", stderr.trim());\n        }\n    }\n\n    @Test\n    public void testDestroy() throws Exception {\n        // First execute the process\n        String[] commandArray = { \"/bin/sh\", TEMP_SCRIPT_FILE_PATH };\n        if (win) {\n            commandArray = new String[] { TEMP_SCRIPT_FILE_PATH };\n        }\n        File file = new File(TEMP_SCRIPT_FILE_PATH);\n        file.deleteOnExit();\n\n        SafeProcess process;\n\n        try {\n            try (PrintWriter out = new PrintWriter(file)) {\n                if (win) {\n                    out.println(\"@echo off\");\n                }\n                out.println(\"echo stdout\");\n                out.println(\"echo stderr 1>&2\");\n                out.println(\"exit 0\");\n            }\n\n            process = ProcessUtil.exec(commandArray);\n        } catch (Exception e) {\n            throw e;\n        } finally {\n            file.delete();\n        }\n\n        String stdout = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8);\n        String stderr = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8);\n\n        assertEquals(\"stdout\", stdout.trim());\n        assertEquals(\"stderr\", stderr.trim());\n\n        // Then destroy it\n        ProcessUtil.destroy(process);\n\n        assertNull(TestUtil.getFieldValue(process, \"inBytes\"));\n        assertNull(TestUtil.getFieldValue(process, \"errBytes\"));\n        assertNull(TestUtil.getFieldValue(process, \"process\"));\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.util.test/src/test/java/org/eclipse/kura/core/util/SafeProcessTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\nimport java.io.File;\nimport java.io.PrintWriter;\nimport java.nio.charset.StandardCharsets;\n\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.junit.BeforeClass;\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimport org.junit.runners.MethodSorters;\n\n@FixMethodOrder(MethodSorters.NAME_ASCENDING)\npublic class SafeProcessTest {\n\n    private static String TEMP_SCRIPT_FILE_PATH = \"/tmp/kura_test_script_SafeProcessTest\";\n    private static boolean win = System.getProperty(\"os.name\").contains(\"indows\");\n\n    @BeforeClass\n    public static void setup() {\n        System.out.println(System.getProperty(\"os.name\"));\n        if (win) {\n            TEMP_SCRIPT_FILE_PATH += \".bat\";\n\n            File f = new File(\"/tmp\");\n            if (!f.exists()) {\n                f.mkdirs();\n                f.deleteOnExit();\n            }\n        }\n    }\n\n    @Test\n    public void testExec() throws Exception {\n        int[] values = new int[] { 0, 1, 2 };\n        String[] commandArray = { \"/bin/sh\", TEMP_SCRIPT_FILE_PATH };\n        if (win) {\n            commandArray = new String[] { TEMP_SCRIPT_FILE_PATH };\n        }\n\n        File file = new File(TEMP_SCRIPT_FILE_PATH);\n        file.deleteOnExit();\n\n        for (int expectedErrorCode : values) {\n            String stdout;\n            String stderr;\n            int errorCode = -1;\n\n            try {\n                try (PrintWriter out = new PrintWriter(file)) {\n                    if (win) {\n                        out.println(\"@echo off\");\n                    }\n                    out.println(\"echo stdout\");\n                    out.println(\"echo stderr 1>&2\");\n                    out.println(\"exit \" + expectedErrorCode);\n                }\n\n                SafeProcess process = new SafeProcess();\n                process.exec(commandArray);\n\n                errorCode = process.exitValue();\n                stdout = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8);\n                stderr = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8);\n            } catch (Exception e) {\n                throw e;\n            } finally {\n                file.delete();\n            }\n\n            assertEquals(expectedErrorCode, errorCode);\n            assertEquals(\"stdout\", stdout.trim());\n            assertEquals(\"stderr\", stderr.trim());\n        }\n    }\n\n    @Test\n    public void testDestroy() throws Exception {\n        // First execute the process\n        String[] commandArray = { \"/bin/sh\", TEMP_SCRIPT_FILE_PATH };\n        if (win) {\n            commandArray = new String[] { TEMP_SCRIPT_FILE_PATH };\n        }\n\n        File file = new File(TEMP_SCRIPT_FILE_PATH);\n        file.deleteOnExit();\n\n        SafeProcess process = new SafeProcess();\n\n        try {\n            try (PrintWriter out = new PrintWriter(file)) {\n                if (win) {\n                    out.println(\"@echo off\");\n                }\n                out.println(\"echo stdout\");\n                out.println(\"echo stderr 1>&2\");\n                out.println(\"exit 0\");\n            }\n\n            process.exec(commandArray);\n        } catch (Exception e) {\n            throw e;\n        } finally {\n            file.delete();\n        }\n\n        String stdout = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8);\n        String stderr = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8);\n\n        assertEquals(\"stdout\", stdout.trim());\n        assertEquals(\"stderr\", stderr.trim());\n\n        // Then destroy it\n        process.destroy();\n\n        assertNull(TestUtil.getFieldValue(process, \"inBytes\"));\n        assertNull(TestUtil.getFieldValue(process, \"errBytes\"));\n        assertNull(TestUtil.getFieldValue(process, \"process\"));\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.util.test/src/test/java/org/eclipse/kura/core/util/ValidationUtilTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.core.util;\n\nimport static org.junit.Assert.*;\n\nimport org.eclipse.kura.KuraException;\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimport org.junit.runners.MethodSorters;\n\n@FixMethodOrder(MethodSorters.NAME_ASCENDING)\npublic class ValidationUtilTest {\n\n\t@Test\n\tpublic void testNotNullWithObject() throws KuraException {\n\t\tObject value = new Object();\n\t\tValidationUtil.notNull(value, \"value\");\n\t}\n\n\t@Test(expected = KuraException.class)\n\tpublic void testNotNullWithNullObject() throws KuraException {\n\t\tObject value = null;\n\t\tValidationUtil.notNull(value, \"value\");\n\t}\n\n\t@Test\n\tpublic void testNotEmptyOrNullWithNonEmptyString() throws KuraException {\n\t\tString value = \"xyz\";\n\t\tValidationUtil.notEmptyOrNull(value, \"value\");\n\t}\n\n\t@Test(expected = KuraException.class)\n\tpublic void testNotEmptyOrNullWithNullString() throws KuraException {\n\t\tString value = null;\n\t\tValidationUtil.notEmptyOrNull(value, \"value\");\n\t}\n\n\t@Test(expected = KuraException.class)\n\tpublic void testNotEmptyOrNullWithEmptyString() throws KuraException {\n\t\tString value = \"\";\n\t\tValidationUtil.notEmptyOrNull(value, \"value\");\n\t}\n\n\t@Test(expected = KuraException.class)\n\tpublic void testNotEmptyOrNullWithWhitespace() throws KuraException {\n\t\tString value = \" \\t\\n\\r\\f\";\n\t\tValidationUtil.notEmptyOrNull(value, \"value\");\n\t}\n\n\t@Test\n\tpublic void testNotNegativeIntStringWithZero() throws KuraException {\n\t\tint value = 0;\n\t\tValidationUtil.notNegative(value, \"value\");\n\t}\n\n\t@Test\n\tpublic void testNotNegativeIntStringWithPositive() throws KuraException {\n\t\tint value = 1;\n\t\tValidationUtil.notNegative(value, \"value\");\n\t}\n\n\t@Test(expected = KuraException.class)\n\tpublic void testNotNegativeIntStringWithNegative() throws KuraException {\n\t\tint value = -1;\n\t\tValidationUtil.notNegative(value, \"value\");\n\t}\n\n\t@Test\n\tpublic void testNotNegativeShortStringWithZero() throws KuraException {\n\t\tshort value = 0;\n\t\tValidationUtil.notNegative(value, \"value\");\n\t}\n\n\t@Test\n\tpublic void testNotNegativeShortStringWithPositive() throws KuraException {\n\t\tshort value = 1;\n\t\tValidationUtil.notNegative(value, \"value\");\n\t}\n\n\t@Test(expected = KuraException.class)\n\tpublic void testNotNegativeShortStringWithNegative() throws KuraException {\n\t\tshort value = -1;\n\t\tValidationUtil.notNegative(value, \"value\");\n\t}\n\n\t@Test\n\tpublic void testNotNegativeLongStringWithZero() throws KuraException {\n\t\tlong value = 0;\n\t\tValidationUtil.notNegative(value, \"value\");\n\t}\n\n\t@Test\n\tpublic void testNotNegativeLongStringWithPositive() throws KuraException {\n\t\tlong value = 1;\n\t\tValidationUtil.notNegative(value, \"value\");\n\t}\n\n\t@Test(expected = KuraException.class)\n\tpublic void testNotNegativeLongStringWithNegative() throws KuraException {\n\t\tlong value = -1;\n\t\tValidationUtil.notNegative(value, \"value\");\n\t}\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.core.util.test/src/test/resources/log4j.properties",
    "content": "log4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.h2db.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.db.h2db.provider.test\nBundle-SymbolicName: org.eclipse.kura.db.h2db.provider.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.apache.felix.service.command;version=\"1.0.0\",\n org.eclipse.kura;version=\"[1.7,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\",\n org.eclipse.kura.db;version=\"2.0.0\",\n org.junit;version=\"4.12.0\",\n org.mockito;version=\"4.8.1\",\n org.mockito.invocation;version=\"4.8.1\",\n org.mockito.stubbing;version=\"4.8.1\",\n org.osgi.framework;version=\"1.10.0\"\nFragment-Host: org.eclipse.kura.db.h2db.provider\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.h2db.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.h2db.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2022 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.h2db.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.db.h2db.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.h2db.provider.test/src/test/java/org/eclipse/kura/internal/db/h2db/provider/DbDataStoreStorageTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.db.h2db.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.Arrays;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.db.H2DbService;\nimport org.eclipse.kura.db.H2DbService.ConnectionCallable;\nimport org.eclipse.kura.message.store.StoredMessage;\nimport org.eclipse.kura.message.store.provider.MessageStore;\nimport org.eclipse.kura.util.jdbc.ConnectionProvider;\nimport org.eclipse.kura.util.jdbc.SQLFunction;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class DbDataStoreStorageTest {\n\n    private static final String TOPIC = \"TEST-TOPIC\";\n    private static final int QOS0 = 0;\n    private static final int QOS1 = 1;\n    private static final int QOS2 = 2;\n    private static final int PRIORITY_HIGH = 0;\n    private static final int PRIORITY_MEDIUM = 1;\n    private static final int PRIORITY_LOW = 2;\n    private static final String TABLE_NAME = \"test-table\";\n    private static final int H2_MAX_ID_VALUE = 2147483647;\n    private byte[] payload;\n    private Exception occurredException = null;\n\n    private MessageStore dataStore;\n    private int messageId;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldStoreNullPayload() {\n        givenNullPayload();\n        givenDbDataStore(10000, 10000);\n\n        whenStore(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n\n        thenNoExceptionsOccurred();\n        thenStoredMessageIs(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n    }\n\n    @Test\n    public void shouldStoreSmallPayload() {\n        givenSmallPayload();\n        givenDbDataStore(10000, 10000);\n\n        whenStore(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n\n        thenNoExceptionsOccurred();\n        thenStoredMessageIs(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n    }\n\n    @Test\n    public void shouldStoreLargePayload() {\n        givenLargePayload();\n        givenDbDataStore(10000, 10000);\n\n        whenStore(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n\n        thenNoExceptionsOccurred();\n        thenStoredMessageIs(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n    }\n\n    @Test\n    public void idsAreResetIfOverflown() {\n        givenSmallPayload();\n        givenDbDataStore(H2_MAX_ID_VALUE, H2_MAX_ID_VALUE);\n\n        whenOverflowingIds();\n\n        thenNoExceptionsOccurred();\n        thenLastIdIsCorrect();\n    }\n\n    @Test\n    public void storeWithPriority0ShouldUpdateDbEvenIfDbIsFull() {\n        givenSmallPayload();\n        givenDbDataStore(H2_MAX_ID_VALUE, H2_MAX_ID_VALUE);\n\n        whenStore(TOPIC, this.payload, QOS0, true, PRIORITY_HIGH);\n\n        thenStoredMessageIs(TOPIC, this.payload, QOS0, true, PRIORITY_HIGH);\n    }\n\n    @Test\n    public void storeWithPriority1ShouldUpdateDbEvenIfDbIsFull() {\n        givenSmallPayload();\n        givenDbDataStore(H2_MAX_ID_VALUE, H2_MAX_ID_VALUE);\n\n        whenStore(TOPIC, this.payload, QOS1, true, PRIORITY_MEDIUM);\n\n        thenStoredMessageIs(TOPIC, this.payload, QOS1, true, PRIORITY_MEDIUM);\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenNullPayload() {\n        this.payload = null;\n    }\n\n    private void givenSmallPayload() {\n        this.payload = new byte[200];\n        for (int i = 0; i < 199; i++) {\n            this.payload[i] = 1;\n        }\n    }\n\n    private void givenLargePayload() {\n        this.payload = new byte[300];\n        for (int i = 0; i < 300; i++) {\n            this.payload[i] = 2;\n        }\n    }\n\n    @SuppressWarnings(\"restriction\")\n    private void givenDbDataStore(int houseKeeperInterval, int purgeAge) {\n        H2DbService h2Service = new MockH2DbService();\n\n        try {\n            this.dataStore = new H2DbMessageStoreImpl(new ConnectionProvider() {\n\n                @Override\n                public <T> T withConnection(SQLFunction<Connection, T> task) throws SQLException {\n                    return h2Service.withConnection(task::call);\n                }\n            }, TABLE_NAME);\n        } catch (KuraStoreException e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * When\n     */\n\n    private void whenStore(String topic, byte[] payload, int qos, boolean retain, int priority) {\n        try {\n            this.messageId = this.dataStore.store(topic, payload, qos, retain, priority);\n        } catch (KuraStoreException e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenOverflowingIds() {\n        try {\n            for (int i = 0; i < H2_MAX_ID_VALUE + 1; i++) {\n                this.messageId = this.dataStore.store(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n\n                Class.forName(\"org.h2.Driver\");\n                Connection c = DriverManager.getConnection(\"jdbc:h2:mem:testdb;\", \"sa\", \"\");\n\n                // keep just one message at every moment\n                for (int j = 0; j < i; j++) {\n                    PreparedStatement stmt = c.prepareStatement(\"DELETE FROM ? WHERE ID=?;\");\n                    stmt.setString(1, TABLE_NAME);\n                    stmt.setInt(2, i);\n                    stmt.execute();\n                }\n\n                c.commit();\n\n            }\n\n            this.messageId = this.dataStore.store(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n            this.messageId = this.dataStore.store(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n            this.messageId = this.dataStore.store(TOPIC, this.payload, QOS2, true, PRIORITY_LOW);\n        } catch (KuraStoreException | SQLException | ClassNotFoundException e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenNoExceptionsOccurred() {\n        assertNull(this.occurredException);\n    }\n\n    private void thenStoredMessageIs(String topic, byte[] payload, int qos, boolean retain, int priority) {\n        StoredMessage message;\n        try {\n            message = this.dataStore.get(this.messageId)\n                    .orElseThrow(() -> new IllegalStateException(\"no message with the given id\"));\n        } catch (KuraStoreException e1) {\n            fail(\"Unable to retrieve last message\");\n            throw new IllegalStateException();\n        }\n\n        assertEquals(topic, message.getTopic());\n        assertTrue(Arrays.equals(payload, message.getPayload()));\n        assertEquals(qos, message.getQos());\n        assertEquals(retain, message.isRetain());\n        assertEquals(priority, message.getPriority());\n\n        // also inspect the database\n        try {\n\n            Class.forName(\"org.h2.Driver\");\n            Connection c = DriverManager.getConnection(\"jdbc:h2:mem:testdb;\", \"sa\", \"\");\n            PreparedStatement stmt = c.prepareStatement(\"SELECT * FROM ?;\", Statement.RETURN_GENERATED_KEYS);\n            stmt.setString(1, TABLE_NAME);\n            ResultSet rs = stmt.executeQuery();\n\n            while (rs.next()) {\n                if (rs.getInt(\"id\") == message.getId()) {\n                    String rowTopic = rs.getString(\"topic\");\n                    int rowQos = rs.getInt(\"qos\");\n                    boolean rowRetain = rs.getBoolean(\"retain\");\n                    byte[] smallPayload = rs.getBytes(\"smallPayload\");\n                    byte[] largePayload = rs.getBytes(\"largePayload\");\n                    int rowPriority = rs.getInt(\"priority\");\n\n                    assertEquals(topic, rowTopic);\n                    assertEquals(qos, rowQos);\n                    assertEquals(retain, rowRetain);\n                    assertEquals(priority, rowPriority);\n                    if (message.getPayload().length < 200) {\n                        assertTrue(Arrays.equals(payload, smallPayload));\n                        assertNull(largePayload);\n                    } else {\n                        assertTrue(Arrays.equals(payload, largePayload));\n                        assertNull(smallPayload);\n                    }\n                }\n            }\n\n        } catch (SQLException | ClassNotFoundException e) {\n            this.occurredException = e;\n        }\n\n    }\n\n    private void thenStoreCapacityExceededException() {\n        assertNotNull(this.occurredException);\n    }\n\n    private void thenLastIdIsCorrect() {\n        assertEquals(3, this.messageId);\n    }\n\n    /*\n     * Utilities\n     */\n\n    @Before\n    public void cleanUp() {\n        this.occurredException = null;\n    }\n\n    private final class MockH2DbService implements H2DbService {\n\n        @Override\n        public Connection getConnection() throws SQLException {\n            try {\n                Class.forName(\"org.h2.Driver\");\n                return DriverManager.getConnection(\"jdbc:h2:mem:testdb;\", \"sa\", \"\");\n            } catch (ClassNotFoundException e) {\n                DbDataStoreStorageTest.this.occurredException = e;\n            }\n            return null;\n        }\n\n        @Override\n        public void close(Connection conn) {\n            // ignore\n\n        }\n\n        @Override\n        public void rollback(Connection conn) {\n            // ignore\n\n        }\n\n        @Override\n        public void close(ResultSet... rss) {\n            // ignore\n\n        }\n\n        @Override\n        public void close(Statement... stmts) {\n            // ignore\n\n        }\n\n        @Override\n        public <T> T withConnection(ConnectionCallable<T> task) throws SQLException {\n            return task.call(this.getConnection());\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.h2db.provider.test/src/test/java/org/eclipse/kura/internal/db/h2db/provider/H2DbServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.db.h2db.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.junit.Test;\n\npublic class H2DbServiceImplTest {\n\n    @Test\n    public void testUpdate() throws KuraException, SQLException {\n        final String enc = \"enc\";\n        char[] encPass = enc.toCharArray();\n        String pass = \"pass\";\n        String user = \"USR\";\n\n        H2DbServiceImpl svc = new H2DbServiceImpl();\n        svc.activate(Collections.emptyMap());\n\n        CryptoService csMock = mock(CryptoService.class);\n        svc.setCryptoService(csMock);\n\n        when(csMock.decryptAes(encPass)).thenReturn(pass.toCharArray());\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"db.user\", user);\n        props.put(\"db.password\", enc);\n        props.put(\"db.connection.pool.max.size\", 10);\n        props.put(\"db.connector.url\", \"jdbc:h2:mem:testdb\");\n\n        try {\n            svc.getConnection();\n        } catch (SQLException e) {\n            assertTrue(e.getMessage().contains(\"not initialized\"));\n        }\n\n        svc.updated(props);\n\n        Connection conn = svc.getConnection();\n        PreparedStatement statement = conn.prepareStatement(\"SELECT USER()\");\n\n        ResultSet rs = statement.executeQuery();\n        rs.next();\n        String result = rs.getString(1);\n\n        assertEquals(user, result);\n\n        svc.deactivate();\n    }\n\n    @Test\n    public void testUpdateFailUrlPattern() throws KuraException, SQLException {\n        String pass = \"pass\";\n        String user = \"USR\";\n\n        H2DbServiceImpl svc = new H2DbServiceImpl();\n        svc.activate(Collections.emptyMap());\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"db.user\", user);\n        props.put(\"db.password\", pass);\n        props.put(\"db.connection.pool.max.size\", 10);\n        props.put(\"db.connector.url\", \"jdb:h2:mem:testdb\");\n\n        try {\n            svc.getConnection();\n        } catch (SQLException e) {\n            assertTrue(e.getMessage().contains(\"not initialized\"));\n        }\n\n        try {\n            svc.updated(props);\n        } catch (IllegalArgumentException e) {\n            assertEquals(\"Invalid DB URL\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void testUpdateFailDriver() throws KuraException, SQLException {\n        String pass = \"pass\";\n        String user = \"USR\";\n\n        H2DbServiceImpl svc = new H2DbServiceImpl();\n        svc.activate(Collections.emptyMap());\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"db.user\", user);\n        props.put(\"db.password\", pass);\n        props.put(\"db.connection.pool.max.size\", 10);\n        props.put(\"db.connector.url\", \"jdbc:h3:mem:testdb\");\n\n        try {\n            svc.getConnection();\n        } catch (SQLException e) {\n            assertTrue(e.getMessage().contains(\"not initialized\"));\n        }\n\n        try {\n            svc.updated(props);\n        } catch (IllegalArgumentException e) {\n            assertEquals(\"JDBC driver must be h2\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void testUpdateFailRemote() throws Throwable {\n        final String enc = \"enc\";\n        char[] encPass = enc.toCharArray();\n        String pass = \"pass\";\n        String user = \"USR\";\n\n        H2DbServiceImpl svc = new H2DbServiceImpl();\n        svc.activate(Collections.emptyMap());\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"db.user\", user);\n        props.put(\"db.password\", enc);\n        props.put(\"db.connection.pool.max.size\", 10);\n        props.put(\"db.connector.url\", \"jdbc:h2:rmt:test\");\n\n        try {\n            svc.updated(props);\n        } catch (IllegalArgumentException e) {\n            assertEquals(\"Remote databases are not supported\", e.getMessage());\n        }\n    }\n\n    @Test\n    public void testUpdateFailAnonymous() throws Throwable {\n        final String enc = \"enc\";\n        char[] encPass = enc.toCharArray();\n        String pass = \"pass\";\n        String user = \"USR\";\n\n        H2DbServiceImpl svc = new H2DbServiceImpl();\n        svc.activate(Collections.emptyMap());\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"db.user\", user);\n        props.put(\"db.password\", enc);\n        props.put(\"db.connection.pool.max.size\", 10);\n        props.put(\"db.connector.url\", \"jdbc:h2:mem:\");\n\n        try {\n            svc.updated(props);\n        } catch (IllegalArgumentException e) {\n            assertTrue(e.getMessage().startsWith(\"Anonymous\"));\n        }\n    }\n\n    @Test\n    public void testUpdateFailUrlOccupied() throws Throwable {\n        final String enc = \"enc\";\n        char[] encPass = enc.toCharArray();\n        String pass = \"pass\";\n        String user = \"USR\";\n        String url = \"jdbc:h2:mem:test\";\n\n        H2DbServiceImpl svc1 = new H2DbServiceImpl();\n        Map<String, H2DbServiceImpl> activeInstances = (Map<String, H2DbServiceImpl>) TestUtil.getFieldValue(svc1,\n                \"activeInstances\");\n        activeInstances.put(url, svc1);\n\n        H2DbServiceImpl svc = new H2DbServiceImpl();\n        svc.activate(Collections.emptyMap());\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"db.user\", user);\n        props.put(\"db.password\", enc);\n        props.put(\"db.connection.pool.max.size\", 10);\n        props.put(\"db.connector.url\", url);\n\n        try {\n            svc.updated(props);\n        } catch (IllegalArgumentException e) {\n            assertTrue(e.getMessage().startsWith(\"Another H2DbService instance\"));\n        }\n    }\n\n    @Test\n    public void testUpdateFile() throws Throwable {\n        final String filePathString = \"/tmp/kurah2/testdb\";\n        final String enc = \"enc\";\n        char[] encPass = enc.toCharArray();\n        String pass = \"pass\";\n        String user = \"USR\";\n\n        H2DbServiceImpl svc = new H2DbServiceImpl();\n        svc.activate(Collections.emptyMap());\n\n        CryptoService csMock = mock(CryptoService.class);\n        svc.setCryptoService(csMock);\n\n        when(csMock.decryptAes(encPass)).thenReturn(pass.toCharArray());\n\n        Map<String, Object> props = new HashMap<>();\n        props.put(\"db.user\", user);\n        props.put(\"db.password\", enc);\n        props.put(\"db.connection.pool.max.size\", 10);\n        File f = new File(filePathString);\n        props.put(\"db.connector.url\", \"jdbc:h2:file:\" + f.getAbsolutePath());\n\n        try {\n            svc.getConnection();\n        } catch (SQLException e) {\n            assertTrue(e.getMessage().contains(\"not initialized\"));\n        }\n\n        svc.updated(props);\n\n        Connection conn = svc.getConnection();\n        PreparedStatement statement = conn.prepareStatement(\"SELECT USER()\");\n\n        ResultSet rs = statement.executeQuery();\n        rs.next();\n        String result = rs.getString(1);\n\n        assertEquals(user, result);\n\n        svc.deactivate();\n\n        Path filePath = Paths.get(filePathString + \".mv.db\");\n        assertTrue(Files.exists(filePath));\n\n        H2DbServiceOptions cfg = (H2DbServiceOptions) TestUtil.getFieldValue(svc, \"configuration\");\n        TestUtil.invokePrivate(svc, \"deleteDbFiles\", cfg);\n\n        assertFalse(Files.exists(filePath));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.util.test\nBundle-SymbolicName: org.eclipse.kura.db.sqlite.provider.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.apache.felix.service.command;version=\"1.0.0\",\n org.eclipse.kura;version=\"[1.7,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\",\n org.eclipse.kura.db;version=\"2.0.0\",\n org.junit;version=\"4.12.0\",\n org.mockito;version=\"4.8.1\",\n org.mockito.invocation;version=\"4.8.1\",\n org.mockito.stubbing;version=\"4.8.1\",\n org.osgi.framework;version=\"1.10.0\"\nFragment-Host: org.eclipse.kura.db.sqlite.provider\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2022 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.db.sqlite.provider.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n    \n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/src/main/java/org/eclipse/kura/db/sqlite/provider/test/SqliteDbServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.db.sqlite.provider.test;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.eclipse.kura.KuraException;\nimport org.junit.Test;\nimport org.osgi.framework.InvalidSyntaxException;\n\npublic class SqliteDbServiceImplTest extends SqliteDbServiceTestBase {\n\n    public SqliteDbServiceImplTest() throws InterruptedException, ExecutionException, TimeoutException {\n        super();\n    }\n\n    @Test\n    public void shouldNotExtractNativeLibrariesInJavaTempdir()\n            throws InterruptedException, ExecutionException, TimeoutException {\n        givenSqliteDbService(Collections.emptyMap());\n\n        whenAConnectionIsRequested();\n\n        thenThereIsNoSqliteLibraryInJavaTempdir();\n    }\n\n    @Test\n    public void shouldCreateDbServiceWithDefaultConfig()\n            throws InterruptedException, ExecutionException, TimeoutException {\n        givenSqliteDbService(Collections.emptyMap());\n\n        whenAConnectionIsRequested();\n\n        thenNoExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldSupportRollbackJournalMode()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"ROLLBACK_JOURNAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\" //\n        ));\n\n        whenQueryIsPerformed(\"CREATE TABLE FOO (BAR INTEGER);\");\n\n        thenNoExceptionIsThrown();\n        thenFileExists(temporaryDirectory() + \"/test.sqlite\");\n        thenFileDoesNotExist(temporaryDirectory() + \"/test.sqlite-shm\");\n        thenFileDoesNotExist(temporaryDirectory() + \"/test.sqlite-wal\");\n    }\n\n    @Test\n    public void shouldSupportWalJournalMode()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"WAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\" //\n        ));\n\n        whenQueryIsPerformed(\"CREATE TABLE FOO (BAR INTEGER);\");\n\n        thenNoExceptionIsThrown();\n        thenFileExists(temporaryDirectory() + \"/test.sqlite\");\n        thenFileExists(temporaryDirectory() + \"/test.sqlite-shm\");\n        thenFileExists(temporaryDirectory() + \"/test.sqlite-wal\");\n    }\n\n    @Test\n    public void shouldSupportWalCheckpoint()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"WAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\", //\n                \"db.wal.checkpoint.interval.seconds\", 5L //\n        ));\n\n        givenExecutedQuery(\"CREATE TABLE FOO (BAR INTEGER);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (1);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (1);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (2);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (3);\");\n\n        whenTimePasses(10, TimeUnit.SECONDS);\n\n        thenFileExists(temporaryDirectory() + \"/test.sqlite-wal\");\n        thenFileSizeIs(temporaryDirectory() + \"/test.sqlite-wal\", 0);\n    }\n\n    @Test\n    public void shouldDisableWalCheckpoint()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"WAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\", //\n                \"db.wal.checkpoint.interval.seconds\", 5L, //\n                \"db.wal.checkpoint.enabled\", false));\n\n        givenExecutedQuery(\"CREATE TABLE FOO (BAR INTEGER);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (1);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (1);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (2);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (3);\");\n\n        whenTimePasses(10, TimeUnit.SECONDS);\n\n        thenFileExists(temporaryDirectory() + \"/test.sqlite-wal\");\n        thenFileSizeIsNotZero(temporaryDirectory() + \"/test.sqlite-wal\");\n    }\n\n    @Test\n    public void shouldSupporDefragInRollbackJournalMode()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"ROLLBACK_JOURNAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\", //\n                \"db.defrag.interval.seconds\", 5L //\n        ));\n\n        givenExecutedQuery(\"CREATE TABLE FOO (BAR TEXT);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES ('\" + largeText(20000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES ('\" + largeText(20000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES ('\" + largeText(20000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES ('\" + largeText(20000) + \"');\");\n        givenInitialFileSize(temporaryDirectory() + \"/test.sqlite\");\n        givenExecutedQuery(\"DELETE FROM FOO;\");\n\n        whenTimePasses(10, TimeUnit.SECONDS);\n\n        thenFileSizeDecreased(temporaryDirectory() + \"/test.sqlite\");\n    }\n\n    @Test\n    public void shouldDisableDefragInRollbackJournalMode()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"ROLLBACK_JOURNAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\", //\n                \"db.defrag.interval.seconds\", 5L, //\n                \"db.defrag.enabled\", false //\n        ));\n\n        givenExecutedQuery(\"CREATE TABLE FOO (BAR TEXT);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES ('\" + largeText(20000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES ('\" + largeText(20000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES ('\" + largeText(20000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES ('\" + largeText(20000) + \"');\");\n        givenInitialFileSize(temporaryDirectory() + \"/test.sqlite\");\n        givenExecutedQuery(\"DELETE FROM FOO;\");\n\n        whenTimePasses(10, TimeUnit.SECONDS);\n\n        thenFileSizeDidNotChange(temporaryDirectory() + \"/test.sqlite\");\n    }\n\n    @Test\n    public void shouldDisableDefragInWalMode()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"WAL\", //\n                \"db.path\", temporaryDirectory() + \"/waldefrag.sqlite\", //\n                \"db.defrag.interval.seconds\", 5L, //\n                \"db.defrag.enabled\", false //\n        ));\n\n        givenExecutedQuery(\"CREATE TABLE FOO (BAR TEXT);\");\n        givenExecutedQuery(\"INSERT INTO FOO (BAR) VALUES ('\" + largeText(2000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO (BAR) VALUES ('\" + largeText(2000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO (BAR) VALUES ('\" + largeText(2000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO (BAR) VALUES ('\" + largeText(2000) + \"');\");\n        givenExecutedQuery(\"PRAGMA wal_checkpoint(TRUNCATE);\");\n        givenInitialFileSize(temporaryDirectory() + \"/waldefrag.sqlite\");\n        givenExecutedQuery(\"DELETE FROM FOO;\");\n        givenExecutedQuery(\"PRAGMA wal_checkpoint(TRUNCATE);\");\n\n        whenTimePasses(10, TimeUnit.SECONDS);\n\n        thenFileSizeDidNotChange(temporaryDirectory() + \"/waldefrag.sqlite\");\n    }\n\n    @Test\n    public void shouldSupporDefragInWalMode()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"WAL\", //\n                \"db.path\", temporaryDirectory() + \"/waldefrag.sqlite\", //\n                \"db.defrag.interval.seconds\", 5L //\n        ));\n\n        givenExecutedQuery(\"CREATE TABLE FOO (BAR TEXT);\");\n        givenExecutedQuery(\"INSERT INTO FOO (BAR) VALUES ('\" + largeText(2000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO (BAR) VALUES ('\" + largeText(2000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO (BAR) VALUES ('\" + largeText(2000) + \"');\");\n        givenExecutedQuery(\"INSERT INTO FOO (BAR) VALUES ('\" + largeText(2000) + \"');\");\n        givenExecutedQuery(\"PRAGMA wal_checkpoint(TRUNCATE);\");\n        givenInitialFileSize(temporaryDirectory() + \"/waldefrag.sqlite\");\n        givenExecutedQuery(\"DELETE FROM FOO;\");\n        givenExecutedQuery(\"PRAGMA wal_checkpoint(TRUNCATE);\");\n\n        whenTimePasses(10, TimeUnit.SECONDS);\n\n        thenFileSizeDecreased(temporaryDirectory() + \"/waldefrag.sqlite\");\n    }\n\n    @Test\n    public void shouldSupportSwitchFromRollbackJournalToWal() throws InterruptedException, ExecutionException,\n            TimeoutException, IOException, KuraException, InvalidSyntaxException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"ROLLBACK_JOURNAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\" //\n        ));\n        givenExecutedQuery(\"CREATE TABLE FOO (BAR INTEGER);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (1);\");\n\n        whenSqliteDbServiceIsUpdated(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"WAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\", //\n                \"db.wal.checkpoint.interval.seconds\", 5L //\n        ));\n        whenQueryIsPerformed(\"INSERT INTO FOO VALUES (2);\");\n\n        thenNoExceptionIsThrown();\n        thenFileExists(temporaryDirectory() + \"/test.sqlite\");\n        thenFileExists(temporaryDirectory() + \"/test.sqlite-shm\");\n        thenFileExists(temporaryDirectory() + \"/test.sqlite-wal\");\n    }\n\n    @Test\n    public void shouldSupportSwitchFromWalToRollbackJournal() throws InterruptedException, ExecutionException,\n            TimeoutException, IOException, KuraException, InvalidSyntaxException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"WAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\", //\n                \"db.wal.checkpoint.interval.seconds\", 5L //\n        ));\n\n        givenExecutedQuery(\"CREATE TABLE FOO (BAR INTEGER);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (1);\");\n\n        whenSqliteDbServiceIsUpdated(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"ROLLBACK_JOURNAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\" //\n        ));\n        whenQueryIsPerformed(\"INSERT INTO FOO VALUES (2);\");\n\n        thenNoExceptionIsThrown();\n        thenFileExists(temporaryDirectory() + \"/test.sqlite\");\n        thenFileDoesNotExist(temporaryDirectory() + \"/test.sqlite-shm\");\n        thenFileDoesNotExist(temporaryDirectory() + \"/test.sqlite-wal\");\n    }\n\n    @Test\n    public void shoulNotSupportTwoIntancesOnSameDbPath()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"ROLLBACK_JOURNAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\" //\n        ));\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"ROLLBACK_JOURNAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\" //\n        ));\n\n        whenAConnectionIsRequested();\n\n        thenExceptionIsThrown();\n    }\n\n    @Test\n    public void deleteDbFileIfItCannotBeOpenedRollbackJournal()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-journal\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-shm\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-wal\", \"foobar\");\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"ROLLBACK_JOURNAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\" //\n        ));\n        whenAConnectionIsRequested();\n\n        thenNoExceptionIsThrown();\n        thenFileContentIsNot(temporaryDirectory() + \"/test.sqlite\", \"foobar\");\n        thenFileContentIsNot(temporaryDirectory() + \"/test.sqlite-journal\", \"foobar\");\n        thenFileContentIsNot(temporaryDirectory() + \"/test.sqlite-shm\", \"foobar\");\n        thenFileContentIsNot(temporaryDirectory() + \"/test.sqlite-wal\", \"foobar\");\n    }\n\n    @Test\n    public void deleteDbFileIfItCannotBeOpenedWAL()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-journal\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-shm\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-wal\", \"foobar\");\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"WAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\" //\n        ));\n        whenAConnectionIsRequested();\n\n        thenNoExceptionIsThrown();\n        thenFileContentIsNot(temporaryDirectory() + \"/test.sqlite\", \"foobar\");\n        thenFileContentIsNot(temporaryDirectory() + \"/test.sqlite-journal\", \"foobar\");\n        thenFileContentIsNot(temporaryDirectory() + \"/test.sqlite-shm\", \"foobar\");\n        thenFileContentIsNot(temporaryDirectory() + \"/test.sqlite-wal\", \"foobar\");\n    }\n\n    @Test\n    public void deleteNotDbFileIfItCannotBeOpenedIFNotEnabledRollbackJournal()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-journal\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-shm\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-wal\", \"foobar\");\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"ROLLBACK_JOURNAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\", //\n                \"delete.db.files.on.failure\", false) //\n        );\n        whenAConnectionIsRequested();\n\n        thenExceptionIsThrown();\n        thenFileContentIs(temporaryDirectory() + \"/test.sqlite\", \"foobar\");\n    }\n\n    @Test\n    public void deleteNotDbFileIfItCannotBeOpenedIFNotEnabledWal()\n            throws InterruptedException, ExecutionException, TimeoutException, IOException {\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-journal\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-shm\", \"foobar\");\n        givenFileWithContent(temporaryDirectory() + \"/test.sqlite-wal\", \"foobar\");\n        givenSqliteDbService(map( //\n                \"db.mode\", \"PERSISTED\", //\n                \"db.journal.mode\", \"WAL\", //\n                \"db.path\", temporaryDirectory() + \"/test.sqlite\", //\n                \"delete.db.files.on.failure\", false) //\n        );\n        whenAConnectionIsRequested();\n\n        thenExceptionIsThrown();\n        thenFileContentIs(temporaryDirectory() + \"/test.sqlite\", \"foobar\");\n    }\n\n    private void givenFileWithContent(final String file, final String content) throws IOException {\n        try (final FileOutputStream out = new FileOutputStream(file)) {\n            out.write(content.getBytes(StandardCharsets.UTF_8));\n        }\n    }\n\n    private void thenThereIsNoSqliteLibraryInJavaTempdir() {\n        final File javaTempDir = new File(System.getProperty(\"java.io.tmpdir\"));\n\n        assertArrayEquals(new String[] {}, javaTempDir.list((dir, name) -> name.startsWith(\"sqlite-\")));\n    }\n\n    private void thenFileContentIs(final String path, final String content) throws IOException {\n        final byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);\n        final byte[] actualContent = new byte[contentBytes.length + 1];\n\n        final int len = fillBuffer(new File(path), actualContent);\n\n        assertEquals(contentBytes.length, len);\n        assertArrayEquals(contentBytes, Arrays.copyOfRange(actualContent, 0, len));\n    }\n\n    private void thenFileContentIsNot(final String path, final String content) throws IOException {\n        final byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);\n        final byte[] actualContent = new byte[contentBytes.length + 1];\n\n        final File file = new File(path);\n\n        if (!file.exists()) {\n            return;\n        }\n\n        final int len = fillBuffer(file, actualContent);\n\n        if (contentBytes.length == len) {\n            assertFalse(Arrays.equals(contentBytes, Arrays.copyOfRange(actualContent, 0, len)));\n        }\n    }\n\n    private int fillBuffer(final File file, final byte[] dst) throws FileNotFoundException, IOException {\n        int pos = 0;\n\n        try (final FileInputStream in = new FileInputStream(file)) {\n\n            int rd;\n\n            while (pos < dst.length && (rd = in.read(dst, pos, dst.length - pos)) != -1) {\n                pos += rd;\n            }\n        }\n\n        return pos;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/src/main/java/org/eclipse/kura/db/sqlite/provider/test/SqliteDbServiceTestBase.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.db.sqlite.provider.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.sql.Connection;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.db.BaseDbService;\nimport org.junit.After;\nimport org.osgi.framework.InvalidSyntaxException;\n\npublic class SqliteDbServiceTestBase {\n\n    private static final String SQLITE_DB_SERVICE_FACTORY_PID = \"org.eclipse.kura.db.SQLiteDbService\";\n    private static final AtomicInteger currentId = new AtomicInteger(0);\n\n    private final ConfigurationService configurationService;\n    private final List<String> createdPids = new ArrayList<>();\n    private final Map<Path, Long> fileSize = new HashMap<>();\n    private BaseDbService dbService;\n    private Optional<Path> temporaryDirectory = Optional.empty();\n    protected Optional<Exception> exception = Optional.empty();\n\n    public SqliteDbServiceTestBase() throws InterruptedException, ExecutionException, TimeoutException {\n        this.configurationService = ServiceUtil.trackService(ConfigurationService.class, Optional.empty()).get(60,\n                TimeUnit.SECONDS);\n    }\n\n    @After\n    public void cleanup() throws InterruptedException, ExecutionException, TimeoutException {\n        for (final String pid : createdPids) {\n            ServiceUtil.deleteFactoryConfiguration(configurationService, pid).get(60, TimeUnit.SECONDS);\n        }\n    }\n\n    protected void givenSqliteDbService(final Map<String, Object> properties)\n            throws InterruptedException, ExecutionException, TimeoutException {\n\n        final String pid = \"testDb\" + currentId.incrementAndGet();\n\n        this.dbService = ServiceUtil.createFactoryConfiguration(configurationService, BaseDbService.class, pid,\n                SQLITE_DB_SERVICE_FACTORY_PID, properties).get(30, TimeUnit.SECONDS);\n\n        createdPids.add(pid);\n    }\n\n    protected void givenExecutedQuery(final String query) {\n        whenQueryIsPerformed(query);\n        thenNoExceptionIsThrown();\n    }\n\n    protected void givenInitialFileSize(final String pathStr) throws IOException {\n        final Path path = new File(pathStr).toPath();\n\n        this.fileSize.put(path, Files.size(path));\n    }\n\n    protected void whenAConnectionIsRequested() {\n        try (final Connection conn = dbService.getConnection()) {\n        } catch (final Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    protected void whenQueryIsPerformed(final String query) {\n        try (final Connection conn = dbService.getConnection(); final Statement statement = conn.createStatement()) {\n            statement.executeUpdate(query);\n        } catch (final Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    protected void whenSqliteDbServiceIsUpdated(final Map<String, Object> properties)\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n\n        final String pid = \"testDb\" + currentId.get();\n\n        ServiceUtil.updateComponentConfiguration(configurationService, pid, properties).get(30, TimeUnit.SECONDS);\n\n    }\n\n    protected void whenTimePasses(final long duration, final TimeUnit timeUnit) throws InterruptedException {\n        Thread.sleep(timeUnit.toMillis(duration));\n    }\n\n    protected void thenFileExists(final String path) {\n        assertTrue(new File(path).exists());\n    }\n\n    protected void thenFileSizeIs(final String path, final int size) throws IOException {\n        assertEquals(size, Files.size(new File(path).toPath()));\n    }\n\n    protected void thenFileSizeIsNotZero(final String path) throws IOException {\n        assertNotEquals(0, Files.size(new File(path).toPath()));\n    }\n\n    protected void thenFileSizeDecreased(final String pathStr) throws IOException {\n        final Path path = new File(pathStr).toPath();\n\n        final long before = this.fileSize.get(path);\n        final long after = Files.size(path);\n\n        assertTrue(\"file size did not decrease, before \" + before + \" after \" + after, after < before);\n    }\n\n    protected void thenFileSizeDidNotChange(String pathStr) throws IOException {\n        final Path path = new File(pathStr).toPath();\n\n        final long before = this.fileSize.get(path);\n        final long after = Files.size(path);\n\n        assertEquals(\"file size decreased, before \" + before + \" after \" + after, before, after);\n\n    }\n\n    protected void thenFileDoesNotExist(final String path) {\n        assertFalse(new File(path).exists());\n    }\n\n    protected void thenNoExceptionIsThrown() {\n        assertEquals(Optional.empty(), this.exception);\n    }\n\n    protected void thenExceptionIsThrown() {\n        assertTrue(this.exception.isPresent());\n        this.exception = Optional.empty();\n    }\n\n    protected <E extends Exception> void thenExceptionIsThrown(final Class<E> clazz, final String messageSubstring) {\n        assertTrue(this.exception.isPresent());\n        assertTrue(clazz.isInstance(this.exception.get()));\n        assertTrue(this.exception.get().getMessage().contains(messageSubstring));\n        this.exception = Optional.empty();\n    }\n\n    protected Path getOrCreateTemporaryDirectory() throws IOException {\n        if (temporaryDirectory.isPresent()) {\n            return temporaryDirectory.get();\n        } else {\n            temporaryDirectory = Optional.of(Files.createTempDirectory(null).toAbsolutePath());\n            return getOrCreateTemporaryDirectory();\n        }\n    }\n\n    protected String temporaryDirectory() throws IOException {\n        return getOrCreateTemporaryDirectory().toString();\n    }\n\n    protected String dbServicePid() {\n        return \"testDb\" + currentId.get();\n    }\n\n    protected String largeText(final int size) {\n        final StringBuilder stringBuilder = new StringBuilder();\n\n        for (int i = 0; i < size; i++) {\n            stringBuilder.append('a');\n        }\n\n        return stringBuilder.toString();\n    }\n\n    protected Map<String, Object> map(final Object... objects) {\n        final Map<String, Object> result = new HashMap<>();\n\n        final Iterator<Object> iter = Arrays.asList(objects).iterator();\n\n        while (iter.hasNext()) {\n            final String key = (String) iter.next();\n            final Object value = iter.next();\n\n            result.put(key, value);\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/src/main/java/org/eclipse/kura/db/sqlite/provider/test/SqliteDebugShellTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.db.sqlite.provider.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.sql.SQLException;\nimport java.util.Collections;\nimport java.util.Optional;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.apache.felix.service.command.CommandProcessor;\nimport org.apache.felix.service.command.CommandSession;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.junit.Test;\n\npublic class SqliteDebugShellTest extends SqliteDbServiceTestBase {\n\n    @Test\n    public void shouldNotAllowAccessToDatabaseIfNotEnabled() throws Exception {\n        givenSqliteDbService(Collections.emptyMap());\n\n        whenCommandIsExecuted(\"executeQuery \" + dbServicePid() + \" 'CREATE TABLE FOO (BAR INTEGER);'\");\n\n        thenExceptionIsThrown(IllegalArgumentException.class, \"is not available\");\n    }\n\n    @Test\n    public void shouldAllowAccessToDatabaseIfEnabled() throws Exception {\n        givenSqliteDbService(map(\"debug.shell.access.enabled\", true));\n\n        whenCommandIsExecuted(\"executeQuery \" + dbServicePid() + \" 'CREATE TABLE FOO (BAR INTEGER);'\");\n\n        thenNoExceptionIsThrown();\n        thenCommandOutputContains(\"0 rows changed\");\n    }\n\n    @Test\n    public void shouldDisableDebugShellOnUpdate() throws Exception {\n        givenSqliteDbService(map(\"debug.shell.access.enabled\", true));\n\n        whenSqliteDbServiceIsUpdated(map(\"debug.shell.access.enabled\", false));\n        whenCommandIsExecuted(\"executeQuery \" + dbServicePid() + \" 'CREATE TABLE FOO (BAR INTEGER);'\");\n\n        thenExceptionIsThrown(IllegalArgumentException.class, \"is not available\");\n    }\n\n    @Test\n    public void shouldEnableDebugShellOnUpdate() throws Exception {\n        givenSqliteDbService(map(\"debug.shell.access.enabled\", false));\n\n        whenSqliteDbServiceIsUpdated(map(\"debug.shell.access.enabled\", true));\n        whenCommandIsExecuted(\"executeQuery \" + dbServicePid() + \" 'CREATE TABLE FOO (BAR INTEGER);'\");\n\n        thenNoExceptionIsThrown();\n        thenCommandOutputContains(\"0 rows changed\");\n    }\n\n    @Test\n    public void shouldPrintResultSet() throws Exception {\n        givenSqliteDbService(map(\"debug.shell.access.enabled\", true));\n        givenExecutedQuery(\"CREATE TABLE FOO (T TEXT, N NUMERIC, I INTEGER, R REAL, B BLOB);\");\n        givenExecutedQuery(\n                \"INSERT INTO FOO (T, N, I, R, B) VALUES (\\\"abc\\\", 123, 12, 12.33, x'0123456789abcdef0123456789abcdef')\");\n\n        whenCommandIsExecuted(\"executeQuery \" + dbServicePid() + \" 'SELECT T, N, I, R, quote(B) AS B FROM FOO;'\");\n\n        thenNoExceptionIsThrown();\n        thenCommandOutputEquals(\"| T\\t| N\\t| I\\t| R\\t| B\\t|\\n\"\n                + \"| abc\\t| 123\\t| 12\\t| 12.33\\t| X'0123456789ABCDEF0123456789ABCDEF'\\t|\\n\" + \"\");\n    }\n\n    @Test\n    public void shouldReportFailure() throws Exception {\n        givenSqliteDbService(map(\"debug.shell.access.enabled\", true));\n        givenExecutedQuery(\"CREATE TABLE FOO (BAR INTEGER);\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (1)\");\n        givenExecutedQuery(\"INSERT INTO FOO VALUES (2)\");\n\n        whenCommandIsExecuted(\"executeQuery \" + dbServicePid() + \" 'SELECT * FROM NONEXISTING;'\");\n\n        thenExceptionIsThrown(SQLException.class, \"\");\n    }\n\n    private final CommandProcessor commandProcessor;\n\n    private final ByteArrayOutputStream out = new ByteArrayOutputStream();\n    private final ByteArrayOutputStream err = new ByteArrayOutputStream();\n\n    public SqliteDebugShellTest() throws InterruptedException, ExecutionException, TimeoutException {\n        super();\n        this.commandProcessor = ServiceUtil.trackService(CommandProcessor.class, Optional.empty()).get(30,\n                TimeUnit.SECONDS);\n    }\n\n    private void whenCommandIsExecuted(String command) {\n        final CommandSession session = commandProcessor.createSession(new InputStream() {\n\n            @Override\n            public int read() throws IOException {\n                return -1;\n            }\n        }, out, err);\n\n        try {\n            session.execute(command);\n        } catch (final Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void thenCommandOutputContains(String string) {\n        final String errString = err.toString();\n        final String outString = out.toString();\n        assertTrue(string + \" not found in out, out : \\\"\" + outString + \"\\\" err : \\\"\" + errString + \"\\\"\",\n                outString.contains(string));\n    }\n\n    private void thenCommandOutputEquals(String string) {\n        assertEquals(string, out.toString());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/src/test/java/org/eclipse/kura/internal/db/sqlite/provider/DatabaseLoaderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.SQLException;\nimport java.sql.Statement;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Properties;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.EncryptionKeyFormat;\nimport org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.EncryptionKeySpec;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.sqlite.SQLiteConfig;\nimport org.sqlite.SQLiteConfig.HexKeyMode;\nimport org.sqlite.SQLiteConfig.JournalMode;\nimport org.sqlite.SQLiteDataSource;\n\npublic class DatabaseLoaderTest {\n\n    private static final String DB_KEY_FORMAT = \"db.key.format\";\n\n    @Test\n    public void shouldOpenInMemoryDatabase() {\n        givenNewOptionsProperty(DB_MODE, \"IN_MEMORY\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n        thenOpenDataSourceInvocationCountIs(1);\n        thenOpenDataSourceInvocationUrlIs(0, \"jdbc:sqlite:file:foo?mode=memory&cache=shared\");\n        thenOpenDataSourceInvocationKeyIs(0, Optional.empty());\n\n        thenThereAreNoEntriesInCryptoService();\n    }\n\n    @Test\n    public void shouldOpenUnencryptedDatabaseIfNoPasswordsAreStored() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenUnencryptedDatabase();\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(1);\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(0, Optional.empty());\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"\");\n        thenCryptoServiceUpdateCountIs(1);\n    }\n\n    @Test\n    public void shouldSupportRollbackJournalMode() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(\"db.journal.mode\", \"ROLLBACK_JOURNAL\");\n        givenUnencryptedDatabase();\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(1);\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.DELETE);\n        thenOpenDataSourceInvocationKeyIs(0, Optional.empty());\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"\");\n        thenCryptoServiceUpdateCountIs(1);\n    }\n\n    @Test\n    public void shouldOpenUnencryptedDatabaseWithPasswordInOldOptions() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n\n        givenOldOptionsProperty(DB_KEY, TEST_ENCRYPTION_KEY);\n\n        givenUnencryptedDatabase();\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n        thenOpenDataSourceInvocationCountIs(2);\n\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(0,\n                Optional.of(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII)));\n\n        thenOpenDataSourceInvocationUrlIs(1, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(1, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(1, Optional.empty());\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"\");\n    }\n\n    @Test\n    public void shouldOpenUnencryptedDatabaseWithPasswordInCrypto() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n\n        givenCryptoServiceEntry(TEST_DB_CRYPTO_ENTRY_KEY, \"ASCII:\" + TEST_ENCRYPTION_KEY);\n\n        givenUnencryptedDatabase();\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n        thenOpenDataSourceInvocationCountIs(2);\n\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(0,\n                Optional.of(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII)));\n\n        thenOpenDataSourceInvocationUrlIs(1, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(1, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(1, Optional.empty());\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"\");\n    }\n\n    @Test\n    public void shouldOpenEncryptedDatabaseIfNoPasswordsAreStoredWithAsciiKey() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY, TEST_ENCRYPTION_KEY);\n\n        givenEncryptedDatabase(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII));\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(1);\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(0,\n                Optional.of(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII)));\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY,\n                EncryptionKeyFormat.ASCII.name() + \":\" + TEST_ENCRYPTION_KEY);\n    }\n\n    @Test\n    public void shouldOpenEncryptedDatabaseIfNoPasswordsAreStoredWithSSEHekKey() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY, TEST_HEX_ENCRYPTION_KEY);\n        givenNewOptionsProperty(DB_KEY_FORMAT, EncryptionKeyFormat.HEX_SSE.name());\n\n        givenEncryptedDatabase(\n                new EncryptionKeySpec(TEST_HEX_ENCRYPTION_KEY.toUpperCase(), EncryptionKeyFormat.HEX_SSE));\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(1);\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(0,\n                Optional.of(new EncryptionKeySpec(TEST_HEX_ENCRYPTION_KEY.toUpperCase(), EncryptionKeyFormat.HEX_SSE)));\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY,\n                EncryptionKeyFormat.HEX_SSE.name() + \":\" + TEST_HEX_ENCRYPTION_KEY.toUpperCase());\n    }\n\n    @Test\n    public void shouldOpenEncryptedDatabaseIfNoPasswordsAreStoredWithSQLCipherHekKey() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY, TEST_HEX_ENCRYPTION_KEY);\n        givenNewOptionsProperty(DB_KEY_FORMAT, EncryptionKeyFormat.HEX_SQLCIPHER.name());\n\n        givenEncryptedDatabase(\n                new EncryptionKeySpec(TEST_HEX_ENCRYPTION_KEY.toUpperCase(), EncryptionKeyFormat.HEX_SQLCIPHER));\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(1);\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(0, Optional\n                .of(new EncryptionKeySpec(TEST_HEX_ENCRYPTION_KEY.toUpperCase(), EncryptionKeyFormat.HEX_SQLCIPHER)));\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY,\n                EncryptionKeyFormat.HEX_SQLCIPHER.name() + \":\" + TEST_HEX_ENCRYPTION_KEY.toUpperCase());\n    }\n\n    @Test\n    public void shouldDecryptEncryptedDatabaseWithPasswordInOldOptions() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenOldOptionsProperty(DB_KEY, TEST_ENCRYPTION_KEY);\n\n        givenEncryptedDatabase(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII));\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(2);\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(0,\n                Optional.of(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII)));\n\n        thenOpenDataSourceInvocationUrlIs(1, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(1, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(1, Optional.empty());\n\n        thenQueryIsExecuted(0, \"PRAGMA rekey = '';\");\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"\");\n\n    }\n\n    @Test\n    public void shouldDecryptEncryptedDatabaseWithPasswordInCrypto() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenOldOptionsProperty(DB_KEY, TEST_ENCRYPTION_KEY);\n\n        givenCryptoServiceEntry(TEST_DB_CRYPTO_ENTRY_KEY, \"ASCII:\" + TEST_ENCRYPTION_KEY);\n\n        givenEncryptedDatabase(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII));\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(2);\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(0,\n                Optional.of(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII)));\n\n        thenOpenDataSourceInvocationUrlIs(1, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(1, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(1, Optional.empty());\n\n        thenQueryIsExecuted(0, \"PRAGMA rekey = '';\");\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"\");\n    }\n\n    @Test\n    public void shouldSupportRekeyWithAsciiKey() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenOldOptionsProperty(DB_KEY, TEST_ENCRYPTION_KEY);\n        givenNewOptionsProperty(DB_KEY, \"otherkey\");\n\n        givenEncryptedDatabase(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII));\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(3);\n\n        thenOpenDataSourceInvocationKeyIs(0, Optional.of(new EncryptionKeySpec(\"otherkey\", EncryptionKeyFormat.ASCII)));\n        thenOpenDataSourceInvocationKeyIs(1,\n                Optional.of(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII)));\n        thenOpenDataSourceInvocationKeyIs(2, Optional.of(new EncryptionKeySpec(\"otherkey\", EncryptionKeyFormat.ASCII)));\n\n        thenQueryIsExecuted(0, \"PRAGMA rekey = 'otherkey';\");\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"ASCII:otherkey\");\n    }\n\n    @Test\n    public void shouldSupportRekeyWithSseHexKey() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenOldOptionsProperty(DB_KEY, TEST_HEX_ENCRYPTION_KEY);\n        givenNewOptionsProperty(DB_KEY, \"cc\");\n        givenNewOptionsProperty(DB_KEY_FORMAT, EncryptionKeyFormat.HEX_SSE.name());\n\n        givenEncryptedDatabase(new EncryptionKeySpec(TEST_HEX_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII));\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(3);\n\n        thenOpenDataSourceInvocationKeyIs(0, Optional.of(new EncryptionKeySpec(\"CC\", EncryptionKeyFormat.HEX_SSE)));\n        thenOpenDataSourceInvocationKeyIs(1,\n                Optional.of(new EncryptionKeySpec(TEST_HEX_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII)));\n        thenOpenDataSourceInvocationKeyIs(2, Optional.of(new EncryptionKeySpec(\"CC\", EncryptionKeyFormat.HEX_SSE)));\n\n        thenQueryIsExecuted(0, \"PRAGMA hexrekey = 'CC';\");\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"HEX_SSE:CC\");\n    }\n\n    @Test\n    public void shouldSupportRekeyWithSqlcipherHexKey() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenOldOptionsProperty(DB_KEY, TEST_HEX_ENCRYPTION_KEY);\n        givenNewOptionsProperty(DB_KEY, \"bb\");\n        givenNewOptionsProperty(DB_KEY_FORMAT, EncryptionKeyFormat.HEX_SQLCIPHER.name());\n\n        givenEncryptedDatabase(new EncryptionKeySpec(TEST_HEX_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII));\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(3);\n\n        thenOpenDataSourceInvocationKeyIs(0,\n                Optional.of(new EncryptionKeySpec(\"BB\", EncryptionKeyFormat.HEX_SQLCIPHER)));\n        thenOpenDataSourceInvocationKeyIs(1,\n                Optional.of(new EncryptionKeySpec(TEST_HEX_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII)));\n        thenOpenDataSourceInvocationKeyIs(2,\n                Optional.of(new EncryptionKeySpec(\"BB\", EncryptionKeyFormat.HEX_SQLCIPHER)));\n\n        thenQueryIsExecuted(0, \"PRAGMA rekey = \\\"x'BB'\\\";\");\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"HEX_SQLCIPHER:BB\");\n    }\n\n    @Test\n    public void shouldNotUpdateCryptoServiceStoredKeysIfNotNeeded() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY, TEST_ENCRYPTION_KEY);\n\n        givenEncryptedDatabase(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII));\n        givenCryptoServiceEntry(TEST_DB_CRYPTO_ENTRY_KEY, EncryptionKeyFormat.ASCII.name() + \":\" + TEST_ENCRYPTION_KEY);\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(1);\n        thenOpenDataSourceInvocationUrlIs(0, TEST_DB_URL);\n        thenOpenDataSourceInvocationJournalModeIs(0, JournalMode.WAL);\n        thenOpenDataSourceInvocationKeyIs(0,\n                Optional.of(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII)));\n\n        thenCryptoServiceUpdateCountIs(0);\n    }\n\n    @Test\n    public void shouldFailIfCorrectEncryptionKeyIsUnknown() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY, \"first\");\n        givenOldOptionsProperty(DB_KEY, \"second\");\n        givenCryptoServiceEntry(TEST_DB_CRYPTO_ENTRY_KEY, EncryptionKeyFormat.ASCII.name() + \":third\");\n\n        givenEncryptedDatabase(new EncryptionKeySpec(TEST_ENCRYPTION_KEY, EncryptionKeyFormat.ASCII));\n\n        whenDataSourceIsCreated();\n\n        thenExceptionIsThrown(SQLException.class);\n    }\n\n    @Test\n    public void shouldFailWithNonAsciiEncryptionKey() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY_FORMAT, EncryptionKeyFormat.ASCII.name());\n        givenNewOptionsProperty(DB_KEY, \"🐖\");\n\n        whenDataSourceIsCreated();\n\n        thenExceptionIsThrown(KuraException.class);\n        thenExceptionMessageContains(\"non ASCII\");\n    }\n\n    @Test\n    public void shouldFailWithHexEncryptionKeyLengthNotAMultipleOfTwo() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY_FORMAT, EncryptionKeyFormat.HEX_SSE.name());\n        givenNewOptionsProperty(DB_KEY, \"abc\");\n\n        whenDataSourceIsCreated();\n\n        thenExceptionIsThrown(KuraException.class);\n        thenExceptionMessageContains(\"multiple of 2\");\n    }\n\n    @Test\n    public void shouldFailWithHexEncryptionKeyWithNotAllowedCharacters() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY_FORMAT, EncryptionKeyFormat.HEX_SSE.name());\n        givenNewOptionsProperty(DB_KEY, \"foobar\");\n\n        whenDataSourceIsCreated();\n\n        thenExceptionIsThrown(KuraException.class);\n        thenExceptionMessageContains(\"only digits and or letters from \\\"a\\\" to \\\"f\\\"\");\n    }\n\n    @Test\n    public void shouldNotDeleteDatabaseFilesIfKeyIsInvalid() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY_FORMAT, EncryptionKeyFormat.HEX_SSE.name());\n        givenNewOptionsProperty(DB_KEY, \"foobar\");\n\n        whenDataSourceIsCreated();\n\n        thenExceptionIsThrown(KuraException.class);\n        thenDatabaseFilesHaveBeenDeleted(false);\n    }\n\n    @Test\n    public void shouldRunVacuumAfterRekeyInRollbackJournalMode() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY, \"otherkey\");\n        givenNewOptionsProperty(DB_KEY_FORMAT, DB_KEY);\n        givenNewOptionsProperty(JOURNAL_MODE, \"ROLLBACK_JOURNAL\");\n\n        givenUnencryptedDatabase();\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(3);\n\n        thenOpenDataSourceInvocationKeyIs(0, Optional.of(new EncryptionKeySpec(\"otherkey\", EncryptionKeyFormat.ASCII)));\n        thenOpenDataSourceInvocationKeyIs(1, Optional.empty());\n        thenOpenDataSourceInvocationKeyIs(2, Optional.of(new EncryptionKeySpec(\"otherkey\", EncryptionKeyFormat.ASCII)));\n\n        thenExecutedQueryCountIs(2);\n        thenQueryIsExecuted(0, \"PRAGMA rekey = 'otherkey';\");\n        thenQueryIsExecuted(1, \"VACUUM;\");\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"ASCII:otherkey\");\n    }\n\n    @Test\n    public void shouldRunVacuumAfterRekeyWalMode() {\n        givenNewOptionsProperty(DB_MODE, PERSISTED);\n        givenNewOptionsProperty(DB_PATH, \"foo\");\n        givenNewOptionsProperty(KURA_SERVICE_PID, \"foo\");\n        givenNewOptionsProperty(DB_KEY, \"otherkey\");\n        givenNewOptionsProperty(DB_KEY_FORMAT, DB_KEY);\n        givenNewOptionsProperty(JOURNAL_MODE, \"WAL\");\n\n        givenUnencryptedDatabase();\n\n        whenDataSourceIsCreated();\n\n        thenNoExceptionIsThrown();\n\n        thenOpenDataSourceInvocationCountIs(3);\n\n        thenOpenDataSourceInvocationKeyIs(0, Optional.of(new EncryptionKeySpec(\"otherkey\", EncryptionKeyFormat.ASCII)));\n        thenOpenDataSourceInvocationKeyIs(1, Optional.empty());\n        thenOpenDataSourceInvocationKeyIs(2, Optional.of(new EncryptionKeySpec(\"otherkey\", EncryptionKeyFormat.ASCII)));\n\n        thenExecutedQueryCountIs(3);\n        thenQueryIsExecuted(0, \"PRAGMA rekey = 'otherkey';\");\n        thenQueryIsExecuted(1, \"VACUUM;\");\n        thenQueryIsExecuted(2, \"PRAGMA wal_checkpoint(TRUNCATE);\");\n\n        thenCryptoServiceEntryIs(TEST_DB_CRYPTO_ENTRY_KEY, \"ASCII:otherkey\");\n    }\n\n    private static final Logger logger = LoggerFactory.getLogger(DatabaseLoaderTest.class);\n\n    private static final String TEST_DB_CRYPTO_ENTRY_KEY = \"sqlite:db:foo\";\n    private static final String PERSISTED = \"PERSISTED\";\n    private static final String TEST_ENCRYPTION_KEY = \"foobar\";\n    private static final String TEST_HEX_ENCRYPTION_KEY = \"aaBB33\";\n    private static final String DB_KEY = \"db.key\";\n    private static final String DB_PATH = \"db.path\";\n    private static final String KURA_SERVICE_PID = \"kura.service.pid\";\n    private static final String DB_MODE = \"db.mode\";\n    private static final String JOURNAL_MODE = \"db.journal.mode\";\n    private static final String TEST_DB_URL = \"jdbc:sqlite:file:foo\";\n\n    private final CryptoService cryptoService = mock(CryptoService.class);\n\n    private Map<String, Object> currentProperties = new HashMap<>();\n    private Optional<Map<String, Object>> oldProperties = Optional.empty();\n    private Map<String, String> cryptoServiceEntries = new HashMap<>();\n\n    private Optional<Exception> exception = Optional.empty();\n    private DatabaseLoader loader;\n\n    private Map<String, Optional<EncryptionKeySpec>> databaseEncryptionKeys = new HashMap<>();\n\n    private final List<SQLiteConfig> sqliteConfigs = new ArrayList<>();\n    private final List<SQLiteDataSource> dataSources = new ArrayList<>();\n    private final List<String> queries = new ArrayList<>();\n    private int cryptoServiceUpdateCount = 0;\n    private boolean databaseFilesDeleted = false;\n\n    public DatabaseLoaderTest() {\n        when(cryptoService.getKeyStorePassword(any())).thenAnswer(i -> Optional\n                .ofNullable(cryptoServiceEntries.get(i.getArgument(0))).map(String::toCharArray).orElse(null));\n\n        try {\n            when(cryptoService.decryptAes(any(char[].class))).then(i -> i.getArgument(0));\n\n            Mockito.doAnswer(i -> {\n                cryptoServiceUpdateCount++;\n                cryptoServiceEntries.put(i.getArgument(0), new String(i.getArgument(1, char[].class)));\n                return null;\n            }).when(cryptoService).setKeyStorePassword(any(), any(char[].class));\n        } catch (KuraException e) {\n            throw new IllegalStateException();\n        }\n    }\n\n    private void givenEncryptedDatabase(final EncryptionKeySpec encryptionKey) {\n        givenEncryptedDatabase(TEST_DB_URL, encryptionKey);\n    }\n\n    private void givenUnencryptedDatabase() {\n        givenUnencryptedDatabase(TEST_DB_URL);\n    }\n\n    private void givenEncryptedDatabase(final String path, final EncryptionKeySpec encryptionKey) {\n        this.databaseEncryptionKeys.put(path, Optional.of(encryptionKey));\n    }\n\n    private void givenUnencryptedDatabase(final String path) {\n        this.databaseEncryptionKeys.put(path, Optional.empty());\n    }\n\n    private void givenCryptoServiceEntry(final String key, final String value) {\n        this.cryptoServiceEntries.put(key, value);\n    }\n\n    private void givenNewOptionsProperty(final String key, final String value) {\n        currentProperties.put(key, value);\n    }\n\n    private void givenOldOptionsProperty(final String key, final String value) {\n\n        if (!oldProperties.isPresent()) {\n            oldProperties = Optional.of(new HashMap<>());\n        }\n\n        oldProperties.get().put(key, value);\n    }\n\n    private void givenDatabaseLoader() {\n\n        this.loader = new DatabaseLoader(new SqliteDbServiceOptions(currentProperties),\n                oldProperties.map(SqliteDbServiceOptions::new), cryptoService) {\n\n            @Override\n            protected void changeEncryptionKey(SQLiteDataSource dataSource, Optional<EncryptionKeySpec> encryptionKey,\n                    final SqliteDbServiceOptions options) throws SQLException {\n                super.changeEncryptionKey(dataSource, encryptionKey, options);\n                databaseEncryptionKeys.put(dataSource.getUrl(), encryptionKey);\n            }\n\n            @Override\n            protected SQLiteDataSource buildDataSource(final SQLiteConfig config) {\n\n                try {\n                    sqliteConfigs.add(config);\n\n                    final Statement stmt = mock(Statement.class);\n\n                    when(stmt.execute(any())).thenAnswer(i -> {\n                        queries.add(i.getArgument(0));\n                        return false;\n                    });\n\n                    when(stmt.executeUpdate(any())).then(i -> {\n                        queries.add(i.getArgument(0));\n                        return 0;\n                    });\n\n                    final Connection connection = mock(Connection.class);\n\n                    when(connection.createStatement()).thenReturn(stmt);\n\n                    final SQLiteDataSource dataSource = new SQLiteDataSource(config) {\n\n                        @Override\n                        public Connection getConnection() throws SQLException {\n\n                            final String url = getUrl();\n\n                            final Optional<EncryptionKeySpec> currentKey = databaseEncryptionKeys.get(url);\n\n                            if (url.contains(\"mode=memory\") || Objects.equals(currentKey, fromSqliteConfig(config))) {\n                                return connection;\n                            } else {\n                                throw new SQLException();\n                            }\n                        }\n                    };\n\n                    dataSources.add(dataSource);\n\n                    return dataSource;\n                } catch (SQLException e) {\n                    throw new IllegalStateException();\n                }\n\n            }\n\n            @Override\n            protected void deleteFile(File file) throws IOException {\n                databaseFilesDeleted = true;\n            }\n        };\n\n    }\n\n    private void whenDataSourceIsCreated() {\n        givenDatabaseLoader();\n        try {\n            this.loader.openDataSource();\n        } catch (Exception e) {\n            logger.info(\"got exception\", e);\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void thenThereAreNoEntriesInCryptoService() {\n        assertTrue(this.cryptoServiceEntries.isEmpty());\n    }\n\n    private void thenCryptoServiceEntryIs(final String key, final String value) {\n        assertEquals(value, this.cryptoServiceEntries.get(key));\n    }\n\n    private void thenOpenDataSourceInvocationCountIs(final int count) {\n        assertEquals(count, this.sqliteConfigs.size());\n    }\n\n    private void thenOpenDataSourceInvocationUrlIs(final int index, final String path) {\n        assertEquals(path, this.dataSources.get(index).getUrl());\n    }\n\n    private void thenOpenDataSourceInvocationKeyIs(final int index, final Optional<EncryptionKeySpec> key) {\n        assertEquals(key, fromSqliteConfig(this.sqliteConfigs.get(index)));\n    }\n\n    private void thenOpenDataSourceInvocationJournalModeIs(final int index, final JournalMode journalMode) {\n        assertEquals(journalMode,\n                JournalMode.valueOf(this.sqliteConfigs.get(index).toProperties().getProperty(\"journal_mode\")));\n    }\n\n    private void thenDatabaseFilesHaveBeenDeleted(final boolean deleted) {\n        assertEquals(deleted, this.databaseFilesDeleted);\n    }\n\n    private void thenNoExceptionIsThrown() {\n        if (this.exception.isPresent()) {\n            this.exception.get().printStackTrace();\n        }\n\n        assertEquals(Optional.empty(), this.exception);\n    }\n\n    private void thenQueryIsExecuted(final int index, final String query) {\n        assertEquals(query, queries.get(index));\n    }\n\n    private void thenExecutedQueryCountIs(final int expectedCount) {\n        assertEquals(expectedCount, queries.size());\n    }\n\n    private void thenCryptoServiceUpdateCountIs(final int expectedCount) {\n        assertEquals(expectedCount, this.cryptoServiceUpdateCount);\n    }\n\n    private void thenExceptionIsThrown(final Class<? extends Exception> classz) {\n        if (!this.exception.isPresent()) {\n            fail(\"Exception expected\");\n        }\n\n        assertEquals(classz, this.exception.get().getClass());\n    }\n\n    private void thenExceptionMessageContains(final String messageContent) {\n        assertTrue(this.exception.get().getMessage().contains(messageContent));\n    }\n\n    private Optional<EncryptionKeySpec> fromSqliteConfig(final SQLiteConfig config) {\n        final Properties properties = config.toProperties();\n\n        final Optional<String> key = Optional.ofNullable(properties.getProperty(\"password\"));\n        final Optional<HexKeyMode> hexKeyMode = Optional.ofNullable(properties.getProperty(\"hexkey_mode\"))\n                .map(HexKeyMode::valueOf);\n\n        if (key.isPresent() && hexKeyMode.isPresent()) {\n            EncryptionKeyFormat format;\n\n            if (hexKeyMode.get() == HexKeyMode.NONE) {\n                format = EncryptionKeyFormat.ASCII;\n            } else if (hexKeyMode.get() == HexKeyMode.SSE) {\n                format = EncryptionKeyFormat.HEX_SSE;\n            } else if (hexKeyMode.get() == HexKeyMode.SQLCIPHER) {\n                format = EncryptionKeyFormat.HEX_SQLCIPHER;\n            } else {\n                throw new IllegalStateException();\n            }\n\n            return Optional.of(new EncryptionKeySpec(key.get(), format));\n        } else {\n            return Optional.empty();\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/src/test/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteDbServiceOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.Test;\n\npublic class SqliteDbServiceOptionsTest {\n\n    @Test\n    public void shouldSupportDefaultPath() {\n        givenConfigurationProperty(\"kura.service.pid\", \"foo\");\n\n        whenOptionsAreCreated();\n\n        thenDbPathIs(\"/opt/mydb.sqlite\");\n        thenDbUrlIs(\"jdbc:sqlite:file:foo?mode=memory&cache=shared\");\n    }\n\n    @Test\n    public void shouldSupportPersistedMode() {\n        givenConfigurationProperty(\"kura.service.pid\", \"foo\");\n        givenConfigurationProperty(\"db.mode\", \"PERSISTED\");\n        givenConfigurationProperty(\"db.path\", \"/tmp/foo\");\n\n        whenOptionsAreCreated();\n\n        thenDbPathIs(\"/tmp/foo\");\n        thenDbUrlIs(\"jdbc:sqlite:file:/tmp/foo\");\n    }\n\n    @Test\n    public void shouldIgnoreURIParameters() {\n        givenConfigurationProperty(\"kura.service.pid\", \"foo\");\n        givenConfigurationProperty(\"db.mode\", \"PERSISTED\");\n        givenConfigurationProperty(\"db.path\", \"/tmp/foo?baz=bar\");\n\n        whenOptionsAreCreated();\n\n        thenDbPathIs(\"/tmp/foo\");\n        thenDbUrlIs(\"jdbc:sqlite:file:/tmp/foo\");\n    }\n\n    @Test\n    public void shouldIgnoreURIParametersDoubleQuestionMark() {\n        givenConfigurationProperty(\"kura.service.pid\", \"foo\");\n        givenConfigurationProperty(\"db.mode\", \"PERSISTED\");\n        givenConfigurationProperty(\"db.path\", \"/tmp/foo?baz=bar?foo\");\n\n        whenOptionsAreCreated();\n\n        thenDbPathIs(\"/tmp/foo\");\n        thenDbUrlIs(\"jdbc:sqlite:file:/tmp/foo\");\n    }\n\n    private final Map<String, Object> properties = new HashMap<>();\n    private SqliteDbServiceOptions options;\n\n    private void givenConfigurationProperty(final String key, final Object value) {\n        properties.put(key, value);\n    }\n\n    private void whenOptionsAreCreated() {\n        this.options = new SqliteDbServiceOptions(properties);\n    }\n\n    private void thenDbPathIs(final String expectedPath) {\n        assertEquals(expectedPath, this.options.getPath());\n    }\n\n    private void thenDbUrlIs(final String expectedDbUrl) {\n        assertEquals(expectedDbUrl, this.options.getDbUrl());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.db.sqlite.provider.test/src/test/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteProviderActivatorTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.db.sqlite.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.io.File;\nimport java.nio.file.Files;\nimport java.util.Optional;\n\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.osgi.framework.BundleContext;\n\npublic class SqliteProviderActivatorTest {\n\n    @Test\n    public void shouldSetSqliteTempDirIfUnset() {\n        givenNoSystemPropertyValue(\"org.sqlite.tmpdir\");\n        givenBundleStorageAreaPath(\"/tmp/foo\");\n\n        whenActivatorIsStarted();\n\n        thenNoExceptionIsThrown();\n        thenSystemPropertyValueIs(\"org.sqlite.tmpdir\", \"/tmp/foo\");\n    }\n\n    @Test\n    public void shouldNotSetSqliteTempDirIfBundleStorageAreaIsNotAvailable() {\n        givenNoSystemPropertyValue(\"org.sqlite.tmpdir\");\n        givenNoBundleStorageArea();\n\n        whenActivatorIsStarted();\n\n        thenNoExceptionIsThrown();\n        thenSystemPropertyValueIs(\"org.sqlite.tmpdir\", null);\n    }\n\n    @Test\n    public void shouldChangeSqliteTempDirIfSetButNonExisting() {\n        givenSystemProperty(\"org.sqlite.tmpdir\", \"bar\");\n        givenBundleStorageAreaPath(\"/tmp/foo\");\n\n        whenActivatorIsStarted();\n\n        thenNoExceptionIsThrown();\n        thenSystemPropertyValueIs(\"org.sqlite.tmpdir\", \"/tmp/foo\");\n    }\n\n    @Test\n    public void shouldNotChangeSqliteTempDirIfSetAndExisting() {\n        givenSystemProperty(\"org.sqlite.tmpdir\", temporaryDirectoryPath());\n        givenBundleStorageAreaPath(\"/tmp/foo\");\n\n        whenActivatorIsStarted();\n\n        thenNoExceptionIsThrown();\n        thenSystemPropertyValueIs(\"org.sqlite.tmpdir\", temporaryDirectoryPath());\n    }\n\n    @Test\n    public void shouldClearSqliteTempDirOnStopIfChanged() {\n        givenNoSystemPropertyValue(\"org.sqlite.tmpdir\");\n        givenBundleStorageAreaPath(\"/tmp/foo\");\n        givenStartedActivator();\n\n        whenActivatorIsStopped();\n\n        thenNoExceptionIsThrown();\n        thenSystemPropertyValueIs(\"org.sqlite.tmpdir\", null);\n    }\n\n    @Test\n    public void shouldNotClearSqliteTempDirOnStopIfNotChanged() {\n        givenSystemProperty(\"org.sqlite.tmpdir\", temporaryDirectoryPath());\n        givenBundleStorageAreaPath(\"/tmp/foo\");\n        givenStartedActivator();\n\n        whenActivatorIsStopped();\n\n        thenNoExceptionIsThrown();\n        thenSystemPropertyValueIs(\"org.sqlite.tmpdir\", temporaryDirectoryPath());\n    }\n\n    private final BundleContext bundleContext = Mockito.mock(BundleContext.class);\n    private Optional<Exception> exception = Optional.empty();\n    private Optional<String> temporaryDirectoryPath = Optional.empty();\n    private SqliteProviderActivator activator = new SqliteProviderActivator();\n\n    private void givenBundleStorageAreaPath(String path) {\n        Mockito.when(bundleContext.getDataFile(\"\")).thenReturn(new File(path));\n    }\n\n    private void givenNoBundleStorageArea() {\n        Mockito.when(bundleContext.getDataFile(\"\")).thenReturn(null);\n    }\n\n    private void givenSystemProperty(final String key, final String value) {\n        System.setProperty(key, value);\n    }\n\n    private void givenNoSystemPropertyValue(final String key) {\n        System.clearProperty(key);\n    }\n\n    private void givenStartedActivator() {\n        whenActivatorIsStarted();\n        thenNoExceptionIsThrown();\n    }\n\n    private void whenActivatorIsStarted() {\n        try {\n            this.exception = Optional.empty();\n            activator.start(bundleContext);\n        } catch (Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void whenActivatorIsStopped() {\n        try {\n            this.exception = Optional.empty();\n            activator.stop(bundleContext);\n        } catch (Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void thenSystemPropertyValueIs(final String key, final String value) {\n        assertEquals(value, System.getProperty(key));\n    }\n\n    private void thenNoExceptionIsThrown() {\n        assertEquals(Optional.empty(), this.exception);\n    }\n\n    private String temporaryDirectoryPath() {\n        if (temporaryDirectoryPath.isPresent()) {\n            return temporaryDirectoryPath.get();\n        }\n\n        try {\n            final String newPath = Files.createTempDirectory(null).toFile().getAbsolutePath();\n            this.temporaryDirectoryPath = Optional.of(newPath);\n            return newPath;\n        } catch (final Exception e) {\n            fail(\"Cannot create temporary directory\");\n            throw new IllegalStateException(\"unreachable\");\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.block.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.driver.block.test\nBundle-SymbolicName: org.eclipse.kura.driver.block.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\"\nFragment-Host: org.eclipse.kura.driver.block;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.block.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.block.test/build.properties",
    "content": "bin.includes = .,\\\n               META-INF/,\\\n               about.html\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.block.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Eurotech\n     \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.driver.block.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/AbstractBlockDriverTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.function.BiFunction;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.channel.ChannelFlag;\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.driver.ChannelDescriptor;\nimport org.eclipse.kura.driver.Driver.ConnectionException;\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.driver.block.BlockFactory;\nimport org.eclipse.kura.driver.block.ProhibitedBlock;\nimport org.eclipse.kura.driver.block.task.AbstractBlockDriver;\nimport org.eclipse.kura.driver.block.task.AbstractBlockDriver.Pair;\nimport org.eclipse.kura.driver.block.task.BlockTask;\nimport org.eclipse.kura.driver.block.task.BlockTaskAggregator;\nimport org.eclipse.kura.driver.block.task.Mode;\nimport org.eclipse.kura.driver.block.task.ToplevelBlockTask;\nimport org.eclipse.kura.driver.block.task.UpdateBlockTask;\nimport org.eclipse.kura.type.DataType;\nimport org.eclipse.kura.type.TypedValues;\nimport org.junit.Test;\n\npublic class AbstractBlockDriverTest {\n\n    @Test\n    public void shouldAggregateTasksFromSameDomain() throws ConnectionException {\n        List<Pair<Integer, BlockTask>> tasks = testTasks(1, Mode.READ, 0, 3, 3, 5, 5, 10);\n        List<ChannelRecord> records = getRecords(tasks);\n        TestBlockFactory factory = new TestBlockFactory(Mode.READ, 0, 10);\n        TestDriver driver = new TestDriver().withTasks(tasks).withBlockFactoryProvider((domain, mode) -> factory);\n        driver.read(records);\n        assertEquals(1, factory.timesCalled);\n        for (ChannelRecord record : records) {\n            assertEquals(true, record.getValue().getValue());\n        }\n    }\n\n    @Test\n    public void shouldSupportPreparedRead() throws ConnectionException, KuraException {\n        List<Pair<Integer, BlockTask>> tasks = testTasks(1, Mode.READ, 0, 3, 3, 5, 5, 10);\n        List<ChannelRecord> records = getRecords(tasks);\n        TestBlockFactory factory = new TestBlockFactory(Mode.READ, 0, 10);\n        TestDriver driver = new TestDriver().withTasks(tasks).withBlockFactoryProvider((domain, mode) -> factory);\n        driver.prepareRead(records).execute();\n        assertEquals(1, factory.timesCalled);\n        for (ChannelRecord record : records) {\n            assertEquals(true, record.getValue().getValue());\n        }\n    }\n\n    @Test\n    public void shouldSupportWrite() throws ConnectionException, KuraException {\n        List<Pair<Integer, BlockTask>> tasks = testTasks(1, Mode.WRITE, 0, 3, 3, 5, 5, 10);\n        List<ChannelRecord> records = getRecords(tasks);\n        TestBlockFactory factory = new TestBlockFactory(Mode.WRITE, 0, 10);\n        TestDriver driver = new TestDriver().withTasks(tasks).withBlockFactoryProvider((domain, mode) -> factory);\n        driver.write(records);\n        assertEquals(1, factory.timesCalled);\n        for (ChannelRecord record : records) {\n            assertEquals(true, record.getValue().getValue());\n        }\n    }\n\n    @Test\n    public void shouldReportUnfeasibleProblemOnRead() throws ConnectionException {\n        List<Pair<Integer, BlockTask>> tasks = testTasks(1, Mode.READ, 0, 4, 4, 6);\n        List<ChannelRecord> records = getRecords(tasks);\n        TestBlockFactory factory = new TestBlockFactory(Mode.READ, 0, 10);\n        TestDriver driver = new TestDriver().withTasks(tasks).withBlockFactoryProvider((domain, mode) -> factory)\n                .beforeAggregation((aggregator) -> aggregator.addBlock(new ProhibitedBlock(5, 10)));\n        driver.read(records);\n        assertEquals(1, factory.timesCalled);\n        for (ChannelRecord record : records) {\n            assertEquals(ChannelFlag.FAILURE, record.getChannelStatus().getChannelFlag());\n        }\n    }\n\n    @Test\n    public void shouldReportUnfeasibleProblemOnPrepareRead() throws ConnectionException, KuraException {\n        List<Pair<Integer, BlockTask>> tasks = testTasks(1, Mode.READ, 0, 4, 4, 6);\n        List<ChannelRecord> records = getRecords(tasks);\n        TestBlockFactory factory = new TestBlockFactory(Mode.READ, 0, 10);\n        TestDriver driver = new TestDriver().withTasks(tasks).withBlockFactoryProvider((domain, mode) -> factory)\n                .beforeAggregation((aggregator) -> aggregator.addBlock(new ProhibitedBlock(5, 10)));\n        driver.prepareRead(records).execute();\n        assertEquals(1, factory.timesCalled);\n        for (ChannelRecord record : records) {\n            assertEquals(ChannelFlag.FAILURE, record.getChannelStatus().getChannelFlag());\n        }\n    }\n\n    @Test\n    public void shouldReportUnfeasibleProblemOnWrite() throws ConnectionException, KuraException {\n        List<Pair<Integer, BlockTask>> tasks = testTasks(1, Mode.WRITE, 0, 4, 4, 6);\n        List<ChannelRecord> records = getRecords(tasks);\n        TestBlockFactory factory = new TestBlockFactory(Mode.WRITE, 0, 10);\n        TestDriver driver = new TestDriver().withTasks(tasks).withBlockFactoryProvider((domain, mode) -> factory)\n                .beforeAggregation((aggregator) -> aggregator.addBlock(new ProhibitedBlock(5, 10)));\n        driver.write(records);\n        assertEquals(1, factory.timesCalled);\n        for (ChannelRecord record : records) {\n            assertEquals(ChannelFlag.FAILURE, record.getChannelStatus().getChannelFlag());\n        }\n    }\n\n    @Test\n    public void shouldSupportMinimumGapSize() throws ConnectionException {\n        List<Pair<Integer, BlockTask>> tasks = testTasks(1, Mode.READ, 0, 3, 5, 7, 9, 12);\n        List<ChannelRecord> records = getRecords(tasks);\n        TestBlockFactory factory = new TestBlockFactory(Mode.READ, 0, 12);\n        TestDriver driver = new TestDriver().withTasks(tasks).withBlockFactoryProvider((domain, mode) -> factory)\n                .withMinimumGapSize(3);\n        driver.read(records);\n        assertEquals(1, factory.timesCalled);\n        for (ChannelRecord record : records) {\n            assertEquals(true, record.getValue().getValue());\n        }\n    }\n\n    @Test\n    public void shouldNotAggregateTasksFromDifferentDomains() throws ConnectionException {\n        List<Pair<Integer, BlockTask>> tasks = new ArrayList<>();\n        tasks.addAll(testTasks(1, Mode.READ, 0, 3, 3, 5));\n        tasks.addAll(testTasks(2, Mode.READ, 4, 6, 6, 10));\n        List<ChannelRecord> records = getRecords(tasks);\n        TestBlockFactory factory1 = new TestBlockFactory(Mode.READ, 0, 5);\n        TestBlockFactory factory2 = new TestBlockFactory(Mode.READ, 4, 10);\n        TestDriver driver = new TestDriver().withTasks(tasks).withBlockFactoryProvider((domain, mode) -> {\n            if (domain == 1) {\n                return factory1;\n            } else if (domain == 2) {\n                return factory2;\n            }\n            return null;\n        }).afterAggregation((result) -> assertEquals(2, result.size()));\n        driver.read(records);\n        assertEquals(1, factory1.timesCalled);\n        assertEquals(1, factory2.timesCalled);\n        for (ChannelRecord record : records) {\n            assertEquals(true, record.getValue().getValue());\n        }\n    }\n\n    @Test\n    public void shouldSupportUpdateTasks() throws ConnectionException {\n        List<Pair<Integer, BlockTask>> tasks = testTasks(1, Mode.UPDATE, 0, 3, 3, 5, 5, 10);\n        List<ChannelRecord> records = getRecords(tasks);\n        TestBlockFactory readFactory = new TestBlockFactory(Mode.READ, 0, 10);\n        TestBlockFactory writeFactory = new TestBlockFactory(Mode.WRITE, 0, 10);\n        TestDriver driver = new TestDriver().withTasks(tasks).withBlockFactoryProvider((domain, mode) -> {\n            if (mode == Mode.READ) {\n                return readFactory;\n            } else if (mode == Mode.WRITE) {\n                return writeFactory;\n            }\n            return null;\n        });\n        driver.write(records);\n        assertEquals(1, readFactory.timesCalled);\n        assertEquals(1, writeFactory.timesCalled);\n        for (ChannelRecord record : records) {\n            assertEquals(true, record.getValue().getValue());\n        }\n    }\n\n    private List<Pair<Integer, BlockTask>> testTasks(int domain, Mode mode, int... ranges) {\n        assertTrue(ranges.length % 2 == 0);\n        List<Pair<Integer, BlockTask>> result = new ArrayList<>(ranges.length / 2);\n        for (int i = 0; i < ranges.length; i += 2) {\n            result.add(new Pair<>(domain, new TestTask(ranges[i], ranges[i + 1], mode)));\n        }\n        return result;\n    }\n\n    private List<ChannelRecord> getRecords(List<Pair<Integer, BlockTask>> tasks) {\n        return tasks.stream().map(pair -> ((TestTask) pair.getSecond()).getRecord()).collect(Collectors.toList());\n    }\n\n    private class TestBlockFactory implements BlockFactory<ToplevelBlockTask> {\n\n        private final int expectedStart;\n        private final int expectedEnd;\n        private int timesCalled;\n        private final Mode mode;\n\n        public TestBlockFactory(Mode mode, int expectedStart, int expectedEnd) {\n            this.expectedStart = expectedStart;\n            this.expectedEnd = expectedEnd;\n            this.mode = mode;\n        }\n\n        @Override\n        public ToplevelBlockTask build(int start, int end) {\n            this.timesCalled++;\n            return new ToplevelBlockTask(start, end, this.mode) {\n\n                @Override\n                public void processBuffer() throws IOException {\n                    assertEquals(TestBlockFactory.this.expectedStart, getStart());\n                    assertEquals(TestBlockFactory.this.expectedEnd, getEnd());\n                }\n\n                @Override\n                public Buffer getBuffer() {\n                    return null;\n                }\n            };\n        }\n\n    }\n\n    private class TestTask extends UpdateBlockTask {\n\n        public TestTask(int start, int end, Mode mode) {\n            super(ChannelRecord.createReadRecord(\"test\", DataType.BOOLEAN), start, end, mode);\n        }\n\n        public ChannelRecord getRecord() {\n            return this.record;\n        }\n\n        @Override\n        protected void runRead() {\n            final ToplevelBlockTask parent = getParent();\n            assertNotNull(parent);\n            assertTrue(parent.getStart() <= getStart());\n            assertTrue(parent.getEnd() >= getEnd());\n            this.record.setValue(TypedValues.newBooleanValue(true));\n        }\n\n        @Override\n        protected void runWrite() {\n            final ToplevelBlockTask parent = getParent();\n            assertNotNull(parent);\n            assertTrue(parent.getStart() <= getStart());\n            assertTrue(parent.getEnd() >= getEnd());\n            this.record.setValue(TypedValues.newBooleanValue(true));\n        }\n\n        @Override\n        protected void runUpdate(ToplevelBlockTask write, ToplevelBlockTask read) {\n            assertTrue(read != write);\n            assertTrue(read.getStart() <= getStart());\n            assertTrue(read.getEnd() >= getEnd());\n            assertTrue(write.getStart() <= getStart());\n            assertTrue(write.getEnd() >= getEnd());\n            this.record.setValue(TypedValues.newBooleanValue(true));\n        }\n\n    }\n\n    private class TestDriver extends AbstractBlockDriver<Integer> {\n\n        private List<Pair<Integer, BlockTask>> tasks;\n        private BiFunction<Integer, Mode, BlockFactory<ToplevelBlockTask>> blockFactoryProvider;\n        private Consumer<List<BlockTask>> afterAggregation;\n        private Consumer<BlockTaskAggregator> beforeAggregation;\n        private int minimumGapSize;\n\n        public TestDriver withTasks(List<Pair<Integer, BlockTask>> tasks) {\n            this.tasks = tasks;\n            return this;\n        }\n\n        public TestDriver withMinimumGapSize(int minimumGapSize) {\n            this.minimumGapSize = minimumGapSize;\n            return this;\n        }\n\n        public TestDriver withBlockFactoryProvider(\n                BiFunction<Integer, Mode, BlockFactory<ToplevelBlockTask>> blockFactoryProvider) {\n            this.blockFactoryProvider = blockFactoryProvider;\n            return this;\n        }\n\n        public TestDriver afterAggregation(Consumer<List<BlockTask>> afterAggregation) {\n            this.afterAggregation = afterAggregation;\n            return this;\n        }\n\n        public TestDriver beforeAggregation(Consumer<BlockTaskAggregator> beforeAggregation) {\n            this.beforeAggregation = beforeAggregation;\n            return this;\n        }\n\n        @Override\n        protected int getReadMinimumGapSizeForDomain(Integer domain) {\n            return this.minimumGapSize;\n        }\n\n        @Override\n        protected void beforeAggregation(Integer domain, Mode mode, BlockTaskAggregator aggregator) {\n            if (this.beforeAggregation != null) {\n                this.beforeAggregation.accept(aggregator);\n            }\n        }\n\n        @Override\n        protected List<BlockTask> optimize(List<ChannelRecord> records, Mode mode) throws KuraException {\n            List<BlockTask> result = super.optimize(records, mode);\n            if (this.afterAggregation != null) {\n                this.afterAggregation.accept(result);\n            }\n            return result;\n        }\n\n        @Override\n        public void connect() throws ConnectionException {\n        }\n\n        @Override\n        public void disconnect() throws ConnectionException {\n        }\n\n        @Override\n        public ChannelDescriptor getChannelDescriptor() {\n            return null;\n        }\n\n        @Override\n        protected BlockFactory<ToplevelBlockTask> getTaskFactoryForDomain(Integer domain, Mode mode) {\n            return this.blockFactoryProvider.apply(domain, mode);\n        }\n\n        @Override\n        protected Stream<Pair<Integer, BlockTask>> toTasks(List<ChannelRecord> records, Mode mode) {\n            return this.tasks.stream();\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BinaryDataTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.test;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\n\nimport java.math.BigInteger;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.function.BiConsumer;\nimport java.util.function.BiFunction;\nimport java.util.function.Function;\n\nimport org.eclipse.kura.driver.binary.BinaryData;\nimport org.eclipse.kura.driver.binary.BinaryDataTypes;\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.driver.binary.ByteArray;\nimport org.eclipse.kura.driver.binary.ByteArrayBuffer;\nimport org.eclipse.kura.driver.binary.Endianness;\nimport org.eclipse.kura.driver.binary.UnsignedIntegerLE;\nimport org.eclipse.kura.driver.binary.adapter.GainOffset;\nimport org.eclipse.kura.driver.binary.adapter.StringData;\nimport org.eclipse.kura.driver.binary.adapter.ToBoolean;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class BinaryDataTest {\n\n    @Test\n    public void shouldSupportUInt8() {\n        testReadWrite(BinaryDataTypes.UINT8, (endianness, size) -> new byte[] { (byte) 0xab }, 171);\n    }\n\n    @Test\n    public void shouldSupportUInt16() {\n        final byte[] testBuf = new byte[] { (byte) 0xa3, (byte) 0xc4 };\n        testReadWrite(BinaryDataTypes.UINT16_LE, (endianness, size) -> testBuf, (Integer) 0xc4a3);\n        testReadWrite(BinaryDataTypes.UINT16_BE, (endianness, size) -> testBuf, (Integer) 0xa3c4);\n    }\n\n    @Test\n    public void shouldSupportUInt32() {\n        final byte[] testBuf = new byte[] { (byte) 0xa3, (byte) 0xc4, (byte) 0x45, (byte) 0x83 };\n        testReadWrite(BinaryDataTypes.UINT32_LE, (endianness, size) -> testBuf, 0x8345c4a3L);\n        testReadWrite(BinaryDataTypes.UINT32_BE, (endianness, size) -> testBuf, 0xa3c44583L);\n    }\n\n    @Test\n    public void shouldSupportInt8() {\n        testReadWrite(BinaryDataTypes.INT8, (endianness, size) -> new byte[] { (byte) 0xab }, -85);\n    }\n\n    @Test\n    public void shouldSupportInt16() {\n        final byte[] testBuf = new byte[] { (byte) 0xa3, (byte) 0xc4 };\n        testReadWrite(BinaryDataTypes.INT16_LE, (endianness, size) -> testBuf, -15197);\n        testReadWrite(BinaryDataTypes.INT16_BE, (endianness, size) -> testBuf, -23612);\n    }\n\n    @Test\n    public void shouldSupportInt32() {\n        final byte[] testBuf = new byte[] { (byte) 0xa3, (byte) 0xc4, (byte) 0x45, (byte) 0x83 };\n        testReadWrite(BinaryDataTypes.INT32_LE, (endianness, size) -> testBuf, -2092579677);\n        testReadWrite(BinaryDataTypes.INT32_BE, (endianness, size) -> testBuf, -1547418237);\n    }\n\n    @Test\n    public void shouldSupportInt64() {\n        final byte[] testBuf = new byte[] { (byte) 0xa3, (byte) 0xc4, (byte) 0x45, (byte) 0x83, (byte) 0xa3,\n                (byte) 0xc4, (byte) 0x45, (byte) 0x83 };\n        testReadWrite(BinaryDataTypes.INT64_LE, (endianness, size) -> testBuf, -8987561274786855773L);\n        testReadWrite(BinaryDataTypes.INT64_BE, (endianness, size) -> testBuf, -6646110718401428093L);\n    }\n\n    @Test\n    public void shouldSupportFloat() {\n        final byte[] testBuf = new byte[] { (byte) 0xa3, (byte) 0xc4, (byte) 0x45, (byte) 0x83 };\n        testReadWrite(BinaryDataTypes.FLOAT_LE, (endianness, size) -> testBuf, (float) -5.8118825e-37);\n        testReadWrite(BinaryDataTypes.FLOAT_BE, (endianness, size) -> testBuf, (float) -2.1279802e-17);\n    }\n\n    @Test\n    public void shouldSupportDouble() {\n        final byte[] testBuf = new byte[] { (byte) 0xa3, (byte) 0xc4, (byte) 0x45, (byte) 0x83, (byte) 0xa3,\n                (byte) 0xc4, (byte) 0x45, (byte) 0x83 };\n        testReadWrite(BinaryDataTypes.DOUBLE_LE, (endianness, size) -> testBuf, -6.816715214851188e-293);\n        testReadWrite(BinaryDataTypes.DOUBLE_BE, (endianness, size) -> testBuf, -2.178907098281569e-136);\n    }\n\n    @Test\n    public void shouldSupportSignedIntegerMax() {\n        testReadWrite(BinaryDataTypes.INT8, BinaryDataTest::createSignedMax, (Integer) (int) Byte.MAX_VALUE);\n        testReadWrite(BinaryDataTypes.INT16_BE, BinaryDataTest::createSignedMax, (Integer) (int) Short.MAX_VALUE);\n        testReadWrite(BinaryDataTypes.INT16_LE, BinaryDataTest::createSignedMax, (Integer) (int) Short.MAX_VALUE);\n        testReadWrite(BinaryDataTypes.INT32_BE, BinaryDataTest::createSignedMax, (Integer) Integer.MAX_VALUE);\n        testReadWrite(BinaryDataTypes.INT32_LE, BinaryDataTest::createSignedMax, (Integer) Integer.MAX_VALUE);\n        testReadWrite(BinaryDataTypes.INT64_BE, BinaryDataTest::createSignedMax, (Long) Long.MAX_VALUE);\n        testReadWrite(BinaryDataTypes.INT64_LE, BinaryDataTest::createSignedMax, (Long) Long.MAX_VALUE);\n    }\n\n    @Test\n    public void shouldSupportSignedIntegerMin() {\n        testReadWrite(BinaryDataTypes.INT8, BinaryDataTest::createSignedMin, (Integer) (int) Byte.MIN_VALUE);\n        testReadWrite(BinaryDataTypes.INT16_BE, BinaryDataTest::createSignedMin, (Integer) (int) Short.MIN_VALUE);\n        testReadWrite(BinaryDataTypes.INT16_LE, BinaryDataTest::createSignedMin, (Integer) (int) Short.MIN_VALUE);\n        testReadWrite(BinaryDataTypes.INT32_BE, BinaryDataTest::createSignedMin, (Integer) Integer.MIN_VALUE);\n        testReadWrite(BinaryDataTypes.INT32_LE, BinaryDataTest::createSignedMin, (Integer) Integer.MIN_VALUE);\n        testReadWrite(BinaryDataTypes.INT64_BE, BinaryDataTest::createSignedMin, (Long) Long.MIN_VALUE);\n        testReadWrite(BinaryDataTypes.INT64_LE, BinaryDataTest::createSignedMin, (Long) Long.MIN_VALUE);\n    }\n\n    @Test\n    public void shouldSupportUnsignedIntegerMax() {\n        testReadWrite(BinaryDataTypes.UINT8, BinaryDataTest::createUnsignedMax, 0xff);\n        testReadWrite(BinaryDataTypes.UINT16_BE, BinaryDataTest::createUnsignedMax, 0x0000ffff);\n        testReadWrite(BinaryDataTypes.UINT16_LE, BinaryDataTest::createUnsignedMax, 0x0000ffff);\n        testReadWrite(BinaryDataTypes.UINT32_BE, BinaryDataTest::createUnsignedMax, 0xffffffffL);\n        testReadWrite(BinaryDataTypes.UINT32_LE, BinaryDataTest::createUnsignedMax, 0xffffffffL);\n    }\n\n    @Test\n    public void shouldSupportUnsignedIntegerMin() {\n        testReadWrite(BinaryDataTypes.UINT8, BinaryDataTest::createUnsignedMin, 0);\n        testReadWrite(BinaryDataTypes.UINT16_BE, BinaryDataTest::createUnsignedMin, 0);\n        testReadWrite(BinaryDataTypes.UINT16_LE, BinaryDataTest::createUnsignedMin, 0);\n        testReadWrite(BinaryDataTypes.UINT32_BE, BinaryDataTest::createUnsignedMin, 0L);\n        testReadWrite(BinaryDataTypes.UINT32_LE, BinaryDataTest::createUnsignedMin, 0L);\n    }\n\n    @Test\n    public void shouldSupportFloatMax() {\n        testReadWrite(BinaryDataTypes.FLOAT_BE, BinaryDataTest::createFloatMax, Float.MAX_VALUE);\n        testReadWrite(BinaryDataTypes.FLOAT_LE, BinaryDataTest::createFloatMax, Float.MAX_VALUE);\n    }\n\n    @Test\n    public void shouldSupportFloatPositiveMin() {\n        testReadWrite(BinaryDataTypes.FLOAT_BE, BinaryDataTest::createFloatPositiveMin, Float.MIN_VALUE);\n        testReadWrite(BinaryDataTypes.FLOAT_LE, BinaryDataTest::createFloatPositiveMin, Float.MIN_VALUE);\n    }\n\n    @Test\n    public void shouldSupportDoubleMax() {\n        testReadWrite(BinaryDataTypes.DOUBLE_BE, BinaryDataTest::createDoubleMax, Double.MAX_VALUE);\n        testReadWrite(BinaryDataTypes.DOUBLE_LE, BinaryDataTest::createDoubleMax, Double.MAX_VALUE);\n    }\n\n    @Test\n    public void shouldSupportDoublePositiveMin() {\n        testReadWrite(BinaryDataTypes.DOUBLE_BE, BinaryDataTest::createFloatPositiveMin, Double.MIN_VALUE);\n        testReadWrite(BinaryDataTypes.DOUBLE_LE, BinaryDataTest::createFloatPositiveMin, Double.MIN_VALUE);\n    }\n\n    @Test\n    public void shouldSupportUnsignedInteger() {\n        final byte[] testBuf = new byte[] { 1, 2, 3, 4 };\n        testRead(new UnsignedIntegerLE(32, 0), (endiannes, size) -> testBuf, BigInteger.valueOf(67305985));\n\n        final byte[] testBuf2 = new byte[] { (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0xAA,\n                (byte) 0xAA, (byte) 0xAA, (byte) 0xAA };\n        testRead(new UnsignedIntegerLE(3, 0), (endiannes, size) -> testBuf2, BigInteger.valueOf(2));\n        testRead(new UnsignedIntegerLE(3, 3), (endiannes, size) -> testBuf2, BigInteger.valueOf(5));\n        testRead(new UnsignedIntegerLE(6, 2), (endiannes, size) -> testBuf2, BigInteger.valueOf(42));\n        testRead(new UnsignedIntegerLE(2, 7), (endiannes, size) -> testBuf2, BigInteger.valueOf(1));\n        testRead(new UnsignedIntegerLE(12, 7), (endiannes, size) -> testBuf2, BigInteger.valueOf(1365));\n        testRead(new UnsignedIntegerLE(17, 7), (endiannes, size) -> testBuf2, BigInteger.valueOf(87381));\n    }\n\n    @Test\n    public void shouldSupportByteArray() {\n        final byte[] testBuf = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };\n        testRead(new ByteArray(testBuf.length), (size, endianness) -> testBuf, testBuf, Assert::assertArrayEquals);\n        testRead(new ByteArray(4), (size, endianness) -> testBuf, new byte[] { 1, 2, 3, 4 }, Assert::assertArrayEquals);\n        testRead(new ByteArray(40), (size, endianness) -> testBuf, testBuf, Assert::assertArrayEquals);\n    }\n\n    @Test\n    public void shouldSupportGainOffset() {\n        testAdapterRead(a -> new GainOffset(a, 1.0f, 0.0f), (byte) 10, 10.0d);\n        testAdapterRead(a -> new GainOffset(a, 1.0f, 0.0f), (short) 10, 10.0d);\n        testAdapterRead(a -> new GainOffset(a, 1.0f, 0.0f), (int) 10, 10.0d);\n        testAdapterRead(a -> new GainOffset(a, 1.0f, 0.0f), (long) 10, 10.0d);\n        testAdapterRead(a -> new GainOffset(a, 1.0f, 0.0f), (short) 10, 10.0d);\n        testAdapterRead(a -> new GainOffset(a, 1.0f, 0.0f), 12.5f, 12.5d);\n        testAdapterRead(a -> new GainOffset(a, 1.0f, 0.0f), 10.123d, 10.123d);\n        testAdapterRead(a -> new GainOffset(a, 1.0f, 0.0f), BigInteger.valueOf(10), 10.0d);\n\n        testAdapterWrite(a -> new GainOffset(a, 1.0f, 0.0f), 10.0d, (short) 10);\n        testAdapterWrite(a -> new GainOffset(a, 1.0f, 0.0f), 10.0d, (short) 10);\n        testAdapterWrite(a -> new GainOffset(a, 1.0f, 0.0f), 10.0d, (int) 10);\n        testAdapterWrite(a -> new GainOffset(a, 1.0f, 0.0f), 10.0d, (long) 10);\n        testAdapterWrite(a -> new GainOffset(a, 1.0f, 0.0f), 10.0d, (short) 10);\n        testAdapterWrite(a -> new GainOffset(a, 1.0f, 0.0f), 10.0d, (float) 10);\n        testAdapterWrite(a -> new GainOffset(a, 1.0f, 0.0f), 10.0d, (double) 10);\n        testAdapterWrite(a -> new GainOffset(a, 1.0f, 0.0f), 10.0d, BigInteger.valueOf(10));\n\n        testAdapterRead(a -> new GainOffset(a, 2.0f, 0.0f), (byte) 10, 20.0d);\n        testAdapterRead(a -> new GainOffset(a, 3.0f, 0.0f), (short) 10, 30.0d);\n        testAdapterRead(a -> new GainOffset(a, 5.5f, 0.0f), (int) 10, 55.0d);\n        testAdapterRead(a -> new GainOffset(a, 15.0f, 0.0f), (long) 10, 150.0d);\n        testAdapterRead(a -> new GainOffset(a, -1.5f, 0.0f), (short) 10, -15.0d);\n        testAdapterRead(a -> new GainOffset(a, -2.0f, 0.0f), (float) 10, -20.0d);\n        testAdapterRead(a -> new GainOffset(a, -5.0f, 0.0f), (double) 10, -50.0d);\n        testAdapterRead(a -> new GainOffset(a, -11.0f, 0.0f), BigInteger.valueOf(10), -110.0d);\n\n        testAdapterRead(a -> new GainOffset(a, 2.0f, 1.0f), (byte) 10, (double) (20 + 1));\n        testAdapterRead(a -> new GainOffset(a, 3.0f, 4.0f), (short) 10, (double) (30 + 4));\n        testAdapterRead(a -> new GainOffset(a, 5.0f, -2.0f), (int) 10, (double) (50 - 2));\n        testAdapterRead(a -> new GainOffset(a, 15.0f, -5.0f), (long) 10, (double) (150 - 5));\n        testAdapterRead(a -> new GainOffset(a, -1.0f, 10.0f), (short) 10, (double) (-10 + 10));\n        testAdapterRead(a -> new GainOffset(a, -2.0f, 54.0f), (float) 10, (double) (-20 + 54));\n        testAdapterRead(a -> new GainOffset(a, -5.0f, 1.0f), (double) 10, (double) (-50 + 1));\n        testAdapterRead(a -> new GainOffset(a, -11.0f, 22.0f), BigInteger.valueOf(10), (double) (-110 + 22));\n\n        testAdapterWrite(a -> new GainOffset(a, 2.0f, 0.0f), 10.0d, (byte) 20);\n        testAdapterWrite(a -> new GainOffset(a, 3.0f, 0.0f), 10.0d, (short) 30);\n        testAdapterWrite(a -> new GainOffset(a, 5.0f, 0.0f), 10.0d, (int) 50);\n        testAdapterWrite(a -> new GainOffset(a, 15.0f, 0.0f), 10.0d, (long) 150);\n        testAdapterWrite(a -> new GainOffset(a, -1.0f, 0.0f), 10.0d, (short) -10);\n        testAdapterWrite(a -> new GainOffset(a, -2.0f, 0.0f), 10.0d, (float) -20);\n        testAdapterWrite(a -> new GainOffset(a, -5.0f, 0.0f), 10.0d, (double) -50);\n        testAdapterWrite(a -> new GainOffset(a, -11.0f, 0.0f), 10.0d, BigInteger.valueOf(-110));\n\n        testAdapterWrite(a -> new GainOffset(a, 2.0f, 1.0f), 10.0d, (byte) (20 + 1));\n        testAdapterWrite(a -> new GainOffset(a, 3.0f, 4.0f), 10.0d, (short) (30 + 4));\n        testAdapterWrite(a -> new GainOffset(a, 5.0f, -2.0f), 10.0d, (int) (50 - 2));\n        testAdapterWrite(a -> new GainOffset(a, 15.0f, -5.0f), 10.0d, (long) (150 - 5));\n        testAdapterWrite(a -> new GainOffset(a, -1.0f, 10.0f), 10.0d, (short) (-10 + 10));\n        testAdapterWrite(a -> new GainOffset(a, -2.0f, 54.0f), 10.0d, (float) (-20 + 54));\n        testAdapterWrite(a -> new GainOffset(a, -5.0f, 1.0f), 10.0d, (double) (-50 + 1));\n        testAdapterWrite(a -> new GainOffset(a, -11.0f, 22.0f), 10.0d, BigInteger.valueOf(-110 + 22));\n    }\n\n    @Test\n    public void shouldSupportStringData() {\n        testAdapterRead(a -> new StringData(a, StandardCharsets.US_ASCII), new byte[] { 0x74, 0x65, 0x73, 0x74 },\n                \"test\");\n        testAdapterWrite(a -> new StringData(a, StandardCharsets.US_ASCII), \"test\",\n                new byte[] { 0x74, 0x65, 0x73, 0x74 }, Assert::assertArrayEquals);\n    }\n\n    @Test\n    public void shouldSupportToBooolean() {\n        testAdapterRead(ToBoolean::new, (byte) 10, true);\n        testAdapterRead(ToBoolean::new, (short) 10, true);\n        testAdapterRead(ToBoolean::new, (int) 10, true);\n        testAdapterRead(ToBoolean::new, (long) 10, true);\n        testAdapterRead(ToBoolean::new, (short) 10, true);\n        testAdapterRead(ToBoolean::new, (float) 10, true);\n        testAdapterRead(ToBoolean::new, (double) 10, true);\n        testAdapterRead(ToBoolean::new, BigInteger.valueOf(10), true);\n\n        testAdapterRead(ToBoolean::new, (byte) 0, false);\n        testAdapterRead(ToBoolean::new, (short) 0, false);\n        testAdapterRead(ToBoolean::new, (int) 0, false);\n        testAdapterRead(ToBoolean::new, (long) 0, false);\n        testAdapterRead(ToBoolean::new, (short) 0, false);\n        testAdapterRead(ToBoolean::new, (float) 0, false);\n        testAdapterRead(ToBoolean::new, (double) 0, false);\n        testAdapterRead(ToBoolean::new, BigInteger.valueOf(0), false);\n    }\n\n    private static void apply(byte[] data, Endianness endianness, BiFunction<byte[], Integer, Byte> func) {\n        int start;\n        int inc;\n        int end;\n        if (endianness == Endianness.BIG_ENDIAN) {\n            start = 0;\n            inc = 1;\n            end = data.length;\n        } else {\n            start = data.length - 1;\n            inc = -1;\n            end = -1;\n        }\n        int j = 0;\n        for (int i = start; i != end; i += inc) {\n            data[i] = func.apply(data, j);\n            j++;\n        }\n    }\n\n    private static byte[] createSignedMax(Endianness endianness, int size) {\n        byte[] result = new byte[size];\n        apply(result, endianness, (data, i) -> {\n            return (i == 0) ? (byte) 0x7f : (byte) 0xff;\n        });\n\n        return result;\n    }\n\n    private static byte[] createSignedMin(Endianness endianness, int size) {\n        byte[] result = new byte[size];\n        apply(result, endianness, (data, i) -> {\n            return (i == 0) ? (byte) 0x80 : (byte) 0;\n        });\n        return result;\n    }\n\n    private static byte[] createUnsignedMax(Endianness endianness, int size) {\n        byte[] result = new byte[size];\n        Arrays.fill(result, (byte) 0xff);\n        return result;\n    }\n\n    private static byte[] createUnsignedMin(Endianness endianness, int size) {\n        return new byte[size];\n    }\n\n    private static byte[] createFloatMax(Endianness endianness, int size) {\n        byte[] result = new byte[size];\n        apply(result, endianness, (data, i) -> {\n            if (i == 0) {\n                return (byte) 0x7f;\n            }\n            if (i == 1) {\n                return (byte) 0x7f;\n            }\n            return (byte) 0xff;\n        });\n        return result;\n    }\n\n    private static byte[] createFloatPositiveMin(Endianness endianness, int size) {\n        byte[] result = new byte[size];\n        apply(result, endianness, (data, i) -> {\n            return (i == data.length - 1) ? (byte) 0x01 : (byte) 0x00;\n        });\n        return result;\n    }\n\n    private static byte[] createDoubleMax(Endianness endianness, int size) {\n        byte[] result = new byte[size];\n        apply(result, endianness, (data, i) -> {\n            if (i == 0) {\n                return (byte) 0x7f;\n            }\n            if (i == 1) {\n                return (byte) 0xef;\n            }\n            return (byte) 0xff;\n        });\n        return result;\n    }\n\n    private <T> void testRead(BinaryData<T> data, BiFunction<Endianness, Integer, byte[]> bufferProvider,\n            T expectedValue) {\n        testRead(data, bufferProvider, expectedValue, Assert::assertEquals);\n    }\n\n    private <T> void testRead(BinaryData<T> data, BiFunction<Endianness, Integer, byte[]> bufferProvider,\n            T expectedValue, final BiConsumer<T, T> validator) {\n        ByteArrayBuffer testBuf = new ByteArrayBuffer(bufferProvider.apply(data.getEndianness(), data.getSize()));\n        validator.accept(expectedValue, data.read(testBuf, 0));\n    }\n\n    private <T> void testReadWrite(BinaryData<T> data, BiFunction<Endianness, Integer, byte[]> bufferProvider,\n            T expectedValue) {\n        testReadWrite(data, bufferProvider, expectedValue, Assert::assertEquals);\n    }\n\n    private <T> void testReadWrite(BinaryData<T> data, BiFunction<Endianness, Integer, byte[]> bufferProvider,\n            T expectedValue, final BiConsumer<T, T> readValidator) {\n        ByteArrayBuffer testBuf = new ByteArrayBuffer(bufferProvider.apply(data.getEndianness(), data.getSize()));\n        readValidator.accept(expectedValue, data.read(testBuf, 0));\n        ByteArrayBuffer writeBuf = new ByteArrayBuffer(new byte[data.getSize()]);\n        data.write(writeBuf, 0, expectedValue);\n        assertArrayEquals(testBuf.getBackingArray(), writeBuf.getBackingArray());\n    }\n\n    private <T, U> void testAdapterRead(final Function<BinaryData<T>, BinaryData<U>> supplier, final T suppliedValue,\n            final U expectedValue) {\n        testAdapterRead(supplier, suppliedValue, expectedValue, Assert::assertEquals);\n    }\n\n    private <T, U> void testAdapterWrite(final Function<BinaryData<T>, BinaryData<U>> supplier, final U writtenValue,\n            final T forwardedValue) {\n        testAdapterWrite(supplier, writtenValue, forwardedValue, Assert::assertEquals);\n    }\n\n    private <T, U> void testAdapterRead(final Function<BinaryData<T>, BinaryData<U>> supplier, final T suppliedValue,\n            final U expectedValue, final BiConsumer<U, U> validator) {\n        final AdapterHelper<T> helper = new AdapterHelper<>(suppliedValue);\n        final BinaryData<U> underTest = supplier.apply(helper);\n        helper.assertIsWrapper(underTest);\n        validator.accept(expectedValue, underTest.read(new ByteArrayBuffer(new byte[0]), 0));\n    }\n\n    private <T, U> void testAdapterWrite(final Function<BinaryData<T>, BinaryData<U>> supplier, final U writtenValue,\n            final T forwardedValue, final BiConsumer<T, T> validator) {\n        @SuppressWarnings(\"unchecked\")\n        final AdapterHelper<T> helper = new AdapterHelper<>((Class<T>) forwardedValue.getClass());\n        final BinaryData<U> underTest = supplier.apply(helper);\n        helper.assertIsWrapper(underTest);\n        underTest.write(new ByteArrayBuffer(new byte[0]), 0, writtenValue);\n        validator.accept(forwardedValue, helper.getValue());\n    }\n\n    private static final class AdapterHelper<T> implements BinaryData<T> {\n\n        private T value;\n        private final Class<T> valueType;\n        private final Endianness endianness;\n        private final int size;\n\n        public AdapterHelper(T value, Class<T> valueType, Endianness endianness, int size) {\n            this.value = value;\n            this.valueType = valueType;\n            this.endianness = endianness;\n            this.size = size;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public AdapterHelper(final T value) {\n            this(value, (Class<T>) value.getClass(), Endianness.LITTLE_ENDIAN, 1);\n        }\n\n        public AdapterHelper(final Class<T> valueType) {\n            this(null, valueType, Endianness.LITTLE_ENDIAN, 1);\n        }\n\n        @Override\n        public Endianness getEndianness() {\n            return endianness;\n        }\n\n        @Override\n        public int getSize() {\n            return size;\n        }\n\n        @Override\n        public void write(Buffer buf, int offset, T value) {\n            this.value = value;\n        }\n\n        @Override\n        public T read(Buffer buf, int offset) {\n            return value;\n        }\n\n        public T getValue() {\n            return value;\n        }\n\n        @Override\n        public Class<T> getValueType() {\n            return valueType;\n        }\n\n        public <U> void assertIsWrapper(final BinaryData<U> wrapper) {\n            assertEquals(getEndianness(), wrapper.getEndianness());\n            assertEquals(getSize(), wrapper.getSize());\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BlockAggregatorTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.eclipse.kura.driver.block.Block;\nimport org.eclipse.kura.driver.block.BlockAggregator;\nimport org.eclipse.kura.driver.block.ProhibitedBlock;\nimport org.junit.Test;\n\npublic class BlockAggregatorTest {\n\n    @Test\n    public void shouldSupportEmptyList() {\n        assertEquals(false, new BlockAggregator<Block>(Collections.emptyList(), (start, end) -> new Block(start, end))\n                .stream().iterator().hasNext());\n    }\n\n    @Test\n    public void shouldSupportSingleBlock() {\n        new TestHelper().setInput(2, 5).expect(2, 5).exec();\n    }\n\n    @Test\n    public void shouldSupportSingleProhibitedBlock() {\n        new TestHelper().prohibit(2, 5).expect().exec();\n    }\n\n    @Test\n    public void shouldAggregateAdjacentBlocks() {\n        new TestHelper().setInput(0, 1, 1, 2).expect(0, 2).exec();\n        new TestHelper().setInput(1, 2, 0, 1).expect(0, 2).exec();\n        new TestHelper().setInput(0, 1, 1, 2, 2, 10).expect(0, 10).exec();\n        new TestHelper().setInput(2, 10, 1, 2, 0, 1).expect(0, 10).exec();\n        new TestHelper().setInput(0, 1, 1, 2, 3, 4, 2, 3).expect(0, 4).exec();\n        new TestHelper().setInput(0, 4, 4, 8, 10, 12, 12, 14).expect(0, 8, 10, 14).exec();\n    }\n\n    @Test\n    public void shouldSupportNonSortedList() {\n        new TestHelper().setInput(10, 12, 12, 14, 4, 8, 0, 4).expect(0, 8, 10, 14).exec();\n    }\n\n    @Test\n    public void shouldNotAggregateNonAdjacentBlocks() {\n        new TestHelper().setInput(0, 1, 2, 3).expect(0, 1, 2, 3).exec();\n    }\n\n    @Test\n    public void shouldSupportOverlappingBlocks() {\n        new TestHelper().setInput(1, 9, 2, 4).expect(1, 9).exec();\n        new TestHelper().setInput(1, 9, 2, 4, 3, 6).expect(1, 9).exec();\n        new TestHelper().setInput(0, 1, 0, 1, 0, 1).expect(0, 1).exec();\n        new TestHelper().setInput(0, 1, 1, 3, 20, 25, 15, 21).expect(0, 3, 15, 25).exec();\n    }\n\n    @Test\n    public void shouldSupportProhibitedBlocks() {\n        new TestHelper().prohibit(0, 1).expect().exec();\n        new TestHelper().setInput(0, 1, 1, 2, 3, 4).prohibit(2, 3).expect(0, 2, 3, 4).exec();\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void shouldReportUnfeasibleProblem1() {\n        new TestHelper().setInput(0, 2).prohibit(0, 1).exec();\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void shouldReportUnfeasibleProblem2() {\n        new TestHelper().setInput(0, 2).prohibit(1, 2).exec();\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void shouldReportUnfeasibleProblem3() {\n        new TestHelper().setInput(0, 2).prohibit(1, 3).exec();\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void shouldReportUnfeasibleProblem4() {\n        new TestHelper().setInput(0, 2, 3, 4, 8, 10).prohibit(3, 9).exec();\n    }\n\n    @Test\n    public void shouldAggregateAccordingToMinimumGapSize() {\n        new TestHelper().setInput(0, 1, 2, 3, 4, 5, 6, 7, 8, 9).expect(0, 9).setMinimumGapSize(2).exec();\n        new TestHelper().setInput(0, 1, 2, 3, 6, 7, 8, 9).expect(0, 3, 6, 9).setMinimumGapSize(2).exec();\n    }\n\n    @Test\n    public void shouldSupportProhibitedBlocksWithMinimumGapSize() {\n        new TestHelper().setInput(0, 1, 2, 3, 8, 9).expect(0, 9).setMinimumGapSize(10).exec();\n        new TestHelper().setInput(0, 1, 2, 3, 8, 9).prohibit(4, 7).expect(0, 3, 8, 9).setMinimumGapSize(10).exec();\n    }\n\n    private static class TestHelper {\n\n        private int[] inputBlocks;\n        private int[] prohibitedBlocks;\n        private int[] outputBlocks;\n        private int minimumGapSize;\n        BlockAggregator<Block> aggregator;\n\n        private TestHelper() {\n        }\n\n        public TestHelper setInput(int... inputBlocks) {\n            if (inputBlocks.length % 2 != 0) {\n                fail(\"block list size must be a multiple of 2\");\n            }\n            this.inputBlocks = inputBlocks;\n            return this;\n        }\n\n        public TestHelper expect(int... outputBlocks) {\n            if (outputBlocks.length % 2 != 0) {\n                fail(\"block list size must be a multiple of 2\");\n            }\n            this.outputBlocks = outputBlocks;\n            return this;\n        }\n\n        public TestHelper setMinimumGapSize(int minimumGapSize) {\n            this.minimumGapSize = minimumGapSize;\n            return (this);\n        }\n\n        public TestHelper prohibit(int... prohibitedBlocks) {\n            if (prohibitedBlocks.length % 2 != 0) {\n                fail(\"block list size must be a multiple of 2\");\n            }\n            this.prohibitedBlocks = prohibitedBlocks;\n            return this;\n        }\n\n        public TestHelper exec() {\n\n            List<Block> inputBlocksTemp = new ArrayList<Block>();\n            if (inputBlocks != null) {\n                for (int i = 0; i < inputBlocks.length; i += 2) {\n                    inputBlocksTemp.add(new Block(inputBlocks[i], inputBlocks[i + 1]));\n                }\n            }\n            if (prohibitedBlocks != null) {\n                for (int i = 0; i < prohibitedBlocks.length; i += 2) {\n                    inputBlocksTemp.add(new ProhibitedBlock(prohibitedBlocks[i], prohibitedBlocks[i + 1]));\n                }\n            }\n            aggregator = new BlockAggregator<Block>(inputBlocksTemp, (start, end) -> new Block(start, end));\n            aggregator.setMinimumGapSize(minimumGapSize);\n            Iterator<Block> blocks = aggregator.stream().iterator();\n\n            if (outputBlocks != null) {\n                int i = 0;\n                while (blocks.hasNext()) {\n                    final Block next = blocks.next();\n                    assertEquals(outputBlocks[i * 2], next.getStart());\n                    assertEquals(outputBlocks[i * 2 + 1], next.getEnd());\n                    i++;\n                }\n                assertEquals(outputBlocks.length / 2, i);\n            } else {\n                // needed for the shouldReportUnfeasibleProblem tests\n                for (; blocks.hasNext(); blocks.next())\n                    ;\n            }\n\n            return this;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BlockTaskAggregatorTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.driver.block.Block;\nimport org.eclipse.kura.driver.block.BlockFactory;\nimport org.eclipse.kura.driver.block.ProhibitedBlock;\nimport org.eclipse.kura.driver.block.task.BlockTask;\nimport org.eclipse.kura.driver.block.task.BlockTaskAggregator;\nimport org.eclipse.kura.driver.block.task.Mode;\nimport org.eclipse.kura.driver.block.task.ToplevelBlockTask;\nimport org.eclipse.kura.driver.block.task.UpdateBlockTaskAggregator;\nimport org.junit.Assert;\nimport org.junit.Test;\n\npublic class BlockTaskAggregatorTest {\n\n    @Test\n    public void shouldSupportSingleTask() {\n        new TestHelper().setInput(2, 5).expect(2, 5).exec();\n    }\n\n    @Test\n    public void shouldSupportSingleProhibitedTask() {\n        new TestHelper().prohibit(2, 5).expect().exec();\n    }\n\n    @Test\n    public void shouldOptimizeAdjacentBlocks() {\n        new TestHelper().setInput(0, 1, 1, 2, 2, 3).expect(0, 3).exec();\n    }\n\n    @Test\n    public void shouldSupportBlockInsertion() {\n        new TestHelper().setInput(0, 1).expect(0, 1).exec();\n    }\n\n    @Test\n    public void shouldAggregateAdjacentBlocks() {\n        new TestHelper().setInput(0, 1, 1, 2).expect(0, 2).exec();\n        new TestHelper().setInput(1, 2, 0, 1).expect(0, 2).exec();\n        new TestHelper().setInput(0, 1, 1, 2, 2, 10).expect(0, 10).exec();\n        new TestHelper().setInput(2, 10, 1, 2, 0, 1).expect(0, 10).exec();\n        new TestHelper().setInput(0, 1, 1, 2, 3, 4, 2, 3).expect(0, 4).exec();\n        new TestHelper().setInput(0, 4, 4, 8, 8, 10, 10, 12).expect(0, 12).exec();\n        new TestHelper().setInput(0, 4, 4, 8, 10, 12, 12, 14).expect(0, 8, 10, 14).exec();\n    }\n\n    @Test\n    public void shouldSupportNonSortedList() {\n        new TestHelper().setInput(10, 12, 12, 14, 4, 8, 0, 4).expect(0, 8, 10, 14).exec();\n    }\n\n    @Test\n    public void shouldNotAggregateNonAdjacentBlocks() {\n        new TestHelper().setInput(0, 1, 2, 3).expect(0, 1, 2, 3).exec();\n    }\n\n    @Test\n    public void shouldSupportOverlappingBlocks() {\n        new TestHelper().setInput(1, 9, 2, 4).expect(1, 9).exec();\n        new TestHelper().setInput(1, 9, 2, 4, 3, 6).expect(1, 9).exec();\n        new TestHelper().setInput(0, 1, 0, 1, 0, 1).expect(0, 1).exec();\n        new TestHelper().setInput(0, 1, 1, 3, 20, 25, 15, 21).expect(0, 3, 15, 25).exec();\n    }\n\n    @Test\n    public void shouldSupportProhibitedBlocks() {\n        new TestHelper().prohibit(0, 1).expect().exec();\n        new TestHelper().setInput(0, 1, 1, 2, 3, 4).prohibit(2, 3).expect(0, 2, 3, 4).exec();\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void shouldReportUnfeasibleProblem1() {\n        new TestHelper().setInput(0, 2).prohibit(0, 1).exec();\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void shouldReportUnfeasibleProblem2() {\n        new TestHelper().setInput(0, 2).prohibit(1, 2).exec();\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void shouldReportUnfeasibleProblem3() {\n        new TestHelper().setInput(0, 2).prohibit(1, 3).exec();\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void shouldReportUnfeasibleProblem4() {\n        new TestHelper().setInput(0, 2, 3, 4, 8, 10).prohibit(4, 9).exec();\n    }\n\n    @Test\n    public void shouldAggregateAccordingToMinimumGapSize() {\n        new TestHelper().setInput(0, 1, 2, 3, 4, 5, 6, 7, 8, 9).expect(0, 9).setMinimumGapSize(2).exec();\n        new TestHelper().setInput(0, 1, 2, 3, 6, 7, 8, 9).expect(0, 3, 6, 9).setMinimumGapSize(2).exec();\n    }\n\n    @Test\n    public void shouldSupportProhibitedBlocksWithMinimumGapSize() {\n        new TestHelper().setInput(0, 1, 2, 3, 8, 9).expect(0, 9).setMinimumGapSize(10).exec();\n        new TestHelper().setInput(0, 1, 2, 3, 8, 9).prohibit(4, 7).expect(0, 3, 8, 9).setMinimumGapSize(10).exec();\n    }\n\n    @Test\n    public void shouldSupportUpdateTask() {\n        new TestHelper().setInput(0, 1, 8, 9).setUpdate(1, 3).expect(1, 3, 0, 3, 8, 9).exec();\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void shouldSupportProhibitedBlocksWithUpdateTask() {\n        new TestHelper().setInput(0, 1, 8, 9).setUpdate(1, 3).prohibit(2, 3).exec();\n    }\n\n    @Test\n    public void shouldSupportMinimumGapSizeWithUpdateTask() {\n        new TestHelper().setInput(0, 1, 8, 9).setUpdate(2, 3, 4, 5).setMinimumGapSize(6)\n                .expect(2, 5, 0, 1, 2, 3, 4, 5, 8, 9).exec();\n    }\n\n    private interface TaskListener {\n\n        public void onRun(BlockTask task, BlockTask parent);\n\n        public void onFail(BlockTask task, BlockTask parent);\n    }\n\n    private class TestTask extends ToplevelBlockTask {\n\n        private TaskListener listener;\n\n        public TestTask(int start, int end, TaskListener listener) {\n            super(start, end, Mode.WRITE);\n            this.listener = listener;\n        }\n\n        public TestTask(int start, int end, Mode mode, TaskListener listener) {\n            super(start, end, mode);\n            this.listener = listener;\n        }\n\n        @Override\n        public void processBuffer() {\n        }\n\n        @Override\n        public void onFailure(Exception reason) {\n            if (listener != null) {\n                listener.onFail(this, getParent());\n            }\n            super.onFailure(reason);\n        }\n\n        public Buffer getBuffer() {\n            return null;\n        }\n    }\n\n    private class TestHelper {\n\n        private TaskListener taskListener = new TaskListener() {\n\n            @Override\n            public void onRun(BlockTask task, BlockTask parent) {\n                if (parent != null) {\n                    Assert.assertTrue(task.getStart() >= parent.getStart());\n                    Assert.assertTrue(task.getEnd() <= parent.getEnd());\n                }\n            }\n\n            @Override\n            public void onFail(BlockTask task, BlockTask parent) {\n                Assert.fail();\n            }\n        };\n\n        private int[] updateBlocks = new int[0];\n        private int[] inputBlocks = new int[0];\n        private int[] prohibitedBlocks = new int[0];\n        private int[] outputBlocks;\n        private int minimumGapSize = 0;\n\n        private TestHelper() {\n        }\n\n        public TestHelper setInput(int... inputBlocks) {\n            if (inputBlocks.length % 2 != 0) {\n                fail(\"block list size must be a multiple of 2\");\n            }\n            this.inputBlocks = inputBlocks;\n            return this;\n        }\n\n        public TestHelper setUpdate(int... updateBlocks) {\n            if (inputBlocks.length % 2 != 0) {\n                fail(\"block list size must be a multiple of 2\");\n            }\n            this.updateBlocks = updateBlocks;\n            return this;\n        }\n\n        public TestHelper expect(int... outputBlocks) {\n            if (outputBlocks.length % 2 != 0) {\n                fail(\"block list size must be a multiple of 2\");\n            }\n            this.outputBlocks = outputBlocks;\n            return this;\n        }\n\n        public TestHelper prohibit(int... prohibitedBlocks) {\n            if (prohibitedBlocks.length % 2 != 0) {\n                fail(\"block list size must be a multiple of 2\");\n            }\n            this.prohibitedBlocks = prohibitedBlocks;\n            return this;\n        }\n\n        public TestHelper setMinimumGapSize(int minimumGapSize) {\n            this.minimumGapSize = minimumGapSize;\n            return (this);\n        }\n\n        public TestHelper exec() {\n            List<Block> tasks = new ArrayList<Block>();\n            for (int i = 0; i < inputBlocks.length; i += 2) {\n                tasks.add(new TestTask(inputBlocks[i], inputBlocks[i + 1], taskListener));\n            }\n            for (int i = 0; i < updateBlocks.length; i += 2) {\n                tasks.add(new TestTask(updateBlocks[i], updateBlocks[i + 1], Mode.UPDATE, taskListener));\n            }\n\n            BlockTaskAggregator aggregator;\n\n            BlockFactory<ToplevelBlockTask> factory = (start, end) -> new TestTask(start, end, taskListener);\n\n            if (updateBlocks.length == 0) {\n                aggregator = new BlockTaskAggregator(tasks, factory);\n            } else {\n                aggregator = new UpdateBlockTaskAggregator(tasks, factory, factory);\n            }\n\n            aggregator.setMinimumGapSize(minimumGapSize);\n            for (int i = 0; i < prohibitedBlocks.length; i += 2) {\n                aggregator.addBlock(new ProhibitedBlock(prohibitedBlocks[i], prohibitedBlocks[i + 1]));\n            }\n\n            final Iterator<ToplevelBlockTask> blocks = aggregator.stream().iterator();\n\n            int childCount = 0;\n            if (outputBlocks != null) {\n                int i = 0;\n                while (blocks.hasNext()) {\n                    final ToplevelBlockTask next = blocks.next();\n                    assertEquals(outputBlocks[i * 2], next.getStart());\n                    assertEquals(outputBlocks[i * 2 + 1], next.getEnd());\n                    childCount += next.getChildren().size();\n                    try {\n                        next.run();\n                    } catch (IOException e) {\n                    }\n                    i++;\n                }\n                assertEquals(outputBlocks.length / 2, i);\n                assertEquals(inputBlocks.length / 2 + updateBlocks.length, childCount);\n            } else {\n                // needed for the shouldReportUnfeasibleProblem tests\n                for (; blocks.hasNext(); blocks.next())\n                    ;\n            }\n\n            return this;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.block.test/src/test/java/org/eclipse/kura/driver/block/test/BlockTaskTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.block.test;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\n\nimport org.eclipse.kura.channel.ChannelFlag;\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.driver.binary.BinaryDataTypes;\nimport org.eclipse.kura.driver.binary.Buffer;\nimport org.eclipse.kura.driver.binary.ByteArray;\nimport org.eclipse.kura.driver.binary.ByteArrayBuffer;\nimport org.eclipse.kura.driver.block.task.BinaryDataTask;\nimport org.eclipse.kura.driver.block.task.BitTask;\nimport org.eclipse.kura.driver.block.task.ByteArrayTask;\nimport org.eclipse.kura.driver.block.task.ChannelBlockTask;\nimport org.eclipse.kura.driver.block.task.Mode;\nimport org.eclipse.kura.driver.block.task.StringTask;\nimport org.eclipse.kura.driver.block.task.ToplevelBlockTask;\nimport org.eclipse.kura.type.DataType;\nimport org.eclipse.kura.type.TypedValues;\nimport org.junit.Test;\n\npublic class BlockTaskTest {\n\n    @Test\n    public void shouldSupportBinaryDataTask() throws IOException {\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.UINT32_BE, mode),\n                new byte[] { 1, 2, 3, 4 }, 16909060L);\n    }\n\n    @Test\n    public void shouldSupportBinaryDataTaskTypeConversions() throws IOException {\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.INT32_BE,\n                DataType.DOUBLE, mode), new byte[] { 1, 2, 3, 4 }, ((Number) 16909060).doubleValue());\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.INT32_BE,\n                DataType.FLOAT, mode), new byte[] { 1, 2, 3, 4 }, ((Number) 16909060).floatValue());\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.INT32_BE,\n                DataType.LONG, mode), new byte[] { 1, 2, 3, 4 }, ((Number) 16909060).longValue());\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.UINT32_BE,\n                DataType.INTEGER, mode), new byte[] { 1, 2, 3, 4 }, 16909060);\n\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.UINT32_BE,\n                DataType.STRING, mode), new byte[] { 1, 2, 3, 4 }, \"16909060\");\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.INT32_BE,\n                DataType.STRING, mode), new byte[] { 1, 2, 3, 4 }, \"16909060\");\n\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.FLOAT_BE,\n                DataType.INTEGER, mode), new byte[] { 0x47, (byte) 0x80, 0, 0 }, 65536);\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.DOUBLE_BE,\n                DataType.INTEGER, mode), new byte[] { 0x40, (byte) 0xf0, 0, 0, 0, 0, 0, 0 }, 65536);\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.FLOAT_BE,\n                DataType.LONG, mode), new byte[] { 0x47, (byte) 0x80, 0, 0 }, 65536L);\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.DOUBLE_BE,\n                DataType.LONG, mode), new byte[] { 0x40, (byte) 0xf0, 0, 0, 0, 0, 0, 0 }, 65536L);\n\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.FLOAT_BE,\n                DataType.STRING, mode), new byte[] { 0x47, (byte) 0x80, 0, 0 }, \"65536.0\");\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, BinaryDataTypes.DOUBLE_BE,\n                DataType.STRING, mode), new byte[] { 0x40, (byte) 0xf0, 0, 0, 0, 0, 0, 0 }, \"65536.0\");\n\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset, new ByteArray(4),\n                DataType.BYTE_ARRAY, mode), new byte[] { 1, 2, 3, 4 }, new byte[] { 1, 2, 3, 4 });\n    }\n\n    @Test\n    public void shouldSupportBitTask() throws IOException {\n        testRead((record, offset, mode) -> new BitTask(record, offset, 0, mode), new byte[] { 1 << 0 }, true);\n        testRead((record, offset, mode) -> new BitTask(record, offset, 1, mode), new byte[] { 1 << 1 }, true);\n        testRead((record, offset, mode) -> new BitTask(record, offset, 2, mode), new byte[] { 1 << 2 }, true);\n        testRead((record, offset, mode) -> new BitTask(record, offset, 3, mode), new byte[] { 1 << 3 }, true);\n        testRead((record, offset, mode) -> new BitTask(record, offset, 4, mode), new byte[] { 1 << 4 }, true);\n        testRead((record, offset, mode) -> new BitTask(record, offset, 5, mode), new byte[] { 1 << 5 }, true);\n        testRead((record, offset, mode) -> new BitTask(record, offset, 6, mode), new byte[] { 1 << 6 }, true);\n        testRead((record, offset, mode) -> new BitTask(record, offset, 7, mode), new byte[] { (byte) (1 << 7) }, true);\n\n        testRead((record, offset, mode) -> new BitTask(record, offset, 0, mode), new byte[] { (byte) (1 << 7) }, false);\n\n        testUpdate((record, offset, mode) -> new BitTask(record, offset, 0, mode), new byte[] { 1 << 0 }, true);\n        testUpdate((record, offset, mode) -> new BitTask(record, offset, 1, mode), new byte[] { 1 << 1 }, true);\n        testUpdate((record, offset, mode) -> new BitTask(record, offset, 2, mode), new byte[] { 1 << 2 }, true);\n        testUpdate((record, offset, mode) -> new BitTask(record, offset, 3, mode), new byte[] { 1 << 3 }, true);\n        testUpdate((record, offset, mode) -> new BitTask(record, offset, 4, mode), new byte[] { 1 << 4 }, true);\n        testUpdate((record, offset, mode) -> new BitTask(record, offset, 5, mode), new byte[] { 1 << 5 }, true);\n        testUpdate((record, offset, mode) -> new BitTask(record, offset, 6, mode), new byte[] { 1 << 6 }, true);\n        testUpdate((record, offset, mode) -> new BitTask(record, offset, 7, mode), new byte[] { (byte) (1 << 7) },\n                true);\n    }\n\n    @Test\n    public void shouldSupportStringTask() throws IOException {\n        final String testString = \"test string\";\n        testReadWrite((record, offset, mode) -> new StringTask(record, offset, offset + testString.length(), mode),\n                testString.getBytes(StandardCharsets.US_ASCII), testString);\n    }\n\n    @Test\n    public void shouldSupportByteArrayTask() throws IOException {\n        final byte[] testByteArray = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n        testReadWrite((record, offset, mode) -> new ByteArrayTask(record, offset, offset + testByteArray.length, mode),\n                testByteArray, Arrays.copyOf(testByteArray, testByteArray.length));\n    }\n\n    @Test\n    public void shouldSupportByteArrayTaskWithBinaryData() throws IOException {\n        final byte[] testByteArray = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n        testReadWrite((record, offset, mode) -> new BinaryDataTask<>(record, offset,\n                new ByteArray(testByteArray.length), DataType.BYTE_ARRAY, mode), testByteArray,\n                Arrays.copyOf(testByteArray, testByteArray.length));\n    }\n\n    private ToplevelBlockTask getToplevelBlockTask(byte[] buf, Mode mode) {\n        return new ToplevelBlockTask(0, buf.length, mode) {\n\n            @Override\n            public void processBuffer() throws IOException {\n            }\n\n            @Override\n            public Buffer getBuffer() {\n                return new ByteArrayBuffer(buf);\n            }\n        };\n    }\n\n    private interface TaskProvider {\n\n        public ChannelBlockTask get(ChannelRecord record, int offset, Mode mode);\n    }\n\n    private void testReadWrite(TaskProvider taskProvider, byte[] raw, Object javaValue) throws IOException {\n        testRead(taskProvider, raw, javaValue);\n        testWrite(taskProvider, raw, javaValue);\n    }\n\n    private void testRead(TaskProvider taskProvider, byte[] raw, Object javaValue) throws IOException {\n        testRead(taskProvider, raw, javaValue, DataType.BOOLEAN);\n    }\n\n    private void testRead(TaskProvider taskProvider, byte[] raw, Object javaValue, DataType valueType)\n            throws IOException {\n        int[] offsets = new int[] { 0, 7 };\n        for (final int offset : offsets) {\n            ChannelRecord record = ChannelRecord.createReadRecord(\"test\", valueType);\n            byte[] buf = new byte[offset + raw.length];\n            System.arraycopy(raw, 0, buf, offset, raw.length);\n            ChannelBlockTask task = taskProvider.get(record, offset, Mode.READ);\n            ToplevelBlockTask parent = getToplevelBlockTask(buf, Mode.READ);\n            parent.addChild(task);\n            parent.run();\n            assertEquals(ChannelFlag.SUCCESS, task.getRecord().getChannelStatus().getChannelFlag());\n            if (!javaValue.getClass().isArray()) {\n                assertEquals(javaValue, task.getRecord().getValue().getValue());\n            } else {\n                assertArrayEquals((byte[]) javaValue, (byte[]) task.getRecord().getValue().getValue());\n            }\n        }\n    }\n\n    private void testWrite(TaskProvider taskProvider, byte[] raw, Object javaValue) throws IOException {\n        int[] offsets = new int[] { 0, 7 };\n        for (final int offset : offsets) {\n            ChannelRecord record = ChannelRecord.createWriteRecord(\"test\", TypedValues.newTypedValue(javaValue));\n            byte[] buf = new byte[offset + raw.length];\n            ChannelBlockTask task = taskProvider.get(record, offset, Mode.WRITE);\n            ToplevelBlockTask parent = getToplevelBlockTask(buf, Mode.WRITE);\n            parent.addChild(task);\n            parent.run();\n            assertEquals(ChannelFlag.SUCCESS, record.getChannelStatus().getChannelFlag());\n            byte[] result = new byte[raw.length];\n            System.arraycopy(buf, offset, result, 0, raw.length);\n            assertArrayEquals(raw, result);\n        }\n    }\n\n    private void testUpdate(TaskProvider taskProvider, byte[] raw, Object javaValue) throws IOException {\n        int[] offsets = new int[] { 0, 7 };\n        for (final int offset : offsets) {\n            ChannelRecord record = ChannelRecord.createWriteRecord(\"test\", TypedValues.newTypedValue(javaValue));\n            byte[] buf = new byte[offset + raw.length];\n            ChannelBlockTask task = taskProvider.get(record, offset, Mode.UPDATE);\n            ToplevelBlockTask readParent = getToplevelBlockTask(buf, Mode.READ);\n            readParent.addChild(task);\n            ToplevelBlockTask writeParent = getToplevelBlockTask(buf, Mode.WRITE);\n            writeParent.addChild(task);\n            readParent.run();\n            writeParent.run();\n            assertEquals(ChannelFlag.SUCCESS, record.getChannelStatus().getChannelFlag());\n            byte[] result = new byte[raw.length];\n            System.arraycopy(buf, offset, result, 0, raw.length);\n            assertArrayEquals(raw, result);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.helper.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.driver.helper.test\nBundle-SymbolicName: org.eclipse.kura.driver.helper.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.testutil;version=\"[1.0,2.0)\",\n org.eclipse.kura.driver;version=\"[1.0,2.0)\",\n org.eclipse.kura.driver.descriptor;version=\"[1.0,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.slf4j;version=\"1.7.21\"\nFragment-Host: org.eclipse.kura.driver.helper.provider;bundle-version=\"[2.0,3.0)\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.helper.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.helper.test/build.properties",
    "content": "bin.includes = .,\\\n               META-INF/,\\\n               about.html\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.helper.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Eurotech\n     \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.driver.helper.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.helper.test/src/test/java/org/eclipse/kura/driver/block/test/DriveDescriptorServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.driver.block.test;\n\nimport static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\nimport static org.osgi.service.cm.ConfigurationAdmin.SERVICE_FACTORYPID;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.driver.ChannelDescriptor;\nimport org.eclipse.kura.driver.Driver;\nimport org.eclipse.kura.driver.descriptor.DriverDescriptor;\nimport org.eclipse.kura.driver.descriptor.DriverDescriptorService;\nimport org.eclipse.kura.internal.driver.DriverDescriptorServiceImpl;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceReference;\n\npublic class DriveDescriptorServiceImplTest {\n\n    @Test\n    public void testNewDriverDescriptor() throws Throwable {\n        Driver driver = mock(Driver.class);\n\n        AD adVal = mock(AD.class);\n        List<AD> adChannelDescriptor = new ArrayList<>();\n        adChannelDescriptor.add(adVal);\n\n        ChannelDescriptor channelDescriptor = mock(ChannelDescriptor.class);\n\n        when(driver.getChannelDescriptor()).thenReturn(channelDescriptor);\n        when(channelDescriptor.getDescriptor()).thenReturn(adChannelDescriptor);\n\n        String kuraServicePid = \"kuraPid\";\n        String factoryPid = \"factoryPid\";\n\n        DriverDescriptorService driverDescriptorService = new DriverDescriptorServiceImpl();\n        DriverDescriptor driverDescriptor = (DriverDescriptor) TestUtil.invokePrivate(driverDescriptorService,\n                \"newDriverDescriptor\", kuraServicePid, factoryPid, driver);\n\n        assertEquals(kuraServicePid, driverDescriptor.getPid());\n        assertEquals(factoryPid, driverDescriptor.getFactoryPid());\n        assertEquals(adChannelDescriptor, driverDescriptor.getChannelDescriptor());\n    }\n\n    @Test(expected = NullPointerException.class)\n    public void testGetDriverDescriptorNullPid() {\n        DriverDescriptorService driverDescriptorService = new DriverDescriptorServiceImpl();\n        driverDescriptorService.getDriverDescriptor(null);\n    }\n\n    @Test\n    public void testGetDriverDescriptorNotMatchingPid() {\n        DriverDescriptorService driverService = getDriverDescriptorServiceImplEmptyDriverServiceReferenceArray();\n\n        Optional<DriverDescriptor> result = driverService.getDriverDescriptor(\"fakePid\");\n\n        assertNotNull(result);\n        assertEquals(false, result.isPresent());\n\n    }\n\n    @Test\n    public void testGetDriverDescriptorMatchingPid() throws NoSuchFieldException {\n        ServiceReference<Driver> driverSr = mock(ServiceReference.class);\n\n        DriverDescriptorService driverDescriptorService = getDriverDescriptorServiceImplOneElementDriverServiceReferenceArray(\n                driverSr);\n\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(driverDescriptorService, \"bundleContext\", context);\n\n        Driver driverInstance = mock(Driver.class);\n        AD adVal = mock(AD.class);\n        List<AD> adChannelDescriptor = new ArrayList<>();\n        adChannelDescriptor.add(adVal);\n\n        ChannelDescriptor channelDescriptor = mock(ChannelDescriptor.class);\n\n        String kuraServicePid = \"fakePid\";\n        String factoryPid = \"factoryPid\";\n\n        when(context.getService(driverSr)).thenReturn(driverInstance);\n        when(driverSr.getProperty(SERVICE_FACTORYPID)).thenReturn(factoryPid);\n        when(driverInstance.getChannelDescriptor()).thenReturn(channelDescriptor);\n        when(channelDescriptor.getDescriptor()).thenReturn(adChannelDescriptor);\n\n        Optional<DriverDescriptor> result = driverDescriptorService.getDriverDescriptor(kuraServicePid);\n\n        assertNotNull(result);\n        assertEquals(true, result.isPresent());\n\n        DriverDescriptor driverDescriptor = result.get();\n        assertEquals(kuraServicePid, driverDescriptor.getPid());\n        assertEquals(factoryPid, driverDescriptor.getFactoryPid());\n        assertEquals(adChannelDescriptor, driverDescriptor.getChannelDescriptor());\n    }\n\n    @Test\n    public void testListDriverDescriptorEmptyDrivers() {\n\n        DriverDescriptorService driverService = getDriverDescriptorServiceImplEmptyDriverServiceReferenceArray();\n\n        List<DriverDescriptor> driverList = driverService.listDriverDescriptors();\n        assertNotNull(driverList);\n        assertEquals(0, driverList.size());\n    }\n\n    @Test\n    public void testListDriverDescrptorOneDriver() throws NoSuchFieldException {\n        ServiceReference<Driver> driverSr = mock(ServiceReference.class);\n\n        DriverDescriptorService driverService = getDriverDescriptorServiceImplOneElementDriverServiceReferenceArray(\n                driverSr);\n        BundleContext context = mock(BundleContext.class);\n        TestUtil.setFieldValue(driverService, \"bundleContext\", context);\n\n        Driver driverInstance = mock(Driver.class);\n        AD adVal = mock(AD.class);\n        List<AD> adChannelDescriptor = new ArrayList<>();\n        adChannelDescriptor.add(adVal);\n\n        ChannelDescriptor channelDescriptor = mock(ChannelDescriptor.class);\n\n        String kuraServicePid = \"fakePid\";\n        String factoryPid = \"factoryPid\";\n\n        when(context.getService(driverSr)).thenReturn(driverInstance);\n        when(driverSr.getProperty(KURA_SERVICE_PID)).thenReturn(kuraServicePid);\n        when(driverSr.getProperty(SERVICE_FACTORYPID)).thenReturn(factoryPid);\n        when(driverInstance.getChannelDescriptor()).thenReturn(channelDescriptor);\n        when(channelDescriptor.getDescriptor()).thenReturn(adChannelDescriptor);\n\n        when(context.getService(driverSr)).thenReturn(driverInstance);\n\n        List<DriverDescriptor> driverDescriptorList = driverService.listDriverDescriptors();\n        assertNotNull(driverDescriptorList);\n        assertEquals(1, driverDescriptorList.size());\n\n        DriverDescriptor driverDescriptor = driverDescriptorList.get(0);\n        assertEquals(kuraServicePid, driverDescriptor.getPid());\n        assertEquals(factoryPid, driverDescriptor.getFactoryPid());\n        assertEquals(adChannelDescriptor, driverDescriptor.getChannelDescriptor());\n    }\n\n    private DriverDescriptorServiceImpl getDriverDescriptorServiceImplEmptyDriverServiceReferenceArray() {\n        return new DriverDescriptorServiceImpl() {\n\n            @Override\n            protected ServiceReference<Driver>[] getDriverServiceReferences(final String filter) {\n                return new ServiceReference[0];\n            }\n\n            @Override\n            protected void ungetDriverServiceReferences(final ServiceReference<Driver>[] refs) {\n            }\n        };\n    }\n\n    private DriverDescriptorServiceImpl getDriverDescriptorServiceImplOneElementDriverServiceReferenceArray(\n            ServiceReference<Driver> driverSr) {\n        return new DriverDescriptorServiceImpl() {\n\n            @Override\n            protected ServiceReference<Driver>[] getDriverServiceReferences(final String filter) {\n                ServiceReference[] driverSrArray = new ServiceReference[1];\n                driverSrArray[0] = driverSr;\n                return driverSrArray;\n            }\n\n            @Override\n            protected void ungetDriverServiceReferences(final ServiceReference<Driver>[] refs) {\n            }\n        };\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.driver.helper.test/src/test/java/org/eclipse/kura/driver/block/test/DriverServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.driver.block.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.List;\n\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.driver.Driver;\nimport org.eclipse.kura.driver.DriverService;\nimport org.eclipse.kura.internal.driver.DriverServiceImpl;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceReference;\n\npublic class DriverServiceImplTest {\n\n    @Test\n    public void testListDriversEmptyDrivers() {\n\n        DriverService driverService = getDriverServiceImplEmptyDriverServiceReferenceArray();\n\n        List<Driver> driverList = driverService.listDrivers();\n        assertNotNull(driverList);\n        assertEquals(0, driverList.size());\n    }\n\n    @Test\n    public void testListDriversOneDriver() throws NoSuchFieldException {\n        BundleContext context = mock(BundleContext.class);\n\n        ServiceReference<Driver> driverSr = mock(ServiceReference.class);\n\n        Driver driverInstance = mock(Driver.class);\n\n        DriverService driverService = getDriverServiceImplOneElementDriverServiceReferenceArray(driverSr);\n        TestUtil.setFieldValue(driverService, \"bundleContext\", context);\n\n        when(context.getService(driverSr)).thenReturn(driverInstance);\n\n        List<Driver> driverList = driverService.listDrivers();\n        assertNotNull(driverList);\n        assertEquals(1, driverList.size());\n        assertEquals(driverInstance, driverList.get(0));\n    }\n\n    private DriverServiceImpl getDriverServiceImplEmptyDriverServiceReferenceArray() {\n        return new DriverServiceImpl() {\n\n            @Override\n            protected ServiceReference<Driver>[] getDriverServiceReferences(final String filter) {\n                return new ServiceReference[0];\n            }\n\n            @Override\n            protected void ungetDriverServiceReferences(final ServiceReference<Driver>[] refs) {\n            }\n        };\n    }\n\n    private DriverServiceImpl getDriverServiceImplOneElementDriverServiceReferenceArray(\n            ServiceReference<Driver> driverSr) {\n        return new DriverServiceImpl() {\n\n            @Override\n            protected ServiceReference<Driver>[] getDriverServiceReferences(final String filter) {\n                ServiceReference[] driverSrArray = new ServiceReference[1];\n                driverSrArray[0] = driverSr;\n                return driverSrArray;\n            }\n\n            @Override\n            protected void ungetDriverServiceReferences(final ServiceReference<Driver>[] refs) {\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.position.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator.position.test\nBundle-SymbolicName: org.eclipse.kura.emulator.position.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.emulator.position\nImport-Package: org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.emulator.position;version=\"1.0.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.verification;version=\"[4.0.0,5.0.0)\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.4.0\",\n org.osgi.service.component;version=\"1.0.0\",\n org.osgi.service.event;version=\"1.3.0\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.position.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.position.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/test/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.position.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.emulator.position.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.position.test/src/test/java/org/eclipse/kura/emulator/position/PositionServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.emulator.position;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.isA;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.position.NmeaPosition;\nimport org.eclipse.kura.position.PositionLockedEvent;\nimport org.junit.Test;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.event.EventAdmin;\nimport org.osgi.util.position.Position;\n\npublic class PositionServiceImplTest {\n\n    private static final String USE_GPSD = \"useGpsd\";\n\n    @Test\n    public void testActivateReadDeactivate() throws MalformedURLException, NoSuchFieldException {\n        // test service activation, wait for position, deactivate\n\n        PositionServiceImpl svc = new PositionServiceImpl();\n\n        Bundle bMock = initBundleMock();\n\n        ComponentContext ccMock = initComponentContextMock(bMock);\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(USE_GPSD, true);\n\n        svc.activate(ccMock, properties);\n\n        verify(eaMock, timeout(5000)).postEvent(isA(PositionLockedEvent.class));\n\n        Position currentPosition = svc.getPosition();\n        NmeaPosition currentNmeaPosition = svc.getNmeaPosition();\n\n        double eps = 0.0000001;\n        assertEquals(0.7370467, currentPosition.getLatitude().getValue(), eps);\n        assertEquals(-1.2482312, currentPosition.getLongitude().getValue(), eps);\n        assertEquals(149.6, currentPosition.getAltitude().getValue(), eps);\n\n        eps *= 10.0;\n        assertEquals(42.229664, currentNmeaPosition.getLatitude(), eps);\n        assertEquals(-71.518378, currentNmeaPosition.getLongitude(), eps);\n        assertEquals(149.6, currentNmeaPosition.getAltitude(), eps);\n    }\n\n    @Test\n    public void testUpdate() throws MalformedURLException, NoSuchFieldException {\n        // test service update\n\n        PositionServiceImpl svc = new PositionServiceImpl();\n\n        Bundle bMock = initBundleMock();\n\n        ComponentContext ccMock = initComponentContextMock(bMock);\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(USE_GPSD, true);\n        svc.activate(ccMock, properties);\n\n        properties = new HashMap<>();\n        properties.put(USE_GPSD, true);\n        svc.updated(properties);\n\n        assertTrue((boolean) TestUtil.getFieldValue(svc, \"useGpsd\"));\n\n        properties.put(USE_GPSD, false);\n        svc.updated(properties);\n\n        assertFalse((boolean) TestUtil.getFieldValue(svc, \"useGpsd\"));\n    }\n\n    private ComponentContext initComponentContextMock(Bundle bMock) {\n        BundleContext bcMock = mock(BundleContext.class);\n        when(bcMock.getBundle()).thenReturn(bMock);\n        ComponentContext ccMock = mock(ComponentContext.class);\n        when(ccMock.getBundleContext()).thenReturn(bcMock);\n        return ccMock;\n    }\n\n    private Bundle initBundleMock() throws MalformedURLException {\n        Bundle bMock = mock(Bundle.class);\n        String name = \"boston.gpx\";\n        URL url = new URL(\"file:../../emulator/org.eclipse.kura.emulator.position/src/main/resources/\" + name);\n        when(bMock.getResource(name)).thenReturn(url);\n        return bMock;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator.test\nBundle-SymbolicName: org.eclipse.kura.emulator.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.emulator\nImport-Package: org.mockito;version=\"5.0.0\"\nRequire-Bundle: \n org.apache.logging.log4j.slf4j2.impl;bundle-version=\"2.8.2\",\n org.apache.logging.log4j.api;bundle-version=\"2.8.2\",\n org.apache.logging.log4j.core;bundle-version=\"2.8.2\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.emulator.test</artifactId>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n    \n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.test/src/test/java/org/eclipse/kura/emulator/EmulatorTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.emulator;\n\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.net.URL;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.osgi.service.component.ComponentContext;\n\npublic class EmulatorTest {\n\n    private static ComponentContext componentContext;\n\n    private static String tempDir = System.getProperty(\"java.io.tmpdir\");\n\n    private static final String SNAPSHOT_0_NAME = \"snapshot_0.xml\";\n\n    private static final String KURA_SNAPSHOTS_PATH = \"kura.snapshots\";\n\n    private static final String EMULATOR = \"emulator\";\n\n    private static final String KURA_MODE = \"org.eclipse.kura.mode\";\n\n    private static final Path snapshotsFolder = Paths.get(tempDir, \"snapshots\");\n    private static final Path snapshot0File = Paths.get(snapshotsFolder.toString(), SNAPSHOT_0_NAME);\n\n    @BeforeClass\n    public static void init() throws IOException {\n\n        System.setProperty(KURA_SNAPSHOTS_PATH, snapshotsFolder.toString());\n        System.setProperty(KURA_MODE, EMULATOR);\n\n        URL snapshotUrl = Emulator.class.getClassLoader().getResource(SNAPSHOT_0_NAME);\n\n        componentContext = mock(ComponentContext.class, Mockito.RETURNS_DEEP_STUBS);\n        when(componentContext.getBundleContext().getBundle().getResource(any())).thenReturn(snapshotUrl);\n    }\n\n    @Test\n    public void testSnapshotCopy() {\n        Emulator emulator = new Emulator();\n        emulator.activate(componentContext);\n        assertTrue(\"Snapshot doesn't exist\", Files.exists(snapshot0File));\n    }\n\n    @After\n    @Before\n    public void cleanUp() throws IOException {\n        Files.deleteIfExists(snapshot0File);\n        Files.deleteIfExists(snapshotsFolder);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.test/src/test/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<Configuration status=\"INFO\">\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\">\n            <PatternLayout pattern=\"%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n\" />\n        </Console>\n    </Appenders>\n    <Loggers>\n        <Root level=\"all\">\n            <AppenderRef ref=\"Console\" />\n        </Root>\n        <Logger name=\"org.glassfish.jersey.internal\" level=\"error\" additivity=\"false\">\n            <AppenderRef ref=\"Console\"/>\n        </Logger>\n    </Loggers>\n</Configuration>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.watchdog.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.emulator.watchdog.test\nBundle-SymbolicName: org.eclipse.kura.emulator.watchdog.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.emulator.watchdog\nImport-Package: org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.7\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.watchdog.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.watchdog.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.watchdog.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Eurotech\n     \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.emulator.watchdog.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.emulator.watchdog.test/src/test/java/org/eclipse/kura/emulator/watchdog/WatchdogServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.emulator.watchdog;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\n\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.watchdog.CriticalComponent;\nimport org.junit.Test;\nimport org.osgi.service.component.ComponentContext;\n\npublic class WatchdogServiceImplTest {\n\n    @Test\n    public void testActivateDeactivate() throws NoSuchFieldException {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();\n        TestUtil.setFieldValue(svc, \"executor\", executor);\n\n        ComponentContext ccMock = mock(ComponentContext.class);\n        Map<String, Object> properties = new HashMap<>();\n\n        svc.activate(ccMock, properties);\n\n        assertTrue(executor.isTerminated());\n\n        ScheduledExecutorService ex = (ScheduledExecutorService) TestUtil.getFieldValue(svc, \"executor\");\n        assertNotEquals(executor, ex);\n        assertFalse(ex.isShutdown());\n\n        try {\n            Thread.sleep(10); // wait for the executor to start the thread\n        } catch (InterruptedException e) {\n        }\n\n        svc.deactivate(ccMock);\n\n        assertTrue(ex.isTerminated());\n\n        assertNull(TestUtil.getFieldValue(svc, \"executor\"));\n    }\n\n    @Test\n    public void testUpdate() throws NoSuchFieldException {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        ScheduledExecutorService executorMock = Executors.newSingleThreadScheduledExecutor();\n        TestUtil.setFieldValue(svc, \"executor\", executorMock);\n\n        ScheduledFuture futureMock = mock(ScheduledFuture.class);\n        TestUtil.setFieldValue(svc, \"future\", futureMock);\n\n        when(futureMock.isDone()).thenReturn(false).thenReturn(true);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"pingInterval\", 5000);\n        properties.put(\"enabled\", true);\n\n        svc.updated(properties);\n\n        try {\n            Thread.sleep(10); // wait for the executor to start the thread\n        } catch (InterruptedException e) {\n        }\n\n        assertFalse(executorMock.isTerminated());\n        assertTrue((boolean) TestUtil.getFieldValue(svc, \"configEnabled\"));\n        assertEquals(5000, TestUtil.getFieldValue(svc, \"pingInterval\"));\n    }\n\n    @Test\n    public void testRegistrationUnregistration() throws NoSuchFieldException {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        List<CriticalServiceImpl> services = new ArrayList<>();\n        TestUtil.setFieldValue(svc, \"criticalServiceList\", services);\n\n        int timeout = 1500;\n        String name = \"ccName\";\n\n        CriticalComponent criticalComponent = mock(CriticalComponent.class);\n        when(criticalComponent.getCriticalComponentTimeout()).thenReturn(timeout);\n        when(criticalComponent.getCriticalComponentName()).thenReturn(name);\n\n        svc.registerCriticalComponent(criticalComponent);\n\n        assertEquals(1, services.size());\n        assertEquals(timeout, services.get(0).getTimeout());\n\n        // test that it won't be added the second time\n        int timeout2 = 400;\n        CriticalComponent criticalComponent2 = mock(CriticalComponent.class);\n        when(criticalComponent2.getCriticalComponentTimeout()).thenReturn(timeout2);\n        when(criticalComponent2.getCriticalComponentName()).thenReturn(name);\n\n        svc.registerCriticalComponent(criticalComponent2);\n\n        assertEquals(1, services.size());\n        assertEquals(timeout, services.get(0).getTimeout()); // still the same timeout\n\n        // remove the first one\n        svc.unregisterCriticalComponent(criticalComponent2);\n\n        assertTrue(services.isEmpty());\n    }\n\n    @Test\n    public void testCheckin() throws NoSuchFieldException, InterruptedException {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        List<CriticalServiceImpl> services = new ArrayList<>();\n        TestUtil.setFieldValue(svc, \"criticalServiceList\", services);\n\n        int timeout = 1500;\n        String name = \"ccName\";\n\n        CriticalComponent criticalComponent = mock(CriticalComponent.class);\n        when(criticalComponent.getCriticalComponentTimeout()).thenReturn(timeout);\n        when(criticalComponent.getCriticalComponentName()).thenReturn(name);\n\n        svc.registerCriticalComponent(criticalComponent);\n\n        long updated = (long) TestUtil.getFieldValue(services.get(0), \"updated\");\n\n        Thread.sleep(2);\n\n        svc.checkin(criticalComponent);\n\n        long updated2 = (long) TestUtil.getFieldValue(services.get(0), \"updated\");\n\n        assertTrue(updated < updated2);\n    }\n\n    @Test\n    public void testWatchdogLoopReboot() throws Throwable {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        List<CriticalServiceImpl> services = new ArrayList<>();\n        TestUtil.setFieldValue(svc, \"criticalServiceList\", services);\n\n        TestUtil.setFieldValue(svc, \"enabled\", true);\n\n        int timeout = 1500;\n        String name = \"ccTestName\";\n\n        CriticalComponent criticalComponent = mock(CriticalComponent.class);\n        when(criticalComponent.getCriticalComponentTimeout()).thenReturn(timeout);\n        when(criticalComponent.getCriticalComponentName()).thenReturn(name);\n\n        svc.registerCriticalComponent(criticalComponent);\n\n        TestUtil.invokePrivate(svc, \"doWatchdogLoop\");\n    }\n\n    @Test\n    public void testWatchdogLoop() throws Throwable {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        List<CriticalServiceImpl> services = new ArrayList<>();\n        TestUtil.setFieldValue(svc, \"criticalServiceList\", services);\n\n        TestUtil.setFieldValue(svc, \"enabled\", true);\n\n        int timeout = 1;\n        String name = \"ccName\";\n\n        CriticalComponent criticalComponent = mock(CriticalComponent.class);\n        when(criticalComponent.getCriticalComponentTimeout()).thenReturn(timeout);\n        when(criticalComponent.getCriticalComponentName()).thenReturn(name);\n\n        svc.registerCriticalComponent(criticalComponent);\n\n        Thread.sleep(2);\n\n        TestUtil.invokePrivate(svc, \"doWatchdogLoop\");\n    }\n\n    @Test\n    public void testEnableDisable() throws NoSuchFieldException {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        svc.setConfigEnabled(true);\n        assertTrue(svc.isConfigEnabled());\n\n        svc.setConfigEnabled(false);\n        assertFalse(svc.isConfigEnabled());\n\n        svc.startWatchdog();\n        assertTrue((boolean) TestUtil.getFieldValue(svc, \"enabled\"));\n\n        svc.stopWatchdog();\n        assertFalse((boolean) TestUtil.getFieldValue(svc, \"enabled\"));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.event.publisher.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.event.publisher.test\nBundle-SymbolicName: org.eclipse.kura.event.publisher.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.event.publisher\nImport-Package: org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.verification;version=\"1.10.19\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloudconnection;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\"\nBundle-ClassPath: .\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.event.publisher.test/build.properties",
    "content": "#\n#  Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.event.publisher.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n <!--\n    Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n  \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Eurotech\n -->\n <project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n     <artifactId>org.eclipse.kura.event.publisher.test</artifactId>\n     <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n                </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n </project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.event.publisher.test/src/main/java/org/eclipse/kura/event/publisher/test/EventPublisherTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.event.publisher.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.verify;\n\nimport java.lang.reflect.Field;\nimport java.util.HashMap;\nimport java.util.Optional;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.cloudconnection.publisher.CloudPublisher;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.event.publisher.EventPublisher;\nimport org.eclipse.kura.event.publisher.EventPublisherConstants;\nimport org.eclipse.kura.event.publisher.helper.CloudEndpointServiceHelper;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.mockito.ArgumentCaptor;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class EventPublisherTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(EventPublisherTest.class);\n\n    private static EventPublisher eventPublisher;\n    private static CloudEndpointServiceHelper endpoint;\n\n    private static final String EVENT_PUBLISHER_FACTORY_PID = \"org.eclipse.kura.event.publisher.EventPublisher\";\n    private static final String EVENT_PUBLISHER_PID = \"eventPubTest\";\n\n    private Exception occurredException;\n    private KuraMessage message;\n\n    /*\n     * Service tracking\n     */\n\n    @BeforeClass\n    public static void setup()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, NoSuchFieldException,\n            SecurityException, IllegalArgumentException, IllegalAccessException {\n        ConfigurationService configurationService = ServiceUtil\n                .trackService(ConfigurationService.class, Optional.empty()).get(30,\n                TimeUnit.SECONDS);\n\n        configurationService.createFactoryConfiguration(EVENT_PUBLISHER_FACTORY_PID, EVENT_PUBLISHER_PID,\n                new HashMap<>(), false);\n\n        eventPublisher = (EventPublisher) ServiceUtil\n                .trackService(CloudPublisher.class,\n                        Optional.of(\"(\" + ConfigurationService.KURA_SERVICE_PID + \"=\" + EVENT_PUBLISHER_PID + \")\"))\n                .get(30, TimeUnit.SECONDS);\n\n        endpoint = mock(CloudEndpointServiceHelper.class);\n        \n        // substitute the field with a mock to verify interactions\n        Field helperField = eventPublisher.getClass().getDeclaredField(\"cloudHelper\");\n        helperField.setAccessible(true);\n        helperField.set(eventPublisher, endpoint);\n\n        logger.info(\"Dependencies satisfied.\");\n    }\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void nullMessageShouldThrowException() throws InvalidSyntaxException {\n        whenPublish(null);\n        \n        thenIllegalArgumentException();\n    }\n\n    @Test\n    public void shouldPublishMessageCorrectly() throws KuraException {\n        givenKuraMessage(\"test-body\");\n\n        whenPublish(this.message);\n\n        thenNoExceptionsOccurred();\n        thenMessageIsCorrectlyPublished(\"$EVT/#account-name/#client-id/EVENT_TOPIC\", \"test-body\");\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenKuraMessage(String bodyContent) {\n        KuraPayload payload = new KuraPayload();\n        payload.setBody(bodyContent.getBytes());\n        this.message = new KuraMessage(payload);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenPublish(KuraMessage message) {\n        try {\n            eventPublisher.publish(message);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenNoExceptionsOccurred() {\n        assertNull(this.occurredException);\n    }\n\n    private void thenIllegalArgumentException() {\n        assertTrue(this.occurredException instanceof IllegalArgumentException);\n    }\n\n    private void thenMessageIsCorrectlyPublished(String expectedFullTopic, String expectedBody) throws KuraException {\n        ArgumentCaptor<KuraMessage> argument = ArgumentCaptor.forClass(KuraMessage.class);\n\n        verify(endpoint, timeout(5000)).publish(argument.capture());\n        \n        String fullTopic = (String) argument.getValue().getProperties().get(EventPublisherConstants.FULL_TOPIC);\n        boolean control = (Boolean) argument.getValue().getProperties().get(EventPublisherConstants.CONTROL);\n        String body = new String(argument.getValue().getPayload().getBody());\n        \n        assertEquals(expectedFullTopic, fullTopic);\n        assertTrue(control);\n        assertEquals(expectedBody, body);\n    }\n\n    /*\n     * Utilities\n     */\n\n    @Before\n    public void cleanup() {\n        this.occurredException = null;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.event.publisher.test/src/test/java/org/eclipse/kura/event/publisher/test/CloudDeliveryListenersTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.event.publisher.test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.HashMap;\n\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener;\nimport org.eclipse.kura.event.publisher.EventPublisher;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.component.ComponentContext;\n\npublic class CloudDeliveryListenersTest {\n\n    private EventPublisher publisher;\n    private CloudDeliveryListener cloudDeliveryListener = mock(CloudDeliveryListener.class);\n    private CloudEndpoint mockCloudEndpoint = mock(CloudEndpoint.class);\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void cloudDeliveryListenersShouldBeNotified() throws InvalidSyntaxException {\n        givenEventPublisher();\n        givenCloudDeliveryListener();\n\n        whenOnMessageConfirmed(\"1234\");\n\n        thenCloudConnectionDeliveryListenerNotified(\"1234\");\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenEventPublisher() throws InvalidSyntaxException {\n        this.publisher = new EventPublisher();\n\n        ComponentContext mockComponentContext = mock(ComponentContext.class);\n        BundleContext mockBundleContext = mock(BundleContext.class);\n        Filter mockFilter = mock(Filter.class);\n\n        when(mockBundleContext.createFilter(Mockito.any())).thenReturn(mockFilter);\n        when(mockBundleContext.getService(Mockito.any())).thenReturn(mockCloudEndpoint);\n        when(mockBundleContext.ungetService(Mockito.any())).thenReturn(true);\n\n        when(mockComponentContext.getBundleContext()).thenReturn(mockBundleContext);\n\n        this.publisher.activate(mockComponentContext, new HashMap<>());\n    }\n\n    private void givenCloudDeliveryListener() {\n        this.publisher.registerCloudDeliveryListener(this.cloudDeliveryListener);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenOnMessageConfirmed(String messageId) {\n        this.publisher.onMessageConfirmed(messageId);\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenCloudConnectionDeliveryListenerNotified(String messageId) {\n        verify(this.cloudDeliveryListener, timeout(1000).times(1)).onMessageConfirmed(messageId);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.event.publisher.test/src/test/java/org/eclipse/kura/event/publisher/test/CloudEndpointServiceHelperTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.event.publisher.test;\n\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.event.publisher.helper.CloudEndpointServiceHelper;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\n\npublic class CloudEndpointServiceHelperTest {\n\n    private CloudEndpointServiceHelper helper;\n    private BundleContext mockContext;\n    private CloudEndpoint mockCloudEndpoint = mock(CloudEndpoint.class);\n    private Exception occurredException;\n\n    /*\n     * Scenarios\n     */\n\n    /*\n     * Steps\n     */\n\n    @Test\n    public void trackedEndpointShouldPublish() throws InvalidSyntaxException, KuraException {\n        givenCloudEndpointServiceHelper();\n        givenCloudEndpointTracked();\n\n        whenPublish();\n\n        thenNoExceptionOccurred();\n        thenCloudEndpointPublishes(1);\n    }\n\n    @Test\n    public void untrackedEndpointShouldNotPublish() throws InvalidSyntaxException, KuraException {\n        givenCloudEndpointServiceHelper();\n\n        whenPublish();\n\n        thenKuraException();\n        thenCloudEndpointPublishes(0);\n    }\n\n    @Test\n    public void closedHelperShouldNotPublish() throws InvalidSyntaxException, KuraException {\n        givenCloudEndpointServiceHelper();\n        givenCloudEndpointTracked();\n        givenClosedHelper();\n\n        whenPublish();\n\n        thenKuraException();\n        thenCloudEndpointPublishes(0);\n    }\n\n    @Test\n    public void removedCloudEndpointShouldNotPublish() throws InvalidSyntaxException, KuraException {\n        givenCloudEndpointServiceHelper();\n        givenCloudEndpointTracked();\n        givenOnCloudEndpointRemoved();\n\n        whenPublish();\n\n        thenKuraException();\n        thenCloudEndpointPublishes(0);\n    }\n\n    /*\n     * Given\n     */\n\n    private void givenCloudEndpointServiceHelper() throws InvalidSyntaxException {\n        mockContext = mock(BundleContext.class);\n        Filter mockFilter = mock(Filter.class);\n\n        when(mockContext.createFilter(Mockito.any())).thenReturn(mockFilter);\n        when(mockContext.getService(Mockito.any())).thenReturn(mockCloudEndpoint);\n        when(mockContext.ungetService(Mockito.any())).thenReturn(true);\n\n        this.helper = new CloudEndpointServiceHelper(mockContext, \"example-cs\");\n    }\n\n    private void givenCloudEndpointTracked() {\n        this.helper.onCloudEndpointAdded(this.mockCloudEndpoint);\n    }\n\n    private void givenClosedHelper() {\n        this.helper.close();\n    }\n\n    private void givenOnCloudEndpointRemoved() {\n        this.helper.onCloudEndpointRemoved(this.mockCloudEndpoint);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenPublish() {\n        try {\n            this.helper.publish(new KuraMessage(new KuraPayload()));\n        }catch(Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenNoExceptionOccurred() {\n        assertNull(this.occurredException);\n    }\n\n    private void thenKuraException() {\n        assertTrue(this.occurredException instanceof KuraException);\n    }\n\n    private void thenCloudEndpointPublishes(int expectedPublishes) throws KuraException {\n        verify(this.mockCloudEndpoint, times(expectedPublishes)).publish(Mockito.any());\n    }\n\n    /*\n     * Utilities\n     */\n\n    @Before\n    public void cleanup() {\n        this.occurredException = null;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.event.publisher.test/src/test/java/org/eclipse/kura/event/publisher/test/CloudEndpointServiceTrackerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.event.publisher.test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport org.eclipse.kura.cloudconnection.CloudEndpoint;\nimport org.eclipse.kura.event.publisher.helper.CloudEndpointServiceTracker;\nimport org.eclipse.kura.event.publisher.helper.CloudEndpointTrackerListener;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\n\npublic class CloudEndpointServiceTrackerTest {\n\n    private CloudEndpointServiceTracker tracker;\n    private CloudEndpointTrackerListener listener = mock(CloudEndpointTrackerListener.class);\n    @SuppressWarnings(\"unchecked\")\n    private ServiceReference<CloudEndpoint> reference = mock(ServiceReference.class);\n\n    /*\n     * Scenarios\n     */\n\n    /*\n     * Steps\n     */\n\n    @Test\n    public void listenerShouldBeNotifiedWhenServiceAdded() throws InvalidSyntaxException {\n        givenCloudEndpointServiceTracker();\n        givenCloudEndpointTrackerListener();\n\n        whenAddingService();\n\n        thenListenerOnCloudEndpointAdded();\n    }\n\n    @Test\n    public void listenerShouldBeNotifiedWhenServiceRemoved() throws InvalidSyntaxException {\n        givenCloudEndpointServiceTracker();\n        givenCloudEndpointTrackerListener();\n\n        whenRemovingService();\n\n        thenListenerOnCloudEndpointRemoved();\n    }\n\n    /*\n     * Given\n     */\n\n    private void givenCloudEndpointServiceTracker() throws InvalidSyntaxException {\n        BundleContext mockContext = mock(BundleContext.class);\n        Filter mockFilter = mock(Filter.class);\n        CloudEndpoint mockCloudEndpoint = mock(CloudEndpoint.class);\n\n        when(mockContext.createFilter(Mockito.any())).thenReturn(mockFilter);\n        when(mockContext.getService(Mockito.any())).thenReturn(mockCloudEndpoint);\n        when(mockContext.ungetService(Mockito.any())).thenReturn(true);\n\n        this.tracker = new CloudEndpointServiceTracker(mockContext, \"example-cs\");\n    }\n\n    private void givenCloudEndpointTrackerListener() {\n        this.tracker.registerCloudStackTrackerListener(this.listener);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenAddingService() {\n        this.tracker.addingService(this.reference);\n    }\n\n    private void whenRemovingService() {\n        this.tracker.removedService(this.reference, mock(CloudEndpoint.class));\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenListenerOnCloudEndpointAdded() {\n        verify(this.listener, times(1)).onCloudEndpointAdded(Mockito.any());\n    }\n\n    private void thenListenerOnCloudEndpointRemoved() {\n        verify(this.listener, times(1)).onCloudEndpointRemoved(Mockito.any());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.event.publisher.test/src/test/java/org/eclipse/kura/event/publisher/test/EventPublisherOptionsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.event.publisher.test;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.event.publisher.EventPublisherOptions;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class EventPublisherOptionsTest {\n    \n    private EventPublisherOptions options;\n    private Map<String, Object> properties = new HashMap<>();\n    private Object returnedValue;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldReturnTopic() {\n        givenProperty(EventPublisherOptions.TOPIC_PROP_NAME, \"ex.topic\");\n        givenEventPublisherOptions();\n\n        whenGetTopic();\n\n        thenReturnedValueIs(\"ex.topic\");\n    }\n\n    @Test\n    public void shouldReturnTopicWithoutSeparators() {\n        givenProperty(EventPublisherOptions.TOPIC_PROP_NAME, \"/example.topic/\");\n        givenEventPublisherOptions();\n        \n        whenGetTopic();\n        \n        thenReturnedValueIs(\"example.topic\");\n    }\n\n    @Test\n    public void shouldReturnDefaultTopic() {\n        givenEventPublisherOptions();\n\n        whenGetTopic();\n\n        thenReturnedValueIs(EventPublisherOptions.DEFAULT_TOPIC);\n    }\n\n    @Test\n    public void shouldReturnTopicPrefix() {\n        givenProperty(EventPublisherOptions.TOPIC_PREFIX_PROP_NAME, \"top.prefix\");\n        givenEventPublisherOptions();\n\n        whenGetTopicPrefix();\n\n        thenReturnedValueIs(Optional.of(\"top.prefix\"));\n    }\n\n    @Test\n    public void shouldReturnDefaultTopicPrefix() {\n        givenEventPublisherOptions();\n\n        whenGetTopicPrefix();\n\n        thenReturnedValueIs(Optional.empty());\n    }\n\n    @Test\n    public void shouldNotReturnTopicPrefix() {\n        givenProperty(EventPublisherOptions.TOPIC_PREFIX_PROP_NAME, \"\");\n        givenEventPublisherOptions();\n\n        whenGetTopicPrefix();\n\n        thenReturnedValueIs(Optional.empty());\n    }\n\n    @Test\n    public void shouldReturnTopicPrefixWithoutSeparators() {\n        givenProperty(EventPublisherOptions.TOPIC_PREFIX_PROP_NAME, \"/prefix/\");\n        givenEventPublisherOptions();\n\n        whenGetTopicPrefix();\n\n        thenReturnedValueIs(Optional.of(\"prefix\"));\n    }\n\n    @Test\n    public void shouldReturnEndpointPid() {\n        givenProperty(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), \"example.endpoint-1\");\n        givenEventPublisherOptions();\n\n        whenGetCloudEndpointPid();\n\n        thenReturnedValueIs(\"example.endpoint-1\");\n    }\n\n    @Test\n    public void shouldReturnDefaultEndpointPid() {\n        givenEventPublisherOptions();\n\n        whenGetCloudEndpointPid();\n\n        thenReturnedValueIs(EventPublisherOptions.DEFAULT_ENDPOINT_PID);\n    }\n\n    @Test\n    public void shouldReturnQos() {\n        givenProperty(EventPublisherOptions.QOS_PROP_NAME, (int) 1);\n        givenEventPublisherOptions();\n\n        whenGetQos();\n\n        thenReturnedValueIs((int) 1);\n    }\n\n    @Test\n    public void shouldReturnDefaultQos() {\n        givenEventPublisherOptions();\n\n        whenGetQos();\n\n        thenReturnedValueIs(EventPublisherOptions.DEFAULT_QOS);\n    }\n\n    @Test\n    public void shouldReturnRetain() {\n        givenProperty(EventPublisherOptions.RETAIN_PROP_NAME, true);\n        givenEventPublisherOptions();\n\n        whenIsRetain();\n\n        thenReturnedValueIs(true);\n    }\n\n    @Test\n    public void shouldReturnDefaultRetain() {\n        givenEventPublisherOptions();\n\n        whenIsRetain();\n\n        thenReturnedValueIs(EventPublisherOptions.DEFAULT_RETAIN);\n    }\n\n    @Test\n    public void shouldReturnPriority() {\n        givenProperty(EventPublisherOptions.PRIORITY_PROP_NAME, 5);\n        givenEventPublisherOptions();\n\n        whenGetPriority();\n\n        thenReturnedValueIs((int) 5);\n    }\n\n    @Test\n    public void shouldReturnDefaultPriority() {\n        givenEventPublisherOptions();\n\n        whenGetPriority();\n\n        thenReturnedValueIs(EventPublisherOptions.DEFAULT_PRIORITY);\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenProperty(String key, Object value) {\n        this.properties.put(key, value);\n    }\n\n    private void givenEventPublisherOptions() {\n        this.options = new EventPublisherOptions(this.properties);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenGetTopicPrefix() {\n        this.returnedValue = this.options.getTopicPrefix();\n    }\n\n    private void whenGetTopic() {\n        this.returnedValue = this.options.getTopic();\n    }\n\n    private void whenGetPriority() {\n        this.returnedValue = this.options.getPriority();\n    }\n\n    private void whenGetCloudEndpointPid() {\n        this.returnedValue = this.options.getCloudEndpointPid();\n    }\n\n    private void whenIsRetain() {\n        this.returnedValue = this.options.isRetain();\n    }\n\n    private void whenGetQos() {\n        this.returnedValue = this.options.getQos();\n    }\n\n    /*\n     * Then\n     */\n\n    @SuppressWarnings(\"unchecked\")\n    private <T> void thenReturnedValueIs(T expectedValue) {\n        assertEquals(expectedValue, (T) this.returnedValue);\n    }\n\n    /*\n     * Utilities\n     */\n\n    @Before\n    public void cleanup() {\n        this.properties.clear();\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.http.server.manager.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name:  org.eclipse.kura.https.server.manager.test\nBundle-SymbolicName: org.eclipse.kura.http.server.manager.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nRequire-Bundle: org.eclipse.kura.http.server.manager;bundle-version=\"1.1.0\"\nImport-Package: org.bouncycastle.asn1.x500;version=\"1.78.1\",\n org.eclipse.kura;version=\"1.6.0\",\n org.eclipse.kura.configuration;version=\"1.2.0\",\n org.eclipse.kura.core.testutil.event;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.http;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.pki;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"1.3.0\",\n org.eclipse.kura.security.keystore;version=\"1.0.0\",\n org.eclipse.kura.util.wire.test;version=\"1.0.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.event;version=\"1.4.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.25\"\nService-Component: OSGI-INF/*.xml\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.http.server.manager.test/OSGI-INF/org.eclipse.kura.https.server.manager.test.HttpServiceTest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n   Copyright (c) 2021 Eurotech and/or its affiliates and others\n\n   This program and the accompanying materials are made\n   available under the terms of the Eclipse Public License 2.0\n   which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" name=\"org.eclipse.kura.http.server.manager.test\" enabled=\"true\" immediate=\"true\">\n   <implementation class=\"org.eclipse.kura.https.server.manager.test.HttpServiceTest\"/>\n   <reference \n    \tbind=\"setConfigurationService\"\n    \tcardinality=\"1..1\"\n    \tinterface=\"org.eclipse.kura.configuration.ConfigurationService\"\n    \tname=\"ConfigurationService\"\n    \tpolicy=\"static\"/>\n   <reference\n    \tbind=\"setCryptoService\" \n    \tcardinality=\"1..1\" \n    \tinterface=\"org.eclipse.kura.crypto.CryptoService\"\n    \tname=\"CryptoService\" \n    \tpolicy=\"static\"/>\n    <reference name=\"KeystoreService\"\n           policy=\"dynamic\"\n           bind=\"setKeystoreService\"\n           cardinality=\"0..1\"\n           interface=\"org.eclipse.kura.security.keystore.KeystoreService\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.http.server.manager.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.http.server.manager.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nbin.includes = .,\\\n               about.html,\\\n               OSGI-INF/,\\\n               META-INF/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.http.server.manager.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n\tSPDX-License-Identifier: EPL-2.0\n\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.http.server.manager.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.http.server.manager.test/src/main/java/org/eclipse/kura/https/server/manager/test/HttpServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.https.server.manager.test;\n\nimport static org.junit.Assert.fail;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.security.KeyPair;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.UnrecoverableKeyException;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509CRL;\nimport java.security.cert.X509Certificate;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.function.Supplier;\n\nimport javax.net.ssl.HttpsURLConnection;\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.X509TrustManager;\n\nimport org.bouncycastle.asn1.x500.X500Name;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.event.EventAdminUtil;\nimport org.eclipse.kura.core.testutil.http.TestServer;\nimport org.eclipse.kura.core.testutil.pki.TestCA;\nimport org.eclipse.kura.core.testutil.pki.TestCA.CRLCreationOptions;\nimport org.eclipse.kura.core.testutil.pki.TestCA.CertificateCreationOptions;\nimport org.eclipse.kura.core.testutil.pki.TestCA.TestCAException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.security.keystore.KeystoreChangedEvent;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.eclipse.kura.util.wire.test.WireTestUtil;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class HttpServiceTest {\n\n    private static final String TEST_KEYSTORE_PID = \"testKeystore\";\n    private static final Logger logger = LoggerFactory.getLogger(HttpServiceTest.class);\n    private static final String HTTP_SERVER_MANAGER_PID = \"org.eclipse.kura.http.server.manager.HttpService\";\n    private static final String HTTPS_KEYSTORE_SERVICE_PID = \"HttpsKeystore\";\n\n    private static CompletableFuture<ConfigurationService> configurationService = new CompletableFuture<>();\n    private static CompletableFuture<CryptoService> cryptoService = new CompletableFuture<>();\n    private static CompletableFuture<KeystoreService> keystoreService = new CompletableFuture<>();\n\n    private static File serverKeystore;\n    private static File clientKeystore;\n    private static TestCA clientCA;\n    private static X509Certificate clientCertificate;\n\n    public void setConfigurationService(final ConfigurationService configurationService) {\n        HttpServiceTest.configurationService.complete(configurationService);\n    }\n\n    public void setCryptoService(final CryptoService cryptoService) {\n        HttpServiceTest.cryptoService.complete(cryptoService);\n    }\n\n    public void setKeystoreService(final KeystoreService keystoreService) {\n        HttpServiceTest.keystoreService.complete(keystoreService);\n    }\n\n    @BeforeClass\n    public static void setUp() throws TestCAException, IOException {\n\n        final TestCA serverCA = new TestCA(\n                CertificateCreationOptions.builder(new X500Name(\"cn=Server CA, dn=foo.org\")).build());\n\n        final KeyPair serverKeyPair = TestCA.generateKeyPair();\n\n        final X509Certificate serverCertificate = serverCA.createAndSignCertificate(\n                CertificateCreationOptions.builder(new X500Name(\"cn=Server Cert, dn=foo.org\")).build(), serverKeyPair);\n\n        clientCA = new TestCA(CertificateCreationOptions.builder(new X500Name(\"cn=Client CA, dn=bar.org\")).build());\n\n        serverKeystore = TestCA.writeKeystore(\n                new KeyStore.PrivateKeyEntry(serverKeyPair.getPrivate(),\n                        new Certificate[] { serverCertificate, serverCA.getCertificate() }),\n                new KeyStore.TrustedCertificateEntry(clientCA.getCertificate()));\n\n        final KeyPair clientKeyPair = TestCA.generateKeyPair();\n\n        clientCertificate = clientCA.createAndSignCertificate(\n                CertificateCreationOptions.builder(new X500Name(\"cn=admin, dn=bar.org\")).build(), clientKeyPair);\n\n        clientKeystore = TestCA.writeKeystore(new KeyStore.PrivateKeyEntry(clientKeyPair.getPrivate(),\n                new Certificate[] { clientCertificate, clientCA.getCertificate() }));\n    }\n\n    @Test\n    public void shouldNotOpenAnyPortWithDefaultConfig()\n            throws InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        final ConfigurationService configService = configurationService.get(5, TimeUnit.MINUTES);\n\n        updateComponentConfiguration(configService, HTTP_SERVER_MANAGER_PID,\n                HttpServiceOptions.defaultConfiguration().toProperties()).get(30, TimeUnit.SECONDS);\n\n        assertAlwaysTrue(() -> getHttpStatusCode(\"http://localhost:80/\") instanceof Failure);\n        assertAlwaysTrue(() -> getHttpStatusCode(\"http://localhost:8080/\") instanceof Failure);\n        assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4442/\") instanceof Failure);\n        assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4443/\") instanceof Failure);\n\n    }\n\n    @Test\n    public void shouldOpenHttpPorts()\n            throws InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        final ConfigurationService configService = configurationService.get(5, TimeUnit.MINUTES);\n\n        updateComponentConfiguration(configService, HTTP_SERVER_MANAGER_PID,\n                HttpServiceOptions.defaultConfiguration().withHttpPorts(8080).toProperties()).get(30, TimeUnit.SECONDS);\n\n        assertTrueAtLeastOnce(() -> getHttpStatusCode(\"http://localhost:8080/\").equals(new StatusCode(404)));\n\n        assertAlwaysTrue(() -> getHttpStatusCode(\"http://localhost:80/\") instanceof Failure);\n        assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4442/\") instanceof Failure);\n        assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4443/\") instanceof Failure);\n\n    }\n\n    @Test\n    public void shouldOpenMultipleHttpPorts()\n            throws InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        final ConfigurationService configService = configurationService.get(5, TimeUnit.MINUTES);\n\n        updateComponentConfiguration(configService, HTTP_SERVER_MANAGER_PID,\n                HttpServiceOptions.defaultConfiguration().withHttpPorts(8080, 8081, 8082).toProperties()).get(30,\n                        TimeUnit.SECONDS);\n\n        assertTrueAtLeastOnce(() -> getHttpStatusCode(\"http://localhost:8080/\").equals(new StatusCode(404)));\n        assertTrueAtLeastOnce(() -> getHttpStatusCode(\"http://localhost:8081/\").equals(new StatusCode(404)));\n        assertTrueAtLeastOnce(() -> getHttpStatusCode(\"http://localhost:8082/\").equals(new StatusCode(404)));\n\n    }\n\n    @Test\n    public void shouldNotSupportHttpsWithoutKeystore()\n            throws InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        final ConfigurationService configService = configurationService.get(5, TimeUnit.MINUTES);\n\n        updateComponentConfiguration(configService, HTTP_SERVER_MANAGER_PID, HttpServiceOptions.defaultConfiguration()\n                .withHttpsPorts(4442).withHttpsClientAuthPorts(4443).toProperties()).get(30, TimeUnit.SECONDS);\n\n        assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:443/\") instanceof Failure);\n        assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4443/\") instanceof Failure);\n\n    }\n\n    @Test\n    public void shouldSupportHttps() throws Exception {\n\n        final ConfigurationService configSvc = configurationService.get(5, TimeUnit.MINUTES);\n        final CryptoService cryptoSvc = cryptoService.get(5, TimeUnit.MINUTES);\n\n        try (final TestKeystore testKeystore = new TestKeystore(configSvc, cryptoSvc, TEST_KEYSTORE_PID,\n                HttpsKeystoreServiceOptions.defaultConfiguration())) {\n\n            updateComponentConfiguration(configSvc, HTTP_SERVER_MANAGER_PID,\n                    HttpServiceOptions.defaultConfiguration().withHttpsPorts(4442)\n                            .withKeystoreServiceTarget(testKeystore.getTargetFilter()).toProperties()).get(30,\n                                    TimeUnit.SECONDS);\n\n            assertTrueAtLeastOnce(() -> getHttpStatusCode(\"https://localhost:4442/\", Optional.empty(),\n                    Optional.of(buildClientTrustManagers())).equals(new StatusCode(404)));\n            assertAlwaysTrue(() -> getHttpStatusCode(\"http://localhost:8080/\") instanceof Failure);\n            assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4443/\") instanceof Failure);\n            assertAlwaysTrue(() -> getHttpStatusCode(\"http://localhost:80/\") instanceof Failure);\n        }\n    }\n\n    @Test\n    public void shouldSupportHttpsClientAuth() throws Exception {\n\n        final ConfigurationService configSvc = configurationService.get(5, TimeUnit.MINUTES);\n        final CryptoService cryptoSvc = cryptoService.get(5, TimeUnit.MINUTES);\n\n        try (final TestKeystore testKeystore = new TestKeystore(configSvc, cryptoSvc, TEST_KEYSTORE_PID,\n                HttpsKeystoreServiceOptions.defaultConfiguration())) {\n\n            updateComponentConfiguration(configSvc, HTTP_SERVER_MANAGER_PID,\n                    HttpServiceOptions.defaultConfiguration().withHttpsClientAuthPorts(4443)\n                            .withKeystoreServiceTarget(testKeystore.getTargetFilter()).toProperties()).get(30,\n                                    TimeUnit.SECONDS);\n\n            final KeyManager[] keyManagers = buildClientKeyManagers();\n\n            assertTrueAtLeastOnce(() -> getHttpStatusCode(\"https://localhost:4443/\", Optional.of(keyManagers),\n                    Optional.of(buildClientTrustManagers())).equals(new StatusCode(404)));\n            assertAlwaysTrue(() -> getHttpStatusCode(\"http://localhost:8080/\") instanceof Failure);\n            assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4442/\") instanceof Failure);\n            assertAlwaysTrue(() -> getHttpStatusCode(\"http://localhost:80/\") instanceof Failure);\n\n        }\n\n        configSvc.deleteFactoryConfiguration(HTTPS_KEYSTORE_SERVICE_PID, false);\n    }\n\n    @Test\n    public void shouldSupportRevocationCheckWithNoSources() throws Exception {\n\n        final ConfigurationService configSvc = configurationService.get(5, TimeUnit.MINUTES);\n        final CryptoService cryptoSvc = cryptoService.get(5, TimeUnit.MINUTES);\n\n        try (final TestKeystore testKeystore = new TestKeystore(configSvc, cryptoSvc, TEST_KEYSTORE_PID,\n                HttpsKeystoreServiceOptions.defaultConfiguration())) {\n\n            updateComponentConfiguration(configSvc, HTTP_SERVER_MANAGER_PID,\n                    HttpServiceOptions.defaultConfiguration().withHttpsClientAuthPorts(4443)\n                            .withRevocationCheckEnabled(true).withKeystoreServiceTarget(testKeystore.getTargetFilter())\n                            .toProperties()).get(30, TimeUnit.SECONDS);\n\n            final KeyManager[] keyManagers = buildClientKeyManagers();\n\n            assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4443/\", Optional.of(keyManagers),\n                    Optional.of(buildClientTrustManagers())) instanceof Failure);\n            assertAlwaysTrue(() -> getHttpStatusCode(\"http://localhost:8080/\") instanceof Failure);\n            assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4442/\") instanceof Failure);\n            assertAlwaysTrue(() -> getHttpStatusCode(\"http://localhost:80/\") instanceof Failure);\n\n        }\n\n        configSvc.deleteFactoryConfiguration(HTTPS_KEYSTORE_SERVICE_PID, false);\n    }\n\n    @Test\n    public void shouldSupportRevocation() throws Exception {\n        final BundleContext bundleContext = FrameworkUtil.getBundle(HttpServiceTest.class).getBundleContext();\n\n        final TestServer server = new TestServer(8087, Optional.empty());\n\n        final ConfigurationService configSvc = configurationService.get(5, TimeUnit.MINUTES);\n        final CryptoService cryptoSvc = cryptoService.get(5, TimeUnit.MINUTES);\n\n        try (final TestKeystore testKeystore = new TestKeystore(configSvc, cryptoSvc, TEST_KEYSTORE_PID,\n                HttpsKeystoreServiceOptions.defaultConfiguration().withCrlManagerEnabled(true)\n                        .withCrlUrls(new String[] { \"http://localhost:8087/crl.pem\" }))) {\n\n            updateComponentConfiguration(configSvc, HTTP_SERVER_MANAGER_PID,\n                    HttpServiceOptions.defaultConfiguration().withHttpsClientAuthPorts(4443)\n                            .withRevocationCheckEnabled(true).withKeystoreServiceTarget(testKeystore.getTargetFilter())\n                            .toProperties()).get(30, TimeUnit.SECONDS);\n\n            CompletableFuture<KeystoreChangedEvent> nextEvent = EventAdminUtil.nextEvent(\n                    new String[] { KeystoreChangedEvent.EVENT_TOPIC }, KeystoreChangedEvent.class, bundleContext);\n\n            server.setResource(\"/crl.pem\", encodeCrl(clientCA.generateCRL(CRLCreationOptions.builder().build())));\n            nextEvent.get(10, TimeUnit.SECONDS);\n\n            final KeyManager[] keyManagers = buildClientKeyManagers();\n\n            Thread.sleep(10000);\n\n            assertTrueAtLeastOnce(() -> getHttpStatusCode(\"https://localhost:4443/\", Optional.of(keyManagers),\n                    Optional.of(buildClientTrustManagers())).equals(new StatusCode(404)));\n\n            nextEvent = EventAdminUtil.nextEvent(new String[] { KeystoreChangedEvent.EVENT_TOPIC },\n                    KeystoreChangedEvent.class, bundleContext);\n\n            clientCA.revokeCertificate(clientCertificate);\n            server.setResource(\"/crl.pem\", encodeCrl(clientCA.generateCRL(CRLCreationOptions.builder().build())));\n\n            nextEvent.get(10, TimeUnit.SECONDS);\n\n            Thread.sleep(10000);\n\n            assertAlwaysTrue(() -> getHttpStatusCode(\"https://localhost:4443/\", Optional.of(keyManagers),\n                    Optional.of(buildClientTrustManagers())) instanceof Failure);\n\n        } finally {\n            server.close();\n        }\n    }\n\n    @Test\n    public void shouldRejectClientConnectionWithNoCert() throws Exception {\n\n        final ConfigurationService configSvc = configurationService.get(5, TimeUnit.MINUTES);\n        final CryptoService cryptoSvc = cryptoService.get(5, TimeUnit.MINUTES);\n\n        try (final TestKeystore testKeystore = new TestKeystore(configSvc, cryptoSvc, TEST_KEYSTORE_PID,\n                HttpsKeystoreServiceOptions.defaultConfiguration())) {\n\n            updateComponentConfiguration(configSvc, HTTP_SERVER_MANAGER_PID,\n                    HttpServiceOptions.defaultConfiguration().withHttpsClientAuthPorts(4443)\n                            .withKeystoreServiceTarget(testKeystore.getTargetFilter()).toProperties()).get(30,\n                                    TimeUnit.SECONDS);\n\n            assertTrueAtLeastOnce(() -> getHttpStatusCode(\"https://localhost:4443/\", Optional.empty(),\n                    Optional.of(buildClientTrustManagers())) instanceof Failure);\n\n        }\n    }\n\n    @Test\n    public void shouldSupportAllAuthMethods() throws Exception {\n\n        final ConfigurationService configSvc = configurationService.get(5, TimeUnit.MINUTES);\n        final CryptoService cryptoSvc = cryptoService.get(5, TimeUnit.MINUTES);\n\n        try (final TestKeystore testKeystore = new TestKeystore(configSvc, cryptoSvc, TEST_KEYSTORE_PID,\n                HttpsKeystoreServiceOptions.defaultConfiguration())) {\n\n            updateComponentConfiguration(configSvc, HTTP_SERVER_MANAGER_PID,\n                    HttpServiceOptions.defaultConfiguration().withHttpPorts(8080).withHttpsPorts(4442)\n                            .withHttpsClientAuthPorts(4443).withKeystoreServiceTarget(testKeystore.getTargetFilter())\n                            .toProperties()).get(30, TimeUnit.SECONDS);\n\n            final KeyManager[] keyManagers = buildClientKeyManagers();\n\n            assertTrueAtLeastOnce(() -> getHttpStatusCode(\"https://localhost:4443/\", Optional.of(keyManagers),\n                    Optional.of(buildClientTrustManagers())).equals(new StatusCode(404)));\n            assertTrueAtLeastOnce(() -> getHttpStatusCode(\"http://localhost:8080/\").equals(new StatusCode(404)));\n            assertTrueAtLeastOnce(() -> getHttpStatusCode(\"https://localhost:4442/\", Optional.empty(),\n                    Optional.of(buildClientTrustManagers())).equals(new StatusCode(404)));\n        }\n\n    }\n\n    private static byte[] encodeCrl(final X509CRL crl) throws IOException {\n        final byte[] crlData;\n\n        try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {\n            TestCA.encodeToPEM(crl, out);\n            crlData = out.toByteArray();\n        }\n\n        return crlData;\n    }\n\n    private static class TestKeystore implements AutoCloseable {\n\n        private final ConfigurationService configSvc;\n        private final String pid;\n\n        public TestKeystore(final ConfigurationService configSvc, final CryptoService cryptoSvc, final String pid,\n                final HttpsKeystoreServiceOptions options)\n                throws InterruptedException, ExecutionException, TimeoutException, KuraException {\n            this.configSvc = configSvc;\n            this.pid = pid;\n\n            WireTestUtil\n                    .createFactoryConfiguration(configSvc, ConfigurableComponent.class, pid,\n                            \"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\",\n                            options.withKeystorePath(serverKeystore.getAbsolutePath())\n                                    .withKeystorePassword(\"changeit\", cryptoSvc).toProperties())\n                    .get(30, TimeUnit.SECONDS);\n        }\n\n        String getTargetFilter() {\n            return \"(kura.service.pid=\" + pid + \")\";\n        }\n\n        @Override\n        public void close() throws Exception {\n            WireTestUtil.deleteFactoryConfiguration(configSvc, pid).get(30, TimeUnit.SECONDS);\n        }\n\n    }\n\n    private static class HttpsKeystoreServiceOptions {\n\n        private String keystorePath = \"\";\n        private String keystorePassword = \"\";\n        private boolean crlManagerEnabled = false;\n        private Optional<String[]> crlUrls = Optional.empty();\n\n        private HttpsKeystoreServiceOptions() {\n        }\n\n        static HttpsKeystoreServiceOptions defaultConfiguration() {\n            return new HttpsKeystoreServiceOptions();\n        }\n\n        HttpsKeystoreServiceOptions withKeystorePath(final String keystorePath) {\n            this.keystorePath = keystorePath;\n            return this;\n        }\n\n        HttpsKeystoreServiceOptions withKeystorePassword(final String keystorePassword,\n                final CryptoService cryptoService) throws KuraException {\n            this.keystorePassword = new String(cryptoService.encryptAes(keystorePassword.toCharArray()));\n            return this;\n        }\n\n        HttpsKeystoreServiceOptions withCrlManagerEnabled(boolean crlManagerEnabled) {\n            this.crlManagerEnabled = crlManagerEnabled;\n            return this;\n        }\n\n        HttpsKeystoreServiceOptions withCrlUrls(String[] crlUrls) {\n            this.crlUrls = Optional.of(crlUrls);\n            return this;\n        }\n\n        Map<String, Object> toProperties() {\n            final Map<String, Object> result = new HashMap<>();\n\n            result.put(\"keystore.path\", this.keystorePath);\n            result.put(\"keystore.password\", this.keystorePassword);\n            result.put(\"crl.check.interval\", 1L);\n            result.put(\"crl.check.interval.time.unit\", TimeUnit.SECONDS.name());\n            result.put(\"crl.update.interval\", 1L);\n            result.put(\"crl.update.interval.time.unit\", TimeUnit.SECONDS.name());\n            result.put(\"crl.management.enabled\", crlManagerEnabled);\n            this.crlUrls.ifPresent(u -> result.put(\"crl.urls\", u));\n\n            return result;\n        }\n\n    }\n\n    private static class HttpServiceOptions {\n\n        private Integer[] httpPorts = new Integer[] {};\n        private Integer[] httpsPorts = new Integer[] {};\n        private Integer[] httpsClientAuthPorts = new Integer[] {};\n        private Optional<String> keystoreServiceTarget = Optional.empty();\n        private Optional<Boolean> revocationCheckEnabled = Optional.empty();\n\n        private HttpServiceOptions() {\n        }\n\n        static HttpServiceOptions defaultConfiguration() {\n            return new HttpServiceOptions();\n        }\n\n        HttpServiceOptions withHttpPorts(final Integer... httpPorts) {\n            this.httpPorts = httpPorts;\n            return this;\n        }\n\n        HttpServiceOptions withHttpsPorts(final Integer... httpsPorts) {\n            this.httpsPorts = httpsPorts;\n            return this;\n        }\n\n        HttpServiceOptions withHttpsClientAuthPorts(final Integer... httpsClientAuthPorts) {\n            this.httpsClientAuthPorts = httpsClientAuthPorts;\n            return this;\n        }\n\n        HttpServiceOptions withKeystoreServiceTarget(final String target) {\n            this.keystoreServiceTarget = Optional.of(target);\n            return this;\n        }\n\n        HttpServiceOptions withRevocationCheckEnabled(final boolean enabled) {\n            this.revocationCheckEnabled = Optional.of(enabled);\n            return this;\n        }\n\n        Map<String, Object> toProperties() {\n            final Map<String, Object> result = new HashMap<>();\n\n            result.put(\"http.ports\", this.httpPorts);\n            result.put(\"https.ports\", this.httpsPorts);\n            result.put(\"https.client.auth.ports\", this.httpsClientAuthPorts);\n            this.revocationCheckEnabled.ifPresent(v -> result.put(\"https.revocation.check.enabled\", v));\n            result.put(\"KeystoreService.target\", this.keystoreServiceTarget.orElse(\"(kura.service.pid=changeit)\"));\n\n            return result;\n        }\n\n    }\n\n    private interface ConnectionResult {\n    }\n\n    private static class StatusCode implements ConnectionResult {\n\n        private final int value;\n\n        StatusCode(final int value) {\n            super();\n            this.value = value;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(this.value);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (obj == null) {\n                return false;\n            }\n            if (getClass() != obj.getClass()) {\n                return false;\n            }\n            StatusCode other = (StatusCode) obj;\n            return this.value == other.value;\n        }\n\n        @Override\n        public String toString() {\n            return \"StatusCode [value=\" + this.value + \"]\";\n        }\n\n    }\n\n    private static class Failure implements ConnectionResult {\n\n        private final Throwable cause;\n\n        Failure(Throwable cause) {\n            this.cause = cause;\n        }\n\n        @Override\n        public String toString() {\n            return \"Failure [cause=\" + this.cause + \"]\";\n        }\n\n    }\n\n    private static ConnectionResult getHttpStatusCode(final String url) {\n        return getHttpStatusCode(url, Optional.empty(), Optional.empty());\n    }\n\n    private static ConnectionResult getHttpStatusCode(final String url, final Optional<KeyManager[]> keyManagers,\n            final Optional<TrustManager[]> trustManagers) {\n        try {\n            final HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();\n\n            logger.info(\"trying {}\", url);\n\n            if (connection instanceof HttpsURLConnection) {\n                final HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;\n\n                final SSLContext context = SSLContext.getInstance(\"TLS\");\n\n                context.init(keyManagers.orElse(null), trustManagers.orElse(null), null);\n\n                HttpsURLConnection.setDefaultHostnameVerifier((h, s) -> true);\n                HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());\n\n                httpsConnection.setHostnameVerifier((h, s) -> true);\n            }\n\n            return new StatusCode(connection.getResponseCode());\n        } catch (final Exception e) {\n            return new Failure(e);\n        }\n    }\n\n    private static void assertAlwaysTrue(final Supplier<Boolean> check) throws InterruptedException {\n        for (int i = 0; i < 3; i++) {\n\n            if (!check.get()) {\n                fail(\"should have been true\");\n            }\n\n            Thread.sleep(1000);\n        }\n    }\n\n    private static void assertTrueAtLeastOnce(final Supplier<Boolean> check) throws InterruptedException {\n        for (int i = 0; i < 3; i++) {\n\n            if (check.get()) {\n                return;\n            }\n\n            Thread.sleep(1000);\n        }\n\n        fail(\"should have been true at least once\");\n    }\n\n    static CompletableFuture<Void> updateComponentConfiguration(final ConfigurationService configurationService,\n            final String pid, final Map<String, Object> properties) throws InvalidSyntaxException {\n\n        final CompletableFuture<Void> result = new CompletableFuture<>();\n        final BundleContext context = FrameworkUtil.getBundle(WireTestUtil.class).getBundleContext();\n\n        final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();\n\n        final ServiceTracker<?, ?> tracker = new ServiceTracker<>(context,\n                FrameworkUtil.createFilter(\"(kura.service.pid=\" + pid + \")\"),\n                new ServiceTrackerCustomizer<Object, Object>() {\n\n                    Optional<ScheduledFuture<?>> task = Optional.empty();\n\n                    @Override\n                    public Object addingService(ServiceReference<Object> reference) {\n\n                        task = Optional.of(executor.schedule(() -> {\n                            try {\n                                configurationService.updateConfiguration(pid, properties);\n                            } catch (KuraException e) {\n                                throw new RuntimeException(e);\n                            }\n                        }, 5, TimeUnit.SECONDS));\n\n                        return context.getService(reference);\n                    }\n\n                    @Override\n                    public void modifiedService(ServiceReference<Object> reference, Object service) {\n                        result.complete(null);\n                    }\n\n                    @Override\n                    public void removedService(ServiceReference<Object> reference, Object service) {\n                        context.ungetService(reference);\n                        final Optional<ScheduledFuture<?>> currentTask = task;\n                        if (currentTask.isPresent()) {\n                            currentTask.get().cancel(false);\n                            task = Optional.empty();\n                        }\n                    }\n                });\n\n        tracker.open();\n\n        return result.whenComplete((ok, ex) -> {\n            tracker.close();\n            executor.shutdown();\n        });\n    }\n\n    private static KeyManager[] buildClientKeyManagers() throws KeyStoreException, NoSuchAlgorithmException,\n            CertificateException, IOException, UnrecoverableKeyException {\n        final KeyStore keystore = KeyStore.getInstance(\"JKS\");\n        try (final FileInputStream in = new FileInputStream(clientKeystore)) {\n            keystore.load(in, \"changeit\".toCharArray());\n        }\n\n        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(\"SunX509\");\n        keyManagerFactory.init(keystore, \"changeit\".toCharArray());\n\n        return keyManagerFactory.getKeyManagers();\n    }\n\n    private static TrustManager[] buildClientTrustManagers() {\n        final TrustManager trustManager = new X509TrustManager() {\n\n            @Override\n            public X509Certificate[] getAcceptedIssuers() {\n                return null;\n            }\n\n            @Override\n            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n                // accept\n            }\n\n            @Override\n            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {\n                // accept\n            }\n        };\n\n        return new TrustManager[] { trustManager };\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.internal.driver.s7plc.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.internal.driver.s7plc.test\nBundle-SymbolicName: org.eclipse.kura.internal.driver.s7plc.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.driver.s7plc.provider\nImport-Package: org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.driver.binary;version=\"[1.0.0,2.0.0)\",\n org.eclipse.kura.driver.block;version=\"[1.0.0,2.0.0)\",\n org.eclipse.kura.driver.block.task;version=\"[1.0.0,2.0.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.7\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.internal.driver.s7plc.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.internal.driver.s7plc.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.internal.driver.s7plc.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Eurotech\n     \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.internal.driver.s7plc.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.internal.driver.s7plc.test/src/test/java/org/eclipse/kura/internal/driver/s7plc/S7PlcChannelDescriptorTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.driver.s7plc;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\n\nimport java.util.List;\n\nimport org.eclipse.kura.core.configuration.metatype.Tad;\nimport org.junit.Test;\n\n\npublic class S7PlcChannelDescriptorTest {\n\n    @Test\n    public void testGetDescriptor() {\n        S7PlcChannelDescriptor descriptor = new S7PlcChannelDescriptor();\n\n        List<Tad> result = (List<Tad>) descriptor.getDescriptor();\n\n        assertNotNull(result);\n        assertEquals(5, result.size());\n\n        assertEquals(\"s7.data.type\", result.get(0).getName());\n        assertEquals(S7PlcDataType.values().length, result.get(0).getOption().size());\n\n        assertEquals(\"data.block.no\", result.get(1).getName());\n        assertEquals(\"offset\", result.get(2).getName());\n        assertEquals(\"byte.count\", result.get(3).getName());\n        assertEquals(\"bit.index\", result.get(4).getName());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.internal.driver.s7plc.test/src/test/java/org/eclipse/kura/internal/driver/s7plc/S7PlcDriverTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.driver.s7plc;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.driver.ChannelDescriptor;\nimport org.eclipse.kura.driver.Driver.ConnectionException;\nimport org.eclipse.kura.driver.block.BlockFactory;\nimport org.eclipse.kura.driver.block.task.BlockTask;\nimport org.eclipse.kura.driver.block.task.Mode;\nimport org.eclipse.kura.driver.block.task.ToplevelBlockTask;\nimport org.junit.Test;\n\nimport Moka7.S7;\nimport Moka7.S7Client;\n\npublic class S7PlcDriverTest {\n\n    public static S7PlcDriver createTestDriver(final S7Client client) {\n        return new S7PlcDriver() {\n\n            @Override\n            protected S7ClientState createClientState(S7PlcOptions options) {\n\n                return new S7ClientState(options, client);\n            }\n        };\n    }\n\n    @Test\n    public void testActivate() {\n        // test that properties should not be null, but may be empty\n\n        S7PlcDriver svc = new S7PlcDriver();\n\n        try {\n            svc.activate(null);\n            fail(\"Exception was expected.\");\n        } catch (NullPointerException e) {\n            // OK\n        }\n\n        svc.activate(new HashMap<String, Object>());\n    }\n\n    @Test\n    public void testDeactivate() throws NoSuchFieldException, ConnectionException {\n        // check that deactivate tries to disconnect the client\n\n        S7Client s7Mock = mock(S7Client.class);\n\n        S7PlcDriver svc = createTestDriver(s7Mock);\n\n        svc.activate(Collections.emptyMap());\n\n        // deactivate a disconnected driver\n        svc.deactivate();\n\n        verify(s7Mock, times(0)).Disconnect();\n\n        svc.activate(Collections.emptyMap());\n\n        svc.connect();\n        // deactivate a connected driver\n        s7Mock.Connected = true;\n\n        svc.deactivate();\n\n        verify(s7Mock, times(1)).Disconnect();\n    }\n\n    @Test\n    public void testUpdated() throws NoSuchFieldException, ConnectionException {\n        // update causes disconnect and reconnect of a connected client; test normal reconnect\n\n        String address = \"127.0.0.1\";\n        int rack = 1;\n        int slot = 1;\n\n        S7Client s7Mock = mock(S7Client.class);\n        S7PlcDriver svc = createTestDriver(s7Mock);\n\n        svc.activate(Collections.emptyMap());\n\n        doAnswer(invocation -> {\n            s7Mock.Connected = false; // set it to false so that connection attempt can be made later on\n\n            return null;\n        }).when(s7Mock).Disconnect();\n\n        when(s7Mock.ConnectTo(address, rack, slot)).thenReturn(0);\n\n        svc.connect();\n        s7Mock.Connected = true;\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"host.ip\", address);\n        properties.put(\"rack\", rack);\n        properties.put(\"slot\", slot);\n\n        svc.updated(properties);\n\n        svc.connect();\n\n        verify(s7Mock, times(1)).Disconnect();\n        verify(s7Mock, times(1)).ConnectTo(address, rack, slot);\n    }\n\n    @Test(expected = Exception.class)\n    public void testAuthenticateExceptionWithPassword() throws Throwable {\n        // check that an exception is thrown in case password decryption fails\n\n        String pass = \"pass\";\n\n        S7Client s7Mock = mock(S7Client.class);\n        S7PlcDriver svc = createTestDriver(s7Mock);\n\n        CryptoService csMock = mock(CryptoService.class);\n        svc.setCryptoService(csMock);\n\n        when(csMock.decryptAes(pass.toCharArray()))\n                .thenThrow(new KuraException(KuraErrorCode.CONFIGURATION_ERROR, \"test\"));\n\n        Map<String, Object> properties = new HashMap<>();\n\n        properties.put(\"password\", pass);\n        properties.put(\"authenticate\", true);\n\n        svc.updated(properties);\n        svc.connect();\n    }\n\n    @Test(expected = Exception.class)\n    public void testAuthenticateWithException() throws Throwable {\n        // check that an exception is thrown when session password fails to be set in the client\n\n        String pass = \"pass\";\n        String dec = \"dec\";\n\n        S7Client s7Mock = mock(S7Client.class);\n        S7PlcDriver svc = createTestDriver(s7Mock);\n\n        when(s7Mock.SetSessionPassword(dec)).thenReturn(123);\n\n        CryptoService csMock = mock(CryptoService.class);\n        svc.setCryptoService(csMock);\n\n        when(csMock.decryptAes(pass.toCharArray())).thenReturn(dec.toCharArray());\n\n        Map<String, Object> properties = new HashMap<>();\n\n        properties.put(\"password\", pass);\n        properties.put(\"authenticate\", true);\n\n        svc.updated(properties);\n        svc.connect();\n    }\n\n    @Test\n    public void testAuthenticate() throws Throwable {\n        // test successful authentication\n\n        String pass = \"pass\";\n        String dec = \"dec\";\n\n        S7Client s7Mock = mock(S7Client.class);\n        S7PlcDriver svc = createTestDriver(s7Mock);\n\n        when(s7Mock.SetSessionPassword(dec)).thenReturn(0);\n\n        CryptoService csMock = mock(CryptoService.class);\n        svc.setCryptoService(csMock);\n\n        when(csMock.decryptAes(pass.toCharArray())).thenReturn(dec.toCharArray());\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"password\", pass);\n        svc.updated(properties);\n\n        TestUtil.invokePrivate(svc, \"authenticate\");\n    }\n\n    @Test\n    public void testReadMinimumGapSizeForDomain() {\n        // test that gap size is returned regardless of the domain, but a default is set\n\n        S7PlcDriver svc = new S7PlcDriver();\n\n        // default value\n        Map<String, Object> properties = new HashMap<>();\n        svc.updated(properties);\n\n        int size = svc.getReadMinimumGapSizeForDomain(null);\n\n        assertEquals(0, size);\n\n        // set value from options\n        int gapSize = 1234;\n        properties.put(\"read.minimum.gap.size\", gapSize);\n        svc.updated(properties);\n\n        size = svc.getReadMinimumGapSizeForDomain(null);\n\n        assertEquals(gapSize, size);\n    }\n\n    @Test\n    public void testGetTaskFactoryForDomain() {\n        S7PlcDriver svc = new S7PlcDriver();\n\n        S7PlcDomain domain = new S7PlcDomain(3);\n        Mode mode = Mode.READ;\n        BlockFactory<ToplevelBlockTask> factory = svc.getTaskFactoryForDomain(domain, mode);\n\n        assertNotNull(factory);\n\n        ToplevelBlockTask task = factory.build(1, 2);\n\n        assertEquals(mode, task.getMode());\n        assertEquals(1, task.getStart());\n        assertEquals(2, task.getEnd());\n    }\n\n    @Test\n    public void testGetChannelDescriptor() {\n        S7PlcDriver svc = new S7PlcDriver();\n\n        ChannelDescriptor descriptor = svc.getChannelDescriptor();\n\n        assertNotNull(descriptor);\n    }\n\n    @Test\n    public void testRunTask() throws IOException {\n        S7PlcDriver svc = new S7PlcDriver();\n\n        BlockTask task = mock(BlockTask.class);\n\n        svc.runTask(task);\n\n        verify(task, times(1)).run();\n    }\n\n    @Test\n    public void testRunTaskWithGeneralException() throws IOException {\n        // test that exceptions are 'handled' during read/write\n\n        S7PlcDriver svc = new S7PlcDriver();\n\n        BlockTask task = mock(BlockTask.class);\n        doThrow(new IOException(\"test\")).when(task).run();\n\n        svc.runTask(task); // no exception is expected\n\n        verify(task, times(1)).run();\n    }\n\n    @Test\n    public void testRunTaskWithReadMoka7Exception() throws IOException, NoSuchFieldException, ConnectionException {\n        // test what happens if read returns just the right value != 0 and Moka7Exception is thrown\n\n        int db = 3;\n        int offset = 0;\n        byte[] data = new byte[4];\n\n        S7Client s7Mock = mock(S7Client.class);\n        S7PlcDriver svc = createTestDriver(s7Mock);\n\n        svc.activate(Collections.emptyMap());\n        svc.connect();\n        s7Mock.Connected = true;\n\n        // result != 0 causes exception\n        when(s7Mock.ReadArea(S7.S7AreaDB, db, offset, data.length, data)).thenReturn(4);\n\n        BlockTask task = mock(BlockTask.class);\n        doAnswer(invocation -> {\n            svc.read(db, offset, data);\n            return null;\n        }).when(task).run();\n\n        svc.runTask(task); // no exception is expected\n\n        verify(task, times(1)).run();\n        verify(s7Mock, times(1)).ReadArea(S7.S7AreaDB, db, offset, data.length, data);\n        verify(s7Mock, times(1)).Disconnect();\n    }\n\n    @Test(expected = IOException.class)\n    public void testWrite() throws NoSuchFieldException, IOException, ConnectionException {\n        // test that exception is thrown as a result of an unsuccessful write\n\n        int db = 3;\n        int offset = 0;\n        byte[] data = new byte[4];\n\n        S7Client s7Mock = mock(S7Client.class);\n        S7PlcDriver svc = createTestDriver(s7Mock);\n        svc.activate(Collections.emptyMap());\n\n        // result != 0 causes exception\n        when(s7Mock.WriteArea(S7.S7AreaDB, db, offset, data.length, data)).thenReturn(3);\n\n        svc.connect();\n\n        svc.write(db, offset, data);\n\n        verify(s7Mock, times(1)).WriteArea(S7.S7AreaDB, db, offset, data.length, data);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.internal.driver.s7plc.test/src/test/java/org/eclipse/kura/internal/driver/s7plc/task/S7PlcTaskBuilderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.driver.s7plc.task;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.driver.binary.BinaryData;\nimport org.eclipse.kura.driver.binary.BinaryDataTypes;\nimport org.eclipse.kura.driver.block.task.AbstractBlockDriver.Pair;\nimport org.eclipse.kura.driver.block.task.BinaryDataTask;\nimport org.eclipse.kura.driver.block.task.BitTask;\nimport org.eclipse.kura.driver.block.task.BlockTask;\nimport org.eclipse.kura.driver.block.task.ByteArrayTask;\nimport org.eclipse.kura.driver.block.task.Mode;\nimport org.eclipse.kura.driver.block.task.StringTask;\nimport org.eclipse.kura.internal.driver.s7plc.S7PlcDataType;\nimport org.eclipse.kura.internal.driver.s7plc.S7PlcDomain;\nimport org.eclipse.kura.type.DataType;\nimport org.junit.Test;\n\npublic class S7PlcTaskBuilderTest {\n\n    @Test\n    public void testBuildTypes() {\n        List<ChannelRecord> records = new ArrayList<>();\n\n        for (S7PlcDataType type : S7PlcDataType.values()) {\n            DataType channelType = DataType.DOUBLE;\n            if (S7PlcDataType.BOOL.equals(type)) {\n                channelType = DataType.BOOLEAN;\n            } else if (S7PlcDataType.CHAR.equals(type)) {\n                channelType = DataType.STRING;\n            }\n            records.add(createChannelRecord(type.name(), type.ordinal(), channelType));\n        }\n\n        records.add(createChannelRecord(\"BYTE_ARRAY\", 123, DataType.BYTE_ARRAY));\n\n        // exception => null => not added\n        records.add(createChannelRecord(\"BYTE_ARRAY\", 124, DataType.BYTE_ARRAY, false));\n\n        Mode mode = Mode.READ;\n\n        Stream<Pair<S7PlcDomain, BlockTask>> stream = S7PlcTaskBuilder.build(records, mode);\n\n        AtomicInteger count = new AtomicInteger(0);\n        stream.forEach(action -> {\n            int idx = count.getAndIncrement();\n\n            BlockTask second = action.getSecond();\n\n            if (idx < 8) {\n                assertEquals(idx, second.getStart());\n                assertEquals(mode, second.getMode());\n\n                if (S7PlcDataType.INT.ordinal() == second.getStart()) {\n                    assertTrue(second instanceof BinaryDataTask);\n                    assertExpectedType(BinaryDataTypes.INT16_BE, second);\n                }\n                if (S7PlcDataType.DINT.ordinal() == second.getStart()) {\n                    assertTrue(second instanceof BinaryDataTask);\n                    assertExpectedType(BinaryDataTypes.INT32_BE, second);\n                }\n                if (S7PlcDataType.WORD.ordinal() == second.getStart()) {\n                    assertTrue(second instanceof BinaryDataTask);\n                    assertExpectedType(BinaryDataTypes.UINT16_BE, second);\n                }\n                if (S7PlcDataType.DWORD.ordinal() == second.getStart()) {\n                    assertTrue(second instanceof BinaryDataTask);\n                    assertExpectedType(BinaryDataTypes.UINT32_BE, second);\n                }\n                if (S7PlcDataType.BYTE.ordinal() == second.getStart()) {\n                    assertTrue(second instanceof BinaryDataTask);\n                    assertExpectedType(BinaryDataTypes.UINT8, second);\n                }\n                if (S7PlcDataType.REAL.ordinal() == second.getStart()) {\n                    assertTrue(second instanceof BinaryDataTask);\n                    assertExpectedType(BinaryDataTypes.FLOAT_BE, second);\n                }\n                if (S7PlcDataType.CHAR.ordinal() == second.getStart()) {\n                    assertTrue(second instanceof StringTask);\n                }\n                if (S7PlcDataType.BOOL.ordinal() == second.getStart()) {\n                    assertTrue(second instanceof BitTask);\n                }\n            } else {\n                assertEquals(123, second.getStart());\n                assertTrue(second instanceof ByteArrayTask);\n            }\n        });\n\n        assertEquals(9, count.get());\n    }\n\n    private void assertExpectedType(BinaryData type, BlockTask second) {\n        try {\n            assertEquals(type, TestUtil.getFieldValue(second, \"dataType\"));\n        } catch (NoSuchFieldException e) {\n            fail(e.getMessage());\n        }\n    }\n\n    private ChannelRecord createChannelRecord(String type, int ord, DataType channelType) {\n        return createChannelRecord(type, ord, channelType, true);\n    }\n\n    private ChannelRecord createChannelRecord(String type, int ord, DataType channelType, boolean addCount) {\n        ChannelRecord channel = ChannelRecord.createReadRecord(\"ch1\", channelType);\n\n        Map<String, Object> config = new HashMap<>();\n        config.put(\"data.block.no\", ord);\n        config.put(\"offset\", ord);\n        config.put(\"s7.data.type\", type);\n        config.put(\"bit.index\", ord); // required for BOOL\n        if (addCount) {\n            config.put(\"byte.count\", ord); // required for CHAR and byte array\n        }\n        channel.setChannelConfig(config);\n\n        return channel;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.internal.driver.s7plc.test/src/test/java/org/eclipse/kura/internal/driver/s7plc/task/S7PlcToplevelBlockTaskTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.driver.s7plc.task;\n\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.util.Collections;\n\nimport org.eclipse.kura.driver.Driver.ConnectionException;\nimport org.eclipse.kura.driver.block.task.Mode;\nimport org.eclipse.kura.internal.driver.s7plc.S7PlcDriver;\nimport org.eclipse.kura.internal.driver.s7plc.S7PlcDriverTest;\nimport org.junit.Test;\n\nimport Moka7.S7;\nimport Moka7.S7Client;\n\npublic class S7PlcToplevelBlockTaskTest {\n\n    @Test\n    public void testProcessBufferRead() throws IOException, NoSuchFieldException, ConnectionException {\n\n        S7Client s7Mock = mock(S7Client.class);\n        S7PlcDriver driver = S7PlcDriverTest.createTestDriver(s7Mock);\n\n        driver.activate(Collections.emptyMap());\n        driver.connect();\n\n        int db = 3;\n        int start = 0;\n\n        when(s7Mock.ReadArea(eq(S7.S7AreaDB), eq(db), eq(start), eq(5), any())).thenReturn(0);\n\n        Mode mode = Mode.READ;\n        int end = 5;\n        S7PlcToplevelBlockTask task = new S7PlcToplevelBlockTask(driver, mode, db, start, end);\n\n        task.processBuffer();\n\n        verify(s7Mock, times(1)).ReadArea(eq(S7.S7AreaDB), eq(db), eq(start), eq(5), any());\n    }\n\n    @Test\n    public void testProcessBufferWrite() throws IOException, NoSuchFieldException, ConnectionException {\n\n        S7Client s7Mock = mock(S7Client.class);\n        S7PlcDriver driver = S7PlcDriverTest.createTestDriver(s7Mock);\n\n        driver.activate(Collections.emptyMap());\n        driver.connect();\n\n        int db = 3;\n        int start = 0;\n\n        when(s7Mock.WriteArea(eq(S7.S7AreaDB), eq(db), eq(start), eq(5), any())).thenReturn(0);\n\n        Mode mode = Mode.UPDATE;\n        int end = 5;\n        S7PlcToplevelBlockTask task = new S7PlcToplevelBlockTask(driver, mode, db, start, end);\n\n        task.processBuffer();\n\n        verify(s7Mock, times(1)).WriteArea(eq(S7.S7AreaDB), eq(db), eq(start), eq(5), any());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.json.marshaller.unmarshaller.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Wire Provider Test\nBundle-SymbolicName: org.eclipse.kura.json.marshaller.unmarshaller.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nFragment-Host: org.eclipse.kura.json.marshaller.unmarshaller.provider;bundle-version=\"[2.0,3.0)\"\nBundle-ActivationPolicy: lazy\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.testutil;version=\"[1.0,2.0)\",\n org.eclipse.kura.internal.json.marshaller.unmarshaller;version=\"[1.1,1.2)\",\n org.eclipse.kura.message;version=\"[1.2,2.0)\",\n org.eclipse.kura.wire;version=\"[2.0,3.0)\",\n org.eclipse.kura.wire.graph;version=\"[1.0,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.json.marshaller.unmarshaller.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.json.marshaller.unmarshaller.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.json.marshaller.unmarshaller.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.json.marshaller.unmarshaller.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.json.marshaller.unmarshaller.provider.test/src/test/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/keystore/test/KeystoreEntryInfoMapperTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.keystore.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.StringReader;\n\nimport org.eclipse.kura.core.keystore.util.CertificateInfo;\nimport org.eclipse.kura.core.keystore.util.EntryInfo;\nimport org.eclipse.kura.core.keystore.util.EntryType;\nimport org.eclipse.kura.core.keystore.util.PrivateKeyInfo;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.keystore.KeystoreEntryInfoMapper;\nimport org.junit.Test;\n\npublic class KeystoreEntryInfoMapperTest {\n\n    private static final String MY_KEYSTORE = \"MyKeystore\";\n\n    @Test\n    public void unmarshalTest() {\n\n        String jsonString = \"{\\n\" + \"    \\\"keystoreServicePid\\\" : \\\"MyKeystore\\\",\\n\"\n                + \"    \\\"alias\\\" : \\\"mycerttestec\\\"\\n\" + \"}\";\n        EntryInfo entry = KeystoreEntryInfoMapper.unmarshal(new StringReader(jsonString), EntryInfo.class);\n\n        assertTrue(entry instanceof EntryInfo);\n        assertEquals(\"mycerttestec\", entry.getAlias());\n        assertEquals(MY_KEYSTORE, entry.getKeystoreServicePid());\n    }\n\n    @Test\n    public void unmarshalCertificateTest() {\n\n        String CERTIFICATE = \"-----BEGIN CERTIFICATE-----\\n\"\n                + \"MIIDdzCCAl+gAwIBAgIEQsO0gDANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV\\n\"\n                + \"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\\n\"\n                + \"VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du\\n\"\n                + \"MB4XDTIxMDQxNDA4MDIyOFoXDTIxMDcxMzA4MDIyOFowbDEQMA4GA1UEBhMHVW5r\\n\"\n                + \"bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE\\n\"\n                + \"ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC\\n\"\n                + \"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJSWJDxu8UNC4JGOgK31WCvz\\n\"\n                + \"NKy2ONH+jTVKnBY7Ckb1hljJY0sKO55aG1HNDfkev2lJTsPIz0nJjNsqBvB1flvf\\n\"\n                + \"r6XVCxdN0yxvU5g9SpRxE/iiPX0Qt7463OfzyKW97haJrrhF005RHYNcORMY/Phj\\n\"\n                + \"hFDnZhtAwpbQLzq2UuIZ7okJsx0IgRbjH71ZZuvYCqG7Ct/bp1D7w3tT7gTbIKYH\\n\"\n                + \"ppQyG9rJDEh9+cr9Hyk8Gz7aAbPT/wMH+/vXDjH2j/M1Tmed0ajuGCJumaTQ4eHs\\n\"\n                + \"9xW3B3ugycb6e7Osl/4ESRO5RQL1k2GBONv10OrKDoZ5b66xwSJmC/w3BRWQ1cMC\\n\"\n                + \"AwEAAaMhMB8wHQYDVR0OBBYEFPospETb5HNeD/DmS9mwt+v/AYq/MA0GCSqGSIb3\\n\"\n                + \"DQEBCwUAA4IBAQBxMe1xQVQKt36A5qVlEZyxI9eb6eQRlYzorOgP2tFaOsvDPpRI\\n\"\n                + \"CALhPmxgQl/5QvKFfCXKoxWj1Spg4sF6fJp6jhSjLpmChS9lf5fRaWS20/pxIddM\\n\"\n                + \"10diq3r6HxLKSxCYK7Pf5scOeZquvwfo8Kxye01bvCMFf1s1K3ZEZszk5Oo2MnWU\\n\"\n                + \"U22YnXfZm1C0h2WMUcou35A7CeVAHPWI0Rvefojv1qYlQScJOkCN5lO6C/1qvRhq\\n\"\n                + \"nDQdQN/m1HQbpfh2DD6F33nBjkyLQyMRF8uMnspLrLLj8lecSTJZO4fGJOaIXh3O\\n\"\n                + \"44da9A02FAf5nRRQpwP2x/4IZ5RTRBzrqbqD\\n\" + \"-----END CERTIFICATE-----\";\n        String jsonString = \"{\\n\" + \"   \\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\n\" + \"   \\\"alias\\\":\\\"myCertTest99\\\",\\n\"\n                + \"   \\\"type\\\":\\\"TRUSTED_CERTIFICATE\\\",\\n\" + \"   \\\"certificate\\\":\\\"\" + CERTIFICATE + \"\\\"\" + \"}\";\n        EntryInfo entry = KeystoreEntryInfoMapper.unmarshal(new StringReader(jsonString), CertificateInfo.class);\n\n        assertTrue(entry instanceof CertificateInfo);\n        CertificateInfo certificateInfo = (CertificateInfo) entry;\n        assertEquals(\"myCertTest99\", certificateInfo.getAlias());\n        assertEquals(MY_KEYSTORE, certificateInfo.getKeystoreServicePid());\n        assertEquals(CERTIFICATE, certificateInfo.getCertificate());\n        assertEquals(EntryType.TRUSTED_CERTIFICATE, certificateInfo.getType());\n    }\n\n    @Test\n    public void unmarshalPrivateKeyTest() {\n\n        String PRIVATEKEY = \"-----BEGIN PRIVATE KEY-----\\n\"\n                + \"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCCcZ1Nu9AVYKJd\\n\"\n                + \"p6gcdObxCiofeOVbJv3Ws19JVa6PGTSgREFy5c97/k+SsSBhHAFp1n3738E2gdxD\\n\"\n                + \"auftKpmV3ZZ93rEQQ+Db71PiyFlrEEtcDE//14EH2jaHBIghxqWmgvWu0e8pca4u\\n\"\n                + \"xnmOOJAPCabNYLLs4pnTh9xJn+B+Mdz+/NNj/C7BV53W2nAcsdVqpbmLjfCrDSd/\\n\"\n                + \"hgel8AoAbdjiRGkYHkgvEuztjx01pO2iGAgpkctigdxF/ygwwOOxcPASw/55ZjSE\\n\"\n                + \"gMZx7PMyxEiIL7jgt/cgG68QhlQ3neYfJ9cd+gLvn1g1fwsGtGpw3Mh3dgs6DQkr\\n\"\n                + \"8HMQW0bpAgMBAAECggEAL2IR3/C/L2TA1gBWwq98TEaC8pe5yJirUFgr3rmvBPAE\\n\"\n                + \"+8qPc6si6UmBoimRN3Uy1j1B2kJ3LtORLTQiNzZoP9YUGnjQHLZrcbjH4fMg+BEd\\n\"\n                + \"LrySOr8PccjEUdtFj+9WsNuVXwGHPKi8uuUBtrW5Lp006BmeJQpTElGhpWTb6Tqy\\n\"\n                + \"OcNceNz+oP1N3AZ3Mnf6Aq6GuvD4QeGMVEiosHPxMqY0eddNK672zq3A0o1NPA9z\\n\"\n                + \"yaVt9UK7SZ6/yOKYrAAM/2iLHmNbrYRer567hgg2B1LGJCRSdB/c34u6lTnPo+Ai\\n\"\n                + \"olQahQNFhiJKTXr2kK9WgS6tWXhqUqsVLUCug4mDAQKBgQDKLbhidAYClyOKJW7U\\n\"\n                + \"GsbM5dmQV80NsnsN3qphKZDTEMinhs3N4oknhi+mZPeyge4MY73BiHXhnMcUkfhw\\n\"\n                + \"nbhRNhrkZTt18S6rTzEp/vDDx+ZosxRKYXmPyuDDWDmvG6ocRyOLIgoYhT0kPQ7a\\n\"\n                + \"oXQkpFPjBq1UmqNOcUwEpNG2sQKBgQClKzyAopsjWNptBQPo/j/PN24uThpdd3yX\\n\"\n                + \"NenmLZsYJyloKDbOGzEXpuyzdtNAiIVDsQ8RzN5lkF6xVvXnOlSA2gmEc8KJmRl8\\n\"\n                + \"/gWzPRHHHNR7QUiGmg9QThrUp2l6DiAm/IcuL0btj99kQa2XcLGlTohwWpdVySSx\\n\"\n                + \"abDX7pSRuQKBgH/jy+77VZHt6R1J8IFbLsYN30HfSGaRsCVl5IDxuhrJUyQlsam6\\n\"\n                + \"0uediibHV6gjaGGN9kql92tvsL7iVzVlj2JPx1MSdjp1BgB3Z7IZAlPV73nrTbp/\\n\"\n                + \"TlYXD3aCKHsMFN8uYN1x+tDn93Uk6nCCEOXczPOfFaWe7A6CvINzfvUBAoGAUJEm\\n\"\n                + \"khi/VB6jbUpk/eIHfiyrsiqm8bC3NYs27PCSFtYDfKshEKhy6faiv2fW5EOzvbFA\\n\"\n                + \"iI5GbYRerGKe0IvDbJbuzY0p97SWmkHOxf+kDFwjyXuuxPmhPqraq6B98uuxA1Nr\\n\"\n                + \"HTwyfO8RKPZglt6ByQDlzOhjqZTUMTY87ReToQECgYBKdX3Idr4zvODkXIlG852C\\n\"\n                + \"o135W+7AWr+dYRLx1FcvgMU9SbF9cwUU5Zutbrv+Kl8xGPyfx09MJ6BNxTkkr09J\\n\"\n                + \"BpbrbOZsUDjMjojyQYL4Ll9rLohk+Pq73xXJjtTRIXZVXJg27pEEqzcVB4o9vgli\\n\" + \"yzOqhyTKM9JP7Uda6Fv6DA==\\n\"\n                + \"-----END PRIVATE KEY-----\";\n        String CERTIFICATE_CHAIN = \"-----BEGIN CERTIFICATE-----\\n\"\n                + \"MIIDdzCCAl+gAwIBAgIED3hXJjANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV\\n\"\n                + \"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\\n\"\n                + \"VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du\\n\"\n                + \"MB4XDTIxMDQxMzA4MTQxOVoXDTIxMDcxMjA4MTQxOVowbDEQMA4GA1UEBhMHVW5r\\n\"\n                + \"bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE\\n\"\n                + \"ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC\\n\"\n                + \"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIJxnU270BVgol2nqBx05vEK\\n\"\n                + \"Kh945Vsm/dazX0lVro8ZNKBEQXLlz3v+T5KxIGEcAWnWffvfwTaB3ENq5+0qmZXd\\n\"\n                + \"ln3esRBD4NvvU+LIWWsQS1wMT//XgQfaNocEiCHGpaaC9a7R7ylxri7GeY44kA8J\\n\"\n                + \"ps1gsuzimdOH3Emf4H4x3P7802P8LsFXndbacByx1WqluYuN8KsNJ3+GB6XwCgBt\\n\"\n                + \"2OJEaRgeSC8S7O2PHTWk7aIYCCmRy2KB3EX/KDDA47Fw8BLD/nlmNISAxnHs8zLE\\n\"\n                + \"SIgvuOC39yAbrxCGVDed5h8n1x36Au+fWDV/Cwa0anDcyHd2CzoNCSvwcxBbRukC\\n\"\n                + \"AwEAAaMhMB8wHQYDVR0OBBYEFCXFCTq9DDNw6jr0nE2VHw+6wqG0MA0GCSqGSIb3\\n\"\n                + \"DQEBCwUAA4IBAQAjsKeIU0vf7vaOhUAMV60eP54kr6koiWBjhCxyKXQ+MECTFntn\\n\"\n                + \"L459+uTFOCyoytWYjbe9ph79ossTWTCUUPCx9ZSaVdrpK5TyzXI+KBBWqGcLHxqc\\n\"\n                + \"1jvU7zKLVf9oKGfhugnFvmj2EqC2vsrQPiG+p1RDfiLI9BqmhoDzBWzjZDdB6xt6\\n\"\n                + \"PMAqecHfS24TzyWi8T4gLctcpSN22Aa394ky7sgBJPAQHWe7VWhRB0bVTZntwRsQ\\n\"\n                + \"pEraINImKSw+m7MF/75s151yjKOzQxPZufl91oYyQMXoqX2fi0EUWo1oLm1x01dN\\n\"\n                + \"L7w7ELyBzbNlk8a3dQc3Dcg+tu7VAf2tRtmc\\n\" + \"-----END CERTIFICATE-----\";\n        String jsonString = \"{\\n\" + \"   \\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\n\" + \"   \\\"alias\\\":\\\"myPrivateKey1\\\",\\n\"\n                + \"   \\\"type\\\":\\\"PRIVATE_KEY\\\",\\n\" + \"   \\\"privateKey\\\" : \\\"\" + PRIVATEKEY + \"\\\",\\n\"\n                + \"   \\\"certificateChain\\\":[\\\"\" + CERTIFICATE_CHAIN + \"\\\"]\\n\" + \"}\";\n        EntryInfo entry = KeystoreEntryInfoMapper.unmarshal(new StringReader(jsonString), PrivateKeyInfo.class);\n\n        assertTrue(entry instanceof PrivateKeyInfo);\n        PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) entry;\n        assertEquals(\"myPrivateKey1\", privateKeyInfo.getAlias());\n        assertEquals(MY_KEYSTORE, privateKeyInfo.getKeystoreServicePid());\n        assertEquals(CERTIFICATE_CHAIN, privateKeyInfo.getCertificateChain()[0]);\n        assertEquals(PRIVATEKEY, privateKeyInfo.getPrivateKey());\n        assertEquals(EntryType.PRIVATE_KEY, privateKeyInfo.getType());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.json.marshaller.unmarshaller.provider.test/src/test/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/message/test/CloudPayloadJsonDecoderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.message.test;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.StringReader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\nimport java.util.Date;\nimport java.util.Map.Entry;\n\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonDecoder;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport com.eclipsesource.json.ParseException;\n\npublic class CloudPayloadJsonDecoderTest {\n\n    @Before\n    public void setUp() throws Exception {\n    }\n\n    @Test\n    public void testStringToJson() throws IOException {\n        String stringToConvert = \"{\\\"ts\\\":1490196349868,\\\"metric.string\\\":\\\"string.value\\\",\\\"metric.long\\\":9223372036854774999,\\\"metric.char\\\":\\\"a\\\",\\\"metric.string.oneof\\\":\\\"string.value.option.1\\\",\\\"metric.password\\\":\\\"xea2sebrvKJQEW1YRDEEGg==\\\",\\\"metric.float\\\":32766.98,\\\"metric.integer.fixed\\\":101,\\\"metric.byte\\\":119,\\\"metric.boolean\\\":false,\\\"temperature\\\":127.19863,\\\"metric.integer\\\":2147483599,\\\"metric.short\\\":32759,\\\"metric.double\\\":4.29496729599998E9}\";\n        KuraPayload kuraPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(stringToConvert));\n        assertNotNull(kuraPayload);\n    }\n\n    @Test(expected = ParseException.class)\n    public void testStringToJsonEmptyStringFailure() throws IOException {\n        String stringToConvert = \"\";\n        CloudPayloadJsonDecoder.buildFromReader(new StringReader(stringToConvert));\n    }\n\n    @Test(expected = ParseException.class)\n    public void testStringToJsonIncompleteFailure() throws IOException {\n        String stringToConvert = \"{\\\"TIMESTAMP\\\":,\\\"POSITION\\\":{\\\"LATITUDE\\\":10,\\\"LONGITUDE\\\":20,\\\"ALTITUDE\\\":200,\\\"HEADING\\\":30,\\\"PRECISION\\\":1,\\\"SATELLITES\\\":3,\\\"SPEED\\\":50,\\\"TIMESTAMP\\\":123456789,\\\"STATUS\\\":0},\\\"metric.name\\\":{\\\"type\\\":\\\"STRING\\\",\\\"value\\\":\\\"metric.value\\\"},\\\"metric.int\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"value\\\":1},\\\"metric.character\\\":{\\\"type\\\":\\\"CHARACTER\\\",\\\"value\\\":99},\\\"metric.float\\\":{\\\"type\\\":\\\"FLOAT\\\",\\\"value\\\":1.2},\\\"metric.bytearray\\\":{\\\"type\\\":\\\"BYTEARRAY\\\",\\\"value\\\":\\\"VGVzdA==\\\"},\\\"metric.double\\\":{\\\"type\\\":\\\"DOUBLE\\\",\\\"value\\\":1.7976931348623157E308}}\";\n        CloudPayloadJsonDecoder.buildFromReader(new StringReader(stringToConvert));\n    }\n\n    @Test\n    public void testStringToJsonUnparsableMetric() throws IOException {\n        String stringToConvert = \"{\\\"SENTON\\\":1490275324619,\\\"METRICS\\\":{\\\"metric.name\\\":{\\\"metric.value\\\":\\\"value\\\"}}}\";\n\n        KuraPayload payload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(stringToConvert));\n\n        assertNull(payload.getTimestamp());\n\n        assertNull(payload.getPosition());\n\n        assertNotNull(payload.metrics());\n        assertEquals(0, payload.metrics().size());\n\n        assertNotNull(payload.getBody());\n    }\n\n    @Test\n    public void testToJsonUnparsablePosition() throws IOException {\n        String stringToConvert = \"{\\\"SENTON\\\":1490275324619,\\\"POSITION\\\":{\\\"LATITUDE\\\":10,\\\"LON\\\":20}}\";\n\n        KuraPayload payload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(stringToConvert));\n\n        assertNull(payload.getTimestamp());\n\n        assertNull(payload.getPosition());\n\n        assertNotNull(payload.metrics());\n        assertEquals(0, payload.metrics().size());\n\n        assertNotNull(payload.getBody());\n    }\n\n    @Test\n    public void testByteToJsonComplete() throws IOException {\n        String stringToConvert = (\"{\\\"SENTON\\\":1490275324619,\"\n                + \"\\\"POSITION\\\":{\\\"LATITUDE\\\":10,\\\"LONGITUDE\\\":20,\\\"ALTITUDE\\\":200,\\\"HEADING\\\":30,\\\"PRECISION\\\":1,\\\"SATELLITES\\\":3,\\\"SPEED\\\":50,\\\"TIMESTAMP\\\":123456789,\\\"STATUS\\\":0},\"\n                + \"\\\"METRICS\\\":{\\\"metric.name\\\":\\\"metric.value\\\",\\\"metric.int\\\":1,\\\"metric.long\\\":12345,\\\"metric.boolean\\\":true,\\\"metric.character\\\":\\\"c\\\",\\\"metric.float\\\":1.2,\\\"metric.bytearray\\\":\\\"VGVzdA==\\\",\\\"metric.double\\\":1.7976931348623157E308},\"\n                + \"\\\"BODY\\\":\\\"\" + Base64.getEncoder().encodeToString(\"test\".getBytes(StandardCharsets.UTF_8)) + \"\\\"}\");\n\n        KuraPayload payload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(stringToConvert));\n\n        assertEquals(1490275324619L, payload.getTimestamp().getTime());\n\n        KuraPosition position = payload.getPosition();\n        assertNotNull(position);\n        assertTrue(position.getAltitude() == 200);\n        assertTrue(position.getLatitude() == 10);\n        assertTrue(position.getLongitude() == 20);\n        assertTrue(position.getHeading() == 30);\n        assertTrue(position.getPrecision() == 1);\n        assertTrue(position.getSatellites() == 3);\n        assertTrue(position.getSpeed() == 50);\n        assertTrue(position.getStatus() == 0);\n        assertTrue(position.getTimestamp().getTime() == 123456789L);\n\n        assertNotNull(payload.metrics());\n        assertEquals(8, payload.metrics().size());\n        assertEquals(\"metric.value\", payload.getMetric(\"metric.name\"));\n        assertEquals(1L, payload.getMetric(\"metric.int\")); // all fixed point numbers decode as long\n        assertEquals(Double.MAX_VALUE, payload.getMetric(\"metric.double\"));\n        assertEquals(1.2, payload.getMetric(\"metric.float\")); // all floating point numbers decode as double\n        // byte[] -> base64 string -> String: it will decode as a String\n        // assertArrayEquals(\"Test\".getBytes(), (byte[]) decodedPayload.getMetric(\"metric.bytearray\"));\n        assertEquals(\"VGVzdA==\", payload.getMetric(\"metric.bytearray\"));\n        // assertEquals('c', decodedPayload.getMetric(\"metric.character\"));\n        assertEquals(true, payload.getMetric(\"metric.boolean\"));\n        assertEquals(12345L, payload.getMetric(\"metric.long\"));\n\n        byte[] body = payload.getBody();\n        assertNotNull(body);\n        assertArrayEquals(\"test\".getBytes(), body);\n    }\n\n    // this test is prepared for one of the new format possibilities with better decoding options - currently invalid\n    // @Test\n    public void testFromJson() throws IOException {\n        String stringToConvert = \"{\\\"TIMESTAMP\\\":1490275324619,\\\"metric.name\\\":{\\\"type\\\":\\\"STRING\\\",\\\"value\\\":\\\"metric.value\\\"},\\\"metric.int\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"value\\\":1},\\\"metric.character\\\":{\\\"type\\\":\\\"CHARACTER\\\",\\\"value\\\":99},\\\"metric.float\\\":{\\\"type\\\":\\\"FLOAT\\\",\\\"value\\\":1.2},\\\"metric.bytearray\\\":{\\\"type\\\":\\\"BYTEARRAY\\\",\\\"value\\\":\\\"VGVzdA==\\\"},\\\"metric.double\\\":{\\\"type\\\":\\\"DOUBLE\\\",\\\"value\\\":1.7976931348623157E308}}\";\n        KuraPayload payload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(stringToConvert));\n        assertNotNull(payload);\n\n        // timestamp\n        Date timestamp = payload.getTimestamp();\n        assertNotNull(timestamp);\n        long expectedTimestamp = 1490275324619L;\n        assertEquals(expectedTimestamp, timestamp.getTime());\n\n        assertNull(payload.getPosition());\n        assertNull(payload.getBody());\n\n        // Metrics\n        assertNotNull(payload.metrics());\n        for (Entry<String, Object> entry : payload.metrics().entrySet()) {\n            assertNotNull(entry.getKey());\n            assertNotNull(entry.getValue());\n        }\n    }\n\n    @Test(expected = NullPointerException.class)\n    public void testFromJsonNullInput() throws IOException {\n        CloudPayloadJsonDecoder.buildFromReader(new StringReader(null));\n    }\n\n    @Test\n    public void testFromJsonUnknownJson() throws IOException {\n        String stringToConvert = \"{\\\"stuff\\\": {\\\"onetype\\\": [{\\\"id\\\":1,\\\"name\\\":\\\"John Doe\\\"},{\\\"id\\\":2,\\\"name\\\":\\\"Don Joeh\\\"}],\\\"othertype\\\": {\\\"id\\\":2,\\\"company\\\":\\\"ACME\\\"}}, \\\"otherstuff\\\": {\\\"thing\\\": [[1,42],[2,2]]}}\";\n        InputStream inputStream = new ByteArrayInputStream(stringToConvert.getBytes(StandardCharsets.UTF_8));\n        KuraPayload payload = CloudPayloadJsonDecoder\n                .buildFromReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));\n        assertNotNull(payload);\n\n        // timestamp\n        Date timestamp = payload.getTimestamp();\n        assertNull(timestamp);\n\n        assertNull(payload.getPosition());\n\n        byte[] body = payload.getBody();\n        assertNotNull(body);\n        assertFalse(body.length == 0);\n\n        assertNotNull(payload.metrics());\n        assertTrue(payload.metrics().isEmpty());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.json.marshaller.unmarshaller.provider.test/src/test/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/message/test/CloudPayloadJsonEncoderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.message.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStreamWriter;\nimport java.io.StringReader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Date;\n\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonDecoder;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.message.CloudPayloadJsonEncoder;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraPosition;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\n\npublic class CloudPayloadJsonEncoderTest {\n\n    @Before\n    public void setUp() throws Exception {\n    }\n\n    @Test(expected = NullPointerException.class)\n    public void testToJsonNullKuraPayload() throws IOException {\n        CloudPayloadJsonEncoder.marshal(null, null);\n    }\n\n    @Test\n    public void testToJsonEmptyKuraPayload() throws IOException {\n        KuraPayload payload = new KuraPayload();\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n        assertFalse(outStream.toString().isEmpty());\n\n        KuraPayload decodedPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(outStream.toString()));\n\n        assertEquals(payload.getPosition(), decodedPayload.getPosition());\n        assertEquals(payload.getBody(), decodedPayload.getBody());\n        assertEquals(payload.getTimestamp(), decodedPayload.getTimestamp());\n        assertEquals(payload.metrics(), decodedPayload.metrics());\n    }\n\n    @Test\n    public void shouldDiscardNonFiniteFloatMetrics() throws IOException {\n        KuraPayload payload = new KuraPayload();\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n\n        payload.addMetric(\"positive.infinity\", Float.POSITIVE_INFINITY);\n        payload.addMetric(\"negative.infinity\", Float.NEGATIVE_INFINITY);\n        payload.addMetric(\"nan\", Float.NaN);\n        payload.addMetric(\"foo\", \"bar\");\n\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n        assertFalse(outStream.toString().isEmpty());\n\n        KuraPayload decodedPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(outStream.toString()));\n\n        assertEquals(payload.getPosition(), decodedPayload.getPosition());\n        assertEquals(payload.getBody(), decodedPayload.getBody());\n        assertEquals(payload.getTimestamp(), decodedPayload.getTimestamp());\n\n        assertNull(decodedPayload.metrics().get(\"positive.infinity\"));\n        assertNull(decodedPayload.metrics().get(\"negative.infinity\"));\n        assertNull(decodedPayload.metrics().get(\"nan\"));\n        assertEquals(\"bar\", decodedPayload.getMetric(\"foo\"));\n    }\n\n    @Test\n    public void shouldDiscardPositiveInfinityInPositionFields() throws IOException {\n        KuraPayload payload = new KuraPayload();\n        KuraPosition position = new KuraPosition();\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n\n        position.setAltitude(Double.POSITIVE_INFINITY);\n        position.setHeading(Double.POSITIVE_INFINITY);\n        position.setLatitude(Double.POSITIVE_INFINITY);\n        position.setLongitude(Double.POSITIVE_INFINITY);\n        position.setPrecision(Double.POSITIVE_INFINITY);\n        position.setSpeed(Double.POSITIVE_INFINITY);\n        position.setSatellites(40);\n\n        payload.setPosition(position);\n\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n        assertFalse(outStream.toString().isEmpty());\n\n        KuraPayload decodedPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(outStream.toString()));\n\n        assertNull(decodedPayload.getPosition().getAltitude());\n        assertNull(decodedPayload.getPosition().getHeading());\n        assertNull(decodedPayload.getPosition().getLatitude());\n        assertNull(decodedPayload.getPosition().getLongitude());\n        assertNull(decodedPayload.getPosition().getPrecision());\n        assertNull(decodedPayload.getPosition().getSpeed());\n        assertEquals(40, (int) decodedPayload.getPosition().getSatellites());\n    }\n\n    @Test\n    public void shouldDiscardNegativeInfinityInPositionFields() throws IOException {\n        KuraPayload payload = new KuraPayload();\n        KuraPosition position = new KuraPosition();\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n\n        position.setAltitude(Double.NEGATIVE_INFINITY);\n        position.setHeading(Double.NEGATIVE_INFINITY);\n        position.setLatitude(Double.NEGATIVE_INFINITY);\n        position.setLongitude(Double.NEGATIVE_INFINITY);\n        position.setPrecision(Double.NEGATIVE_INFINITY);\n        position.setSpeed(Double.NEGATIVE_INFINITY);\n        position.setSatellites(40);\n\n        payload.setPosition(position);\n\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n        assertFalse(outStream.toString().isEmpty());\n\n        KuraPayload decodedPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(outStream.toString()));\n\n        assertNull(decodedPayload.getPosition().getAltitude());\n        assertNull(decodedPayload.getPosition().getHeading());\n        assertNull(decodedPayload.getPosition().getLatitude());\n        assertNull(decodedPayload.getPosition().getLongitude());\n        assertNull(decodedPayload.getPosition().getPrecision());\n        assertNull(decodedPayload.getPosition().getSpeed());\n        assertEquals(40, (int) decodedPayload.getPosition().getSatellites());\n    }\n\n    @Test\n    public void shouldDiscardNaNInfinityInPositionFields() throws IOException {\n        KuraPayload payload = new KuraPayload();\n        KuraPosition position = new KuraPosition();\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n\n        position.setAltitude(Double.NaN);\n        position.setHeading(Double.NaN);\n        position.setLatitude(Double.NaN);\n        position.setLongitude(Double.NaN);\n        position.setPrecision(Double.NaN);\n        position.setSpeed(Double.NaN);\n        position.setSatellites(40);\n\n        payload.setPosition(position);\n\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n        assertFalse(outStream.toString().isEmpty());\n\n        KuraPayload decodedPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(outStream.toString()));\n\n        assertNull(decodedPayload.getPosition().getAltitude());\n        assertNull(decodedPayload.getPosition().getHeading());\n        assertNull(decodedPayload.getPosition().getLatitude());\n        assertNull(decodedPayload.getPosition().getLongitude());\n        assertNull(decodedPayload.getPosition().getPrecision());\n        assertNull(decodedPayload.getPosition().getSpeed());\n        assertEquals(40, (int) decodedPayload.getPosition().getSatellites());\n    }\n\n    @Test\n    public void shoyldDiscardNonFiniteDoubleMetrics() throws IOException {\n        KuraPayload payload = new KuraPayload();\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n\n        payload.addMetric(\"positive.infinity\", Double.POSITIVE_INFINITY);\n        payload.addMetric(\"negative.infinity\", Double.NEGATIVE_INFINITY);\n        payload.addMetric(\"nan\", Double.NaN);\n        payload.addMetric(\"foo\", \"bar\");\n\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n        assertFalse(outStream.toString().isEmpty());\n\n        KuraPayload decodedPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(outStream.toString()));\n\n        assertEquals(payload.getPosition(), decodedPayload.getPosition());\n        assertEquals(payload.getBody(), decodedPayload.getBody());\n        assertEquals(payload.getTimestamp(), decodedPayload.getTimestamp());\n\n        assertNull(decodedPayload.metrics().get(\"positive.infinity\"));\n        assertNull(decodedPayload.metrics().get(\"negative.infinity\"));\n        assertNull(decodedPayload.metrics().get(\"nan\"));\n        assertEquals(\"bar\", decodedPayload.getMetric(\"foo\"));\n    }\n\n    @Test\n    public void shouldEncodeEmptyPosition() throws IOException {\n        KuraPayload payload = new KuraPayload();\n        KuraPosition position = new KuraPosition();\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n\n        payload.setPosition(position);\n\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n        assertFalse(outStream.toString().isEmpty());\n\n        KuraPayload decodedPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(outStream.toString()));\n\n        assertNull(decodedPayload.getPosition().getAltitude());\n        assertNull(decodedPayload.getPosition().getHeading());\n        assertNull(decodedPayload.getPosition().getLatitude());\n        assertNull(decodedPayload.getPosition().getLongitude());\n        assertNull(decodedPayload.getPosition().getPrecision());\n        assertNull(decodedPayload.getPosition().getSpeed());\n    }\n\n    @Test\n    public void testToJsonKuraPayloadOnlyTimestamp() throws IOException {\n        KuraPayload payload = new KuraPayload();\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n\n        payload.setTimestamp(new Date());\n\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n        assertFalse(outStream.toString().isEmpty());\n\n        KuraPayload decodedPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(outStream.toString()));\n\n        assertNull(decodedPayload.getPosition());\n        assertNull(decodedPayload.getBody());\n        assertEquals(payload.getTimestamp(), decodedPayload.getTimestamp());\n        assertNotNull(decodedPayload.metrics());\n        assertTrue(decodedPayload.metrics().isEmpty());\n    }\n\n    @Test(expected = IllegalArgumentException.class)\n    public void testToJsonKuraPayloadChar() throws IOException {\n        KuraPayload payload = new KuraPayload();\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n        payload.setTimestamp(new Date());\n\n        payload.addMetric(\"metric.name\", \"metric.value\");\n        payload.addMetric(\"metric.character\", 'c'); // characters are not supported, yet\n\n        payload.setBody(\"Test body\".getBytes());\n\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n    }\n\n    @Test\n    public void testToJsonKuraPayload() throws IOException {\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n        KuraPayload payload = new KuraPayload();\n        payload.setTimestamp(new Date());\n        KuraPosition position = new KuraPosition();\n        position.setAltitude(200);\n        position.setLatitude(10);\n        position.setLongitude(20);\n        position.setHeading(30);\n        position.setPrecision(1);\n        position.setSatellites(3);\n        position.setSpeed(50);\n        position.setStatus(0);\n        position.setTimestamp(new Date(123456789L));\n\n        payload.setPosition(position);\n\n        payload.addMetric(\"metric.name\", \"metric.value\");\n\n        payload.addMetric(\"metric.int\", 1);\n        payload.addMetric(\"metric.double\", Double.MAX_VALUE);\n        payload.addMetric(\"metric.float\", 1.2f);\n        // payload.addMetric(\"metric.character\", 'c'); // characters are not supported, yet\n        payload.addMetric(\"metric.bytearray\", \"Test\".getBytes());\n        payload.addMetric(\"metric.boolean\", true);\n        payload.addMetric(\"metric.long\", 12345L);\n\n        payload.setBody(\"Test body\".getBytes());\n\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        CloudPayloadJsonEncoder.marshal(writer, payload);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n        assertFalse(outStream.toString().isEmpty());\n\n        KuraPayload decodedPayload = CloudPayloadJsonDecoder.buildFromReader(new StringReader(outStream.toString()));\n\n        assertEquals(payload.getTimestamp(), decodedPayload.getTimestamp());\n\n        KuraPosition decodedPosition = decodedPayload.getPosition();\n        assertNotNull(decodedPosition);\n        assertTrue(decodedPosition.getAltitude() == 200);\n        assertTrue(decodedPosition.getLatitude() == 10);\n        assertTrue(decodedPosition.getLongitude() == 20);\n        assertTrue(decodedPosition.getHeading() == 30);\n        assertTrue(decodedPosition.getPrecision() == 1);\n        assertTrue(decodedPosition.getSatellites() == 3);\n        assertTrue(decodedPosition.getSpeed() == 50);\n        assertTrue(decodedPosition.getStatus() == 0);\n        assertTrue(decodedPosition.getTimestamp().getTime() == 123456789L);\n\n        assertNotNull(decodedPayload.metrics());\n        assertTrue(decodedPayload.metrics().size() == 7);\n        assertEquals(\"metric.value\", decodedPayload.getMetric(\"metric.name\"));\n        assertEquals(1L, decodedPayload.getMetric(\"metric.int\")); // all fixed point numbers decode as long\n        assertEquals(Double.MAX_VALUE, decodedPayload.getMetric(\"metric.double\"));\n        assertEquals(1.2, decodedPayload.getMetric(\"metric.float\")); // all floating point numbers decode as double\n        // byte[] -> base64 string -> String: it will decode as a String\n        // assertArrayEquals(\"Test\".getBytes(), (byte[]) decodedPayload.getMetric(\"metric.bytearray\"));\n        assertEquals(\"VGVzdA==\", decodedPayload.getMetric(\"metric.bytearray\"));\n        // assertEquals('c', decodedPayload.getMetric(\"metric.character\"));\n        assertEquals(true, decodedPayload.getMetric(\"metric.boolean\"));\n        assertEquals(12345L, decodedPayload.getMetric(\"metric.long\"));\n\n        Assert.assertArrayEquals(\"Test body\".getBytes(), decodedPayload.getBody());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.json.marshaller.unmarshaller.provider.test/src/test/java/org/eclipse/kura/internal/json/marshaller/unmarshaller/test/JsonEncoderDecoderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.json.marshaller.unmarshaller.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.core.configuration.ComponentConfigurationImpl;\nimport org.eclipse.kura.core.inventory.resources.SystemBundle;\nimport org.eclipse.kura.core.inventory.resources.SystemBundles;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemPackages;\nimport org.eclipse.kura.core.inventory.resources.SystemResourcesInfo;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.JsonMarshallUnmarshallImpl;\nimport org.eclipse.kura.internal.json.marshaller.unmarshaller.wiregraph.WireGraphJsonMarshallUnmarshallImpl;\nimport org.eclipse.kura.system.SystemResourceInfo;\nimport org.eclipse.kura.system.SystemResourceType;\nimport org.eclipse.kura.wire.WireConfiguration;\nimport org.eclipse.kura.wire.graph.MultiportWireConfiguration;\nimport org.eclipse.kura.wire.graph.WireComponentConfiguration;\nimport org.eclipse.kura.wire.graph.WireGraphConfiguration;\nimport org.junit.Test;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\n\npublic class JsonEncoderDecoderTest {\n\n    @Test\n    public void testUnmarshalWireConfigurationEmptyArray() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        @SuppressWarnings(\"unchecked\")\n        List<WireConfiguration> wireConfigList = (List<WireConfiguration>) TestUtil.invokePrivate(jsonEncoderDecoder,\n                \"unmarshalWireConfiguration\", new JsonArray());\n        assertNotNull(wireConfigList);\n        assertEquals(0, wireConfigList.size());\n    }\n\n    @Test\n    public void testUnmarshalWireConfigurationSingleWire() throws Throwable {\n\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n        JsonArray array = new JsonArray();\n        JsonObject wire = new JsonObject();\n        wire.add(\"emitter\", \"foo\");\n        wire.add(\"receiver\", \"bar\");\n        array.add(wire);\n\n        @SuppressWarnings(\"unchecked\")\n        List<WireConfiguration> wireConfigList = (List<WireConfiguration>) TestUtil.invokePrivate(jsonEncoderDecoder,\n                \"unmarshalWireConfiguration\", array);\n\n        assertNotNull(wireConfigList);\n        assertEquals(1, wireConfigList.size());\n\n        assertEquals(\"foo\", wireConfigList.get(0).getEmitterPid());\n        assertEquals(\"bar\", wireConfigList.get(0).getReceiverPid());\n    }\n\n    @Test\n    public void testUnmarshalWireComponentConfigurationEmptyArray() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        @SuppressWarnings(\"unchecked\")\n        List<WireComponentConfiguration> wireComponentConfigurationList = (List<WireComponentConfiguration>) TestUtil\n                .invokePrivate(jsonEncoderDecoder, \"unmarshalWireComponentConfiguration\", new JsonArray());\n        assertNotNull(wireComponentConfigurationList);\n        assertEquals(0, wireComponentConfigurationList.size());\n    }\n\n    @Test\n    public void testUnmarshalWireComponentConfigurationSingleComponent() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n        String json = \"[{\\n\" + \"        \\\"pid\\\": \\\"foo\\\",\\n\" + \"        \\\"inputPortCount\\\": 0,\\n\"\n                + \"        \\\"outputPortCount\\\": 5,\\n\" + \"        \\\"renderingProperties\\\": {\\n\"\n                + \"            \\\"position\\\": {\\n\" + \"                \\\"x\\\": 10,\\n\" + \"                \\\"y\\\": 100\\n\"\n                + \"            },\\n\" + \"            \\\"inputPortNames\\\": {\\n\" + \"                \\\"0\\\": \\\"resetPort\\\"\\n\"\n                + \"            },\\n\" + \"            \\\"outputPortNames\\\": {\\n\" + \"                \\\"3\\\": \\\"then\\\",\\n\"\n                + \"                \\\"4\\\": \\\"else\\\"\\n\" + \"            },\\n\" + \"            \\\"rotation\\\": 0,\\n\"\n                + \"            \\\"color\\\": \\\"red\\\",\\n\" + \"            \\\"size\\\": {\\n\"\n                + \"                \\\"width\\\": 100,\\n\" + \"                \\\"height\\\": 50\\n\" + \"            }\\n\"\n                + \"        }\\n\" + \"    }\\n\" + \"]\";\n\n        JsonArray jsonArray = Json.parse(json).asArray();\n        @SuppressWarnings(\"unchecked\")\n        List<WireComponentConfiguration> wireComponentConfigurationList = (List<WireComponentConfiguration>) TestUtil\n                .invokePrivate(jsonEncoderDecoder, \"unmarshalWireComponentConfiguration\", jsonArray);\n        assertNotNull(wireComponentConfigurationList);\n        assertEquals(1, wireComponentConfigurationList.size());\n\n        WireComponentConfiguration wireComponentConfiguration = wireComponentConfigurationList.get(0);\n        assertEquals(\"foo\", wireComponentConfiguration.getConfiguration().getPid());\n        assertEquals(null, wireComponentConfiguration.getConfiguration().getDefinition());\n        assertEquals(null, wireComponentConfiguration.getConfiguration().getConfigurationProperties());\n        assertEquals(0, wireComponentConfiguration.getProperties().get(\"inputPortCount\"));\n        assertEquals(5, wireComponentConfiguration.getProperties().get(\"outputPortCount\"));\n        assertEquals(10f, wireComponentConfiguration.getProperties().get(\"position.x\"));\n        assertEquals(100f, wireComponentConfiguration.getProperties().get(\"position.y\"));\n        assertEquals(\"resetPort\", wireComponentConfiguration.getProperties().get(\"inputPortNames.0\"));\n        assertEquals(\"then\", wireComponentConfiguration.getProperties().get(\"outputPortNames.3\"));\n        assertEquals(\"else\", wireComponentConfiguration.getProperties().get(\"outputPortNames.4\"));\n    }\n\n    @Test\n    public void testUnmarshalWireComponentConfigurationTwoComponents() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n        String json = \"[{\\n\" + \"        \\\"pid\\\": \\\"foo\\\",\\n\" + \"        \\\"inputPortCount\\\": 0,\\n\"\n                + \"        \\\"outputPortCount\\\": 5,\\n\" + \"        \\\"renderingProperties\\\": {\\n\"\n                + \"            \\\"position\\\": {\\n\" + \"                \\\"x\\\": 10,\\n\" + \"                \\\"y\\\": 100\\n\"\n                + \"            },\\n\" + \"            \\\"inputPortNames\\\": {\\n\" + \"                \\\"0\\\": \\\"resetPort\\\"\\n\"\n                + \"            },\\n\" + \"            \\\"outputPortNames\\\": {\\n\" + \"                \\\"3\\\": \\\"then\\\",\\n\"\n                + \"                \\\"4\\\": \\\"else\\\"\\n\" + \"            },\\n\" + \"            \\\"rotation\\\": 0,\\n\"\n                + \"            \\\"color\\\": \\\"red\\\",\\n\" + \"            \\\"size\\\": {\\n\"\n                + \"                \\\"width\\\": 100,\\n\" + \"                \\\"height\\\": 50\\n\" + \"            }\\n\"\n                + \"        }\\n\" + \"    },\\n\" + \"    {\\n\" + \"        \\\"pid\\\": \\\"bar\\\",\\n\"\n                + \"        \\\"inputPortCount\\\": 6,\\n\" + \"        \\\"outputPortCount\\\": 1,\\n\"\n                + \"        \\\"renderingProperties\\\": {\\n\" + \"            \\\"position\\\": {\\n\"\n                + \"                \\\"x\\\": 150,\\n\" + \"                \\\"y\\\": 100\\n\" + \"            },\\n\"\n                + \"            \\\"rotation\\\": 0,\\n\" + \"            \\\"color\\\": \\\"red\\\",\\n\" + \"            \\\"size\\\": {\\n\"\n                + \"                \\\"width\\\": 100,\\n\" + \"                \\\"height\\\": 50\\n\" + \"            }\\n\"\n                + \"        }\\n\" + \"    }\\n\" + \"]\";\n\n        JsonArray jsonArray = Json.parse(json).asArray();\n        @SuppressWarnings(\"unchecked\")\n        List<WireComponentConfiguration> wireComponentConfigurationList = (List<WireComponentConfiguration>) TestUtil\n                .invokePrivate(jsonEncoderDecoder, \"unmarshalWireComponentConfiguration\", jsonArray);\n        assertNotNull(wireComponentConfigurationList);\n        assertEquals(2, wireComponentConfigurationList.size());\n    }\n\n    @Test\n    public void testUnmarshalDefaultJson() throws Exception {\n        JsonMarshallUnmarshallImpl jsonEncoderDecoder = new JsonMarshallUnmarshallImpl();\n        String defaultJson = \"{\\\"components\\\":[],\\\"wires\\\":[]}\";\n\n        WireGraphConfiguration wireGraphConfiguration = jsonEncoderDecoder.unmarshal(defaultJson,\n                WireGraphConfiguration.class);\n        assertNotNull(wireGraphConfiguration);\n\n        assertEquals(0, wireGraphConfiguration.getWireComponentConfigurations().size());\n        assertEquals(0, wireGraphConfiguration.getWireConfigurations().size());\n    }\n\n    @Test\n    public void testUnmarshalWrongJson() throws Exception {\n        JsonMarshallUnmarshallImpl jsonEncoderDecoder = new JsonMarshallUnmarshallImpl();\n        String defaultJson = \"{\\\"components\\\":{},\\\"wires\\\":{}}\";\n\n        WireGraphConfiguration wireGraphConfiguration = jsonEncoderDecoder.unmarshal(defaultJson,\n                WireGraphConfiguration.class);\n        assertNotNull(wireGraphConfiguration);\n\n        assertEquals(0, wireGraphConfiguration.getWireComponentConfigurations().size());\n        assertEquals(0, wireGraphConfiguration.getWireConfigurations().size());\n    }\n\n    @Test\n    public void testUnmarshalWireConfigurationEmitterReceiverNotStrings() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        JsonArray wireConfigArray = new JsonArray();\n        JsonObject wire = new JsonObject();\n        wire.add(\"emitter\", 3);\n        wire.add(\"receiver\", 2);\n        wireConfigArray.add(wire);\n\n        List<WireConfiguration> result = (List<WireConfiguration>) TestUtil.invokePrivate(jsonEncoderDecoder,\n                \"unmarshalWireConfiguration\", wireConfigArray);\n\n        assertNotNull(result);\n        assertEquals(0, result.size());\n    }\n\n    @Test\n    public void testUnmarshalWireConfigurationReceiverNotString() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        JsonArray wireConfigArray = new JsonArray();\n        JsonObject wire = new JsonObject();\n        wire.add(\"emitter\", \"test\");\n        wire.add(\"receiver\", 2);\n        wireConfigArray.add(wire);\n\n        List<WireConfiguration> result = (List<WireConfiguration>) TestUtil.invokePrivate(jsonEncoderDecoder,\n                \"unmarshalWireConfiguration\", wireConfigArray);\n\n        assertNotNull(result);\n        assertEquals(0, result.size());\n    }\n\n    @Test\n    public void testUnmarshalWireComponentConfigurationWrongArray() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        JsonArray wireComponentConfiguration = new JsonArray();\n        JsonObject compProps = new JsonObject();\n        compProps.add(\"inputPortCount\", \"test\");\n        compProps.add(\"outputPortCount\", \"test2\");\n        compProps.add(\"renderingProperties\", 2);\n        compProps.add(\"pid\", 2);\n        wireComponentConfiguration.add(compProps);\n\n        List<WireComponentConfiguration> result = (List<WireComponentConfiguration>) TestUtil\n                .invokePrivate(jsonEncoderDecoder, \"unmarshalWireComponentConfiguration\", wireComponentConfiguration);\n\n        assertNotNull(result);\n        assertEquals(0, result.size());\n    }\n\n    @Test\n    public void testUnmarshalOutputPortNamesValueNotString() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        JsonObject ports = new JsonObject();\n        ports.add(\"outputPort1\", \"CorrectName\");\n        ports.add(\"outputPort2\", 3);\n\n        Map<String, Object> result = (Map<String, Object>) TestUtil.invokePrivate(jsonEncoderDecoder,\n                \"unmarshalOutputPortNames\", ports);\n\n        assertNotNull(result);\n        assertEquals(1, result.size());\n        assertEquals(\"CorrectName\", result.get(\"outputPortNames.outputPort1\"));\n    }\n\n    @Test\n    public void testUnmarshalInputPortNamesValueNotString() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        JsonObject ports = new JsonObject();\n        ports.add(\"inputPort1\", \"CorrectName\");\n        ports.add(\"inputPort2\", 3);\n\n        Map<String, Object> result = (Map<String, Object>) TestUtil.invokePrivate(jsonEncoderDecoder,\n                \"unmarshalInputPortNames\", ports);\n\n        assertNotNull(result);\n        assertEquals(1, result.size());\n        assertEquals(\"CorrectName\", result.get(\"inputPortNames.inputPort1\"));\n    }\n\n    @Test\n    public void testUnmarshalRenderingPropertiesWrongInput() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        JsonObject renderProps = new JsonObject();\n        renderProps.add(\"position\", 1);\n        renderProps.add(\"inputPortNames\", 3);\n        renderProps.add(\"outputPortNames\", \"test\");\n\n        Map<String, Object> result = (Map<String, Object>) TestUtil.invokePrivate(jsonEncoderDecoder,\n                \"unmarshalRenderingProperties\", renderProps);\n\n        assertNotNull(result);\n        assertEquals(0, result.size());\n    }\n\n    @Test\n    public void testUnmarshalPosition() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        JsonObject renderProps = new JsonObject();\n        renderProps.add(\"x\", \"1\");\n        renderProps.add(\"y\", \"3\");\n\n        Map<String, Object> result = (Map<String, Object>) TestUtil.invokePrivate(jsonEncoderDecoder,\n                \"unmarshalPosition\", renderProps);\n\n        assertNotNull(result);\n        assertEquals(0, result.size());\n    }\n\n    @Test\n    public void testMarshalWireSingleArc() throws Throwable {\n        MultiportWireConfiguration wireConfig = new MultiportWireConfiguration(\"emitterPid\", \"receiverPid\", 0, 0);\n\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n        JsonObject result = (JsonObject) TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalWireConfiguration\",\n                wireConfig);\n        assertNotNull(result);\n\n        String expected = \"{\\\"emitter\\\":\\\"emitterPid\\\",\\\"emitterPort\\\":0,\\\"receiver\\\":\\\"receiverPid\\\",\\\"receiverPort\\\":0}\";\n        assertEquals(expected, result.toString());\n    }\n\n    @Test\n    public void testMarshalWireConfigListEmpty() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        List<WireConfiguration> emptyWireConfig = new ArrayList<>();\n        JsonArray result = (JsonArray) TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalWireConfigurationList\",\n                emptyWireConfig);\n\n        assertNotNull(result);\n\n        String expected = \"[]\";\n        assertEquals(expected, result.toString());\n    }\n\n    @Test\n    public void testMarshalWireConfigListOneElement() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        List<MultiportWireConfiguration> wireConfigList = new ArrayList<>();\n        MultiportWireConfiguration wireConfig = new MultiportWireConfiguration(\"emitterPid\", \"receiverPid\", 0, 0);\n        wireConfigList.add(wireConfig);\n\n        JsonArray result = (JsonArray) TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalWireConfigurationList\",\n                wireConfigList);\n\n        assertNotNull(result);\n\n        String expected = \"[{\\\"emitter\\\":\\\"emitterPid\\\",\\\"emitterPort\\\":0,\\\"receiver\\\":\\\"receiverPid\\\",\\\"receiverPort\\\":0}]\";\n        assertEquals(expected, result.toString());\n    }\n\n    @Test\n    public void testMarshalWireConfigListMoreElements() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        List<MultiportWireConfiguration> wireConfigList = new ArrayList<>();\n        MultiportWireConfiguration wireConfig = new MultiportWireConfiguration(\"emitterPid\", \"receiverPid\", 0, 0);\n        MultiportWireConfiguration wireConfig2 = new MultiportWireConfiguration(\"foo\", \"bar\", 0, 0);\n        wireConfigList.add(wireConfig);\n        wireConfigList.add(wireConfig2);\n\n        JsonArray result = (JsonArray) TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalWireConfigurationList\",\n                wireConfigList);\n\n        assertNotNull(result);\n\n        String expected = \"[{\\\"emitter\\\":\\\"emitterPid\\\",\\\"emitterPort\\\":0,\\\"receiver\\\":\\\"receiverPid\\\",\\\"receiverPort\\\":0},{\\\"emitter\\\":\\\"foo\\\",\\\"emitterPort\\\":0,\\\"receiver\\\":\\\"bar\\\",\\\"receiverPort\\\":0}]\";\n        assertEquals(expected, result.toString());\n    }\n\n    @Test\n    public void testMarshalPosition() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        Map<String, Object> positionMap = new HashMap<>();\n        positionMap.put(\"position.x\", 10f);\n        positionMap.put(\"position.y\", 100f);\n\n        JsonObject result = (JsonObject) TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalPosition\", positionMap);\n\n        assertNotNull(result);\n\n        String expected = \"{\\\"x\\\":10,\\\"y\\\":100}\";\n        assertEquals(expected, result.toString());\n    }\n\n    @Test\n    public void testMarshalInputPortNames() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        Map<String, Object> inputMap = new HashMap<>();\n        inputMap.put(\"inputPortNames.0\", \"resetPort\");\n\n        JsonObject result = (JsonObject) TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalInputPortNames\", inputMap);\n\n        assertNotNull(result);\n\n        String expected = \"{\\\"0\\\":\\\"resetPort\\\"}\";\n        assertEquals(expected, result.toString());\n    }\n\n    @Test\n    public void testMarshalOutputPortNames() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        Map<String, Object> inputMap = new HashMap<>();\n        inputMap.put(\"outputPortNames.3\", \"then\");\n\n        JsonObject result = (JsonObject) TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalOutputPortNames\", inputMap);\n\n        assertNotNull(result);\n\n        String expected = \"{\\\"3\\\":\\\"then\\\"}\";\n        assertEquals(expected, result.toString());\n    }\n\n    @Test\n    public void testMarshalComponentProperties() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        Map<String, Object> inputMap = new HashMap<>();\n        inputMap.put(\"inputPortNames.0\", \"resetPort\");\n        inputMap.put(\"position.x\", 10f);\n        inputMap.put(\"position.y\", 100f);\n        inputMap.put(\"outputPortNames.3\", \"then\");\n        inputMap.put(\"inputPortCount\", 0);\n        inputMap.put(\"outputPortCount\", 5);\n\n        JsonObject result = (JsonObject) TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalComponentProperties\",\n                \"testPid\", inputMap);\n\n        assertNotNull(result);\n\n        String expected = \"{\\\"pid\\\":\\\"testPid\\\",\\\"inputPortCount\\\":0,\\\"outputPortCount\\\":5,\\\"renderingProperties\\\":{\\\"position\\\":{\\\"x\\\":10,\\\"y\\\":100},\\\"inputPortNames\\\":{\\\"0\\\":\\\"resetPort\\\"},\\\"outputPortNames\\\":{\\\"3\\\":\\\"then\\\"}}}\";\n        assertEquals(expected, result.toString());\n    }\n\n    @Test\n    public void testMarshalWireComponentConfigurationList() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        Map<String, Object> inputMap = new HashMap<>();\n        inputMap.put(\"inputPortNames.0\", \"resetPort\");\n        inputMap.put(\"position.x\", 10f);\n        inputMap.put(\"position.y\", 100f);\n        inputMap.put(\"outputPortNames.3\", \"then\");\n        inputMap.put(\"inputPortCount\", 0);\n        inputMap.put(\"outputPortCount\", 5);\n\n        JsonObject result = (JsonObject) TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalComponentProperties\",\n                \"testPid\", inputMap);\n\n        assertNotNull(result);\n\n        String expected = \"{\\\"pid\\\":\\\"testPid\\\",\\\"inputPortCount\\\":0,\\\"outputPortCount\\\":5,\\\"renderingProperties\\\":{\\\"position\\\":{\\\"x\\\":10,\\\"y\\\":100},\\\"inputPortNames\\\":{\\\"0\\\":\\\"resetPort\\\"},\\\"outputPortNames\\\":{\\\"3\\\":\\\"then\\\"}}}\";\n        assertEquals(expected, result.toString());\n    }\n\n    @Test\n    public void testMarshalWireGraphConfiguration() throws Throwable {\n        WireGraphJsonMarshallUnmarshallImpl jsonEncoderDecoder = new WireGraphJsonMarshallUnmarshallImpl();\n\n        Map<String, Object> inputMap = new HashMap<>();\n        inputMap.put(\"inputPortNames.0\", \"resetPort\");\n        inputMap.put(\"position.x\", 10f);\n        inputMap.put(\"position.y\", 100f);\n        inputMap.put(\"outputPortNames.3\", \"then\");\n        inputMap.put(\"inputPortCount\", 0);\n        inputMap.put(\"outputPortCount\", 5);\n\n        ComponentConfiguration emitterConfig = new ComponentConfigurationImpl(\"emitterPid\", null, null);\n        ComponentConfiguration receiverConfig = new ComponentConfigurationImpl(\"receiverPid\", null, null);\n\n        List<WireComponentConfiguration> wireComponentConfigurations = new ArrayList<>();\n        WireComponentConfiguration emitterWireComponentConfiguration = new WireComponentConfiguration(emitterConfig,\n                inputMap);\n        WireComponentConfiguration receiverWireComponentConfiguration = new WireComponentConfiguration(receiverConfig,\n                inputMap);\n        wireComponentConfigurations.add(emitterWireComponentConfiguration);\n        wireComponentConfigurations.add(receiverWireComponentConfiguration);\n\n        List<MultiportWireConfiguration> wireConfigurations = new ArrayList<>();\n        MultiportWireConfiguration wireConfiguration = new MultiportWireConfiguration(\"emitterPid\", \"receiverPid\", 0,\n                0);\n        wireConfigurations.add(wireConfiguration);\n\n        WireGraphConfiguration wireGraphConfiguration = new WireGraphConfiguration(wireComponentConfigurations,\n                wireConfigurations);\n\n        ByteArrayOutputStream outStream = new ByteArrayOutputStream();\n        OutputStreamWriter writer = new OutputStreamWriter(outStream, StandardCharsets.UTF_8);\n        TestUtil.invokePrivate(jsonEncoderDecoder, \"marshalWireGraphConfiguration\", writer, wireGraphConfiguration);\n        writer.flush();\n\n        assertNotNull(outStream.toString());\n\n        String expected = \"{\\\"components\\\":[{\\\"pid\\\":\\\"emitterPid\\\",\\\"inputPortCount\\\":0,\\\"outputPortCount\\\":5,\\\"renderingProperties\\\":{\\\"position\\\":{\\\"x\\\":10,\\\"y\\\":100},\\\"inputPortNames\\\":{\\\"0\\\":\\\"resetPort\\\"},\\\"outputPortNames\\\":{\\\"3\\\":\\\"then\\\"}}},{\\\"pid\\\":\\\"receiverPid\\\",\\\"inputPortCount\\\":0,\\\"outputPortCount\\\":5,\\\"renderingProperties\\\":{\\\"position\\\":{\\\"x\\\":10,\\\"y\\\":100},\\\"inputPortNames\\\":{\\\"0\\\":\\\"resetPort\\\"},\\\"outputPortNames\\\":{\\\"3\\\":\\\"then\\\"}}}],\\\"wires\\\":[{\\\"emitter\\\":\\\"emitterPid\\\",\\\"emitterPort\\\":0,\\\"receiver\\\":\\\"receiverPid\\\",\\\"receiverPort\\\":0}]}\";\n        assertEquals(expected, outStream.toString());\n    }\n\n    @Test\n    public void testSystemDeploymentPackages() throws KuraException {\n        SystemDeploymentPackages systemDeploymentPackages = new SystemDeploymentPackages();\n        SystemDeploymentPackage[] systemDeploymentPackageArray = new SystemDeploymentPackage[1];\n        SystemDeploymentPackage systemDeploymentPackage = new SystemDeploymentPackage(\"dp1\", \"1.0.0\");\n        SystemBundle[] systemBundles = new SystemBundle[1];\n        systemBundles[0] = new SystemBundle(\"bundle1\", \"2.0.0\");\n        systemBundles[0].setId(0);\n        systemBundles[0].setState(\"ACTIVE\");\n        systemDeploymentPackage.setBundleInfos(systemBundles);\n        systemDeploymentPackageArray[0] = systemDeploymentPackage;\n        systemDeploymentPackages.setDeploymentPackages(systemDeploymentPackageArray);\n\n        String json = new JsonMarshallUnmarshallImpl().marshal(systemDeploymentPackages);\n\n        String expectedJson = \"{\\\"deploymentPackages\\\":[{\\\"name\\\":\\\"dp1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"bundles\\\":[{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"id\\\":0,\\\"state\\\":\\\"ACTIVE\\\",\\\"signed\\\":false}],\\\"signed\\\":false}]}\";\n        assertEquals(expectedJson, json);\n    }\n\n    @Test\n    public void testSystemDeploymentPackagesAllSigned() throws KuraException {\n        SystemDeploymentPackages systemDeploymentPackages = new SystemDeploymentPackages();\n        SystemDeploymentPackage[] systemDeploymentPackageArray = new SystemDeploymentPackage[1];\n        SystemDeploymentPackage systemDeploymentPackage = new SystemDeploymentPackage(\"dp1\", \"1.0.0\");\n        SystemBundle[] systemBundles = new SystemBundle[1];\n        systemBundles[0] = new SystemBundle(\"bundle1\", \"2.0.0\");\n        systemBundles[0].setId(0);\n        systemBundles[0].setState(\"ACTIVE\");\n        systemBundles[0].setSigned(true);\n        systemDeploymentPackage.setBundleInfos(systemBundles);\n        systemDeploymentPackage.setSigned(true);\n        systemDeploymentPackageArray[0] = systemDeploymentPackage;\n        systemDeploymentPackages.setDeploymentPackages(systemDeploymentPackageArray);\n\n        String json = new JsonMarshallUnmarshallImpl().marshal(systemDeploymentPackages);\n\n        String expectedJson = \"{\\\"deploymentPackages\\\":[{\\\"name\\\":\\\"dp1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"bundles\\\":[{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"id\\\":0,\\\"state\\\":\\\"ACTIVE\\\",\\\"signed\\\":true}],\\\"signed\\\":true}]}\";\n        assertEquals(expectedJson, json);\n    }\n\n    @Test\n    public void testSystemBundles() throws KuraException {\n        SystemBundles systemBundles = new SystemBundles();\n        SystemBundle[] systemBundlesArray = new SystemBundle[2];\n        systemBundlesArray[0] = new SystemBundle(\"bundle1\", \"1.0.0\");\n        systemBundlesArray[0].setId(0);\n        systemBundlesArray[0].setState(\"ACTIVE\");\n        systemBundlesArray[1] = new SystemBundle(\"bundle2\", \"2.0.0\");\n        systemBundlesArray[1].setId(1);\n        systemBundlesArray[1].setState(\"RESOLVED\");\n        systemBundlesArray[1].setSigned(true);\n        systemBundles.setBundles(systemBundlesArray);\n\n        String json = new JsonMarshallUnmarshallImpl().marshal(systemBundles);\n\n        String expectedJson = \"{\\\"bundles\\\":[{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"id\\\":0,\\\"state\\\":\\\"ACTIVE\\\",\\\"signed\\\":false},{\\\"name\\\":\\\"bundle2\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"id\\\":1,\\\"state\\\":\\\"RESOLVED\\\",\\\"signed\\\":true}]}\";\n        assertEquals(expectedJson, json);\n    }\n\n    @Test\n    public void testSystemBundlesAllSigned() throws KuraException {\n        SystemBundles systemBundles = new SystemBundles();\n        SystemBundle[] systemBundlesArray = new SystemBundle[2];\n        systemBundlesArray[0] = new SystemBundle(\"bundle1\", \"1.0.0\");\n        systemBundlesArray[0].setId(0);\n        systemBundlesArray[0].setState(\"ACTIVE\");\n        systemBundlesArray[0].setSigned(true);\n        systemBundlesArray[1] = new SystemBundle(\"bundle2\", \"2.0.0\");\n        systemBundlesArray[1].setId(1);\n        systemBundlesArray[1].setState(\"RESOLVED\");\n        systemBundlesArray[1].setSigned(true);\n        systemBundles.setBundles(systemBundlesArray);\n\n        String json = new JsonMarshallUnmarshallImpl().marshal(systemBundles);\n\n        String expectedJson = \"{\\\"bundles\\\":[{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"id\\\":0,\\\"state\\\":\\\"ACTIVE\\\",\\\"signed\\\":true},{\\\"name\\\":\\\"bundle2\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"id\\\":1,\\\"state\\\":\\\"RESOLVED\\\",\\\"signed\\\":true}]}\";\n        assertEquals(expectedJson, json);\n    }\n\n    @Test\n    public void testSystemPackages() throws KuraException {\n        List<SystemPackage> systemPackageList = new ArrayList<>();\n        systemPackageList.add(new SystemPackage(\"package1\", \"1.0.0\", SystemResourceType.DEB));\n        systemPackageList.add(new SystemPackage(\"package2\", \"2.0.0\", SystemResourceType.RPM));\n        SystemPackages systemPackages = new SystemPackages(systemPackageList);\n\n        String json = new JsonMarshallUnmarshallImpl().marshal(systemPackages);\n\n        String expectedJson = \"{\\\"systemPackages\\\":[{\\\"name\\\":\\\"package1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"type\\\":\\\"DEB\\\"},{\\\"name\\\":\\\"package2\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"type\\\":\\\"RPM\\\"}]}\";\n        assertEquals(expectedJson, json);\n    }\n\n    @Test\n    public void testSystemResourcesInfo() throws KuraException {\n        List<SystemResourceInfo> SystemResourcesInfoList = new ArrayList<>();\n        SystemResourcesInfoList.add(new SystemResourceInfo(\"package1\", \"1.0.0\", SystemResourceType.DEB));\n        SystemResourcesInfoList.add(new SystemResourceInfo(\"bundle1\", \"2.0.0\", SystemResourceType.BUNDLE));\n        SystemResourcesInfoList.add(new SystemResourceInfo(\"dp1\", \"3.0.0\", SystemResourceType.DP));\n        SystemResourcesInfo systemResourceInfo = new SystemResourcesInfo(SystemResourcesInfoList);\n\n        String json = new JsonMarshallUnmarshallImpl().marshal(systemResourceInfo);\n\n        String expectedJson = \"{\\\"inventory\\\":[{\\\"name\\\":\\\"package1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"type\\\":\\\"DEB\\\"},{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"type\\\":\\\"BUNDLE\\\"},{\\\"name\\\":\\\"dp1\\\",\\\"version\\\":\\\"3.0.0\\\",\\\"type\\\":\\\"DP\\\"}]}\";\n        assertEquals(expectedJson, json);\n    }\n\n    @Test\n    public void testSystemDeploymentPackagesWithStreamMarshal() throws KuraException {\n        SystemDeploymentPackages systemDeploymentPackages = new SystemDeploymentPackages();\n        SystemDeploymentPackage[] systemDeploymentPackageArray = new SystemDeploymentPackage[1];\n        SystemDeploymentPackage systemDeploymentPackage = new SystemDeploymentPackage(\"dp1\", \"1.0.0\");\n        SystemBundle[] systemBundles = new SystemBundle[1];\n        systemBundles[0] = new SystemBundle(\"bundle1\", \"2.0.0\");\n        systemBundles[0].setId(0);\n        systemBundles[0].setState(\"ACTIVE\");\n        systemDeploymentPackage.setBundleInfos(systemBundles);\n        systemDeploymentPackageArray[0] = systemDeploymentPackage;\n        systemDeploymentPackages.setDeploymentPackages(systemDeploymentPackageArray);\n\n        OutputStream out = new ByteArrayOutputStream();\n\n        new JsonMarshallUnmarshallImpl().marshal(out, systemDeploymentPackages);\n\n        String expectedJson = \"{\\\"deploymentPackages\\\":[{\\\"name\\\":\\\"dp1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"bundles\\\":[{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"id\\\":0,\\\"state\\\":\\\"ACTIVE\\\",\\\"signed\\\":false}],\\\"signed\\\":false}]}\";\n        assertEquals(expectedJson, out.toString());\n    }\n\n    @Test\n    public void testSystemDeploymentPackagesAllSignedWithStreamMarshal() throws KuraException {\n        SystemDeploymentPackages systemDeploymentPackages = new SystemDeploymentPackages();\n        SystemDeploymentPackage[] systemDeploymentPackageArray = new SystemDeploymentPackage[1];\n        SystemDeploymentPackage systemDeploymentPackage = new SystemDeploymentPackage(\"dp1\", \"1.0.0\");\n        SystemBundle[] systemBundles = new SystemBundle[1];\n        systemBundles[0] = new SystemBundle(\"bundle1\", \"2.0.0\");\n        systemBundles[0].setId(0);\n        systemBundles[0].setState(\"ACTIVE\");\n        systemBundles[0].setSigned(true);\n        systemDeploymentPackage.setBundleInfos(systemBundles);\n        systemDeploymentPackage.setSigned(true);\n        systemDeploymentPackageArray[0] = systemDeploymentPackage;\n        systemDeploymentPackages.setDeploymentPackages(systemDeploymentPackageArray);\n\n        OutputStream out = new ByteArrayOutputStream();\n\n        new JsonMarshallUnmarshallImpl().marshal(out, systemDeploymentPackages);\n\n        String expectedJson = \"{\\\"deploymentPackages\\\":[{\\\"name\\\":\\\"dp1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"bundles\\\":[{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"id\\\":0,\\\"state\\\":\\\"ACTIVE\\\",\\\"signed\\\":true}],\\\"signed\\\":true}]}\";\n        assertEquals(expectedJson, out.toString());\n    }\n\n    @Test\n    public void testSystemBundlesWithStreamMarshal() throws KuraException {\n        SystemBundles systemBundles = new SystemBundles();\n        SystemBundle[] systemBundlesArray = new SystemBundle[2];\n        systemBundlesArray[0] = new SystemBundle(\"bundle1\", \"1.0.0\");\n        systemBundlesArray[0].setId(0);\n        systemBundlesArray[0].setState(\"ACTIVE\");\n        systemBundlesArray[1] = new SystemBundle(\"bundle2\", \"2.0.0\");\n        systemBundlesArray[1].setId(1);\n        systemBundlesArray[1].setState(\"RESOLVED\");\n        systemBundlesArray[1].setSigned(true);\n        systemBundles.setBundles(systemBundlesArray);\n\n        OutputStream out = new ByteArrayOutputStream();\n\n        new JsonMarshallUnmarshallImpl().marshal(out, systemBundles);\n\n        String expectedJson = \"{\\\"bundles\\\":[{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"id\\\":0,\\\"state\\\":\\\"ACTIVE\\\",\\\"signed\\\":false},{\\\"name\\\":\\\"bundle2\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"id\\\":1,\\\"state\\\":\\\"RESOLVED\\\",\\\"signed\\\":true}]}\";\n        assertEquals(expectedJson, out.toString());\n    }\n\n    @Test\n    public void testSystemBundlesAllSignedWithStreamMarshal() throws KuraException {\n        SystemBundles systemBundles = new SystemBundles();\n        SystemBundle[] systemBundlesArray = new SystemBundle[2];\n        systemBundlesArray[0] = new SystemBundle(\"bundle1\", \"1.0.0\");\n        systemBundlesArray[0].setId(0);\n        systemBundlesArray[0].setState(\"ACTIVE\");\n        systemBundlesArray[0].setSigned(true);\n        systemBundlesArray[1] = new SystemBundle(\"bundle2\", \"2.0.0\");\n        systemBundlesArray[1].setId(1);\n        systemBundlesArray[1].setState(\"RESOLVED\");\n        systemBundlesArray[1].setSigned(true);\n        systemBundles.setBundles(systemBundlesArray);\n\n        OutputStream out = new ByteArrayOutputStream();\n\n        new JsonMarshallUnmarshallImpl().marshal(out, systemBundles);\n\n        String expectedJson = \"{\\\"bundles\\\":[{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"id\\\":0,\\\"state\\\":\\\"ACTIVE\\\",\\\"signed\\\":true},{\\\"name\\\":\\\"bundle2\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"id\\\":1,\\\"state\\\":\\\"RESOLVED\\\",\\\"signed\\\":true}]}\";\n        assertEquals(expectedJson, out.toString());\n    }\n\n    @Test\n    public void testSystemPackagesWithStreamMarshal() throws KuraException {\n        List<SystemPackage> systemPackageList = new ArrayList<>();\n        systemPackageList.add(new SystemPackage(\"package1\", \"1.0.0\", SystemResourceType.DEB));\n        systemPackageList.add(new SystemPackage(\"package2\", \"2.0.0\", SystemResourceType.RPM));\n        SystemPackages systemPackages = new SystemPackages(systemPackageList);\n\n        OutputStream out = new ByteArrayOutputStream();\n\n        new JsonMarshallUnmarshallImpl().marshal(out, systemPackages);\n\n        String expectedJson = \"{\\\"systemPackages\\\":[{\\\"name\\\":\\\"package1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"type\\\":\\\"DEB\\\"},{\\\"name\\\":\\\"package2\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"type\\\":\\\"RPM\\\"}]}\";\n        assertEquals(expectedJson, out.toString());\n    }\n\n    @Test\n    public void testSystemResourcesInfoWithStreamMarshal() throws KuraException {\n        List<SystemResourceInfo> SystemResourcesInfoList = new ArrayList<>();\n        SystemResourcesInfoList.add(new SystemResourceInfo(\"package1\", \"1.0.0\", SystemResourceType.DEB));\n        SystemResourcesInfoList.add(new SystemResourceInfo(\"bundle1\", \"2.0.0\", SystemResourceType.BUNDLE));\n        SystemResourcesInfoList.add(new SystemResourceInfo(\"dp1\", \"3.0.0\", SystemResourceType.DP));\n        SystemResourcesInfo systemResourceInfo = new SystemResourcesInfo(SystemResourcesInfoList);\n\n        OutputStream out = new ByteArrayOutputStream();\n\n        new JsonMarshallUnmarshallImpl().marshal(out, systemResourceInfo);\n\n        String expectedJson = \"{\\\"inventory\\\":[{\\\"name\\\":\\\"package1\\\",\\\"version\\\":\\\"1.0.0\\\",\\\"type\\\":\\\"DEB\\\"},{\\\"name\\\":\\\"bundle1\\\",\\\"version\\\":\\\"2.0.0\\\",\\\"type\\\":\\\"BUNDLE\\\"},{\\\"name\\\":\\\"dp1\\\",\\\"version\\\":\\\"3.0.0\\\",\\\"type\\\":\\\"DP\\\"}]}\";\n        assertEquals(expectedJson, out.toString());\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.clock.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.linux.clock.test\nBundle-SymbolicName: org.eclipse.kura.linux.clock.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.linux.clock\nImport-Package: org.apache.commons.io;version=\"2.4.0\",\n org.eclipse.kura.core.linux.executor;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.core.util;version=\"[2.0,3.0)\",\n org.eclipse.kura.crypto;version=\"1.3.0\",\n org.eclipse.kura.executor;version=\"[1.0,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.7\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.clock.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.clock.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = \nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.clock.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.linux.clock.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n                <configuration>\n                    <skipTests>true</skipTests>  <!-- no IT tests-->\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.clock.test/src/test/java/org/eclipse/kura/linux/clock/ChronyClockSyncProviderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.linux.executor.LinuxExitStatus;\nimport org.eclipse.kura.core.util.IOUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.junit.Test;\n\npublic class ChronyClockSyncProviderTest {\n\n    @Test\n    public void testSynch() throws NoSuchFieldException, IOException, KuraException, NoSuchAlgorithmException {\n\n        InputStream journalEntry = new ByteArrayInputStream(\n                IOUtil.readResource(\"journal-entry.json\").getBytes(StandardCharsets.UTF_8));\n        OutputStream statusOutputStream = new ByteArrayOutputStream();\n        IOUtils.copy(journalEntry, statusOutputStream);\n\n        CommandStatus successFullStatus = new CommandStatus(new Command(new String[] {}), new LinuxExitStatus(0));\n        CommandStatus notRunningProgramStatus = new CommandStatus(new Command(new String[] {}), new LinuxExitStatus(3));\n        successFullStatus.setOutputStream(statusOutputStream);\n\n        CommandExecutorService commandExecutorMock = mock(CommandExecutorService.class);\n        when(commandExecutorMock.execute(any())).thenReturn(successFullStatus);\n        when(commandExecutorMock.execute(new Command(new String[] { \"systemctl\", \"status\", \"chrony\" })))\n                .thenReturn(notRunningProgramStatus);\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        when(cryptoServiceMock.sha256Hash(any())).thenReturn(\"\");\n\n        ChronyClockSyncProvider ntsClockSyncProvider = new ChronyClockSyncProvider(commandExecutorMock,\n                cryptoServiceMock);\n        AtomicBoolean invoked = new AtomicBoolean(false);\n        ClockSyncListener listener = (offset, update) -> {\n            assertEquals(0, offset);\n\n            invoked.set(true);\n        };\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.provider\", \"chrony-advanced\");\n        properties.put(\"chrony.advanced.configlocation\", \"placeholder_path\");\n        ClockServiceConfig clockServiceConfig = new ClockServiceConfig(properties);\n\n        ntsClockSyncProvider.init(clockServiceConfig, null, listener);\n\n        boolean synched = ntsClockSyncProvider.syncClock();\n\n        assertTrue(synched);\n        assertTrue(invoked.get());\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.clock.test/src/test/java/org/eclipse/kura/linux/clock/ClockServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assume.assumeTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.ArgumentMatchers.isA;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport org.eclipse.kura.clock.ClockEvent;\nimport org.eclipse.kura.core.linux.executor.LinuxExitStatus;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.core.util.IOUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.executor.Command;\nimport org.eclipse.kura.executor.CommandExecutorService;\nimport org.eclipse.kura.executor.CommandStatus;\nimport org.junit.Test;\nimport org.osgi.service.event.EventAdmin;\n\npublic class ClockServiceImplTest {\n\n    @Test\n    public void testActivateException() {\n        // error log output only\n\n        ClockServiceImpl svc = new ClockServiceImpl();\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", \"true\");\n\n        svc.activate(properties);\n    }\n\n    @Test\n    public void testActivateDeactivate() throws NoSuchFieldException {\n        // too few properties, but enough to test activation\n\n        ClockServiceImpl svc = new ClockServiceImpl();\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.provider\", \"java-ntp\");\n        svc.activate(properties);\n\n        Object provider = TestUtil.getFieldValue(svc, \"provider\");\n        assertNotNull(provider);\n        assertTrue(provider instanceof JavaNtpClockSyncProvider);\n\n        svc.deactivate();\n\n        provider = TestUtil.getFieldValue(svc, \"provider\");\n        assertNull(provider);\n    }\n\n    @Test\n    public void testActivateDeactivateChronyProvider() throws NoSuchFieldException {\n        CommandStatus status = new CommandStatus(new Command(new String[] {}), new LinuxExitStatus(0));\n        CommandExecutorService serviceMock = mock(CommandExecutorService.class);\n        when(serviceMock.execute(any())).thenReturn(status);\n\n        ClockServiceImpl clockService = new ClockServiceImpl();\n        clockService.setExecutorService(serviceMock);\n\n        Map<String, Object> properties = new HashMap<>();\n\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.provider\", ClockProviderType.CHRONY_ADVANCED.getValue());\n\n        clockService.activate(properties);\n\n        Object provider = TestUtil.getFieldValue(clockService, \"provider\");\n        assertNotNull(provider);\n        assertTrue(provider instanceof ChronyClockSyncProvider);\n\n        clockService.deactivate();\n\n        provider = TestUtil.getFieldValue(clockService, \"provider\");\n        assertNull(provider);\n    }\n\n    @Test\n    public void testActivateDeactivateChronyProviderWithConfiguration()\n            throws NoSuchFieldException, IOException, NoSuchAlgorithmException {\n        CommandStatus status = new CommandStatus(new Command(new String[] {}), new LinuxExitStatus(0));\n        CommandExecutorService serviceMock = mock(CommandExecutorService.class);\n        when(serviceMock.execute(any())).thenReturn(status);\n\n        CryptoService cryptoServiceMock = mock(CryptoService.class);\n        when(cryptoServiceMock.sha256Hash(anyString()))\n                .thenReturn(\"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad\");\n\n        ClockServiceImpl clockService = new ClockServiceImpl();\n        clockService.setExecutorService(serviceMock);\n        clockService.setCryptoService(cryptoServiceMock);\n\n        Map<String, Object> properties = new HashMap<>();\n\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.provider\", ClockProviderType.CHRONY_ADVANCED.getValue());\n        properties.put(\"chrony.advanced.config\", IOUtil.readResource(\"chrony.conf\"));\n\n        clockService.activate(properties);\n\n        Object provider = TestUtil.getFieldValue(clockService, \"provider\");\n        assertNotNull(provider);\n        assertTrue(provider instanceof ChronyClockSyncProvider);\n\n        clockService.deactivate();\n\n        provider = TestUtil.getFieldValue(clockService, \"provider\");\n        assertNull(provider);\n    }\n\n    @Test\n    public void testUpdate() throws NoSuchFieldException {\n        // a new provider is created, disabled when enabled = false\n\n        ClockServiceImpl svc = new ClockServiceImpl();\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.provider\", \"java-ntp\");\n        svc.activate(properties);\n\n        Object provider = TestUtil.getFieldValue(svc, \"provider\");\n\n        svc.updated(properties);\n\n        assertEquals(provider, TestUtil.getFieldValue(svc, \"provider\"));\n\n        // disable it\n        properties.put(\"enabled\", false);\n\n        svc.updated(properties);\n\n        assertNull(TestUtil.getFieldValue(svc, \"provider\"));\n    }\n\n    @Test\n    public void testJavaNTPScheduleOnce() throws Throwable {\n        // test java NTP provider's scheduleOnce()\n\n        Object lock = new Object();\n\n        ClockServiceImpl svc = new ClockServiceImpl() {\n\n            @Override\n            public void onClockUpdate(long offset, boolean update) {\n                synchronized (lock) {\n                    lock.notifyAll();\n                }\n            }\n        };\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.provider\", \"java-ntp\");\n        properties.put(\"clock.ntp.host\", \"localhost\");\n        properties.put(\"clock.ntp.port\", 123);\n        properties.put(\"clock.ntp.timeout\", 100);\n        properties.put(\"clock.ntp.retry.interval\", 1);\n        properties.put(\"clock.ntp.refresh-interval\", 0);\n        properties.put(\"clock.ntp.max-retry\", 1);\n        svc.activate(properties);\n\n        TestUtil.invokePrivate(svc, \"startClockSyncProvider\");\n\n        JavaNtpClockSyncProvider provider = (JavaNtpClockSyncProvider) TestUtil.getFieldValue(svc, \"provider\");\n\n        synchronized (lock) {\n            lock.wait(1500); // wait a bit so that synch runs once; it will wait the full time\n        }\n\n        ScheduledExecutorService scheduler = (ScheduledExecutorService) TestUtil.getFieldValue(provider, \"scheduler\");\n        List<Runnable> list = scheduler.shutdownNow();\n        assertTrue(list.isEmpty()); // task has not been re-scheduled\n    }\n\n    @Test\n    public void testClockUpdateBasic() throws Throwable {\n        // test the service's onClockUpdate(), without performing the actual updates\n\n        ClockServiceImpl svc = new ClockServiceImpl();\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.set.hwclock\", false);\n        svc.activate(properties);\n\n        svc.onClockUpdate(0, false); // 0 offset => don't perform sys clock update\n\n        verify(eaMock, times(1)).postEvent(isA(ClockEvent.class));\n    }\n\n    @Test\n    public void testClockUpdateLinux() throws Throwable {\n        // test the service's onClockUpdate(), only run on Linux\n\n        assumeTrue(\"Only run this test on Linux\", System.getProperty(\"os.name\").matches(\"[Ll]inux\"));\n        assumeTrue(\"Only run this test as root\", \"root\".equals(System.getProperty(\"user.name\")));\n\n        CommandStatus status = new CommandStatus(new Command(new String[] {}), new LinuxExitStatus(0));\n        CommandExecutorService serviceMock = mock(CommandExecutorService.class);\n        when(serviceMock.execute(any())).thenReturn(status);\n        ClockServiceImpl svc = new ClockServiceImpl();\n        svc.setExecutorService(serviceMock);\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.set.hwclock\", true);\n        TestUtil.setFieldValue(svc, \"properties\", properties);\n\n        svc.onClockUpdate(1, true);\n\n        verify(eaMock, times(1)).postEvent(isA(ClockEvent.class)); // sys clock updated successfully\n    }\n\n    @Test\n    public void testClockUpdateErrors() throws Throwable {\n        // test the service's onClockUpdate() with clock update failures; test of proper logging, mostly\n\n        CommandStatus status = new CommandStatus(new Command(new String[] {}), new LinuxExitStatus(1));\n        CommandExecutorService serviceMock = mock(CommandExecutorService.class);\n        when(serviceMock.execute(any())).thenReturn(status);\n        ClockServiceImpl svc = new ClockServiceImpl();\n        svc.setExecutorService(serviceMock);\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.set.hwclock\", true);\n        svc.activate(properties);\n\n        svc.onClockUpdate(1, true);\n\n        verify(eaMock, times(0)).postEvent(isA(ClockEvent.class)); // sys clock not updated\n    }\n\n    @Test\n    public void testClockUpdate() throws Throwable {\n        // test the service's onClockUpdate()\n\n        CommandStatus status = new CommandStatus(new Command(new String[] {}), new LinuxExitStatus(0));\n        CommandExecutorService serviceMock = mock(CommandExecutorService.class);\n        when(serviceMock.execute(any())).thenReturn(status);\n        ClockServiceImpl svc = new ClockServiceImpl();\n        svc.setExecutorService(serviceMock);\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.set.hwclock\", true);\n        svc.activate(properties);\n\n        svc.onClockUpdate(1, true);\n\n        verify(eaMock, times(1)).postEvent(isA(ClockEvent.class)); // sys clock updated successfully\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.clock.test/src/test/java/org/eclipse/kura/linux/clock/JavaNtpClockSyncProviderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.linux.clock;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.junit.Test;\n\npublic class JavaNtpClockSyncProviderTest {\n\n    private static final long WAIT_CLOCK_SYNC_MS = 1000;\n    private static final long SYNC_TIMEOUT_MS = 100;\n    private static final long SLACK_WAIT_TIME_MS = 10;\n\n    @Test\n    public void testStartFail() throws Throwable {\n        // test running updates through java NTP - first run doesn't sync\n\n        Object lock = new Object();\n\n        JavaNtpClockSyncProvider provider = new JavaNtpClockSyncProvider() {\n\n            @Override\n            protected boolean syncClock() throws KuraException {\n                synchronized (lock) {\n                    lock.notifyAll();\n                }\n\n                return false;\n            }\n        };\n\n        initProviderWithProperties(provider);\n        provider.start();\n\n        synchronized (lock) {\n            lock.wait(WAIT_CLOCK_SYNC_MS); // wait a bit so that synch runs once\n        }\n\n        waitProviderToSync(provider);\n\n        assertTrue((boolean) TestUtil.getFieldValue(provider, \"isSynced\"));\n\n        // now wait for the second run\n        Thread.sleep(WAIT_CLOCK_SYNC_MS);\n\n        assertEquals(1, TestUtil.getFieldValue(provider, \"syncCount\"));\n        assertEquals(0, TestUtil.getFieldValue(provider, \"numRetry\"));\n        assertFalse((boolean) TestUtil.getFieldValue(provider, \"isSynced\"));\n    }\n\n    private void initProviderWithProperties(JavaNtpClockSyncProvider provider) throws KuraException {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"enabled\", true);\n        properties.put(\"clock.provider\", \"java-ntp\");\n        properties.put(\"clock.ntp.host\", \"localhost\");\n        properties.put(\"clock.ntp.port\", 123);\n        properties.put(\"clock.ntp.timeout\", 100);\n        properties.put(\"clock.ntp.retry.interval\", 1);\n        properties.put(\"clock.ntp.refresh-interval\", 1);\n        properties.put(\"clock.ntp.max-retry\", 1);\n\n        ClockServiceConfig clockServiceConfig = new ClockServiceConfig(properties);\n        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();\n\n        provider.init(clockServiceConfig, scheduler, null);\n    }\n\n    @Test\n    public void testStart() throws Throwable {\n        // test running updates through java NTP - synch immediately\n\n        Object lock = new Object();\n\n        JavaNtpClockSyncProvider provider = new JavaNtpClockSyncProvider() {\n\n            @Override\n            protected boolean syncClock() throws KuraException {\n                synchronized (lock) {\n                    lock.notifyAll();\n                }\n\n                return true;\n            }\n        };\n\n        initProviderWithProperties(provider);\n        provider.start();\n\n        synchronized (lock) {\n            lock.wait(WAIT_CLOCK_SYNC_MS); // wait a bit so that synch runs once\n        }\n\n        waitProviderToSync(provider);\n\n        assertTrue((boolean) TestUtil.getFieldValue(provider, \"isSynced\"));\n        assertEquals(0, TestUtil.getFieldValue(provider, \"syncCount\"));\n        assertEquals(0, TestUtil.getFieldValue(provider, \"numRetry\"));\n    }\n\n    @Test\n    public void testStartSynchException() throws Throwable {\n        // test running updates through java NTP - exception during synch\n\n        Object lock = new Object();\n\n        JavaNtpClockSyncProvider provider = new JavaNtpClockSyncProvider() {\n\n            @Override\n            protected boolean syncClock() throws KuraException {\n                synchronized (lock) {\n                    lock.notifyAll();\n                }\n\n                throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, \"test\");\n            }\n        };\n\n        initProviderWithProperties(provider);\n        provider.start();\n\n        synchronized (lock) {\n            lock.wait(WAIT_CLOCK_SYNC_MS); // wait a bit so that synch runs once\n        }\n\n        waitProviderToSync(provider);\n\n        assertEquals(0, TestUtil.getFieldValue(provider, \"syncCount\"));\n        assertEquals(1, TestUtil.getFieldValue(provider, \"numRetry\"));\n        assertTrue((boolean) TestUtil.getFieldValue(provider, \"isSynced\"));\n    }\n\n    private void waitProviderToSync(JavaNtpClockSyncProvider provider) throws InterruptedException {\n        long elapsedTime = 0;\n        while (!provider.isSynced && SYNC_TIMEOUT_MS > elapsedTime) {\n            Thread.sleep(SLACK_WAIT_TIME_MS);\n            elapsedTime += SLACK_WAIT_TIME_MS;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.clock.test/src/test/resources/chrony.conf",
    "content": "server time.cloudflare.com iburst nts\nserver nts.sth1.ntp.se iburst nts\nserver nts.sth2.ntp.se iburst nts\n\nsourcedir /etc/chrony/sources.d\n\ndriftfile /var/lib/chrony/chrony.drift\n\nlogdir /var/log/chrony\n\nmaxupdateskew 100.0\n\nrtcsync\n\nmakestep 1 3\n\nleapsectz right/UTC\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.clock.test/src/test/resources/journal-entry.json",
    "content": "{\n\t\"__MONOTONIC_TIMESTAMP\" : \"60346572534\",\n\t\"__CURSOR\" : \"s=65a5673def214faba8649471208a8c5d;i=9ac5;b=6e5e265212f243ada5d097d96d9bf71d;m=e0cef9ef6;t=5c6705e1c6e65;x=e9ca500f560703ed\",\n\t\"_BOOT_ID\" : \"6e5e265212f243ada5d097d96d9bf71d\",\n\t\"__REALTIME_TIMESTAMP\" : \"1625560801111653\",\n\t\"MESSAGE\" : \"System clock was stepped by 0.000247 seconds\"\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.usb.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.linux.usb.test\nBundle-SymbolicName: org.eclipse.kura.linux.usb.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.linux.usb\nImport-Package: org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.7\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.usb.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.usb.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.usb.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.linux.usb.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.usb.test/src/test/java/org/eclipse/kura/linux/usb/UsbServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.linux.usb;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.eclipse.kura.usb.UsbBlockDevice;\nimport org.eclipse.kura.usb.UsbDevice;\nimport org.eclipse.kura.usb.UsbDeviceEvent;\nimport org.eclipse.kura.usb.UsbNetDevice;\nimport org.eclipse.kura.usb.UsbTtyDevice;\nimport org.junit.Test;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventAdmin;\n\npublic class UsbServiceImplTest {\n\n    private String deviceNode = \"node\";\n    private String interfaceName = \"iface\";\n    private String manufacturerName = \"manufacturer\";\n    private String productId = \"productId\";\n    private String productName = \"product\";\n    private String usbBusNumber = \"busNo\";\n    private String usbDevicePath = \"path\";\n    private String vendorId = \"vendor\";\n\n    @Test\n    public void testAttachedBlock() {\n        UsbServiceImpl svc = new UsbServiceImpl();\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        doAnswer(invocation -> {\n            Event event = invocation.getArgument(0, Event.class);\n\n            assertEquals(\"org/eclipse/kura/usb/NetworkEvent/device/ADDED\", event.getTopic());\n            assertEquals(vendorId, event.getProperty(UsbDeviceEvent.USB_EVENT_VENDOR_ID_PROPERTY));\n            assertEquals(productId, event.getProperty(UsbDeviceEvent.USB_EVENT_PRODUCT_ID_PROPERTY));\n            assertEquals(manufacturerName, event.getProperty(UsbDeviceEvent.USB_EVENT_MANUFACTURER_NAME_PROPERTY));\n            assertEquals(productName, event.getProperty(UsbDeviceEvent.USB_EVENT_PRODUCT_NAME_PROPERTY));\n            assertEquals(usbBusNumber, event.getProperty(UsbDeviceEvent.USB_EVENT_BUS_NUMBER_PROPERTY));\n            assertEquals(usbDevicePath, event.getProperty(UsbDeviceEvent.USB_EVENT_DEVICE_PATH_PROPERTY));\n            assertEquals(usbBusNumber + \"-\" + usbDevicePath,\n                    event.getProperty(UsbDeviceEvent.USB_EVENT_USB_PORT_PROPERTY));\n            assertEquals(deviceNode, event.getProperty(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY));\n\n            return null;\n        }).when(eaMock).postEvent(any());\n\n        UsbDevice device = new UsbBlockDevice(vendorId, productId, manufacturerName, productName, usbBusNumber,\n                usbDevicePath, deviceNode);\n\n        svc.attached(device);\n\n        verify(eaMock, times(1)).postEvent(any());\n    }\n    @Test\n    public void testAttachedNet() {\n        UsbServiceImpl svc = new UsbServiceImpl();\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        doAnswer(invocation -> {\n            Event event = invocation.getArgument(0, Event.class);\n\n            assertEquals(\"org/eclipse/kura/usb/NetworkEvent/device/ADDED\", event.getTopic());\n            assertEquals(interfaceName, event.getProperty(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY));\n\n            return null;\n        }).when(eaMock).postEvent(any());\n\n        UsbDevice device = new UsbNetDevice(vendorId, productId, manufacturerName, productName, usbBusNumber,\n                usbDevicePath, interfaceName);\n\n        svc.attached(device);\n\n        verify(eaMock, times(1)).postEvent(any());\n    }\n    @Test\n    public void testAttachedTty() {\n        UsbServiceImpl svc = new UsbServiceImpl();\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        doAnswer(invocation -> {\n            Event event = invocation.getArgument(0, Event.class);\n\n            assertEquals(\"org/eclipse/kura/usb/NetworkEvent/device/ADDED\", event.getTopic());\n            assertEquals(deviceNode, event.getProperty(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY));\n\n            return null;\n        }).when(eaMock).postEvent(any());\n\n        UsbDevice device = new UsbTtyDevice(vendorId, productId, manufacturerName, productName, usbBusNumber,\n                usbDevicePath, deviceNode);\n\n        svc.attached(device);\n\n        verify(eaMock, times(1)).postEvent(any());\n    }\n    @Test\n    public void testDetachedBlock() {\n        UsbServiceImpl svc = new UsbServiceImpl();\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        doAnswer(invocation -> {\n            Event event = invocation.getArgument(0, Event.class);\n\n            assertEquals(\"org/eclipse/kura/usb/NetworkEvent/device/REMOVED\", event.getTopic());\n            assertEquals(deviceNode, event.getProperty(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY));\n\n            return null;\n        }).when(eaMock).postEvent(any());\n\n        UsbDevice device = new UsbBlockDevice(vendorId, productId, manufacturerName, productName, usbBusNumber,\n                usbDevicePath, deviceNode);\n\n        svc.detached(device);\n\n        verify(eaMock, times(1)).postEvent(any());\n    }\n\n    @Test\n    public void testDetachedNet() {\n        UsbServiceImpl svc = new UsbServiceImpl();\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        doAnswer(invocation -> {\n            Event event = invocation.getArgument(0, Event.class);\n\n            assertEquals(\"org/eclipse/kura/usb/NetworkEvent/device/REMOVED\", event.getTopic());\n            assertEquals(vendorId, event.getProperty(UsbDeviceEvent.USB_EVENT_VENDOR_ID_PROPERTY));\n            assertEquals(productId, event.getProperty(UsbDeviceEvent.USB_EVENT_PRODUCT_ID_PROPERTY));\n            assertEquals(manufacturerName, event.getProperty(UsbDeviceEvent.USB_EVENT_MANUFACTURER_NAME_PROPERTY));\n            assertEquals(productName, event.getProperty(UsbDeviceEvent.USB_EVENT_PRODUCT_NAME_PROPERTY));\n            assertEquals(usbBusNumber, event.getProperty(UsbDeviceEvent.USB_EVENT_BUS_NUMBER_PROPERTY));\n            assertEquals(usbDevicePath, event.getProperty(UsbDeviceEvent.USB_EVENT_DEVICE_PATH_PROPERTY));\n            assertEquals(usbBusNumber + \"-\" + usbDevicePath,\n                    event.getProperty(UsbDeviceEvent.USB_EVENT_USB_PORT_PROPERTY));\n            assertEquals(interfaceName, event.getProperty(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY));\n\n            return null;\n        }).when(eaMock).postEvent(any());\n\n        UsbDevice device = new UsbNetDevice(vendorId, productId, manufacturerName, productName, usbBusNumber,\n                usbDevicePath, interfaceName);\n\n        svc.detached(device);\n\n        verify(eaMock, times(1)).postEvent(any());\n    }\n\n    @Test\n    public void testDetachedTty() {\n        UsbServiceImpl svc = new UsbServiceImpl();\n\n        EventAdmin eaMock = mock(EventAdmin.class);\n        svc.setEventAdmin(eaMock);\n\n        doAnswer(invocation -> {\n            Event event = invocation.getArgument(0, Event.class);\n\n            assertEquals(\"org/eclipse/kura/usb/NetworkEvent/device/REMOVED\", event.getTopic());\n            assertEquals(deviceNode, event.getProperty(UsbDeviceEvent.USB_EVENT_RESOURCE_PROPERTY));\n\n            return null;\n        }).when(eaMock).postEvent(any());\n\n        UsbDevice device = new UsbTtyDevice(vendorId, productId, manufacturerName, productName, usbBusNumber,\n                usbDevicePath, deviceNode);\n\n        svc.detached(device);\n\n        verify(eaMock, times(1)).postEvent(any());\n    }\n\n    @Test\n    public void testGetUsbDevices() {\n        List<UsbBlockDevice> blockDevices = new ArrayList<>();\n        UsbBlockDevice bdev = mock(UsbBlockDevice.class);\n        blockDevices.add(bdev);\n        List<UsbNetDevice> netDevices = new ArrayList<>();\n        UsbNetDevice ndev = mock(UsbNetDevice.class);\n        netDevices.add(ndev);\n        List<UsbTtyDevice> ttyDevices = new ArrayList<>();\n        UsbTtyDevice tdev = mock(UsbTtyDevice.class);\n        ttyDevices.add(tdev);\n\n        UsbServiceImpl svc = new UsbServiceImpl() {\n\n            @Override\n            public synchronized List<UsbBlockDevice> getUsbBlockDevices() {\n                return blockDevices;\n            }\n\n            @Override\n            public synchronized List<UsbNetDevice> getUsbNetDevices() {\n                return netDevices;\n            }\n\n            @Override\n            public synchronized List<UsbTtyDevice> getUsbTtyDevices() {\n                return ttyDevices;\n            }\n        };\n\n        List<? extends UsbDevice> devices = svc.getUsbDevices();\n\n        assertEquals(3, devices.size());\n        assertTrue(devices.contains(bdev));\n        assertTrue(devices.contains(ndev));\n        assertTrue(devices.contains(tdev));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.watchdog.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.linux.watchdog.test\nBundle-SymbolicName: org.eclipse.kura.linux.watchdog.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.linux.watchdog\nImport-Package: org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.7\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.watchdog.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.watchdog.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.watchdog.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.linux.watchdog.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.watchdog.test/src/test/java/org/eclipse/kura/linux/watchdog/RebootCauseFileWriterTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.linux.watchdog;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\n\nimport org.junit.Test;\n\npublic class RebootCauseFileWriterTest {\n\n    @Test\n    public void testWriteRebootCauseExistingFile() throws IOException {\n        String path = \"target/existingFile\";\n        RebootCauseFileWriter svc = new RebootCauseFileWriter(path);\n\n        File f = new File(path);\n        f.createNewFile();\n\n        svc.writeRebootCause(\"test\");\n\n        assertEquals(0, f.length());\n\n        f.delete();\n    }\n\n    @Test\n    public void testWriteRebootCauseNonExistingFile() throws IOException {\n        String path = \"target/nonExistingFile\";\n        RebootCauseFileWriter svc = new RebootCauseFileWriter(path);\n\n        File f = new File(path);\n\n        svc.writeRebootCause(\"test\");\n\n        assertTrue(f.length() >= 18);\n\n        FileReader reader = new FileReader(f);\n        char[] cbuf = new char[100];\n        int read = reader.read(cbuf);\n        reader.close();\n\n        f.delete();\n\n        String s = new String(cbuf, 0, read);\n        assertTrue(s.contains(\"test\"));\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.linux.watchdog.test/src/test/java/org/eclipse/kura/linux/watchdog/WatchdogServiceImplTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.linux.watchdog;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.Future;\n\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.watchdog.CriticalComponent;\nimport org.junit.Test;\n\npublic class WatchdogServiceImplTest {\n\n    private static final String WATCHDOG_TEST_DEVICE = \"target/watchdogTestDevice\";\n\n    private class WatchdogTestWriter extends StringWriter {\n\n        private int lastLength = 0;\n\n        @Override\n        public synchronized void write(String str) {\n            super.write(str);\n            notify();\n        }\n\n        public synchronized boolean waitForData(int delayMs) { // waits for some data to be written since the last call\n                                                               // to this method\n            if (toString().length() == this.lastLength) {\n                try {\n                    this.wait(delayMs);\n                } catch (InterruptedException e) {\n                }\n            }\n            final int currentLength = toString().length();\n            final boolean result = currentLength != this.lastLength;\n            this.lastLength = currentLength;\n            return result;\n        }\n    }\n\n    public class TestWatchdogServiceImpl extends WatchdogServiceImpl {\n\n        private final Writer testWriter;\n        private volatile boolean hasCheckedCriticalComponents;\n\n        public TestWatchdogServiceImpl(Writer fileWriter) {\n            this.testWriter = fileWriter;\n        }\n\n        protected Writer getWatchdogFileWriter() throws IOException {\n            return this.testWriter;\n        }\n\n        @Override\n        protected synchronized void checkCriticalComponents() {\n            super.checkCriticalComponents();\n            this.hasCheckedCriticalComponents = true;\n            notify();\n        }\n\n        @Override\n        protected Writer getWatchdogDeviceWriter(String watchdogDevice) throws IOException {\n            return testWriter;\n        }\n\n        @Override\n        protected boolean isWatchdogDeviceAvailable(String watchdogDevice) {\n            return true;\n        }\n\n        public synchronized boolean waitForCriticalComponentCheck(int delayMs) {\n            if (!this.hasCheckedCriticalComponents) {\n                try {\n                    this.wait(delayMs);\n                } catch (InterruptedException e) {\n                }\n            }\n            return this.hasCheckedCriticalComponents;\n        }\n    }\n\n    @Test\n    public void testActivateDeactivate() throws NoSuchFieldException, IOException, InterruptedException {\n        // activate and deactivate\n\n        final WatchdogTestWriter watchdogWriter = new WatchdogTestWriter();\n        TestWatchdogServiceImpl svc = new TestWatchdogServiceImpl(watchdogWriter);\n\n        Map<String, Object> properties = getProperties(true);\n        svc.activate(properties);\n\n        assertTrue(svc.waitForCriticalComponentCheck(10000));\n        assertTrue(watchdogWriter.toString().startsWith(\"w\")); // check that the watchdog has been kicked at least once\n\n        assertNotNull(TestUtil.getFieldValue(svc, \"pollExecutor\"));\n\n        Future task = (Future) TestUtil.getFieldValue(svc, \"pollTask\");\n        assertNotNull(task);\n\n        assertFalse(task.isCancelled());\n\n        svc.deactivate();\n\n        assertNull(TestUtil.getFieldValue(svc, \"pollTask\"));\n        assertTrue(task.isCancelled());\n        assertNull(TestUtil.getFieldValue(svc, \"pollExecutor\"));\n\n        assertTrue(watchdogWriter.waitForData(10000));\n        assertTrue(watchdogWriter.toString().endsWith(\"ww\")); // check that the watchdog has been kicked at least twice\n                                                              // and it has not been disabled\n    }\n\n    private Map<String, Object> getProperties(boolean enabled) {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"watchdogDevice\", WATCHDOG_TEST_DEVICE);\n        properties.put(\"rebootCauseFilePath\", \"target/watchdogTestCauses\");\n        properties.put(\"enabled\", enabled);\n\n        return properties;\n    }\n\n    @Test\n    public void testUpdatedDisabled() throws IOException, NoSuchFieldException {\n        // run activate/update\n\n        final WatchdogTestWriter watchdogWriter = new WatchdogTestWriter();\n\n        WatchdogServiceImpl svc = new TestWatchdogServiceImpl(watchdogWriter);\n\n        Map<String, Object> properties = getProperties(false);\n\n        svc.activate(properties);\n\n        assertFalse(watchdogWriter.waitForData(1000));\n\n        assertNull(TestUtil.getFieldValue(svc, \"watchdogFileWriter\"));\n        assertNull(TestUtil.getFieldValue(svc, \"timedOutOn\"));\n\n        svc.deactivate();\n\n        assertFalse(watchdogWriter.waitForData(1000));\n        assertTrue(watchdogWriter.toString().isEmpty());\n    }\n\n    @Test\n    public void testDisable() throws Throwable {\n        // disable the service and check that watchdog device is properly updated\n\n        final WatchdogTestWriter watchdogWriter = new WatchdogTestWriter();\n\n        WatchdogServiceImpl svc = new TestWatchdogServiceImpl(watchdogWriter);\n\n        Map<String, Object> properties = getProperties(false);\n\n        WatchdogServiceOptions options = new WatchdogServiceOptions(properties);\n        TestUtil.setFieldValue(svc, \"options\", options);\n\n        TestUtil.setFieldValue(svc, \"watchdogFileWriter\", watchdogWriter);\n\n        TestUtil.invokePrivate(svc, \"disableWatchdog\");\n\n        assertTrue(watchdogWriter.waitForData(10000));\n        assertEquals(\"V\", watchdogWriter.toString());\n\n        svc.deactivate();\n    }\n\n    @Test\n    public void testRegisterUnregisterGetCriticalComponent() throws NoSuchFieldException {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        List<CriticalComponentRegistration> criticalComponentRegistrations = new CopyOnWriteArrayList<>();\n        TestUtil.setFieldValue(svc, \"criticalComponentRegistrations\", criticalComponentRegistrations);\n\n        CriticalComponent cc1 = new TestCC(\"1\", 0);\n        svc.registerCriticalComponent(cc1);\n\n        List<CriticalComponent> components = svc.getCriticalComponents();\n        assertEquals(1, components.size());\n\n        assertEquals(\"1\", components.get(0).getCriticalComponentName());\n        assertEquals(0, components.get(0).getCriticalComponentTimeout());\n\n        // add the same component\n        svc.registerCriticalComponent(cc1);\n\n        components = svc.getCriticalComponents();\n        assertEquals(1, components.size());\n\n        // add a new component with the same name and timeout\n        CriticalComponent cc2 = new TestCC(\"1\", 0);\n        svc.registerCriticalComponent(cc2);\n\n        components = svc.getCriticalComponents();\n        assertEquals(2, components.size());\n\n        assertEquals(criticalComponentRegistrations.size(), components.size());\n\n        // the deprecated method also does the same\n        CriticalComponent cc3 = new TestCC(\"3\", 1);\n        svc.registerCriticalService(cc3);\n\n        components = svc.getCriticalComponents();\n        assertEquals(3, components.size());\n\n        assertEquals(criticalComponentRegistrations.size(), components.size());\n\n        assertEquals(\"1\", components.get(0).getCriticalComponentName());\n        assertEquals(0, components.get(0).getCriticalComponentTimeout());\n\n        assertEquals(\"1\", components.get(1).getCriticalComponentName());\n        assertEquals(0, components.get(1).getCriticalComponentTimeout());\n\n        assertEquals(\"3\", components.get(2).getCriticalComponentName());\n        assertEquals(1, components.get(2).getCriticalComponentTimeout());\n\n        // add the first component, again - won't work\n        svc.registerCriticalComponent(cc1);\n\n        components = svc.getCriticalComponents();\n        assertEquals(3, components.size());\n\n        // unregister first one\n        svc.unregisterCriticalComponent(cc1);\n\n        components = svc.getCriticalComponents();\n        assertEquals(2, components.size());\n\n        // re-register first one\n        svc.registerCriticalComponent(cc1);\n\n        components = svc.getCriticalComponents();\n        assertEquals(3, components.size());\n\n        // unregister the now second one\n        svc.unregisterCriticalComponent(cc1);\n\n        components = svc.getCriticalComponents();\n        assertEquals(2, components.size());\n\n        // the deprecated method also works\n        svc.unregisterCriticalService(cc3);\n\n        components = svc.getCriticalComponents();\n        assertEquals(1, components.size());\n\n        assertEquals(\"1\", components.get(0).getCriticalComponentName());\n        assertEquals(0, components.get(0).getCriticalComponentTimeout());\n    }\n\n    @Test\n    public void testCheckin() throws NoSuchFieldException {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        List<CriticalComponentRegistration> criticalComponentRegistrations = new CopyOnWriteArrayList<>();\n        TestUtil.setFieldValue(svc, \"criticalComponentRegistrations\", criticalComponentRegistrations);\n\n        CriticalComponent cc1 = new TestCC(\"1\", 1);\n        svc.registerCriticalComponent(cc1);\n\n        CriticalComponent cc2 = new TestCC(\"2\", 2);\n        svc.registerCriticalComponent(cc2);\n\n        CriticalComponentRegistration cci2 = criticalComponentRegistrations.get(1);\n        TestUtil.setFieldValue(cci2, \"updated\", 12345);\n\n        svc.checkin(cc2);\n\n        assertTrue((long) TestUtil.getFieldValue(cci2, \"updated\") > 12345);\n        assertTrue((long) TestUtil.getFieldValue(cci2, \"updated\") <= System.nanoTime());\n    }\n\n    public void testWatchdogFileDoesNotExist() throws Throwable {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        Map<String, Object> properties = getProperties(true);\n\n        svc.activate(properties);\n\n        assertNull(TestUtil.getFieldValue(svc, \"pollTask\"));\n    }\n\n    public void testShouldNotCreateWatchdogFile() throws InterruptedException {\n        WatchdogServiceImpl svc = new WatchdogServiceImpl();\n\n        Map<String, Object> properties = getProperties(true);\n\n        svc.activate(properties);\n\n        Thread.sleep(2000);\n\n        assertFalse(new File(WATCHDOG_TEST_DEVICE).exists());\n\n        svc.deactivate();\n\n        assertFalse(new File(WATCHDOG_TEST_DEVICE).exists());\n    }\n\n}\n\nclass TestCC implements CriticalComponent {\n\n    private final String name;\n    private final int timeout;\n\n    public TestCC(String name, int timeout) {\n        this.name = name;\n        this.timeout = timeout;\n    }\n\n    @Override\n    public String getCriticalComponentName() {\n        return this.name;\n    }\n\n    @Override\n    public int getCriticalComponentTimeout() {\n        return this.timeout;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.log.filesystem.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.log.filesystem.provider.test\nBundle-SymbolicName: org.eclipse.kura.log.filesystem.provider.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.log.filesystem.provider\nImport-Package: org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.log;version=\"[1.1,1.2)\",\n org.eclipse.kura.log.listener;version=\"[1.0,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.mockito.verification;version=\"1.10.19\",\n org.osgi.framework;version=\"1.7\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.log.filesystem.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.log.filesystem.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2021 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\noutput.. = target/classes/"
  },
  {
    "path": "kura/test/org.eclipse.kura.log.filesystem.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.log.filesystem.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.log.filesystem.provider.test/src/test/java/org/eclipse/kura/log/filesystem/provider/FilesystemLogProviderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.log.filesystem.provider;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.timeout;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.verifyNoInteractions;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.log.LogEntry;\nimport org.eclipse.kura.log.listener.LogListener;\n\nimport org.junit.Test;\nimport org.mockito.ArgumentMatchers;\n\npublic class FilesystemLogProviderTest {\n\n    private static final int LISTENER_CALL_TIMEOUT = 5000;\n\n    private int nLogLines = 0;\n    private Map<String, Object> properties;\n    private File file;\n    private boolean exceptionOccured = false;\n    private FilesystemLogProvider logProvider;\n    private List<LogListener> listeners;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void allListenersShouldBeCalled() {\n        givenFile(\"kuratest\");\n        givenPropertiesWithLogFilePath();\n        givenFilesystemLogProvider();\n        givenLogListeners(3);\n\n        whenRegisteringLogListeners();\n        whenActivate();\n\n        thenListenersGetCalled(this.nLogLines);\n        thenNoExceptionsOccurred();\n    }\n\n    @Test\n    public void updateWithWrongProperties() {\n        givenFile(\"kuratest\");\n        givenPropertiesWithLogFilePath();\n        givenFilesystemLogProvider();\n        givenLogListeners(3);\n\n        whenRegisteringLogListeners();\n        whenUpdateWithWrongProperties();\n\n        thenListenersAreNotCalled();\n        thenNoExceptionsOccurred();\n    }\n\n    @Test\n    public void updateWithCorrectProperties() {\n        givenFile(\"kuratest\");\n        givenPropertiesWithLogFilePath();\n        givenFilesystemLogProvider();\n        givenLogListeners(3);\n\n        whenRegisteringLogListeners();\n        whenActivate();\n        whenUpdateWithCorrectProperties();\n        whenNewLinesAreAddedToFile(10);\n\n        thenListenersGetCalled(10);\n    }\n\n    @Test\n    public void deactivateShouldStopLogProvider() {\n        givenFile(\"kuratest\");\n        givenPropertiesWithLogFilePath();\n        givenFilesystemLogProvider();\n        givenLogListeners(3);\n\n        whenRegisteringLogListeners();\n        whenActivate();\n        whenDeactivate();\n        whenNewLinesAreAddedToFile(10);\n\n        thenListenersGetCalled(this.nLogLines - 10);\n        thenNoExceptionsOccurred();\n    }\n\n    @Test\n    public void unregisteredListenersShouldNotBeNotified() {\n        givenFile(\"kuratest\");\n        givenPropertiesWithLogFilePath();\n        givenFilesystemLogProvider();\n        givenLogListeners(3);\n\n        whenRegisteringLogListeners();\n        whenActivate();\n        whenUnregisteringLogListeners();\n        whenNewLinesAreAddedToFile(10);\n\n        thenListenersGetCalled(this.nLogLines - 10);\n    }\n\n    @Test\n    public void listenerShouldNotBeCalledFileNotAccessible() {\n        givenFile(\"kuratesterror\");\n        givenFileBecomesNotReadable();\n        givenPropertiesWithLogFilePath();\n        givenFilesystemLogProvider();\n        givenLogListeners(1);\n\n        whenRegisteringLogListeners();\n        whenActivate();\n\n        thenListenersAreNotCalled();\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenFile(String filename) {\n        this.exceptionOccured = false;\n        try {\n            this.file = File.createTempFile(filename, \".log\");\n            this.file.deleteOnExit();\n\n            try (FileWriter writer = new FileWriter(this.file)) {\n                writer.write(\"20210101 - line01\\n\");\n                writer.write(\"20210102 - line02\\n\");\n                writer.write(\"20210103 - line03\\n\");\n                writer.write(\"20210104 - line04\\n\");\n                writer.write(\"20210105 - line05\\n\");\n                writer.write(\"exception on line05\\n\");\n                writer.write(\"exception on line05\\n\");\n                writer.write(\"exception on line05\\n\");\n                writer.write(\"20210106 - line06\\n\");\n                writer.write(\"20210107 - line07\\n\");\n                writer.write(\"20210108 - line08\\n\");\n                writer.write(\"20210109 - line09\\n\");\n                writer.write(\"20210110 - line10\\n\");\n                this.nLogLines = 10;\n            }\n        } catch (IOException e) {\n            this.exceptionOccured = true;\n        }\n    }\n\n    private void givenPropertiesWithLogFilePath() {\n        this.properties = new HashMap<>();\n        this.properties.put(FilesystemLogProvider.LOG_FILEPATH_PROP_KEY, this.file.getAbsolutePath());\n    }\n\n    private void givenFilesystemLogProvider() {\n        if (this.logProvider != null) {\n            this.logProvider.deactivate();\n        }\n        this.logProvider = new FilesystemLogProvider();\n    }\n\n    private void givenLogListeners(int nListeners) {\n        this.listeners = new ArrayList<>(nListeners);\n        for (int i = 0; i < nListeners; i++) {\n            LogListener listener = mock(LogListener.class);\n            this.listeners.add(listener);\n        }\n    }\n\n    private void givenFileBecomesNotReadable() {\n        this.file.setReadable(false);\n        this.file.setWritable(false);\n        this.file.setExecutable(false);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenRegisteringLogListeners() {\n        for (LogListener listener : this.listeners) {\n            this.logProvider.registerLogListener(listener);\n        }\n    }\n\n    private void whenActivate() {\n        this.logProvider.activate(this.properties);\n    }\n\n    private void whenUpdateWithWrongProperties() {\n        this.properties = new HashMap<>();\n        this.properties.put(FilesystemLogProvider.LOG_FILEPATH_PROP_KEY, \"this/is/a/nonexistent/path\");\n        this.logProvider.updated(this.properties);\n    }\n\n    private void whenUpdateWithCorrectProperties() {\n        waitUntilListenersAreNotified(this.nLogLines);\n\n        this.properties = new HashMap<>();\n        this.properties.put(FilesystemLogProvider.LOG_FILEPATH_PROP_KEY, this.file.getAbsolutePath());\n        this.logProvider.updated(this.properties);\n    }\n\n    private void whenDeactivate() {\n        waitUntilListenersAreNotified(this.nLogLines);\n        this.logProvider.deactivate();\n    }\n\n    private void whenNewLinesAreAddedToFile(int nLines) {\n        try (FileWriter writer = new FileWriter(this.file)) {\n            for (int i = 0; i < nLines; i++) {\n                writer.write(\"line\" + (this.nLogLines + i) + \"\\n\");\n            }\n            this.nLogLines += nLines;\n        } catch (IOException e) {\n            this.exceptionOccured = true;\n        }\n    }\n\n    private void whenUnregisteringLogListeners() {\n        for (LogListener listener : this.listeners) {\n            verify(listener, timeout(LISTENER_CALL_TIMEOUT).times(this.nLogLines))\n                    .newLogEntry(ArgumentMatchers.any(LogEntry.class));\n        }\n\n        for (LogListener listener : this.listeners) {\n            this.logProvider.unregisterLogListener(listener);\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenListenersGetCalled(int times) {\n        waitUntilListenersAreNotified(times);\n    }\n\n    private void thenListenersAreNotCalled() {\n        for (LogListener listener : this.listeners) {\n            verifyNoInteractions(listener);\n        }\n    }\n\n    private void thenNoExceptionsOccurred() {\n        assertFalse(this.exceptionOccured);\n    }\n\n    /*\n     * Utility methods\n     */\n\n    private void waitUntilListenersAreNotified(int times) {\n        for (LogListener listener : this.listeners) {\n            verify(listener, timeout(LISTENER_CALL_TIMEOUT).times(times)).newLogEntry(ArgumentMatchers.any(LogEntry.class));\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.log.filesystem.provider.test/src/test/java/org/eclipse/kura/log/filesystem/provider/KuraLogLineParserTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.log.filesystem.provider;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\n\nimport org.eclipse.kura.log.LogEntry;\nimport org.junit.Test;\n\npublic class KuraLogLineParserTest {\n\n    private static final String EXAMPLE_KURA_LOG_LINE = \"2021-11-12T17:13:47,184 [qtp30640932-8244] WARN  o.e.k.w.s.s.SkinServlet - Failed to load skin resource, Resource File /skin.js does not exist\";\n    private static final String EXAMPLE_KURA_AUDIT_LOG_LINE = \"<132>1 2021-11-12T23:32:15.594Z raspberrypi EclipseKura - - [RequestContext@28392 category=\\\"AuditLogger\\\" exception=\\\"\\\" priority=\\\"WARN\\\" thread=\\\"qtp30640932-60362\\\"] {entrypoint=Internal} UI Session - Failure - Session expired\";\n    private static final String EXAMPLE_GENERIC_LOG_LINE = \"20211112 - this is a generic log line\";\n    private static final String EXAMPLE_STACKTRACE = \"java.lang.UnsupportedOperationException: null\\n    at java.util.Collections$UnmodifiableMap.put(Collections.java:1459) ~[?:1.8.0_282]\";\n    private static final String EXAMPLE_KURA_LOG_LINE_WITH_EXCEPTION = \"14:01:17.971 [Thread-2] ERROR org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider - Unexpected exception in FilesystemLogProvider.\";\n\n    private static final String EXAMPLE_KURA_LOG_LINE_WITH_PID_WHITESPACE = \"2022-08-10T11:03:30,545 [ConfigurationListener Event Queue] INFO  o.e.k.e.p.ExamplePublisher - Activating ExamplePublisher... Done.\";\n\n    private String logLine;\n    private String filePath;\n    private String stacktrace;\n    private LogEntry parsedLogEntry;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldParseCorrectKuraEntry() throws ParseException {\n        givenKuraLogLine(EXAMPLE_KURA_LOG_LINE);\n\n        whenParseLogLine();\n\n        thenLogEntryIs(\n                new SimpleDateFormat(\"yyyy-MM-dd'T'hh:mm:ss,S\").parse(\"2021-11-12T17:13:47,184\").toInstant()\n                        .getEpochSecond(), // timestamp\n                \"qtp30640932-8244\", // pid\n                \"o.e.k.w.s.s.SkinServlet - Failed to load skin resource, Resource File /skin.js does not exist\", // message\n                \"WARN\", // priority\n                \"Kura\", // syslogid\n                this.filePath, // transport\n                \"\"); // stacktrace\n    }\n\n    @Test\n    public void shouldParseCorrectAuditEntry() throws ParseException {\n        givenKuraAuditLogLine(EXAMPLE_KURA_AUDIT_LOG_LINE);\n\n        whenParseLogLine();\n\n        thenLogEntryIs(\n                new SimpleDateFormat(\"yyyy-MM-dd'T'hh:mm:ss.SSSXXX\").parse(\"2021-11-12T23:32:15.594Z\").toInstant()\n                        .getEpochSecond(), // timestamp\n                \"qtp30640932-60362\", // pid\n                \"{entrypoint=Internal} UI Session - Failure - Session expired\", // message\n                \"WARN\", // priority\n                \"EclipseKura\", // syslogid\n                this.filePath, // transport\n                \"\"); // stacktrace\n    }\n\n    @Test\n    public void shouldParseGenericEntry() {\n        givenGenericLogLine(EXAMPLE_GENERIC_LOG_LINE);\n\n        whenParseLogLine();\n\n        thenLogEntryIs(KuraLogLineParser.DEFAULT_TIMESTAMP, // timestamp\n                KuraLogLineParser.DEFAULT_PID, // pid\n                this.logLine, // message\n                KuraLogLineParser.DEFAULT_PRIORITY, // priority\n                KuraLogLineParser.DEFAULT_SYSLOG_IDENTIFIER, // syslogid\n                this.filePath, // transport\n                KuraLogLineParser.DEFAULT_STACKTRACE); // stacktrace\n    }\n\n    @Test\n    public void shouldParseExceptionsCorrectly() {\n        givenKuraLogLineWithStacktrace(EXAMPLE_KURA_LOG_LINE_WITH_EXCEPTION, EXAMPLE_STACKTRACE);\n\n        whenParseLogLine();\n\n        thenLogEntryIs(0, // timestamp\n                \"Thread-2\", // pid\n                \"org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider - Unexpected exception in FilesystemLogProvider.\", // message\n                \"ERROR\", // priority\n                \"Kura\", // syslogid\n                this.filePath, // transport\n                EXAMPLE_STACKTRACE); // stacktrace\n    }\n\n    @Test\n    public void shouldParseCorrectKuraEntryWithPidWithWhitespace() throws ParseException {\n        givenKuraLogLine(EXAMPLE_KURA_LOG_LINE_WITH_PID_WHITESPACE);\n\n        whenParseLogLine();\n\n        thenLogEntryIs(\n                new SimpleDateFormat(\"yyyy-MM-dd'T'hh:mm:ss,S\").parse(\"2022-08-10T11:03:30,545\").toInstant()\n                        .getEpochSecond(), // timestamp\n                \"ConfigurationListener Event Queue\", // pid\n                \"o.e.k.e.p.ExamplePublisher - Activating ExamplePublisher... Done.\", // message\n                \"INFO\", // priority\n                \"Kura\", // syslogid\n                this.filePath, // transport\n                \"\"); // stacktrace\n    }\n\n    /*\n     * Steps\n     */\n\n    /*\n     * Given\n     */\n\n    private void givenKuraLogLine(String line) {\n        this.logLine = line;\n        this.filePath = \"/var/log/kura.log\";\n        this.stacktrace = \"\";\n    }\n\n    private void givenKuraAuditLogLine(String line) {\n        this.logLine = line;\n        this.filePath = \"/var/log/kura-audit.log\";\n        this.stacktrace = \"\";\n    }\n\n    private void givenGenericLogLine(String line) {\n        this.logLine = line;\n        this.filePath = \"example/file/path/test.log\";\n        this.stacktrace = \"\";\n    }\n\n    private void givenKuraLogLineWithStacktrace(String line, String stacktrace) {\n        this.logLine = line;\n        this.filePath = \"/var/log/kura.log\";\n        this.stacktrace = stacktrace;\n    }\n\n    /*\n     * When\n     */\n\n    private void whenParseLogLine() {\n        this.parsedLogEntry = null;\n        this.parsedLogEntry = new KuraLogLineParser(this.logLine, this.filePath, this.stacktrace).createLogEntry();\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenLogEntryIs(long expectedTimestamp, String expectedPid, String expectedMessage,\n            String expectedPriority, String expectedSyslogId, String expectedTransport, String expectedStacktrace) {\n\n        assertEquals(this.parsedLogEntry.getTimestamp(), expectedTimestamp);\n        assertEquals(this.parsedLogEntry.getProperties().get(\"_PID\"), expectedPid);\n        assertEquals(this.parsedLogEntry.getProperties().get(\"MESSAGE\"), expectedMessage);\n        assertEquals(this.parsedLogEntry.getProperties().get(\"PRIORITY\"), expectedPriority);\n        assertEquals(this.parsedLogEntry.getProperties().get(\"SYSLOG_IDENTIFIER\"), expectedSyslogId);\n        assertEquals(this.parsedLogEntry.getProperties().get(\"_TRANSPORT\"), expectedTransport);\n        assertEquals(this.parsedLogEntry.getProperties().get(\"STACKTRACE\"), expectedStacktrace);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.message.store.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.message.store.provider.test\nBundle-SymbolicName: org.eclipse.kura.message.store.provider.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.apache.felix.service.command;version=\"1.0.0\",\n org.eclipse.kura;version=\"[1.7,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\",\n org.eclipse.kura.data;version=\"[1.1,2.0)\",\n org.eclipse.kura.db;version=\"[2.0,3.0)\",\n org.eclipse.kura.message.store;version=\"[1.0,2.0)\",\n org.eclipse.kura.message.store.provider;version=\"[1.0,2.0)\",\n org.junit;version=\"4.12.0\",\n org.junit.runner;version=\"4.12.0\",\n org.junit.runners;version=\"4.12.0\",\n org.osgi.framework;version=\"1.10.0\"\nRequire-Bundle: org.eclipse.kura.db.sqlite.provider,\n org.eclipse.kura.core;bundle-version=\"1.3.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.message.store.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.message.store.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2022 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.message.store.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.message.store.provider.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n    \n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.message.store.provider.test/src/main/java/org/eclipse/kura/message/store/provider/test/MessageStoreProviderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.message.store.provider.test;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport org.eclipse.kura.KuraStoreException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.message.store.StoredMessage;\nimport org.eclipse.kura.message.store.provider.MessageStore;\nimport org.eclipse.kura.message.store.provider.MessageStoreProvider;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\n@RunWith(Parameterized.class)\npublic class MessageStoreProviderTest {\n\n    @Test\n    public void shouldStoreSimpleMessage() throws KuraStoreException {\n        givenMessageStore();\n\n        whenMessageIsStored(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        thenMessageTopicIs(0, \"testTopic\");\n        thenMessagePayloadIs(0, byteArray(1, 2, 3, 4));\n        thenMessageQoSIs(0, 1);\n        thenMessageRetainIs(0, true);\n        thenMessagePriorityIs(0, 7);\n        thenMessageCreatedOnIsInThePast(0);\n        thenMessagePublishedOnIsNotSet(0);\n        thenMessageConfirmedOnIsNotSet(0);\n        thenMessageDroppedOnIsNotSet(0);\n        thenDataTransportTokenIsNotSet(0);\n    }\n\n    @Test\n    public void shouldGetMessageCountEmpty() throws KuraStoreException {\n        givenMessageStore();\n\n        thenMessageCountIs(0);\n    }\n\n    @Test\n    public void shouldGetMessageCountNonEmpty() throws KuraStoreException {\n        givenMessageStore();\n\n        whenMessageIsStored(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n        whenMessageIsStored(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        thenMessageCountIs(2);\n    }\n\n    @Test\n    public void shouldStoreNullPayload() throws KuraStoreException {\n        givenMessageStore();\n\n        whenMessageIsStored(\"testTopic\", null, 1, true, 7);\n\n        thenMessagePayloadIs(0, null);\n    }\n\n    @Test\n    public void shouldNotAllowNullTopic() throws KuraStoreException {\n        givenMessageStore();\n\n        whenMessageIsStored(null, byteArray(1), 1, true, 7);\n\n        thenKuraStoreExceptionIsThrown();\n    }\n\n    @Test\n    public void shouldResetIdentityGeneratorWithNoStoredMessages() throws KuraStoreException {\n        givenMessageStore();\n\n        givenLastMessageId(Integer.MAX_VALUE);\n\n        whenMessageIsStored(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        thenNoExceptionIsThrown();\n        thenLastMessageIdIs(1);\n    }\n\n    @Test\n    public void shouldResetIdentityGeneratorWithSomeMessages() throws KuraStoreException {\n        givenMessageStore();\n\n        whenMessageIsStored(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n        whenMessageIsStored(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        givenLastMessageId(Integer.MAX_VALUE);\n\n        whenMessageIsStored(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        thenNoExceptionIsThrown();\n        thenLastMessageIdIs(3);\n    }\n\n    @Test\n    public void shouldSupportMarkAsPublishedWithQoSZero() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"testTopic\", byteArray(1, 2, 3, 4), 0, true, 7);\n\n        whenMessageIsMarkedAsPublished(0);\n\n        thenMessageCreatedOnIsInThePast(0);\n        thenMessagePublishedOnIsInThePast(0);\n        thenMessageConfirmedOnIsNotSet(0);\n        thenMessageDroppedOnIsNotSet(0);\n        thenDataTransportTokenIsNotSet(0);\n    }\n\n    @Test\n    public void shouldSupportMarkAsPublishedWithDataTransportToken() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        whenMessageIsMarkedAsPublished(0, new DataTransportToken(23, \"foo\"));\n\n        thenMessageCreatedOnIsInThePast(0);\n        thenMessagePublishedOnIsInThePast(0);\n        thenMessageConfirmedOnIsNotSet(0);\n        thenMessageDroppedOnIsNotSet(0);\n        thenDataTransportTokenIs(0, new DataTransportToken(23, \"foo\"));\n    }\n\n    @Test\n    public void shouldSupportMarkAsConfirmed() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        whenMessageIsMarkedAsPublished(0, new DataTransportToken(23, \"foo\"));\n        whenMessageIsMarkedAsConfirmed(0);\n\n        thenMessageCreatedOnIsInThePast(0);\n        thenMessagePublishedOnIsInThePast(0);\n        thenMessageConfirmedOnIsInThePast(0);\n        thenMessageDroppedOnIsNotSet(0);\n        thenDataTransportTokenIs(0, new DataTransportToken(23, \"foo\"));\n    }\n\n    @Test\n    public void shouldGetNextMessageWithSingleMessage() throws KuraStoreException {\n        givenMessageStore();\n\n        whenMessageIsStored(\"testTopic\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        thenNextMessageTopicIs(\"testTopic\");\n        thenNextMessagePayloadIs(byteArray(1, 2, 3, 4));\n        thenNextMessageQoSIs(1);\n        thenNextMessageRetainIs(true);\n        thenNextMessagePriorityIs(7);\n        thenNextMessageCreatedOnIsInThePast();\n        thenNextMessagePublishedOnIsNotSet();\n        thenNextMessageConfirmedOnIsNotSet();\n        thenNextMessageDroppedOnIsNotSet();\n        thenNextMessageDataTransportTokenIsNotSet();\n    }\n\n    @Test\n    public void shouldReturnOldestMessage() throws KuraStoreException {\n        givenMessageStore();\n\n        whenMessageIsStored(\"1\", byteArray(1, 2, 3, 4), 1, true, 7);\n        whenMessageIsStored(\"2\", byteArray(2, 2, 3, 4), 1, true, 7);\n        whenMessageIsStored(\"3\", byteArray(3, 2, 3, 4), 1, true, 7);\n        whenMessageIsStored(\"4\", byteArray(4, 2, 3, 4), 1, true, 7);\n        whenMessageIsStored(\"5\", byteArray(5, 2, 3, 4), 1, true, 7);\n\n        thenNextMessageTopicIs(\"1\");\n        thenNextMessagePayloadIs(byteArray(1, 2, 3, 4));\n        thenNextMessageQoSIs(1);\n        thenNextMessageRetainIs(true);\n        thenNextMessagePriorityIs(7);\n        thenNextMessageCreatedOnIsInThePast();\n        thenNextMessagePublishedOnIsNotSet();\n        thenNextMessageConfirmedOnIsNotSet();\n        thenNextMessageDroppedOnIsNotSet();\n        thenNextMessageDataTransportTokenIsNotSet();\n    }\n\n    @Test\n    public void shouldReturnOldestNonPublishedMessage() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"1\", byteArray(1, 2, 3, 4), 1, true, 7);\n        givenStoredMessage(\"2\", byteArray(2, 2, 3, 4), 2, false, 7);\n        givenStoredMessage(\"3\", byteArray(3, 2, 3, 4), 3, true, 7);\n        givenStoredMessage(\"4\", byteArray(4, 2, 3, 4), 4, false, 7);\n        givenStoredMessage(\"5\", byteArray(5, 2, 3, 4), 5, true, 7);\n\n        whenMessageIsMarkedAsPublished(0);\n        whenMessageIsMarkedAsPublished(1);\n\n        thenNextMessageTopicIs(\"3\");\n        thenNextMessagePayloadIs(byteArray(3, 2, 3, 4));\n        thenNextMessageQoSIs(3);\n        thenNextMessageRetainIs(true);\n        thenNextMessagePriorityIs(7);\n        thenNextMessageCreatedOnIsInThePast();\n        thenNextMessagePublishedOnIsNotSet();\n        thenNextMessageConfirmedOnIsNotSet();\n        thenNextMessageDroppedOnIsNotSet();\n        thenNextMessageDataTransportTokenIsNotSet();\n    }\n\n    @Test\n    public void shouldReturnHighestPriorityMessage() throws KuraStoreException {\n        givenMessageStore();\n\n        whenMessageIsStored(\"1\", byteArray(1, 2, 3, 4), 1, true, 7);\n        whenMessageIsStored(\"2\", byteArray(2, 2, 3, 4), 2, false, 6);\n        whenMessageIsStored(\"3\", byteArray(3, 2, 3, 4), 3, true, 2);\n        whenMessageIsStored(\"4\", byteArray(4, 2, 3, 4), 4, false, 4);\n        whenMessageIsStored(\"5\", byteArray(5, 2, 3, 4), 5, true, 3);\n\n        thenNextMessageTopicIs(\"3\");\n        thenNextMessagePayloadIs(byteArray(3, 2, 3, 4));\n        thenNextMessageQoSIs(3);\n        thenNextMessageRetainIs(true);\n        thenNextMessagePriorityIs(2);\n        thenNextMessageCreatedOnIsInThePast();\n        thenNextMessagePublishedOnIsNotSet();\n        thenNextMessageConfirmedOnIsNotSet();\n        thenNextMessageDroppedOnIsNotSet();\n        thenNextMessageDataTransportTokenIsNotSet();\n    }\n\n    @Test\n    public void shouldReturnOldestNonPublishedMessageWithHighestPriority() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"1\", byteArray(1, 2, 3, 4), 1, true, 7);\n        givenStoredMessage(\"6\", byteArray(3, 2, 3, 4), 3, true, 2);\n        givenStoredMessage(\"2\", byteArray(2, 2, 3, 4), 2, false, 2);\n        givenStoredMessage(\"3\", byteArray(3, 2, 3, 4), 3, true, 2);\n        givenStoredMessage(\"4\", byteArray(4, 2, 3, 4), 4, false, 1);\n        givenStoredMessage(\"5\", byteArray(5, 2, 3, 4), 5, true, 3);\n\n        whenMessageIsMarkedAsPublished(4);\n        whenMessageIsMarkedAsPublished(1, new DataTransportToken(1, \"bar\"));\n\n        thenNextMessageTopicIs(\"2\");\n        thenNextMessagePayloadIs(byteArray(2, 2, 3, 4));\n        thenNextMessageQoSIs(2);\n        thenNextMessageRetainIs(false);\n        thenNextMessagePriorityIs(2);\n        thenNextMessageCreatedOnIsInThePast();\n        thenNextMessagePublishedOnIsNotSet();\n        thenNextMessageConfirmedOnIsNotSet();\n        thenNextMessageDroppedOnIsNotSet();\n        thenNextMessageDataTransportTokenIsNotSet();\n    }\n\n    @Test\n    public void shouldRetireveUnpublishedMessageList() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"1\", byteArray(1, 2, 3, 4), 1, true, 7);\n        givenStoredMessage(\"6\", byteArray(3, 2, 3, 4), 3, true, 2);\n        givenStoredMessage(\"2\", byteArray(2, 2, 3, 4), 2, false, 2);\n        givenStoredMessage(\"3\", byteArray(3, 2, 3, 4), 3, true, 2);\n        givenStoredMessage(\"4\", byteArray(4, 2, 3, 4), 0, false, 1);\n        givenStoredMessage(\"5\", byteArray(5, 2, 3, 4), 5, true, 3);\n\n        whenMessageIsMarkedAsPublished(4);\n        whenMessageIsMarkedAsPublished(1, new DataTransportToken(1, \"bar\"));\n        whenUnpublishedMessagesAreRertieved();\n\n        thenRetrievedMessageIdSetIs(0, 2, 3, 5);\n    }\n\n    @Test\n    public void shouldRetireveInFlightMessageList() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"1\", byteArray(1, 2, 3, 4), 1, true, 7);\n        givenStoredMessage(\"6\", byteArray(3, 2, 3, 4), 3, true, 2);\n        givenStoredMessage(\"2\", byteArray(2, 2, 3, 4), 2, false, 2);\n        givenStoredMessage(\"3\", byteArray(3, 2, 3, 4), 3, true, 2);\n        givenStoredMessage(\"4\", byteArray(4, 2, 3, 4), 0, false, 1);\n        givenStoredMessage(\"5\", byteArray(5, 2, 3, 4), 5, true, 3);\n\n        whenMessageIsMarkedAsPublished(4);\n        whenMessageIsMarkedAsPublished(1, new DataTransportToken(1, \"bar\"));\n        whenMessageIsMarkedAsPublished(2, new DataTransportToken(2, \"baz\"));\n        whenInFlightMessagesAreRertieved();\n\n        thenRetrievedMessageIdSetIs(1, 2);\n    }\n\n    @Test\n    public void shouldRetireveDroppedMessageList() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"1\", byteArray(1, 2, 3, 4), 1, true, 7);\n        givenStoredMessage(\"6\", byteArray(3, 2, 3, 4), 3, true, 2);\n        givenStoredMessage(\"2\", byteArray(2, 2, 3, 4), 2, false, 2);\n        givenStoredMessage(\"3\", byteArray(3, 2, 3, 4), 3, true, 2);\n        givenStoredMessage(\"4\", byteArray(4, 2, 3, 4), 0, false, 1);\n        givenStoredMessage(\"5\", byteArray(5, 2, 3, 4), 5, true, 3);\n\n        whenMessageIsMarkedAsPublished(4);\n        whenMessageIsMarkedAsPublished(1, new DataTransportToken(1, \"bar\"));\n        whenMessageIsMarkedAsPublished(2, new DataTransportToken(2, \"baz\"));\n        whenInFlightMessagesAreDropped();\n        whenMessageIsStored(\"6\", byteArray(5, 2, 3, 4), 5, true, 3);\n        whenDroppedMessagesAreRertieved();\n\n        thenRetrievedMessageIdSetIs(1, 2);\n    }\n\n    @Test\n    public void shouldDeleteOldPublishedMessagesWithQoS0() throws KuraStoreException, InterruptedException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 0, true, 7);\n\n        whenMessageIsMarkedAsPublished(0);\n        whenTimePasses(2, TimeUnit.SECONDS);\n        whenStaleMessagesAreDeleted(1);\n\n        thenMessageDoesNotExist(0);\n    }\n\n    @Test\n    public void shouldNotDeleteOldNonPublishedMessagesWithQoS0() throws KuraStoreException, InterruptedException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 0, true, 7);\n\n        whenTimePasses(2, TimeUnit.SECONDS);\n        whenStaleMessagesAreDeleted(1);\n\n        thenMessageExists(0);\n    }\n\n    @Test\n    public void shouldNotDeleteRecentPublishedMessagesWithQoS0() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 0, true, 7);\n\n        whenMessageIsMarkedAsPublished(0);\n        whenStaleMessagesAreDeleted(10);\n\n        thenMessageExists(0);\n    }\n\n    @Test\n    public void shouldNotDeleteRecentNonPublishedMessagesWithQoS0() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 0, true, 7);\n\n        whenStaleMessagesAreDeleted(10);\n\n        thenMessageExists(0);\n    }\n\n    @Test\n    public void shouldNotDeleteOldPublishedAndNotConfirmedMessagesWithQoS1()\n            throws KuraStoreException, InterruptedException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        whenMessageIsMarkedAsPublished(0, new DataTransportToken(1, \"bar\"));\n        whenTimePasses(2, TimeUnit.SECONDS);\n        whenStaleMessagesAreDeleted(1);\n\n        thenMessageExists(0);\n    }\n\n    @Test\n    public void shouldNotDeleteRecentPublishedAndNotConfirmedMessagesWithQoS1() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        whenMessageIsMarkedAsPublished(0, new DataTransportToken(1, \"foo\"));\n        whenStaleMessagesAreDeleted(10);\n\n        thenMessageExists(0);\n    }\n\n    @Test\n    public void shouldDeleteOldPublishedAndConfirmedMessagesWithQoS1() throws KuraStoreException, InterruptedException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        whenMessageIsMarkedAsPublished(0, new DataTransportToken(1, \"bar\"));\n        whenMessageIsMarkedAsConfirmed(0);\n        whenTimePasses(2, TimeUnit.SECONDS);\n        whenStaleMessagesAreDeleted(1);\n\n        thenMessageDoesNotExist(0);\n    }\n\n    @Test\n    public void shouldNotDeleteMessagesConfirmedRecentlyWithQoS1() throws KuraStoreException, InterruptedException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        whenMessageIsMarkedAsPublished(0, new DataTransportToken(1, \"bar\"));\n        whenTimePasses(2, TimeUnit.SECONDS);\n        whenMessageIsMarkedAsConfirmed(0);\n\n        whenStaleMessagesAreDeleted(1);\n\n        thenMessageExists(0);\n    }\n\n    @Test\n    public void shouldNotDeleteRecentlyDroppedMessages() throws KuraStoreException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        whenMessageIsMarkedAsPublished(0, new DataTransportToken(1, \"bar\"));\n        whenInFlightMessagesAreDropped();\n\n        whenStaleMessagesAreDeleted(10);\n\n        thenMessageExists(0);\n    }\n\n    @Test\n    public void shouldDeleteOldDroppedMessages() throws KuraStoreException, InterruptedException {\n        givenMessageStore();\n        givenStoredMessage(\"foo\", byteArray(1, 2, 3, 4), 1, true, 7);\n\n        whenMessageIsMarkedAsPublished(0, new DataTransportToken(1, \"bar\"));\n        whenInFlightMessagesAreDropped();\n        whenTimePasses(2, TimeUnit.SECONDS);\n\n        whenStaleMessagesAreDeleted(1);\n\n        thenMessageDoesNotExist(0);\n    }\n\n    private static final AtomicInteger NEXT_ID = new AtomicInteger();\n\n    private final TestTarget target;\n    private final MessageStoreProvider messageStoreProvider;\n    private final int id;\n    private final String storePid;\n    private final String storeName;\n\n    private MessageStore messageStore;\n    private List<Integer> messageIds = new ArrayList<>();\n    private Optional<Exception> exception = Optional.empty();\n    private Optional<List<StoredMessage>> retrievedMessages = Optional.empty();\n\n    @Parameters(name = \"{0}\")\n    public static Collection<TestTarget> targets() {\n        return Arrays.asList(TestTarget.H2, TestTarget.SQLITE);\n    }\n\n    public MessageStoreProviderTest(final TestTarget target)\n            throws InterruptedException, ExecutionException, TimeoutException {\n        this.target = target;\n        this.id = NEXT_ID.incrementAndGet();\n        this.storePid = \"db\" + this.id;\n        this.storeName = \"store\" + this.id;\n\n        final ConfigurationService configurationService = ServiceUtil\n                .trackService(ConfigurationService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n        this.messageStoreProvider = ServiceUtil\n                .createFactoryConfiguration(configurationService, MessageStoreProvider.class, this.storePid,\n                        this.target.storeFactoryPid(), target.getConfigurationForPid(this.storePid))\n                .get(30, TimeUnit.SECONDS);\n    }\n\n    private void givenMessageStore() throws KuraStoreException {\n        this.messageStore = this.messageStoreProvider.openMessageStore(this.storeName);\n    }\n\n    private void givenLastMessageId(final int value) {\n        this.target.setMessageId(storePid, storeName, value);\n    }\n\n    private void givenStoredMessage(final String topic, final byte[] payload, final int qos, final boolean retain,\n            final int priority) throws KuraStoreException {\n        messageIds.add(this.messageStore.store(topic, payload, qos, retain, priority));\n    }\n\n    private void whenMessageIsStored(final String topic, final byte[] payload, final int qos, final boolean retain,\n            final int priority) {\n        try {\n            givenStoredMessage(topic, payload, qos, retain, priority);\n        } catch (final Exception e) {\n            this.exception = Optional.of(e);\n        }\n    }\n\n    private void whenMessageIsMarkedAsPublished(final int messageIndex) throws KuraStoreException {\n        this.messageStore.markAsPublished(this.messageIds.get(messageIndex));\n    }\n\n    private void whenMessageIsMarkedAsPublished(final int messageIndex, final DataTransportToken token)\n            throws KuraStoreException {\n        this.messageStore.markAsPublished(this.messageIds.get(messageIndex), token);\n    }\n\n    private void whenMessageIsMarkedAsConfirmed(final int messageIndex) throws KuraStoreException {\n        this.messageStore.markAsConfirmed(this.messageIds.get(messageIndex));\n    }\n\n    private void whenInFlightMessagesAreDropped() throws KuraStoreException {\n        this.messageStore.dropAllInFlightMessages();\n    }\n\n    private void whenUnpublishedMessagesAreRertieved() throws KuraStoreException {\n        this.retrievedMessages = Optional.of(this.messageStore.getUnpublishedMessages());\n    }\n\n    private void whenInFlightMessagesAreRertieved() throws KuraStoreException {\n        this.retrievedMessages = Optional.of(this.messageStore.getInFlightMessages());\n    }\n\n    private void whenDroppedMessagesAreRertieved() throws KuraStoreException {\n        this.retrievedMessages = Optional.of(this.messageStore.getDroppedMessages());\n    }\n\n    private void thenRetrievedMessageIdSetIs(final int... ids) {\n        final List<StoredMessage> messages = this.retrievedMessages\n                .orElseThrow(() -> new IllegalStateException(\"no messages have been retrieved\"));\n\n        assertEquals(ids.length, messages.size());\n\n        for (final int id : ids) {\n            assertTrue(messages.stream().anyMatch(m -> m.getId() == this.messageIds.get(id)));\n        }\n    }\n\n    private void thenMessageTopicIs(final int messageIndex, final String topic) throws KuraStoreException {\n        assertEquals(topic, getStoredMessage(0).getTopic());\n    }\n\n    private void thenMessagePayloadIs(final int messageIndex, final byte[] payload) throws KuraStoreException {\n        assertArrayEquals(payload, getStoredMessage(messageIndex).getPayload());\n    }\n\n    private void thenMessageQoSIs(final int messageIndex, final int qos) throws KuraStoreException {\n        assertEquals(qos, getStoredMessage(messageIndex).getQos());\n    }\n\n    private void thenMessageRetainIs(final int messageIndex, final boolean retain) throws KuraStoreException {\n        assertEquals(retain, getStoredMessage(messageIndex).isRetain());\n    }\n\n    private void thenMessagePriorityIs(final int messageIndex, final int priority) throws KuraStoreException {\n        assertEquals(priority, getStoredMessage(messageIndex).getPriority());\n    }\n\n    private void thenMessageCreatedOnIsInThePast(final int messageIndex) throws KuraStoreException {\n        thenIsInTheRecentPast(getStoredMessage(messageIndex).getCreatedOn());\n    }\n\n    private void thenMessagePublishedOnIsInThePast(final int messageIndex) throws KuraStoreException {\n        thenIsInTheRecentPast(getStoredMessage(messageIndex).getPublishedOn());\n    }\n\n    private void thenMessageConfirmedOnIsInThePast(final int messageIndex) throws KuraStoreException {\n        thenIsInTheRecentPast(getStoredMessage(messageIndex).getConfirmedOn());\n    }\n\n    private void thenMessagePublishedOnIsNotSet(final int messageIndex) throws KuraStoreException {\n        assertEquals(Optional.empty(), getStoredMessage(messageIndex).getPublishedOn());\n    }\n\n    private void thenMessageConfirmedOnIsNotSet(final int messageIndex) throws KuraStoreException {\n        assertEquals(Optional.empty(), getStoredMessage(messageIndex).getConfirmedOn());\n    }\n\n    private void thenMessageDroppedOnIsNotSet(final int messageIndex) throws KuraStoreException {\n        assertEquals(Optional.empty(), getStoredMessage(messageIndex).getDroppedOn());\n    }\n\n    private void thenDataTransportTokenIsNotSet(final int messageIndex) throws KuraStoreException {\n        assertEquals(Optional.empty(), getStoredMessage(messageIndex).getDataTransportToken());\n    }\n\n    private void thenDataTransportTokenIs(final int messageIndex, final DataTransportToken token)\n            throws KuraStoreException {\n        assertEquals(Optional.of(token), getStoredMessage(messageIndex).getDataTransportToken());\n    }\n\n    private void thenNextMessageTopicIs(final String topic) throws KuraStoreException {\n        assertEquals(topic, getNextMessage().getTopic());\n    }\n\n    private void thenNextMessagePayloadIs(final byte[] payload) throws KuraStoreException {\n        assertArrayEquals(payload, getNextMessage().getPayload());\n    }\n\n    private void thenNextMessageQoSIs(final int qos) throws KuraStoreException {\n        assertEquals(qos, getNextMessage().getQos());\n    }\n\n    private void thenNextMessageRetainIs(final boolean retain) throws KuraStoreException {\n        assertEquals(retain, getNextMessage().isRetain());\n    }\n\n    private void thenNextMessagePriorityIs(final int priority) throws KuraStoreException {\n        assertEquals(priority, getNextMessage().getPriority());\n    }\n\n    private void thenNextMessageCreatedOnIsInThePast() throws KuraStoreException {\n        thenIsInTheRecentPast(getNextMessage().getCreatedOn());\n    }\n\n    private void thenNextMessagePublishedOnIsInThePast() throws KuraStoreException {\n        thenIsInTheRecentPast(getNextMessage().getPublishedOn());\n    }\n\n    private void thenNextMessageConfirmedOnIsInThePast() throws KuraStoreException {\n        thenIsInTheRecentPast(getNextMessage().getConfirmedOn());\n    }\n\n    private void thenNextMessagePublishedOnIsNotSet() throws KuraStoreException {\n        assertEquals(Optional.empty(), getNextMessage().getPublishedOn());\n    }\n\n    private void thenNextMessageConfirmedOnIsNotSet() throws KuraStoreException {\n        assertEquals(Optional.empty(), getNextMessage().getConfirmedOn());\n    }\n\n    private void thenNextMessageDroppedOnIsNotSet() throws KuraStoreException {\n        assertEquals(Optional.empty(), getNextMessage().getDroppedOn());\n    }\n\n    private void thenNextMessageDataTransportTokenIsNotSet() throws KuraStoreException {\n        assertEquals(Optional.empty(), getNextMessage().getDataTransportToken());\n    }\n\n    private void thenNextMessageDataTransportTokenIs(final DataTransportToken token) throws KuraStoreException {\n        assertEquals(Optional.of(token), getNextMessage().getDataTransportToken());\n    }\n\n    private void thenMessageExists(final int messageIndex) throws KuraStoreException {\n        assertTrue(this.messageStore.get(this.messageIds.get(messageIndex)).isPresent());\n    }\n\n    private void thenMessageDoesNotExist(final int messageIndex) throws KuraStoreException {\n        assertEquals(Optional.empty(), this.messageStore.get(this.messageIds.get(messageIndex)));\n    }\n\n    private void whenStaleMessagesAreDeleted(final int purgeAgeSeconds) throws KuraStoreException {\n        this.messageStore.deleteStaleMessages(purgeAgeSeconds);\n    }\n\n    private void whenTimePasses(final long amount, final TimeUnit timeUnit) throws InterruptedException {\n        Thread.sleep(timeUnit.toMillis(amount));\n    }\n\n    private void thenLastMessageIdIs(final int value) {\n        assertEquals(value, (int) this.messageIds.get(this.messageIds.size() - 1));\n    }\n\n    private void thenMessageCountIs(final int expectedCount) throws KuraStoreException {\n        assertEquals(expectedCount, this.messageStore.getMessageCount());\n    }\n\n    private void thenNoExceptionIsThrown() {\n        if (this.exception.isPresent()) {\n            this.exception.get().printStackTrace();\n        }\n        assertEquals(Optional.empty(), this.exception);\n    }\n\n    private void thenIsInTheRecentPast(final Optional<Date> maybeDate) {\n        final long now = System.currentTimeMillis();\n        final long date = maybeDate.orElseThrow(() -> new IllegalStateException(\"Date is not set\")).toInstant()\n                .toEpochMilli();\n\n        assertTrue(date <= now && now - date < TimeUnit.SECONDS.toMillis(5));\n    }\n\n    private void thenKuraStoreExceptionIsThrown() {\n        assertEquals(KuraStoreException.class,\n                this.exception.orElseThrow(() -> new IllegalStateException(\"expected exception\")).getClass());\n    }\n\n    private StoredMessage getStoredMessage(final int index) throws KuraStoreException {\n        return this.messageStore.get(this.messageIds.get(index))\n                .orElseThrow(() -> new IllegalStateException(\"no stored message\"));\n    }\n\n    private StoredMessage getNextMessage() throws IllegalStateException, KuraStoreException {\n        return this.messageStore.getNextMessage()\n                .orElseThrow(() -> new IllegalStateException(\"no next message returned\"));\n    }\n\n    private byte[] byteArray(final int... values) {\n        final byte[] result = new byte[values.length];\n\n        for (int i = 0; i < values.length; i++) {\n            result[i] = (byte) values[i];\n        }\n\n        return result;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.message.store.provider.test/src/main/java/org/eclipse/kura/message/store/provider/test/TestTarget.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.message.store.provider.test;\n\nimport java.sql.Connection;\nimport java.sql.Statement;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.db.BaseDbService;\nimport org.eclipse.kura.db.H2DbService;\nimport org.eclipse.kura.message.store.provider.MessageStoreProvider;\n\npublic interface TestTarget {\n\n    public static final TestTarget H2 = new H2();\n    public static final TestTarget SQLITE = new Sqlite();\n\n    public String storeFactoryPid();\n\n    public Map<String, Object> getConfigurationForPid(final String pid);\n\n    public void setMessageId(final String pid, final String collection, final int value);\n\n    public class H2 implements TestTarget {\n\n        @Override\n        public String storeFactoryPid() {\n            return \"org.eclipse.kura.core.db.H2DbService\";\n        }\n\n        @Override\n        public Map<String, Object> getConfigurationForPid(String pid) {\n\n            return Collections.singletonMap(\"db.connector.url\", \"jdbc:h2:mem:testdb-\" + pid);\n        }\n\n        @Override\n        public void setMessageId(final String pid, final String collection, final int value) {\n\n            try {\n                final H2DbService dbService = ServiceUtil\n                        .trackService(H2DbService.class, Optional.of(\"(kura.service.pid=\" + pid + \")\"))\n                        .get(30, TimeUnit.SECONDS);\n\n                try (final Connection c = dbService.getConnection(); final Statement stmt = c.createStatement()) {\n                    stmt.executeUpdate(\n                            \"ALTER TABLE \\\"\" + collection + \"\\\" ALTER COLUMN id RESTART WITH \" + value + \";\");\n                    c.commit();\n                }\n\n                ((MessageStoreProvider) dbService).openMessageStore(collection).store(\"foo\", null, 1, false, 1);\n            } catch (Exception e) {\n                throw new IllegalStateException(\"cannot set next message id\", e);\n            }\n\n        }\n\n        @Override\n        public String toString() {\n            return \"H2\";\n        }\n\n    }\n\n    public class Sqlite implements TestTarget {\n\n        @Override\n        public String storeFactoryPid() {\n\n            return \"org.eclipse.kura.db.SQLiteDbService\";\n        }\n\n        @Override\n        public Map<String, Object> getConfigurationForPid(String pid) {\n\n            return Collections.emptyMap();\n        }\n\n        @Override\n        public void setMessageId(final String pid, final String collection, final int value) {\n            try {\n                final BaseDbService dbService = ServiceUtil\n                        .trackService(BaseDbService.class, Optional.of(\"(kura.service.pid=\" + pid + \")\"))\n                        .get(30, TimeUnit.SECONDS);\n\n                try (final Connection c = dbService.getConnection(); final Statement stmt = c.createStatement()) {\n                    stmt.executeUpdate(\n                            \"UPDATE sqlite_sequence SET seq = \" + value + \" WHERE name = \\\"\" + collection + \"\\\";\");\n                }\n\n            } catch (Exception e) {\n                throw new IllegalStateException(\"cannot set next message id\", e);\n            }\n        }\n\n        @Override\n        public String toString() {\n            return \"SQLite\";\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.protocol.modbus.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.protocol.modbus.test\nBundle-SymbolicName: org.eclipse.kura.protocol.modbus.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.2,2.0)\",\n org.eclipse.kura.protocol.modbus;version=\"1.0.1\",\n org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.system;version=\"[1.1,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.protocol.modbus.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.protocol.modbus.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.junit,\\\n                     org.apache.logging.log4j.api\n\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.protocol.modbus.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n     Eurotech\n     \n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n    <artifactId>org.eclipse.kura.protocol.modbus.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.protocol.modbus.test/src/test/java/org/eclipse/kura/protocol/modbus/ModbusProtocolDeviceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.protocol.modbus;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.IOException;\nimport java.util.Properties;\n\nimport org.eclipse.kura.KuraConnectionStatus;\nimport org.eclipse.kura.protocol.modbus.test.ModbusServer;\nimport org.junit.After;\nimport org.junit.AfterClass;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ModbusProtocolDeviceTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(ModbusProtocolDeviceTest.class);\n\n    private static ModbusServer modbusServer;\n\n    private ModbusProtocolDevice modbusDevice;\n\n    @BeforeClass\n    public static void startServer() throws Exception {\n        modbusServer = new ModbusServer();\n        modbusServer.start(32345);\n        logger.info(\"MODBUS server started\");\n    }\n\n    @AfterClass\n    public static void stopServer() throws IOException {\n        modbusServer.stop();\n        logger.info(\"MODBUS server stopped\");\n    }\n\n    @Before\n    public void connect() throws ModbusProtocolException {\n        modbusDevice = new ModbusProtocolDevice();\n        Properties connectionConfig = new Properties();\n        connectionConfig.setProperty(\"connectionType\", ModbusProtocolDevice.PROTOCOL_CONNECTION_TYPE_ETHER_TCP);\n        connectionConfig.setProperty(\"ipAddress\", \"127.0.0.1\");\n        connectionConfig.setProperty(\"ethport\", \"32345\");\n        connectionConfig.setProperty(\"respTimeout\", \"10000\");\n        connectionConfig.setProperty(\"transmissionMode\", ModbusTransmissionMode.RTU);\n        modbusDevice.configureConnection(connectionConfig);\n        modbusDevice.connect();\n    }\n\n    @After\n    public void disconnect() throws ModbusProtocolException {\n        modbusDevice.disconnect();\n    }\n\n    @Test\n    public void testGetConnectStatus() throws ModbusProtocolException {\n        int connectStatus = modbusDevice.getConnectStatus();\n        assertEquals(KuraConnectionStatus.CONNECTED, connectStatus);\n    }\n\n    @Test\n    public void testReadCoils() throws ModbusProtocolException {\n        boolean[] coils = modbusDevice.readCoils(1, 0, 1);\n        assertEquals(1, coils.length);\n        assertTrue(coils[0]);\n    }\n\n    @Test\n    public void testWriteSingleCoil() throws ModbusProtocolException {\n        modbusDevice.writeSingleCoil(1, 0, true);\n        assertTrue(\"No exception\", true);\n    }\n\n    @Test\n    public void testWriteMultipleCoils() throws ModbusProtocolException {\n        modbusDevice.writeMultipleCoils(1, 1, new boolean[] { true, false, true, true, false });\n        assertTrue(\"No exception\", true);\n    }\n\n    @Test\n    public void testReadHoldingRegisters() throws ModbusProtocolException {\n        int[] holdingReg = modbusDevice.readHoldingRegisters(1, 0, 1);\n        assertEquals(1, holdingReg.length);\n        assertEquals(2, holdingReg[0]);\n    }\n\n    @Test\n    public void testWriteSingleRegister() throws ModbusProtocolException {\n        modbusDevice.writeSingleRegister(1, 0, 37);\n        assertTrue(\"No exception\", true);\n    }\n\n    @Test\n    public void testWriteMultipleRegister() throws ModbusProtocolException {\n        modbusDevice.writeMultipleRegister(1, 0, new int[] { 12, 24, 46, 58 });\n        assertTrue(\"No exception\", true);\n    }\n\n    @Test\n    public void testReadDiscreteInputs() throws ModbusProtocolException {\n        boolean[] discreteInputs = modbusDevice.readDiscreteInputs(1, 1, 4);\n        assertEquals(4, discreteInputs.length);\n        assertTrue(discreteInputs[0]);\n        assertTrue(discreteInputs[1]);\n        assertTrue(discreteInputs[2]);\n        assertTrue(discreteInputs[3]);\n    }\n\n    @Test\n    public void testReadInputRegisters() throws ModbusProtocolException {\n        int[] inputRegs = modbusDevice.readInputRegisters(1, 8, 1);\n        assertEquals(inputRegs.length, 1);\n        assertEquals(10, inputRegs[0]);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.protocol.modbus.test/src/test/java/org/eclipse/kura/protocol/modbus/test/ModbusHandler.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.protocol.modbus.test;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.Socket;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ModbusHandler extends Thread {\n\n    private static final Logger logger = LoggerFactory.getLogger(ModbusHandler.class);\n\n    private Socket socket = null;\n\n    public ModbusHandler(Socket socket) {\n        super(\"ModbusHandler\");\n        this.socket = socket;\n    }\n\n    public void run() {\n        try (OutputStream out = socket.getOutputStream(); InputStream in = socket.getInputStream()) {\n            byte[] input = new byte[256];\n            int length = in.read(input);\n            byte[] output = handleRequest(input);\n            out.write(output);\n        } catch (IOException e) {\n            logger.error(\"ModbusHandler\", e);\n            throw new RuntimeException(e);\n        } finally {\n            try {\n                socket.close();\n            } catch (IOException e) {\n                logger.error(\"ModbusHandler\", e);\n            }\n        }\n    }\n\n    private byte[] handleRequest(byte[] input) {\n        byte command = input[7];\n        switch (command) {\n        case 1:\n            return new byte[] { 0, 1, 0, 0, 0, 4, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, };           // readColis\n        case 5:\n            return new byte[] { 0, 1, 0, 0, 0, 6, 1, 5, 0, 0, input[10], 0, 0, 0, 0 };             // writeSingleCoil\n        case 15:\n            return new byte[] { 0, 1, 0, 0, 0, 6, 1, 15, 0, 1, 0, 5, 0, 0, 0, 0, 0 };              // writeMultiplecoils\n        case 3:\n            return new byte[] { 0, 1, 0, 0, 0, 5, 1, 3, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0 };            // readHoldingRegister\n        case 6:\n            return new byte[] { 0, 1, 0, 0, 0, 6, 1, 6, 0, 0, 0, input[11], 0, 0, 0 };             // wrieSingleRigister\n        case 16:\n            return new byte[] { 0, 1, 0, 0, 0, 6, 1, 16, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0 };           // writeMultipleRegisters\n        case 2:\n            return new byte[] { 0, 1, 0, 0, 0, 6, 1, 2, 1, 127, 0, 0, 0, 0, 0, 0, 0, 0 };          // readDiscreteInputs\n        case 4:\n            return new byte[] { 0, 1, 0, 0, 0, 6, 1, 4, 2, 0, 10, 0, 0, 0, 0, 0, 0, 0 };           // readInputRegisters\n        case 11:\n            return new byte[] {};                                                                  // getCommEventCouner\n        case 7:\n            return new byte[] {};                                                                  // readExceptionStatus\n        case 12:\n            return new byte[] {};                                                                  // getCommEventLog\n        }\n        return new byte[] {};\n    }\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.protocol.modbus.test/src/test/java/org/eclipse/kura/protocol/modbus/test/ModbusServer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.protocol.modbus.test;\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\nimport java.util.concurrent.CountDownLatch;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ModbusServer {\n\n    private static final Logger logger = LoggerFactory.getLogger(ModbusServer.class);\n\n    CountDownLatch latch = new CountDownLatch(1);\n\n    private boolean listening = true;\n    private ServerSocket serverSocket;\n\n    public void start(int port) throws IOException, InterruptedException {\n        new Thread() {\n\n            @Override\n            public void run() {\n                try {\n                    serverSocket = new ServerSocket(port);\n                    latch.countDown();   // make sure server is ready before running tests\n                    while (listening) {\n                        ModbusHandler modbusHandler = new ModbusHandler(serverSocket.accept());\n                        modbusHandler.start();\n                    }\n                } catch (IOException e) {\n                    logger.error(\"ModbusServer fatal error\", e);\n                    System.exit(-1);\n                }\n            }\n        }.start();\n        latch.await();  // wait for server socket is ready\n    }\n\n    public void stop() throws IOException {\n        // serverSocket.close();\n        listening = false;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.raspberrypi.sensehat.test\nBundle-SymbolicName: org.eclipse.kura.raspberrypi.sensehat.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.raspberrypi.sensehat;bundle-version=\"1.0.300\"\nImport-Package: org.eclipse.kura;version=\"[1.2,2.0)\",\n org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.system;version=\"[1.1,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.7\",\n org.osgi.service.cm;version=\"1.4\",\n org.osgi.service.component;version=\"1.2\",\n org.slf4j;version=\"1.6.4\",\n org.apache.log4j\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     slf4j.log4j12,\\\n                     org.junit\n                  \n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n    <artifactId>org.eclipse.kura.raspberrypi.sensehat.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/ledmatrix/FrameBufferTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.raspberrypi.sensehat.ledmatrix;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\nimport java.lang.reflect.Field;\nimport java.net.URL;\n\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.junit.Test;\nimport org.mockito.invocation.InvocationOnMock;\nimport org.mockito.stubbing.Answer;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.service.component.ComponentContext;\n\npublic class FrameBufferTest {\n\n    @Test\n    public void testFlipVertical() throws Exception {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        assertNotNull(frameBuffer);\n        frameBuffer.flipVertical(Images.ARROW_UP);\n        short[][][] pixels = frameBuffer.getPixels();\n        assertArrayEquals(Images.ARROW_DOWN, pixels);\n        FrameBuffer.closeFrameBuffer();\n    }\n\n    @Test\n    public void testFlipHorizontal() {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        assertNotNull(frameBuffer);\n        FrameBuffer.setRotation(270);\n        frameBuffer.flipHorizontal(Images.ARROW_RIGHT);\n        short[][][] pixels = frameBuffer.getPixels();\n        assertArrayEquals(Images.ARROW_DOWN, pixels);\n        FrameBuffer.closeFrameBuffer();\n\n    }\n\n    @Test\n    public void testSetPixels() {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        assertNotNull(frameBuffer);\n        frameBuffer.setPixels(Images.TRIANGLE);\n        short[][][] pixels = frameBuffer.getPixels();\n        assertArrayEquals(Images.TRIANGLE, pixels);\n        FrameBuffer.closeFrameBuffer();\n    }\n\n    @Test\n    public void testSetPixel() {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        assertNotNull(frameBuffer);\n        frameBuffer.clearFrameBuffer();\n        frameBuffer.setPixel(new int[] { 4, 3 }, Images.B);\n        short[][][] pixels = frameBuffer.getPixels();\n        assertArrayEquals(Images.B, pixels[4][3]);\n        for (int i = 0; i < 8; i++) {\n            for (int j = 0; j < 8; j++) {\n                if (i != 4 && j != 3) {\n                    assertArrayEquals(Images.W, pixels[i][j]);\n                }\n            }\n        }\n    }\n\n    @Test\n    public void testGetPixels() {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        assertNotNull(frameBuffer);\n        frameBuffer.setPixels(Images.TRIANGLE);\n        short[][][] pixels = frameBuffer.getPixels();\n        assertArrayEquals(Images.TRIANGLE, pixels);\n        FrameBuffer.closeFrameBuffer();\n    }\n\n    @Test\n    public void testGetPixel() {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        assertNotNull(frameBuffer);\n        frameBuffer.setPixels(Images.TRIANGLE);\n        for (int i = 0; i < 8; i++) {\n            for (int j = 0; j < 8; j++) {\n                if (i < j) {\n                    assertArrayEquals(Images.W, frameBuffer.getPixel(new int[] { i, j }));\n                } else {\n                    assertArrayEquals(Images.B, frameBuffer.getPixel(new int[] { i, j }));\n                }\n            }\n        }\n    }\n\n    @Test\n    public void testShowMessage() {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        frameBuffer.setPixels(Images.TRIANGLE);\n        frameBuffer.showMessage(\"test\", Images.B, Images.W);\n        // showMessage() will show blank display at the end of the message\n        assertArrayEquals(Images.BLANK, frameBuffer.getPixels());\n    }\n\n    @Test\n    public void testShowLetter() {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        assertNotNull(frameBuffer);\n        frameBuffer.showLetter(\"T\", Images.B, Images.W);\n        short[][][] pixels = frameBuffer.getPixels();\n        assertArrayEquals(Images.LETTER_T, pixels);\n        FrameBuffer.closeFrameBuffer();\n    }\n\n    @Test\n    public void testClearFrameBuffer() {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        assertNotNull(frameBuffer);\n        frameBuffer.setPixels(Images.TRIANGLE);\n        frameBuffer.clearFrameBuffer();\n        short[][][] pixels = frameBuffer.getPixels();\n        assertArrayEquals(Images.BLANK, pixels);\n        FrameBuffer.closeFrameBuffer();\n    }\n\n    @Test\n    public void testCloseFrameBuffer() throws Exception {\n        configureVirtualFrameBuffer();\n        FrameBuffer frameBuffer = FrameBuffer.getFrameBuffer(createMockedContext());\n        assertNotNull(frameBuffer);\n        Field field = FrameBuffer.class.getDeclaredField(\"raf\");\n        field.setAccessible(true);\n        RandomAccessFile raf = (RandomAccessFile) field.get(null);\n        assertNotNull(raf);\n        FrameBuffer.closeFrameBuffer();\n        raf = (RandomAccessFile) field.get(null);\n        boolean closed = (boolean) TestUtil.getFieldValue(raf, \"closed\");\n        assertTrue(\"FrameBuffer not closed!\", closed);\n    }\n\n    private ComponentContext createMockedContext() {\n        Bundle bundle = mock(Bundle.class);\n        when(bundle.getResource(anyString())).thenAnswer(new Answer<URL>() {\n\n            @Override\n            public URL answer(InvocationOnMock invocation) throws Throwable {\n                return new URL(\"file:./src/test/resources/test-sensehat_text.pbm\");\n            }\n        });\n        BundleContext bundleCtx = mock(BundleContext.class);\n        when(bundleCtx.getBundle()).thenReturn(bundle);\n        ComponentContext ctx = mock(ComponentContext.class);\n        when(ctx.getBundleContext()).thenReturn(bundleCtx);\n        return ctx;\n    }\n\n    private void configureVirtualFrameBuffer() {\n        try {\n            Field field = FrameBuffer.class.getDeclaredField(\"FrameBufferFile\");\n            field.setAccessible(true);\n            field.set(null, new File(\"target/fb-test.output\"));\n            Field graphicsFolderField = FrameBuffer.class.getDeclaredField(\"graphicsFolder\");\n            graphicsFolderField.setAccessible(true);\n            graphicsFolderField.set(null, new File(\"src/test/resources/\"));\n        } catch (Exception e) {\n            throw new RuntimeException(e.getMessage());\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/ledmatrix/Images.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\n\npackage org.eclipse.kura.raspberrypi.sensehat.ledmatrix;\n\npublic class Images {\n\n    public static final short[] B = new short[] { 0, 0, 248 };\n    public static final short[] W = new short[] { 0, 0, 0 };\n\n    //@formatter:off\n    public static final short TRIANGLE[][][] = new short[][][] { \n        { B, W, W, W, W, W, W, W }, \n        { B, B, W, W, W, W, W, W },\n        { B, B, B, W, W, W, W, W }, \n        { B, B, B, B, W, W, W, W }, \n        { B, B, B, B, B, W, W, W },\n        { B, B, B, B, B, B, W, W }, \n        { B, B, B, B, B, B, B, W }, \n        { B, B, B, B, B, B, B, B } \n    };\n\n    public static final short ARROW_UP[][][] = new short[][][] { \n        { W, W, W, B, W, W, W, W },\n        { W, W, B, B, B, W, W, W },\n        { W, B, W, B, W, B, W, W },\n        { B, W, W, B, W, W, B, W },\n        { W, W, W, B, W, W, W, W },\n        { W, W, W, B, W, W, W, W },\n        { W, W, W, B, W, W, W, W },\n        { W, W, W, B, W, W, W, W }\n\n    };\n\n    public static final short ARROW_DOWN[][][] = new short[][][] { \n        { W, W, W, B, W, W, W, W },\n        { W, W, W, B, W, W, W, W },\n        { W, W, W, B, W, W, W, W },\n        { W, W, W, B, W, W, W, W },\n        { B, W, W, B, W, W, B, W },\n        { W, B, W, B, W, B, W, W },\n        { W, W, B, B, B, W, W, W },\n        { W, W, W, B, W, W, W, W }\n\n    };\n    \n    public static final short ARROW_RIGHT[][][] = new short[][][] { \n        { W, W, W, W, B, W, W, W },\n        { W, W, W, W, W, B, W, W },\n        { W, W, W, W, W, W, B, W },\n        { B, B, B, B, B, B, B, B },\n        { W, W, W, W, W, W, B, W },\n        { W, W, W, W, W, B, W, W },\n        { W, W, W, W, B, W, W, W },\n        { W, W, W, W, W, W, W, W }\n\n    };    \n\n    public static final short ARROW_LEFT[][][] = new short[][][] { \n        { W, W, W, B, W, W, W, W },\n        { W, W, B, W, W, W, W, W },\n        { W, B, W, W, W, W, W, W },\n        { B, B, B, B, B, B, B, B },\n        { W, B, W, W, W, W, W, W },\n        { W, W, B, W, W, W, W, W },\n        { W, W, W, B, W, W, W, W },\n        { W, W, W, W, W, W, W, W }\n\n    };      \n    \n    public static final short LETTER_T[][][] = new short[][][] { \n        { W, W, W, W, W, W, W, W },\n        { W, W, W, W, W, W, W, W },\n        { W, W, W, W, W, W, B, W },\n        { W, W, W, W, W, W, B, W },\n        { B, B, B, B, B, B, B, W },\n        { W, W, W, W, W, W, B, W },\n        { W, W, W, W, W, W, B, W },\n        { W, W, W, W, W, W, W, W }\n\n    };    \n    \n    public static final short BLANK[][][] = new short[][][] { \n        { W, W, W, W, W, W, W, W },\n        { W, W, W, W, W, W, W, W },\n        { W, W, W, W, W, W, W, W },\n        { W, W, W, W, W, W, W, W },\n        { W, W, W, W, W, W, W, W },\n        { W, W, W, W, W, W, W, W },\n        { W, W, W, W, W, W, W, W },\n        { W, W, W, W, W, W, W, W }\n\n    };    \n    \n    //@formatter:on      \n\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/sensors/HTS221Test.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.raspberrypi.sensehat.sensors;\n\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.CTRL_REG1;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.HUMIDITY_H_REG;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.HUMIDITY_L_REG;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.TEMP_H_REG;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.TEMP_L_REG;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices.DummyDevice;\nimport org.junit.Test;\n\npublic class HTS221Test {\n\n    @Test\n    public void testGetHumiditySensor() {\n        HTS221 hts221 = HTS221.getHumiditySensor(1, 2, 1, 1);\n        assertNotNull(\"HTS221 not created\", hts221);\n    }\n\n    @Test\n    public void testInitDevice() {\n        HTS221 hts221 = HTS221.getHumiditySensor(1, 2, 1, 1);\n        boolean result = hts221.initDevice();\n        assertTrue(\"HTS221 not inited\", result);\n    }\n\n    @Test\n    public void testCloseDevice() throws NoSuchFieldException {\n        HTS221 hts221 = HTS221.getHumiditySensor(1, 2, 1, 1);\n        hts221.initDevice();\n        assertNotNull(hts221);\n        KuraI2CDevice humidityI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(hts221, \"humidityI2CDevice\");\n        assertNotNull(humidityI2CDevice);\n        HTS221.closeDevice();\n        HTS221 closedHummiditySensor = (HTS221) TestUtil.getFieldValue(hts221, \"humiditySensor\");\n        KuraI2CDevice closedHummidityI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(hts221, \"humidityI2CDevice\");\n        assertNull(closedHummiditySensor);\n        assertNull(closedHummidityI2CDevice);\n    }\n\n    @Test\n    public void testGetHumidity() throws NoSuchFieldException {\n        HTS221 hts221 = HTS221.getHumiditySensor(1, 2, 1, 1);\n        boolean result = hts221.initDevice();\n        float humidity = hts221.getHumidity();\n        float mh = (float) TestUtil.getFieldValue(hts221, \"mh\");\n        float qh = (float) TestUtil.getFieldValue(hts221, \"qh\");\n        assertTrue(mh * (HUMIDITY_H_REG << 8 | HUMIDITY_L_REG) + qh == humidity);\n\n    }\n\n    @Test\n    public void testGetTemperature() throws NoSuchFieldException {\n        HTS221 hts221 = HTS221.getHumiditySensor(1, 2, 1, 1);\n        boolean result = hts221.initDevice();\n        float temperature = hts221.getTemperature();\n        float mt = (float) TestUtil.getFieldValue(hts221, \"mt\");\n        float qt = (float) TestUtil.getFieldValue(hts221, \"qt\");\n        assertTrue(mt * (TEMP_H_REG << 8 | TEMP_L_REG) + qt == temperature);\n    }\n\n    @Test\n    public void testIsHumidityReady() {\n        HTS221 hts221 = HTS221.getHumiditySensor(1, 2, 1, 1);\n        hts221.initDevice();\n        boolean result = hts221.isHumidityReady();\n        assertTrue(\"Humidity not ready\", result);\n\n    }\n\n    @Test\n    public void testIsTemperatureReady() {\n        HTS221 hts221 = HTS221.getHumiditySensor(1, 2, 1, 1);\n        hts221.initDevice();\n        boolean result = hts221.isTemperatureReady();\n        assertTrue(\"Temperature not ready\", result);\n    }\n\n    @Test\n    public void testRead() {\n        // we test by writing to the simualted device register the same value as the register address\n        // and then we expect the same value\n        HTS221 hts221 = HTS221.getHumiditySensor(1, 2, 1, 1);\n        hts221.initDevice();\n        int val = HTS221.read(CTRL_REG1);\n        assertEquals(\"Sensor reading not as expected\", CTRL_REG1, val);\n    }\n\n    @Test\n    public void testWrite() throws NoSuchFieldException {\n        HTS221 hts221 = HTS221.getHumiditySensor(1, 2, 1, 1);\n        hts221.initDevice();\n        HTS221.write(0, new byte[] { 50 });\n        KuraI2CDevice humidityI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(hts221, \"humidityI2CDevice\");\n        DummyDevice dummyyDevice = (DummyDevice) TestUtil.getFieldValue(humidityI2CDevice, \"device\");\n        int registerValue = (int) TestUtil.getFieldValue(dummyyDevice, \"register\");\n        assertEquals(\"Sensor writing not as expected\", 50, registerValue);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/sensors/KuraI2CDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.raspberrypi.sensehat.sensors;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\nimport org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices.DummyDevice;\nimport org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices.HTS221DummyDevice;\nimport org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices.LPS25HDummyDevice;\nimport org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices.LSM9DS1TAccDummyyDevice;\nimport org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices.LSM9DS1TMagDummyyDevice;\n\npublic class KuraI2CDevice {\n\n    private int bus;\n    private int address;\n    private int addressSize;\n    private int frequency;\n\n    private DummyDevice device;\n\n    public KuraI2CDevice(int bus, int address, int addressSize, int frequency) {\n        this.bus = bus;\n        this.address = address;\n        this.addressSize = addressSize;\n        this.frequency = frequency;\n        switch (address) {\n        case LPS25HDummyDevice.ID:\n            device = new LPS25HDummyDevice();\n            break;\n        case HTS221DummyDevice.ID:\n            device = new HTS221DummyDevice();\n            break;\n        case LSM9DS1TMagDummyyDevice.ID:\n            device = new LSM9DS1TMagDummyyDevice();\n            break;\n        case LSM9DS1TAccDummyyDevice.ID:\n            device = new LSM9DS1TAccDummyyDevice();\n            break;\n        }\n    }\n\n    public int read() throws IOException {\n        return device.read();\n    }\n\n    public void write(int value) throws IOException {\n        device.write(value);\n    }\n\n    public void write(int register, int size, ByteBuffer value) throws IOException {\n        device.write(register, size, value);\n    }\n\n    public void beginTransaction() throws IOException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void endTransaction() throws IOException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void close() throws IOException {\n        device.close();\n    }\n\n    public boolean isOpen() {\n        return device.isOpen();\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/sensors/LPS25HTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.raspberrypi.sensehat.sensors;\n\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.PRESS_OUT_H;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.PRESS_OUT_L;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.PRESS_OUT_XL;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.TEMP_OUT_H;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.TEMP_OUT_L;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices.DummyDevice;\nimport org.junit.Test;\n\npublic class LPS25HTest {\n\n    @Test\n    public void testGetPressureSensor() {\n        LPS25H lps25h = LPS25H.getPressureSensor(1, 1, 1, 1);\n        assertNotNull(\"LPS25H not created\", lps25h);\n    }\n\n    @Test\n    public void testRead() {\n        // we test by writing to the simualted device register the same value as the register address\n        // and then we expect the same value\n        LPS25H lps25h = LPS25H.getPressureSensor(1, 1, 1, 1);\n        lps25h.initDevice();\n        int val = LPS25H.read(TEMP_OUT_H);\n        assertEquals(\"Sensor reading not as expected\", TEMP_OUT_H, val);\n    }\n\n    @Test\n    public void testWrite() throws NoSuchFieldException {\n        LPS25H lps25h = LPS25H.getPressureSensor(1, 1, 1, 1);\n        lps25h.initDevice();\n        LPS25H.write(0, new byte[] { 50 });\n        KuraI2CDevice pressureI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lps25h, \"pressureI2CDevice\");\n        DummyDevice dummyyDevice = (DummyDevice) TestUtil.getFieldValue(pressureI2CDevice, \"device\");\n        int registerValue = (int) TestUtil.getFieldValue(dummyyDevice, \"register\");\n        assertEquals(\"Sensor writing not as expected\", 50, registerValue);\n    }\n\n    @Test\n    public void testInitDevice() {\n        LPS25H lps25h = LPS25H.getPressureSensor(1, 1, 1, 1);\n        boolean result = lps25h.initDevice();\n        assertTrue(\"Device not inited\", result);\n    }\n\n    @Test\n    public void testCloseDevice() throws NoSuchFieldException {\n        LPS25H lps25h = LPS25H.getPressureSensor(1, 1, 1, 1);\n        KuraI2CDevice pressureI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lps25h, \"pressureI2CDevice\");\n        lps25h.initDevice();\n        assertNotNull(lps25h);\n        assertNotNull(pressureI2CDevice);\n        LPS25H.closeDevice();\n        LPS25H closedPressureSensor = (LPS25H) TestUtil.getFieldValue(lps25h, \"pressureSensor\");\n        KuraI2CDevice closedPressureI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lps25h, \"pressureI2CDevice\");\n        assertNull(closedPressureSensor);\n        assertNull(closedPressureI2CDevice);\n    }\n\n    @Test\n    public void testGetPressure() {\n        LPS25H lps25h = LPS25H.getPressureSensor(1, 1, 1, 1);\n        lps25h.initDevice();\n        float pressure = lps25h.getPressure();\n        // simulate reading device registers using the same values that are sent as commands\n        assertTrue((PRESS_OUT_H << 16 | PRESS_OUT_L << 8 | PRESS_OUT_XL) / 4096F == pressure);\n    }\n\n    @Test\n    public void testGetTemperature() {\n        LPS25H lps25h = LPS25H.getPressureSensor(1, 1, 1, 1);\n        lps25h.initDevice();\n        float temperaure = lps25h.getTemperature();\n        // simulate reading device registers using the same values that are sent as commands\n        assertTrue(42.5F + (TEMP_OUT_H << 8 | TEMP_OUT_L << 0) / 480F == temperaure);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/sensors/LSM9DS1Test.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.raspberrypi.sensehat.sensors;\n\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.ACC_DEVICE;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.CTRL_REG1_G;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.CTRL_REG2_M;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.MAG_DEVICE;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.Arrays;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices.DummyDevice;\nimport org.junit.Test;\n\npublic class LSM9DS1Test {\n\n    @Test\n    public void testGetIMUSensor() {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        assertNotNull(\"LSM9DS1 not created\", lsm9ds1);\n    }\n\n    @Test\n    public void testInitDevice() {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        boolean result = lsm9ds1.initDevice(true, true, true);\n        assertTrue(\"LSM9DS1 not inited\", result);\n    }\n\n    @Test\n    public void testCloseDevice() throws NoSuchFieldException {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        lsm9ds1.initDevice(true, true, true);\n        KuraI2CDevice accI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"accI2CDevice\");\n        KuraI2CDevice magI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"magI2CDevice\");\n        assertNotNull(lsm9ds1);\n        assertNotNull(accI2CDevice);\n        assertNotNull(magI2CDevice);\n        LSM9DS1.closeDevice();\n        LSM9DS1 sensor = (LSM9DS1) TestUtil.getFieldValue(lsm9ds1, \"imuSensor\");\n        KuraI2CDevice closedAccDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"accI2CDevice\");\n        KuraI2CDevice closedMagDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"magI2CDevice\");\n        assertNull(sensor);\n        assertNull(closedAccDevice);\n        assertNull(closedMagDevice);\n    }\n\n    @Test\n    public void testRead() throws KuraException {\n        // we test by writing to the simulated device register the same value as the register address\n        // and then we expect the same value\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        lsm9ds1.initDevice(true, true, true);\n        int val = LSM9DS1.read(ACC_DEVICE, CTRL_REG1_G);\n        assertEquals(\"Sensor reading not as expected\", CTRL_REG1_G, val);\n        int magval = LSM9DS1.read(MAG_DEVICE, CTRL_REG2_M);\n        assertEquals(\"Sensor reading not as expected\", CTRL_REG2_M, magval);\n    }\n\n    @Test\n    public void testWrite() throws NoSuchFieldException, KuraException {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        lsm9ds1.initDevice(true, true, true);\n        LSM9DS1.write(ACC_DEVICE, 0, new byte[] { 22 });\n        LSM9DS1.write(MAG_DEVICE, 0, new byte[] { 33 });\n        KuraI2CDevice accI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"accI2CDevice\");\n        DummyDevice accSensor = (DummyDevice) TestUtil.getFieldValue(accI2CDevice, \"device\");\n        KuraI2CDevice magI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"accI2CDevice\");\n        DummyDevice magSensor = (DummyDevice) TestUtil.getFieldValue(accI2CDevice, \"device\");\n        int accValue = (int) TestUtil.getFieldValue(accSensor, \"register\");\n        assertEquals(\"Sensor writing not as expected\", 22, accValue);\n        int magValue = (int) TestUtil.getFieldValue(magSensor, \"register\");\n        assertEquals(\"Sensor writing not as expected\", 22, magValue);\n    }\n\n    @Test\n    public void testGetCompassRaw() {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        float[] compasRaw = lsm9ds1.getCompassRaw();\n        float[] expected = new float[] { 9.692838F, -17.843777F, -21.380009F };\n        assertTrue(Arrays.equals(expected, compasRaw));\n    }\n\n    @Test\n    public void testGetGyroscopeRaw() {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        float[] gyroRaw = lsm9ds1.getGyroscopeRaw();\n        float[] expected = new float[] { -0.024642F, -0.020255F, 0.011905F };\n        assertTrue(Arrays.equals(expected, gyroRaw));\n    }\n\n    @Test\n    public void testGetAccelerometerRaw() {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        float[] accelerometerRaw = lsm9ds1.getAccelerometerRaw();\n        float[] expected = new float[] { -0.16921997F, -0.17315522F, 0.17095335F };\n        assertTrue(Arrays.equals(expected, accelerometerRaw));\n    }\n\n    @Test\n    public void testEnableAccelerometer() throws NoSuchFieldException {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        LSM9DS1.enableAccelerometer();\n        KuraI2CDevice accI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"accI2CDevice\");\n        DummyDevice dummyyDevice = (DummyDevice) TestUtil.getFieldValue(accI2CDevice, \"device\");\n        int registerValue = (int) TestUtil.getFieldValue(dummyyDevice, \"register\");\n        assertEquals(0x7B, registerValue);\n    }\n\n    @Test\n    public void testDisableAccelerometer() throws NoSuchFieldException {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        LSM9DS1.disableAccelerometer();\n        KuraI2CDevice accI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"accI2CDevice\");\n        DummyDevice dummyyDevice = (DummyDevice) TestUtil.getFieldValue(accI2CDevice, \"device\");\n        int registerValue = (int) TestUtil.getFieldValue(dummyyDevice, \"register\");\n        assertEquals(0x0, registerValue);\n    }\n\n    @Test\n    public void testEnableGyroscope() throws NoSuchFieldException {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        LSM9DS1.enableGyroscope();\n        int gyroSampleRate = (int) TestUtil.getFieldValue(lsm9ds1, \"gyroSampleRate\");\n        assertEquals(119, gyroSampleRate);\n        KuraI2CDevice accI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"accI2CDevice\");\n        DummyDevice dummyyDevice = (DummyDevice) TestUtil.getFieldValue(accI2CDevice, \"device\");\n        int registerValue = (int) TestUtil.getFieldValue(dummyyDevice, \"register\");\n        assertEquals(0x44, registerValue);\n    }\n\n    @Test\n    public void testDisableGyroscope() throws NoSuchFieldException {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        LSM9DS1.disableGyroscope();\n        KuraI2CDevice accI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"accI2CDevice\");\n        DummyDevice dummyyDevice = (DummyDevice) TestUtil.getFieldValue(accI2CDevice, \"device\");\n        int registerValue = (int) TestUtil.getFieldValue(dummyyDevice, \"register\");\n        assertEquals(16, registerValue);\n    }\n\n    @Test\n    public void testEnableMagnetometer() throws NoSuchFieldException {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        LSM9DS1.enableMagnetometer();\n        KuraI2CDevice magI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"magI2CDevice\");\n        DummyDevice dummyyDevice = (DummyDevice) TestUtil.getFieldValue(magI2CDevice, \"device\");\n        int registerValue = (int) TestUtil.getFieldValue(dummyyDevice, \"register\");\n        assertEquals(0x0, registerValue);\n    }\n\n    @Test\n    public void testDisableMagnetometer() throws NoSuchFieldException {\n        LSM9DS1 lsm9ds1 = LSM9DS1.getIMUSensor(1, 3, 4, 1, 1);\n        LSM9DS1.disableMagnetometer();\n        KuraI2CDevice magI2CDevice = (KuraI2CDevice) TestUtil.getFieldValue(lsm9ds1, \"magI2CDevice\");\n        DummyDevice dummyyDevice = (DummyDevice) TestUtil.getFieldValue(magI2CDevice, \"device\");\n        int registerValue = (int) TestUtil.getFieldValue(dummyyDevice, \"register\");\n        assertEquals(0x3, registerValue);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/sensors/dummydevices/DummyDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\npublic abstract class DummyDevice {\n\n    protected boolean open;\n    protected int register = -1;\n\n    public abstract int read();\n\n    public void write(int value) throws IOException {\n        register = value;\n    }\n\n    public void write(int register, int size, ByteBuffer value) throws IOException {\n        if (value.array().length == 4) {\n            this.register = value.getInt() & 0xFF;\n        } else {\n            this.register = value.get() & 0xFF;\n        }\n    }\n\n    public void close() throws IOException {\n        open = false;\n    }\n\n    public boolean isOpen() {\n        return open;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/sensors/dummydevices/HTS221DummyDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices;\n\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.CTRL_REG1;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.H0_T0_OUT_H;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.H0_T0_OUT_L;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.H0_rH_x2;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.H1_T0_OUT_H;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.H1_T0_OUT_L;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.H1_rH_x2;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.HUMIDITY_H_REG;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.HUMIDITY_L_REG;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.STATUS_REG;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.T0_OUT_H;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.T0_OUT_L;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.T0_T1_msb;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.T0_degC_x8;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.T1_OUT_H;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.T1_OUT_L;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.T1_degC_x8;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.TEMP_H_REG;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.TEMP_L_REG;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.WHO_AM_I;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.HTS221.WHO_AM_I_ID;\n\nimport java.util.Random;\n\npublic class HTS221DummyDevice extends DummyDevice {\n\n    public static final int ID = 2;\n\n    private Random rnd = new Random();\n\n    @Override\n    public int read() {\n        switch (register) {\n        case STATUS_REG:\n            return 3;  // temparature (bit 1) and humiditiy (bit 2) ready\n        case WHO_AM_I:\n            return WHO_AM_I_ID;\n        case HUMIDITY_H_REG:   // we can return any value, returning the same for the simplicity\n        case HUMIDITY_L_REG:\n        case TEMP_H_REG:\n        case TEMP_L_REG:\n        case CTRL_REG1:\n            return register;\n        case H0_rH_x2:  // random values are OK for calibration\n        case H1_rH_x2:\n        case T0_T1_msb:\n        case T0_degC_x8:\n        case T1_degC_x8:\n        case H0_T0_OUT_H:\n        case H0_T0_OUT_L:\n        case H1_T0_OUT_H:\n        case H1_T0_OUT_L:\n        case T0_OUT_H:\n        case T0_OUT_L:\n        case T1_OUT_H:\n        case T1_OUT_L:\n            byte[] rndVal = new byte[1];\n            rnd.nextBytes(rndVal);\n            return rndVal[0];\n        default:\n            return 0;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/sensors/dummydevices/LPS25HDummyDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices;\n\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.PRESS_OUT_H;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.PRESS_OUT_L;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.PRESS_OUT_XL;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.TEMP_OUT_H;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.TEMP_OUT_L;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.WHO_AM_I;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LPS25H.WHO_AM_I_ID;\n\npublic class LPS25HDummyDevice extends DummyDevice {\n\n    public static final int ID = 1;\n\n    @Override\n    public int read() {\n        switch (register) {\n        case WHO_AM_I:\n            return WHO_AM_I_ID;\n        case PRESS_OUT_L:   // we can return any value, returning the same for the simplicity\n        case PRESS_OUT_H:\n        case PRESS_OUT_XL:\n        case TEMP_OUT_L:\n        case TEMP_OUT_H:\n            return register;\n        default:\n            return 0;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/sensors/dummydevices/LSM9DS1TAccDummyyDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices;\n\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.CTRL_REG1_G;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.CTRL_REG6_XL;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_X_H_G;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_X_H_XL;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_X_L_G;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_X_L_XL;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Y_H_G;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Y_H_XL;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Y_L_G;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Y_L_XL;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Z_H_G;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Z_H_XL;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Z_L_G;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Z_L_XL;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.WHO_AM_I_AG_ID;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.WHO_AM_I_XG;\n\npublic class LSM9DS1TAccDummyyDevice extends DummyDevice {\n\n    public static final int ID = 3;\n\n    @Override\n    public int read() {\n        switch (register) {\n        case WHO_AM_I_XG:\n            return WHO_AM_I_AG_ID;\n        case CTRL_REG1_G:  // we can return any value, returning the same for the simplicity\n        case CTRL_REG6_XL:\n            return register;\n        case OUT_X_L_XL:\n        case OUT_Y_L_XL:\n        case OUT_Z_L_XL:\n        case OUT_X_L_G:\n        case OUT_Y_L_G:\n        case OUT_Z_L_G:\n            return -10;\n        case OUT_X_H_XL:\n        case OUT_Y_H_XL:\n        case OUT_Z_H_XL:\n        case OUT_X_H_G:\n        case OUT_Y_H_G:\n        case OUT_Z_H_G:\n            return 10;\n        default:\n            return 0;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/java/org/eclipse/kura/raspberrypi/sensehat/sensors/dummydevices/LSM9DS1TMagDummyyDevice.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.raspberrypi.sensehat.sensors.dummydevices;\n\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.CTRL_REG2_M;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_X_H_M;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_X_L_M;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Y_H_M;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Y_L_M;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Z_H_M;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.OUT_Z_L_M;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.WHO_AM_I_M;\nimport static org.eclipse.kura.raspberrypi.sensehat.sensors.LSM9DS1.WHO_AM_I_M_ID;\n\npublic class LSM9DS1TMagDummyyDevice extends DummyDevice {\n\n    public static final int ID = 4;\n\n    @Override\n    public int read() {\n        switch (register) {\n        case WHO_AM_I_M:\n            return WHO_AM_I_M_ID;\n        case CTRL_REG2_M:\n            return register;\n        case OUT_X_L_M:\n        case OUT_Y_L_M:\n        case OUT_Z_L_M:\n            return -10;\n        case OUT_X_H_M:\n        case OUT_Y_H_M:\n        case OUT_Z_H_M:\n            return 10;\n        default:\n            return 0;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.raspberrypi.sensehat.test/src/test/resources/test-sensehat_text.pbm",
    "content": "1111111111111111111111111111111111111111111011111110111110000011111011\n1111101111111011111110111111101111111011111110111111010111111011111000\n0011111011111101011110111111110111111110111111110111111110111111111111\n1111110100000111111111111111111111111111110001111111111111000111111111\n1101011100000001110101110000000111010111101101111010101100000001101010\n1111011011111111110111110110111011110101111110111111101111110101111011\n1011011111011111111110000011010111010110110101110101100000111111111101\n1110110000000101111111111111110111101100111101010111010110110101110011\n1011110101111101011101010110100110011101110011111101011111011011000000\n0111011111101100010111010101110101011101011000110110000111011010110110\n1101011011011001111111111101111111010000110111110101111110011001001101\n1011010110110101101101100100111111001101101101011011011010110111000011\n1111111100111111001111111111111111111111110101111101011111010111110101\n1111010111111111110111110110111011110001111111111111111111110001111011\n1011011111011111111100000011111011011110110111101101000000110000000101\n1011010110110101101101100100111000001101111101011111010111110110111011\n0000000101111101011111011011101111000111000000010110110101101101011011\n0101111101000000011110110111101101111011011111110110000011011111010110\n1101011011010000101100000001111011111110111111101111000000011111111101\n1111010000000101111101111111111011111101111111011111011000000111111101\n0000000111101111110101111011101101111101000000010111111101111111011111\n1101111111000000011111101111100111111110110000000100000001111101111110\n1111110111110000000110000011011111010111110101111101100000110000000111\n1011011110110111101101111100111000001101111101010111011011110101000011\n0000000111101101110011011010110101110011011100110110110101101101011011\n0110011101111111011111110100000001111111011111110110000001011111110111\n1111011111111000000111000001101111110111111110111111110000010000000110\n1111111100111110111111000000010011100111010111111011111101011100111001\n1111100111110111000011111111011111111001001111010101110101101101011101\n0101111001101111110101011101010111010101110000111110000001011011110111\n0111011101111000111110001111011101110111011101110111101111111000111101\n1101110111011101101111000000011000111101010111010101110101011111001111\n1111111111101111000000111110110111111011111011110101011101010111010101\n1110000111000000011110111111110111111101110000111111111111011101110000\n0101011111111111111110111111011111110111111110000101111111111111111100\n0000011101111110101111011101111111111101111101000000010111111111111111\n0000011111110111000011111111011100001111000001111110111111110111111101\n1100001111100011110111011101110111011101111000111100000111110101111101\n0111110101111110111111101111110101111101011111010111000001111111111100\n0001111110111111110111111101110110111101010111010101110101011110110111\n1111111111110111100000110111011110111111100001110111111101111111101111\n1100000111110001111011111101111111101111111100011110000111011111111001\n1111011111111000011101110111101101111000111101101111011101110111011101\n1011111001111111011111111001110111011100110111010101110110011101110111\n1111101111111101010111011110110111110011111111110101111110011111111111\n1111111111111111110101001110010011111111111111111111111111100100111001\n0011111111111111111111111111111111110000000111111111111111111001101101\n1011010000110101111101100000111011100111011001111011110011011100111011\n1111111100000001011111010111110111111111100100110110110101010101101110\n1101011111011111110111111101111111011111110111111111111111111101011111\n1001111111111111111111111111011111010111110100000001111111111111101111\n1101111110111111011111101111111110111111110111111001111110111111110111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111111111111111111111111111111111111111111111111111111111111111\n1111111111"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.cloudconnection.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.cloudconnection.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: com.google.gson;version=\"2.9.0\",\n org.eclipse.kura.core.testutil.requesthandler;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.25\"\nFragment-Host: org.eclipse.kura.rest.cloudconnection.provider\nRequire-Bundle: org.eclipse.kura.http.server.manager;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java\nbin.includes = META-INF/,\\\n               .\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n        Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.rest.cloudconnection.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                        <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/test/CloudConnectionEndpointsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.rest.cloudconnection.provider.test;\n\nimport static org.junit.Assert.fail;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Optional;\nimport java.util.Scanner;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.CloudConnectionConstants;\nimport org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudConnectionFactoryPidAndCloudEndpointPid;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudEndpointPidRequest;\nimport org.eclipse.kura.internal.rest.cloudconnection.provider.dto.PidAndFactoryPidAndCloudEndpointPid;\nimport org.eclipse.kura.rest.configuration.api.PidAndFactoryPid;\nimport org.eclipse.kura.rest.configuration.api.PidSet;\nimport org.eclipse.kura.rest.configuration.api.UpdateComponentConfigurationRequest;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\n\nimport com.google.gson.Gson;\n\n@RunWith(Parameterized.class)\npublic class CloudConnectionEndpointsTest extends AbstractRequestHandlerTest {\n\n    private static final String CLOUD_ENDPOINT_INSTANCE_TEST = \"org.eclipse.kura.cloud.CloudService-test\";\n\n    private static final String MQTT_APP_ID = \"CLD-V1\";\n\n    private static final String METHOD_SPEC_GET = \"GET\";\n    private static final String METHOD_SPEC_POST = \"POST\";\n    private static final String METHOD_SPEC_DELETE = \"DELETE\";\n    private static final String MQTT_METHOD_SPEC_DEL = \"DEL\";\n    private static final String METHOD_SPEC_PUT = \"PUT\";\n    private static final String REST_APP_ID = \"cloudconnection/v1\";\n\n    private static CloudConnectionFactory cloudConnectionFactory;\n    private static ConfigurationService configurationService;\n\n    private Gson gson = new Gson();\n\n    private CloudConnectionFactoryPidAndCloudEndpointPid cloudConnectionFactoryPidAndCloudEndpointPid;\n    private PidAndFactoryPidAndCloudEndpointPid pidAndFactoryPidAndCloudEndpointPid;\n    private PidAndFactoryPid pidAndFactoryPid;\n    private PidSet pidSet;\n\n    private UpdateComponentConfigurationRequest updateComponentConfigurationRequest;\n    private CloudEndpointPidRequest cloudEndpointPidRequest;\n\n    private static final String EXPECTED_GET_STACK_COMPONENT_PIDS_RESPONSE = new Scanner(\n            CloudConnectionEndpointsTest.class.getResourceAsStream(\"/getStackComponentPidsResponse.json\"), \"UTF-8\")\n                    .useDelimiter(\"\\\\A\").next().replace(\" \", \"\");\n\n    private static final String UPDATE_COMPONENT_CONFIGURATION_REQUEST = new Scanner(\n            CloudConnectionEndpointsTest.class.getResourceAsStream(\"/updateConfigurationRequest.json\"), \"UTF-8\")\n                    .useDelimiter(\"\\\\A\").next().replace(\" \", \"\");\n\n    private static final String EXPECTED_IS_ENDPOINT_CONNECTED_RESPONSE = new Scanner(\n            CloudConnectionEndpointsTest.class.getResourceAsStream(\"/isConnectedResponse.json\"), \"UTF-8\")\n                    .useDelimiter(\"\\\\A\").next().replace(\" \", \"\");\n\n    @Parameterized.Parameters(name = \"{0}\")\n    public static Collection<Transport> transports() {\n        return Arrays.asList(new MqttTransport(MQTT_APP_ID), new RestTransport(REST_APP_ID));\n    }\n\n    public CloudConnectionEndpointsTest(Transport transport) {\n        super(transport);\n\n    }\n\n    @BeforeClass\n    public static void setup() {\n        try {\n            configurationService = ServiceUtil.trackService(ConfigurationService.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n            cloudConnectionFactory = ServiceUtil.trackService(CloudConnectionFactory.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n            cloudConnectionFactory.createConfiguration(CLOUD_ENDPOINT_INSTANCE_TEST);\n        } catch (Exception e) {\n            fail(\"Unable to create the test CloudEndpoint\");\n        }\n    }\n\n    @Test\n    public void shouldGetCloudComponentInstances() {\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/instances\");\n\n        thenRequestSucceeds();\n        thenResponseBodyIsNotEmpty();\n    }\n\n    @Test\n    public void shouldGetStackComponentPids() {\n        givenCloudConnectionFactoryPidAndCloudEndpointPid(\"org.eclipse.kura.cloud.CloudService\",\n                CLOUD_ENDPOINT_INSTANCE_TEST);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/cloudEndpoint/stackComponentPids\",\n                gson.toJson(this.cloudConnectionFactoryPidAndCloudEndpointPid));\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_GET_STACK_COMPONENT_PIDS_RESPONSE);\n    }\n\n    @Test\n    public void shouldCreateCloudEndpoint() {\n        givenCloudConnectionFactoryPidAndCloudEndpointPid(\"org.eclipse.kura.cloud.CloudService\",\n                \"org.eclipse.kura.cloud.CloudService-createTest\" + this.getTransportType());\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/cloudEndpoint\",\n                gson.toJson(this.cloudConnectionFactoryPidAndCloudEndpointPid));\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldDeleteCloudEndpoint() throws InterruptedException, ExecutionException, TimeoutException {\n        givenNewCloudEndpoint(\"org.eclipse.kura.cloud.CloudService-toDelete\" + this.getTransportType());\n        givenCloudConnectionFactoryPidAndCloudEndpointPid(\"org.eclipse.kura.cloud.CloudService\",\n                \"org.eclipse.kura.cloud.CloudService-toDelete\" + this.getTransportType());\n        givenExistingCloudEndpoint(\"org.eclipse.kura.cloud.CloudService\",\n                \"org.eclipse.kura.cloud.CloudService-toDelete\" + this.getTransportType());\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/cloudEndpoint\",\n                gson.toJson(this.cloudConnectionFactoryPidAndCloudEndpointPid));\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldGetCloudComponentFactories() {\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/factories\");\n\n        thenRequestSucceeds();\n        thenResponseBodyIsNotEmpty();\n    }\n\n    @Test\n    public void shouldCreatePublisherInstance() {\n        givenPidAndFactoryPidAndCloudEndpointPid(\"test-pub-\" + this.getTransportType(),\n                \"org.eclipse.kura.cloud.publisher.CloudPublisher\", CLOUD_ENDPOINT_INSTANCE_TEST);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/pubSub\",\n                gson.toJson(this.pidAndFactoryPidAndCloudEndpointPid));\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldCreateSubscriberInstance() {\n        givenPidAndFactoryPidAndCloudEndpointPid(\"test-sub-\" + this.getTransportType(),\n                \"org.eclipse.kura.cloud.subscriber.CloudSubscriber\", CLOUD_ENDPOINT_INSTANCE_TEST);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/pubSub\",\n                gson.toJson(this.pidAndFactoryPidAndCloudEndpointPid));\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldDeletePublisherInstance()\n            throws KuraException, InterruptedException, ExecutionException, TimeoutException {\n        givenPubSubInstance(\"pub-to-delete-\" + this.getTransportType(),\n                \"org.eclipse.kura.cloud.publisher.CloudPublisher\", CLOUD_ENDPOINT_INSTANCE_TEST);\n        givenPid(\"pub-to-delete-\" + this.getTransportType());\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/pubSub\",\n                gson.toJson(this.pidAndFactoryPid));\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldDeleteSubscriberInstance()\n            throws KuraException, InterruptedException, ExecutionException, TimeoutException {\n        givenPubSubInstance(\"sub-to-delete-\" + this.getTransportType(),\n                \"org.eclipse.kura.cloud.subscriber.CloudSubscriber\", CLOUD_ENDPOINT_INSTANCE_TEST);\n        givenPid(\"sub-to-delete-\" + this.getTransportType());\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/pubSub\",\n                gson.toJson(this.pidAndFactoryPid));\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldGetConfigurations() {\n        givenPidSet(CLOUD_ENDPOINT_INSTANCE_TEST, \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-test\", //\n                \"org.eclipse.kura.data.DataService-test\");\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/configurations\", gson.toJson(this.pidSet));\n\n        thenRequestSucceeds();\n        thenResponseBodyIsNotEmpty();\n    }\n\n    @Test\n    public void shouldUpdateStackComponentConfigurations() {\n\n        givenUpdateComponentConfigurationRequest(UPDATE_COMPONENT_CONFIGURATION_REQUEST);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_PUT), \"/configurations\",\n                gson.toJson(this.updateComponentConfigurationRequest));\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldConnectEndpoint() {\n        givenCloudEndpointPidRequest(CLOUD_ENDPOINT_INSTANCE_TEST);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/cloudEndpoint/connect\",\n                gson.toJson(this.cloudEndpointPidRequest));\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldDisconnectEndpoint() {\n        givenCloudEndpointPidRequest(CLOUD_ENDPOINT_INSTANCE_TEST);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/cloudEndpoint/disconnect\",\n                gson.toJson(this.cloudEndpointPidRequest));\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldCheckEndpointStatus() {\n        givenCloudEndpointPidRequest(CLOUD_ENDPOINT_INSTANCE_TEST);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/cloudEndpoint/isConnected\",\n                gson.toJson(this.cloudEndpointPidRequest));\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_IS_ENDPOINT_CONNECTED_RESPONSE);\n    }\n\n    private void givenCloudEndpointPidRequest(String pid) {\n        this.cloudEndpointPidRequest = new CloudEndpointPidRequest(pid);\n    }\n\n    private void givenCloudConnectionFactoryPidAndCloudEndpointPid(String cloudConnectionFactoryPid,\n            String cloudEndpointPid) {\n        this.cloudConnectionFactoryPidAndCloudEndpointPid = new CloudConnectionFactoryPidAndCloudEndpointPid(\n                cloudConnectionFactoryPid, cloudEndpointPid);\n    }\n\n    private void givenUpdateComponentConfigurationRequest(String jsonFileContent) {\n        this.updateComponentConfigurationRequest = this.gson.fromJson(jsonFileContent,\n                UpdateComponentConfigurationRequest.class);\n\n    }\n\n    private void givenPidAndFactoryPidAndCloudEndpointPid(String pid, String factoryPid, String cloudEndpointPid) {\n        this.pidAndFactoryPidAndCloudEndpointPid = new PidAndFactoryPidAndCloudEndpointPid(pid, factoryPid,\n                cloudEndpointPid);\n    }\n\n    private void givenPid(String pid) {\n        this.pidAndFactoryPid = new PidAndFactoryPid(pid);\n    }\n\n    private void givenPidSet(String... pids) {\n        this.pidSet = new PidSet(new HashSet<String>(Arrays.asList(pids)));\n    }\n\n    private void givenNewCloudEndpoint(String cloudEndpointPid) {\n        try {\n            cloudConnectionFactory.createConfiguration(cloudEndpointPid);\n\n        } catch (KuraException e) {\n            e.printStackTrace();\n            fail(\"Unable to create the test CloudService\");\n        }\n    }\n\n    private void givenExistingCloudEndpoint(String cloudConnectionFactoryPid, String cloudEndpointPid)\n            throws InterruptedException, ExecutionException, TimeoutException {\n        CompletableFuture<Object> trackFuture = ServiceUtil.trackService(cloudConnectionFactoryPid,\n                Optional.of(String.format(\"(kura.service.pid=%s)\", cloudEndpointPid)));\n        trackFuture.get(5, TimeUnit.SECONDS);\n    }\n\n    private void givenPubSubInstance(String pid, String factoryPid, String cloudEndpointPid)\n            throws KuraException, InterruptedException, ExecutionException, TimeoutException {\n        configurationService.createFactoryConfiguration(factoryPid, pid, Collections.singletonMap(\n                CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), cloudEndpointPid), true);\n        CompletableFuture<Object> trackFuture = ServiceUtil.trackService(\n                \"org.eclipse.kura.configuration.ConfigurableComponent\",\n                Optional.of(String.format(\"(kura.service.pid=%s)\", pid)));\n        trackFuture.get(5, TimeUnit.SECONDS);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/getStackComponentPidsResponse.json",
    "content": "{\n    \"pids\": [\n        \"org.eclipse.kura.cloud.CloudService-test\",\n        \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-test\",\n        \"org.eclipse.kura.data.DataService-test\"\n    ]\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/isConnectedResponse.json",
    "content": "{\n    \"connected\": false\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/updateConfigurationRequest.json",
    "content": "{\n    \"configs\": [\n        {\n            \"pid\": \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-test\",\n            \"properties\": {\n                \"broker-url\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"mqtt://localhost:1883\"\n                },\n                \"topic.context.account-name\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"account-name-testX2\"\n                },\n                \"username\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"username\"\n                },\n                \"password\": {\n                    \"type\": \"PASSWORD\",\n                    \"value\": \"Placeholder\"\n                },\n                \"client-id\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"\"\n                },\n                \"keep-alive\": {\n                    \"type\": \"INTEGER\",\n                    \"value\": 30\n                },\n                \"timeout\": {\n                    \"type\": \"INTEGER\",\n                    \"value\": 20\n                },\n                \"clean-session\": {\n                    \"type\": \"BOOLEAN\",\n                    \"value\": true\n                },\n                \"lwt.topic\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"$EDC/#account-name/#client-id/MQTT/LWT\"\n                },\n                \"lwt.payload\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"\"\n                },\n                \"lwt.qos\": {\n                    \"type\": \"INTEGER\",\n                    \"value\": 0\n                },\n                \"lwt.retain\": {\n                    \"type\": \"BOOLEAN\",\n                    \"value\": false\n                },\n                \"in-flight.persistence\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"memory\"\n                },\n                \"protocol-version\": {\n                    \"type\": \"INTEGER\",\n                    \"value\": 4\n                },\n                \"SslManagerService.target\": {\n                    \"type\": \"STRING\",\n                    \"value\": \"(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)\"\n                }\n            }\n        }\n    ],\n    \"takeSnapshot\" : true\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.configuration.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.configuration.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.configuration.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: com.eclipsesource.json;version=\"0.9.5\",\n org.apache.commons.io;version=\"2.4.0\",\n org.eclipse.kura;version=\"1.6.0\",\n org.eclipse.kura.configuration,\n org.eclipse.kura.configuration.metatype;version=\"1.1.0\",\n org.eclipse.kura.core.testutil.json;version=\"1.0.0\",\n org.eclipse.kura.core.testutil.requesthandler;version=\"1.0.0\",\n org.eclipse.kura.core.util;version=\"1.3.0\",\n org.eclipse.kura.crypto;version=\"1.3.0\",\n org.eclipse.kura.data;version=\"1.1.2\",\n org.eclipse.kura.data.transport.listener;version=\"1.0.1\",\n org.eclipse.kura.marshalling;version=\"1.0.0\",\n org.eclipse.kura.message;version=\"1.4.0\",\n org.eclipse.kura.util.wire.test;version=\"1.1.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.25\"\nRequire-Bundle: org.eclipse.kura.rest.configuration.provider;bundle-version=\"1.0.0\",\n org.eclipse.kura.http.server.manager;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.configuration.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.configuration.provider.test/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.configuration.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2021 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               ."
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.configuration.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.rest.configuration.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.configuration.provider.test/src/main/java/org/eclipse/kura/rest/configuration/provider/test/ConfigurationRestServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.configuration.provider.test;\n\nimport static java.util.Collections.singletonMap;\nimport static org.eclipse.kura.core.testutil.json.JsonProjection.self;\nimport static org.eclipse.kura.rest.configuration.provider.test.ConfigurationUtil.adBuilder;\nimport static org.eclipse.kura.rest.configuration.provider.test.ConfigurationUtil.configurationBuilder;\nimport static org.eclipse.kura.rest.configuration.provider.test.ConfigurationUtil.ocdBuilder;\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.fail;\nimport static org.mockito.ArgumentMatchers.anyLong;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.doNothing;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.when;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.TreeSet;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.Icon;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.configuration.metatype.Scalar;\nimport org.eclipse.kura.core.testutil.json.JsonProjection;\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.util.wire.test.WireTestUtil;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mockito;\nimport org.mockito.stubbing.Answer;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonValue;\n\n@RunWith(Parameterized.class)\npublic class ConfigurationRestServiceTest extends AbstractRequestHandlerTest {\n\n    private char[] encryptedPassword;\n\n    @Test\n    public void shouldSupportGetSnapshots() throws KuraException {\n        givenMockGetSnapshotsReturnEmpty();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/snapshots\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"ids\\\":[]}\");\n    }\n\n    @Test\n    public void testListSnapshots() throws KuraException {\n        givenMockGetSnapshotsReturnSome(5);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/snapshots\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"ids\\\":[10000,10001,10002,10003,10004]}\");\n    }\n\n    @Test\n    public void testListSnapshotsKuraException() throws KuraException {\n        givenMockGetSnapshotsReturnException();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/snapshots\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void testListFactoryComponentsPidsEmpty() {\n        givenMockGetFactoryComponentPidsReturnEmpty();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/factoryComponents\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"pids\\\":[]}\");\n    }\n\n    @Test\n    public void testListFactoryComponentsPids() throws KuraException {\n        givenMockGetFactoryComponentPidsReturnSome(5);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/factoryComponents\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"pids\\\":[\\\"pid0\\\",\\\"pid1\\\",\\\"pid2\\\",\\\"pid3\\\",\\\"pid4\\\"]}\");\n    }\n\n    @Test\n    public void testListConfigurableComponentsPidsEmpty() {\n        givenMockGetConfigurableComponentPidsReturnEmpty();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"pids\\\":[]}\");\n    }\n\n    @Test\n    public void testListConfigurableComponentsPids() throws KuraException {\n        givenMockGetConfigurableComponentPidsReturnSome(5);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"pids\\\":[\\\"pid0\\\",\\\"pid1\\\",\\\"pid2\\\",\\\"pid3\\\",\\\"pid4\\\"]}\");\n    }\n\n    @Test\n    public void testListComponentConfigurationsException() throws KuraException {\n        givenMockGetComponentConfigurationsReturnException();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void testListComponentConfigurationsEmpty() throws KuraException {\n        givenMockGetComponentConfigurationsReturnEmpty();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"configs\\\":[]}\");\n    }\n\n    @Test\n    public void testListComponentConfigurations() throws KuraException {\n        givenMockGetComponentConfigurationsReturnSome(5);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"pid0\\\"},\" + \"{\\\"pid\\\":\\\"pid1\\\"},\"\n                + \"{\\\"pid\\\":\\\"pid2\\\"},\" + \"{\\\"pid\\\":\\\"pid3\\\"},\" + \"{\\\"pid\\\":\\\"pid4\\\"}]\" + \"}\");\n    }\n\n    @Test\n    public void testGetBooleanPropertyTrue() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.BOOLEAN, true);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"BOOLEAN\"));\n        thenTestPropertyValueIs(Json.value(true));\n    }\n\n    @Test\n    public void testGetBooleanPropertyFalse() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.BOOLEAN, false);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"BOOLEAN\"));\n        thenTestPropertyValueIs(Json.value(false));\n    }\n\n    @Test\n    public void testGetByteProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.BYTE, (byte) 12);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"BYTE\"));\n        thenTestPropertyValueIs(Json.value(12));\n    }\n\n    @Test\n    public void testGetCharProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.CHAR, 'f');\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"CHAR\"));\n        thenTestPropertyValueIs(Json.value(\"f\"));\n    }\n\n    @Test\n    public void testGetDoubleProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.DOUBLE, 123.1d);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"DOUBLE\"));\n        thenTestPropertyValueIs(Json.value(123.1d));\n    }\n\n    @Test\n    public void testGetFloatProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.FLOAT, 123.1f);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"FLOAT\"));\n        thenTestPropertyValueIs(Json.value(123.1d));\n    }\n\n    @Test\n    public void testGetIntegerProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.INTEGER, 123);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"INTEGER\"));\n        thenTestPropertyValueIs(Json.value(123));\n    }\n\n    @Test\n    public void testGetShortProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.SHORT, (short) 123);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"SHORT\"));\n        thenTestPropertyValueIs(Json.value(123));\n    }\n\n    @Test\n    public void testGetLongProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.LONG, 123L);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"LONG\"));\n        thenTestPropertyValueIs(Json.value(123));\n    }\n\n    @Test\n    public void testReturnPlaceholderInsteadOfEncryptedPassword() throws KuraException {\n        givenEncryptedPassword(\"foobar\");\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.PASSWORD, new Password(this.encryptedPassword));\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"PASSWORD\"));\n        thenTestPropertyValueIs(Json.value(\"placeholder\"));\n    }\n\n    @Test\n    public void testReturnNoValueForMissingPasswordProperty() throws KuraException {\n        givenEncryptedPassword(\"foobar\");\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.PASSWORD, null);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyIsMissing();\n    }\n\n    @Test\n    public void testGetSnapshotReturnsUnencryptedPassword() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.PASSWORD, new Password(\"foobar\".toCharArray()));\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/snapshots/byId\", \"{\\\"id\\\":10000}\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"PASSWORD\"));\n        thenTestPropertyValueIs(Json.value(\"foobar\"));\n    }\n\n    private void givenEncryptedPassword(final String password) throws KuraException {\n        this.encryptedPassword = this.cryptoService.encryptAes(password.toCharArray());\n    }\n\n    @Test\n    public void testGetNullProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.STRING, null);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyIsMissing();\n    }\n\n    @Test\n    public void testGetNullsInArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.STRING, new String[] { \"foo\", null, null });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"STRING\"));\n        thenTestPropertyValueIs(Json.array(\"foo\", null, null));\n    }\n\n    @Test\n    public void testGetStringProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.STRING, \"test string\");\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"STRING\"));\n        thenTestPropertyValueIs(Json.value(\"test string\"));\n    }\n\n    @Test\n    public void testGetBooleanArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.BOOLEAN, new Boolean[] { true, false, true });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"BOOLEAN\"));\n        thenTestPropertyValueIs(Json.array(true, false, true));\n    }\n\n    @Test\n    public void testGetByteArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.BYTE, new Byte[] { 1, 2, 3 });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"BYTE\"));\n        thenTestPropertyValueIs(Json.array(1, 2, 3));\n    }\n\n    @Test\n    public void testGetCharArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.CHAR, new Character[] { 'a', 'b', 'c' });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"CHAR\"));\n        thenTestPropertyValueIs(Json.array(\"a\", \"b\", \"c\"));\n    }\n\n    @Test\n    public void testGetDoubleArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.DOUBLE, new Double[] { 1.0d, 2.0d, 3.0d });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"DOUBLE\"));\n        thenTestPropertyValueIs(Json.parse(\"[1.0,2.0,3.0]\"));\n    }\n\n    @Test\n    public void testGetFloatArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.FLOAT, new Float[] { 1.0f, 2.0f, 3.0f });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"FLOAT\"));\n        thenTestPropertyValueIs(Json.parse(\"[1.0,2.0,3.0]\"));\n    }\n\n    @Test\n    public void testGetIntegerArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.INTEGER, new Integer[] { 1, 2, 3 });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"INTEGER\"));\n        thenTestPropertyValueIs(Json.array(1, 2, 3));\n    }\n\n    @Test\n    public void testGetShortArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.SHORT, new Short[] { 1, 2, 3 });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"SHORT\"));\n        thenTestPropertyValueIs(Json.array(1, 2, 3));\n    }\n\n    @Test\n    public void testGetLongArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.LONG, new Long[] { 1L, 2L, 3L });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"LONG\"));\n        thenTestPropertyValueIs(Json.array(1, 2, 3));\n    }\n\n    @Test\n    public void testGetPasswordArrayProperty() throws KuraException {\n\n        givenEncryptedPassword(\"foobar\");\n\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.PASSWORD,\n                new Password[] { new Password(this.encryptedPassword) });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"PASSWORD\"));\n        thenTestPropertyValueIs(Json.array(\"placeholder\"));\n    }\n\n    @Test\n    public void testGetStringArrayProperty() throws KuraException {\n        givenATestConfigurationPropertyWithAdTypeAndValue(Scalar.STRING, new String[] { \"foo\", \"bar\", \"baz\" });\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/configurableComponents/configurations\");\n\n        thenRequestSucceeds();\n        thenTestPropertyTypeIs(Json.value(\"STRING\"));\n        thenTestPropertyValueIs(Json.array(\"foo\", \"bar\", \"baz\"));\n    }\n\n    @Test\n    public void testUpdateConfigurationBooleanPropertyTrue() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"value\\\":true}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", true);\n    }\n\n    @Test\n    public void testUpdateConfigurationBooleanPropertyFalse() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"value\\\":false}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", false);\n    }\n\n    @Test\n    public void testUpdateByteProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"BYTE\\\",\\\"value\\\":15}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", (byte) 15);\n    }\n\n    @Test\n    public void testUpdateCharProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"CHAR\\\",\\\"value\\\":\\\"a\\\"}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", 'a');\n    }\n\n    @Test\n    public void testUpdateDoubleProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"DOUBLE\\\",\\\"value\\\":2.0}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", 2.0d);\n    }\n\n    @Test\n    public void testUpdateFloatProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"FLOAT\\\",\\\"value\\\":2.0}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", 2.0f);\n    }\n\n    @Test\n    public void testUpdateIntegerPropert() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"value\\\":123}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", 123);\n    }\n\n    @Test\n    public void testUpdateShortProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"SHORT\\\",\\\"value\\\":123}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", (short) 123);\n    }\n\n    @Test\n    public void testUpdateLongProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"LONG\\\",\\\"value\\\":123}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", 123L);\n    }\n\n    @Test\n    public void testUpdatePasswordProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"PASSWORD\\\",\\\"value\\\":\\\"foobar\\\"}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsPassword(\"foo\", \"testProp\", \"foobar\");\n    }\n\n    @Test\n    public void testUpdateStringProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"STRING\\\",\\\"value\\\":\\\"test string\\\"}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", \"test string\");\n    }\n\n    @Test\n    public void testUpdateBooleanArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"value\\\":[false,true,false]}}\" + \"}\"\n                        + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new Boolean[] { false, true, false });\n    }\n\n    @Test\n    public void testUpdateByteArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"BYTE\\\",\\\"value\\\":[15,12]}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new Byte[] { 15, 12 });\n    }\n\n    @Test\n    public void testUpdateCharArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"CHAR\\\",\\\"value\\\":[\\\"a\\\",\\\"b\\\",\\\"c\\\"]}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new Character[] { 'a', 'b', 'c' });\n    }\n\n    @Test\n    public void testUpdateDoubleArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"DOUBLE\\\",\\\"value\\\":[2.0,3.0]}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new Double[] { 2.0d, 3.0d });\n    }\n\n    @Test\n    public void testUpdateFloatArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"FLOAT\\\",\\\"value\\\":[2.0,4.0]}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new Float[] { 2.0f, 4.0f });\n    }\n\n    @Test\n    public void testUpdateIntegerArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"value\\\":[1,2,3]}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new Integer[] { 1, 2, 3 });\n    }\n\n    @Test\n    public void testUpdateShortArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"SHORT\\\",\\\"value\\\":[1,2,3]}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new Short[] { 1, 2, 3 });\n    }\n\n    @Test\n    public void testUpdateLongArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"LONG\\\",\\\"value\\\":[1,2,3]}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new Long[] { 1L, 2L, 3L });\n    }\n\n    @Test\n    public void testUpdatePasswordArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"PASSWORD\\\",\\\"value\\\":[\\\"foobar\\\",\\\"a\\\"]}}\" + \"}\"\n                        + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsPasswords(\"foo\", \"testProp\", \"foobar\", \"a\");\n    }\n\n    @Test\n    public void testUpdateStringArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"STRING\\\",\\\"value\\\":[\\\"test string\\\",\\\"foo\\\"]}}\" + \"}\"\n                        + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new String[] { \"test string\", \"foo\" });\n    }\n\n    @Test\n    public void testUpdateNullProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\"\n                + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"STRING\\\"},\\\"otherProp\\\":{\\\"type\\\":\\\"STRING\\\",\\\"value\\\":null}}\"\n                + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContains(\"foo\", \"testProp\", null);\n        thenReceivedPropertiesForPidContains(\"foo\", \"otherProp\", null);\n    }\n\n    @Test\n    public void testUpdateNullsInArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"STRING\\\",value:[null,\\\"foo\\\",null]}}\" + \"}\" + \"]}\");\n\n        thenRequestSucceeds();\n        thenReceivedPropertiesForPidContainsArray(\"foo\", \"testProp\", new String[] { null, \"foo\", null });\n    }\n\n    @Test\n    public void testUpdateTypeMismatchNumericProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"value\\\":\\\"foo\\\"}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateTypeMismatchStringProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"STRING\\\",\\\"value\\\":12}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateTypeMismatchPasswordProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"PASSWORD\\\",\\\"value\\\":12}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateTypeMismatchCharProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"CHAR\\\",\\\"value\\\":12}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateInvalidLengthCharProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"CHAR\\\",\\\"value\\\":\\\"foo\\\"}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateTypeMismatchNumericArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"value\\\":[\\\"foo\\\"]}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateTypeMismatchStringArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"STRING\\\",\\\"value\\\":[12]}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateTypeMismatchPasswordArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"PASSWORD\\\",\\\"value\\\":[12]}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateTypeMismatchCharArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\", \"{\\\"configs\\\":[\"\n                + \"{\\\"pid\\\":\\\"foo\\\",\" + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"CHAR\\\",\\\"value\\\":[12]}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateInvalidLengthCharArrayProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"CHAR\\\",\\\"value\\\":[\\\"foo\\\"]}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testUpdateTypeMismatchBooleanProperty() {\n        whenRequestIsPerformed(new MethodSpec(\"PUT\"), \"/configurableComponents/configurations/_update\",\n                \"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"foo\\\",\"\n                        + \"properties: {\\\"testProp\\\":{\\\"type\\\":\\\"BOOLEAN\\\",\\\"value\\\":\\\"foo\\\"}}\" + \"}\" + \"]}\");\n\n        thenResponseCodeIs(400);\n        thenResponseElementExists(self().field(\"message\"));\n    }\n\n    @Test\n    public void testListComponentConfigurationsByPidException() throws KuraException {\n        givenMockGetComponentConfigurationPidReturnException();\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void testListComponentConfigurationsByPidEmpty() throws KuraException {\n        givenMockGetComponentConfigurationPidReturnEmpty();\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"configs\\\":[]}\");\n    }\n\n    @Test\n    public void testListComponentConfigurationsByPid() throws KuraException {\n        givenMockGetComponentConfigurationPidReturnSome(5);\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"pid1\\\",\\\"pid3\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"pid1\\\"},\" + \"{\\\"pid\\\":\\\"pid3\\\"}]\" + \"}\");\n    }\n\n    @Test\n    public void testListDefaultComponentConfigurationException() throws KuraException {\n        givenMockGetDefaultComponentConfigurationReturnException();\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid/_default\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"configs\\\":[]}\");\n    }\n\n    @Test\n    public void testListDefaultComponentConfiguration() throws KuraException {\n        givenMockGetDefaultComponentConfigurationReturnOne(\"test\");\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid/_default\",\n                \"{\\\"pids\\\":[\\\"test\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\n                \"{\\\"configs\\\":[{\\\"pid\\\":\\\"test\\\",\\\"definition\\\":{\\\"name\\\":\\\"test\\\",\\\"id\\\":\\\"test\\\"}}]}\");\n    }\n\n    @Test\n    public void testGetSnapshotException() throws KuraException {\n        givenMockGetSnapshotsReturnSome(5);\n        givenMockGetSnapshotReturnException(10000);\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/snapshots/byId\", \"{\\\"id\\\":10000}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void testGetSnapshot() throws KuraException {\n        givenMockGetSnapshotsReturnSome(5);\n        givenMockGetSnapshotReturnSome(10000, 5);\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/snapshots/byId\", \"{\\\"id\\\":10000}\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"configs\\\":[\" + \"{\\\"pid\\\":\\\"pid0\\\"},\" + \"{\\\"pid\\\":\\\"pid1\\\"},\"\n                + \"{\\\"pid\\\":\\\"pid2\\\"},\" + \"{\\\"pid\\\":\\\"pid3\\\"},\" + \"{\\\"pid\\\":\\\"pid4\\\"}]\" + \"}\");\n    }\n\n    @Test\n    public void testGetSnapshotNotFound() throws KuraException {\n        givenMockGetSnapshotsReturnSome(5);\n        givenMockGetSnapshotReturnSome(10000, 5);\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/snapshots/byId\", \"{\\\"id\\\":12346}\");\n\n        thenResponseCodeIs(404);\n    }\n\n    @Test\n    public void testTakeSnapshotException() throws KuraException {\n        givenMockSnapshotReturnException();\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\", \"EXEC\"), \"/snapshots/_write\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void testTakeSnapshot() throws KuraException {\n        givenMockSnapshotReturnOne(12345);\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\", \"EXEC\"), \"/snapshots/_write\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"id\\\":12345}\");\n    }\n\n    @Test\n    public void testRollbackException() throws KuraException {\n        givenMockRollbackReturnException();\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\", \"EXEC\"), \"/snapshots/_rollback\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void testRollback() throws KuraException {\n        givenMockRollbackReturnOne(11111);\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\", \"EXEC\"), \"/snapshots/_rollback\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"id\\\":11111}\");\n    }\n\n    @Test\n    public void testRollbackToIdException() throws KuraException {\n        givenMockRollbackReturnException(12345);\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\", \"EXEC\"), \"/snapshots/byId/_rollback\", \"{\\\"id\\\":12345}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void testRollbackToId() throws KuraException {\n        givenMockRollbackReturnNothing(12345);\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\", \"EXEC\"), \"/snapshots/byId/_rollback\", \"{\\\"id\\\":12345}\");\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n    }\n\n    @Test\n    public void testADIdAndType() throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.BOOLEAN).build()) //\n                                .build()) //\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(Json.value(\"fooAdName\"),\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"id\"));\n        thenResponseElementIs(Json.value(\"BOOLEAN\"),\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"type\"));\n    }\n\n    @Test\n    public void testADShouldNotSerializeFieldsIfUnset() throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.BOOLEAN).build()) //\n                                .build()) //\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(null,\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"name\"));\n        thenResponseElementIs(null,\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"description\"));\n        thenResponseElementIs(null,\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"min\"));\n        thenResponseElementIs(null,\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"max\"));\n        thenResponseElementIs(null, self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0)\n                .field(\"defaultValue\"));\n        thenResponseElementIs(null, self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0)\n                .field(\"defaultValue\"));\n        thenResponseElementIs(null,\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"option\"));\n    }\n\n    @Test\n    public void testADName() throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.BOOLEAN).withName(\"testName\").build()) //\n                                .build()) //\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(Json.value(\"testName\"),\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"name\"));\n    }\n\n    @Test\n    public void testADDescription() throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.BOOLEAN).withDescription(\"test description\")\n                                        .build()) //\n                                .build()) //\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(Json.value(\"test description\"),\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"description\"));\n    }\n\n    @Test\n    public void testADCardinality() throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.BOOLEAN).withCardinality(1).build()) //\n                                .build()) //\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(Json.value(1),\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"cardinality\"));\n    }\n\n    @Test\n    public void testADMin() throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.BOOLEAN).withMin(\"10\").build()) //\n                                .build()) //\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(Json.value(\"10\"),\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"min\"));\n    }\n\n    @Test\n    public void testADMax() throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.BOOLEAN).withMax(\"10\").build()) //\n                                .build()) //\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(Json.value(\"10\"),\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"max\"));\n    }\n\n    @Test\n    public void testADDefaultValue() throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.BOOLEAN).withDefault(\"true\").build()) //\n                                .build()) //\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(Json.value(\"true\"), self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\")\n                .arrayItem(0).field(\"defaultValue\"));\n    }\n\n    @Test\n    public void testADOption() throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.BOOLEAN) //\n                                        .withOption(null, \"foo\") //\n                                        .withOption(\"bar\", \"baz\") //\n                                        .build()) //\n                                .build()) //\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(Json.parse(\"[{\\\"value\\\":\\\"foo\\\"},{\\\"label\\\":\\\"bar\\\",\\\"value\\\":\\\"baz\\\"}]\"),\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"option\"));\n    }\n\n    @Test\n    public void testGetConfigurationByPid() throws KuraException {\n        givenEncryptedPassword(\"foobar\");\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.PASSWORD) //\n                                        .withOption(null, \"foo\") //\n                                        .withOption(\"pass\", \"baz\") //\n                                        .build()) //\n                                .build()) //\n                .withConfigurationProperties(\n                        singletonMap(\"testProp\", new Password[] { new Password(this.encryptedPassword) }))\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(Json.parse(\"{\\\"pid\\\":\\\"foo\\\",\\\"definition\\\":{\\\"ad\\\":[{\\\"option\\\":[{\\\"value\\\":\\\"foo\\\"},\"\n                + \"{\\\"label\\\":\\\"pass\\\",\\\"value\\\":\\\"baz\\\"}],\\\"id\\\":\\\"fooAdName\\\",\\\"type\\\":\\\"PASSWORD\\\",\"\n                + \"\\\"cardinality\\\":0,\\\"isRequired\\\":false}],\\\"id\\\":\\\"foo\\\"},\"\n                + \"\\\"properties\\\":{\\\"testProp\\\":{\\\"value\\\":[\\\"\" + \"placeholder\" + \"\\\"],\\\"type\\\":\\\"PASSWORD\\\"}}}\"),\n                self().field(\"configs\").arrayItem(0));\n    }\n\n    @Test\n    public void testGetConfigurationByPidDefault() throws KuraException {\n        givenEncryptedPassword(\"foobar\");\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"fooAdName\", Scalar.STRING) //\n                                        .withOption(null, \"foo\") //\n                                        .withOption(\"pass\", \"baz\") //\n                                        .withDefault(\"default\").build()) //\n                                .build()) //\n                .withConfigurationProperties(\n                        singletonMap(\"testProp\", new Password[] { new Password(this.encryptedPassword) }))\n                .build());\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), \"/configurableComponents/configurations/byPid/_default\",\n                \"{\\\"pids\\\":[\\\"foo\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseElementIs(\n                Json.parse(\"{\\\"pid\\\":\\\"foo\\\",\\\"definition\\\":{\\\"ad\\\":[{\\\"option\\\":[{\\\"value\\\":\\\"foo\\\"},\"\n                        + \"{\\\"label\\\":\\\"pass\\\",\\\"value\\\":\\\"baz\\\"}],\\\"id\\\":\\\"fooAdName\\\",\\\"type\\\":\\\"STRING\\\",\"\n                        + \"\\\"cardinality\\\":0,\\\"defaultValue\\\":\\\"default\\\",\\\"isRequired\\\":false}]\"\n                        + \",\\\"id\\\":\\\"foo\\\"},\\\"properties\\\":{\\\"testProp\\\":{\\\"value\\\":[\\\"\"\n                        + new String(this.encryptedPassword) + \"\\\"],\\\"type\\\":\\\"PASSWORD\\\"}}}\"),\n                self().field(\"configs\").arrayItem(0));\n    }\n\n    private static ConfigurationService configurationService = Mockito.mock(ConfigurationService.class);\n    private final CryptoService cryptoService;\n\n    private final Map<String, Map<String, Object>> receivedConfigsByPid = new HashMap<>();\n\n    @Parameterized.Parameters\n    public static Collection<Transport> transports() {\n        return Arrays.asList(new RestTransport(\"configuration/v2\"), new MqttTransport(\"CONF-V2\"));\n    }\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        WireTestUtil.trackService(ConfigurationService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n        final ConfigurationAdmin configurationAdmin = WireTestUtil\n                .trackService(ConfigurationAdmin.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n        final Configuration config = configurationAdmin\n                .getConfiguration(\"org.eclipse.kura.internal.rest.configuration.ConfigurationRestService\", \"?\");\n        final Dictionary<String, Object> properties = new Hashtable<>();\n        properties.put(\"ConfigurationService.target\", \"(kura.service.pid=mockConfigurationService)\");\n\n        config.update(properties);\n\n        final Dictionary<String, Object> configurationServiceProperties = new Hashtable<>();\n        configurationServiceProperties.put(\"service.ranking\", Integer.MIN_VALUE);\n        configurationServiceProperties.put(\"kura.service.pid\", \"mockConfigurationService\");\n\n        FrameworkUtil.getBundle(ConfigurationRestServiceTest.class).getBundleContext()\n                .registerService(ConfigurationService.class, configurationService, configurationServiceProperties);\n\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public ConfigurationRestServiceTest(final Transport transport) throws InterruptedException, ExecutionException,\n            TimeoutException, KuraException, InvalidSyntaxException, IOException {\n        super(transport);\n        this.cryptoService = WireTestUtil.trackService(CryptoService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n        Mockito.reset(configurationService);\n\n        final Answer<?> configurationUpdateAnswer = i -> {\n            this.receivedConfigsByPid.put(i.getArgument(0, String.class), i.getArgument(1, Map.class));\n            return null;\n        };\n        Mockito.doAnswer(configurationUpdateAnswer).when(configurationService)\n                .updateConfiguration(ArgumentMatchers.any(), ArgumentMatchers.any());\n        Mockito.doAnswer(configurationUpdateAnswer).when(configurationService)\n                .updateConfiguration(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.anyBoolean());\n    }\n\n    private void thenResponseElementIs(final JsonValue expected, final JsonProjection projection) {\n        final JsonValue root = Json\n                .parse(expectResponse().getBody().orElseThrow(() -> new IllegalStateException(\"expected body\")));\n        final JsonValue actual;\n\n        try {\n            actual = projection.apply(root);\n        } catch (final Exception e) {\n            fail(\"failed to apply \" + projection + \" to \" + root);\n            throw new IllegalStateException(\"unreachable\");\n        }\n\n        assertEquals(\"after applying \" + projection + \" to \" + root, expected, actual);\n    }\n\n    private void thenResponseElementExists(final JsonProjection projection) {\n        final JsonValue root = Json\n                .parse(expectResponse().getBody().orElseThrow(() -> new IllegalStateException(\"expected body\")));\n\n        try {\n            assertNotNull(\"response element \" + projection + \" is null\", projection.apply(root));\n        } catch (final Exception e) {\n            fail(\"failed to apply \" + projection + \" to \" + root);\n            throw new IllegalStateException(\"unreachable\");\n        }\n    }\n\n    private void givenMockGetSnapshotsReturnEmpty() throws KuraException {\n        when(configurationService.getSnapshots()).thenReturn(new TreeSet<Long>());\n    }\n\n    private void givenMockGetSnapshotsReturnSome(int howManySnapshots) throws KuraException {\n        Set<Long> snapshots = new TreeSet<>();\n        for (int i = 0; i < howManySnapshots; i++) {\n            snapshots.add((long) i + 10000);\n        }\n        when(configurationService.getSnapshots()).thenReturn(snapshots);\n    }\n\n    private void givenMockGetSnapshotsReturnException() throws KuraException {\n        when(configurationService.getSnapshots()).thenThrow(new KuraException(KuraErrorCode.CONFIGURATION_ERROR));\n    }\n\n    private void givenMockGetFactoryComponentPidsReturnEmpty() {\n        when(configurationService.getFactoryComponentPids()).thenReturn(Collections.emptySet());\n    }\n\n    private void givenMockGetFactoryComponentPidsReturnSome(int howManyComponents) throws KuraException {\n        Set<String> components = new HashSet<>();\n        for (int i = 0; i < howManyComponents; i++) {\n            components.add(\"pid\" + i);\n        }\n        when(configurationService.getFactoryComponentPids()).thenReturn(components);\n    }\n\n    private void givenMockGetConfigurableComponentPidsReturnEmpty() {\n        when(configurationService.getConfigurableComponentPids()).thenReturn(new HashSet<String>());\n    }\n\n    private void givenMockGetConfigurableComponentPidsReturnSome(int howManyComponents) throws KuraException {\n        Set<String> components = new HashSet<>();\n        for (int i = 0; i < howManyComponents; i++) {\n            components.add(\"pid\" + i);\n        }\n        when(configurationService.getConfigurableComponentPids()).thenReturn(components);\n    }\n\n    private void givenMockGetComponentConfigurationsReturnException() throws KuraException {\n        when(configurationService.getComponentConfigurations()).thenThrow(new KuraException(KuraErrorCode.BAD_REQUEST));\n    }\n\n    private void givenMockGetComponentConfigurationsReturnEmpty() throws KuraException {\n        when(configurationService.getComponentConfigurations()).thenReturn(Collections.emptyList());\n    }\n\n    private void givenMockGetComponentConfigurationPidReturnException() throws KuraException {\n        when(configurationService.getComponentConfiguration(anyString()))\n                .thenThrow(new KuraException(KuraErrorCode.BAD_REQUEST));\n    }\n\n    private void givenMockGetComponentConfigurationPidReturnEmpty() throws KuraException {\n        when(configurationService.getComponentConfiguration(anyString())).thenReturn(null);\n    }\n\n    private void givenMockGetComponentConfigurationsReturnSome(int howManyConfigurations) throws KuraException {\n        List<ComponentConfiguration> configs = new ArrayList<>();\n        for (int i = 0; i < howManyConfigurations; i++) {\n            final String generatedPid = \"pid\" + i;\n            configs.add(new ComponentConfiguration() {\n\n                @Override\n                public String getPid() {\n                    return generatedPid;\n                }\n\n                @Override\n                public OCD getDefinition() {\n                    return null;\n                }\n\n                @Override\n                public Map<String, Object> getConfigurationProperties() {\n                    return null;\n                }\n            });\n        }\n        when(configurationService.getComponentConfigurations()).thenReturn(configs);\n    }\n\n    private void givenMockGetComponentConfigurationPidReturnSome(int howManyConfigurations) throws KuraException {\n        List<ComponentConfiguration> configs = new ArrayList<>();\n        for (int i = 0; i < howManyConfigurations; i++) {\n            final String generatedPid = \"pid\" + i;\n            configs.add(new ComponentConfiguration() {\n\n                @Override\n                public String getPid() {\n                    return generatedPid;\n                }\n\n                @Override\n                public OCD getDefinition() {\n                    return null;\n                }\n\n                @Override\n                public Map<String, Object> getConfigurationProperties() {\n                    return null;\n                }\n            });\n        }\n        when(configurationService.getComponentConfiguration(\"pid1\")).thenReturn(configs.get(1));\n        when(configurationService.getComponentConfiguration(\"pid3\")).thenReturn(configs.get(3));\n    }\n\n    private void givenMockGetDefaultComponentConfigurationReturnException() throws KuraException {\n        when(configurationService.getDefaultComponentConfiguration(ArgumentMatchers.any()))\n                .thenThrow(new KuraException(KuraErrorCode.BAD_REQUEST));\n    }\n\n    private void givenMockGetDefaultComponentConfigurationReturnOne(String pid) throws KuraException {\n        ComponentConfiguration config = new ComponentConfiguration() {\n\n            @Override\n            public String getPid() {\n                return pid;\n            }\n\n            @Override\n            public OCD getDefinition() {\n                return new OCD() {\n\n                    @Override\n                    public List<AD> getAD() {\n                        return null;\n                    }\n\n                    @Override\n                    public List<Icon> getIcon() {\n                        return null;\n                    }\n\n                    @Override\n                    public String getName() {\n                        return pid;\n                    }\n\n                    @Override\n                    public String getDescription() {\n                        return null;\n                    }\n\n                    @Override\n                    public String getId() {\n                        return pid;\n                    }\n                };\n            }\n\n            @Override\n            public Map<String, Object> getConfigurationProperties() {\n                return null;\n            }\n        };\n\n        when(configurationService.getDefaultComponentConfiguration(ArgumentMatchers.any())).thenReturn(config);\n    }\n\n    private void givenMockGetSnapshotReturnException(int snapshotId) throws KuraException {\n        when(configurationService.getSnapshot(snapshotId)).thenThrow(new KuraException(KuraErrorCode.BAD_REQUEST));\n    }\n\n    private void givenMockGetSnapshotReturnSome(long snapshotId, int howManyConfigurations) throws KuraException {\n        List<ComponentConfiguration> configs = new ArrayList<>();\n        for (int i = 0; i < howManyConfigurations; i++) {\n            final String generatedPid = \"pid\" + i;\n            configs.add(new ComponentConfiguration() {\n\n                @Override\n                public String getPid() {\n                    return generatedPid;\n                }\n\n                @Override\n                public OCD getDefinition() {\n                    return null;\n                }\n\n                @Override\n                public Map<String, Object> getConfigurationProperties() {\n                    return null;\n                }\n            });\n        }\n        when(configurationService.getSnapshot(snapshotId)).thenReturn(configs);\n    }\n\n    private void givenMockSnapshotReturnException() throws KuraException {\n        when(configurationService.snapshot()).thenThrow(new KuraException(KuraErrorCode.BAD_REQUEST));\n    }\n\n    private void givenMockSnapshotReturnOne(long snapshotId) throws KuraException {\n        when(configurationService.snapshot()).thenReturn(snapshotId);\n    }\n\n    private void givenMockRollbackReturnException() throws KuraException {\n        when(configurationService.rollback()).thenThrow(new KuraException(KuraErrorCode.BAD_REQUEST));\n    }\n\n    private void givenMockRollbackReturnException(long snapshotId) throws KuraException {\n        doThrow(new KuraException(KuraErrorCode.BAD_REQUEST)).when(configurationService).rollback(snapshotId);\n    }\n\n    private void givenMockRollbackReturnOne(long snapshotId) throws KuraException {\n        when(configurationService.rollback()).thenReturn(snapshotId);\n    }\n\n    private void givenMockRollbackReturnNothing(long snapshotId) throws KuraException {\n        doNothing().when(configurationService).rollback(snapshotId);\n    }\n\n    private void givenConfigurations(final ComponentConfiguration... configurations) throws KuraException {\n        final Map<String, ComponentConfiguration> byPid = Arrays.stream(configurations)\n                .collect(Collectors.toMap(c -> c.getPid(), c -> c));\n\n        Mockito.when(configurationService.getComponentConfigurations()).thenReturn(byPid.values().stream().toList());\n\n        Mockito.when(configurationService.getComponentConfiguration(ArgumentMatchers.any())).thenAnswer(i -> {\n            final String pid = i.getArgument(0, String.class);\n            return byPid.get(pid);\n        });\n\n        Mockito.when(configurationService.getDefaultComponentConfiguration(ArgumentMatchers.any())).thenAnswer(i -> {\n            final String pid = i.getArgument(0, String.class);\n            return byPid.get(pid);\n        });\n\n        givenMockGetSnapshotsReturnSome(5);\n\n        Mockito.when(configurationService.getSnapshot(anyLong())).thenReturn(byPid.values().stream().toList());\n    }\n\n    private void givenATestConfigurationPropertyWithAdTypeAndValue(final Scalar type, final Object value)\n            throws KuraException {\n        givenConfigurations(configurationBuilder(\"foo\") //\n                .withDefinition( //\n                        ocdBuilder(\"foo\") //\n                                .withAd(adBuilder(\"testProp\", type) //\n                                        .build()) //\n                                .build()) //\n                .withConfigurationProperties(singletonMap(\"testProp\", value)).build());\n    }\n\n    private void thenTestPropertyTypeIs(final JsonValue type) {\n        thenResponseElementIs(type,\n                self().field(\"configs\").arrayItem(0).field(\"definition\").field(\"ad\").arrayItem(0).field(\"type\"));\n        thenResponseElementIs(type,\n                self().field(\"configs\").arrayItem(0).field(\"properties\").field(\"testProp\").field(\"type\"));\n    }\n\n    private void thenTestPropertyIsMissing() {\n        thenResponseElementIs(null, self().field(\"configs\").arrayItem(0).field(\"properties\").field(\"testProp\"));\n    }\n\n    private void thenTestPropertyValueIs(final JsonValue value) {\n        thenResponseElementIs(value,\n                self().field(\"configs\").arrayItem(0).field(\"properties\").field(\"testProp\").field(\"value\"));\n    }\n\n    private void thenReceivedPropertiesForPidContains(final String pid, final String expectedKey,\n            final Object expectedValue) {\n        assertEquals(expectedValue, this.receivedConfigsByPid.get(pid).get(expectedKey));\n    }\n\n    private void thenReceivedPropertiesForPidContainsArray(final String pid, final String expectedKey,\n            final Object[] expectedValue) {\n        assertArrayEquals(expectedValue, (Object[]) this.receivedConfigsByPid.get(pid).get(expectedKey));\n    }\n\n    private void thenReceivedPropertiesForPidContainsPassword(final String pid, final String expectedKey,\n            final String expectedValue) {\n        assertEquals(expectedValue,\n                new String(((Password) this.receivedConfigsByPid.get(pid).get(expectedKey)).getPassword()));\n    }\n\n    private void thenReceivedPropertiesForPidContainsPasswords(final String pid, final String expectedKey,\n            final String... expectedValues) {\n        final Password[] passwords = (Password[]) this.receivedConfigsByPid.get(pid).get(expectedKey);\n\n        for (int i = 0; i < expectedValues.length; i++) {\n            assertEquals(expectedValues[i], new String(passwords[i].getPassword()));\n        }\n\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.configuration.provider.test/src/main/java/org/eclipse/kura/rest/configuration/provider/test/ConfigurationUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.configuration.provider.test;\n\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.configuration.metatype.Icon;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.configuration.metatype.Option;\nimport org.eclipse.kura.configuration.metatype.Scalar;\n\npublic class ConfigurationUtil {\n\n    private ConfigurationUtil() {\n    }\n\n    public static AdBuilder adBuilder(final String id, final Scalar type) {\n        return new AdBuilder(id, type);\n    }\n\n    public static OCDBuilder ocdBuilder(final String id) {\n        return new OCDBuilder(id);\n    }\n\n    public static ComponentConfigurationBuilder configurationBuilder(final String pid) {\n        return new ComponentConfigurationBuilder(pid);\n    }\n\n    public static class AdBuilder {\n\n        private final String id;\n        private final Scalar type;\n        private int cardinality;\n        private String defaultValue;\n        private String description;\n        private String max;\n        private String min;\n        private String name;\n        private List<Option> options = new ArrayList<>();\n        private boolean isRequired;\n\n        private AdBuilder(final String id, final Scalar type) {\n            this.id = id;\n            this.type = type;\n        }\n\n        public AdBuilder withCardinality(final int cardinality) {\n            this.cardinality = cardinality;\n            return this;\n        }\n\n        public AdBuilder withDefault(final String defaultValue) {\n            this.defaultValue = defaultValue;\n            return this;\n        }\n\n        public AdBuilder withDescription(final String description) {\n            this.description = description;\n            return this;\n        }\n\n        public AdBuilder withMax(final String max) {\n            this.max = max;\n            return this;\n        }\n\n        public AdBuilder withMin(final String min) {\n            this.min = min;\n            return this;\n        }\n\n        public AdBuilder withName(final String name) {\n            this.name = name;\n            return this;\n        }\n\n        public AdBuilder withOption(final String label, final String value) {\n            this.options.add(new Option() {\n\n                @Override\n                public String getLabel() {\n                    return label;\n                }\n\n                @Override\n                public String getValue() {\n                    return value;\n                }\n            });\n            return this;\n        }\n\n        public AdBuilder withRequired(final boolean isRequired) {\n            this.isRequired = isRequired;\n            return this;\n        }\n\n        public AD build() {\n            return new AD() {\n\n                @Override\n                public List<Option> getOption() {\n                    return options;\n                }\n\n                @Override\n                public String getName() {\n                    return name;\n                }\n\n                @Override\n                public String getDescription() {\n                    return description;\n                }\n\n                @Override\n                public String getId() {\n                    return id;\n                }\n\n                @Override\n                public Scalar getType() {\n                    return type;\n                }\n\n                @Override\n                public int getCardinality() {\n                    return cardinality;\n                }\n\n                @Override\n                public String getMin() {\n                    return min;\n                }\n\n                @Override\n                public String getMax() {\n                    return max;\n                }\n\n                @Override\n                public String getDefault() {\n                    return defaultValue;\n                }\n\n                @Override\n                public boolean isRequired() {\n                    return isRequired;\n                }\n\n            };\n        }\n    }\n\n    public static class OCDBuilder {\n\n        private final String id;\n        private final List<Icon> icon = new ArrayList<>();\n        private final List<AD> ads = new ArrayList<>();\n\n        private String description;\n        private String name;\n\n        private OCDBuilder(final String id) {\n            this.id = id;\n        }\n\n        public OCDBuilder withAd(final AD ad) {\n            this.ads.add(ad);\n            return this;\n        }\n\n        public OCDBuilder withDescription(final String description) {\n            this.description = description;\n            return this;\n        }\n\n        public OCDBuilder withIcon(final String resource, final BigInteger size) {\n            this.icon.add(new Icon() {\n\n                @Override\n                public String getResource() {\n                    return resource;\n                }\n\n                @Override\n                public BigInteger getSize() {\n                    return size;\n                }\n\n            });\n            return this;\n        }\n\n        public OCDBuilder withName(final String name) {\n            this.name = name;\n            return this;\n        }\n\n        public OCD build() {\n            return new OCD() {\n\n                @Override\n                public List<AD> getAD() {\n                    return ads;\n                }\n\n                @Override\n                public List<Icon> getIcon() {\n                    return icon;\n                }\n\n                @Override\n                public String getName() {\n                    return name;\n                }\n\n                @Override\n                public String getDescription() {\n                    return description;\n                }\n\n                @Override\n                public String getId() {\n                    return id;\n                }\n\n            };\n        }\n    }\n\n    public static class ComponentConfigurationBuilder {\n\n        private final String pid;\n        private OCD definition;\n        private Map<String, Object> configurationProperties;\n\n        private ComponentConfigurationBuilder(final String pid) {\n            this.pid = pid;\n        }\n\n        public ComponentConfigurationBuilder withDefinition(final OCD definition) {\n            this.definition = definition;\n            return this;\n        }\n\n        public ComponentConfigurationBuilder withConfigurationProperties(\n                final Map<String, Object> configurationProperties) {\n            this.configurationProperties = configurationProperties;\n            return this;\n        }\n\n        public ComponentConfiguration build() {\n            return new ComponentConfiguration() {\n\n                @Override\n                public String getPid() {\n                    return pid;\n                }\n\n                @Override\n                public OCD getDefinition() {\n                    return definition;\n                }\n\n                @Override\n                public Map<String, Object> getConfigurationProperties() {\n                    return configurationProperties;\n                }\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.identity.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.identity.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: com.google.gson;version=\"2.9.0\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.testutil.requesthandler;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\",\n org.eclipse.kura.identity.configuration.extension;version=\"[1.0.0,2.0.0]\",\n org.eclipse.kura.util.validation;version=\"[1.0,2.0)\",\n org.eclipse.kura.util.wire.test;version=\"[1.1,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.component.runtime;version=\"[1.4.0,2.0.0]\",\n org.osgi.service.component.runtime.dto;version=\"[1.4.0,2.0.0]\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.osgi.util.promise;version=\"[1.1.0,2.0.0]\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.25\"\nFragment-Host: org.eclipse.kura.rest.identity.provider\nRequire-Bundle: org.eclipse.kura.http.server.manager;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java,\\\n           src/test/java\nbin.includes = META-INF/,\\\n               .\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n        Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.rest.identity.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                        <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/src/main/java/org/eclipse/kura/internal/rest/identity/provider/test/IdentityV1EndpointsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.test;\n\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\nimport static org.mockito.Mockito.when;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.Optional;\nimport java.util.Scanner;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.internal.rest.identity.provider.IdentityRestServiceV1;\nimport org.eclipse.kura.internal.rest.identity.provider.LegacyIdentityService;\nimport org.eclipse.kura.internal.rest.identity.provider.dto.UserDTO;\nimport org.eclipse.kura.util.validation.ValidatorOptions;\nimport org.eclipse.kura.util.wire.test.WireTestUtil;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\n\nimport com.google.gson.Gson;\n\n@SuppressWarnings(\"restriction\")\n@RunWith(Parameterized.class)\npublic class IdentityV1EndpointsTest extends AbstractRequestHandlerTest {\n\n    private static final String MQTT_APP_ID = \"IDN-V1\";\n    private static final String REST_APP_ID = \"identity/v1\";\n\n    private static final String METHOD_SPEC_GET = \"GET\";\n    private static final String METHOD_SPEC_POST = \"POST\";\n    private static final String METHOD_SPEC_DELETE = \"DELETE\";\n    private static final String MQTT_METHOD_SPEC_DEL = \"DEL\";\n    private static final String METHOD_SPEC_PUT = \"PUT\";\n\n    private static LegacyIdentityService identityServiceMock = mock(LegacyIdentityService.class);\n\n    private static UserDTO user;\n\n    private Gson gson = new Gson();\n\n    private static final String EXPECTED_GET_USER_CONFIG_RESPONSE = new Scanner(\n            IdentityV1EndpointsTest.class.getResourceAsStream(\"/getUserConfigResponse.json\"), \"UTF-8\")\n                    .useDelimiter(\"\\\\A\").next().replace(\" \", \"\");\n\n    private static final String EXPECTED_GET_USER_RESPONSE = new Scanner(\n            IdentityV1EndpointsTest.class.getResourceAsStream(\"/getUserResponse.json\"), \"UTF-8\").useDelimiter(\"\\\\A\")\n                    .next().replace(\" \", \"\");\n\n    private static final String EXPECTED_GET_PASSWORD_REQUIREMENTS_RESPONSE = new Scanner(\n            IdentityV1EndpointsTest.class.getResourceAsStream(\"/getPasswordRequirementsResponse.json\"), \"UTF-8\")\n                    .useDelimiter(\"\\\\A\").next().replace(\" \", \"\");\n\n    private static final String EXPECTED_NON_EXISTING_USER_RESPONSE = new Scanner(\n            IdentityV1EndpointsTest.class.getResourceAsStream(\"/getNonExistingUserResponse.json\"), \"UTF-8\")\n                    .useDelimiter(\"\\\\A\").next();\n\n    private static Set<UserDTO> userConfigs;\n\n    private static ServiceRegistration<LegacyIdentityService> identityServiceRegistration;\n\n    @Parameterized.Parameters(name = \"{0}\")\n    public static Collection<Transport> transports() {\n        return Arrays.asList(new MqttTransport(MQTT_APP_ID), new RestTransport(REST_APP_ID));\n    }\n\n    public IdentityV1EndpointsTest(Transport transport) {\n        super(transport);\n    }\n\n    @Test\n    public void shouldInvokeCreateUserSuccessfully() throws KuraException {\n        givenUser(new UserDTO(\"testuser\", Collections.emptySet(), true, false, \"testpassw\"));\n\n        givenIdentityService();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/identities\", gson.toJson(user));\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n    }\n\n    @Test\n    public void shouldInvokeUpdateUserSuccessfully() throws KuraException {\n        givenUser(new UserDTO(\"testuser\", Collections.emptySet(), true, false, \"testpassw\"));\n\n        givenIdentityService();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_PUT), \"/identities\", gson.toJson(user));\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n    }\n\n    @Test\n    public void shouldInvokeDeleteUserSuccessfully() throws KuraException {\n        givenUser(new UserDTO(\"testuser\", Collections.emptySet(), true, false, \"testpassw\"));\n\n        givenIdentityService();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/identities\",\n                gson.toJson(user));\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n    }\n\n    @Test\n    public void shouldReturnUserSuccessfully() throws KuraException {\n        givenUser(new UserDTO(\"testuser3\", Collections.emptySet(), true, false));\n\n        givenIdentityService();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/identities/byName\", gson.toJson(user));\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_GET_USER_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnUserConfig() throws KuraException {\n        givenUserConfigs(new UserDTO(\"testuser2\", //\n                new HashSet<String>(Arrays.asList(\"perm1\", \"perm2\")), //\n                false, //\n                true));\n\n        givenIdentityService();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/identities\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_GET_USER_CONFIG_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnDefinedPermissions() throws KuraException {\n        givenIdentityService();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/definedPermissions\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"permissions\\\": [\\\"perm1\\\",\\\"perm2\\\"]}\");\n    }\n\n    @Test\n    public void shouldReturnPasswordRequirements() throws KuraException {\n        givenIdentityService();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/passwordRequirements\");\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_GET_PASSWORD_REQUIREMENTS_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnNonExistingUserDeleteResponse() throws KuraException {\n        givenIdentityService();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/identities\",\n                gson.toJson(new UserDTO(\"nonExistingUser\", null, false, false)));\n\n        thenResponseCodeIs(404);\n        thenResponseBodyEqualsJson(EXPECTED_NON_EXISTING_USER_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnNonExistingUserPostResponse() throws KuraException {\n        givenIdentityService();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/identities/byName\",\n                gson.toJson(new UserDTO(\"nonExistingUser\", null, false, false)));\n\n        thenResponseCodeIs(404);\n        thenResponseBodyEqualsJson(EXPECTED_NON_EXISTING_USER_RESPONSE);\n    }\n\n    private void givenUser(UserDTO userParam) {\n        user = userParam;\n    }\n\n    private void givenUserConfigs(UserDTO... userConfigurations) {\n        userConfigs = new HashSet<>(Arrays.asList(userConfigurations));\n    }\n\n    private static void givenIdentityService() throws KuraException {\n        reset(identityServiceMock);\n\n        when(identityServiceMock.getDefinedPermissions())\n                .thenReturn(new HashSet<String>(Arrays.asList(\"perm1\", \"perm2\")));\n\n        when(identityServiceMock.getUserConfig()).thenReturn(userConfigs);\n\n        if (user != null) {\n            when(identityServiceMock.getUser(\"testuser3\"))\n                    .thenReturn(new UserDTO(\"testuser3\", Collections.emptySet(), true, false));\n\n            when(identityServiceMock.getUser(\"testuser\"))\n                    .thenReturn(new UserDTO(\"testuser\", Collections.emptySet(), true, false));\n\n        }\n\n        when(identityServiceMock.getUser(\"nonExistingUser\"))\n                .thenThrow(new KuraException(KuraErrorCode.NOT_FOUND, \"Identity does not exist\"));\n\n        doThrow(new KuraException(KuraErrorCode.NOT_FOUND, \"Identity does not exist\")).when(identityServiceMock)\n                .deleteUser(\"nonExistingUser\");\n\n        when(identityServiceMock.getValidatorOptions()).thenReturn(new ValidatorOptions(8, false, false, false));\n    }\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        createIdentityServiceMock();\n        registerIdentityServiceMock();\n    }\n\n    @AfterClass\n    public static void tearDown() throws Exception {\n        unregisterIdentityServiceMock();\n    }\n\n    private static void createIdentityServiceMock() throws KuraException {\n        givenIdentityService();\n\n        final Dictionary<String, Object> configurationServiceProperties = new Hashtable<>();\n        configurationServiceProperties.put(\"service.ranking\", Integer.MIN_VALUE);\n        configurationServiceProperties.put(\"kura.service.pid\", \"identityServiceMock\");\n        identityServiceRegistration = FrameworkUtil.getBundle(IdentityV1EndpointsTest.class).getBundleContext()\n                .registerService(LegacyIdentityService.class, identityServiceMock, configurationServiceProperties);\n    }\n\n    private static void registerIdentityServiceMock() throws Exception {\n        final Dictionary<String, Object> properties = new Hashtable<>();\n        properties.put(\"IdentityService.target\", \"(kura.service.pid=identityServiceMock)\");\n\n        final ConfigurationAdmin configurationAdmin = WireTestUtil\n                .trackService(ConfigurationAdmin.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n        final Configuration config = configurationAdmin.getConfiguration(IdentityRestServiceV1.class.getName(), \"?\");\n        config.update(properties);\n    }\n\n    private static void unregisterIdentityServiceMock() {\n        identityServiceRegistration.unregister();\n\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/src/main/java/org/eclipse/kura/internal/rest/identity/provider/test/IdentityV2EndpointsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\n// Content with portions generated by generative AI platform\n\npackage org.eclipse.kura.internal.rest.identity.provider.test;\n\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.mock;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.identity.AssignedPermissions;\nimport org.eclipse.kura.identity.IdentityConfiguration;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.identity.PasswordStrengthRequirements;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.identity.Permission;\nimport org.eclipse.kura.identity.configuration.extension.IdentityConfigurationExtension;\nimport org.eclipse.kura.internal.rest.identity.provider.util.IdentityDTOUtils;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.AdditionalConfigurationsDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.IdentityConfigurationDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.IdentityConfigurationRequestDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.IdentityDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.PasswordConfigurationDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.PermissionConfigurationDTO;\nimport org.eclipse.kura.internal.rest.identity.provider.v2.dto.PermissionDTO;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.mockito.ArgumentMatchers;\nimport org.mockito.Mockito;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.component.runtime.ServiceComponentRuntime;\nimport org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;\nimport org.osgi.util.promise.Promise;\n\nimport com.google.gson.Gson;\n\n@RunWith(Parameterized.class)\npublic class IdentityV2EndpointsTest extends AbstractRequestHandlerTest {\n\n    private static final String MQTT_APP_ID = \"IDN-V2\";\n    private static final String REST_APP_ID = \"identity/v2\";\n\n    private static final String METHOD_SPEC_GET = \"GET\";\n    private static final String METHOD_SPEC_POST = \"POST\";\n    private static final String METHOD_SPEC_DELETE = \"DELETE\";\n    private static final String MQTT_METHOD_SPEC_DEL = \"DEL\";\n    private static final String METHOD_SPEC_PUT = \"PUT\";\n    private static IdentityService identityService;\n\n    private static final int HTTP_STATUS_CONFLICT = 409;\n\n    private Gson gson = new Gson();\n\n    private IdentityDTO identity;\n    private IdentityConfigurationRequestDTO identityConfigurationRequestDTO;\n    private String testUsername;\n    private String testPermissionName;\n\n    private IdentityConfigurationDTO identityConfiguration;\n    private PasswordConfigurationDTO passwordConfiguration;\n    private AdditionalConfigurationsDTO additionalConfigurations;\n    private PermissionConfigurationDTO permissionConfiguration;\n\n    private static PasswordStrengthVerificationService passwordStrengthVerificationServiceMock = mock(\n            PasswordStrengthVerificationService.class);\n\n    private final Map<String, MockExtensionHolder> extensions = new HashMap<>();\n\n    @Parameterized.Parameters(name = \"{0} - {1}\")\n    public static Collection<?> transports() {\n        return Arrays.asList(new Object[][] { //\n                { new MqttTransport(MQTT_APP_ID), \"test_user_for_mqtt\", \"test.permission.for.mqtt\" }, //\n                { new RestTransport(REST_APP_ID), \"test_user_for_rest\", \"test.permission.for.rest\" } });\n    }\n\n    @Test\n    public void shouldInvokeCreateIdentitySuccessfully() throws KuraException {\n        givenNewIdentity(new IdentityDTO(this.testUsername));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/identities\", gson.toJson(this.identity));\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n    }\n\n    @Test\n    public void shouldReturnErrorIfIdentityAlreadyExists() throws KuraException {\n        givenExistingIdentity(new IdentityDTO(this.testUsername));\n\n        givenNewIdentity(new IdentityDTO(this.testUsername));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/identities\", gson.toJson(this.identity));\n\n        thenResponseCodeIs(HTTP_STATUS_CONFLICT);\n        thenResponseBodyIsNotEmpty();\n    }\n\n    @Test\n    public void shouldUpdateIdentityWithConfiguration() throws KuraException {\n        givenExistingIdentity(new IdentityDTO(this.testUsername));\n        givenExistingPermission(new PermissionDTO(this.testPermissionName));\n        givenMockIdentityConfigurationExtension(\"test.extension\");\n        givenMockIdentityConfigurationExtension(\"test2.extension\");\n\n        givenPermissionConfiguration(this.testPermissionName);\n        givenPasswordConfiguration(\"Abcdef1234567@\", true, false);\n        givenAdditionalConfigurations(TestComponentConfiguration.forPid(\"test.extension\"),\n                TestComponentConfiguration.forPid(\"test2.extension\"));\n\n        givenIdentityConfigurationFor(new IdentityDTO(this.testUsername));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_PUT), \"/identities\", gson.toJson(this.identityConfiguration));\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n    }\n\n    @Test\n    public void shouldGetIdentityByName() {\n        givenExistingIdentity(new IdentityDTO(this.testUsername));\n        givenExistingPermission(new PermissionDTO(this.testPermissionName));\n        givenAssignedPermissionToIdentity();\n\n        givenIdentityConfigurationRequestDTO();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/identities/byName\",\n                gson.toJson(this.identityConfigurationRequestDTO));\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"identity\\\":{\\\"name\\\":\\\"\" + this.testUsername\n                + \"\\\"},\\\"permissionConfiguration\\\":{\\\"permissions\\\":[{\\\"name\\\":\\\"\" + this.testPermissionName\n                + \"\\\"}]},\\\"passwordConfiguration\\\":{\\\"passwordChangeNeeded\\\":false,\\\"passwordAuthEnabled\\\":false},\\\"additionalConfigurations\\\":{\\\"configurations\\\":[]}}\");\n    }\n\n    @Test\n    public void shouldGetIdentityDefaultByName() {\n        givenExistingIdentity(new IdentityDTO(this.testUsername));\n        givenExistingPermission(new PermissionDTO(this.testPermissionName));\n        givenIdentityConfigurationRequestDTO();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/identities/default/byName\",\n                gson.toJson(this.identityConfigurationRequestDTO));\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"identity\\\":{\\\"name\\\":\\\"\" + this.testUsername\n                + \"\\\"},\\\"permissionConfiguration\\\":{\\\"permissions\\\":[]},\\\"passwordConfiguration\\\":{\\\"passwordChangeNeeded\\\":false,\\\"passwordAuthEnabled\\\":false},\\\"additionalConfigurations\\\":{\\\"configurations\\\":[]}}\");\n    }\n\n    @Test\n    public void shouldDeleteExistingIdentity() {\n        givenExistingIdentity(new IdentityDTO(this.testUsername));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/identities\",\n                gson.toJson(new IdentityDTO(this.testUsername)));\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n\n    }\n\n    @Test\n    public void shouldReturnErrorDeletingNonExistingIdentity() {\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/identities\",\n                gson.toJson(new IdentityDTO(this.testUsername)));\n\n        thenResponseCodeIs(404);\n        thenResponseBodyEqualsJson(\"{\\\"message\\\":\\\"Identity not found\\\"}\");\n\n    }\n\n    @Test\n    public void shouldReturnErrorDeletingWithMalformedIdentityRequest() {\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/identities\",\n                \"{\\\"nm\\\":\\\"identity\\\"}\");\n\n        thenResponseCodeIs(400);\n        thenResponseBodyEqualsJson(\"{\\\"message\\\":\\\"Missing 'name' property\\\"}\");\n\n    }\n\n    @Test\n    public void shouldGetDefinedPermissions() {\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/definedPermissions\");\n\n        thenRequestSucceeds();\n        thenResponseBodyIsNotEmpty();\n\n    }\n\n    @Test\n    public void shouldGetIdentities() {\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/identities\");\n\n        thenRequestSucceeds();\n        thenResponseBodyIsNotEmpty();\n\n    }\n\n    @Test\n    public void shouldGetPasswordStrenghtRequirements() {\n\n        givenPasswordStrenghtServiceMockConfiguration(8, false, false, false);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/passwordStrenghtRequirements\");\n\n        thenRequestSucceeds();\n        thenResponseBodyIsNotEmpty();\n\n    }\n\n    @Test\n    public void shouldCreatePermission() {\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/permissions\",\n                gson.toJson(new PermissionDTO(testPermissionName)));\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n\n    }\n\n    @Test\n    public void shouldDeleteExistingPermission() {\n        givenExistingPermission(new PermissionDTO(this.testPermissionName));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/permissions\",\n                gson.toJson(new PermissionDTO(this.testPermissionName)));\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n\n    }\n\n    @Test\n    public void shouldReturnErrorDeletingNonExistingPermission() {\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/permissions\",\n                gson.toJson(new PermissionDTO(this.testPermissionName)));\n\n        thenResponseCodeIs(404);\n        thenResponseBodyEqualsJson(\"{\\\"message\\\":\\\"Permission not found\\\"}\");\n\n    }\n\n    @Test\n    public void shouldReturnErrorDeletingWithMalformedPermissionRequest() {\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), \"/permissions\",\n                \"{\\\"nm\\\":\\\"permission\\\"}\");\n\n        thenResponseCodeIs(400);\n        thenResponseBodyEqualsJson(\"{\\\"message\\\":\\\"Missing 'name' property\\\"}\");\n\n    }\n\n    @Test\n    public void shouldValidateIdentityConfiguration() {\n        givenExistingIdentity(new IdentityDTO(this.testUsername));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/identities/validate\",\n                gson.toJson(new IdentityConfigurationDTO(new IdentityDTO(this.testUsername))));\n\n        thenRequestSucceeds();\n    }\n\n    @BeforeClass\n    public static void setup() {\n        try {\n            final ServiceComponentRuntime scr = ServiceUtil\n                    .trackService(ServiceComponentRuntime.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n            disableComponent(scr, \"org.eclipse.kura.core.identity.PasswordStrengthVerificationServiceImpl\");\n\n            FrameworkUtil.getBundle(IdentityV2EndpointsTest.class).getBundleContext().registerService(\n                    PasswordStrengthVerificationService.class, passwordStrengthVerificationServiceMock,\n                    new Hashtable<>());\n\n            identityService = ServiceUtil.trackService(IdentityService.class, Optional.empty()).get(30,\n                    TimeUnit.SECONDS);\n\n        } catch (InterruptedException | ExecutionException | TimeoutException e) {\n            e.printStackTrace();\n            fail(\"Unable to track IdentityService\");\n        }\n    }\n\n    @Before\n    public void cleanUp() {\n        try {\n            identityService.deleteIdentity(this.testUsername);\n            identityService.deletePermission(new Permission(this.testPermissionName));\n        } catch (KuraException e) {\n            e.printStackTrace();\n            fail(\"unable to clean the Identities repository\");\n        }\n    }\n\n    @After\n    public void cleanup() {\n        for (final MockExtensionHolder reg : this.extensions.values()) {\n            reg.registration.unregister();\n        }\n    }\n\n    public IdentityV2EndpointsTest(Transport transport, String testUsername, String testPermissionName) {\n        super(transport);\n        this.testUsername = testUsername;\n        this.testPermissionName = testPermissionName;\n    }\n\n    private void givenAdditionalConfigurations(ComponentConfiguration... componentConfigurations) {\n\n        this.additionalConfigurations = new AdditionalConfigurationsDTO();\n        this.additionalConfigurations.setConfigurations(Stream.of(componentConfigurations)\n                .map(IdentityDTOUtils::fromComponentConfiguration).collect(Collectors.toSet()));\n\n    }\n\n    private void givenPermissionConfiguration(String... permissionNames) {\n        this.permissionConfiguration = new PermissionConfigurationDTO();\n        this.permissionConfiguration.setPermissions(new HashSet<PermissionDTO>(\n                Stream.of(permissionNames).map(PermissionDTO::new).collect(Collectors.toList())));\n\n    }\n\n    private void givenExistingPermission(PermissionDTO permissionDTO) {\n        try {\n            identityService.createPermission(IdentityDTOUtils.toPermission(permissionDTO));\n        } catch (KuraException e) {\n            e.printStackTrace();\n            fail(\"unable to create the permission\");\n        }\n    }\n\n    private void givenPasswordConfiguration(String password, boolean passwordAuthEnabled,\n            boolean passwordChangeEnabled) {\n        this.passwordConfiguration = new PasswordConfigurationDTO();\n\n        this.passwordConfiguration.setPassword(password);\n        this.passwordConfiguration.setPasswordAuthEnabled(passwordAuthEnabled);\n        this.passwordConfiguration.setPasswordChangeNeeded(passwordChangeEnabled);\n    }\n\n    private void givenIdentityConfigurationFor(IdentityDTO identityDTO) {\n        this.identityConfiguration = new IdentityConfigurationDTO(identityDTO);\n\n        this.identityConfiguration.setAdditionalConfigurations(this.additionalConfigurations);\n        this.identityConfiguration.setPasswordConfiguration(this.passwordConfiguration);\n        this.identityConfiguration.setPermissionConfiguration(this.permissionConfiguration);\n    }\n\n    private void givenNewIdentity(IdentityDTO identity) {\n        this.identity = identity;\n    }\n\n    private void givenExistingIdentity(IdentityDTO identity) {\n        try {\n            identityService.createIdentity(identity.getName());\n        } catch (KuraException e) {\n            e.printStackTrace();\n            fail(\"unable to create the identity\");\n        }\n    }\n\n    private void givenMockIdentityConfigurationExtension(final String pid) {\n        this.extensions.put(pid, new MockExtensionHolder(pid));\n    }\n\n    private void givenIdentityConfigurationRequestDTO() {\n        this.identityConfigurationRequestDTO = new IdentityConfigurationRequestDTO();\n        this.identityConfigurationRequestDTO.setIdentity(new IdentityDTO(testUsername));\n        this.identityConfigurationRequestDTO.setConfigurationComponents(new HashSet<String>(\n                Arrays.asList(\"AdditionalConfigurations\", \"AssignedPermissions\", \"PasswordConfiguration\")));\n    }\n\n    private void givenPasswordStrenghtServiceMockConfiguration(int passwordMinimumLength, boolean digitsRequired,\n            boolean specialCharactersRequired, boolean bothCasesRequired) {\n\n        try {\n            Mockito.when(passwordStrengthVerificationServiceMock.getPasswordStrengthRequirements())\n                    .thenReturn(new PasswordStrengthRequirements(passwordMinimumLength, digitsRequired,\n                            specialCharactersRequired, bothCasesRequired));\n        } catch (Exception ex) {\n            ex.printStackTrace();\n            fail(\"Unable to configure password strenght requirements\");\n        }\n    }\n\n    private void givenAssignedPermissionToIdentity() {\n        try {\n            Set<Permission> permissions = new HashSet<>(Arrays.asList(new Permission(this.testPermissionName)));\n            identityService.updateIdentityConfiguration(\n                    new IdentityConfiguration(this.testUsername, Arrays.asList(new AssignedPermissions(permissions))));\n        } catch (Exception ex) {\n            ex.printStackTrace();\n            fail(\"Unable to configure identity permissions\");\n        }\n    }\n\n    private static Future<?> disableComponent(final ServiceComponentRuntime scr, final String componentName) {\n        return withComponent(scr, componentName, scr::disableComponent);\n    }\n\n    private static Future<?> withComponent(final ServiceComponentRuntime scr, final String componentName,\n            final Function<ComponentDescriptionDTO, Promise<?>> func) {\n        final Optional<ComponentDescriptionDTO> component = scr.getComponentDescriptionDTOs().stream()\n                .filter(d -> Objects.equals(componentName, d.name)).findAny();\n\n        final CompletableFuture<Void> result = new CompletableFuture<>();\n\n        if (component.isPresent()) {\n            func.apply(component.get()).onResolve(() -> result.complete(null));\n        } else {\n            result.complete(null);\n        }\n\n        return result;\n    }\n\n    private static class MockExtensionHolder {\n\n        private final ServiceRegistration<IdentityConfigurationExtension> registration;\n        private final IdentityConfigurationExtension extension;\n\n        private final Map<String, ComponentConfiguration> defaultConfigurations = new HashMap<>();\n        private final Map<String, ComponentConfiguration> configurations = new HashMap<>();\n\n        public MockExtensionHolder(final String pid) {\n            this.extension = Mockito.mock(IdentityConfigurationExtension.class);\n\n            try {\n                Mockito.when(this.extension.getConfiguration(ArgumentMatchers.anyString())).thenAnswer(a -> {\n                    final String name = a.getArgument(0, String.class);\n\n                    return Optional.ofNullable(this.configurations.get(name));\n                });\n\n                Mockito.when(this.extension.getDefaultConfiguration(ArgumentMatchers.anyString())).thenAnswer(a -> {\n                    final String name = a.getArgument(0, String.class);\n\n                    return Optional.ofNullable(this.defaultConfigurations.get(name));\n                });\n\n                Mockito.doAnswer(i -> {\n                    final String identityName = i.getArgument(0, String.class);\n                    final ComponentConfiguration connfig = i.getArgument(1, ComponentConfiguration.class);\n\n                    this.configurations.put(identityName, connfig);\n\n                    return (Void) null;\n                }).when(this.extension).updateConfiguration(ArgumentMatchers.anyString(), ArgumentMatchers.any());\n\n            } catch (KuraException e) {\n                // no need\n            }\n\n            final Dictionary<String, Object> properties = new Hashtable<>();\n            properties.put(\"kura.service.pid\", pid);\n\n            this.registration = FrameworkUtil.getBundle(IdentityV2EndpointsTest.class).getBundleContext()\n                    .registerService(IdentityConfigurationExtension.class, this.extension, properties);\n        }\n\n        void throwOnIdentityValidation(final String identityName) {\n            try {\n                Mockito.doThrow(new KuraException(KuraErrorCode.INVALID_PARAMETER)).when(this.extension)\n                        .validateConfiguration(ArgumentMatchers.eq(identityName), ArgumentMatchers.any());\n            } catch (KuraException e) {\n                // no need\n            }\n        }\n    }\n\n    private static class TestComponentConfiguration implements ComponentConfiguration {\n\n        private final String pid;\n        private final OCD ocd;\n        private final Map<String, Object> properties;\n\n        public TestComponentConfiguration(String pid, OCD ocd, Map<String, Object> properties) {\n            this.pid = pid;\n            this.ocd = ocd;\n            this.properties = properties;\n        }\n\n        @Override\n        public String getPid() {\n            return this.pid;\n        }\n\n        @Override\n        public OCD getDefinition() {\n            return this.ocd;\n        }\n\n        @Override\n        public Map<String, Object> getConfigurationProperties() {\n            return this.properties;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(this.ocd, this.pid, this.properties);\n        }\n\n        static TestComponentConfiguration forPid(final String pid) {\n            return new TestComponentConfiguration(pid, null, Collections.singletonMap(\"foo\", \"bar\"));\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (obj == null || getClass() != obj.getClass()) {\n                return false;\n            }\n            TestComponentConfiguration other = (TestComponentConfiguration) obj;\n            return Objects.equals(this.ocd, other.ocd) && Objects.equals(this.pid, other.pid)\n                    && Objects.equals(this.properties, other.properties);\n        }\n\n        @Override\n        public String toString() {\n            return \"TestComponentConfiguration [pid=\" + this.pid + \", ocd=\" + this.ocd + \", properties=\"\n                    + this.properties + \"]\";\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/src/main/resources/getNonExistingUserResponse.json",
    "content": "{\"message\" : \"Identity does not exist\"}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/src/main/resources/getPasswordRequirementsResponse.json",
    "content": "{\n    \"passwordMinimumLength\": 8,\n    \"passwordRequireDigits\": false,\n    \"passwordRequireSpecialChars\": false,\n    \"passwordRequireBothCases\": false\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/src/main/resources/getUserConfigResponse.json",
    "content": "{\n    \"userConfig\": [\n        {\n            \"userName\": \"testuser2\",\n            \"passwordAuthEnabled\": false,\n            \"passwordChangeNeeded\": true,\n            \"permissions\": [\n                \"perm1\",\n                \"perm2\"\n            ]\n        }\n    ]\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/src/main/resources/getUserResponse.json",
    "content": "{\n    \"userName\": \"testuser3\",\n    \"passwordAuthEnabled\": true,\n    \"passwordChangeNeeded\": false,\n    \"permissions\": []\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/src/test/java/org/eclipse/kura/internal/rest/identity/provider/test/IdentityRestServiceV1DependenciesTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.test;\n\nimport static org.junit.Assert.assertNull;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Objects;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.internal.rest.identity.provider.IdentityRestServiceV1;\nimport org.eclipse.kura.internal.rest.identity.provider.LegacyIdentityService;\nimport org.junit.Test;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\n\npublic class IdentityRestServiceV1DependenciesTest {\n\n    private static final String MQTT_APP_ID = \"IDN-V1\";\n    private static final String REST_ROLE_NAME = \"identity\";\n    private static final String KURA_PERMISSION_REST_ROLE = \"kura.permission.rest.\" + REST_ROLE_NAME;\n\n    private final IdentityRestServiceV1 service = new IdentityRestServiceV1();\n\n    private UserAdmin userAdminMock;\n    private CryptoService cryptoServiceMock;\n    private PasswordStrengthVerificationService passwordStrengthVerificationServiceMock;\n\n    private LegacyIdentityService legacyIdentityServiceMock;\n    private RequestHandlerRegistry requestHandlerRegistryMock;\n    private Exception occurredException;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldCreateRoleOnUserAdminBinding() {\n        givenUserAdminMock();\n\n        whenBindUserAdmin();\n\n        thenRoleIsCreated(KURA_PERMISSION_REST_ROLE, Role.GROUP);\n    }\n\n    @Test\n    public void shouldRegisterRequestHandler() throws KuraException {\n        givenMockRequestHandlerRegistry();\n\n        whenBindRequestHandlerRegistry();\n\n        thenRequestHandlerIsRegistered(MQTT_APP_ID);\n    }\n\n    @Test\n    public void shouldUnregisterRequestHandler() throws KuraException {\n        givenMockRequestHandlerRegistry();\n        givenBoundRequestHandlerRegistry();\n\n        whenUnbindRequestHandlerRegistry();\n\n        thenRequestHandlerIsUnregistered(MQTT_APP_ID);\n    }\n\n    @Test\n    public void shouldCatchExceptionsOnRequestHandlerBind() throws KuraException {\n        givenFailingMockRequestHandlerRegistry();\n\n        whenBindRequestHandlerRegistry();\n\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void shouldCatchExceptionsOnRequestHandlerUnbind() throws KuraException {\n        givenFailingMockRequestHandlerRegistry();\n\n        whenUnbindRequestHandlerRegistry();\n\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void shouldActivateRestIdentityService() throws KuraException {\n        givenUserAdminMock();\n        givenCryptoServiceMock();\n        givenMockConfigurationService();\n        givenLegacyIdentityServiceMock();\n\n        whenActivateWithDependencies();\n\n        thenNoExceptionOccurred();\n    }\n\n    /*\n     * Given\n     */\n\n    private void givenCryptoServiceMock() {\n        this.cryptoServiceMock = mock(CryptoService.class);\n    }\n\n    private void givenMockConfigurationService() {\n        this.passwordStrengthVerificationServiceMock = mock(PasswordStrengthVerificationService.class);\n    }\n\n    private void givenUserAdminMock() {\n        this.userAdminMock = mock(UserAdmin.class);\n    }\n\n    private void givenMockRequestHandlerRegistry() {\n        this.requestHandlerRegistryMock = mock(RequestHandlerRegistry.class);\n    }\n\n    private void givenBoundRequestHandlerRegistry() {\n        bindRequestHandlerRegistry();\n    }\n\n    private void givenFailingMockRequestHandlerRegistry() throws KuraException {\n        this.requestHandlerRegistryMock = mock(RequestHandlerRegistry.class);\n        doThrow(new KuraException(KuraErrorCode.BAD_REQUEST)).when(this.requestHandlerRegistryMock)\n                .registerRequestHandler(any(), any());\n        doThrow(new KuraException(KuraErrorCode.BAD_REQUEST)).when(this.requestHandlerRegistryMock).unregister(any());\n    }\n\n    private void givenLegacyIdentityServiceMock() {\n        this.legacyIdentityServiceMock = mock(LegacyIdentityService.class);\n    }\n\n    /*\n     * When\n     */\n\n    private void whenBindUserAdmin() {\n        this.service.bindUserAdmin(this.userAdminMock);\n    }\n\n    private void whenBindRequestHandlerRegistry() {\n        bindRequestHandlerRegistry();\n    }\n\n    private void whenUnbindRequestHandlerRegistry() {\n        try {\n            this.service.unbindRequestHandlerRegistry(this.requestHandlerRegistryMock);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenActivateWithDependencies() {\n        try {\n            this.service.bindPasswordStrengthVerificationService(passwordStrengthVerificationServiceMock);\n            this.service.bindCryptoService(this.cryptoServiceMock);\n            this.service.bindLegacyIdentityService(this.legacyIdentityServiceMock);\n            this.service.bindRequestHandlerRegistry(this.requestHandlerRegistryMock);\n            this.service.bindUserAdmin(this.userAdminMock);\n\n            this.service.activate();\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenRoleIsCreated(String expectedKuraPermission, int expectedRole) {\n        verify(this.userAdminMock, times(1)).createRole(expectedKuraPermission, expectedRole);\n    }\n\n    private void thenRequestHandlerIsRegistered(String expectedMqttAppId) throws KuraException {\n        verify(this.requestHandlerRegistryMock, times(1)).registerRequestHandler(eq(expectedMqttAppId),\n                any(RequestHandler.class));\n    }\n\n    private void thenRequestHandlerIsUnregistered(String expectedMqttAppId) throws KuraException {\n        verify(this.requestHandlerRegistryMock, times(1)).unregister(expectedMqttAppId);\n    }\n\n    private void thenNoExceptionOccurred() {\n        String errorMessage = \"Empty message\";\n        if (Objects.nonNull(this.occurredException)) {\n            StringWriter sw = new StringWriter();\n            this.occurredException.printStackTrace(new PrintWriter(sw));\n\n            errorMessage = String.format(\"No exception expected, \\\"%s\\\" found. Caused by: %s\",\n                    this.occurredException.getClass().getName(), sw.toString());\n        }\n\n        assertNull(errorMessage, this.occurredException);\n    }\n\n    private void bindRequestHandlerRegistry() {\n        try {\n            this.service.bindRequestHandlerRegistry(this.requestHandlerRegistryMock);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/src/test/java/org/eclipse/kura/internal/rest/identity/provider/test/IdentityRestServiceV2DependenciesTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.test;\n\nimport static org.junit.Assert.assertNull;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Objects;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.identity.IdentityService;\nimport org.eclipse.kura.internal.rest.identity.provider.IdentityRestServiceV2;\nimport org.junit.Test;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\n\npublic class IdentityRestServiceV2DependenciesTest {\n\n    private static final String MQTT_APP_ID = \"IDN-V2\";\n    private static final String REST_ROLE_NAME = \"identity\";\n    private static final String KURA_PERMISSION_REST_ROLE = \"kura.permission.rest.\" + REST_ROLE_NAME;\n\n    private final IdentityRestServiceV2 service = new IdentityRestServiceV2();\n\n    private UserAdmin userAdminMock;\n    private IdentityService identityServiceMock;\n\n    private RequestHandlerRegistry requestHandlerRegistryMock;\n    private Exception occurredException;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldCreateRoleOnUserAdminBinding() {\n        givenUserAdminMock();\n\n        whenBindUserAdmin();\n\n        thenRoleIsCreated(KURA_PERMISSION_REST_ROLE, Role.GROUP);\n    }\n\n    @Test\n    public void shouldRegisterRequestHandler() throws KuraException {\n        givenRequestHandlerRegistryMock();\n\n        whenBindRequestHandlerRegistry();\n\n        thenRequestHandlerIsRegistered(MQTT_APP_ID);\n    }\n\n    @Test\n    public void shouldUnregisterRequestHandler() throws KuraException {\n        givenRequestHandlerRegistryMock();\n        givenBoundRequestHandlerRegistry();\n\n        whenUnbindRequestHandlerRegistry();\n\n        thenRequestHandlerIsUnregistered(MQTT_APP_ID);\n    }\n\n    @Test\n    public void shouldCatchExceptionsOnRequestHandlerBind() throws KuraException {\n        givenFailingRequestHandlerRegistryMock();\n\n        whenBindRequestHandlerRegistry();\n\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void shouldCatchExceptionsOnRequestHandlerUnbind() throws KuraException {\n        givenFailingRequestHandlerRegistryMock();\n\n        whenUnbindRequestHandlerRegistry();\n\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void shouldBindRestIdentityServiceDependencies() {\n        givenUserAdminMock();\n        givenIdentityServiceMock();\n        givenRequestHandlerRegistryMock();\n\n        whenBindDependencies();\n\n        thenNoExceptionOccurred();\n    }\n\n    /*\n     * Given\n     */\n\n    private void givenUserAdminMock() {\n        this.userAdminMock = mock(UserAdmin.class);\n    }\n\n    private void givenRequestHandlerRegistryMock() {\n        this.requestHandlerRegistryMock = mock(RequestHandlerRegistry.class);\n    }\n\n    private void givenBoundRequestHandlerRegistry() {\n        bindRequestHandlerRegistry();\n    }\n\n    private void givenIdentityServiceMock() {\n        this.identityServiceMock = mock(IdentityService.class);\n    }\n\n    private void givenFailingRequestHandlerRegistryMock() throws KuraException {\n        this.requestHandlerRegistryMock = mock(RequestHandlerRegistry.class);\n        doThrow(new KuraException(KuraErrorCode.BAD_REQUEST)).when(this.requestHandlerRegistryMock)\n                .registerRequestHandler(any(), any());\n        doThrow(new KuraException(KuraErrorCode.BAD_REQUEST)).when(this.requestHandlerRegistryMock).unregister(any());\n    }\n\n    /*\n     * When\n     */\n\n    private void whenBindUserAdmin() {\n        this.service.bindUserAdmin(this.userAdminMock);\n    }\n\n    private void whenBindRequestHandlerRegistry() {\n        bindRequestHandlerRegistry();\n    }\n\n    private void whenUnbindRequestHandlerRegistry() {\n        try {\n            this.service.unbindRequestHandlerRegistry(this.requestHandlerRegistryMock);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenBindDependencies() {\n        try {\n            this.service.bindIdentityService(this.identityServiceMock);\n            this.service.bindRequestHandlerRegistry(this.requestHandlerRegistryMock);\n            this.service.bindUserAdmin(this.userAdminMock);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenRoleIsCreated(String expectedKuraPermission, int expectedRole) {\n        verify(this.userAdminMock, times(1)).createRole(expectedKuraPermission, expectedRole);\n    }\n\n    private void thenRequestHandlerIsRegistered(String expectedMqttAppId) throws KuraException {\n        verify(this.requestHandlerRegistryMock, times(1)).registerRequestHandler(eq(expectedMqttAppId),\n                any(RequestHandler.class));\n    }\n\n    private void thenRequestHandlerIsUnregistered(String expectedMqttAppId) throws KuraException {\n        verify(this.requestHandlerRegistryMock, times(1)).unregister(expectedMqttAppId);\n    }\n\n    private void thenNoExceptionOccurred() {\n        String errorMessage = \"Empty message\";\n        if (Objects.nonNull(this.occurredException)) {\n            StringWriter sw = new StringWriter();\n            this.occurredException.printStackTrace(new PrintWriter(sw));\n\n            errorMessage = String.format(\"No exception expected, \\\"%s\\\" found. Caused by: %s\",\n                    this.occurredException.getClass().getName(), sw.toString());\n        }\n\n        assertNull(errorMessage, this.occurredException);\n    }\n\n    private void bindRequestHandlerRegistry() {\n        try {\n            this.service.bindRequestHandlerRegistry(this.requestHandlerRegistryMock);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.identity.provider.test/src/test/java/org/eclipse/kura/internal/rest/identity/provider/test/IdentityServiceV1Test.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.identity.provider.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\nimport static org.mockito.ArgumentMatchers.anyString;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.io.UnsupportedEncodingException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.identity.PasswordStrengthRequirements;\nimport org.eclipse.kura.identity.PasswordStrengthVerificationService;\nimport org.eclipse.kura.internal.rest.identity.provider.LegacyIdentityService;\nimport org.eclipse.kura.internal.rest.identity.provider.dto.UserDTO;\nimport org.eclipse.kura.util.validation.ValidatorOptions;\nimport org.junit.Test;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\n\n@SuppressWarnings(\"restriction\")\npublic class IdentityServiceV1Test {\n\n    private static final String USER_ROLE_NAME_PREFIX = \"kura.user.\";\n    private static final String PERMISSION_ROLE_NAME_PREFIX = \"kura.permission.\";\n\n    private LegacyIdentityService identityService;\n    private Exception occurredException;\n    private UserDTO user;\n    private UserDTO newUser;\n\n    private CryptoService cryptoService;\n    private UserAdmin userAdmin;\n    private PasswordStrengthVerificationService passwordStrengthVerificationService;\n\n    private Set<String> definedPermissions;\n    private Set<UserDTO> userConfig;\n    private boolean isPasswordValid;\n    private ValidatorOptions validatorOptions;\n\n    @Test\n    public void shouldCreateAnUser() throws KuraException {\n        givenIdentityService();\n\n        whenCreatingUser(new UserDTO(\"testuser\", Collections.emptySet(), true, false, \"testpassw\"));\n\n        thenNoExceptionOccurred();\n        thenUserIsCreated();\n    }\n\n    @Test\n    public void shouldDeleteExistingUser() {\n        givenIdentityService();\n        givenExistingUser(new UserDTO(\"testuser\", Collections.emptySet(), true, false, \"testpassw\"));\n\n        whenDeleting(\"testuser\");\n\n        thenNoExceptionOccurred();\n        thenUserIsDeleted();\n    }\n\n    @Test\n    public void shouldGetDefinedPermissions() throws InvalidSyntaxException {\n        givenIdentityService();\n        givenExistingPermissions(new PermissionRole(\"perm1\"), new PermissionRole(\"perm2\"));\n\n        whenGettingDefinedPermissions();\n\n        thenNoExceptionOccurred();\n        thenPermissionsAre(\"perm1\", \"perm2\");\n\n    }\n\n    @Test\n    public void shoulGetUser() {\n        givenIdentityService();\n        givenExistingUser(new UserDTO(\"testuser\", Collections.emptySet(), true, false, \"testpassw\"));\n\n        whenGettingUser(\"testuser\");\n\n        thenNoExceptionOccurred();\n        thenUserIs(\"testuser\");\n\n    }\n\n    @Test\n    public void shouldGetUserConfig() {\n        givenIdentityService();\n        givenExistingUser(new UserDTO(\"testuser\", Collections.emptySet(), true, false, \"testpassw\"));\n\n        whenGetUserConfig();\n\n        thenNoExceptionOccurred();\n        thenConfigContains(new UserDTO(\"testuser\", Collections.emptySet(), true, false, \"testpassw\"));\n    }\n\n    @Test\n    public void shouldGetValidatorOptions() {\n        givenIdentityService();\n\n        whenGettingValidatorOptions();\n\n        thenNoExceptionOccurred();\n        thenValidatorOptionsAre(8, false, false, false);\n\n    }\n\n    private void thenValidatorOptionsAre(int passwordMinimumLength, boolean passwordRequireDigits,\n            boolean passwordRequireBothCases, boolean passwordRequireSpecialChars) {\n\n        assertEquals(passwordMinimumLength, this.validatorOptions.isPasswordMinimumLength());\n        assertEquals(passwordRequireDigits, this.validatorOptions.isPasswordRequireDigits());\n        assertEquals(passwordRequireBothCases, this.validatorOptions.isPasswordRequireBothCases());\n        assertEquals(passwordRequireSpecialChars, this.validatorOptions.isPasswordRequireSpecialChars());\n\n    }\n\n    @Test\n    public void shouldUpdatedUser() throws InvalidSyntaxException {\n        givenIdentityService();\n        givenExistingUser(new UserDTO(\"testuser\", Collections.emptySet(), true, false, \"testpassw\"));\n\n        whenUpdatingUser(new UserDTO(\"testuser\", Collections.emptySet(), true, true, \"testpassw2\"));\n\n        thenNoExceptionOccurred();\n        thenUserIsUpdated();\n    }\n\n    @Test\n    public void shouldValidateRightPassword() {\n        givenIdentityService();\n\n        whenValidatingPassword(\"password123\");\n\n        thenNoExceptionOccurred();\n        thenPasswordValidationIs(true);\n    }\n\n    @Test\n    public void shouldNotValidateWrongPassword() {\n        givenIdentityService();\n\n        whenValidatingPassword(\"short\");\n\n        thenPasswordValidationIs(false);\n    }\n\n    private void whenValidatingPassword(String password) {\n        try {\n            this.identityService.validateUserPassword(password);\n            this.isPasswordValid = true;\n        } catch (Exception e) {\n            this.isPasswordValid = false;\n            this.occurredException = e;\n        }\n    }\n\n    private void givenIdentityService() {\n        this.cryptoService = mock(CryptoService.class);\n        this.userAdmin = mock(UserAdmin.class);\n        this.passwordStrengthVerificationService = mock(PasswordStrengthVerificationService.class);\n\n        try {\n            when(this.passwordStrengthVerificationService.getPasswordStrengthRequirements())\n                    .thenReturn(defaultPasswordStrengthRequirements());\n\n            when(this.cryptoService.sha256Hash(anyString())).thenReturn(\"sha256hash\");\n        } catch (KuraException | NoSuchAlgorithmException | UnsupportedEncodingException e) {\n            fail(\"fail to setup mocks\");\n        }\n\n        this.identityService = new LegacyIdentityService(this.cryptoService, this.userAdmin,\n                this.passwordStrengthVerificationService);\n\n    }\n\n    private void givenExistingUser(UserDTO user) {\n        this.user = user;\n\n        UserImpl userImpl = new UserImpl(this.user.getUserName(), this.user.getPassword(),\n                this.user.isPasswordChangeNeeded().get());\n\n        try {\n            when(this.userAdmin.getRole(USER_ROLE_NAME_PREFIX + user.getUserName())).thenReturn(userImpl);\n            when(this.userAdmin.getRoles(null)).thenReturn(new Role[] { userImpl });\n        } catch (InvalidSyntaxException e) {\n            fail(\"unable to setup mock user admin\");\n        }\n    }\n\n    private void givenExistingPermissions(Role... roles) throws InvalidSyntaxException {\n        when(this.userAdmin.getRoles(null)).thenReturn(roles);\n    }\n\n    private void whenCreatingUser(UserDTO newUser) {\n        try {\n            this.newUser = newUser;\n            when(this.userAdmin.createRole(USER_ROLE_NAME_PREFIX + newUser.getUserName(), Role.USER)).then(anser -> {\n\n                User userImpl = new UserImpl(newUser.getUserName(), newUser.getPassword(),\n                        newUser.isPasswordChangeNeeded().get());\n\n                when(this.userAdmin.getRole(USER_ROLE_NAME_PREFIX + newUser.getUserName())).thenReturn(userImpl);\n\n                return userImpl;\n            });\n            this.identityService.createUser(this.newUser);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenDeleting(String username) {\n        try {\n            this.identityService.deleteUser(username);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenGettingDefinedPermissions() {\n        this.definedPermissions = this.identityService.getDefinedPermissions();\n    }\n\n    private void whenGetUserConfig() {\n        this.userConfig = this.identityService.getUserConfig();\n    }\n\n    private void whenGettingValidatorOptions() {\n        try {\n            this.validatorOptions = this.identityService.getValidatorOptions();\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n\n    }\n\n    private void whenUpdatingUser(UserDTO user) {\n        this.user = user;\n        try {\n            this.identityService.updateUser(user);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenGettingUser(String username) {\n        try {\n            this.user = this.identityService.getUser(username);\n        } catch (KuraException e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void thenUserIsCreated() {\n        verify(this.userAdmin, times(1)).createRole(USER_ROLE_NAME_PREFIX + this.newUser.getUserName(), Role.USER);\n    }\n\n    private void thenUserIsDeleted() {\n        verify(this.userAdmin, times(1)).removeRole(USER_ROLE_NAME_PREFIX + this.user.getUserName());\n    }\n\n    private void thenPermissionsAre(String... permissions) {\n        assertTrue(new HashSet<>(this.definedPermissions).containsAll(Arrays.asList(permissions)));\n    }\n\n    private void thenUserIs(String username) {\n        assertEquals(username, this.user.getUserName());\n    }\n\n    private void thenConfigContains(UserDTO userDTO) {\n        assertTrue(this.userConfig.contains(userDTO));\n    }\n\n    private void thenUserIsUpdated() throws InvalidSyntaxException {\n        verify(this.userAdmin, times(1)).getRole(USER_ROLE_NAME_PREFIX + this.user.getUserName());\n        verify(this.userAdmin, times(1)).getRoles(null);\n    }\n\n    private void thenPasswordValidationIs(boolean expectedValue) {\n        assertEquals(expectedValue, this.isPasswordValid);\n\n    }\n\n    private void thenNoExceptionOccurred() {\n        String errorMessage = \"Empty message\";\n        if (Objects.nonNull(this.occurredException)) {\n            StringWriter sw = new StringWriter();\n            this.occurredException.printStackTrace(new PrintWriter(sw));\n\n            errorMessage = String.format(\"No exception expected, \\\"%s\\\" found. Caused by: %s\",\n                    this.occurredException.getClass().getName(), sw.toString());\n        }\n\n        assertNull(errorMessage, this.occurredException);\n    }\n\n    public static class PermissionRole implements Group {\n\n        private final String name;\n\n        public PermissionRole(String name) {\n            this.name = name;\n        }\n\n        @Override\n        public String getName() {\n            return PERMISSION_ROLE_NAME_PREFIX + this.name;\n\n        }\n\n        @Override\n        public int getType() {\n            return Role.GROUP;\n        }\n\n        @Override\n        public Dictionary<String, Object> getProperties() {\n            return null;\n        }\n\n        @Override\n        public Dictionary<String, Object> getCredentials() {\n            return null;\n        }\n\n        @Override\n        public boolean hasCredential(String key, Object value) {\n            return false;\n        }\n\n        @Override\n        public boolean addMember(Role role) {\n            return false;\n        }\n\n        @Override\n        public boolean addRequiredMember(Role role) {\n            return false;\n        }\n\n        @Override\n        public boolean removeMember(Role role) {\n            return false;\n        }\n\n        @Override\n        public Role[] getMembers() {\n            return null;\n        }\n\n        @Override\n        public Role[] getRequiredMembers() {\n            return null;\n        }\n    }\n\n    public static class UserImpl implements User {\n\n        private final String name;\n        private final String password;\n        private final boolean needPasswordChange;\n\n        public UserImpl(String name, String password, boolean needPasswordChange) {\n            this.name = name;\n            this.password = password;\n            this.needPasswordChange = needPasswordChange;\n        }\n\n        @Override\n        public String getName() {\n            return USER_ROLE_NAME_PREFIX + this.name;\n        }\n\n        @Override\n        public int getType() {\n            return Role.USER;\n        }\n\n        @Override\n        public Dictionary<String, Object> getProperties() {\n            Dictionary<String, Object> properties = new Hashtable<>();\n            properties.put(\"kura.need.password.change\", this.needPasswordChange);\n            return properties;\n        }\n\n        @Override\n        public boolean hasCredential(String key, Object value) {\n            return true;\n        }\n\n        @Override\n        public Dictionary<String, Object> getCredentials() {\n            Dictionary<String, Object> credentials = new Hashtable<>();\n            credentials.put(\"kura.password\", this.password);\n\n            return credentials;\n        }\n    }\n\n    private static PasswordStrengthRequirements defaultPasswordStrengthRequirements() {\n        return new PasswordStrengthRequirements(8, false, false, false);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.inventory.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.inventory.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.inventory.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.core.inventory;version=\"1.0.0\",\n org.eclipse.kura;version=\"1.6.0\",\n org.eclipse.kura.core.util;version=\"1.3.0\",\n org.eclipse.kura.message;version=\"1.4.0\",\n org.junit;version=\"[4.12,5.0)\",\n org.junit.rules;version=\"[4.12,5.0)\",\n org.junit.experimental.runners;version=\"[4.12,5.0)\",\n org.eclipse.kura.cloudconnection.message;version=\"[1.0,2.0)\",\n org.junit.runner;version=\"[4.12,5.0)\",\n org.junit.runners;version=\"[4.12,5.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.slf4j;version=\"1.6.4\"\nFragment-Host: org.eclipse.kura.rest.inventory.provider\n\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.inventory.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.inventory.provider.test/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.inventory.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               ."
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.inventory.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.rest.inventory.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.inventory.provider.test/src/main/java/org/eclipse/kura/rest/inventory/provider/test/InventoryRestServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.inventory.provider.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.core.inventory.InventoryHandlerV1;\nimport org.eclipse.kura.internal.rest.inventory.InventoryRestService;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.junit.Test;\nimport org.mockito.ArgumentCaptor;\n\npublic class InventoryRestServiceTest {\n\n    private static final String ARGS_KEY = \"args\";\n\n    InventoryHandlerV1 inventoryHandlerV1;\n    InventoryRestService inventoryRestService;\n    Boolean hasExceptionOccured = false;\n\n    private ArgumentCaptor<KuraMessage> kuraPayloadArgumentCaptor = ArgumentCaptor.forClass(KuraMessage.class);\n\n    @Test\n    public void listInventoryTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenGetInventorySummary();\n\n        thenVerifyDoGetIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"inventory\"), \"\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void listBundlesTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenGetBundles();\n\n        thenVerifyDoGetIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"bundles\"), \"\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void startBundlesTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenStartBundles(\"{ \\\"name\\\":\\\"org.eclipse.kura.example.publisher\\\"}\");\n\n        thenVerifyDoExecIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"bundles\", \"_start\"),\n                \"{ \\\"name\\\":\\\"org.eclipse.kura.example.publisher\\\"}\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void stopBundlesTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenStopBundles(\"{ \\\"name\\\":\\\"org.eclipse.kura.example.publisher\\\"}\");\n\n        thenVerifyDoExecIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"bundles\", \"_stop\"), \"{ \\\"name\\\":\\\"org.eclipse.kura.example.publisher\\\"}\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void listDeploymentPackagesTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenGetDeploymentPackages();\n\n        thenVerifyDoGetIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"deploymentPackages\"), \"\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void listSystemPackagesTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenGetSystemPackages();\n\n        thenVerifyDoGetIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"systemPackages\"), \"\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void listContainersTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenGetContainers();\n\n        thenVerifyDoGetIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"containers\"), \"\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void startContainerTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenStartContainer(\"{ \\\"name\\\":\\\"kura-test-container\\\"}\");\n\n        thenVerifyDoExecIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"containers\", \"_start\"), \"{ \\\"name\\\":\\\"kura-test-container\\\"}\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void stopContainerTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenStopContainer(\"{ \\\"name\\\":\\\"kura-test-container\\\"}\");\n\n        thenVerifyDoExecIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"containers\", \"_stop\"), \"{ \\\"name\\\":\\\"kura-test-container\\\"}\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void listImagesTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenGetImages();\n\n        thenVerifyDoGetIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"images\"), \"\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    @Test\n    public void deleteImageTest() throws KuraException {\n        givenInventoryHandler();\n        givenInventoryRestService();\n\n        whenDeleteImage(\"{ \\\"name\\\":\\\"nginx\\\"}\");\n\n        thenVerifyDoExecIsRun();\n        thenInventoryRequestIs(Arrays.asList(\"images\", \"_delete\"), \"{ \\\"name\\\":\\\"nginx\\\"}\");\n        thenVerifyNoExceptionOccurred();\n    }\n\n    private void givenInventoryHandler() throws KuraException {\n        inventoryHandlerV1 = mock(InventoryHandlerV1.class);\n\n        KuraResponsePayload fakeKuraPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK);\n        KuraMessage fakeKuraMessage = new KuraMessage(fakeKuraPayload);\n\n        when(inventoryHandlerV1.doGet(any(), any())).thenReturn(fakeKuraMessage);\n        when(inventoryHandlerV1.doExec(any(), any())).thenReturn(fakeKuraMessage);\n    }\n\n    private void givenInventoryRestService() {\n        inventoryRestService = new InventoryRestService();\n        inventoryRestService.setInventoryHandlerV1(inventoryHandlerV1);\n    }\n\n    private void whenGetInventorySummary() {\n        try {\n            inventoryRestService.getInventorySummary();\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenGetBundles() {\n        try {\n            inventoryRestService.getBundles();\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenStartBundles(String jsonArgument) {\n        try {\n            inventoryRestService.startBundle(jsonArgument);\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenStopBundles(String jsonArgument) {\n        try {\n            inventoryRestService.stopBundle(jsonArgument);\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenGetDeploymentPackages() {\n        try {\n            inventoryRestService.getDeploymentPackages();\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenGetSystemPackages() {\n        try {\n            inventoryRestService.getSystemPackages();\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenGetContainers() {\n        try {\n            inventoryRestService.getContainers();\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenStartContainer(String jsonArgument) {\n        try {\n            inventoryRestService.startContainer(jsonArgument);\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenStopContainer(String jsonArgument) {\n        try {\n            inventoryRestService.stopContainer(jsonArgument);\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenGetImages() {\n        try {\n            inventoryRestService.getImages();\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void whenDeleteImage(String jsonArgument) {\n        try {\n            inventoryRestService.deleteImage(jsonArgument);\n        } catch (Exception e) {\n            hasExceptionOccured = true;\n        }\n    }\n\n    private void thenVerifyDoGetIsRun() throws KuraException {\n        verify(inventoryHandlerV1).doGet(any(), kuraPayloadArgumentCaptor.capture());\n    }\n\n    private void thenVerifyDoExecIsRun() throws KuraException {\n        verify(inventoryHandlerV1).doExec(any(), kuraPayloadArgumentCaptor.capture());\n    }\n\n    private void thenInventoryRequestIs(List<String> expectedArgs, String expectedBody) {\n        KuraMessage receivedKuraPayload = kuraPayloadArgumentCaptor.getValue();\n\n        assertEquals(expectedArgs, receivedKuraPayload.getProperties().get(ARGS_KEY));\n        assertEquals(expectedBody, new String(receivedKuraPayload.getPayload().getBody()));\n    }\n\n    private void thenVerifyNoExceptionOccurred() {\n        assertFalse(hasExceptionOccured);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.keystore.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.keystore.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.keystore.provider.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: com.eclipsesource.json;version=\"0.9.5\",\n javax.servlet;version=\"3.1.0\",\n javax.servlet.http;version=\"3.1.0\",\n org.apache.commons.io;version=\"2.11.0\",\n org.bouncycastle.asn1.x500;version=\"1.78.1\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.core.crypto,\n org.eclipse.kura.core.keystore.util;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.http;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.pki;version=\"[1.1.0,2.0.0)\",\n org.eclipse.kura.core.testutil.requesthandler;version=\"1.2.0\",\n org.eclipse.kura.core.testutil.service;version=\"1.0.0\",\n org.eclipse.kura.security.keystore;version=\"[1.0,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.slf4j;version=\"1.6.4\"\nFragment-Host: org.eclipse.kura.rest.keystore.provider\nRequire-Bundle: org.eclipse.kura.http.server.manager;bundle-version=\"1.4.0\",\n org.junit\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.keystore.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.keystore.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.keystore.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.rest.keystore.provider.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n    \n    <build>\n       <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.keystore.provider.test/src/main/java/org/eclipse/kura/rest/keystore/provider/KeystoreRequestHandlerV2Test.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.keystore.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.security.KeyPair;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.PrivateKey;\nimport java.security.cert.Certificate;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\nimport org.bouncycastle.asn1.x500.X500Name;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.pki.TestCA;\nimport org.eclipse.kura.core.testutil.pki.TestCA.CertificateCreationOptions;\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.junit.runners.Parameterized.Parameters;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\n\n@RunWith(Parameterized.class)\npublic class KeystoreRequestHandlerV2Test extends AbstractRequestHandlerTest {\n\n    @Test\n    public void shouldUploadSimplePrivateKeyEntry() {\n        givenKeystoreService(\"bar\");\n        givenKeyPair(\"leaf\");\n\n        whenKeyPairIsUploaded(\"bar\", \"testalias\", true);\n        thenRequestSucceeds();\n        thenKeystoreEntryEqualsCurrentKeyPair(\"bar\", \"testalias\");\n    }\n\n    @Test\n    public void shouldUploadPrivateKeyEntryWithMultipleCertificatesInChain() {\n        givenKeystoreService(\"foo\");\n        givenKeyPair(\"ca\", \"leaf\");\n\n        whenKeyPairIsUploaded(\"foo\", \"testalias\", true);\n        thenRequestSucceeds();\n        thenKeystoreEntryEqualsCurrentKeyPair(\"foo\", \"testalias\");\n    }\n\n    @Test\n    public void shouldUpdateSimplePrivateKeyEntry() {\n        givenKeystoreService(\"bar\");\n        givenKeyPairInKeystore(\"bar\", \"testalias\", \"leaf\");\n        givenNewLeafCert(\"otherleaf\");\n\n        whenKeyPairIsUploaded(\"bar\", \"testalias\", false);\n        thenRequestSucceeds();\n        thenKeystoreEntryEqualsCurrentKeyPair(\"bar\", \"testalias\");\n    }\n\n    @Test\n    public void shouldUpdatePrivateKeyEntryWithMultipleCertificatesInChain() {\n        givenKeystoreService(\"foo\");\n        givenKeyPairInKeystore(\"foo\", \"testalias\", \"ca\", \"leaf\");\n        givenNewLeafCert(\"otherleaf\");\n\n        whenKeyPairIsUploaded(\"foo\", \"testalias\", false);\n        thenRequestSucceeds();\n        thenKeystoreEntryEqualsCurrentKeyPair(\"foo\", \"testalias\");\n    }\n\n    @Test\n    public void shouldRejectEmptyRequestObject() {\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), privateKeyRespurceURI, \"{}\");\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectRequestObjectWithoutPid() {\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), privateKeyRespurceURI,\n                \"{\\\"alias\\\":\\\"foo\\\",\\\"privateKey\\\":\\\"bar\\\",\\\"certificateChain\\\":[\\\"foo\\\"]}\");\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectRequestObjectWithoutAlias() {\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), privateKeyRespurceURI,\n                \"{\\\"keystoreServicePid\\\":\\\"foo\\\",\\\"privateKey\\\":\\\"bar\\\",\\\"certificateChain\\\":[\\\"foo\\\"]}\");\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectRequestObjectWithoutCertificateChain() {\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), privateKeyRespurceURI,\n                \"{\\\"keystoreServicePid\\\":\\\"foo\\\",\\\"alias\\\":\\\"bar\\\",\\\"privateKey\\\":\\\"bar\\\"}\");\n        thenResponseCodeIs(400);\n    }\n\n    @Parameters\n    public static Collection<Object[]> parameters() {\n        return Arrays.asList(\n                new Object[] { new RestTransport(\"keystores/v2\"), \"/entries/privatekey\" },\n                new Object[] { new MqttTransport(\"KEYS-V2\"), \"/keystores/entries/privatekey\" });\n    }\n\n    public KeystoreRequestHandlerV2Test(final Transport transport, final String privateKeyRespurceURI) {\n        super(transport);\n        this.privateKeyRespurceURI = privateKeyRespurceURI;\n    }\n\n    private final String privateKeyRespurceURI;\n    private final Map<String, KeystoreService> createdKeystoreServices = new HashMap<>();\n\n    private KeyPair leafKeyPair;\n    private String leafKeyPem;\n    private List<String> certificateChainPem = new ArrayList<>();\n\n    private PrivateKey leafKey;\n    private List<X509Certificate> certificateChain = new ArrayList<>();\n\n    private TestCA testCA;\n\n    private void givenKeystoreService(final String pid) {\n        try {\n            final Path dir = Files.createTempDirectory(null);\n            final String keystorePath = dir.toFile().getAbsolutePath() + \"/\" + System.currentTimeMillis() + \".ks\";\n\n            final ConfigurationService configurationService = ServiceUtil\n                    .trackService(ConfigurationService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n            final KeystoreService keystoreService = ServiceUtil\n                    .createFactoryConfiguration(configurationService, KeystoreService.class, pid,\n                            \"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\",\n                            Collections.singletonMap(\"keystore.path\", keystorePath))\n                    .get(30, TimeUnit.SECONDS);\n\n            this.createdKeystoreServices.put(pid, keystoreService);\n\n        } catch (final Exception e) {\n            fail(\"failed to create test keystore\");\n        }\n    }\n\n    private void givenKeyPair(final String leafCN) {\n        givenKeyPair(\"foo\", leafCN, false);\n    }\n\n    private void givenKeyPairInKeystore(final String keystorePid, final String alias, final String leafCN) {\n        givenKeyPair(leafCN);\n\n        storeCurrentKeyPair(keystorePid, alias);\n    }\n\n    private void givenKeyPair(final String caCN, final String leafCN) {\n        givenKeyPair(caCN, leafCN, true);\n    }\n\n    private void givenKeyPairInKeystore(final String keystorePid, final String alias, final String caCN,\n            final String leafCN) {\n        givenKeyPair(caCN, leafCN);\n\n        storeCurrentKeyPair(keystorePid, alias);\n    }\n\n    private void givenKeyPair(final String caCN, final String leafCN, final boolean includeCA) {\n        try {\n            this.testCA = new TestCA(\n                    CertificateCreationOptions.builder(new X500Name(\"cn=\" + caCN + \", dc=bar.com\")).build());\n\n            this.leafKeyPair = TestCA.generateKeyPair();\n\n            this.leafKey = this.leafKeyPair.getPrivate();\n            this.leafKeyPem = privateKeyToPEMString(this.leafKeyPair.getPrivate());\n\n            final X509Certificate leafCert = testCA.createAndSignCertificate(\n                    CertificateCreationOptions.builder(new X500Name(\"cn=\" + leafCN + \", dc=bar.com\")).build(),\n                    this.leafKeyPair);\n\n            this.certificateChain.clear();\n            this.certificateChainPem.clear();\n            this.certificateChain.add(leafCert);\n            this.certificateChainPem.add(certificateToPEMString(leafCert));\n\n            if (includeCA) {\n                this.certificateChain.add(testCA.getCertificate());\n                this.certificateChainPem.add(certificateToPEMString(testCA.getCertificate()));\n            }\n\n        } catch (Exception e) {\n            fail(\"cannot cerate test certificate chain\");\n        }\n    }\n\n    private void givenNewLeafCert(final String leafCN) {\n        try {\n            final X509Certificate leafCert = this.testCA.createAndSignCertificate(\n                    CertificateCreationOptions.builder(new X500Name(\"cn=\" + leafCN + \", dc=bar.com\")).build(),\n                    this.leafKeyPair);\n\n            this.certificateChain.set(0, leafCert);\n            this.certificateChainPem.set(0, certificateToPEMString(leafCert));\n        } catch (Exception e) {\n            fail(\"cannot cerate new certificate\");\n        }\n    }\n\n    private void storeCurrentKeyPair(final String keystorePid, final String alias) {\n        try {\n            this.createdKeystoreServices.get(keystorePid).setEntry(alias,\n                    new PrivateKeyEntry(this.leafKey, this.certificateChain.toArray(new X509Certificate[0])));\n        } catch (final Exception e) {\n            fail(\"cannot store certificate chain\");\n        }\n    }\n\n    private void whenKeyPairIsUploaded(final String keystorePid, final String alias,\n            final boolean includePrivateKey) {\n        final JsonObject object = Json.object();\n        if (includePrivateKey) {\n            object.add(\"privateKey\", this.leafKeyPem);\n        }\n\n        final JsonArray chain = Json.array();\n        for (final String cert : certificateChainPem) {\n            chain.add(cert);\n        }\n\n        object.add(\"certificateChain\", chain);\n        object.add(\"keystoreServicePid\", keystorePid);\n        object.add(\"alias\", alias);\n\n        whenRequestIsPerformed(new MethodSpec(\"POST\"), privateKeyRespurceURI,\n                object.toString());\n    }\n\n    private void thenKeystoreEntryEqualsCurrentKeyPair(final String pid, final String alias) {\n        try {\n            final PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) this.createdKeystoreServices.get(pid)\n                    .getEntry(alias);\n\n            assertEquals(this.leafKeyPem, privateKeyToPEMString(privateKeyEntry.getPrivateKey()));\n\n            final List<String> entryCertificatesAsPem = new ArrayList<>();\n\n            for (final Certificate cert : privateKeyEntry.getCertificateChain()) {\n                entryCertificatesAsPem.add(certificateToPEMString((X509Certificate) cert));\n            }\n\n            assertEquals(this.certificateChainPem, entryCertificatesAsPem);\n        } catch (KuraException | IOException e) {\n            fail(\"Unable to retrieve keystore entry\");\n        }\n    }\n\n    @After\n    public void cleanupKeystoreServices() {\n        try {\n            final ConfigurationService configurationService = ServiceUtil\n                    .trackService(ConfigurationService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n            for (final String pid : createdKeystoreServices.keySet()) {\n                ServiceUtil.deleteFactoryConfiguration(configurationService, pid).get(30, TimeUnit.SECONDS);\n            }\n        } catch (Exception e) {\n            fail(\"failed to delete test keystore\");\n        }\n    }\n\n    private String certificateToPEMString(final X509Certificate cert) throws IOException {\n        try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {\n            TestCA.encodeToPEM(cert, out);\n            return new String(out.toByteArray(), StandardCharsets.UTF_8);\n        }\n    }\n\n    private String privateKeyToPEMString(final PrivateKey key) throws IOException {\n        try (final ByteArrayOutputStream out = new ByteArrayOutputStream()) {\n            TestCA.encodeToPEM(key, out);\n            return new String(out.toByteArray(), StandardCharsets.UTF_8);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.keystore.provider.test/src/test/java/org/eclipse/kura/rest/keystore/provider/KeystoreRestServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.keystore.provider;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\nimport static org.mockito.Mockito.when;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyStore;\nimport java.security.KeyStore.Entry;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.keystore.util.CertificateInfo;\nimport org.eclipse.kura.core.keystore.util.EntryInfo;\nimport org.eclipse.kura.core.keystore.util.EntryType;\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.internal.rest.keystore.provider.CsrResponse;\nimport org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestService;\nimport org.eclipse.kura.internal.rest.keystore.request.CsrReadRequest;\nimport org.eclipse.kura.internal.rest.keystore.request.EntryRequest;\nimport org.eclipse.kura.internal.rest.keystore.request.KeyPairWriteRequest;\nimport org.eclipse.kura.internal.rest.keystore.request.TrustedCertificateWriteRequest;\nimport org.eclipse.kura.security.keystore.KeystoreInfo;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.junit.Test;\nimport org.osgi.service.component.ComponentContext;\n\npublic class KeystoreRestServiceTest {\n\n    private final String CERTIFICATE_RSA = \"-----BEGIN CERTIFICATE-----\\n\"\n            + \"MIIDdzCCAl+gAwIBAgIEQsO0gDANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV\\n\"\n            + \"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\\n\"\n            + \"VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du\\n\"\n            + \"MB4XDTIxMDQxNDA4MDIyOFoXDTIxMDcxMzA4MDIyOFowbDEQMA4GA1UEBhMHVW5r\\n\"\n            + \"bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE\\n\"\n            + \"ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC\\n\"\n            + \"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJSWJDxu8UNC4JGOgK31WCvz\\n\"\n            + \"NKy2ONH+jTVKnBY7Ckb1hljJY0sKO55aG1HNDfkev2lJTsPIz0nJjNsqBvB1flvf\\n\"\n            + \"r6XVCxdN0yxvU5g9SpRxE/iiPX0Qt7463OfzyKW97haJrrhF005RHYNcORMY/Phj\\n\"\n            + \"hFDnZhtAwpbQLzq2UuIZ7okJsx0IgRbjH71ZZuvYCqG7Ct/bp1D7w3tT7gTbIKYH\\n\"\n            + \"ppQyG9rJDEh9+cr9Hyk8Gz7aAbPT/wMH+/vXDjH2j/M1Tmed0ajuGCJumaTQ4eHs\\n\"\n            + \"9xW3B3ugycb6e7Osl/4ESRO5RQL1k2GBONv10OrKDoZ5b66xwSJmC/w3BRWQ1cMC\\n\"\n            + \"AwEAAaMhMB8wHQYDVR0OBBYEFPospETb5HNeD/DmS9mwt+v/AYq/MA0GCSqGSIb3\\n\"\n            + \"DQEBCwUAA4IBAQBxMe1xQVQKt36A5qVlEZyxI9eb6eQRlYzorOgP2tFaOsvDPpRI\\n\"\n            + \"CALhPmxgQl/5QvKFfCXKoxWj1Spg4sF6fJp6jhSjLpmChS9lf5fRaWS20/pxIddM\\n\"\n            + \"10diq3r6HxLKSxCYK7Pf5scOeZquvwfo8Kxye01bvCMFf1s1K3ZEZszk5Oo2MnWU\\n\"\n            + \"U22YnXfZm1C0h2WMUcou35A7CeVAHPWI0Rvefojv1qYlQScJOkCN5lO6C/1qvRhq\\n\"\n            + \"nDQdQN/m1HQbpfh2DD6F33nBjkyLQyMRF8uMnspLrLLj8lecSTJZO4fGJOaIXh3O\\n\"\n            + \"44da9A02FAf5nRRQpwP2x/4IZ5RTRBzrqbqD\\n\" + \"-----END CERTIFICATE-----\";\n    private final String CERTIFICATE_DSA = \"-----BEGIN CERTIFICATE-----\\n\"\n            + \"MIIDODCCAvSgAwIBAgIERIUjyDANBglghkgBZQMEAwIFADBsMRAwDgYDVQQGEwdV\\n\"\n            + \"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\\n\"\n            + \"VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du\\n\"\n            + \"MB4XDTIxMDQxMzA4MTk0M1oXDTIxMDcxMjA4MTk0M1owbDEQMA4GA1UEBhMHVW5r\\n\"\n            + \"bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE\\n\"\n            + \"ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC\\n\"\n            + \"AbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADD\\n\"\n            + \"Hj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gE\\n\"\n            + \"exAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/Ii\\n\"\n            + \"Axmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4\\n\"\n            + \"V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozI\\n\"\n            + \"puE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4Vrl\\n\"\n            + \"nwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgDJAY6FsVu1ibRVd4XIn/VLHJ1GJrFFK\\n\"\n            + \"d0I9u76h1KYbO+buEqmRIrnpUMXjErYwad+wc+Fe5/kGhhCKfEts3yNVwNvuLsNU\\n\"\n            + \"kVmdTC8vI3BqlyV2F+9Ekar2ogiqtE+BxNPHMEOGIXOJMjSMSWsOHaMOM2c29bXy\\n\"\n            + \"IdZr1ENwcPZloyEwHzAdBgNVHQ4EFgQUQa440XL4ulW3fLrOHq7uWiKo/UYwDQYJ\\n\"\n            + \"YIZIAWUDBAMCBQADLwAwLAIUbWlpb/M22woaHk/uCyscfbEJqv4CFFPG75R7jtvz\\n\" + \"FllKUJXh+xxmMVfc\\n\"\n            + \"-----END CERTIFICATE-----\";\n    private final String CERTIFICATE_EC = \"-----BEGIN CERTIFICATE-----\\n\"\n            + \"MIIB7zCCAZOgAwIBAgIEc21cijAMBggqhkjOPQQDAgUAMGwxEDAOBgNVBAYTB1Vu\\n\"\n            + \"a25vd24xEDAOBgNVBAgTB1Vua25vd24xEDAOBgNVBAcTB1Vua25vd24xEDAOBgNV\\n\"\n            + \"BAoTB1Vua25vd24xEDAOBgNVBAsTB1Vua25vd24xEDAOBgNVBAMTB1Vua25vd24w\\n\"\n            + \"HhcNMjEwNDIwMDkwNTA1WhcNMjEwNzE5MDkwNTA1WjBsMRAwDgYDVQQGEwdVbmtu\\n\"\n            + \"b3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYDVQQK\\n\"\n            + \"EwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3duMFkw\\n\"\n            + \"EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEASCbfb0l60WEkKVAgKFvPslueJE2ppKQ\\n\"\n            + \"aa6AfQnGHnhGvKtRMVOMpy96aZPcYWdpX9323DMMPyhbosE/GjK5sqMhMB8wHQYD\\n\"\n            + \"VR0OBBYEFJ+MTQRX0X4ihcyt9h9+ODxCh/5LMAwGCCqGSM49BAMCBQADSAAwRQIh\\n\"\n            + \"AISr/AGgA2FwJeZFPKB2KEoWPCPsPMpBgA4KrsoJBQmVAiBAkLzQIUWad1cvyEUn\\n\" + \"WNntICChHGdKmvPhWZSQ6n61ew==\\n\"\n            + \"-----END CERTIFICATE-----\";\n\n    @Test\n    public void listKeystoresTest() throws KuraException, IOException, GeneralSecurityException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n\n        KeystoreRestService krs = new KeystoreRestService() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        krs.activate(null);\n\n        List<KeystoreInfo> keystores = krs.listKeystores();\n\n        List<String> types = Arrays.asList(\"JKS\", \"PKCS12\");\n        assertEquals(1, keystores.size());\n        assertTrue(types.contains(keystores.get(0).getType()));\n        assertEquals(0, keystores.get(0).getSize());\n    }\n\n    @Test\n    public void listKeysTest() throws KuraException, IOException, GeneralSecurityException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        ByteArrayInputStream is = new ByteArrayInputStream(this.CERTIFICATE_RSA.getBytes());\n        X509Certificate cert = (X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        ks.setCertificateEntry(\"alias\", cert);\n        Map<String, Entry> certs = new HashMap<>();\n        certs.put(\"alias\", new KeyStore.TrustedCertificateEntry(cert));\n        when(ksMock.getKeyStore()).thenReturn(ks);\n        when(ksMock.getEntries()).thenReturn(certs);\n\n        KeystoreRestService krs = new KeystoreRestService() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        krs.activate(null);\n\n        List<EntryInfo> keys = krs.getEntries(null, null);\n\n        assertEquals(1, keys.size());\n        assertTrue(keys.get(0) instanceof CertificateInfo);\n        CertificateInfo result = (CertificateInfo) keys.get(0);\n        assertEquals(\"alias\", result.getAlias());\n        assertEquals(\"MyKeystore\", result.getKeystoreServicePid());\n        assertEquals(EntryType.TRUSTED_CERTIFICATE, result.getType());\n        assertEquals(2048, result.getSize());\n        assertEquals(\"SHA256withRSA\", result.getAlgorithm());\n    }\n\n    @Test\n    public void listKeysTestWithId() throws KuraException, IOException, GeneralSecurityException, NoSuchFieldException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        ByteArrayInputStream is = new ByteArrayInputStream(this.CERTIFICATE_DSA.getBytes());\n        X509Certificate cert = (X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        ks.setCertificateEntry(\"alias\", cert);\n        Map<String, Entry> certs = new HashMap<>();\n        certs.put(\"alias\", new KeyStore.TrustedCertificateEntry(cert));\n        when(ksMock.getKeyStore()).thenReturn(ks);\n        when(ksMock.getEntries()).thenReturn(certs);\n\n        KeystoreRestService krs = new KeystoreRestService() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        krs.activate(null);\n\n        List<EntryInfo> keys = krs.getEntries(\"MyKeystore\", null);\n\n        assertEquals(1, keys.size());\n        assertTrue(keys.get(0) instanceof CertificateInfo);\n        CertificateInfo result = (CertificateInfo) keys.get(0);\n        assertEquals(\"alias\", result.getAlias());\n        assertEquals(\"MyKeystore\", result.getKeystoreServicePid());\n        assertEquals(EntryType.TRUSTED_CERTIFICATE, result.getType());\n        assertEquals(1024, result.getSize());\n        assertEquals(\"SHA256withDSA\", result.getAlgorithm());\n        assertEquals(this.CERTIFICATE_DSA, result.getCertificate());\n    }\n\n    @Test\n    public void listKeyTest() throws KuraException, IOException, GeneralSecurityException, NoSuchFieldException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        ByteArrayInputStream is = new ByteArrayInputStream(this.CERTIFICATE_EC.getBytes());\n        X509Certificate cert = (X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        ks.setCertificateEntry(\"alias\", cert);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n        when(ksMock.getEntry(\"alias\")).thenReturn(new KeyStore.TrustedCertificateEntry(cert));\n\n        KeystoreRestService krs = new KeystoreRestService() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        krs.activate(null);\n\n        EntryInfo key = krs.getEntry(\"MyKeystore\", \"alias\");\n\n        assertTrue(key instanceof CertificateInfo);\n        CertificateInfo result = (CertificateInfo) key;\n        assertEquals(\"alias\", result.getAlias());\n        assertEquals(\"MyKeystore\", result.getKeystoreServicePid());\n        assertEquals(EntryType.TRUSTED_CERTIFICATE, result.getType());\n        assertEquals(256, result.getSize());\n        assertEquals(\"SHA256withECDSA\", result.getAlgorithm());\n        assertEquals(this.CERTIFICATE_EC, result.getCertificate());\n    }\n\n    @Test\n    public void storeKeyEntryCertTest()\n            throws KuraException, IOException, GeneralSecurityException, NoSuchFieldException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n\n        KeystoreRestService krs = new KeystoreRestService() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        krs.activate(null);\n\n        TrustedCertificateWriteRequest writeRequest = new TrustedCertificateWriteRequest(\"MyKeystore\", \"MyAlias\");\n        TestUtil.setFieldValue(writeRequest, \"certificate\", this.CERTIFICATE_RSA);\n        krs.storeTrustedCertificateEntry(writeRequest);\n\n        verify(ksMock, times(1)).setEntry(eq(\"MyAlias\"), any(TrustedCertificateEntry.class));\n\n    }\n\n    @Test\n    public void deleteKeyEntryTest() throws KuraException, IOException, GeneralSecurityException, NoSuchFieldException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n\n        KeystoreRestService krs = new KeystoreRestService() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        krs.activate(null);\n\n        EntryRequest deleteRequest = new EntryRequest(\"MyKeystore\", \"MyAlias\");\n\n        krs.deleteKeyEntry(deleteRequest);\n        verify(ksMock).deleteEntry(\"MyAlias\");\n    }\n\n    @Test\n    public void createKeyPairTest() throws KuraException, IOException, GeneralSecurityException, NoSuchFieldException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n\n        KeystoreRestService krs = new KeystoreRestService() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        krs.activate(null);\n\n        KeyPairWriteRequest writeRequest = new KeyPairWriteRequest(\"MyKeystore\", \"MyAlias\");\n        TestUtil.setFieldValue(writeRequest, \"algorithm\", \"RSA\");\n        TestUtil.setFieldValue(writeRequest, \"signatureAlgorithm\", \"SHA256WithRSA\");\n        TestUtil.setFieldValue(writeRequest, \"size\", 1024);\n        TestUtil.setFieldValue(writeRequest, \"attributes\", \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n\n        krs.storeKeypairEntry(writeRequest);\n\n        verify(ksMock, times(1)).createKeyPair(\"MyAlias\", \"RSA\", 1024, \"SHA256WithRSA\",\n                \"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n    }\n\n    @Test\n    public void getCSRTest() throws KuraException, IOException, GeneralSecurityException, NoSuchFieldException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n        when(ksMock.getCSR(eq(\"MyAlias\"), any(), eq(\"SHA256WithRSA\")))\n                .thenReturn(\"-----BEGIN CERTIFICATE REQUEST-----\");\n\n        KeystoreRestService krs = new KeystoreRestService() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        krs.activate(null);\n\n        KeyPairWriteRequest writeRequest = new KeyPairWriteRequest(\"MyKeystore\", \"MyAlias\");\n        writeRequest.setAlgorithm(\"RSA\");\n        writeRequest.setSignatureAlgorithm(\"SHA256WithRSA\");\n        writeRequest.setSize(1024);\n        writeRequest.setAttributes(\"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n\n        krs.storeKeypairEntry(writeRequest);\n\n        CsrReadRequest readRequest = new CsrReadRequest(\"MyKeystore\", \"MyAlias\");\n        readRequest.setSignatureAlgorithm(\"SHA256WithRSA\");\n        readRequest.setAttributes(\"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n\n        CsrResponse csr = krs.getCSR(readRequest);\n        assertNotNull(csr);\n        assertTrue(csr.getSigningRequest().startsWith(\"-----BEGIN CERTIFICATE REQUEST-----\"));\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.keystore.provider.test/src/test/java/org/eclipse/kura/rest/keystore/provider/request/handler/KeystoreServiceRequestHandlerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.keystore.provider.request.handler;\n\nimport static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.nio.charset.StandardCharsets;\nimport java.security.GeneralSecurityException;\nimport java.security.KeyStore;\nimport java.security.KeyStore.Entry;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.PrivateKey;\nimport java.security.Security;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport javax.security.auth.x500.X500Principal;\n\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\nimport org.bouncycastle.openssl.PEMParser;\nimport org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.message.KuraMessage;\nimport org.eclipse.kura.core.keystore.util.CertificateInfo;\nimport org.eclipse.kura.core.keystore.util.CsrInfo;\nimport org.eclipse.kura.core.keystore.util.EntryInfo;\nimport org.eclipse.kura.core.keystore.util.KeyPairInfo;\nimport org.eclipse.kura.core.keystore.util.PrivateKeyInfo;\nimport org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreServiceRequestHandlerV1;\nimport org.eclipse.kura.message.KuraRequestPayload;\nimport org.eclipse.kura.message.KuraResponsePayload;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.junit.Test;\nimport org.osgi.service.component.ComponentContext;\n\nimport com.google.gson.JsonArray;\nimport com.google.gson.JsonObject;\nimport com.google.gson.JsonParser;\n\npublic class KeystoreServiceRequestHandlerTest {\n\n    private static final String ENTRIES_RESOURCE = \"entries\";\n    private static final String ENTRY_RESOURCE = \"entry\";\n    private static final String KEYSTORES_RESOURCE = \"keystores\";\n    private static final String CERTIFICATE_RESOURCE = \"certificate\";\n    private static final String KEYPAIR_RESOURCE = \"keypair\";\n    private final String EMPTY_KEYSTORE_1 = \"[{\\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\\"type\\\":\\\"JKS\\\",\\\"size\\\":0}]\";\n    private final String EMPTY_KEYSTORE_2 = \"[{\\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\\"type\\\":\\\"PKCS12\\\",\\\"size\\\":0}]\";\n    private final String KEYSTORE_ENTRY = \"[{\\\"subjectDN\\\":\\\"CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown\\\",\\\"issuer\\\":\\\"CN=Unknown,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown\\\",\\\"startDate\\\":1618387348000,\\\"expirationDate\\\":1626163348000,\\\"algorithm\\\":\\\"SHA256withRSA\\\",\\\"size\\\":2048,\\\"type\\\":\\\"TRUSTED_CERTIFICATE\\\",\\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\\"alias\\\":\\\"alias\\\"}]\";\n    private final String KEYSTORE_ENTRY_WITH_CERT = \"{\\\"subjectDN\\\":\\\"CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown\\\",\\\"issuer\\\":\\\"CN=Unknown,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown\\\",\\\"startDate\\\":1618387348000,\\\"expirationDate\\\":1626163348000,\\\"algorithm\\\":\\\"SHA256withRSA\\\",\\\"size\\\":2048,\\\"certificate\\\":\\\"-----BEGIN CERTIFICATE-----\\\\nMIIDdzCCAl+gAwIBAgIEQsO0gDANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV\\\\nbmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\\\\nVQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du\\\\nMB4XDTIxMDQxNDA4MDIyOFoXDTIxMDcxMzA4MDIyOFowbDEQMA4GA1UEBhMHVW5r\\\\nbm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE\\\\nChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC\\\\nASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJSWJDxu8UNC4JGOgK31WCvz\\\\nNKy2ONH+jTVKnBY7Ckb1hljJY0sKO55aG1HNDfkev2lJTsPIz0nJjNsqBvB1flvf\\\\nr6XVCxdN0yxvU5g9SpRxE/iiPX0Qt7463OfzyKW97haJrrhF005RHYNcORMY/Phj\\\\nhFDnZhtAwpbQLzq2UuIZ7okJsx0IgRbjH71ZZuvYCqG7Ct/bp1D7w3tT7gTbIKYH\\\\nppQyG9rJDEh9+cr9Hyk8Gz7aAbPT/wMH+/vXDjH2j/M1Tmed0ajuGCJumaTQ4eHs\\\\n9xW3B3ugycb6e7Osl/4ESRO5RQL1k2GBONv10OrKDoZ5b66xwSJmC/w3BRWQ1cMC\\\\nAwEAAaMhMB8wHQYDVR0OBBYEFPospETb5HNeD/DmS9mwt+v/AYq/MA0GCSqGSIb3\\\\nDQEBCwUAA4IBAQBxMe1xQVQKt36A5qVlEZyxI9eb6eQRlYzorOgP2tFaOsvDPpRI\\\\nCALhPmxgQl/5QvKFfCXKoxWj1Spg4sF6fJp6jhSjLpmChS9lf5fRaWS20/pxIddM\\\\n10diq3r6HxLKSxCYK7Pf5scOeZquvwfo8Kxye01bvCMFf1s1K3ZEZszk5Oo2MnWU\\\\nU22YnXfZm1C0h2WMUcou35A7CeVAHPWI0Rvefojv1qYlQScJOkCN5lO6C/1qvRhq\\\\nnDQdQN/m1HQbpfh2DD6F33nBjkyLQyMRF8uMnspLrLLj8lecSTJZO4fGJOaIXh3O\\\\n44da9A02FAf5nRRQpwP2x/4IZ5RTRBzrqbqD\\\\n-----END CERTIFICATE-----\\\",\\\"type\\\":\\\"TRUSTED_CERTIFICATE\\\",\\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\\"alias\\\":\\\"alias\\\"}\";\n    private final String KEYSTORE_ENTRY_ARRAY_WITH_CERT = \"[\" + this.KEYSTORE_ENTRY_WITH_CERT + \"]\";\n    private final String CERTIFICATE = \"-----BEGIN CERTIFICATE-----\\n\"\n            + \"MIIDdzCCAl+gAwIBAgIEQsO0gDANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV\\n\"\n            + \"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\\n\"\n            + \"VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du\\n\"\n            + \"MB4XDTIxMDQxNDA4MDIyOFoXDTIxMDcxMzA4MDIyOFowbDEQMA4GA1UEBhMHVW5r\\n\"\n            + \"bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE\\n\"\n            + \"ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC\\n\"\n            + \"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJSWJDxu8UNC4JGOgK31WCvz\\n\"\n            + \"NKy2ONH+jTVKnBY7Ckb1hljJY0sKO55aG1HNDfkev2lJTsPIz0nJjNsqBvB1flvf\\n\"\n            + \"r6XVCxdN0yxvU5g9SpRxE/iiPX0Qt7463OfzyKW97haJrrhF005RHYNcORMY/Phj\\n\"\n            + \"hFDnZhtAwpbQLzq2UuIZ7okJsx0IgRbjH71ZZuvYCqG7Ct/bp1D7w3tT7gTbIKYH\\n\"\n            + \"ppQyG9rJDEh9+cr9Hyk8Gz7aAbPT/wMH+/vXDjH2j/M1Tmed0ajuGCJumaTQ4eHs\\n\"\n            + \"9xW3B3ugycb6e7Osl/4ESRO5RQL1k2GBONv10OrKDoZ5b66xwSJmC/w3BRWQ1cMC\\n\"\n            + \"AwEAAaMhMB8wHQYDVR0OBBYEFPospETb5HNeD/DmS9mwt+v/AYq/MA0GCSqGSIb3\\n\"\n            + \"DQEBCwUAA4IBAQBxMe1xQVQKt36A5qVlEZyxI9eb6eQRlYzorOgP2tFaOsvDPpRI\\n\"\n            + \"CALhPmxgQl/5QvKFfCXKoxWj1Spg4sF6fJp6jhSjLpmChS9lf5fRaWS20/pxIddM\\n\"\n            + \"10diq3r6HxLKSxCYK7Pf5scOeZquvwfo8Kxye01bvCMFf1s1K3ZEZszk5Oo2MnWU\\n\"\n            + \"U22YnXfZm1C0h2WMUcou35A7CeVAHPWI0Rvefojv1qYlQScJOkCN5lO6C/1qvRhq\\n\"\n            + \"nDQdQN/m1HQbpfh2DD6F33nBjkyLQyMRF8uMnspLrLLj8lecSTJZO4fGJOaIXh3O\\n\"\n            + \"44da9A02FAf5nRRQpwP2x/4IZ5RTRBzrqbqD\\n\" + \"-----END CERTIFICATE-----\";\n    private final String JSON_MESSAGE_PUT_CERT = \"{\\n\" + \"   \\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\n\"\n            + \"   \\\"alias\\\":\\\"myCertTest99\\\",\\n\" + \"   \\\"type\\\":\\\"TRUSTED_CERTIFICATE\\\",\\n\" + \"   \\\"certificate\\\":\\\"\"\n            + this.CERTIFICATE + \"\\n\" + \"}\";\n    private final String JSON_MESSAGE_DEL = \"{\\n\" + \"    \\\"keystoreServicePid\\\" : \\\"MyKeystore\\\",\\n\"\n            + \"    \\\"alias\\\" : \\\"mycerttestec\\\"\\n\" + \"}\";\n    private final String PRIVATE_KEY = \"-----BEGIN PRIVATE KEY-----\\n\"\n            + \"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCCcZ1Nu9AVYKJd\\n\"\n            + \"p6gcdObxCiofeOVbJv3Ws19JVa6PGTSgREFy5c97/k+SsSBhHAFp1n3738E2gdxD\\n\"\n            + \"auftKpmV3ZZ93rEQQ+Db71PiyFlrEEtcDE//14EH2jaHBIghxqWmgvWu0e8pca4u\\n\"\n            + \"xnmOOJAPCabNYLLs4pnTh9xJn+B+Mdz+/NNj/C7BV53W2nAcsdVqpbmLjfCrDSd/\\n\"\n            + \"hgel8AoAbdjiRGkYHkgvEuztjx01pO2iGAgpkctigdxF/ygwwOOxcPASw/55ZjSE\\n\"\n            + \"gMZx7PMyxEiIL7jgt/cgG68QhlQ3neYfJ9cd+gLvn1g1fwsGtGpw3Mh3dgs6DQkr\\n\"\n            + \"8HMQW0bpAgMBAAECggEAL2IR3/C/L2TA1gBWwq98TEaC8pe5yJirUFgr3rmvBPAE\\n\"\n            + \"+8qPc6si6UmBoimRN3Uy1j1B2kJ3LtORLTQiNzZoP9YUGnjQHLZrcbjH4fMg+BEd\\n\"\n            + \"LrySOr8PccjEUdtFj+9WsNuVXwGHPKi8uuUBtrW5Lp006BmeJQpTElGhpWTb6Tqy\\n\"\n            + \"OcNceNz+oP1N3AZ3Mnf6Aq6GuvD4QeGMVEiosHPxMqY0eddNK672zq3A0o1NPA9z\\n\"\n            + \"yaVt9UK7SZ6/yOKYrAAM/2iLHmNbrYRer567hgg2B1LGJCRSdB/c34u6lTnPo+Ai\\n\"\n            + \"olQahQNFhiJKTXr2kK9WgS6tWXhqUqsVLUCug4mDAQKBgQDKLbhidAYClyOKJW7U\\n\"\n            + \"GsbM5dmQV80NsnsN3qphKZDTEMinhs3N4oknhi+mZPeyge4MY73BiHXhnMcUkfhw\\n\"\n            + \"nbhRNhrkZTt18S6rTzEp/vDDx+ZosxRKYXmPyuDDWDmvG6ocRyOLIgoYhT0kPQ7a\\n\"\n            + \"oXQkpFPjBq1UmqNOcUwEpNG2sQKBgQClKzyAopsjWNptBQPo/j/PN24uThpdd3yX\\n\"\n            + \"NenmLZsYJyloKDbOGzEXpuyzdtNAiIVDsQ8RzN5lkF6xVvXnOlSA2gmEc8KJmRl8\\n\"\n            + \"/gWzPRHHHNR7QUiGmg9QThrUp2l6DiAm/IcuL0btj99kQa2XcLGlTohwWpdVySSx\\n\"\n            + \"abDX7pSRuQKBgH/jy+77VZHt6R1J8IFbLsYN30HfSGaRsCVl5IDxuhrJUyQlsam6\\n\"\n            + \"0uediibHV6gjaGGN9kql92tvsL7iVzVlj2JPx1MSdjp1BgB3Z7IZAlPV73nrTbp/\\n\"\n            + \"TlYXD3aCKHsMFN8uYN1x+tDn93Uk6nCCEOXczPOfFaWe7A6CvINzfvUBAoGAUJEm\\n\"\n            + \"khi/VB6jbUpk/eIHfiyrsiqm8bC3NYs27PCSFtYDfKshEKhy6faiv2fW5EOzvbFA\\n\"\n            + \"iI5GbYRerGKe0IvDbJbuzY0p97SWmkHOxf+kDFwjyXuuxPmhPqraq6B98uuxA1Nr\\n\"\n            + \"HTwyfO8RKPZglt6ByQDlzOhjqZTUMTY87ReToQECgYBKdX3Idr4zvODkXIlG852C\\n\"\n            + \"o135W+7AWr+dYRLx1FcvgMU9SbF9cwUU5Zutbrv+Kl8xGPyfx09MJ6BNxTkkr09J\\n\"\n            + \"BpbrbOZsUDjMjojyQYL4Ll9rLohk+Pq73xXJjtTRIXZVXJg27pEEqzcVB4o9vgli\\n\" + \"yzOqhyTKM9JP7Uda6Fv6DA==\\n\"\n            + \"-----END PRIVATE KEY-----\";\n    private final String[] CERTIFICATE_CHAIN = {\n            \"-----BEGIN CERTIFICATE-----\\n\" + \"MIIDdzCCAl+gAwIBAgIED3hXJjANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV\\n\"\n                    + \"bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD\\n\"\n                    + \"VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du\\n\"\n                    + \"MB4XDTIxMDQxMzA4MTQxOVoXDTIxMDcxMjA4MTQxOVowbDEQMA4GA1UEBhMHVW5r\\n\"\n                    + \"bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE\\n\"\n                    + \"ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC\\n\"\n                    + \"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIJxnU270BVgol2nqBx05vEK\\n\"\n                    + \"Kh945Vsm/dazX0lVro8ZNKBEQXLlz3v+T5KxIGEcAWnWffvfwTaB3ENq5+0qmZXd\\n\"\n                    + \"ln3esRBD4NvvU+LIWWsQS1wMT//XgQfaNocEiCHGpaaC9a7R7ylxri7GeY44kA8J\\n\"\n                    + \"ps1gsuzimdOH3Emf4H4x3P7802P8LsFXndbacByx1WqluYuN8KsNJ3+GB6XwCgBt\\n\"\n                    + \"2OJEaRgeSC8S7O2PHTWk7aIYCCmRy2KB3EX/KDDA47Fw8BLD/nlmNISAxnHs8zLE\\n\"\n                    + \"SIgvuOC39yAbrxCGVDed5h8n1x36Au+fWDV/Cwa0anDcyHd2CzoNCSvwcxBbRukC\\n\"\n                    + \"AwEAAaMhMB8wHQYDVR0OBBYEFCXFCTq9DDNw6jr0nE2VHw+6wqG0MA0GCSqGSIb3\\n\"\n                    + \"DQEBCwUAA4IBAQAjsKeIU0vf7vaOhUAMV60eP54kr6koiWBjhCxyKXQ+MECTFntn\\n\"\n                    + \"L459+uTFOCyoytWYjbe9ph79ossTWTCUUPCx9ZSaVdrpK5TyzXI+KBBWqGcLHxqc\\n\"\n                    + \"1jvU7zKLVf9oKGfhugnFvmj2EqC2vsrQPiG+p1RDfiLI9BqmhoDzBWzjZDdB6xt6\\n\"\n                    + \"PMAqecHfS24TzyWi8T4gLctcpSN22Aa394ky7sgBJPAQHWe7VWhRB0bVTZntwRsQ\\n\"\n                    + \"pEraINImKSw+m7MF/75s151yjKOzQxPZufl91oYyQMXoqX2fi0EUWo1oLm1x01dN\\n\"\n                    + \"L7w7ELyBzbNlk8a3dQc3Dcg+tu7VAf2tRtmc\\n\" + \"-----END CERTIFICATE-----\" };\n    private final String JSON_MESSAGE_PUT_KEY = \"{\\n\" + \"   \\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\n\"\n            + \"   \\\"alias\\\":\\\"myPrivateKey\\\",\\n\" + \"   \\\"type\\\":\\\"PRIVATE_KEY\\\",\\n\" + \"   \\\"privateKey\\\" : \\\"\"\n            + this.PRIVATE_KEY + \",\\n\" + \"   \\\"certificateChain\\\":[\\\"\" + this.CERTIFICATE_CHAIN + \"\\\"]\\n\" + \"}\";\n    private final String JSON_MESSAGE_PUT_KEY_PAIR = \"{\\n\" + \"   \\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\n\"\n            + \"   \\\"alias\\\":\\\"myKeyPair\\\",\\n\" + \"   \\\"type\\\":\\\"KEY_PAIR\\\",\\n\" + \"   \\\"algorithm\\\" : \\\"RSA\\\",\\n\"\n            + \"   \\\"size\\\": 2048,\\n\" + \"   \\\"signatureAlgorithm\\\" : \\\"SHA256WithRSA\\\",\\n\"\n            + \"   \\\"attributes\\\" : \\\"CN=Kura, OU=IoT, O=Eclipse, C=US\\\"\\n\" + \"}\";\n    private final String JSON_MESSAGE_GET_CSR = \"{\\n\" + \"    \\\"keystoreServicePid\\\":\\\"MyKeystore\\\",\\n\"\n            + \"    \\\"alias\\\":\\\"alias\\\",\\n\" + \"    \\\"algorithm\\\" : \\\"SHA256withRSA\\\",\\n\"\n            + \"    \\\"attributes\\\" : \\\"CN=Kura, OU=IoT, O=Eclipse, C=US\\\"\\n\" + \"}\";\n    private final String JSON_MESSAGE_GET_KEYS_BY_KEYSTORE = \"{\\n\" + \"    \\\"keystoreServicePid\\\":\\\"MyKeystore\\\"\\n\"\n            + \"}\";\n    private final String JSON_MESSAGE_GET_KEYS_BY_ALIAS = \"{\\n\" + \"    \\\"alias\\\":\\\"alias\\\"\\n\" + \"}\";\n    private final String JSON_MESSAGE_GET_KEYS_BY_KEYSTORE_ALIAS = \"{\\n\"\n            + \"    \\\"keystoreServicePid\\\":\\\"MyKeystore\\\", \\n\" + \"    \\\"alias\\\":\\\"alias\\\"\\n\" + \"}\";\n\n    @Test(expected = KuraException.class)\n    public void doGetTestNoResources() throws KuraException {\n        KeystoreServiceRequestHandlerV1 handler = new KeystoreServiceRequestHandlerV1();\n\n        List<String> resourcesList = Collections.emptyList();\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n        KuraRequestPayload reqPayload = new KuraRequestPayload();\n\n        KuraMessage message = new KuraMessage(reqPayload, reqResources);\n\n        handler.doGet(null, message);\n    }\n\n    @Test(expected = KuraException.class)\n    public void testDoGetOtherwise() throws KuraException, NoSuchFieldException {\n        KeystoreServiceRequestHandlerV1 handler = new KeystoreServiceRequestHandlerV1();\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(\"test\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload reqPayload = new KuraRequestPayload();\n\n        KuraMessage message = new KuraMessage(reqPayload, reqResources);\n\n        handler.doGet(null, message);\n    }\n\n    @Test\n    public void testDoGetKeystores() throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        List<String> responses = Arrays.asList(this.EMPTY_KEYSTORE_1, this.EMPTY_KEYSTORE_2);\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        assertTrue(responses.contains(new String(resPayload.getBody(), StandardCharsets.UTF_8)));\n    }\n\n    @Test\n    public void testDoGetAllKeys() throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        ByteArrayInputStream is = new ByteArrayInputStream(this.CERTIFICATE.getBytes());\n        X509Certificate cert = (X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        ks.setCertificateEntry(\"alias\", cert);\n        Map<String, Entry> certs = new HashMap<>();\n        certs.put(\"alias\", new KeyStore.TrustedCertificateEntry(cert));\n        when(ksMock.getKeyStore()).thenReturn(ks);\n        when(ksMock.getEntries()).thenReturn(certs);\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        resourcesList.add(ENTRIES_RESOURCE);\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n        String response = new String(resPayload.getBody(), StandardCharsets.UTF_8);\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n        JsonArray expectedJson = new JsonParser().parse(this.KEYSTORE_ENTRY).getAsJsonArray();\n        JsonArray receivedJson = new JsonParser().parse(response).getAsJsonArray();\n\n        assertEquals(expectedJson, receivedJson);\n    }\n\n    @Test\n    public void testDoGetKeysByKeystore()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        ByteArrayInputStream is = new ByteArrayInputStream(this.CERTIFICATE.getBytes());\n        X509Certificate cert = (X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        ks.setCertificateEntry(\"alias\", cert);\n        Map<String, Entry> certs = new HashMap<>();\n        certs.put(\"alias\", new KeyStore.TrustedCertificateEntry(cert));\n        when(ksMock.getKeyStore()).thenReturn(ks);\n        when(ksMock.getEntries()).thenReturn(certs);\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n\n            @SuppressWarnings(\"unchecked\")\n            @Override\n            protected <T> T unmarshal(String jsonString, Class<T> clazz) {\n                EntryInfo entryInfo = new EntryInfo(\"MyKeystore\", null);\n                return (T) entryInfo;\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        resourcesList.add(ENTRIES_RESOURCE);\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        request.setBody(this.JSON_MESSAGE_GET_KEYS_BY_KEYSTORE.getBytes());\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        String response = new String(resPayload.getBody(), StandardCharsets.UTF_8);\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n\n        JsonArray expectedJson = new JsonParser().parse(this.KEYSTORE_ENTRY_ARRAY_WITH_CERT).getAsJsonArray();\n        JsonArray receivedJson = new JsonParser().parse(response).getAsJsonArray();\n\n        assertEquals(expectedJson, receivedJson);\n    }\n\n    @Test\n    public void testDoGetKeyByAlias()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        ByteArrayInputStream is = new ByteArrayInputStream(this.CERTIFICATE.getBytes());\n        X509Certificate cert = (X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        ks.setCertificateEntry(\"alias\", cert);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n        when(ksMock.getEntry(\"alias\")).thenReturn(new KeyStore.TrustedCertificateEntry(cert));\n\n        List<String> aliases = new ArrayList<>();\n        aliases.add(\"alias\");\n        when(ksMock.getAliases()).thenReturn(aliases);\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n\n            @SuppressWarnings(\"unchecked\")\n            @Override\n            protected <T> T unmarshal(String jsonString, Class<T> clazz) {\n                EntryInfo entryInfo = new EntryInfo(null, \"alias\");\n                return (T) entryInfo;\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        resourcesList.add(ENTRIES_RESOURCE);\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        request.setBody(this.JSON_MESSAGE_GET_KEYS_BY_ALIAS.getBytes());\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n\n        String response = new String(resPayload.getBody(), StandardCharsets.UTF_8);\n\n        JsonArray expectedJson = new JsonParser().parse(this.KEYSTORE_ENTRY_ARRAY_WITH_CERT).getAsJsonArray();\n        JsonArray receivedJson = new JsonParser().parse(response).getAsJsonArray();\n\n        assertEquals(expectedJson, receivedJson);\n    }\n\n    @Test\n    public void testDoGetKeyByKeystoreAlias()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        ByteArrayInputStream is = new ByteArrayInputStream(this.CERTIFICATE.getBytes());\n        X509Certificate cert = (X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        ks.setCertificateEntry(\"alias\", cert);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n        when(ksMock.getEntry(\"alias\")).thenReturn(new KeyStore.TrustedCertificateEntry(cert));\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n\n            @SuppressWarnings(\"unchecked\")\n            @Override\n            protected <T> T unmarshal(String jsonString, Class<T> clazz) {\n                EntryInfo entryInfo = new EntryInfo(\"MyKeystore\", \"alias\");\n                return (T) entryInfo;\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        resourcesList.add(ENTRIES_RESOURCE);\n        resourcesList.add(ENTRY_RESOURCE);\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        request.setBody(this.JSON_MESSAGE_GET_KEYS_BY_KEYSTORE_ALIAS.getBytes());\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doGet(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n        String response = new String(resPayload.getBody(), StandardCharsets.UTF_8);\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n\n        JsonObject expectedJson = new JsonParser().parse(this.KEYSTORE_ENTRY_WITH_CERT).getAsJsonObject();\n        JsonObject receivedJson = new JsonParser().parse(response).getAsJsonObject();\n\n        assertEquals(expectedJson, receivedJson);\n    }\n\n    @Test\n    public void testDoPostTrustedCertificate()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n\n            @SuppressWarnings(\"unchecked\")\n            @Override\n            protected <T> T unmarshal(String jsonString, Class<T> clazz) {\n                assertEquals(KeystoreServiceRequestHandlerTest.this.JSON_MESSAGE_PUT_CERT, jsonString);\n                CertificateInfo info = new CertificateInfo(\"MyKeystore\", \"myCertTest99\");\n                info.setCertificate(KeystoreServiceRequestHandlerTest.this.CERTIFICATE);\n                return (T) info;\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        resourcesList.add(ENTRIES_RESOURCE);\n        resourcesList.add(CERTIFICATE_RESOURCE);\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        request.setBody(this.JSON_MESSAGE_PUT_CERT.getBytes());\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doPost(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n    }\n\n    @Test(expected = KuraException.class)\n    public void testDoPostPrivateKey()\n            throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n\n            @SuppressWarnings(\"unchecked\")\n            @Override\n            protected <T> T unmarshal(String jsonString, Class<T> clazz) {\n                PrivateKeyInfo info = new PrivateKeyInfo(\"MyKeystore\", \"myPrivateKey\");\n                info.setPrivateKey(KeystoreServiceRequestHandlerTest.this.PRIVATE_KEY);\n                info.setCertificateChain(KeystoreServiceRequestHandlerTest.this.CERTIFICATE_CHAIN);\n                return (T) info;\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        resourcesList.add(ENTRIES_RESOURCE);\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        request.setBody(this.JSON_MESSAGE_PUT_KEY.getBytes());\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doPost(null, message);\n        resMessage.getPayload();\n    }\n\n    @Test\n    public void testDoPostKeyPair() throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n\n            @SuppressWarnings(\"unchecked\")\n            @Override\n            protected <T> T unmarshal(String jsonString, Class<T> clazz) {\n                KeyPairInfo info = new KeyPairInfo(\"MyKeystore\", \"myKeyPair\");\n                info.setAlgorithm(\"RSA\");\n                info.setSignatureAlgorithm(\"SHA256WithRSA\");\n                info.setAttributes(\"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n                info.setSize(2048);\n                return (T) info;\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        resourcesList.add(ENTRIES_RESOURCE);\n        resourcesList.add(KEYPAIR_RESOURCE);\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        request.setBody(this.JSON_MESSAGE_PUT_KEY_PAIR.getBytes());\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doPost(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n    }\n\n    @Test\n    public void getCSRTest() throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n        when(ksMock.getEntry(\"alias\")).thenReturn(createPrivateKey(\"alias\", this.PRIVATE_KEY, this.CERTIFICATE_CHAIN));\n        String csrString = \"-----BEGIN CERTIFICATE REQUEST-----\";\n        when(ksMock.getCSR(any(String.class), any(X500Principal.class), any(String.class))).thenReturn(csrString);\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n\n            @SuppressWarnings(\"unchecked\")\n            @Override\n            protected <T> T unmarshal(String jsonString, Class<T> clazz) {\n                CsrInfo info = new CsrInfo(\"MyKeystore\", \"alias\");\n                info.setSignatureAlgorithm(\"SHA256withRSA\");\n                info.setAttributes(\"CN=Kura, OU=IoT, O=Eclipse, C=US\");\n                return (T) info;\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        resourcesList.add(ENTRIES_RESOURCE);\n        resourcesList.add(\"csr\");\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        request.setBody(this.JSON_MESSAGE_GET_CSR.getBytes());\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doPost(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        String reds = new String(resPayload.getBody(), StandardCharsets.UTF_8);\n        assertTrue(reds.contains(csrString));\n    }\n\n    @Test\n    public void testDoDel() throws KuraException, NoSuchFieldException, GeneralSecurityException, IOException {\n        KeystoreService ksMock = mock(KeystoreService.class);\n        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());\n        char[] password = \"some password\".toCharArray();\n        ks.load(null, password);\n        when(ksMock.getKeyStore()).thenReturn(ks);\n\n        KeystoreServiceRequestHandlerV1 keystoreRH = new KeystoreServiceRequestHandlerV1() {\n\n            @Override\n            public void activate(ComponentContext componentContext) {\n                this.keystoreServices.put(\"MyKeystore\", ksMock);\n            }\n\n            @SuppressWarnings(\"unchecked\")\n            @Override\n            protected <T> T unmarshal(String jsonString, Class<T> clazz) {\n                assertEquals(KeystoreServiceRequestHandlerTest.this.JSON_MESSAGE_DEL, jsonString);\n                return (T) new EntryInfo(\"MyKeystore\", \"mycerttestec\");\n            }\n        };\n        keystoreRH.activate(null);\n\n        List<String> resourcesList = new ArrayList<>();\n        resourcesList.add(KEYSTORES_RESOURCE);\n        resourcesList.add(ENTRIES_RESOURCE);\n        Map<String, Object> reqResources = new HashMap<>();\n        reqResources.put(ARGS_KEY.value(), resourcesList);\n\n        KuraRequestPayload request = new KuraRequestPayload();\n        request.setBody(this.JSON_MESSAGE_DEL.getBytes());\n        KuraMessage message = new KuraMessage(request, reqResources);\n\n        KuraMessage resMessage = keystoreRH.doDel(null, message);\n        KuraResponsePayload resPayload = (KuraResponsePayload) resMessage.getPayload();\n\n        assertEquals(KuraResponsePayload.RESPONSE_CODE_OK, resPayload.getResponseCode());\n    }\n\n    private PrivateKeyEntry createPrivateKey(String alias, String privateKey, String[] certificateChain)\n            throws IOException, GeneralSecurityException, KuraException {\n        // Works with RSA and DSA. EC is not supported since the certificate is encoded\n        // with ECDSA while the corresponding private key with EC.\n        // This cause an error when the PrivateKeyEntry is generated.\n        Certificate[] certs = parsePublicCertificates(certificateChain);\n\n        Security.addProvider(new BouncyCastleProvider());\n        PEMParser pemParser = new PEMParser(new StringReader(privateKey));\n        Object object = pemParser.readObject();\n        pemParser.close();\n        JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(\"BC\");\n        PrivateKey privkey = null;\n        if (object instanceof org.bouncycastle.asn1.pkcs.PrivateKeyInfo) {\n            privkey = converter.getPrivateKey((org.bouncycastle.asn1.pkcs.PrivateKeyInfo) object);\n        }\n\n        return new PrivateKeyEntry(privkey, certs);\n    }\n\n    private X509Certificate[] parsePublicCertificates(String[] publicKeys) throws CertificateException {\n        List<X509Certificate> certificateChain = new ArrayList<>();\n        for (String publicKey : publicKeys) {\n            ByteArrayInputStream is = new ByteArrayInputStream(publicKey.getBytes());\n            certificateChain.add((X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(is));\n        }\n        return certificateChain.toArray(new X509Certificate[0]);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.keystore.provider.test/src/test/resources/cert",
    "content": "-----BEGIN CERTIFICATE-----\nMIICezCCAjigAwIBAgIESvucGTALBgcqhkjOOAQDBQAwDzENMAsGA1UEAxMEa3Vy\nYTAeFw0xNzA4MjQxNDMxMjNaFw0zMTA1MDMxNDMxMjNaMA8xDTALBgNVBAMTBGt1\ncmEwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I8\n70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk\nn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX\nKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKBgQD34aCF1ps93su8\nq1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgWE7fP\nCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD\n3+Fa5Z8GkotmXoB7VSVkAUw7/s9JKgOBhAACgYAaqPBZ1sLviuLYcBbVYhtJRUB1\nFBrCxMut8sWDAFCEaZ/gLuOZP7Odw9ifuDLkfF9iDi20MNUbojgFLg1u71IOLUtW\n6+0vICqfZRai7i2kNHM82J1TLaS4QYQzTDGUxs0xAOSaidyBlGPvwrzTQixIK5Ph\nH0VBeEr9a2RIbaHgOKMhMB8wHQYDVR0OBBYEFJe86lxIv5UYsZ/uGcIdewCPUeaj\nMAsGByqGSM44BAMFAAMwADAtAhUAiw2QQPqB75io+p1cxQfMQW4Z/6oCFEA7AGYv\nkLQlC6I0o6bJqtKRlwar\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.keystore.provider.test/src/test/resources/log4j.properties",
    "content": "log4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nFragment-Host: org.eclipse.kura.rest.provider\nImport-Package: com.eclipsesource.json;version=\"0.9.5\",\n jakarta.annotation;version=\"2.1.1\",\n jakarta.annotation.security;version=\"2.1.1\",\n jakarta.servlet;version=\"5.0.0\",\n jakarta.servlet.http;version=\"5.0.0\",\n jakarta.ws.rs;version=\"3.1.0\",\n jakarta.ws.rs.container;version=\"3.1.0\",\n org.apache.commons.io;version=\"2.4.0\",\n org.bouncycastle.asn1.x500;version=\"1.78.1\",\n org.eclipse.kura;version=\"1.6.0\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.testutil.json;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.pki;version=\"1.0.0\",\n org.eclipse.kura.core.testutil.requesthandler;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.data;version=\"[1.1,2.0)\",\n org.eclipse.kura.data.transport.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.marshalling;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.4,2.0)\",\n org.eclipse.kura.rest.auth;version=\"1.0.0\",\n org.eclipse.kura.security.keystore;version=\"1.1.0\",\n org.eclipse.kura.ssl;version=\"2.1.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.25\"\nRequire-Bundle: org.eclipse.kura.http.server.manager;bundle-version=\"1.1.0\",\n org.eclipse.kura.core.keystore;bundle-version=\"1.4.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.provider.test/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2022 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               ."
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n        Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.rest.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.provider.test/src/main/java/org/eclipse/kura/rest/provider/test/PasswordChangeSessionTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\n// Content with portions generated by generative AI platform\npackage org.eclipse.kura.rest.provider.test;\n\nimport static org.junit.Assert.fail;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.Response;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonObject;\n\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\n\npublic class PasswordChangeSessionTest extends AbstractRequestHandlerTest {\n\n    private static final String PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID = \"org.eclipse.kura.identity.PasswordStrengthVerificationService\";\n\n    private final List<ServiceRegistration<?>> registeredServices = new ArrayList<>();\n\n    public PasswordChangeSessionTest() {\n        super(new RestTransport(\"testservice\"));\n    }\n\n    @Test\n    public void shouldAllowResourceAccessAfterPasswordChangeWithoutRelogin() {\n        givenPasswordStrengthDoesNotRestrictChange();\n        givenServiceRequiresAssetsRole();\n        givenNoBasicCredentials();\n        givenIdentityRequiringPasswordChange();\n        givenUserIsLoggedIn();\n        givenXsrfToken();\n\n        whenPasswordIsChanged();\n        whenXsrfTokenIsObtained();\n        whenProtectedResourceIsRequested();\n\n        thenResourceAccessIsGranted();\n    }\n\n    @After\n    public void cleanUp() {\n        this.registeredServices.forEach(ServiceRegistration::unregister);\n    }\n\n    private void givenNoBasicCredentials() {\n        givenBasicCredentials(Optional.empty());\n    }\n\n    private void givenBasicCredentials(final Optional<String> basicCredentials) {\n        ((RestTransport) this.transport).setBasicCredentials(basicCredentials);\n    }\n\n    private void givenPasswordStrengthDoesNotRestrictChange() {\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, \"new.password.min.length\", 1,\n                \"new.password.require.digits\", false, \"new.password.require.special.characters\", false,\n                \"new.password.require.both.cases\", false);\n    }\n\n    private void givenServiceRequiresAssetsRole() {\n        givenService(new RequiresAssetsRole());\n    }\n\n    private void givenIdentityRequiringPasswordChange() {\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n    }\n\n    private void givenUserIsLoggedIn() {\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n    }\n\n    private void givenConfiguration(final String pid, final Object... properties) {\n        try {\n            final ConfigurationAdmin configAdmin = ServiceUtil.trackService(ConfigurationAdmin.class, Optional.empty())\n                    .get(30, TimeUnit.SECONDS);\n\n            final Configuration configuration = configAdmin.getConfiguration(pid, \"?\");\n\n            final Dictionary<String, Object> configurationProperties = Optional\n                    .ofNullable(configuration.getProperties()).orElseGet(Hashtable::new);\n\n            final Iterator<Object> iter = Arrays.asList(properties).iterator();\n\n            while (iter.hasNext()) {\n                final String key = (String) iter.next();\n                final Object value = iter.next();\n\n                configurationProperties.put(key, value);\n            }\n\n            configuration.update(configurationProperties);\n\n        } catch (Exception e) {\n            fail(\"cannot update configuration\");\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T extends TestService> void givenService(final T service) {\n        final BundleContext bundleContext = FrameworkUtil.getBundle(PasswordChangeSessionTest.class).getBundleContext();\n\n        final Dictionary<String, Object> properties = new Hashtable<>();\n        properties.put(\"osgi.jakartars.resource\", true);\n\n        registeredServices.add(bundleContext.registerService((Class<T>) service.getClass(), service, properties));\n\n        final RestTransport restTransport = (RestTransport) this.transport;\n\n        for (int i = 0; i < 100; i++) {\n            final Response response = restTransport.runRequest(\"/ping\", new MethodSpec(\"GET\"));\n\n            if (response.getStatus() != 404 && response.getStatus() != 503) {\n                break;\n            }\n\n            try {\n                synchronized (this) {\n                    this.wait(100);\n                }\n            } catch (InterruptedException e) {\n                fail(\"Interrupted while waiting for service startup\");\n                return;\n            }\n        }\n    }\n\n    private void givenIdentity(final String username, final Optional<String> password, final List<String> roles,\n            final boolean needsPasswordChange) {\n        final UserAdmin userAdmin;\n\n        try {\n            userAdmin = ServiceUtil.trackService(UserAdmin.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n        } catch (Exception e) {\n            fail(\"failed to track UserAdmin\");\n            return;\n        }\n\n        final User user = getOrCreateRole(userAdmin, \"kura.user.\" + username, User.class);\n\n        if (password.isPresent()) {\n            try {\n                final CryptoService cryptoService = ServiceUtil.trackService(CryptoService.class, Optional.empty())\n                        .get(30, TimeUnit.SECONDS);\n\n                user.getCredentials().put(\"kura.password\", cryptoService.sha256Hash(password.get()));\n\n            } catch (Exception e) {\n                fail(\"failed to compute password hash\");\n            }\n        }\n\n        if (needsPasswordChange) {\n            user.getProperties().put(\"kura.need.password.change\", \"true\");\n        } else {\n            user.getProperties().remove(\"kura.need.password.change\");\n        }\n\n        for (final String role : roles) {\n            getOrCreateRole(userAdmin, \"kura.permission.\" + role, Group.class).addMember(user);\n        }\n    }\n\n    private void givenSuccessfulRequest(final String proto, final int port, final MethodSpec method,\n            final String resource, final String body) {\n        whenRequestIsPerformed(proto, port, method, resource, body);\n        thenRequestSucceeds();\n    }\n\n    private void givenXsrfToken() {\n        whenXsrfTokenIsObtained();\n    }\n\n    private void whenPasswordIsChanged() {\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/changePassword\",\n                \"{\\\"currentPassword\\\":\\\"bar\\\",\\\"newPassword\\\":\\\"baz\\\"}\");\n    }\n\n    private void whenProtectedResourceIsRequested() {\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n    }\n\n    private void whenRequestIsPerformed(final String proto, final int port, final MethodSpec method,\n            final String resource, final String body) {\n        final RestTransport restTransport = (RestTransport) this.transport;\n\n        this.response = Optional\n                .of(restTransport.runRequest(proto + \"://localhost:\" + port + \"/services\", resource, method, body));\n    }\n\n    private void whenXsrfTokenIsObtained() {\n        final RestTransport restTransport = (RestTransport) this.transport;\n\n        final Response response = restTransport.runRequest(\"http://localhost:8080/services\", \"/session/v1/xsrfToken\",\n                new MethodSpec(\"GET\"), null);\n\n        final JsonObject object = Json\n                .parse(response.getBody().orElseThrow(() -> new IllegalStateException(\"no response body\"))).asObject();\n\n        final String token = object.get(\"xsrfToken\").asString();\n\n        restTransport.setHeader(\"X-XSRF-Token\", token);\n    }\n\n    private void thenResourceAccessIsGranted() {\n        thenResponseCodeIs(200);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T extends Role> T getOrCreateRole(final UserAdmin userAdmin, final String name, final Class<T> classz) {\n        final Role existing = userAdmin.getRole(name);\n\n        if (classz.isInstance(existing)) {\n            return (T) existing;\n        }\n\n        final int type;\n\n        if (classz == User.class) {\n            type = Role.USER;\n        } else if (classz == Group.class) {\n            type = Role.GROUP;\n        } else {\n            fail(\"Unsupported role type\");\n            return null;\n        }\n\n        return (T) userAdmin.createRole(name, type);\n    }\n\n    public static abstract class TestService {\n\n        @GET\n        @Path(\"/ping\")\n        public String ping() {\n            return \"ok\";\n        }\n\n    }\n\n    @Path(\"testservice\")\n    public static class RequiresAssetsRole extends TestService {\n\n        @GET\n        @Path(\"requireAssets\")\n        @RolesAllowed(\"assets\")\n        public String requireAssets() {\n            return \"Hello\";\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.provider.test/src/main/java/org/eclipse/kura/rest/provider/test/RestServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.provider.test;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.fail;\n\nimport java.io.File;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.security.KeyPair;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStore.TrustedCertificateEntry;\nimport java.security.Principal;\nimport java.security.SecureRandom;\nimport java.security.cert.Certificate;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Base64;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.StringTokenizer;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport org.bouncycastle.asn1.x500.X500Name;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.pki.TestCA;\nimport org.eclipse.kura.core.testutil.pki.TestCA.CertificateCreationOptions;\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.Response;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.rest.auth.AuthenticationProvider;\nimport org.eclipse.kura.security.keystore.KeystoreService;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonObject;\n\nimport jakarta.annotation.Priority;\nimport jakarta.annotation.security.RolesAllowed;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.ws.rs.GET;\nimport jakarta.ws.rs.Path;\nimport jakarta.ws.rs.container.ContainerRequestContext;\n\npublic class RestServiceTest extends AbstractRequestHandlerTest {\n\n    private static final String LOGIN_BANNER_SERVICE_PID = \"org.eclipse.kura.identity.LoginBannerService\";\n    private static final String PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID = \"org.eclipse.kura.identity.PasswordStrengthVerificationService\";\n\n    public RestServiceTest() {\n        super(new RestTransport(\"testservice\"));\n    }\n\n    @Test\n    public void shouldReturnNotFoundIfNoServiceIsRegistered() {\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/foo\");\n\n        thenResponseCodeIs(404);\n    }\n\n    @Test\n    public void shouldNotRequireAuth() {\n        givenService(new NoAuth());\n        givenNoBasicCredentials();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/noAuth\");\n\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldRerturn403IfUserIsNotInRole() {\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"fooo\", Optional.of(\"barr\"), Collections.emptyList());\n        givenBasicCredentials(Optional.of(\"fooo:barr\"));\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(403);\n    }\n\n    @Test\n    public void shouldRerturn401IfPasswordIsWrong() {\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenBasicCredentials(Optional.of(\"foo:baz\"));\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldAllowAccessIfUserIsInRole() {\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo1\", Optional.of(\"bar1\"), Collections.singletonList(\"rest.assets\"));\n        givenBasicCredentials(Optional.of(\"foo1:bar1\"));\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldRerturn401IfNoCredentialsAreProvided() {\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldEnableAuthenticationProvider() {\n\n        whenAuthenticationProviderIsRegistered(new DummyAuthenticationProvider(\"foo\", \"bar\", \"admin\"));\n\n        thenProviderIsEnabled();\n    }\n\n    @Test\n    public void shouldDisableAuthenticationProvider() {\n\n        givenAuthenticationProvider(new DummyAuthenticationProvider(\"foo\", \"bar\", \"admin\"));\n\n        whenLastRegisteredServiceIsUnregistered();\n\n        thenProviderIsDisabled();\n    }\n\n    @Test\n    public void shouldSupportCustomAuthenticationProvider() {\n        givenService(new RequiresAssetsRole());\n        givenAuthenticationProvider(new DummyAuthenticationProvider(\"bar\", \"baz\", \"admin\"));\n        givenBasicCredentials(Optional.of(\"bar:baz\"));\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenProviderAuthenticatedRequest();\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldSupportLowPriorityAuthenticationHandler() {\n        givenService(new RequiresAssetsRole());\n        givenAuthenticationProvider(new LowPriorityAuthenticationProvider(\"foo\", \"bar\", \"admin\"));\n        givenBasicCredentials(Optional.of(\"foo:bar\"));\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.singletonList(\"rest.assets\"));\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenProviderDidNotAuthenticateRequest();\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldSupportHighPriorityAuthenticationHandler() {\n        givenService(new RequiresAssetsRole());\n        givenAuthenticationProvider(new HighPriorityAuthenticationProvider(\"foo\", \"bar\", \"admin\"));\n        givenBasicCredentials(Optional.of(\"foo:bar\"));\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.singletonList(\"rest.assets\"));\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenProviderAuthenticatedRequest();\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldSupportDisablingBuiltInPasswordAuthentication() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"auth.password.enabled\", false));\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo1\", Optional.of(\"bar1\"), Collections.singletonList(\"rest.assets\"));\n        givenBasicCredentials(Optional.of(\"foo1:bar1\"));\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldSupportCertificateAuthenticationOnResourcePath() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.empty(), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"GET\"), \"/testservice/requireAssets\", null);\n\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldRejectRequestIfCertCommonNameDoesNotMatchIdentity() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"doesNotExist\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"GET\"), \"/testservice/requireAssets\", null);\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldCreateSessionWithUsernameAndPassword() {\n        givenConfiguration(LOGIN_BANNER_SERVICE_PID, //\n                \"pre.login.banner.enabled\", false, //\n                \"post.login.banner.enabled\", false);\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n\n        thenResponseCodeIs(200);\n        thenResponseBodyEqualsJson(\"{\\\"passwordChangeNeeded\\\":false}\");\n        thenResponseHasCookie(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldNotCreateSessionWithWrongPassword() {\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"baz\\\"}\");\n\n        thenResponseCodeIs(401);\n        thenResponseDoesNotHaveCookie(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldNotCreateSessionWithWrongUsername() {\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"bar\\\",\\\"password\\\":\\\"bar\\\"}\");\n\n        thenResponseCodeIs(401);\n        thenResponseDoesNotHaveCookie(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldCreateSessionWithCertificate() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.empty(), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n\n        thenRequestSucceeds();\n        thenResponseHasCookie(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldCreateSessionWithCertificateAndReturnPostLoginMessage() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenConfiguration(LOGIN_BANNER_SERVICE_PID, //\n                \"post.login.banner.enabled\", true, //\n                \"post.login.banner.content\", \"foo\");\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.empty(), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n\n        thenRequestSucceeds();\n        thenResponseHasCookie(\"JSESSIONID\");\n        thenResponseBodyEqualsJson(\"{\\\"passwordChangeNeeded\\\":false,\\\"message\\\":\\\"foo\\\"}\");\n    }\n\n    @Test\n    public void shouldNotCreateSessionWithCertificateIfCNDoesNotMatchIdentity() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.empty(), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"bar\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n\n        thenResponseCodeIs(401);\n        thenResponseDoesNotHaveCookie(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldReturnXSRFTokenIfSessionIsOpen() {\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/xsrfToken\", null);\n\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldNotReturnXSRFTokenIfSessionIsNotOpen() {\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/xsrfToken\", null);\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldAllowAccessingResourceThroughSessionAuth() {\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldNotAllowAccessingResourceThroughSessionAuthIfXsrfTokenIsMissing() {\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldSupportLogout() {\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n        givenSuccessfulRequest(new MethodSpec(\"GET\"), \"/requireAssets\");\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/logout\", null);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldRequireXsrfTokenForLogout() {\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/logout\", null);\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldDenyResourceAccessIfPasswordChangeIsNeeded() {\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldRejectPassordChangeWithSamePassword() {\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, //\n                \"new.password.min.length\", 1, //\n                \"new.password.require.digits\", false, //\n                \"new.password.require.special.characters\", false, //\n                \"new.password.require.both.cases\", false //\n        );\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/changePassword\",\n                \"{\\\"currentPassword\\\":\\\"bar\\\",\\\"newPassword\\\":\\\"bar\\\"}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldAllowResourceAccessAfterPasswordChange() {\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, //\n                \"new.password.min.length\", 1, //\n                \"new.password.require.digits\", false, //\n                \"new.password.require.special.characters\", false, //\n                \"new.password.require.both.cases\", false //\n        );\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/changePassword\",\n                \"{\\\"currentPassword\\\":\\\"bar\\\",\\\"newPassword\\\":\\\"baz\\\"}\");\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"baz\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldSupportSessionExpiration() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"session.inactivity.interval\", 1));\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n        givenSuccessfulRequest(new MethodSpec(\"GET\"), \"/requireAssets\");\n        givenDelay(2, TimeUnit.SECONDS);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldNotAllowGettingXsrfTokenIfSessionIsExpired() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"session.inactivity.interval\", 1));\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n        givenSuccessfulRequest(new MethodSpec(\"GET\"), \"/requireAssets\");\n        givenDelay(2, TimeUnit.SECONDS);\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/xsrfToken\", null);\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldExtendSessionLifetimeOnActivity() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"session.inactivity.interval\", 1));\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n        givenSuccessfulRequest(new MethodSpec(\"GET\"), \"/requireAssets\");\n        givenDelay(500, TimeUnit.MILLISECONDS);\n        givenSuccessfulRequest(new MethodSpec(\"GET\"), \"/requireAssets\");\n        givenDelay(500, TimeUnit.MILLISECONDS);\n        givenSuccessfulRequest(new MethodSpec(\"GET\"), \"/requireAssets\");\n        givenDelay(500, TimeUnit.MILLISECONDS);\n        givenSuccessfulRequest(new MethodSpec(\"GET\"), \"/requireAssets\");\n        givenDelay(2, TimeUnit.SECONDS);\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldIgnorePasswordChangeNeededWithCertificateAuth() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        givenSuccessfulRequest(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n        givenXsrfToken(\"https\", 9999);\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"GET\"), \"/testservice/requireAssets\", null);\n\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldSupportDisablingBuiltInBasicAuthentication() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"auth.basic.enabled\", false));\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo1\", Optional.of(\"bar1\"), Collections.singletonList(\"rest.assets\"));\n        givenBasicCredentials(Optional.of(\"foo1:bar1\"));\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldSupportDisablingCertificateAuthenticationOnResourcePath() {\n        givenRestServiceConfiguration(map(\"allowed.ports\", new Integer[] { 8080, 9999 }, //\n                \"auth.certificate.stateless.enabled\", false));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.empty(), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"GET\"), \"/testservice/requireAssets\", null);\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldAllowAccessingResourceThroughSessionAuthEvenIfBasicAuthIsDisabled() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"auth.basic.enabled\", false));\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldAllowAccessingResourceThroughSessionAuthEvenIfLegacyCertificateAuthIsDisabled() {\n        givenRestServiceConfiguration(map(\"allowed.ports\", new Integer[] { 8080, 9999 }, //\n                \"auth.certificate.stateless.enabled\", false));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        givenSuccessfulRequest(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n        givenXsrfToken(\"https\", 9999);\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"GET\"), \"/testservice/requireAssets\", null);\n\n        thenResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldTerminateSessionIfUserCredentialsChange() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"auth.basic.enabled\", false));\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n        givenSuccessfulRequest(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        whenIdentityIsUpdated(\"foo\", Optional.of(\"baz\"), Arrays.asList(\"rest.assets\"));\n        whenRequestIsPerformed(new MethodSpec(\"GET\"), \"/requireAssets\");\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldRejectPassordChangeWithTooShort() {\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, //\n                \"new.password.min.length\", 4, //\n                \"new.password.require.digits\", false, //\n                \"new.password.require.special.characters\", false, //\n                \"new.password.require.both.cases\", false //\n        );\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/changePassword\",\n                \"{\\\"currentPassword\\\":\\\"bar\\\",\\\"newPassword\\\":\\\"baz\\\"}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectPassordChangeWithoutDigits() {\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, //\n                \"new.password.min.length\", 4, //\n                \"new.password.require.digits\", true, //\n                \"new.password.require.special.characters\", false, //\n                \"new.password.require.both.cases\", false //\n        );\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/changePassword\",\n                \"{\\\"currentPassword\\\":\\\"bar\\\",\\\"newPassword\\\":\\\"nodigits\\\"}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectPassordChangeWithoutSpecialCharacters() {\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, //\n                \"new.password.min.length\", 4, //\n                \"new.password.require.digits\", true, //\n                \"new.password.require.special.characters\", true, //\n                \"new.password.require.both.cases\", false //\n        );\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/changePassword\",\n                \"{\\\"currentPassword\\\":\\\"bar\\\",\\\"newPassword\\\":\\\"nospecialcharacters1\\\"}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectPassordChangeWithoutBothCases() {\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, //\n                \"new.password.min.length\", 4, //\n                \"new.password.require.digits\", true, //\n                \"new.password.require.special.characters\", true, //\n                \"new.password.require.both.cases\", true //\n        );\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/changePassword\",\n                \"{\\\"currentPassword\\\":\\\"bar\\\",\\\"newPassword\\\":\\\"nobothcases1@\\\"}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldAcceptPasswordThatFullfillsRequirements() {\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, //\n                \"new.password.min.length\", 4, //\n                \"new.password.require.digits\", true, //\n                \"new.password.require.special.characters\", true, //\n                \"new.password.require.both.cases\", true //\n        );\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"), true);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/changePassword\",\n                \"{\\\"currentPassword\\\":\\\"bar\\\",\\\"newPassword\\\":\\\"1validPW@\\\"}\");\n\n        thenRequestSucceeds();\n    }\n\n    @Test\n    public void shouldReturnCurrentIdentityInfo() {\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\", \"rest.foo\", \"rest.bar\"), false);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/currentIdentity\", null);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\n                \"{\\\"name\\\":\\\"foo\\\",\\\"passwordChangeNeeded\\\":false,\\\"permissions\\\":[\\\"rest.bar\\\",\\\"rest.assets\\\",\\\"rest.foo\\\"]}\");\n    }\n\n    @Test\n    public void shouldReturnCurrentIdentityInfoWithNoPermissions() {\n        givenService(new RequiresAssetsRole());\n        givenNoBasicCredentials();\n        givenIdentity(\"nopermissions\", Optional.of(\"bar\"), Collections.emptyList(), false);\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"nopermissions\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/currentIdentity\", null);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\"{\\\"name\\\":\\\"nopermissions\\\",\\\"passwordChangeNeeded\\\":false,\\\"permissions\\\":[]}\");\n    }\n\n    @Test\n    public void shouldReturnCurrentAuthenticationMethodInfo() {\n        givenHttpServiceClientCertAuthDisabled();\n        givenService(new RequiresAssetsRole());\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, //\n                \"access.banner.enabled\", false);\n        givenNoBasicCredentials();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/authenticationInfo\", null);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(\n                \"{\\\"passwordAuthenticationEnabled\\\":true,\\\"certificateAuthenticationEnabled\\\":false}\");\n    }\n\n    @Test\n    public void shouldReturnMessageIfLoginBannnerIsEnabled() {\n        givenHttpServiceClientCertAuthDisabled();\n        givenConfiguration(LOGIN_BANNER_SERVICE_PID, //\n                \"pre.login.banner.enabled\", true, //\n                \"pre.login.banner.content\", \"foo\");\n        givenNoBasicCredentials();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/authenticationInfo\", null);\n\n        thenResponseCodeIs(200);\n        thenResponseBodyEqualsJson(\n                \"{\\\"passwordAuthenticationEnabled\\\":true,\\\"certificateAuthenticationEnabled\\\":false,\\\"message\\\":\\\"foo\\\"}\");\n    }\n\n    @Test\n    public void shouldReturnPostLoginMessageIfLoginBannnerIsEnabled() {\n        givenHttpServiceClientCertAuthDisabled();\n        givenConfiguration(LOGIN_BANNER_SERVICE_PID, //\n                \"post.login.banner.enabled\", true, //\n                \"post.login.banner.content\", \"foo\");\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        thenRequestSucceeds();\n\n        thenResponseBodyEqualsJson(\"{\\\"passwordChangeNeeded\\\":false,\\\"message\\\":\\\"foo\\\"}\");\n    }\n\n    @Test\n    public void shouldChangeSessionCookieRepeatingPasswordAuthentication() {\n        givenConfiguration(LOGIN_BANNER_SERVICE_PID, //\n                \"pre.login.banner.enabled\", false, //\n                \"post.login.banner.enabled\", false);\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n\n        thenResponseCodeIs(200);\n        thenResponseBodyEqualsJson(\"{\\\"passwordChangeNeeded\\\":false}\");\n        thenCurrentCookieDiffersFromPreviousSnapshot(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldChangeSessionCookieAfterPasswordChange() {\n        givenConfiguration(LOGIN_BANNER_SERVICE_PID, //\n                \"pre.login.banner.enabled\", false);\n        givenConfiguration(PASSWORD_STRENGTH_VERIFICATION_SERVICE_PID, //\n                \"new.password.min.length\", 1, //\n                \"new.password.require.digits\", false, //\n                \"new.password.require.special.characters\", false, //\n                \"new.password.require.both.cases\", false);\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList(), true);\n        givenNoBasicCredentials();\n\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        givenXsrfToken(\"http\", 8080);\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/changePassword\",\n                \"{\\\"currentPassword\\\":\\\"bar\\\",\\\"newPassword\\\":\\\"baz\\\"}\");\n\n        thenRequestSucceeds();\n        thenCurrentCookieDiffersFromPreviousSnapshot(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldChangeSessionCookieRepeatingCertificateAuthentication() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.empty(), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        givenSuccessfulRequest(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n\n        thenRequestSucceeds();\n        thenCurrentCookieDiffersFromPreviousSnapshot(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldChangeSessionCookieAuthenticatingWithPasswordAndThenWithCertificateOnDifferentPort() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n\n        thenRequestSucceeds();\n        thenCurrentCookieDiffersFromPreviousSnapshot(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldChangeSessionCookieAuthenticatingWithCertificateAndThenWithPasswordOnDifferentPort() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        givenSuccessfulRequest(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        thenRequestSucceeds();\n        thenCurrentCookieDiffersFromPreviousSnapshot(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldChangeSessionCookieAuthenticatingWithPasswordAndThenWithCertificateOnSamePort() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        givenSuccessfulRequest(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n\n        thenRequestSucceeds();\n        thenCurrentCookieDiffersFromPreviousSnapshot(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldChangeSessionCookieAuthenticatingWithCertificateAndThenWithPasswordOnSamePort() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"foo\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        givenSuccessfulRequest(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        thenRequestSucceeds();\n        thenCurrentCookieDiffersFromPreviousSnapshot(\"JSESSIONID\");\n    }\n\n    @Test\n    public void shouldNotLoginWithOldCookieAfterNewLogin() {\n        givenConfiguration(LOGIN_BANNER_SERVICE_PID, //\n                \"pre.login.banner.enabled\", false);\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n\n        whenCookieIsRestoredFromSnapshot(\"JSESSIONID\");\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/xsrfToken\", null);\n\n        thenResponseCodeIs(401);\n\n    }\n\n    @Test\n    public void shouldInvalidateSessionAfterFailedPasswordLogin() {\n        givenConfiguration(LOGIN_BANNER_SERVICE_PID, //\n                \"pre.login.banner.enabled\", false);\n        givenService(new RequiresAssetsRole());\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList());\n        givenNoBasicCredentials();\n\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"baz\\\"}\");\n\n        whenCookieIsRestoredFromSnapshot(\"JSESSIONID\");\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/xsrfToken\", null);\n\n        thenResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldInvalidateSessionAfterFailedCertificateLogin() {\n        givenRestServiceConfiguration(Collections.singletonMap(\"allowed.ports\", new Integer[] { 8080, 9999 }));\n        givenNoBasicCredentials();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Arrays.asList(\"rest.assets\"));\n        givenService(new RequiresAssetsRole());\n        givenCA(\"clientCA\");\n        givenCA(\"serverCA\");\n        givenKeystoreService(\"clientKeystore\");\n        givenCACertificateInKeystore(\"clientKeystore\", \"serverCA\");\n        givenKeystoreService(\"serverKeystore\");\n        givenCACertificateInKeystore(\"serverKeystore\", \"clientCA\");\n        givenKeyPairInKeystore(\"clientKeystore\", \"clientCA\", \"bar\");\n        givenKeyPairInKeystore(\"serverKeystore\", \"serverCA\", \"serverCert\");\n        givenHttpServiceClientCertAuthEnabled(\"serverKeystore\", 9999);\n        givenClientKeystore(\"clientKeystore\");\n\n        givenSuccessfulRequest(\"http\", 8080, new MethodSpec(\"POST\"), \"/session/v1/login/password\",\n                \"{\\\"username\\\":\\\"foo\\\",\\\"password\\\":\\\"bar\\\"}\");\n        givenSnapshotOfCurrentCookies();\n        givenCookieInSnapshot(\"JSESSIONID\");\n\n        givenXsrfToken();\n\n        whenRequestIsPerformed(\"https\", 9999, new MethodSpec(\"POST\"), \"/session/v1/login/certificate\", null);\n\n        whenCookieIsRestoredFromSnapshot(\"JSESSIONID\");\n        whenRequestIsPerformed(\"http\", 8080, new MethodSpec(\"GET\"), \"/session/v1/xsrfToken\", null);\n\n        thenResponseCodeIs(401);\n    }\n\n    private List<ServiceRegistration<?>> registeredServices = new ArrayList<>();\n    private CompletableFuture<Void> providerEnabled = new CompletableFuture<>();\n    private CompletableFuture<Void> providerDisabled = new CompletableFuture<>();\n    private CompletableFuture<Void> providerAuthenticated = new CompletableFuture<>();\n    private boolean customizedConfig = false;\n    private final Map<String, KeystoreService> keystoreServices = new HashMap<>();\n    private final Map<String, TestCA> testCAs = new HashMap<>();\n    private final Set<String> createdFactoryPids = new HashSet<>();\n\n    public void givenNoBasicCredentials() {\n        givenBasicCredentials(Optional.empty());\n    }\n\n    public void givenBasicCredentials(final Optional<String> basicCredentials) {\n        ((RestTransport) this.transport).setBasicCredentials(basicCredentials);\n    }\n\n    private void givenRestServiceConfiguration(final Map<String, Object> properties) {\n        try {\n            final ConfigurationService configurationService = ServiceUtil\n                    .trackService(ConfigurationService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n            ServiceUtil\n                    .updateComponentConfiguration(configurationService,\n                            \"org.eclipse.kura.internal.rest.provider.RestService\", properties)\n                    .get(30, TimeUnit.SECONDS);\n\n            customizedConfig = true;\n        } catch (final Exception e) {\n            fail(\"failed to update rest service configuration\");\n            return;\n        }\n\n    }\n\n    private void givenKeystoreService(final String pid) {\n        try {\n            final ConfigurationService configurationService = ServiceUtil\n                    .trackService(ConfigurationService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n            final java.nio.file.Path directoryPath = Files.createTempDirectory(null);\n\n            final Map<String, Object> properties = Collections.singletonMap(\"keystore.path\",\n                    new File(directoryPath.toFile(), System.nanoTime() + \".ks\").getAbsolutePath());\n\n            final KeystoreService keystoreService = ServiceUtil\n                    .createFactoryConfiguration(configurationService, KeystoreService.class, pid,\n                            \"org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl\", properties)\n                    .get(30, TimeUnit.SECONDS);\n\n            this.keystoreServices.put(pid, keystoreService);\n            this.createdFactoryPids.add(pid);\n        } catch (final Exception e) {\n            fail(\"failed to create KeystoreService\");\n            return;\n        }\n    }\n\n    private void givenCA(final String cn) {\n        try {\n            final TestCA testCA = new TestCA(\n                    CertificateCreationOptions.builder(new X500Name(\"cn=\" + cn + \", dc=bar.com\")).build());\n            this.testCAs.put(cn, testCA);\n        } catch (Exception e) {\n            fail(\"cannot cerate test CA\");\n        }\n    }\n\n    private void givenCACertificateInKeystore(final String keystorePid, final String caCN) {\n        try {\n            final TestCA testCA = this.testCAs.get(caCN);\n            final KeystoreService keystoreService = this.keystoreServices.get(keystorePid);\n\n            keystoreService.setEntry(caCN, new TrustedCertificateEntry(testCA.getCertificate()));\n        } catch (Exception e) {\n            fail(\"cannot store trusted certificate\");\n        }\n    }\n\n    private void givenKeyPairInKeystore(final String keystorePid, final String caCN, final String certCN) {\n        try {\n            final TestCA testCA = this.testCAs.get(caCN);\n            final KeystoreService keystoreService = this.keystoreServices.get(keystorePid);\n\n            final KeyPair keyPair = TestCA.generateKeyPair();\n            final X509Certificate clientCertificate = testCA.createAndSignCertificate(\n                    CertificateCreationOptions.builder(new X500Name(\"cn=\" + certCN + \", dc=bar.com\")).build(), keyPair);\n\n            keystoreService.setEntry(certCN, new PrivateKeyEntry(keyPair.getPrivate(),\n                    new Certificate[] { clientCertificate, testCA.getCertificate() }));\n        } catch (Exception e) {\n            fail(\"cannot create client key pair\");\n        }\n    }\n\n    private void givenHttpServiceClientCertAuthEnabled(final String keystorePid, final int port) {\n        try {\n            final ConfigurationService configurationService = ServiceUtil\n                    .trackService(ConfigurationService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n            final Map<String, Object> properties = new HashMap<>();\n            properties.put(\"KeystoreService.target\", \"(kura.service.pid=\" + keystorePid + \")\");\n            properties.put(\"https.client.auth.ports\", new Integer[] { port });\n\n            configurationService.updateConfiguration(\"org.eclipse.kura.http.server.manager.HttpService\", properties);\n\n            RestTransport.waitPortOpen(\"localhost\", port, 1, TimeUnit.MINUTES);\n\n        } catch (Exception e) {\n            fail(\"cannot set httpservice keystore pid\");\n        }\n    }\n\n    private void givenHttpServiceClientCertAuthDisabled() {\n        try {\n            final ConfigurationService configurationService = ServiceUtil\n                    .trackService(ConfigurationService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n            final Map<String, Object> properties = Collections.singletonMap(\"https.client.auth.ports\",\n                    new Integer[] {});\n\n            configurationService.updateConfiguration(\"org.eclipse.kura.http.server.manager.HttpService\", properties);\n\n            RestTransport.waitPortOpen(\"localhost\", 8080, 1, TimeUnit.MINUTES);\n\n        } catch (Exception e) {\n            fail(\"cannot set httpservice keystore pid\");\n        }\n    }\n\n    private void givenConfiguration(final String pid, final Object... properties) {\n        try {\n            final ConfigurationAdmin configAdmin = ServiceUtil.trackService(ConfigurationAdmin.class, Optional.empty())\n                    .get(30, TimeUnit.SECONDS);\n\n            final Configuration configuration = configAdmin.getConfiguration(pid, \"?\");\n\n            final Dictionary<String, Object> configurationProperties = Optional\n                    .ofNullable(configuration.getProperties()).orElseGet(Hashtable::new);\n\n            final Iterator<Object> iter = Arrays.asList(properties).iterator();\n\n            while (iter.hasNext()) {\n                final String key = (String) iter.next();\n                final Object value = iter.next();\n\n                configurationProperties.put(key, value);\n            }\n\n            configuration.update(configurationProperties);\n\n        } catch (Exception e) {\n            fail(\"cannot updtate configuration\");\n        }\n    }\n\n    private void givenClientKeystore(final String keystorePid) {\n        try {\n            final KeystoreService keystoreService = this.keystoreServices.get(keystorePid);\n\n            TrustManagerFactory trustManagerFactory = TrustManagerFactory\n                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());\n            trustManagerFactory.init(keystoreService.getKeyStore());\n            SSLContext sslContext = SSLContext.getInstance(\"TLSv1.2\");\n\n            sslContext.init(\n                    keystoreService.getKeyManagers(KeyManagerFactory.getDefaultAlgorithm()).toArray(new KeyManager[0]),\n                    trustManagerFactory.getTrustManagers(), new SecureRandom());\n\n            ((RestTransport) this.transport).setSslContext(sslContext);\n        } catch (Exception e) {\n            fail(\"cannot set httpservice keystore pid\");\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T extends TestService> void givenService(final T service) {\n        final BundleContext bundleContext = FrameworkUtil.getBundle(RestServiceTest.class).getBundleContext();\n\n        final Dictionary<String, Object> properties = new Hashtable<>();\n        properties.put(\"osgi.jakartars.resource\", true);\n\n        registeredServices.add(bundleContext.registerService((Class<T>) service.getClass(), service, properties));\n\n        final RestTransport restTransport = (RestTransport) this.transport;\n\n        for (int i = 0; i < 100; i++) {\n            final Response response = restTransport.runRequest(\"/ping\", new MethodSpec(\"GET\"));\n\n            if (response.getStatus() != 404 && response.getStatus() != 503) {\n                break;\n            }\n\n            try {\n                synchronized (this) {\n                    this.wait(100);\n                }\n            } catch (InterruptedException e) {\n                fail(\"Interrupted wile waiting for service startup\");\n                return;\n            }\n        }\n    }\n\n    private void givenIdentity(final String username, final Optional<String> password, final List<String> roles) {\n        givenIdentity(username, password, roles, false);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void givenIdentity(final String username, final Optional<String> password, final List<String> roles,\n            final boolean needsPasswordChange) {\n        final UserAdmin userAdmin;\n\n        try {\n            userAdmin = ServiceUtil.trackService(UserAdmin.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n        } catch (Exception e) {\n            fail(\"failed to track UserAdmin\");\n            return;\n        }\n\n        final User user = getOrCreateRole(userAdmin, \"kura.user.\" + username, User.class);\n\n        if (password.isPresent()) {\n            try {\n                final CryptoService cryptoService = ServiceUtil.trackService(CryptoService.class, Optional.empty())\n                        .get(30, TimeUnit.SECONDS);\n\n                user.getCredentials().put(\"kura.password\", cryptoService.sha256Hash(password.get()));\n\n            } catch (Exception e) {\n                fail(\"failed to compute password hash\");\n            }\n        }\n\n        if (needsPasswordChange) {\n            user.getProperties().put(\"kura.need.password.change\", \"true\");\n        } else {\n            user.getProperties().remove(\"kura.need.password.change\");\n        }\n\n        for (final String role : roles) {\n            getOrCreateRole(userAdmin, \"kura.permission.\" + role, Group.class).addMember(user);\n        }\n    }\n\n    private void givenAuthenticationProvider(final AuthenticationProvider provider) {\n        final BundleContext bundleContext = FrameworkUtil.getBundle(RestServiceTest.class).getBundleContext();\n\n        this.registeredServices.add(bundleContext.registerService(AuthenticationProvider.class, provider, null));\n\n        try {\n            this.providerEnabled.get(30, TimeUnit.SECONDS);\n        } catch (final Exception e) {\n            fail(\"provider was not enabled\");\n        }\n    }\n\n    private void givenSuccessfulRequest(final String proto, final int port, final MethodSpec method,\n            final String resource, final String body) {\n        whenRequestIsPerformed(proto, port, method, resource, body);\n        thenRequestSucceeds();\n    }\n\n    private void givenSuccessfulRequest(final MethodSpec method, final String resource) {\n        whenRequestIsPerformed(method, resource);\n        thenRequestSucceeds();\n    }\n\n    private void givenXsrfToken() {\n        whenXsrfTokenIsObtained();\n    }\n\n    private void givenXsrfToken(final String protocol, final int port) {\n        whenXsrfTokenIsObtained(protocol, port);\n    }\n\n    private void givenDelay(final long amount, final TimeUnit timeUnit) {\n        whenDelayPasses(amount, timeUnit);\n    }\n\n    private void whenRequestIsPerformed(final String proto, final int port, final MethodSpec method,\n            final String resource, final String body) {\n        final RestTransport restTransport = (RestTransport) this.transport;\n\n        this.response = Optional\n                .of(restTransport.runRequest(proto + \"://localhost:\" + port + \"/services\", resource, method, body));\n    }\n\n    private void whenXsrfTokenIsObtained() {\n        whenXsrfTokenIsObtained(\"http\", 8080);\n    }\n\n    private void whenXsrfTokenIsObtained(final String protocol, final int port) {\n        final RestTransport restTransport = (RestTransport) this.transport;\n\n        final Response response = restTransport.runRequest(protocol + \"://localhost:\" + port + \"/services\",\n                \"/session/v1/xsrfToken\", new MethodSpec(\"GET\"), null);\n\n        final JsonObject object = Json\n                .parse(response.getBody().orElseThrow(() -> new IllegalStateException(\"no response body\"))).asObject();\n\n        final String token = object.get(\"xsrfToken\").asString();\n\n        restTransport.setHeader(\"X-XSRF-Token\", token);\n    }\n\n    private void whenDelayPasses(final long amount, final TimeUnit timeUnit) {\n        synchronized (this) {\n            try {\n                this.wait(timeUnit.toMillis(amount));\n            } catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n            }\n        }\n    }\n\n    private void whenAuthenticationProviderIsRegistered(final AuthenticationProvider provider) {\n        givenAuthenticationProvider(provider);\n    }\n\n    private void whenLastRegisteredServiceIsUnregistered() {\n        this.registeredServices.remove(this.registeredServices.size() - 1).unregister();\n    }\n\n    private void whenIdentityIsUpdated(final String username, final Optional<String> password,\n            final List<String> roles) {\n        givenIdentity(username, password, roles, false);\n    }\n\n    private void thenProviderIsEnabled() {\n        try {\n            this.providerEnabled.get(30, TimeUnit.SECONDS);\n        } catch (final Exception e) {\n            fail(\"provider was not enabled\");\n        }\n    }\n\n    private void thenProviderIsDisabled() {\n        try {\n            this.providerDisabled.get(30, TimeUnit.SECONDS);\n        } catch (final Exception e) {\n            fail(\"provider was not enabled\");\n        }\n    }\n\n    private void thenProviderAuthenticatedRequest() {\n        try {\n            this.providerAuthenticated.get(30, TimeUnit.SECONDS);\n        } catch (final Exception e) {\n            fail(\"provider didn't authenticate request\");\n        }\n    }\n\n    private void thenProviderDidNotAuthenticateRequest() {\n        assertFalse(\"provider authenticated request\", this.providerAuthenticated.isDone());\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T extends Role> T getOrCreateRole(final UserAdmin userAdmin, final String name, final Class<T> classz) {\n\n        final Role existing = userAdmin.getRole(name);\n\n        if (classz.isInstance(existing)) {\n            return (T) existing;\n        }\n\n        final int type;\n\n        if (classz == User.class) {\n            type = Role.USER;\n        } else if (classz == Group.class) {\n            type = Role.GROUP;\n        } else {\n            fail(\"Unsupported role type\");\n            return null;\n        }\n\n        return (T) userAdmin.createRole(name, type);\n    }\n\n    @After\n    public void cleanUp() {\n        this.registeredServices.forEach(ServiceRegistration::unregister);\n\n        if (customizedConfig) {\n            final Map<String, Object> defaultConfig = new HashMap<>();\n            defaultConfig.put(\"auth.password.enabled\", true);\n            defaultConfig.put(\"auth.certificate.enabled\", true);\n            defaultConfig.put(\"auth.certificate.stateless.enabled\", true);\n            defaultConfig.put(\"auth.basic.enabled\", true);\n            defaultConfig.put(\"session.inactivity.interval\", 900);\n            defaultConfig.put(\"allowed.ports\", new Integer[] {});\n\n            givenRestServiceConfiguration(defaultConfig);\n        }\n\n        try {\n            if (createdFactoryPids.isEmpty()) {\n                return;\n            }\n\n            final ConfigurationService configurationService = ServiceUtil\n                    .trackService(ConfigurationService.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n\n            for (final String pid : createdFactoryPids) {\n                ServiceUtil.deleteFactoryConfiguration(configurationService, pid).get(30, TimeUnit.SECONDS);\n            }\n        } catch (final Exception e) {\n            fail(\"failed to cleanup registered factory components\");\n        }\n    }\n\n    private static Map<String, Object> map(final Object... objects) {\n        final Iterator<Object> iter = Arrays.asList(objects).iterator();\n\n        final Map<String, Object> result = new HashMap<>();\n\n        while (iter.hasNext()) {\n            final Object key = iter.next();\n            final Object value = iter.next();\n\n            result.put((String) key, value);\n        }\n\n        return result;\n    }\n\n    public static abstract class TestService {\n\n        @GET\n        @Path(\"/ping\")\n        public String ping() {\n            return \"ok\";\n        }\n\n    }\n\n    @Path(\"testservice\")\n    public static class NoAuth extends TestService {\n\n        @GET\n        @Path(\"/noAuth\")\n        public String noAuth() {\n            return \"Hello\";\n        }\n    }\n\n    @Path(\"testservice\")\n    public static class RequiresAssetsRole extends TestService {\n\n        @GET\n        @Path(\"requireAssets\")\n        @RolesAllowed(\"assets\")\n        public String requireAssets() {\n            return \"Hello\";\n        }\n    }\n\n    public class DummyAuthenticationProvider implements AuthenticationProvider {\n\n        final String expectedCredentials;\n        final String targetIdentity;\n\n        public DummyAuthenticationProvider(final String expectedUsername, final String expectedPassword,\n                final String targetIdentity) {\n            this.expectedCredentials = expectedUsername + \":\" + expectedPassword;\n            this.targetIdentity = targetIdentity;\n        }\n\n        @Override\n        public void onEnabled() {\n            providerEnabled.complete(null);\n        }\n\n        @Override\n        public void onDisabled() {\n            providerDisabled.complete(null);\n        }\n\n        @Override\n        public Optional<Principal> authenticate(HttpServletRequest request, ContainerRequestContext requestContext) {\n\n            String authHeader = requestContext.getHeaderString(\"Authorization\");\n            if (authHeader == null) {\n                return Optional.empty();\n            }\n\n            StringTokenizer tokens = new StringTokenizer(authHeader);\n            String authScheme = tokens.nextToken();\n            if (!\"Basic\".equals(authScheme)) {\n                return Optional.empty();\n            }\n\n            final String credentials = new String(Base64.getDecoder().decode(tokens.nextToken()),\n                    StandardCharsets.UTF_8);\n\n            if (expectedCredentials.equals(credentials)) {\n                providerAuthenticated.complete(null);\n                return Optional.of(() -> targetIdentity);\n            } else {\n                return Optional.empty();\n            }\n        }\n    }\n\n    @Priority(1000)\n    private class LowPriorityAuthenticationProvider extends DummyAuthenticationProvider {\n\n        public LowPriorityAuthenticationProvider(String expectedUsername, String expectedPassword,\n                String targetIdentity) {\n            super(expectedUsername, expectedPassword, targetIdentity);\n        }\n    }\n\n    @Priority(1)\n    private class HighPriorityAuthenticationProvider extends DummyAuthenticationProvider {\n\n        public HighPriorityAuthenticationProvider(String expectedUsername, String expectedPassword,\n                String targetIdentity) {\n            super(expectedUsername, expectedPassword, targetIdentity);\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.security.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.security.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.security.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.core.testutil.requesthandler;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.util.wire.test;version=\"[1.1,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.25\",\n org.mockito.verification\nFragment-Host: org.eclipse.kura.rest.security.provider\nRequire-Bundle: org.eclipse.kura.http.server.manager;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.security.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java,\\\n           src/test/java\nbin.includes = META-INF/,\\\n               .\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.security.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n        Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.rest.security.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                        <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.security.provider.test/src/main/java/org/eclipse/kura/internal/rest/security/provider/test/SecurityEndpointsV1Test.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.security.provider.test;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV1;\nimport org.eclipse.kura.security.SecurityService;\nimport org.eclipse.kura.util.wire.test.WireTestUtil;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\n\nimport jakarta.ws.rs.core.Response.Status;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.junit.Assert.fail;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\nimport static org.mockito.Mockito.when;\n\n@RunWith(Parameterized.class)\npublic class SecurityEndpointsV1Test extends AbstractRequestHandlerTest {\n\n    private static final String MQTT_APP_ID = \"SEC-V1\";\n\n    private static final String EXPECTED_DEBUG_ENABLE_TRUE_RESPONSE = \"{\\\"enabled\\\":true}\";\n\n    private static final String METHOD_SPEC_GET = \"GET\";\n    private static final String METHOD_SPEC_POST = \"POST\";\n    private static final String REST_APP_ID = \"security/v1\";\n\n    private static final SecurityService securityServiceMock = mock(SecurityService.class);\n    private static ServiceRegistration<SecurityService> securityServiceRegistration;\n    public static final String DEBUG_ENABLED = \"/debug-enabled\";\n    public static final String ADMIN_ADMIN = \"admin:admin\";\n\n    @Parameterized.Parameters\n    public static Collection<Transport> transports() {\n        return Arrays.asList(new RestTransport(REST_APP_ID), new MqttTransport(MQTT_APP_ID));\n    }\n\n    private static boolean debugEnabled;\n\n    public SecurityEndpointsV1Test(Transport transport) {\n        super(transport);\n    }\n\n    @Test\n    public void shouldInvokeReloadSecurityPolicyFingerprintSuccessfully() {\n        givenSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/security-policy-fingerprint/reload\");\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n    }\n\n    @Test\n    public void shouldInvokeReloadCommandLineFingerprintSuccessfully() {\n        givenSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/command-line-fingerprint/reload\");\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n    }\n\n    @Test\n    public void shouldReturnExpectedDebugStatus() {\n        givenDebugEnabledStatus(true);\n        givenSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), DEBUG_ENABLED);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_DEBUG_ENABLE_TRUE_RESPONSE);\n    }\n\n    @Test\n    public void shouldNotReturnDebugStatusOverRestIfNotLoggedIn() {\n        givenDebugEnabledStatus(true);\n        givenSecurityService();\n        givenNoRestBasicCredentials();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), DEBUG_ENABLED);\n\n        thenRestResponseCodeIs(401);\n        thenMqttResponseCodeIs(200);\n    }\n\n    @Test\n    public void shouldReturnDebugStatusEvenIfIdentityHasNoPermissions() {\n        givenDebugEnabledStatus(true);\n        givenSecurityService();\n        givenIdentity(\"foo\", Optional.of(\"bar\"), Collections.emptyList(), false);\n        givenRestBasicCredentials(\"foo:bar\");\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), DEBUG_ENABLED);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_DEBUG_ENABLE_TRUE_RESPONSE);\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnReloadSecurityPolicyFingerprint() throws KuraException {\n        givenFailingSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/security-policy-fingerprint/reload\");\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnReloadCommandLineFingerprint() throws KuraException {\n        givenFailingSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/command-line-fingerprint/reload\");\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnGetDebugStatus() throws KuraException {\n        givenFailingSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), DEBUG_ENABLED);\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    private static void givenDebugEnabledStatus(boolean debugStatus) {\n        debugEnabled = debugStatus;\n    }\n\n    private static void givenSecurityService() {\n        reset(securityServiceMock);\n\n        when(securityServiceMock.isDebugEnabled()).thenReturn(debugEnabled);\n    }\n\n    private static void givenFailingSecurityService() throws KuraException {\n        reset(securityServiceMock);\n\n        when(securityServiceMock.isDebugEnabled()).thenThrow(RuntimeException.class);\n        doThrow(RuntimeException.class).when(securityServiceMock).applyDefaultProductionSecurityPolicy();\n        doThrow(RuntimeException.class).when(securityServiceMock).reloadCommandLineFingerprint();\n        doThrow(RuntimeException.class).when(securityServiceMock).reloadSecurityPolicyFingerprint();\n    }\n\n    /*\n     * Utilities\n     */\n\n    private void givenIdentity(final String username, final Optional<String> password, final List<String> roles,\n            final boolean needsPasswordChange) {\n        final UserAdmin userAdmin;\n\n        try {\n            userAdmin = ServiceUtil.trackService(UserAdmin.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n        } catch (Exception e) {\n            fail(\"failed to track UserAdmin\");\n            return;\n        }\n\n        final User user = getOrCreateRole(userAdmin, \"kura.user.\" + username, User.class);\n\n        if (password.isPresent()) {\n            try {\n                final CryptoService cryptoService = ServiceUtil.trackService(CryptoService.class, Optional.empty())\n                        .get(30, TimeUnit.SECONDS);\n\n                user.getCredentials().put(\"kura.password\", cryptoService.sha256Hash(password.get()));\n\n            } catch (Exception e) {\n                fail(\"failed to compute password hash\");\n            }\n        }\n\n        if (needsPasswordChange) {\n            user.getProperties().put(\"kura.need.password.change\", \"true\");\n        } else {\n            user.getProperties().remove(\"kura.need.password.change\");\n        }\n\n        for (final String role : roles) {\n            getOrCreateRole(userAdmin, \"kura.permission.\" + role, Group.class).addMember(user);\n        }\n    }\n\n    private void givenNoRestBasicCredentials() {\n        if (this.transport instanceof RestTransport) {\n            ((RestTransport) this.transport).setBasicCredentials(Optional.empty());\n        }\n    }\n\n    private void givenRestBasicCredentials(final String credentials) {\n        if (this.transport instanceof RestTransport) {\n            ((RestTransport) this.transport).setBasicCredentials(Optional.of(credentials));\n        }\n    }\n\n    private void thenRestResponseCodeIs(final int expectedStatusCode) {\n        if (this.transport instanceof RestTransport) {\n            thenResponseCodeIs(expectedStatusCode);\n        }\n    }\n\n    private void thenMqttResponseCodeIs(final int expectedStatusCode) {\n        if (this.transport instanceof MqttTransport) {\n            thenResponseCodeIs(expectedStatusCode);\n        }\n    }\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        createSecurityServiceMock();\n        registerSecurityServiceMock();\n        configureSecurityServiceMock();\n    }\n\n    @AfterClass\n    public static void cleanup() throws Exception {\n        unregisterSecurityServiceMock();\n    }\n\n    private static void createSecurityServiceMock() {\n        givenSecurityService();\n    }\n\n    private static void registerSecurityServiceMock() {\n        final Dictionary<String, Object> configurationServiceProperties = new Hashtable<>();\n        configurationServiceProperties.put(\"service.ranking\", Integer.MIN_VALUE);\n        configurationServiceProperties.put(\"kura.service.pid\", \"mockSecurityService\");\n        securityServiceRegistration = FrameworkUtil.getBundle(SecurityEndpointsV1Test.class).getBundleContext()\n                .registerService(SecurityService.class, securityServiceMock, configurationServiceProperties);\n    }\n\n    private static void configureSecurityServiceMock() throws Exception {\n        final Dictionary<String, Object> properties = new Hashtable<>();\n        properties.put(\"SecurityService.target\", \"(kura.service.pid=mockSecurityService)\");\n\n        final ConfigurationAdmin configurationAdmin = WireTestUtil.trackService(ConfigurationAdmin.class,\n                Optional.empty()).get(30, TimeUnit.SECONDS);\n        final Configuration config = configurationAdmin.getConfiguration(SecurityRestServiceV1.class.getName(), \"?\");\n        config.update(properties);\n    }\n\n    private static void unregisterSecurityServiceMock() throws Exception {\n        securityServiceRegistration.unregister();\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T extends Role> T getOrCreateRole(final UserAdmin userAdmin, final String name, final Class<T> classz) {\n\n        final Role existing = userAdmin.getRole(name);\n\n        if (classz.isInstance(existing)) {\n            return (T) existing;\n        }\n\n        final int type;\n\n        if (classz == User.class) {\n            type = Role.USER;\n        } else if (classz == Group.class) {\n            type = Role.GROUP;\n        } else {\n            fail(\"Unsupported role type\");\n            return null;\n        }\n\n        return (T) userAdmin.createRole(name, type);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.security.provider.test/src/main/java/org/eclipse/kura/internal/rest/security/provider/test/SecurityEndpointsV2Test.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.security.provider.test;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV2;\nimport org.eclipse.kura.security.SecurityService;\nimport org.eclipse.kura.util.wire.test.WireTestUtil;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\n\nimport jakarta.ws.rs.core.Response.Status;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\n@RunWith(Parameterized.class)\npublic class SecurityEndpointsV2Test extends AbstractRequestHandlerTest {\n\n    private static final String MQTT_APP_ID = \"SEC-V2\";\n\n    private static final String METHOD_SPEC_POST = \"POST\";\n    private static final String REST_APP_ID = \"security/v2\";\n\n    private static final SecurityService securityServiceMock = mock(SecurityService.class);\n    private static ServiceRegistration<SecurityService> securityServiceRegistration;\n    public static final String ADMIN_ADMIN = \"admin:admin\";\n    public static final String SECURITY_POLICY_APPLY_DEFAULT_PRODUCTION = \"/security-policy/apply-default-production\";\n    public static final String SECURITY_POLICY_APPLY = \"/security-policy/apply\";\n    private static String securityPolicy;\n\n    @Parameterized.Parameters\n    public static Collection<Transport> transports() {\n        return Arrays.asList(new RestTransport(REST_APP_ID), new MqttTransport(MQTT_APP_ID));\n    }\n\n    public SecurityEndpointsV2Test(Transport transport) {\n        super(transport);\n    }\n\n    @Test\n    public void shouldCopyDefaultSecurityPolicy() throws KuraException {\n        givenSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), SECURITY_POLICY_APPLY_DEFAULT_PRODUCTION);\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n        thenApplyDefaultProductionSecurityPolicyIsCalled();\n    }\n\n    @Test\n    public void shouldReloadFingerprintsWhenDefaultSecurityPolicyIsApplied() throws IOException, KuraException {\n        givenSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), SECURITY_POLICY_APPLY_DEFAULT_PRODUCTION);\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n        thenFingerprintsAreReloaded();\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnApplyDefaultProductionSecurityPolicy() throws KuraException {\n        givenFailingSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), SECURITY_POLICY_APPLY_DEFAULT_PRODUCTION);\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnApplyNullSecurityPolicy() throws KuraException {\n        givenSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), SECURITY_POLICY_APPLY, null);\n\n        thenResponseCodeIs(Status.BAD_REQUEST.getStatusCode());\n        thenResponseBodyEqualsJson(\"{\\\"message\\\":\\\"Security Policy cannot be null or empty\\\"}\");\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnApplyEmptySecurityPolicy() throws KuraException {\n        givenSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), SECURITY_POLICY_APPLY, \"\");\n\n        thenResponseCodeIs(Status.BAD_REQUEST.getStatusCode());\n        thenResponseBodyEqualsJson(\"{\\\"message\\\":\\\"Security Policy cannot be null or empty\\\"}\");\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnApplyTooBigSecurityPolicy() throws KuraException {\n        givenSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n        givenTooLargeSecurityPolicy();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), SECURITY_POLICY_APPLY, securityPolicy);\n\n        thenResponseCodeIs(Status.BAD_REQUEST.getStatusCode());\n        thenResponseBodyEqualsJson(\"{\\\"message\\\":\\\"Security policy too large\\\"}\");\n    }\n\n    @Test\n    public void shouldApplySecurityPolicy() throws KuraException {\n        givenSecurityService();\n        givenRestBasicCredentials(ADMIN_ADMIN);\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), SECURITY_POLICY_APPLY,\n                \"This is a very cool security policy!\");\n\n        thenRequestSucceeds();\n        thenResponseBodyIsEmpty();\n        thenApplySecurityPolicyIsCalled(\"This is a very cool security policy!\");\n    }\n\n    private static void givenSecurityService() {\n        reset(securityServiceMock);\n    }\n\n    private static void givenFailingSecurityService() throws KuraException {\n        reset(securityServiceMock);\n\n        doThrow(RuntimeException.class).when(securityServiceMock).applyDefaultProductionSecurityPolicy();\n        doThrow(RuntimeException.class).when(securityServiceMock).reloadCommandLineFingerprint();\n        doThrow(RuntimeException.class).when(securityServiceMock).reloadSecurityPolicyFingerprint();\n    }\n\n    /*\n     * Utilities\n     */\n\n    private void givenRestBasicCredentials(final String credentials) {\n        if (this.transport instanceof RestTransport) {\n            ((RestTransport) this.transport).setBasicCredentials(Optional.of(credentials));\n        }\n    }\n\n    private static void givenTooLargeSecurityPolicy() {\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < 100000; i++) {\n            sb.append(\"This is a very large security policy!\");\n        }\n        securityPolicy = sb.toString();\n    }\n\n    private void thenApplyDefaultProductionSecurityPolicyIsCalled() throws KuraException {\n        verify(securityServiceMock, times(1)).applyDefaultProductionSecurityPolicy();\n    }\n\n    private void thenFingerprintsAreReloaded() throws KuraException {\n        verify(securityServiceMock, times(1)).reloadSecurityPolicyFingerprint();\n        verify(securityServiceMock, times(1)).reloadCommandLineFingerprint();\n    }\n\n    private void thenApplySecurityPolicyIsCalled(final String securityPolicy) throws KuraException {\n        verify(securityServiceMock, times(1)).applySecurityPolicy(securityPolicy);\n    }\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        createSecurityServiceMock();\n        registerSecurityServiceMock();\n        configureSecurityServiceMock();\n    }\n\n    @AfterClass\n    public static void cleanup() throws Exception {\n        unregisterSecurityServiceMock();\n    }\n\n    private static void createSecurityServiceMock() {\n        givenSecurityService();\n    }\n\n    private static void registerSecurityServiceMock() {\n        final Dictionary<String, Object> configurationServiceProperties = new Hashtable<>();\n        configurationServiceProperties.put(\"service.ranking\", Integer.MIN_VALUE);\n        configurationServiceProperties.put(\"kura.service.pid\", \"mockSecurityService\");\n        securityServiceRegistration = FrameworkUtil.getBundle(SecurityEndpointsV2Test.class).getBundleContext()\n                .registerService(SecurityService.class, securityServiceMock, configurationServiceProperties);\n    }\n\n    private static void configureSecurityServiceMock() throws Exception {\n        final Dictionary<String, Object> properties = new Hashtable<>();\n        properties.put(\"SecurityService.target\", \"(kura.service.pid=mockSecurityService)\");\n\n        final ConfigurationAdmin configurationAdmin = WireTestUtil.trackService(ConfigurationAdmin.class,\n                Optional.empty()).get(30, TimeUnit.SECONDS);\n        final Configuration config = configurationAdmin.getConfiguration(SecurityRestServiceV2.class.getName(), \"?\");\n        config.update(properties);\n    }\n\n    private static void unregisterSecurityServiceMock() throws Exception {\n        securityServiceRegistration.unregister();\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.security.provider.test/src/test/java/org/eclipse/kura/internal/rest/security/provider/test/SecurityServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.security.provider.test;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.internal.rest.security.provider.SecurityRestServiceV1;\nimport org.junit.Test;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Objects;\n\nimport static org.junit.Assert.assertNull;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\npublic class SecurityServiceTest {\n\n    private static final String MQTT_APP_ID = \"SEC-V1\";\n    private static final String REST_ROLE_NAME = \"security\";\n    private static final String KURA_PERMISSION_REST_ROLE = \"kura.permission.rest.\" + REST_ROLE_NAME;\n\n    private SecurityRestServiceV1 service = new SecurityRestServiceV1();\n    private UserAdmin userAdmin;\n    private RequestHandlerRegistry requestHandlerRegistry;\n    private Exception occurredException;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldCreateRoleOnUserAdminBinding() {\n        givenMockUserAdmin();\n\n        whenBindUserAdmin();\n\n        thenRoleIsCreated(KURA_PERMISSION_REST_ROLE, Role.GROUP);\n    }\n\n    @Test\n    public void shouldRegisterRequestHandler() throws KuraException {\n        givenMockRequestHandlerRegistry();\n\n        whenBindRequestHandlerRegistry();\n\n        thenRequestHandlerIsRegistered(MQTT_APP_ID);\n    }\n\n    @Test\n    public void shouldUnregisterRequestHandler() throws KuraException {\n        givenMockRequestHandlerRegistry();\n\n        whenUnbindRequestHandlerRegistry();\n\n        thenRequestHandlerIsUnregistered(MQTT_APP_ID);\n    }\n\n    @Test\n    public void shouldCatchExceptionsOnRequestHandlerBind() throws KuraException {\n        givenFailingMockRequestHandlerRegistry();\n\n        whenBindRequestHandlerRegistry();\n\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void shouldCatchExceptionsOnRequestHandlerUnbind() throws KuraException {\n        givenFailingMockRequestHandlerRegistry();\n\n        whenUnbindRequestHandlerRegistry();\n\n        thenNoExceptionOccurred();\n    }\n\n    /*\n     * Given\n     */\n\n    private void givenMockUserAdmin() {\n        this.userAdmin = mock(UserAdmin.class);\n    }\n\n    private void givenMockRequestHandlerRegistry() {\n        this.requestHandlerRegistry = mock(RequestHandlerRegistry.class);\n    }\n\n    private void givenFailingMockRequestHandlerRegistry() throws KuraException {\n        this.requestHandlerRegistry = mock(RequestHandlerRegistry.class);\n        doThrow(new KuraException(KuraErrorCode.BAD_REQUEST)).when(this.requestHandlerRegistry)\n                .registerRequestHandler(any(), any());\n        doThrow(new KuraException(KuraErrorCode.BAD_REQUEST)).when(this.requestHandlerRegistry).unregister(any());\n    }\n\n    /*\n     * When\n     */\n\n    private void whenBindUserAdmin() {\n        this.service.bindUserAdmin(this.userAdmin);\n    }\n\n    private void whenBindRequestHandlerRegistry() {\n        try {\n            this.service.bindRequestHandlerRegistry(this.requestHandlerRegistry);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenUnbindRequestHandlerRegistry() {\n        try {\n            this.service.unbindRequestHandlerRegistry(this.requestHandlerRegistry);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenRoleIsCreated(String expectedKuraPermission, int expectedRole) {\n        verify(this.userAdmin, times(1)).createRole(expectedKuraPermission, expectedRole);\n    }\n\n    private void thenRequestHandlerIsRegistered(String expectedMqttAppId) throws KuraException {\n        verify(this.requestHandlerRegistry, times(1)).registerRequestHandler(eq(expectedMqttAppId),\n                any(RequestHandler.class));\n    }\n\n    private void thenRequestHandlerIsUnregistered(String expectedMqttAppId) throws KuraException {\n        verify(this.requestHandlerRegistry, times(1)).unregister(expectedMqttAppId);\n    }\n\n    private void thenNoExceptionOccurred() {\n        String errorMessage = \"Empty message\";\n        if (Objects.nonNull(this.occurredException)) {\n            StringWriter sw = new StringWriter();\n            this.occurredException.printStackTrace(new PrintWriter(sw));\n\n            errorMessage = String.format(\"No exception expected, \\\"%s\\\" found. Caused by: %s\",\n                    this.occurredException.getClass().getName(), sw.toString());\n        }\n\n        assertNull(errorMessage, this.occurredException);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.service.listing.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.service.listing.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: com.eclipsesource.json;version=\"0.9.5\",\n jakarta.ws.rs.core;version=\"3.1.0\",\n org.eclipse.kura.core.testutil.requesthandler;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.testutil.service;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.util.wire.test;version=\"[1.1,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.25\"\nService-Component: OSGI-INF/*.xml\nRequire-Bundle: org.eclipse.kura.http.server.manager;bundle-version=\"1.1.0\",\n org.eclipse.kura.api,\n org.eclipse.kura.rest.service.listing.provider\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/OSGI-INF/TargetFilterTestService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"update\" immediate=\"true\" modified=\"deactivate\" name=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService\">\n    <implementation class=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService\"/>\n    <service>\n       <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n    </service>\n    <reference cardinality=\"0..n\" interface=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestInterface\" name=\"TestInterface\" policy=\"dynamic\"/>\n\n\n\n\n\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/OSGI-INF/TestFactory1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"update\" immediate=\"true\" modified=\"deactivate\" name=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\">\n   \n    <service>\n       <provide interface=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestInterface\"/>\n       <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n    </service>\n    <implementation class=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService\"/>\n    <property name=\"testProperty\" type=\"String\" value=\"testValue\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/OSGI-INF/TestFactory2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"update\" immediate=\"true\" modified=\"deactivate\" name=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\">\n    <implementation class=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService\"/>\n    <service>\n       <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n       <provide interface=\"org.eclipse.kura.internal.rest.service.listing.provider.test.OtherTestInterface\"/>\n    </service>\n    <property name=\"testProperty\" type=\"String\">value1\nvalue2\n    </property>\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/OSGI-INF/metatype/org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright (c) 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService\" \n    name=\"TargetFilterTestService\" \n    description=\"TargetFilterTestService\">\n\n        <AD \n\t        id=\"TestInterface.target\" \n\t        name=\"TestInterface target\" \n\t        type=\"String\" \n\t        cardinality=\"0\" \n\t        required=\"trie\"\n\t        default=\"(kura.service.pid=changeme)\">\n        </AD>\n\n    </OCD>\n\n    <Designate pid=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService\">\n        <Object ocdref=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService\" />\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/OSGI-INF/metatype/org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright (c) 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\" \n    name=\"TestFactory1\" \n    description=\"TestFactory1\">\n\n    </OCD>\n\n    <Designate factoryPid=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\">\n        <Object ocdref=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\" />\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/OSGI-INF/metatype/org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  Copyright (c) 2023 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\" \n    name=\"TestFactory2\" \n    description=\"TestFactory2\">\n\n    </OCD>\n\n    <Designate factoryPid=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\">\n        <Object ocdref=\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\" />\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java,\\\n           src/test/java\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n        Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.rest.service.listing.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                        <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/test/OtherTestInterface.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.service.listing.provider.test;\n\npublic interface OtherTestInterface {\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/test/ServiceListingEndpointsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.service.listing.provider.test;\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\n\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.crypto.CryptoService;\nimport org.eclipse.kura.internal.rest.service.listing.provider.test.constants.ServiceListeningTestConstants;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.mockito.Mockito;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonArray;\n\n@RunWith(Parameterized.class)\npublic class ServiceListingEndpointsTest extends AbstractRequestHandlerTest {\n\n    private static final String METHOD_SPEC_GET = \"GET\";\n    private static final String METHOD_SPEC_POST = \"POST\";\n\n    public ServiceListingEndpointsTest(final Transport transport) {\n        super(transport);\n    }\n\n    @Parameterized.Parameters\n    public static Collection<Transport> parameters() {\n        return Arrays.asList(new RestTransport(\"serviceListing/v1\"), new MqttTransport(\"SVCLIST-V1\"));\n    }\n\n    @Test\n    public void shouldReturnNotFoundIfNoServiceIsRegistered() {\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/nothing\");\n\n        thenResponseCodeIs(404);\n    }\n\n    @Test\n    public void restShouldReturnUnauthorizedStatusWhenNoRestPermissionIsGiven() {\n\n        givenIdentity(\"noAuthUser\", Optional.of(\"pass1\"), Collections.emptyList());\n        givenBasicCredentials(Optional.empty());\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/servicePids\");\n\n        thenRestResponseCodeIs(401);\n    }\n\n    @Test\n    public void shouldReturnListOfAllServices() {\n\n        givenRegisteredService(TestInterface.class, \"TestService\", Collections.emptyMap());\n        givenIdentity(\"authUser\", Optional.of(\"pass2\"), Collections.emptyList());\n        givenBasicCredentials(Optional.of(\"authUser:pass2\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/servicePids\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"TestService\");\n    }\n\n    @Test\n    public void shouldReturnListOfFilteredServices() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byInterface\",\n                ServiceListeningTestConstants.COMPLETE_POST_BODY);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(ServiceListeningTestConstants.FILTERED_SERVICES_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnErrorMessageWhenRequestBodyIsNull() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byInterface\",\n                ServiceListeningTestConstants.NULL_POST_BODY);\n\n        thenResponseCodeIs(Status.BAD_REQUEST.getStatusCode());\n        thenResponseBodyEqualsJson(ServiceListeningTestConstants.NULL_BODY_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnErrorMessageWhenRequestBodyIsEmpty() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byInterface\",\n                ServiceListeningTestConstants.EMPTY_POST_BODY);\n\n        thenResponseCodeIs(Status.BAD_REQUEST.getStatusCode());\n        thenResponseBodyEqualsJson(ServiceListeningTestConstants.EMPTY_BODY_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnErrorMessageWhenRequestBodyHasNullField() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byInterface\",\n                ServiceListeningTestConstants.NULL_FIELD_POST_BODY);\n\n        thenResponseCodeIs(Status.BAD_REQUEST.getStatusCode());\n        thenResponseBodyEqualsJson(ServiceListeningTestConstants.NULL_FIELD_BODY_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnErrorMessageWhenRequestBodyHasEmptyField() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byInterface\",\n                ServiceListeningTestConstants.EMPTY_FIELD_POST_BODY);\n\n        thenResponseCodeIs(Status.BAD_REQUEST.getStatusCode());\n        thenResponseBodyEqualsJson(ServiceListeningTestConstants.EMPTY_FIELD_BODY_RESPONSE);\n    }\n\n    @Test\n    public void shouldSupportPropertyMatchFilter() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n        givenRegisteredService(TestInterface.class, \"foo\", Collections.singletonMap(\"foo\", \"bar\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byProperty\",\n                \"{\\\"name\\\":\\\"foo\\\",\\\"value\\\":\\\"bar\\\"}\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"foo\");\n    }\n\n    @Test\n    public void shouldSupportPropertyMatchFilterWithArray() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n        givenRegisteredService(TestInterface.class, \"foo\",\n                Collections.singletonMap(\"foo\", new String[] { \"bar\", \"baz\" }));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byProperty\",\n                \"{\\\"name\\\":\\\"foo\\\",\\\"value\\\":\\\"bar\\\"}\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"foo\");\n    }\n\n    @Test\n    public void shouldSupportPropertyPresenceFilter() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        givenRegisteredService(TestInterface.class, \"foo\", Collections.singletonMap(\"foo\", \"bar\"));\n        givenRegisteredService(TestInterface.class, \"bar\", Collections.singletonMap(\"foo\", \"baz\"));\n        givenRegisteredService(TestInterface.class, \"baz\", Collections.singletonMap(\"fooo\", \"bar\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byProperty\", \"{\\\"name\\\":\\\"foo\\\"}\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"foo\");\n        thenResponseContainsPid(\"bar\");\n        thenResponseDoesNotContainPid(\"baz\");\n    }\n\n    @Test\n    public void shouldSupportNotFilter() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        givenRegisteredService(TestInterface.class, \"foo\", Collections.singletonMap(\"foo\", \"bar\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byProperty\",\n                \"{\\\"not\\\": {\\\"name\\\":\\\"foo\\\",\\\"value\\\":\\\"bar\\\"} }\");\n\n        thenRequestSucceeds();\n        thenResponseDoesNotContainPid(\"foo\");\n    }\n\n    @Test\n    public void shouldSupportAndFilter() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        givenRegisteredService(TestInterface.class, \"foo\", Collections.singletonMap(\"foo\", \"bar\"));\n        givenRegisteredService(TestInterface.class, \"bar\", Collections.singletonMap(\"foo\", \"bar\"));\n        givenRegisteredService(TestInterface.class, \"baz\", Collections.singletonMap(\"fooo\", \"bar\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byProperty\",\n                \"{\\\"and\\\": [ {\\\"name\\\":\\\"foo\\\",\\\"value\\\":\\\"bar\\\"}, {\\\"name\\\":\\\"kura.service.pid\\\",\\\"value\\\":\\\"foo\\\"} ] }\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"foo\");\n        thenResponseDoesNotContainPid(\"bar\");\n        thenResponseDoesNotContainPid(\"baz\");\n    }\n\n    @Test\n    public void shouldSupportOrFilter() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        givenRegisteredService(TestInterface.class, \"foo\", Collections.singletonMap(\"foo\", \"baz\"));\n        givenRegisteredService(TestInterface.class, \"bar\", Collections.singletonMap(\"foo\", \"bar\"));\n        givenRegisteredService(TestInterface.class, \"baz\", Collections.singletonMap(\"fooo\", \"bar\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byProperty\",\n                \"{\\\"or\\\": [ {\\\"name\\\":\\\"fooo\\\" }, {\\\"name\\\":\\\"foo\\\",\\\"value\\\":\\\"bar\\\"} ] }\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"baz\");\n        thenResponseContainsPid(\"bar\");\n        thenResponseDoesNotContainPid(\"foo\");\n    }\n\n    @Test\n    public void shouldSupportServicesSatisfyingReference() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        givenRegisteredService(TestInterface.class, \"foo\", Collections.singletonMap(\"foo\", \"baz\"));\n        givenRegisteredService(TestInterface.class, \"bar\", Collections.singletonMap(\"foo\", \"bar\"));\n        givenRegisteredService(OtherTestInterface.class, \"baz\", Collections.singletonMap(\"fooo\", \"bar\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/satisfyingReference\",\n                \"{\\\"pid\\\": \\\"org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService\\\",\"\n                        + \" \\\"referenceName\\\": \\\"TestInterface\\\" }\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"foo\");\n        thenResponseContainsPid(\"bar\");\n        thenResponseDoesNotContainPid(\"baz\");\n    }\n\n    @Test\n    public void shouldSupportListingFactoryPids() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), \"/factoryPids\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\");\n        thenResponseContainsPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\");\n    }\n\n    @Test\n    public void shouldSupportListingFactorysPidByInterface() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/factoryPids/byInterface\",\n                \"{\\\"interfaceNames\\\":[\\\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestInterface\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\");\n        thenResponseDoesNotContainPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\");\n    }\n\n    @Test\n    public void shouldSupportListingFactoryPidsSpecifyingMultipleInterfaces() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/factoryPids/byInterface\",\n                \"{\\\"interfaceNames\\\":[\\\"org.eclipse.kura.configuration.ConfigurableComponent\\\", \\\"org.eclipse.kura.internal.rest.service.listing.provider.test.OtherTestInterface\\\"]}\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\");\n        thenResponseDoesNotContainPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\");\n    }\n\n    @Test\n    public void shouldSupportListingFactoryPidsByProperty() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/factoryPids/byProperty\",\n                \"{\\\"name\\\": \\\"testProperty\\\", \\\"value\\\": \\\"testValue\\\"}\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\");\n        thenResponseDoesNotContainPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\");\n    }\n\n    @Test\n    public void shouldSupportListingFactoryPidsByPropertyOfArrayType() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/factoryPids/byProperty\",\n                \"{\\\"name\\\": \\\"testProperty\\\", \\\"value\\\": \\\"value2\\\"}\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\");\n        thenResponseDoesNotContainPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\");\n    }\n\n    @Test\n    public void shouldSupportListingFactoryPidsByPropertyAndObjectClass() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/factoryPids/byProperty\",\n                \"{\\\"and\\\": [ {\\\"name\\\":\\\"objectClass\\\", \\\"value\\\":\\\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestInterface\\\"}, {\\\"name\\\":\\\"testProperty\\\",\\\"value\\\": \\\"testValue\\\"} ] }\");\n\n        thenRequestSucceeds();\n        thenResponseContainsPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1\");\n        thenResponseDoesNotContainPid(\"org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2\");\n    }\n\n    @Test\n    public void shouldRejectEmptyFilter() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byProperty\", \"{}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectFilterWithSpacesInPropertyName() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byProperty\",\n                \"{\\\"name\\\": \\\" testProperty \\\", \\\"value\\\": \\\"value2\\\"}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectFilterWithMultipleTypes() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/byProperty\",\n                \"{\\\"and\\\": [], \\\"name\\\": \\\" testProperty \\\", \\\"value\\\": \\\"value2\\\"}\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectReferenceWithoutPid() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/satisfyingReference\",\n                \"{ \\\"referenceName\\\": \\\"TestInterface\\\" }\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectReferenceWithEmptyPid() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/satisfyingReference\",\n                \"{ \\\"pid\\\": \\\"\\\", \\\"referenceName\\\": \\\"TestInterface\\\" }\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectReferenceWithoutReferenceName() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/satisfyingReference\",\n                \"{ \\\"pid\\\": \\\"foo\\\" }\");\n\n        thenResponseCodeIs(400);\n    }\n\n    @Test\n    public void shouldRejectReferenceWithEmptyReferenceName() {\n        givenBasicCredentials(Optional.of(\"admin:admin\"));\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), \"/servicePids/satisfyingReference\",\n                \"{ \\\"pid\\\": \\\"foo\\\", \\\"referenceName\\\": \\\"\\\" }\");\n\n        thenResponseCodeIs(400);\n    }\n\n    /*\n     * GIVEN\n     */\n\n    @SuppressWarnings(\"unchecked\")\n    private void givenIdentity(final String username, final Optional<String> password, final List<String> roles) {\n        final UserAdmin userAdmin;\n\n        try {\n            userAdmin = ServiceUtil.trackService(UserAdmin.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n        } catch (Exception e) {\n            fail(\"failed to track UserAdmin\");\n            return;\n        }\n\n        final User user = getRoleOrCreateOne(userAdmin, \"kura.user.\" + username, User.class);\n\n        if (password.isPresent()) {\n            try {\n                final CryptoService cryptoService = ServiceUtil.trackService(CryptoService.class, Optional.empty())\n                        .get(30, TimeUnit.SECONDS);\n\n                user.getCredentials().put(\"kura.password\", cryptoService.sha256Hash(password.get()));\n\n            } catch (Exception e) {\n                fail(\"failed to compute password hash\");\n            }\n        }\n\n        for (final String role : roles) {\n            getRoleOrCreateOne(userAdmin, \"kura.permission.\" + role, Group.class).addMember(user);\n        }\n    }\n\n    public void givenBasicCredentials(final Optional<String> basicCredentials) {\n        if (this.transport instanceof RestTransport) {\n            ((RestTransport) this.transport).setBasicCredentials(basicCredentials);\n        }\n    }\n\n    private <T> void givenRegisteredService(final Class<T> clazz, final String pid,\n            final Map<String, Object> properties) {\n\n        final T testService = Mockito.mock(clazz);\n        BundleContext context = FrameworkUtil.getBundle(ServiceListingEndpointsTest.class).getBundleContext();\n        final Dictionary<String, Object> dict = new Hashtable<>();\n        dict.put(\"kura.service.pid\", pid);\n\n        for (final Entry<String, Object> e : properties.entrySet()) {\n            dict.put(e.getKey(), e.getValue());\n        }\n\n        registeredServices.add(context.registerService(clazz, testService, dict));\n    }\n\n    /*\n     * THEN\n     */\n\n    private void thenResponseContainsPid(final String pid) {\n        JsonArray responseArray = expectJsonResponse().get(\"pids\").asArray();\n        assertTrue(responseArray.values().contains(Json.value(pid)));\n    }\n\n    private void thenResponseDoesNotContainPid(final String pid) {\n        JsonArray responseArray = expectJsonResponse().get(\"pids\").asArray();\n        assertFalse(responseArray.values().contains(Json.value(pid)));\n    }\n\n    private void thenRestResponseCodeIs(final int responseCode) {\n        if (this.transport instanceof RestTransport) {\n            thenResponseCodeIs(responseCode);\n        }\n    }\n\n    /*\n     * Utils\n     */\n\n    private final List<ServiceRegistration<?>> registeredServices = new ArrayList<>();\n\n    @SuppressWarnings(\"unchecked\")\n    private <S extends Role> S getRoleOrCreateOne(final UserAdmin userAdmin, final String name, final Class<S> classz) {\n\n        final Role role = userAdmin.getRole(name);\n        if (classz.isInstance(role)) {\n            return (S) role;\n        }\n        final int type;\n        if (classz == User.class) {\n            type = Role.USER;\n        } else if (classz == Group.class) {\n            type = Role.GROUP;\n        } else {\n            fail(\"Unsupported role type\");\n            return null;\n        }\n        return (S) userAdmin.createRole(name, type);\n    }\n\n    @After\n    public void unregisterTestService() {\n        for (final ServiceRegistration<?> reg : registeredServices) {\n            reg.unregister();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/test/TargetFilterTestService.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.service.listing.provider.test;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class TargetFilterTestService implements ConfigurableComponent, TestInterface, OtherTestInterface {\n\n    private static final Logger logger = LoggerFactory.getLogger(TargetFilterTestService.class);\n\n    public void activate() {\n        logger.info(\"TargetFilterTestService activated\");\n    }\n\n    public void update() {\n    }\n\n    public void deactivate() {\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/test/TestInterface.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.service.listing.provider.test;\n\npublic interface TestInterface {\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.service.listing.provider.test/src/main/java/org/eclipse/kura/internal/rest/service/listing/provider/test/constants/ServiceListeningTestConstants.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.internal.rest.service.listing.provider.test.constants;\n\npublic class ServiceListeningTestConstants {\n\n    /*\n     * POST BODIES\n     */\n\n    public static final String COMPLETE_POST_BODY = \"{\\\"interfaceNames\\\": [ \\\"org.eclipse.kura.configuration.ConfigurableComponent\\\", \\\"org.eclipse.kura.security.keystore.KeystoreService\\\"]}\";\n    public static final String NULL_POST_BODY = \"{}\";\n    public static final String EMPTY_POST_BODY = \"{\\\"interfaceNames\\\": []}\";\n    public static final String NULL_FIELD_POST_BODY = \"{\\\"interfaceNames\\\": [\\\"org.eclipse.kura.configuration.ConfigurableComponent\\\",]}\";\n    public static final String EMPTY_FIELD_POST_BODY = \"{\\\"interfaceNames\\\": [\\\"org.eclipse.kura.configuration.ConfigurableComponent\\\",\\\"\\\"]}\";\n\n    /*\n     * END POINTS\n     */\n\n    \n\n    /*\n     * CORRECT RESPONSES\n     */\n\n    public static final String FILTERED_SERVICES_RESPONSE = \"{\\\"pids\\\":[\\\"SSLKeystore\\\"]}\";\n\n    /*\n     * FAILING MESSAGES ON FAILING\n     */\n\n    public static final String NULL_BODY_RESPONSE = \"{\\\"message\\\":\\\"Bad request. interfaceNames cannot be null\\\"}\";\n    public static final String EMPTY_BODY_RESPONSE = \"{\\\"message\\\":\\\"Bad request. interfaceNames cannot be empty\\\"}\";\n    public static final String NULL_FIELD_BODY_RESPONSE = \"{\\\"message\\\":\\\"Bad request. interfaceNames elements cannot be null\\\"}\";\n    public static final String EMPTY_FIELD_BODY_RESPONSE = \"{\\\"message\\\":\\\"Bad request. interfaceNames elements cannot be empty\\\"}\";\n\n    private ServiceListeningTestConstants() {\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.system.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.system.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.core.testutil.requesthandler;version=\"1.1.0\",\n org.eclipse.kura.util.wire.test;version=\"1.1.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.cm;version=\"1.6.0\",\n org.osgi.service.useradmin;version=\"1.1.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.25\"\nFragment-Host: org.eclipse.kura.rest.system.provider\nRequire-Bundle: org.eclipse.kura.http.server.manager;bundle-version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2023 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java,\\\n           src/test/java\nbin.includes = META-INF/,\\\n               .\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n        Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.rest.system.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                        <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/src/main/java/org/eclipse/kura/rest/system/provider/test/EndpointsTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.system.provider.test;\n\nimport static org.eclipse.kura.rest.system.Constants.MQTT_APP_ID;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_EXTENDED_PROPERTIES;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_EXTENDED_PROPERTIES_FILTER;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_FRAMEWORK_PROPERTIES;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_FRAMEWORK_PROPERTIES_FILTER;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_KURA_PROPERTIES;\nimport static org.eclipse.kura.rest.system.Constants.RESOURCE_KURA_PROPERTIES_FILTER;\nimport static org.eclipse.kura.rest.system.Constants.REST_APP_ID;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.reset;\n\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.Optional;\nimport java.util.Scanner;\nimport java.util.concurrent.TimeUnit;\n\nimport jakarta.ws.rs.core.Response.Status;\n\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.rest.system.SystemRestService;\nimport org.eclipse.kura.system.SystemService;\nimport org.eclipse.kura.util.wire.test.WireTestUtil;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\n\n@RunWith(Parameterized.class)\npublic class EndpointsTest extends AbstractRequestHandlerTest {\n\n    private static final String EXPECTED_FRAMEWORK_PROPERTIES_RESPONSE = new Scanner(\n            EndpointsTest.class.getResourceAsStream(\"/FRAMEWORK_PROPERTIES_RESPONSE\"), \"UTF-8\")\n                    .useDelimiter(\"\\\\A\").next().replace(\" \", \"\");\n    private static final String EXPECTED_EXTENDED_PROPERTIES_RESPONSE = new Scanner(\n            EndpointsTest.class.getResourceAsStream(\"/EXTENDED_PROPERTIES_RESPONSE\"), \"UTF-8\")\n                    .useDelimiter(\"\\\\A\").next().replace(\" \", \"\");\n    private static final String EXPECTED_KURA_PROPERTIES_RESPONSE = new Scanner(\n            EndpointsTest.class.getResourceAsStream(\"/KURA_PROPERTIES_RESPONSE\"), \"UTF-8\").useDelimiter(\"\\\\A\").next()\n                    .replace(\" \", \"\");\n\n    private static final String FRAMEWORK_PROPERTIES_FILTER_REQUEST = new Scanner(\n            EndpointsTest.class.getResourceAsStream(\"/FRAMEWORK_PROPERTIES_FILTER_REQUEST\"), \"UTF-8\")\n                    .useDelimiter(\"\\\\A\").next().replace(\" \", \"\");\n    private static final String EXTENDED_PROPERTIES_FILTER_REQUEST = new Scanner(\n            EndpointsTest.class.getResourceAsStream(\"/EXTENDED_PROPERTIES_FILTER_REQUEST\"), \"UTF-8\").useDelimiter(\"\\\\A\")\n                    .next().replace(\" \", \"\");\n    private static final String KURA_PROPERTIES_FILTER_REQUEST = new Scanner(\n            EndpointsTest.class.getResourceAsStream(\"/KURA_PROPERTIES_FILTER_REQUEST\"), \"UTF-8\").useDelimiter(\"\\\\A\")\n                    .next().replace(\" \", \"\");\n\n\n    private static final String METHOD_SPEC_GET = \"GET\";\n    private static final String METHOD_SPEC_POST = \"POST\";\n\n    private static SystemService systemServiceMock = mock(SystemService.class);\n\n    @Parameterized.Parameters\n    public static Collection<Transport> transports() {\n        return Arrays.asList(new RestTransport(REST_APP_ID), new MqttTransport(MQTT_APP_ID));\n    }\n\n    public EndpointsTest(Transport transport) {\n        super(transport);\n    }\n\n    /*\n     * Scenarios\n     */\n\n    // Positive tests\n\n    // GET\n\n    @Test\n    public void shouldReturnExpectedFrameworkProperties() {\n        givenSystemServiceMockWithFrameworkProperties();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), RESOURCE_FRAMEWORK_PROPERTIES);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_FRAMEWORK_PROPERTIES_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnExpectedExtendedProperties() {\n        givenSystemServiceMockWithExtendedProperties();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), RESOURCE_EXTENDED_PROPERTIES);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_EXTENDED_PROPERTIES_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnCorrectKuraProperties() {\n        givenSystemServiceMockWithKuraProperties();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), RESOURCE_KURA_PROPERTIES);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_KURA_PROPERTIES_RESPONSE);\n    }\n\n    // POST\n\n    @Test\n    public void shouldReturnFilteredFrameworkProperties() {\n        givenSystemServiceMockWithFrameworkProperties();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), RESOURCE_FRAMEWORK_PROPERTIES_FILTER,\n                FRAMEWORK_PROPERTIES_FILTER_REQUEST);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_FRAMEWORK_PROPERTIES_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnFilteredExtendedProperties() {\n        givenSystemServiceMockWithExtendedProperties();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), RESOURCE_EXTENDED_PROPERTIES_FILTER,\n                EXTENDED_PROPERTIES_FILTER_REQUEST);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_EXTENDED_PROPERTIES_RESPONSE);\n    }\n\n    @Test\n    public void shouldReturnFilteredKuraProperties() {\n        givenSystemServiceMockWithKuraProperties();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), RESOURCE_KURA_PROPERTIES_FILTER,\n                KURA_PROPERTIES_FILTER_REQUEST);\n\n        thenRequestSucceeds();\n        thenResponseBodyEqualsJson(EXPECTED_KURA_PROPERTIES_RESPONSE);\n    }\n\n    // Exceptions test\n\n    // GET\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnFailingFrameworkProperties() {\n        givenFailingSystemServiceMock();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), RESOURCE_FRAMEWORK_PROPERTIES);\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnFailingExtendedProperties() {\n        givenFailingSystemServiceMock();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), RESOURCE_FRAMEWORK_PROPERTIES);\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnFailingKuraProperties() {\n        givenFailingSystemServiceMock();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), RESOURCE_KURA_PROPERTIES);\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    // POST\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnFailingFrameworkPropertiesFilter() {\n        givenFailingSystemServiceMock();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), RESOURCE_FRAMEWORK_PROPERTIES_FILTER,\n                FRAMEWORK_PROPERTIES_FILTER_REQUEST);\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnFailingExtendedPropertiesFilter() {\n        givenFailingSystemServiceMock();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), RESOURCE_EXTENDED_PROPERTIES_FILTER,\n                EXTENDED_PROPERTIES_FILTER_REQUEST);\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    @Test\n    public void shouldRethrowWebApplicationExceptionOnFailingKuraPropertiesFilter() {\n        givenFailingSystemServiceMock();\n\n        whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), RESOURCE_KURA_PROPERTIES_FILTER,\n                KURA_PROPERTIES_FILTER_REQUEST);\n\n        thenResponseCodeIs(Status.INTERNAL_SERVER_ERROR.getStatusCode());\n    }\n\n    /*\n     * Steps\n     */\n\n    private static void givenSystemServiceMockWithFrameworkProperties() {\n        reset(systemServiceMock);\n        SystemServiceMockDecorator.addFrameworkPropertiesMockMethods(systemServiceMock);\n    }\n\n    private static void givenSystemServiceMockWithExtendedProperties() {\n        reset(systemServiceMock);\n        SystemServiceMockDecorator.addExtendedPropertiesMockMethods(systemServiceMock);\n    }\n\n    private static void givenSystemServiceMockWithKuraProperties() {\n        reset(systemServiceMock);\n        SystemServiceMockDecorator.addKuraPropertiesMockMethods(systemServiceMock);\n    }\n\n    private static void givenFailingSystemServiceMock() {\n        reset(systemServiceMock);\n        SystemServiceMockDecorator.addFailingMockMethods(systemServiceMock);\n    }\n\n    /*\n     * Utilities\n     */\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        createSystemServiceMock();\n        registerSystemServiceMock();\n    }\n\n    private static void createSystemServiceMock() {\n        givenSystemServiceMockWithFrameworkProperties();\n\n        final Dictionary<String, Object> configurationServiceProperties = new Hashtable<>();\n        configurationServiceProperties.put(\"service.ranking\", Integer.MIN_VALUE);\n        configurationServiceProperties.put(\"kura.service.pid\", \"mockSystemService\");\n        FrameworkUtil.getBundle(EndpointsTest.class).getBundleContext().registerService(SystemService.class,\n                systemServiceMock, configurationServiceProperties);\n    }\n\n    private static void registerSystemServiceMock() throws Exception {\n        final Dictionary<String, Object> properties = new Hashtable<>();\n        properties.put(\"SystemService.target\", \"(kura.service.pid=mockSystemService)\");\n\n        final ConfigurationAdmin configurationAdmin = WireTestUtil\n                .trackService(ConfigurationAdmin.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n        final Configuration config = configurationAdmin.getConfiguration(SystemRestService.class.getName(), \"?\");\n        config.update(properties);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/src/main/java/org/eclipse/kura/rest/system/provider/test/SystemServiceMockDecorator.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.system.provider.test;\n\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.when;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Properties;\n\nimport org.eclipse.kura.system.ExtendedProperties;\nimport org.eclipse.kura.system.ExtendedPropertyGroup;\nimport org.eclipse.kura.system.InternetConnectionStatus;\nimport org.eclipse.kura.system.SystemService;\n\npublic class SystemServiceMockDecorator {\n\n    private static final String PROPERTIES_VALUE = \"test\";\n    private static final String PROPERTIES_FALSE_STRING_VALUE = \"false\";\n    private static final String EXT_PROPERTIES_VERSION = \"1.0.0\";\n\n    /**\n     * \n     * @param service\n     *            the mock SystemService to modify. It adds mock methods that return all the properties specified\n     *            in resource {@link FRAMEWORK_PROPERTIES_RESPONSE}.\n     */\n    public static void addFrameworkPropertiesMockMethods(SystemService service) {\n        initFrameworkProperties(service);\n    }\n\n    /**\n     * \n     * @param service\n     *            the mock SystemService to modify. It adds mock methods to include all the extended properties\n     *            specified in resource {@link EXTENDED_PROPERTIES_RESPONSE}.\n     */\n    public static void addExtendedPropertiesMockMethods(SystemService service) {\n        initExtendedProperties(service);\n    }\n\n    /**\n     * \n     * @param service\n     *            the mock SystemService to modify. It adds mock methods to include all the kura properties\n     *            specified in resource {@link KURA_PROPERTIES_RESPONSE}.\n     */\n    public static void addKuraPropertiesMockMethods(SystemService service) {\n        initKuraProperties(service);\n    }\n\n    /**\n     * \n     * @param service\n     *            the mock SystemService to modify. Its mock methods are all modified to throw a\n     *            {@link RuntimeException}.\n     */\n    public static void addFailingMockMethods(SystemService service) {\n        initExceptions(service);\n    }\n\n    private static void initFrameworkProperties(SystemService service) {\n        when(service.getBiosVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getCommandUser()).thenReturn(PROPERTIES_VALUE);\n        when(service.getCpuVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getDeviceName()).thenReturn(PROPERTIES_VALUE);\n        when(service.getFileSeparator()).thenReturn(PROPERTIES_VALUE);\n        when(service.getFirmwareVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getHostname()).thenReturn(PROPERTIES_VALUE);\n        when(service.getJavaHome()).thenReturn(PROPERTIES_VALUE);\n        when(service.getJavaVendor()).thenReturn(PROPERTIES_VALUE);\n        when(service.getJavaVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getJavaVmInfo()).thenReturn(PROPERTIES_VALUE);\n        when(service.getJavaVmName()).thenReturn(PROPERTIES_VALUE);\n        when(service.getJavaVmVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getJavaVmVendor()).thenReturn(PROPERTIES_VALUE);\n        when(service.getJdkVendorVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getKuraDataDirectory()).thenReturn(PROPERTIES_VALUE);\n        when(service.getKuraFrameworkConfigDirectory()).thenReturn(PROPERTIES_VALUE);\n        when(service.getKuraHome()).thenReturn(PROPERTIES_VALUE);\n        when(service.getKuraMarketplaceCompatibilityVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getKuraSnapshotsDirectory()).thenReturn(PROPERTIES_VALUE);\n        when(service.getKuraStyleDirectory()).thenReturn(PROPERTIES_VALUE);\n        when(service.getKuraTemporaryConfigDirectory()).thenReturn(PROPERTIES_VALUE);\n        when(service.getKuraUserConfigDirectory()).thenReturn(PROPERTIES_VALUE);\n        when(service.getKuraVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getModelId()).thenReturn(PROPERTIES_VALUE);\n        when(service.getModelName()).thenReturn(PROPERTIES_VALUE);\n        when(service.getNetVirtualDevicesConfig()).thenReturn(PROPERTIES_VALUE);\n        when(service.getOsArch()).thenReturn(PROPERTIES_VALUE);\n        when(service.getOsDistro()).thenReturn(PROPERTIES_VALUE);\n        when(service.getOsDistroVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getOsgiFwName()).thenReturn(PROPERTIES_VALUE);\n        when(service.getOsgiFwVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getOsName()).thenReturn(PROPERTIES_VALUE);\n        when(service.getOsVersion()).thenReturn(PROPERTIES_VALUE);\n        when(service.getPartNumber()).thenReturn(PROPERTIES_VALUE);\n        when(service.getPlatform()).thenReturn(PROPERTIES_VALUE);\n        when(service.getPrimaryMacAddress()).thenReturn(PROPERTIES_VALUE);\n        when(service.getPrimaryNetworkInterfaceName()).thenReturn(PROPERTIES_VALUE);\n        when(service.getSerialNumber()).thenReturn(PROPERTIES_VALUE);\n        when(service.getTotalMemory()).thenReturn(0L);\n        when(service.getFreeMemory()).thenReturn(0L);\n        when(service.getKuraSnapshotsCount()).thenReturn(0);\n        when(service.getKuraWifiTopChannel()).thenReturn(0);\n        when(service.getNumberOfProcessors()).thenReturn(0);\n        when(service.getFileCommandZipMaxUploadNumber()).thenReturn(0);\n        when(service.getFileCommandZipMaxUploadSize()).thenReturn(0);\n        when(service.isLegacyBluetoothBeaconScan()).thenReturn(false);\n        when(service.isLegacyPPPLoggingEnabled()).thenReturn(false);\n        when(service.getKuraWebEnabled()).thenReturn(PROPERTIES_FALSE_STRING_VALUE);\n        when(service.getInternetConnectionStatus()).thenReturn(InternetConnectionStatus.UNAVAILABLE);\n        when(service.getInternetConnectionStatusCheckHost()).thenReturn(PROPERTIES_VALUE);\n        when(service.getInternetConnectionStatusCheckIp()).thenReturn(PROPERTIES_VALUE);\n\n        Properties kuraProperties = new Properties();\n        kuraProperties.put(SystemService.KEY_KURA_HAVE_NET_ADMIN, false);\n        when(service.getProperties()).thenReturn(kuraProperties);\n    }\n\n    private static void initExtendedProperties(SystemService service) {\n        ExtendedProperties extendedProperties = mock(ExtendedProperties.class);\n\n        List<ExtendedPropertyGroup> groups = new ArrayList<>();\n        groups.add(createExtendedPropertyGroup(\"group1\"));\n        groups.add(createExtendedPropertyGroup(\"group2\"));\n\n        when(extendedProperties.getVersion()).thenReturn(EXT_PROPERTIES_VERSION);\n        when(extendedProperties.getPropertyGroups()).thenReturn(groups);\n        when(service.getExtendedProperties()).thenReturn(Optional.of(extendedProperties));\n    }\n\n    private static ExtendedPropertyGroup createExtendedPropertyGroup(String name) {\n        ExtendedPropertyGroup group = mock(ExtendedPropertyGroup.class);\n\n        Map<String, String> propertiesGroup = new HashMap<>();\n        propertiesGroup.put(\"key1\", \"val1\");\n        propertiesGroup.put(\"key2\", \"val2\");\n\n        when(group.getName()).thenReturn(name);\n        when(group.getProperties()).thenReturn(propertiesGroup);\n\n        return group;\n    }\n\n    private static void initKuraProperties(SystemService service) {\n        Properties defaults = new Properties();\n        defaults.setProperty(SystemService.KEY_KURA_HAVE_NET_ADMIN, PROPERTIES_VALUE);\n        defaults.setProperty(SystemService.KEY_KURA_PLUGINS_DIR, PROPERTIES_VALUE);\n\n        Properties kuraProperties = new Properties(defaults);\n        kuraProperties.setProperty(SystemService.KEY_KURA_HOME_DIR, PROPERTIES_VALUE);\n        kuraProperties.setProperty(SystemService.KEY_KURA_PACKAGES_DIR, PROPERTIES_VALUE);\n        kuraProperties.setProperty(SystemService.KEY_KURA_NAME, PROPERTIES_VALUE);\n\n        when(service.getProperties()).thenReturn(kuraProperties);\n    }\n\n    private static void initExceptions(SystemService service) {\n        when(service.getBiosVersion()).thenThrow(RuntimeException.class);\n        when(service.getCommandUser()).thenThrow(RuntimeException.class);\n        when(service.getCpuVersion()).thenThrow(RuntimeException.class);\n        when(service.getDeviceName()).thenThrow(RuntimeException.class);\n        when(service.getFileSeparator()).thenThrow(RuntimeException.class);\n        when(service.getFirmwareVersion()).thenThrow(RuntimeException.class);\n        when(service.getHostname()).thenThrow(RuntimeException.class);\n        when(service.getJavaHome()).thenThrow(RuntimeException.class);\n        when(service.getJavaVendor()).thenThrow(RuntimeException.class);\n        when(service.getJavaVersion()).thenThrow(RuntimeException.class);\n        when(service.getJavaVmInfo()).thenThrow(RuntimeException.class);\n        when(service.getJavaVmName()).thenThrow(RuntimeException.class);\n        when(service.getJavaVmVersion()).thenThrow(RuntimeException.class);\n        when(service.getJavaVmVendor()).thenThrow(RuntimeException.class);\n        when(service.getJdkVendorVersion()).thenThrow(RuntimeException.class);\n        when(service.getKuraDataDirectory()).thenThrow(RuntimeException.class);\n        when(service.getKuraFrameworkConfigDirectory()).thenThrow(RuntimeException.class);\n        when(service.getKuraHome()).thenThrow(RuntimeException.class);\n        when(service.getKuraMarketplaceCompatibilityVersion()).thenThrow(RuntimeException.class);\n        when(service.getKuraSnapshotsDirectory()).thenThrow(RuntimeException.class);\n        when(service.getKuraStyleDirectory()).thenThrow(RuntimeException.class);\n        when(service.getKuraTemporaryConfigDirectory()).thenThrow(RuntimeException.class);\n        when(service.getKuraUserConfigDirectory()).thenThrow(RuntimeException.class);\n        when(service.getKuraVersion()).thenThrow(RuntimeException.class);\n        when(service.getModelId()).thenThrow(RuntimeException.class);\n        when(service.getModelName()).thenThrow(RuntimeException.class);\n        when(service.getNetVirtualDevicesConfig()).thenThrow(RuntimeException.class);\n        when(service.getOsArch()).thenThrow(RuntimeException.class);\n        when(service.getOsDistro()).thenThrow(RuntimeException.class);\n        when(service.getOsDistroVersion()).thenThrow(RuntimeException.class);\n        when(service.getOsgiFwName()).thenThrow(RuntimeException.class);\n        when(service.getOsgiFwVersion()).thenThrow(RuntimeException.class);\n        when(service.getOsName()).thenThrow(RuntimeException.class);\n        when(service.getOsVersion()).thenThrow(RuntimeException.class);\n        when(service.getPartNumber()).thenThrow(RuntimeException.class);\n        when(service.getPlatform()).thenThrow(RuntimeException.class);\n        when(service.getPrimaryMacAddress()).thenThrow(RuntimeException.class);\n        when(service.getPrimaryNetworkInterfaceName()).thenThrow(RuntimeException.class);\n        when(service.getSerialNumber()).thenThrow(RuntimeException.class);\n        when(service.getTotalMemory()).thenThrow(RuntimeException.class);\n        when(service.getFreeMemory()).thenThrow(RuntimeException.class);\n        when(service.getKuraSnapshotsCount()).thenThrow(RuntimeException.class);\n        when(service.getKuraWifiTopChannel()).thenThrow(RuntimeException.class);\n        when(service.getNumberOfProcessors()).thenThrow(RuntimeException.class);\n        when(service.getFileCommandZipMaxUploadNumber()).thenThrow(RuntimeException.class);\n        when(service.getFileCommandZipMaxUploadSize()).thenThrow(RuntimeException.class);\n        when(service.isLegacyBluetoothBeaconScan()).thenThrow(RuntimeException.class);\n        when(service.isLegacyPPPLoggingEnabled()).thenThrow(RuntimeException.class);\n        when(service.getKuraWebEnabled()).thenThrow(RuntimeException.class);\n\n        when(service.getExtendedProperties()).thenThrow(RuntimeException.class);\n\n        when(service.getProperties()).thenThrow(RuntimeException.class);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/src/main/resources/EXTENDED_PROPERTIES_FILTER_REQUEST",
    "content": "{\n    \"groupNames\": [\n        \"group1\", \"group2\"\n    ]\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/src/main/resources/EXTENDED_PROPERTIES_RESPONSE",
    "content": "{\n    \"version\":\"1.0.0\",\n    \"extendedProperties\": {\n        \"group2\": {\n            \"key1\":\"val1\",\n            \"key2\":\"val2\"\n        },\n        \"group1\": {\n            \"key1\":\"val1\",\n            \"key2\":\"val2\"\n        }\n    }\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/src/main/resources/FRAMEWORK_PROPERTIES_FILTER_REQUEST",
    "content": "{\n    \"names\": [\n        \"biosVersion\",\n        \"cpuVersion\",\n        \"deviceName\",\n        \"modelId\",\n        \"modelName\",\n        \"partNumber\",\n        \"platform\",\n        \"numberOfProcessors\",\n        \"totalMemory\",\n        \"freeMemory\",\n        \"serialNumber\",\n        \"javaHome\",\n        \"javaVendor\",\n        \"javaVersion\",\n        \"javaVmInfo\",\n        \"javaVmName\",\n        \"javaVmVersion\",\n        \"javaVmVendor\",\n        \"jdkVendorVersion\",\n        \"osArch\",\n        \"osDistro\",\n        \"osDistroVersion\",\n        \"osName\",\n        \"osVersion\",\n        \"isLegacyBluetoothBeaconScan\",\n        \"isLegacyPPPLoggingEnabled\",\n        \"primaryMacAddress\",\n        \"primaryNetworkInterfaceName\",\n        \"fileSeparator\",\n        \"firmwareVersion\",\n        \"internetConnectionStatus\",\n        \"kuraDataDirectory\",\n        \"kuraFrameworkConfigDirectory\",\n        \"kuraHomeDirectory\",\n        \"kuraMarketplaceCompatibilityVersion\",\n        \"kuraSnapshotsCount\",\n        \"kuraSnapshotsDirectory\",\n        \"kuraStyleDirectory\",\n        \"kuraTemporaryConfigDirectory\",\n        \"kuraUserConfigDirectory\",\n        \"kuraVersion\",\n        \"kuraHaveWebInterface\",\n        \"kuraHaveNetAdmin\",\n        \"kuraWifiTopChannel\",\n        \"kuraDefaultNetVirtualDevicesConfig\",\n        \"osgiFirmwareName\",\n        \"osgiFirmwareVersion\",\n        \"commandUser\",\n        \"commandZipMaxUploadNumber\",\n        \"commandZipMaxUploadSize\"\n    ]\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/src/main/resources/FRAMEWORK_PROPERTIES_RESPONSE",
    "content": "{\n    \"biosVersion\":\"test\",\n    \"cpuVersion\":\"test\",\n    \"deviceName\":\"test\",\n    \"modelId\":\"test\",\n    \"modelName\":\"test\",\n    \"partNumber\":\"test\",\n    \"platform\":\"test\",\n    \"numberOfProcessors\": 0,\n    \"totalMemory\": 0,\n    \"freeMemory\": 0,\n    \"serialNumber\":\"test\",\n    \"javaHome\":\"test\",\n    \"javaVendor\":\"test\",\n    \"javaVersion\":\"test\",\n    \"javaVmInfo\":\"test\",\n    \"javaVmName\":\"test\",\n    \"javaVmVersion\":\"test\",\n    \"javaVmVendor\": \"test\",\n    \"jdkVendorVersion\": \"test\",\n    \"osArch\":\"test\",\n    \"osDistro\":\"test\",\n    \"osDistroVersion\":\"test\",\n    \"osName\":\"test\",\n    \"osVersion\":\"test\",\n    \"isLegacyBluetoothBeaconScan\": false,\n    \"isLegacyPPPLoggingEnabled\": false,\n    \"primaryMacAddress\":\"test\",\n    \"primaryNetworkInterfaceName\":\"test\",\n    \"fileSeparator\":\"test\",\n    \"firmwareVersion\":\"test\",\n    \"internetConnectionStatus\": \"UNAVAILABLE\",\n    \"kuraDataDirectory\":\"test\",\n    \"kuraFrameworkConfigDirectory\":\"test\",\n    \"kuraHomeDirectory\":\"test\",\n    \"kuraMarketplaceCompatibilityVersion\":\"test\",\n    \"kuraSnapshotsCount\": 0,\n    \"kuraSnapshotsDirectory\":\"test\",\n    \"kuraStyleDirectory\":\"test\",\n    \"kuraTemporaryConfigDirectory\":\"test\",\n    \"kuraUserConfigDirectory\":\"test\",\n    \"kuraVersion\":\"test\",\n    \"kuraHaveWebInterface\":false,\n    \"kuraHaveNetAdmin\": false,\n    \"kuraWifiTopChannel\": 0,\n    \"kuraDefaultNetVirtualDevicesConfig\":\"test\",\n    \"osgiFirmwareName\":\"test\",\n    \"osgiFirmwareVersion\":\"test\",\n    \"commandUser\":\"test\",\n    \"commandZipMaxUploadNumber\": 0,\n    \"commandZipMaxUploadSize\": 0\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/src/main/resources/KURA_PROPERTIES_FILTER_REQUEST",
    "content": "{\n    \"names\": [\n        \"kura.have.net.admin\",\n        \"kura.name\",\n        \"kura.home\",\n        \"kura.plugins\",\n        \"kura.packages\"\n    ]\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/src/main/resources/KURA_PROPERTIES_RESPONSE",
    "content": "{\n    \"kuraProperties\": {\n        \"kura.have.net.admin\":\"test\",\n        \"kura.name\":\"test\",\n        \"kura.home\":\"test\",\n        \"kura.plugins\":\"test\",\n        \"kura.packages\":\"test\"\n    }\n}"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.system.provider.test/src/test/java/org/eclipse/kura/rest/system/provider/test/DependenciesTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.rest.system.provider.test;\n\nimport static org.eclipse.kura.rest.system.Constants.KURA_PERMISSION_REST_ROLE;\nimport static org.eclipse.kura.rest.system.Constants.MQTT_APP_ID;\nimport static org.junit.Assert.assertNull;\nimport static org.mockito.ArgumentMatchers.any;\nimport static org.mockito.ArgumentMatchers.eq;\nimport static org.mockito.Mockito.doThrow;\nimport static org.mockito.Mockito.mock;\nimport static org.mockito.Mockito.times;\nimport static org.mockito.Mockito.verify;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.util.Objects;\n\nimport org.eclipse.kura.KuraErrorCode;\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloudconnection.request.RequestHandler;\nimport org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry;\nimport org.eclipse.kura.rest.system.SystemRestService;\nimport org.junit.Test;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.UserAdmin;\n\npublic class DependenciesTest {\n\n    private SystemRestService service = new SystemRestService();\n    private UserAdmin userAdmin;\n    private RequestHandlerRegistry requestHandlerRegistry;\n    private Exception occurredException;\n\n    /*\n     * Scenarios\n     */\n\n    @Test\n    public void shouldCreateRoleOnUserAdminBinding() {\n        givenMockUserAdmin();\n\n        whenBindUserAdmin();\n\n        thenRoleIsCreated(KURA_PERMISSION_REST_ROLE, Role.GROUP);\n    }\n\n    @Test\n    public void shouldRegisterRequestHandler() throws KuraException {\n        givenMockRequestHandlerRegistry();\n\n        whenBindRequestHandlerRegistry();\n\n        thenRequestHandlerIsRegistered(MQTT_APP_ID);\n    }\n\n    @Test\n    public void shouldUnregisterRequestHandler() throws KuraException {\n        givenMockRequestHandlerRegistry();\n\n        whenUnbindRequestHandlerRegistry();\n\n        thenRequestHandlerIsUnregistered(MQTT_APP_ID);\n    }\n\n    @Test\n    public void shouldCatchExceptionsOnRequestHandlerBind() throws KuraException {\n        givenFailingMockRequestHandlerRegistry();\n\n        whenBindRequestHandlerRegistry();\n\n        thenNoExceptionOccurred();\n    }\n\n    @Test\n    public void shouldCatchExceptionsOnRequestHandlerUnbind() throws KuraException {\n        givenFailingMockRequestHandlerRegistry();\n\n        whenUnbindRequestHandlerRegistry();\n\n        thenNoExceptionOccurred();\n    }\n\n    /*\n     * Given\n     */\n\n    private void givenMockUserAdmin() {\n        this.userAdmin = mock(UserAdmin.class);\n    }\n\n    private void givenMockRequestHandlerRegistry() {\n        this.requestHandlerRegistry = mock(RequestHandlerRegistry.class);\n    }\n\n    private void givenFailingMockRequestHandlerRegistry() throws KuraException {\n        this.requestHandlerRegistry = mock(RequestHandlerRegistry.class);\n        doThrow(new KuraException(KuraErrorCode.BAD_REQUEST)).when(this.requestHandlerRegistry)\n                .registerRequestHandler(any(), any());\n        doThrow(new KuraException(KuraErrorCode.BAD_REQUEST)).when(this.requestHandlerRegistry).unregister(any());\n    }\n\n    /*\n     * When\n     */\n\n    private void whenBindUserAdmin() {\n        this.service.bindUserAdmin(this.userAdmin);\n    }\n\n    private void whenBindRequestHandlerRegistry() {\n        try {\n            this.service.bindRequestHandlerRegistry(this.requestHandlerRegistry);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    private void whenUnbindRequestHandlerRegistry() {\n        try {\n            this.service.unbindRequestHandlerRegistry(this.requestHandlerRegistry);\n        } catch (Exception e) {\n            this.occurredException = e;\n        }\n    }\n\n    /*\n     * Then\n     */\n\n    private void thenRoleIsCreated(String expectedKuraPermission, int expectedRole) {\n        verify(this.userAdmin, times(1)).createRole(expectedKuraPermission, expectedRole);\n    }\n\n    private void thenRequestHandlerIsRegistered(String expectedMqttAppId) throws KuraException {\n        verify(this.requestHandlerRegistry, times(1)).registerRequestHandler(eq(expectedMqttAppId),\n                any(RequestHandler.class));\n    }\n\n    private void thenRequestHandlerIsUnregistered(String expectedMqttAppId) throws KuraException {\n        verify(this.requestHandlerRegistry, times(1)).unregister(expectedMqttAppId);\n    }\n\n    private void thenNoExceptionOccurred() {\n        String errorMessage = \"Empty message\";\n        if (Objects.nonNull(this.occurredException)) {\n            StringWriter sw = new StringWriter();\n            this.occurredException.printStackTrace(new PrintWriter(sw));\n\n            errorMessage = String.format(\"No exception expected, \\\"%s\\\" found. Caused by: %s\",\n                    this.occurredException.getClass().getName(), sw.toString());\n        }\n\n        assertNull(errorMessage, this.occurredException);\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.tamper.detection.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.rest.tamper.detection.provider.test\nBundle-SymbolicName: org.eclipse.kura.rest.tamper.detection.provider.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nRequire-Bundle: org.eclipse.kura.rest.tamper.detection.provider;bundle-version=\"1.0.0\",\n org.eclipse.kura.http.server.manager;bundle-version=\"1.1.0\"\nImport-Package: com.google.gson;version=\"2.7.0\",\n com.google.gson.reflect;version=\"2.7.0\",\n org.apache.commons.io;version=\"2.4.0\",\n org.eclipse.kura;version=\"1.6.0\",\n org.eclipse.kura.cloud;version=\"1.1.0\",\n org.eclipse.kura.configuration;version=\"1.2.0\",\n org.eclipse.kura.core.testutil.requesthandler;version=\"1.0.0\",\n org.eclipse.kura.core.util;version=\"1.2.0\",\n org.eclipse.kura.crypto;version=\"1.3.0\",\n org.eclipse.kura.data;version=\"1.1.2\",\n org.eclipse.kura.data.transport.listener;version=\"1.0.1\",\n org.eclipse.kura.marshalling;version=\"1.0.0\",\n org.eclipse.kura.message;version=\"1.4.0\",\n org.eclipse.kura.security.tamper.detection;version=\"1.0.0\",\n org.eclipse.kura.type;version=\"1.1.0\",\n org.eclipse.kura.util.wire.test;version=\"1.1.0\",\n org.junit,\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.7.25\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.tamper.detection.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.tamper.detection.provider.test/build.properties",
    "content": "#\n# Copyright (c) 2021 Eurotech and/or its affiliates and others\n#\n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n# SPDX-License-Identifier: EPL-2.0\n#\n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               about.html\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.tamper.detection.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.rest.tamper.detection.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.rest.tamper.detection.provider.test/src/main/java/org/eclipse/kura/rest/tamper/detection/provider/test/TamperDetectionRemoteServiceTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.rest.tamper.detection.provider.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.IOException;\nimport java.net.MalformedURLException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest;\nimport org.eclipse.kura.core.testutil.requesthandler.MqttTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.RestTransport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.security.tamper.detection.TamperDetectionService;\nimport org.eclipse.kura.security.tamper.detection.TamperStatus;\nimport org.eclipse.kura.type.TypedValues;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.junit.runners.Parameterized;\nimport org.mockito.Mockito;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\n\nimport com.google.gson.Gson;\nimport com.google.gson.reflect.TypeToken;\n\n@RunWith(Parameterized.class)\npublic class TamperDetectionRemoteServiceTest extends AbstractRequestHandlerTest {\n\n    @Parameterized.Parameters\n    public static Collection<Transport> transports() {\n        return Arrays.asList(new RestTransport(\"tamper/v1\"), new MqttTransport(\"TAMPER-V1\"));\n    }\n\n    public TamperDetectionRemoteServiceTest(final Transport transport) {\n        super(transport);\n    }\n\n    @Test\n    public void shouldSupportListingTamperDetectionServices() throws MalformedURLException, IOException {\n        assertEquals(0, runRequestAndGetResponse(\"/list\", new MethodSpec(\"GET\"),\n                new TypeToken<ArrayList<TamperDetectionServiceInfo>>() {\n                }).size());\n    }\n\n    @Test\n    public void shouldProvideTamperDetectionServiceInfo() throws MalformedURLException, IOException {\n        try (final Fixture fixture = new Fixture()) {\n            final TamperDetectionService tamperDetectionService = Mockito.mock(TamperDetectionService.class);\n            Mockito.when(tamperDetectionService.getDisplayName()).thenReturn(\"foo\");\n\n            fixture.registerService(tamperDetectionService, TamperDetectionService.class, \"moo\");\n\n            final List<TamperDetectionServiceInfo> infos = runRequestAndGetResponse(\"/list\", new MethodSpec(\"GET\"),\n                    new TypeToken<ArrayList<TamperDetectionServiceInfo>>() {\n                    });\n\n            assertEquals(1, infos.size());\n            assertEquals(\"foo\", infos.get(0).getDisplayName());\n            assertEquals(\"moo\", infos.get(0).getPid());\n        }\n    }\n\n    @Test\n    public void shouldReportNotFound() throws MalformedURLException, IOException {\n        try (final Fixture fixture = new Fixture()) {\n            final TamperDetectionService tamperDetectionService = Mockito.mock(TamperDetectionService.class);\n            Mockito.when(tamperDetectionService.getDisplayName()).thenReturn(\"foo\");\n\n            fixture.registerService(tamperDetectionService, TamperDetectionService.class, \"moo\");\n\n            assertEquals(404, transport.runRequest(\"/pid/boo\", new MethodSpec(\"GET\")).getStatus());\n        }\n    }\n\n    @Test\n    public void shouldProvideMultipleTamperDetectionServiceInfo() throws MalformedURLException, IOException {\n        try (final Fixture fixture = new Fixture()) {\n\n            final TamperDetectionService first = Mockito.mock(TamperDetectionService.class);\n            Mockito.when(first.getDisplayName()).thenReturn(\"foo\");\n            fixture.registerService(first, TamperDetectionService.class, \"moo\");\n\n            final TamperDetectionService second = Mockito.mock(TamperDetectionService.class);\n            Mockito.when(second.getDisplayName()).thenReturn(\"boo\");\n            fixture.registerService(second, TamperDetectionService.class, \"bar\");\n\n            final List<TamperDetectionServiceInfo> infos = runRequestAndGetResponse(\"/list\", new MethodSpec(\"GET\"),\n                    new TypeToken<ArrayList<TamperDetectionServiceInfo>>() {\n                    });\n\n            assertEquals(2, infos.size());\n            assertTrue(infos.stream().anyMatch(p -> p.getPid().equals(\"moo\") && p.getDisplayName().equals(\"foo\")));\n            assertTrue(infos.stream().anyMatch(p -> p.getPid().equals(\"bar\") && p.getDisplayName().equals(\"boo\")));\n        }\n    }\n\n    @Test\n    public void shouldReportTamperStatusInfo() throws MalformedURLException, IOException, KuraException {\n        try (final Fixture fixture = new Fixture()) {\n            final TamperDetectionService tamperDetectionService = Mockito.mock(TamperDetectionService.class);\n            Mockito.when(tamperDetectionService.getDisplayName()).thenReturn(\"foo\");\n            Mockito.when(tamperDetectionService.getTamperStatus())\n                    .thenReturn(new TamperStatus(false, Collections.emptyMap()));\n\n            fixture.registerService(tamperDetectionService, TamperDetectionService.class, \"moo\");\n\n            final TamperStatusInfo info = runRequestAndGetResponse(\"/pid/moo\", new MethodSpec(\"GET\"),\n                    new TypeToken<TamperStatusInfo>() {\n                    });\n\n            assertEquals(false, info.isDeviceTampered);\n            assertTrue(info.properties.isEmpty());\n        }\n    }\n\n    @Test\n    public void shouldReportTamperStatusInfoTimestamp() throws MalformedURLException, IOException, KuraException {\n        try (final Fixture fixture = new Fixture()) {\n            final TamperDetectionService tamperDetectionService = Mockito.mock(TamperDetectionService.class);\n            Mockito.when(tamperDetectionService.getDisplayName()).thenReturn(\"foo\");\n            Mockito.when(tamperDetectionService.getTamperStatus()).thenReturn(\n                    new TamperStatus(true, Collections.singletonMap(\"timestamp\", TypedValues.newLongValue(5000L))));\n\n            fixture.registerService(tamperDetectionService, TamperDetectionService.class, \"moo\");\n\n            final TamperStatusInfo info = runRequestAndGetResponse(\"/pid/moo\", new MethodSpec(\"GET\"),\n                    new TypeToken<TamperStatusInfo>() {\n                    });\n\n            assertEquals(true, info.isDeviceTampered);\n            assertEquals(5000.0d, info.properties.get(\"timestamp\"));\n        }\n    }\n\n    @Test\n    public void shouldSupportTamperStatusReset() throws MalformedURLException, IOException, KuraException {\n        try (final Fixture fixture = new Fixture()) {\n            final TamperDetectionService tamperDetectionService = new TamperDetectionService() {\n\n                boolean isDeviceTampered = true;\n\n                @Override\n                public void resetTamperStatus() throws KuraException {\n                    isDeviceTampered = false;\n                }\n\n                @Override\n                public TamperStatus getTamperStatus() throws KuraException {\n                    return new TamperStatus(isDeviceTampered, Collections.emptyMap());\n                }\n\n                @Override\n                public String getDisplayName() {\n                    return \"Foo\";\n                }\n            };\n\n            fixture.registerService(tamperDetectionService, TamperDetectionService.class, \"moo\");\n\n            assertEquals(true,\n                    runRequestAndGetResponse(\"/pid/moo\", new MethodSpec(\"GET\"), new TypeToken<TamperStatusInfo>() {\n                    }).isDeviceTampered);\n\n            assertEquals(1, transport.runRequest(\"/pid/moo/_reset\", new MethodSpec(\"POST\", \"EXEC\")).getStatus() / 200);\n\n            assertEquals(false,\n                    runRequestAndGetResponse(\"/pid/moo\", new MethodSpec(\"GET\"), new TypeToken<TamperStatusInfo>() {\n                    }).isDeviceTampered);\n        }\n    }\n\n    @Test\n    public void shouldSupportTrackingByServicePid() throws MalformedURLException, IOException {\n        try (final Fixture fixture = new Fixture()) {\n            final TamperDetectionService tamperDetectionService = Mockito.mock(TamperDetectionService.class);\n            Mockito.when(tamperDetectionService.getDisplayName()).thenReturn(\"foo\");\n\n            fixture.registerService(tamperDetectionService, TamperDetectionService.class,\n                    Collections.singletonMap(\"service.pid\", \"moo\"));\n\n            final List<TamperDetectionServiceInfo> infos = runRequestAndGetResponse(\"/list\", new MethodSpec(\"GET\"),\n                    new TypeToken<ArrayList<TamperDetectionServiceInfo>>() {\n                    });\n\n            assertEquals(1, infos.size());\n            assertEquals(\"foo\", infos.get(0).getDisplayName());\n            assertEquals(\"moo\", infos.get(0).getPid());\n        }\n    }\n\n    private static class Fixture implements AutoCloseable {\n\n        private final List<ServiceRegistration<?>> registeredServices = new ArrayList<>();\n\n        public <T> void registerService(final T service, final Class<? super T> providedInterface, final String pid) {\n            registerService(service, providedInterface, Collections.singletonMap(\"kura.service.pid\", pid));\n        }\n\n        public <T> void registerService(final T service, final Class<? super T> providedInterface,\n                final Map<String, Object> properties) {\n            final BundleContext bundleContext = FrameworkUtil.getBundle(TamperDetectionRemoteServiceTest.class)\n                    .getBundleContext();\n\n            final Dictionary<String, Object> actualProperties = new Hashtable<>();\n\n            for (final Entry<String, Object> e : properties.entrySet()) {\n                actualProperties.put(e.getKey(), e.getValue());\n            }\n\n            registeredServices.add(bundleContext.registerService(providedInterface, service, actualProperties));\n        }\n\n        @Override\n        public void close() {\n            for (final ServiceRegistration<?> reg : registeredServices) {\n                reg.unregister();\n            }\n        }\n\n    }\n\n    private <T> T runRequestAndGetResponse(final String resource, final MethodSpec method,\n            final TypeToken<T> responseType) {\n        final String response = this.transport.runRequest(resource, method).getBody()\n                .orElseThrow(() -> new IllegalStateException(\"expected body\"));\n\n        final Gson gson = new Gson();\n        return gson.fromJson(response, responseType.getType());\n    }\n\n    public class TamperStatusInfo {\n\n        private boolean isDeviceTampered;\n        private Map<String, Object> properties;\n\n        public boolean isDeviceTampered() {\n            return isDeviceTampered;\n        }\n\n        public Map<String, Object> getProperties() {\n            return properties;\n        }\n    }\n\n    public class TamperDetectionServiceInfo {\n\n        private String pid;\n        private String displayName;\n\n        public String getPid() {\n            return pid;\n        }\n\n        public String getDisplayName() {\n            return displayName;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.stress.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.stress.test\nBundle-SymbolicName: org.eclipse.kura.stress.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.apache.logging.log4j;version=\"2.8.2\",\n org.eclipse.kura.core.testutil,\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\",\n org.slf4j;version=\"1.6.4\"\nFragment-Host: org.eclipse.kura.stress;bundle-version=\"1.1.0\"\n\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.stress.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.stress.test/build.properties",
    "content": "#\n# Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.stress.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.stress.test</artifactId>\n\t<packaging>eclipse-test-plugin</packaging>\n\t\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\t\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.stress.test/src/test/java/org/eclipse/kura/stress/test/StressTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\n\npackage org.eclipse.kura.stress.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.core.testutil.TestUtil;\nimport org.eclipse.kura.stress.HeapStress;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.mockito.Mockito;\nimport org.osgi.service.component.ComponentContext;\n\npublic class StressTest {\n\n    private static final String HEAP_ENABLE_PROP_NAME = \"heap.enable\";\n    private static final String HEAP_THREADS_PROP_NAME = \"heap.threads\";\n    private static final String HEAP_KBYTES_PROP_NAME = \"heap.size\";\n    private static final String HEAP_STRIDE_KBYTES_PROP_NAME = \"heap.stride\";\n    private static final String HEAP_HANG_MS_PROP_NAME = \"heap.keep\";\n    private static final String HEAP_INTERVAL_MS_PROP_NAME = \"heap.interval\";\n    private static final String HEAP_LOG_PROP_NAME = \"heap.log\";\n    private static final String HEAP_DELAY_MS_PROP_NAME = \"heap.delay\";\n\n    @Test\n    public void testActivate() throws NoSuchFieldException, InterruptedException {\n        ComponentContext componentContext = Mockito.mock(ComponentContext.class);\n        // initialize stress parameters\n        Map<String, Object> properties = setupStressConfig();\n\n        HeapStress stress = new HeapStress();\n        stress.activate(componentContext, properties);\n\n        // check Stress initialized correctly\n        assertNotNull(TestUtil.getFieldValue(stress, \"properties\"));\n        assertEquals(properties, TestUtil.getFieldValue(stress, \"properties\"));\n\n        ScheduledExecutorService worker = (ScheduledExecutorService) TestUtil.getFieldValue(stress, \"worker\");\n        @SuppressWarnings(\"unchecked\")\n        List<ScheduledFuture<?>> taskList = (List<ScheduledFuture<?>>) TestUtil.getFieldValue(stress, \"handle\");\n        assertEquals(properties.get(HEAP_THREADS_PROP_NAME), taskList.size());\n\n        // let the stress run for a while\n        Thread.sleep(3000);\n        // confirm stress is running\n        Assert.assertFalse(taskList.get(0).isDone());\n        Assert.assertFalse(taskList.get(1).isDone());\n\n        // stop stress\n        // taskList.get(0).cancel(true);\n        // taskList.get(1).cancel(true);\n        worker.shutdown();\n        worker.awaitTermination(1, TimeUnit.SECONDS);\n\n        // check stress completed successfully\n        assertTrue(\"Stress tasks not completed\", worker.isTerminated());\n        assertTrue(\"Stress not shutdown properly\", worker.isShutdown());\n    }\n\n    @Test\n    public void testDeactivate() throws NoSuchFieldException, InterruptedException {\n        ComponentContext componentContext = Mockito.mock(ComponentContext.class);\n        // initialize stress parameters\n        Map<String, Object> properties = setupStressConfig();\n\n        HeapStress stress = new HeapStress();\n        stress.activate(componentContext, properties);\n\n        // let the stress run for a while\n        Thread.sleep(1000);\n\n        stress.deactivate(componentContext);\n\n        ScheduledExecutorService worker = (ScheduledExecutorService) TestUtil.getFieldValue(stress, \"worker\");\n        worker.awaitTermination(1, TimeUnit.SECONDS);\n        assertTrue(\"Stress not shutdown properly\", worker.isShutdown());\n    }\n\n    @Test\n    public void testUpdated() throws NoSuchFieldException, InterruptedException {\n        ComponentContext componentContext = Mockito.mock(ComponentContext.class);\n        // initialize stress parameters\n        Map<String, Object> properties = setupStressConfig();\n\n        HeapStress stress = new HeapStress();\n        stress.activate(componentContext, properties);\n\n        // let the stress run for a while then update config\n        Thread.sleep(3000);\n        Map<String, Object> propertiesUpdated = setupStressConfig();\n        propertiesUpdated.put(HEAP_KBYTES_PROP_NAME, 10);\n        stress.updated(propertiesUpdated);\n\n        // check Stress updated correctly\n        assertEquals(propertiesUpdated, TestUtil.getFieldValue(stress, \"properties\"));\n\n        ScheduledExecutorService worker = (ScheduledExecutorService) TestUtil.getFieldValue(stress, \"worker\");\n        @SuppressWarnings(\"unchecked\")\n        List<ScheduledFuture<?>> taskList = (List<ScheduledFuture<?>>) TestUtil.getFieldValue(stress, \"handle\");\n\n        // let the stress run for a while\n        Thread.sleep(1000);\n        // confirm updated stress is running\n        Assert.assertFalse(taskList.get(2).isDone());\n        Assert.assertFalse(taskList.get(3).isDone());\n\n        // stop stress\n        worker.shutdown();\n        worker.awaitTermination(1, TimeUnit.SECONDS);\n\n        // check stress completed successfully\n        Assert.assertTrue(\"Stress tasks not completed\", worker.isTerminated());\n        Assert.assertTrue(\"Stress not shutdown properly\", worker.isShutdown());\n    }\n\n    private Map<String, Object> setupStressConfig() {\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(HEAP_ENABLE_PROP_NAME, Boolean.TRUE);\n        properties.put(HEAP_THREADS_PROP_NAME, 2);\n        properties.put(HEAP_KBYTES_PROP_NAME, 100);\n        properties.put(HEAP_STRIDE_KBYTES_PROP_NAME, 100);\n        properties.put(HEAP_HANG_MS_PROP_NAME, 100);\n        properties.put(HEAP_INTERVAL_MS_PROP_NAME, 100);\n        properties.put(HEAP_LOG_PROP_NAME, Boolean.TRUE);\n        properties.put(HEAP_DELAY_MS_PROP_NAME, 500);\n        return properties;\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.stress.test/src/test/resources/log4j.properties",
    "content": "log4j.appender.stdout=org.apache.log4j.ConsoleAppender\nlog4j.appender.stdout.Target=System.out\nlog4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout\nlog4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%t] %-5p %c{1}:%L - %m%n\n\nlog4j.rootLogger=INFO,stdout\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.test.helloworld/.gitignore",
    "content": "/bin/\n/target\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.test.helloworld/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Kura Test Hello World\nBundle-SymbolicName: org.eclipse.kura.test.helloworld;singleton:=true\nBundle-Version: 6.0.0.qualifier\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ActivationPolicy: lazy\nImport-Package: org.osgi.service.component;version=\"1.2.0\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.test.helloworld/OSGI-INF/helloworld.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\"\n\tname=\"org.eclipse.kura.test.helloworld.HelloWorld\"\n\tactivate=\"activate\"\n\tdeactivate=\"deactivate\" \n\tenabled=\"true\"\n    immediate=\"true\">\n   <implementation class=\"org.eclipse.kura.test.helloworld.HelloWorld\"/>\n   <property name=\"service.pid\" type=\"String\" value=\"org.eclipse.kura.test.helloworld.HelloWorld\"/>\n</scr:component>"
  },
  {
    "path": "kura/test/org.eclipse.kura.test.helloworld/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.test.helloworld/build.properties",
    "content": "#\n# Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html\nadditional.bundles = slf4j.api,\\\n                     org.eclipse.osgi,\\\n                     org.eclipse.osgi.services,\\\n                     org.eclipse.osgi.util\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.test.helloworld/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.test.helloworld</artifactId>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\t\n\t<build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.test.helloworld/src/main/java/org/eclipse/kura/test/helloworld/HelloWorld.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.test.helloworld;\n\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class HelloWorld {\n\n    private static final Logger s_logger = LoggerFactory.getLogger(HelloWorld.class);\n\n    private static final String APP_ID = HelloWorld.class.getName();\n\n    // ----------------------------------------------------------------\n    //\n    // Activation APIs\n    //\n    // ----------------------------------------------------------------\n\n    protected void activate(ComponentContext componentContext) {\n        s_logger.info(\"Bundle \" + APP_ID + \" has started\");\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        s_logger.info(\"Deactivating \" + APP_ID + \" ...\");\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.test.helloworld/src/main/resources/org.eclipse.kura.test.helloworld.dpp",
    "content": "#Deployment Plugin Project File\n#Wed Jul 16 14:21:53 CDT 2014\nbuild.ant.name=<.>/src/main/resources/org.eclipse.kura.test.helloworld_build.xml\nbuild.dp.file=<.>/target/org.eclipse.kura.test.helloworld.dp\nbuild.location=\nbundles.0.bundle_path=/home/ibinshtok/eurotechdev/kuradev/workspace/plugins/org.eclipse.kura.test.helloworld_1.0.0.201407161421.jar\nbundles.0.customizer=false\nbundles.0.headers.count=0\nbundles.0.missing=false\nbundles.0.name=bundles/org.eclipse.kura.test.helloworld_1.0.0.201407161421.jar\nbundles.0.symbolic_name=org.eclipse.kura.test.helloworld;singleton\\:\\=true\nbundles.0.version=1.0.0.201407161421\nbundles.count=1\ncertificates.count=0\ngeneral.signbundles=false\nheaders.other.headers=\nheaders.symbolic.name=org.eclipse.kura.test.helloworld\nheaders.version=1.0.0\nresources.count=0\n\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.useradmin.store.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.useradmin.store.test\nBundle-SymbolicName: org.eclipse.kura.useradmin.store.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"1.6.0\",\n org.eclipse.kura.configuration;version=\"1.2.0\",\n org.eclipse.kura.util.wire.test;version=\"1.1.0\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.useradmin\nRequire-Bundle: org.apache.felix.useradmin;bundle-version=\"1.0.4\",\n org.eclipse.kura.useradmin.store;bundle-version=\"1.1.0\"\n\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.useradmin.store.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.useradmin.store.test/build.properties",
    "content": "#\n# Copyright (c) 2021 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\n\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api,\\\n                     org.apache.logging.log4j.api\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.useradmin.store.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n\tSPDX-License-Identifier: EPL-2.0\n\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.useradmin.store.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.useradmin.store.test/src/main/java/org/eclipse/kura/useradmin/store/test/RoleRepositoryStoreTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.useradmin.store.test;\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.function.Function;\nimport java.util.function.IntConsumer;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.util.wire.test.WireTestUtil;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.service.useradmin.Group;\nimport org.osgi.service.useradmin.Role;\nimport org.osgi.service.useradmin.User;\nimport org.osgi.service.useradmin.UserAdmin;\n\npublic class RoleRepositoryStoreTest {\n\n    private final UserAdmin userAdmin;\n    private final ConfigurationService configurationService;\n\n    @BeforeClass\n    public static void setUp() {\n        try {\n            // wait for spurious updates\n            WireTestUtil\n                    .modified(\"(kura.service.pid=org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl)\")\n                    .get(30, TimeUnit.SECONDS);\n        } catch (final Exception e) {\n            // no need\n        }\n    }\n\n    public RoleRepositoryStoreTest()\n            throws InterruptedException, ExecutionException, TimeoutException, KuraException, InvalidSyntaxException {\n        userAdmin = WireTestUtil.trackService(UserAdmin.class, Optional.empty()).get(30, TimeUnit.SECONDS);\n        configurationService = WireTestUtil.trackService(ConfigurationService.class, Optional.empty()).get(30,\n                TimeUnit.SECONDS);\n\n        final CompletableFuture<Void> modified = WireTestUtil\n                .modified(\"(kura.service.pid=org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl)\");\n\n        final Role[] roles = userAdmin.getRoles(null);\n\n        if (roles == null) {\n            return;\n        }\n\n        for (final Role role : roles) {\n            userAdmin.removeRole(role.getName());\n        }\n\n        modified.get(30, TimeUnit.SECONDS);\n    }\n\n    @Test\n    public void shouldHaveDefaultConfig() throws KuraException {\n        final Options currentOptions = getCurrentRoleRepositoryStoreOptions();\n\n        assertEquals(\"[]\", currentOptions.rolesConfig);\n        assertEquals(\"[]\", currentOptions.usersConfig);\n        assertEquals(\"[]\", currentOptions.groupsConfig);\n        assertEquals(5000L, currentOptions.writeDelayMs);\n    }\n\n    @Test\n    public void shouldCreateEmptyUser()\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        testRoleKindConfig(k -> userAdmin.createRole(\"foo\" + k, k), k -> \"[{\\\"name\\\":\\\"foo\" + k + \"\\\"}]\", Role.USER,\n                Role.GROUP);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldSerializeRoleProperties()\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        testRoleKindConfig(k -> {\n            final Role role = userAdmin.createRole(\"foo\" + k, k);\n            role.getProperties().put(\"foo\", \"bar\");\n            role.getProperties().put(\"boo\", new byte[] { 1, 2, 3, 4 });\n        }, k -> \"[{\\\"name\\\":\\\"foo\" + k + \"\\\",\\\"properties\\\":{\\\"boo\\\":[1,2,3,4],\\\"foo\\\":\\\"bar\\\"}}]\", Role.USER,\n                Role.GROUP);\n    }\n\n    @Test\n    public void shouldSupportRemovingRoleProperties()\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        shouldSerializeRoleProperties();\n\n        testRoleKindConfig(k -> {\n            final Role role = userAdmin.getRole(\"foo\" + k);\n            role.getProperties().remove(\"boo\");\n        }, k -> \"[{\\\"name\\\":\\\"foo\" + k + \"\\\",\\\"properties\\\":{\\\"foo\\\":\\\"bar\\\"}}]\", Role.USER, Role.GROUP);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @Test\n    public void shouldSerializeRoleCredentials()\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        testRoleKindConfig(k -> {\n            final User role = (User) userAdmin.createRole(\"foo\" + k, k);\n            role.getCredentials().put(\"foo\", \"bar\");\n            role.getCredentials().put(\"boo\", new byte[] { 1, 2, 3, 4 });\n        }, k -> \"[{\\\"name\\\":\\\"foo\" + k + \"\\\",\\\"credentials\\\":{\\\"boo\\\":[1,2,3,4],\\\"foo\\\":\\\"bar\\\"}}]\", Role.USER,\n                Role.GROUP);\n    }\n\n    @Test\n    public void shouldSupportRemovingRoleCredentials()\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        shouldSerializeRoleCredentials();\n\n        testRoleKindConfig(k -> {\n            final User role = (User) userAdmin.getRole(\"foo\" + k);\n            role.getCredentials().remove(\"boo\");\n        }, k -> \"[{\\\"name\\\":\\\"foo\" + k + \"\\\",\\\"credentials\\\":{\\\"foo\\\":\\\"bar\\\"}}]\", Role.USER, Role.GROUP);\n    }\n\n    @Test\n    public void shouldSupportBasicMembers()\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n\n        final Role foo = userAdmin.createRole(\"foo\", Role.USER);\n        final Role bar = userAdmin.createRole(\"bar\", Role.USER);\n        final Role baz = userAdmin.createRole(\"baz\", Role.GROUP);\n\n        testRoleKindConfig(k -> {\n            final Group group = (Group) userAdmin.createRole(\"group\", Role.GROUP);\n            group.addMember(foo);\n            group.addMember(bar);\n            group.addMember(baz);\n        }, k -> \"[{\\\"name\\\":\\\"baz\\\"},{\\\"name\\\":\\\"group\\\",\\\"basicMembers\\\":[\\\"bar\\\",\\\"baz\\\",\\\"foo\\\"]}]\", Role.GROUP);\n    }\n\n    @Test\n    public void shouldSupportRemovingBasicMembers()\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n\n        shouldSupportBasicMembers();\n\n        testRoleKindConfig(k -> {\n            final Group group = (Group) userAdmin.getRole(\"group\");\n            group.removeMember(userAdmin.getRole(\"baz\"));\n        }, k -> \"[{\\\"name\\\":\\\"baz\\\"},{\\\"name\\\":\\\"group\\\",\\\"basicMembers\\\":[\\\"bar\\\",\\\"foo\\\"]}]\", Role.GROUP);\n    }\n\n    @Test\n    public void shouldSupportRequiredMembers()\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n\n        final Role foo = userAdmin.createRole(\"foo\", Role.USER);\n        final Role bar = userAdmin.createRole(\"bar\", Role.USER);\n        final Role baz = userAdmin.createRole(\"baz\", Role.GROUP);\n\n        testRoleKindConfig(k -> {\n            final Group group = (Group) userAdmin.createRole(\"group\", Role.GROUP);\n            group.addRequiredMember(foo);\n            group.addRequiredMember(bar);\n            group.addRequiredMember(baz);\n        }, k -> \"[{\\\"name\\\":\\\"baz\\\"},{\\\"name\\\":\\\"group\\\",\\\"requiredMembers\\\":[\\\"bar\\\",\\\"baz\\\",\\\"foo\\\"]}]\", Role.GROUP);\n    }\n\n    @Test\n    public void shouldSupportRemovingRequiredMembers()\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n\n        shouldSupportRequiredMembers();\n\n        testRoleKindConfig(k -> {\n            final Group group = (Group) userAdmin.getRole(\"group\");\n            group.removeMember(userAdmin.getRole(\"baz\"));\n        }, k -> \"[{\\\"name\\\":\\\"baz\\\"},{\\\"name\\\":\\\"group\\\",\\\"requiredMembers\\\":[\\\"bar\\\",\\\"foo\\\"]}]\", Role.GROUP);\n    }\n\n    private void testRoleKindConfig(final IntConsumer setup, final Function<Integer, String> expectedConfig,\n            final int... kinds)\n            throws KuraException, InvalidSyntaxException, InterruptedException, ExecutionException, TimeoutException {\n        for (final int type : kinds) {\n\n            final CompletableFuture<Void> modified = WireTestUtil\n                    .modified(\"(kura.service.pid=org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl)\");\n\n            setup.accept(type);\n\n            modified.get(30, TimeUnit.SECONDS);\n\n            final Options currentOptions = getCurrentRoleRepositoryStoreOptions();\n\n            final String expected = expectedConfig.apply(type);\n\n            if (type == Role.ROLE) {\n                assertEquals(expected, currentOptions.rolesConfig);\n            } else if (type == Role.USER) {\n                assertEquals(expected, currentOptions.usersConfig);\n            } else if (type == Role.GROUP) {\n                assertEquals(expected, currentOptions.groupsConfig);\n            } else {\n                throw new IllegalStateException();\n            }\n        }\n    }\n\n    private Options getCurrentRoleRepositoryStoreOptions() throws KuraException {\n        final ComponentConfiguration config = configurationService\n                .getComponentConfiguration(\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\");\n\n        return new Options(config.getConfigurationProperties());\n    }\n\n    private static final class Options {\n\n        private static final String ROLES_CONFIG_ID = \"roles.config\";\n        private static final String USERS_CONFIG_ID = \"users.config\";\n        private static final String GROUPS_CONFIG_ID = \"groups.config\";\n        private static final String WRITE_DELAY_MS_ID = \"write.delay.ms\";\n\n        private final String rolesConfig;\n        private final String usersConfig;\n        private final String groupsConfig;\n        private final long writeDelayMs;\n\n        Options(final Map<String, Object> properties) {\n            this.rolesConfig = (String) properties.getOrDefault(ROLES_CONFIG_ID, \"[]\");\n            this.usersConfig = (String) properties.getOrDefault(USERS_CONFIG_ID, \"[]\");\n            this.groupsConfig = (String) properties.getOrDefault(GROUPS_CONFIG_ID, \"[]\");\n            this.writeDelayMs = (Long) properties.getOrDefault(WRITE_DELAY_MS_ID, 5000L);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.util.test\nBundle-SymbolicName: org.eclipse.kura.util.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nFragment-Host: org.eclipse.kura.util;bundle-version=\"1.0.0\"\nImport-Package: org.apache.commons.io;version=\"2.11.0\",\n org.eclipse.kura.gpio;version=\"[1.1,2.0)\",\n org.eclipse.kura.watchdog;version=\"[1.0,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\",\n org.mockito.invocation;version=\"5.0.0\",\n org.mockito.stubbing;version=\"5.0.0\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/build.properties",
    "content": "#\n# Copyright (c) 2018, 2020 Red Hat Inc and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Red Hat Inc\n#\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2018, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n    \n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.util.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/src/main/java/org/eclipse/kura/osgi/BundleUtilTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.osgi;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.util.osgi.BundleUtil;\nimport org.junit.Test;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.FrameworkUtil;\n\npublic class BundleUtilTest {\n\n    private Map<String, String> keyValueMap = new HashMap<>();\n    private Class<?>[] servicesClasses;\n    private Set<Bundle> bundles;\n    private BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext();\n\n    @Test\n    public void shouldReturnGPIOBundle() {\n\n        givenServicesPropertiesFilter(\"service.pid\", \"org.eclipse.kura.gpio.GPIOService\");\n        givenServiceClasses(new Class<?>[] { org.eclipse.kura.gpio.GPIOService.class });\n\n        whenBundleListIsRequested();\n\n        thenBundlesAre(1);\n        thenBundleSymbolicNamesAre(\"org.eclipse.kura.emulator.gpio\");\n    }\n\n    @Test\n    public void shouldReturnWatchdogAndGPIOBundles() {\n        givenServiceClasses(new Class<?>[] { org.eclipse.kura.gpio.GPIOService.class,\n                org.eclipse.kura.watchdog.WatchdogService.class });\n\n        whenBundleListIsRequested();\n\n        thenBundlesAre(2);\n\n        thenBundleSymbolicNamesAre(\"org.eclipse.kura.emulator.gpio\", \"org.eclipse.kura.watchdog\");\n    }\n\n    @Test\n    public void shouldReturnNoBundleWithWrongProperty() {\n        givenServicesPropertiesFilter(\"service.pid\", \"wrongServicePid\");\n        givenServiceClasses(new Class<?>[] { org.eclipse.kura.gpio.GPIOService.class });\n\n        whenBundleListIsRequested();\n\n        thenBundlesAre(0);\n    }\n\n    @Test\n    public void shouldReturnOnlyBundleWithRightProperty() {\n        givenServicesPropertiesFilter(\"service.pid\", \"org.eclipse.kura.gpio.GPIOService\");\n        givenServiceClasses(new Class<?>[] { org.eclipse.kura.gpio.GPIOService.class,\n                org.eclipse.kura.watchdog.WatchdogService.class });\n\n        whenBundleListIsRequested();\n\n        thenBundlesAre(1);\n        thenBundleSymbolicNamesAre(\"org.eclipse.kura.emulator.gpio\");\n    }\n\n    @Test\n    public void shouldReturnGPIOBundleBySingleHeader() {\n        givenBundleHeaders(\"Bundle-Name\", \"org.eclipse.kura.emulator.gpio\");\n\n        whenBundleListIsRequestByHeaders();\n\n        thenBundlesAre(1);\n        thenBundleSymbolicNamesAre(\"org.eclipse.kura.emulator.gpio\");\n    }\n\n    @Test\n    public void shouldReturnGPIOBundleByMultipleHeaders() {\n        givenBundleHeaders(\"Bundle-Name\", \"org.eclipse.kura.emulator.gpio\", \"Bundle-Vendor\", \"Eclipse Kura\");\n\n        whenBundleListIsRequestByHeaders();\n\n        thenBundlesAre(1);\n        thenBundleSymbolicNamesAre(\"org.eclipse.kura.emulator.gpio\");\n    }\n\n    @Test\n    public void shouldReturnManyBundlesByHeader() {\n        givenBundleHeaders(\"Bundle-Vendor\", \"Eclipse Kura\");\n\n        whenBundleListIsRequestByHeaders();\n\n        thenBundlesAreMany();\n    }\n\n    private void givenBundleHeaders(String... headers) {\n        for (int i = 0; i < headers.length; i = i + 2) {\n            this.keyValueMap.put(headers[i], headers[i + 1]);\n        }\n    }\n\n    private void givenServicesPropertiesFilter(String... properties) {\n        for (int i = 0; i < properties.length; i = i + 2) {\n            this.keyValueMap.put(properties[i], properties[i + 1]);\n        }\n    }\n\n    private void givenServiceClasses(Class<?>[] classes) {\n        this.servicesClasses = classes;\n\n    }\n\n    private void whenBundleListIsRequested() {\n        this.bundles = BundleUtil.getBundles(this.bundleContext, this.servicesClasses, this.keyValueMap);\n\n        printBundlesSymbolicName(this.bundles);\n    }\n\n    private void whenBundleListIsRequestByHeaders() {\n        this.bundles = BundleUtil.getBundles(this.bundleContext, this.keyValueMap);\n\n        printBundlesSymbolicName(this.bundles);\n    }\n\n    private void thenBundlesAre(int expectedNumberOfBundles) {\n        assertEquals(expectedNumberOfBundles, this.bundles.size());\n\n    }\n\n    private void thenBundlesAreMany() {\n        assertTrue(\"Too few Bundles\", this.bundles.size() > 1);\n\n    }\n\n    private void thenBundleSymbolicNamesAre(String... symbolicNames) {\n        List<String> bundleSymbolicNames = this.bundles.stream().map(Bundle::getSymbolicName)\n                .collect(Collectors.toList());\n\n        assertTrue(\"Not found all bundles\", bundleSymbolicNames.containsAll(bundleSymbolicNames));\n    }\n\n    private void printBundlesSymbolicName(Set<Bundle> bundle) {\n        String bundlesSymbolicName = bundles.stream().map(Bundle::getSymbolicName)\n                .collect(Collectors.joining(\"\", \",\", \"\"));\n\n        System.out.println(\"Bundles Found: \" + bundlesSymbolicName);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/src/main/java/org/eclipse/kura/osgi/SingleServiceTrackerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2022 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n\npackage org.eclipse.kura.osgi;\n\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.function.Consumer;\n\nimport org.eclipse.kura.util.osgi.SingleServiceTracker;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Constants;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.ServiceRegistration;\n\npublic class SingleServiceTrackerTest {\n\n    private static final class MockConsumer<T> implements Consumer<T> {\n\n        private T service;\n\n        @Override\n        public void accept(T t) {\n            this.service = t;\n        }\n\n        public T getService() {\n            return service;\n        }\n    }\n\n    private static final class MockService {\n    }\n\n    private BundleContext context;\n\n    private List<ServiceRegistration<?>> registrations = new LinkedList<>();\n\n    @Before\n    public void setup() {\n        this.context = FrameworkUtil.getBundle(SingleServiceTrackerTest.class).getBundleContext();\n    }\n\n    @After\n    public void unregisterAll() {\n        this.registrations.forEach(ServiceRegistration::unregister);\n    }\n\n    protected <T> ServiceRegistration<T> register(final Class<T> clazz, final T service,\n            final Dictionary<String, ?> properties) {\n\n        final ServiceRegistration<T> registration = this.context.registerService(clazz, service, properties);\n        this.registrations.add(registration);\n        return registration;\n\n    }\n\n    protected void unregister(final ServiceRegistration<?> registration) {\n        this.registrations.remove(registration);\n        registration.unregister();\n    }\n\n    @Test\n    public void testInitOrder1() {\n\n        final MockConsumer<MockService> consumer = new MockConsumer<>();\n        final SingleServiceTracker<MockService> tracker = new SingleServiceTracker<>(this.context, MockService.class,\n                consumer);\n\n        Assert.assertNull(consumer.getService());\n\n        final MockService service1 = new MockService();\n        final MockService service2 = new MockService();\n\n        final ServiceRegistration<MockService> handle2 = register(MockService.class, service2, withRanking(2));\n        final ServiceRegistration<MockService> handle1 = register(MockService.class, service1, withRanking(1));\n\n        tracker.open();\n        Assert.assertEquals(service2, consumer.getService());\n        tracker.close();\n\n        Assert.assertNull(consumer.getService());\n\n    }\n\n    @Test\n    public void testOrderRemove1() {\n\n        final BundleContext context = FrameworkUtil.getBundle(SingleServiceTrackerTest.class).getBundleContext();\n\n        final MockConsumer<MockService> consumer = new MockConsumer<>();\n        final SingleServiceTracker<MockService> tracker = new SingleServiceTracker<>(context, MockService.class,\n                consumer);\n\n        Assert.assertNull(consumer.getService());\n\n        final MockService service1 = new MockService();\n        final MockService service2 = new MockService();\n\n        final ServiceRegistration<MockService> handle2 = register(MockService.class, service2, withRanking(2));\n        final ServiceRegistration<MockService> handle1 = register(MockService.class, service1, withRanking(1));\n\n        tracker.open();\n        Assert.assertEquals(service2, consumer.getService());\n        unregister(handle2);\n        Assert.assertEquals(service1, consumer.getService());\n        tracker.close();\n\n        Assert.assertNull(consumer.getService());\n\n    }\n\n    @Test\n    public void testOrderAdd1() {\n\n        final BundleContext context = FrameworkUtil.getBundle(SingleServiceTrackerTest.class).getBundleContext();\n\n        final MockConsumer<MockService> consumer = new MockConsumer<>();\n        final SingleServiceTracker<MockService> tracker = new SingleServiceTracker<>(context, MockService.class,\n                consumer);\n\n        Assert.assertNull(consumer.getService());\n\n        final MockService service1 = new MockService();\n        final MockService service2 = new MockService();\n\n        final ServiceRegistration<MockService> handle1 = register(MockService.class, service1, withRanking(1));\n\n        tracker.open();\n        Assert.assertEquals(service1, consumer.getService());\n\n        final ServiceRegistration<MockService> handle2 = register(MockService.class, service2, withRanking(2));\n\n        Assert.assertEquals(service2, consumer.getService());\n        tracker.close();\n\n        Assert.assertNull(consumer.getService());\n\n    }\n\n    /**\n     * Add new service with same ranking\n     */\n    @Test\n    public void testOrderAdd2() {\n\n        final BundleContext context = FrameworkUtil.getBundle(SingleServiceTrackerTest.class).getBundleContext();\n\n        final MockConsumer<MockService> consumer = new MockConsumer<>();\n        final SingleServiceTracker<MockService> tracker = new SingleServiceTracker<>(context, MockService.class,\n                consumer);\n\n        Assert.assertNull(consumer.getService());\n\n        final MockService service1 = new MockService();\n        final MockService service2 = new MockService();\n\n        final ServiceRegistration<MockService> handle1 = register(MockService.class, service1, withRanking(1));\n\n        tracker.open();\n        Assert.assertEquals(service1, consumer.getService());\n\n        final ServiceRegistration<MockService> handle2 = register(MockService.class, service2, withRanking(1));\n\n        Assert.assertEquals(service1, consumer.getService());\n        tracker.close();\n\n        Assert.assertNull(consumer.getService());\n\n    }\n\n    /**\n     * Add new service with a lower ranking\n     */\n    @Test\n    public void testOrderAdd3() {\n\n        final BundleContext context = FrameworkUtil.getBundle(SingleServiceTrackerTest.class).getBundleContext();\n\n        final MockConsumer<MockService> consumer = new MockConsumer<>();\n        final SingleServiceTracker<MockService> tracker = new SingleServiceTracker<>(context, MockService.class,\n                consumer);\n\n        Assert.assertNull(consumer.getService());\n\n        final MockService service1 = new MockService();\n        final MockService service2 = new MockService();\n        final MockService service3 = new MockService();\n\n        final ServiceRegistration<MockService> handle1 = register(MockService.class, service1, withRanking(null));\n        final ServiceRegistration<MockService> handle2 = register(MockService.class, service2, withRanking(null));\n\n        tracker.open();\n        Assert.assertEquals(service1, consumer.getService());\n\n        final ServiceRegistration<MockService> handle3 = register(MockService.class, service3, withRanking(-1));\n\n        Assert.assertEquals(service1, consumer.getService());\n        tracker.close();\n\n        Assert.assertNull(consumer.getService());\n\n    }\n\n    @Test\n    public void testOrderModify1() {\n\n        final BundleContext context = FrameworkUtil.getBundle(SingleServiceTrackerTest.class).getBundleContext();\n\n        final MockConsumer<MockService> consumer = new MockConsumer<>();\n        final SingleServiceTracker<MockService> tracker = new SingleServiceTracker<>(context, MockService.class,\n                consumer);\n\n        Assert.assertNull(consumer.getService());\n\n        final MockService service1 = new MockService();\n        final MockService service2 = new MockService();\n\n        final ServiceRegistration<MockService> handle2 = register(MockService.class, service2, withRanking(2));\n        final ServiceRegistration<MockService> handle1 = register(MockService.class, service1, withRanking(1));\n\n        tracker.open();\n        Assert.assertEquals(service2, consumer.getService());\n        handle1.setProperties(withRanking(3));\n        Assert.assertEquals(service1, consumer.getService());\n        tracker.close();\n\n        Assert.assertNull(consumer.getService());\n\n    }\n\n    @Test\n    public void testOrderModify2() {\n\n        final BundleContext context = FrameworkUtil.getBundle(SingleServiceTrackerTest.class).getBundleContext();\n\n        final MockConsumer<MockService> consumer = new MockConsumer<>();\n        final SingleServiceTracker<MockService> tracker = new SingleServiceTracker<>(context, MockService.class,\n                consumer);\n\n        Assert.assertNull(consumer.getService());\n\n        final MockService service1 = new MockService();\n        final MockService service2 = new MockService();\n\n        final ServiceRegistration<MockService> handle1 = register(MockService.class, service1, withRanking(null));\n        final ServiceRegistration<MockService> handle2 = register(MockService.class, service2, withRanking(2));\n\n        tracker.open();\n        Assert.assertEquals(service2, consumer.getService());\n        handle1.setProperties(withRanking(3));\n        Assert.assertEquals(service1, consumer.getService());\n        tracker.close();\n\n        Assert.assertNull(consumer.getService());\n\n    }\n\n    @Test\n    public void testOrderModify3() throws InterruptedException {\n\n        final BundleContext context = FrameworkUtil.getBundle(SingleServiceTrackerTest.class).getBundleContext();\n\n        final MockConsumer<MockService> consumer = new MockConsumer<>();\n        final SingleServiceTracker<MockService> tracker = new SingleServiceTracker<>(context, MockService.class,\n                consumer);\n\n        Assert.assertNull(consumer.getService());\n\n        final MockService service1 = new MockService();\n        final MockService service2 = new MockService();\n\n        final ServiceRegistration<MockService> handle1 = register(MockService.class, service1, withRanking(1));\n        final ServiceRegistration<MockService> handle2 = register(MockService.class, service2, withRanking(1));\n\n        tracker.open();\n\n        // expect the first registered service\n        Assert.assertEquals(service1, consumer.getService());\n\n        // update, but don't change ranking\n        handle1.setProperties(withRanking(1));\n\n        // should still be the same service\n        Assert.assertEquals(service1, consumer.getService());\n\n        // change ranking\n\n        handle2.setProperties(withRanking(2));\n        Assert.assertEquals(service2, consumer.getService());\n\n        tracker.close();\n\n        Assert.assertNull(consumer.getService());\n\n    }\n\n    /**\n     * Add new service with same ranking\n     */\n    @Test\n    public void testOrder1() {\n\n        final BundleContext context = FrameworkUtil.getBundle(SingleServiceTrackerTest.class).getBundleContext();\n\n        final MockConsumer<MockService> consumer = new MockConsumer<>();\n        final SingleServiceTracker<MockService> tracker = new SingleServiceTracker<>(context, MockService.class,\n                consumer);\n\n        Assert.assertNull(consumer.getService());\n\n        final MockService service1 = new MockService();\n        final MockService service2 = new MockService();\n        final MockService service3 = new MockService();\n\n        final ServiceRegistration<MockService> handle1 = register(MockService.class, service1, withRanking(1));\n        final ServiceRegistration<MockService> handle2 = register(MockService.class, service2, withRanking(1));\n        final ServiceRegistration<MockService> handle3 = register(MockService.class, service3, withRanking(2));\n\n        tracker.open();\n\n        Assert.assertEquals(service3, consumer.getService());\n\n        unregister(handle3);\n        Assert.assertEquals(service1, consumer.getService());\n\n        tracker.close();\n\n        Assert.assertNull(consumer.getService());\n    }\n\n    private Dictionary<String, ?> withRanking(final Integer ranking) {\n        final Hashtable<String, Object> properties = new Hashtable<>();\n        if (ranking != null) {\n            properties.put(Constants.SERVICE_RANKING, ranking);\n        }\n        return properties;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/src/main/java/org/eclipse/kura/util/base/ConvertStringTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.base;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport org.junit.Test;\n\npublic class ConvertStringTest {\n\n    private String string;\n\n    @Test\n    public void convertUTF8StringToHex() {\n        givenString(\"kura€&\");\n\n        thenIsConvertedIn(\"6B757261E282AC26\");\n    }\n\n    @Test\n    public void unescapeUTF8String() {\n        givenString(\"kura\\\\xe2\\\\x82\\\\xac&\");\n\n        thenIsUnescapedIn(\"kura€&\");\n    }\n\n    private void thenIsUnescapedIn(String string) {\n        assertEquals(string, StringUtil.unescapeUTF8String(this.string));\n    }\n\n    private void thenIsConvertedIn(String hex) {\n        assertTrue(StringUtil.toHex(string).equalsIgnoreCase(hex));\n    }\n\n    private void givenString(String string) {\n        this.string = string;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/src/test/java/org/eclipse/kura/util/FilterUtilTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2018, 2020 Red Hat Inc and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Red Hat Inc\n *******************************************************************************/\n\npackage org.eclipse.kura.util;\n\nimport static org.eclipse.kura.util.osgi.FilterUtil.and;\nimport static org.eclipse.kura.util.osgi.FilterUtil.equal;\nimport static org.eclipse.kura.util.osgi.FilterUtil.not;\nimport static org.eclipse.kura.util.osgi.FilterUtil.or;\nimport static org.junit.Assert.assertEquals;\nimport static org.osgi.framework.FrameworkUtil.createFilter;\n\nimport org.eclipse.kura.util.base.StringUtil;\nimport org.eclipse.kura.util.osgi.FilterUtil;\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.osgi.framework.InvalidSyntaxException;\n\npublic class FilterUtilTest {\n\n    @Test\n    public void testEqual1() throws InvalidSyntaxException {\n        testFilter(\"(foo=bar)\", equal(\"foo\", \"bar\"));\n    }\n\n    @Test\n    public void testEqual2() throws InvalidSyntaxException {\n        testFilter(\"\", equal(null, \"bar\"));\n    }\n\n    @Test\n    public void testAnd1() throws InvalidSyntaxException {\n        testFilter(\"(&(foo1=bar1)(foo2=bar2))\", and(equal(\"foo1\", \"bar1\"), equal(\"foo2\", \"bar2\")));\n    }\n\n    @Test\n    public void testAnd2() throws InvalidSyntaxException {\n        testFilter(\"(&(foo1=bar1)(foo2=bar2)(foo3=bar3))\",\n                and(equal(\"foo1\", \"bar1\"), equal(\"foo2\", \"bar2\"), equal(\"foo3\", \"bar3\")));\n    }\n\n    @Test\n    public void testAnd3() throws InvalidSyntaxException {\n        testFilter(\"(foo1=bar1)\", and(equal(\"foo1\", \"bar1\"), equal(\"\", \"bar2\")));\n    }\n\n    @Test\n    public void testSpecialAnd1() throws InvalidSyntaxException {\n        testFilter(\"(foo1=bar1)\", and(equal(\"foo1\", \"bar1\")));\n    }\n\n    @Test\n    public void testOr1() throws InvalidSyntaxException {\n        testFilter(\"(|(foo1=bar1)(foo2=bar2))\", or(equal(\"foo1\", \"bar1\"), equal(\"foo2\", \"bar2\")));\n    }\n\n    @Test\n    public void testNot1() throws InvalidSyntaxException {\n        testFilter(\"(!(foo1=bar1))\", not(equal(\"foo1\", \"bar1\")));\n    }\n\n    @Test\n    public void testNot2() throws InvalidSyntaxException {\n        testFilter(\"\", not(equal(\"\", \"bar1\")));\n    }\n\n    @Test\n    public void testSimpleFilter() throws InvalidSyntaxException {\n        testFilter(\"(&(objectClass=org.eclipse.kura.util.FilterUtilTest)(foo=bar))\",\n                FilterUtil.simpleFilter(FilterUtilTest.class, \"foo\", \"bar\"));\n    }\n\n    @Test\n    public void testQuote1() throws InvalidSyntaxException {\n        testFilter(\"(foo=bar\\\\*bar)\", equal(\"foo\", \"bar*bar\"));\n    }\n\n    @Test\n    public void testQuote2() throws InvalidSyntaxException {\n        testFilter(\"(foo\\\\*foo=bar\\\\*bar)\", equal(\"foo*foo\", \"bar*bar\"));\n    }\n\n    @Test\n    public void testQuoteNull() throws InvalidSyntaxException {\n        Assert.assertNull(FilterUtil.quote(null));\n    }\n\n    private void testFilter(final String expected, final String actual) throws InvalidSyntaxException {\n        if (!StringUtil.isNullOrEmpty(expected)) {\n            createFilter(expected);\n        }\n\n        if (!StringUtil.isNullOrEmpty(actual)) {\n            createFilter(actual);\n        }\n\n        assertEquals(expected, actual);\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/src/test/java/org/eclipse/kura/util/zip/UnZipTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage org.eclipse.kura.util.zip;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.apache.commons.io.FileUtils;\nimport org.junit.After;\nimport org.junit.Test;\n\npublic class UnZipTest {\n\n    private static final String WORK_FOLDER = \"/tmp/kura_test/\";\n    private static final String SINGLE_INPUT_ZIP_FILE = \"singleCompressedFile.zip\";\n    private static final String MULTIPLE_INPUT_ZIP_FILE = \"multipleCompressedFile.zip\";\n    private static final String TOO_MANY_INPUT_ZIP_FILE = \"tooManyCompressedFiles.zip\";\n    private static final String TOO_BIG_INPUT_ZIP_FILE = \"tooBigCompressedFile.zip\";\n    private static final String ILLEGAL_PATH_INPUT_ZIP_FILE = \"illegalPathCompressedFile.zip\";\n    private static final String UNCOMPRESSED_INPUT_ZIP_FILE = \"uncompressedFile.txt\";\n    private static final String INPUT_TAR_FILE = \"singleCompressedFile.tar\";\n    private static final String SINGLE_INPUT_ZIP_FILE_PATH = \"target/test-classes/\" + SINGLE_INPUT_ZIP_FILE;\n    private static final String MULTIPLE_INPUT_ZIP_FILE_PATH = \"target/test-classes/\" + MULTIPLE_INPUT_ZIP_FILE;\n    private static final String TOO_MANY_INPUT_ZIP_FILE_PATH = \"target/test-classes/\" + TOO_MANY_INPUT_ZIP_FILE;\n    private static final String TOO_BIG_INPUT_ZIP_FILE_PATH = \"target/test-classes/\" + TOO_BIG_INPUT_ZIP_FILE;\n    private static final String ILLEGAL_PATH_INPUT_ZIP_FILE_PATH = \"target/test-classes/\" + ILLEGAL_PATH_INPUT_ZIP_FILE;\n    private static final String UNCOMPRESSED_INPUT_ZIP_FILE_PATH = \"target/test-classes/\" + UNCOMPRESSED_INPUT_ZIP_FILE;\n    private static final String INPUT_TAR_FILE_PATH = \"target/test-classes/\" + INPUT_TAR_FILE;\n\n    private byte[] compressedInput;\n    private boolean exceptionCaught;\n\n    @After\n    public void clean() throws IOException {\n        FileUtils.deleteDirectory(new File(WORK_FOLDER));\n    }\n\n    @Test\n    public void unZipFileTest() throws IOException {\n        givenCompressedFile();\n\n        whenFileIsUnzipped();\n\n        thenUncompressedFileExists();\n        thenUncompressedFileIsAFile();\n        thenUncompressedFileIsCorrect();\n    }\n\n    @Test\n    public void unZipByteStreamTest() throws IOException {\n        givenCompressedStream();\n\n        whenStreamIsUnzipped();\n\n        thenUncompressedFileExists();\n        thenUncompressedFileIsAFile();\n        thenUncompressedFileIsCorrect();\n    }\n\n    @Test\n    public void catchExceptionWhenTooManyFilesTest() throws IOException {\n        givenTooManyCompressedFile();\n\n        whenTooManyFilesIsUnzipped();\n\n        thenExceptionIsCaught();\n    }\n\n    @Test\n    public void catchExceptionWhenTooBigFileTest() throws IOException {\n        givenTooBigCompressedFile();\n\n        whenTooBigFileIsUnzipped();\n\n        thenExceptionIsCaught();\n    }\n\n    @Test\n    public void catchExceptionWhenIllegalPathFileTest() throws IOException {\n        givenIllegalPathCompressedFile();\n\n        whenIllegalPathFileIsUnzipped();\n\n        thenExceptionIsCaught();\n    }\n\n    @Test\n    public void unZipMultipleFilesTest() throws IOException {\n        givenMultipleCompressedFile();\n\n        whenMultipleFileIsUnzipped();\n\n        thenMultipleUncompressedFileExists();\n    }\n\n    @Test\n    public void unZipUncompressedFileTest() throws IOException {\n        givenUnCompressedFile();\n\n        whenUncompressedFileIsUnzipped();\n\n        thenUncompressedFileNotExist();\n    }\n\n    @Test\n    public void unZipTarFileTest() throws IOException {\n        givenTarCompressedFile();\n\n        whenTarFileIsUnzipped();\n\n        thenUncompressedFileNotExist();\n    }\n\n    private void givenCompressedFile() throws IOException {\n        createOutputFolder();\n        copyFile(SINGLE_INPUT_ZIP_FILE_PATH, SINGLE_INPUT_ZIP_FILE);\n    }\n\n    private void givenCompressedStream() throws IOException {\n        createOutputFolder();\n        this.compressedInput = getFileBytes(new File(SINGLE_INPUT_ZIP_FILE_PATH));\n    }\n\n    private void givenTooManyCompressedFile() throws IOException {\n        createOutputFolder();\n        copyFile(TOO_MANY_INPUT_ZIP_FILE_PATH, TOO_MANY_INPUT_ZIP_FILE);\n    }\n\n    private void givenTooBigCompressedFile() throws IOException {\n        createOutputFolder();\n        copyFile(TOO_BIG_INPUT_ZIP_FILE_PATH, TOO_BIG_INPUT_ZIP_FILE);\n    }\n\n    private void givenIllegalPathCompressedFile() throws IOException {\n        createOutputFolder();\n        copyFile(ILLEGAL_PATH_INPUT_ZIP_FILE_PATH, ILLEGAL_PATH_INPUT_ZIP_FILE);\n    }\n\n    private void givenMultipleCompressedFile() throws IOException {\n        createOutputFolder();\n        copyFile(MULTIPLE_INPUT_ZIP_FILE_PATH, MULTIPLE_INPUT_ZIP_FILE);\n    }\n\n    private void givenUnCompressedFile() throws IOException {\n        createOutputFolder();\n        copyFile(UNCOMPRESSED_INPUT_ZIP_FILE_PATH, UNCOMPRESSED_INPUT_ZIP_FILE);\n    }\n\n    private void givenTarCompressedFile() throws IOException {\n        createOutputFolder();\n        copyFile(INPUT_TAR_FILE_PATH, INPUT_TAR_FILE);\n    }\n\n    private void createOutputFolder() {\n        File inputFolder = new File(WORK_FOLDER);\n        inputFolder.mkdirs();\n    }\n\n    private void copyFile(String inputFilePath, String inputFileName) throws IOException {\n        FileUtils.copyFile(new File(inputFilePath), new File(WORK_FOLDER + inputFileName));\n    }\n\n    private void whenFileIsUnzipped() throws IOException {\n        UnZip.unZipFile(WORK_FOLDER + SINGLE_INPUT_ZIP_FILE, WORK_FOLDER);\n    }\n\n    private void whenStreamIsUnzipped() throws IOException {\n        UnZip.unZipBytes(this.compressedInput, WORK_FOLDER);\n    }\n\n    private void whenTooManyFilesIsUnzipped() throws IOException {\n        this.exceptionCaught = false;\n        try {\n            UnZip.unZipFile(WORK_FOLDER + TOO_MANY_INPUT_ZIP_FILE, WORK_FOLDER);\n        } catch (IllegalStateException e) {\n            this.exceptionCaught = true;\n        }\n    }\n\n    private void whenTooBigFileIsUnzipped() throws IOException {\n        this.exceptionCaught = false;\n        try {\n            UnZip.unZipFile(WORK_FOLDER + TOO_BIG_INPUT_ZIP_FILE, WORK_FOLDER);\n        } catch (IllegalStateException e) {\n            this.exceptionCaught = true;\n        }\n    }\n\n    private void whenIllegalPathFileIsUnzipped() {\n        this.exceptionCaught = false;\n        try {\n            UnZip.unZipFile(WORK_FOLDER + ILLEGAL_PATH_INPUT_ZIP_FILE, WORK_FOLDER);\n        } catch (IOException e) {\n            this.exceptionCaught = true;\n        }\n    }\n\n    private void whenMultipleFileIsUnzipped() throws IOException {\n        UnZip.unZipFile(WORK_FOLDER + MULTIPLE_INPUT_ZIP_FILE, WORK_FOLDER);\n    }\n\n    private void whenUncompressedFileIsUnzipped() throws IOException {\n        UnZip.unZipFile(WORK_FOLDER + UNCOMPRESSED_INPUT_ZIP_FILE, WORK_FOLDER);\n    }\n\n    private void whenTarFileIsUnzipped() throws IOException {\n        UnZip.unZipFile(WORK_FOLDER + INPUT_TAR_FILE, WORK_FOLDER);\n    }\n\n    private void thenUncompressedFileExists() {\n        File uncompressedFile = new File(WORK_FOLDER + \"file.txt\");\n        assertTrue(uncompressedFile.exists());\n    }\n\n    private void thenUncompressedFileIsAFile() {\n        File uncompressedFile = new File(WORK_FOLDER + \"file.txt\");\n        assertTrue(!uncompressedFile.isDirectory());\n        assertTrue(uncompressedFile.isFile());\n    }\n\n    private void thenMultipleUncompressedFileExists() {\n        File uncompressedFile = new File(WORK_FOLDER + \"file.txt\");\n        File uncompressedFile1 = new File(WORK_FOLDER + \"file1.txt\");\n        assertTrue(uncompressedFile.exists());\n        assertTrue(uncompressedFile1.exists());\n    }\n\n    private void thenUncompressedFileIsCorrect() throws IOException {\n        File file = new File(WORK_FOLDER + \"file.txt\");\n        String content = FileUtils.readFileToString(file, \"UTF-8\");\n        assertEquals(\"This is an awesome text file!\\n\", content);\n    }\n\n    private void thenExceptionIsCaught() {\n        assertTrue(this.exceptionCaught);\n    }\n\n    private void thenUncompressedFileNotExist() {\n        File uncompressedFile = new File(WORK_FOLDER + \"file.txt\");\n        assertFalse(uncompressedFile.exists());\n    }\n\n    private static byte[] getFileBytes(File file) throws IOException {\n        try (ByteArrayOutputStream ous = new ByteArrayOutputStream(); InputStream ios = new FileInputStream(file)) {\n            byte[] buffer = new byte[4096];\n            int read = 0;\n            while ((read = ios.read(buffer)) != -1) {\n                ous.write(buffer, 0, read);\n            }\n            return ous.toByteArray();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.util.test/src/test/resources/uncompressedFile.txt",
    "content": "This is an awesome text file!\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.watchdog.criticaltest/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.watchdog.criticaltest\nBundle-SymbolicName: org.eclipse.kura.watchdog.criticaltest;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura;version=\"[1.0,2.0)\",\n org.eclipse.kura.cloud;version=\"[1.0,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.0,2.0)\",\n org.eclipse.kura.watchdog;version=\"[1.0,2.0)\",\n org.osgi.service.component;version=\"[1.0,2.0)\",\n org.slf4j;version=\"1.6.4\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.watchdog.criticaltest/OSGI-INF/component.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n  Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n  \n  This program and the accompanying materials are made\n  available under the terms of the Eclipse Public License 2.0\n  which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" deactivate=\"deactivate\"\n               name=\"FailingCriticalComponent\">\n    <implementation class=\"org.eclipse.kura.watchdog.criticaltest.FailingCriticalComponent\"/>\n    <property name=\"kura.service.pid\" value=\"FailingCriticalComponent\"/>\n    <reference name=\"WatchdogService\"\n               policy=\"static\"\n               cardinality=\"1..1\"\n               bind=\"bindWatchdogService\"\n               unbind=\"unbindWatchdogService\"\n               interface=\"org.eclipse.kura.watchdog.WatchdogService\" />\n</scr:component>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.watchdog.criticaltest/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.watchdog.criticaltest/build.properties",
    "content": "#\n#  Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.watchdog.criticaltest/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.watchdog.criticaltest</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.watchdog.criticaltest/src/main/java/org/eclipse/kura/watchdog/criticaltest/FailingCriticalComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n * \n * SPDX-License-Identifier: EPL-2.0\n * \n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.watchdog.criticaltest;\n\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.watchdog.CriticalComponent;\nimport org.eclipse.kura.watchdog.WatchdogService;\nimport org.osgi.service.component.ComponentContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Component that 'immediately' causes watchdog service to reboot the system, if it is enabled. It is registered as a\n * critical component and never checks in.\n */\npublic class FailingCriticalComponent implements ConfigurableComponent, CriticalComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(FailingCriticalComponent.class);\n\n    private String pid;\n\n    private int timeout = 30000;\n\n    private WatchdogService watchdogService;\n\n    protected void activate(ComponentContext componentContext, Map<String, Object> properties) {\n        this.pid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);\n        logger.info(\"Activating {} and registering with watchdog service...\", this.pid);\n\n        this.watchdogService.registerCriticalComponent(this);\n\n        logger.info(\"Activated {}...\", this.pid);\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n        logger.info(\"Deactivating {}...\", this.pid);\n\n        this.watchdogService.unregisterCriticalComponent(this);\n\n        logger.info(\"Deactivated {}...\", this.pid);\n    }\n\n    @Override\n    public String getCriticalComponentName() {\n        return this.pid;\n    }\n\n    @Override\n    public int getCriticalComponentTimeout() {\n        return this.timeout;\n    }\n\n    public void bindWatchdogService(WatchdogService watchdogService) {\n        this.watchdogService = watchdogService;\n    }\n\n    public void unbindWatchdogService(WatchdogService watchdogService) {\n        this.watchdogService = null;\n    }\n}\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.xml.marshaller.unmarshaller.provider.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Wire Provider Test\nBundle-SymbolicName: org.eclipse.kura.xml.marshaller.unmarshaller.provider.test\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nBundle-License: Eclipse Public License v2.0\nFragment-Host: org.eclipse.kura.xml.marshaller.unmarshaller.provider;bundle-version=\"[2.0,3.0)\"\nBundle-ActivationPolicy: lazy\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: org.eclipse.kura;version=\"[1.4,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.core.configuration.util;version=\"[2.0,3.0)\",\n org.eclipse.kura.core.inventory.resources;version=\"[1.0,2.0)\",\n org.eclipse.kura.core.testutil;version=\"[1.0,2.0)\",\n org.eclipse.kura.internal.xml.marshaller.unmarshaller;version=\"[1.0,2.0)\",\n org.eclipse.kura.test.annotation;version=\"[1.0,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners;version=\"[4.12.0,5.0.0)\",\n org.mockito;version=\"5.0.0\";resolution:=optional,\n org.mockito.invocation;version=\"5.0.0\";resolution:=optional,\n org.mockito.stubbing;version=\"5.0.0\";resolution:=optional,\n org.slf4j;version=\"1.7.21\"\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.xml.marshaller.unmarshaller.provider.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test/org.eclipse.kura.xml.marshaller.unmarshaller.provider.test/build.properties",
    "content": "#\n#  Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nbin.includes = .,\\\n               META-INF/,\\\n               about.html\nadditional.bundles = org.eclipse.kura.api,\\\n                     slf4j.api\n\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.xml.marshaller.unmarshaller.provider.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n\tSPDX-License-Identifier: EPL-2.0\n\t\n\tContributors:\n\t Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.xml.marshaller.unmarshaller.provider.test</artifactId>\n    <packaging>eclipse-test-plugin</packaging>\n\n    <properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test/org.eclipse.kura.xml.marshaller.unmarshaller.provider.test/src/test/java/org/eclipse/kura/internal/xml/marshaller/unmarshaller/test/XmlEncoderDecoderTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.internal.xml.marshaller.unmarshaller.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.Password;\nimport org.eclipse.kura.core.configuration.ComponentConfigurationImpl;\nimport org.eclipse.kura.core.configuration.XmlComponentConfigurations;\nimport org.eclipse.kura.core.configuration.XmlSnapshotIdResult;\nimport org.eclipse.kura.core.configuration.metatype.Tad;\nimport org.eclipse.kura.core.configuration.metatype.Tocd;\nimport org.eclipse.kura.core.configuration.metatype.Tscalar;\nimport org.eclipse.kura.core.configuration.util.ComponentUtil;\nimport org.eclipse.kura.core.inventory.resources.SystemBundle;\nimport org.eclipse.kura.core.inventory.resources.SystemBundles;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackage;\nimport org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages;\nimport org.eclipse.kura.internal.xml.marshaller.unmarshaller.XmlMarshallUnmarshallImpl;\nimport org.junit.Ignore;\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class XmlEncoderDecoderTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(XmlEncoderDecoderTest.class);\n\n    private static final String stringWriter = \"String Writer\";\n    private static final String string = \"String\";\n    private static final String pid = \"Pid\";\n    private static final String hashmapValues = \"Hashmap values\";\n    private static final String differentInstanceMessage = \"Unmarshalled Object from String is not of type %s, but was %s\";\n    private static final String missingItemsMessage = \"Unmarshalled object does not contain all the value from the marshalled object. Missing value : %s ;\";\n    private static final String propertyValueDiffersMessage = \"Property value  %s of unmarshalled object from %s differs from original. Orignal : %s ; Received : %s ;\";\n\n    @Test\n    public void testXmlComponentConfigurationsUnmarshalling() {\n\n        try {\n\n            XmlMarshallUnmarshallImpl xmlMarshallerImpl = new XmlMarshallUnmarshallImpl();\n            XmlComponentConfigurations xmlComponentConfigurations = getSampleXmlComponentConfigurationsObject();\n\n            // test String unmarshalling\n            String marshalledString = xmlMarshallerImpl.marshal(xmlComponentConfigurations);\n            Object unmarshalledObjectFromString = xmlMarshallerImpl.unmarshal(marshalledString,\n                    XmlComponentConfigurations.class);\n            assertTrue(\n                    String.format(differentInstanceMessage, XmlComponentConfigurations.class,\n                            unmarshalledObjectFromString.getClass()),\n                    unmarshalledObjectFromString instanceof XmlComponentConfigurations);\n\n            XmlComponentConfigurations outputXmlComponentConfigurations = (XmlComponentConfigurations) unmarshalledObjectFromString;\n\n            assertValuesForEquality(pid, xmlComponentConfigurations.getConfigurations().get(0).getPid(),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getPid(), false);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"int\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"int\"),\n                    false);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"long\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"long\"),\n                    false);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"string\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"string\"),\n                    false);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"boolean\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"boolean\"),\n                    false);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"double\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"double\"),\n                    false);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"float\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"float\"),\n                    false);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"char\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"char\"),\n                    false);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"short\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"short\"),\n                    false);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"byte\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"byte\"),\n                    false);\n\n            // test Reader unmarshalling\n            Object unmarshalledObjectFromStringReader = xmlMarshallerImpl.unmarshal(marshalledString,\n                    XmlComponentConfigurations.class);\n            assertTrue(\n                    String.format(differentInstanceMessage, XmlComponentConfigurations.class,\n                            unmarshalledObjectFromStringReader.getClass()),\n                    unmarshalledObjectFromStringReader instanceof XmlComponentConfigurations);\n\n            outputXmlComponentConfigurations = (XmlComponentConfigurations) unmarshalledObjectFromStringReader;\n\n            assertValuesForEquality(pid, xmlComponentConfigurations.getConfigurations().get(0).getPid(),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getPid(), true);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"int\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"int\"),\n                    true);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"long\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"long\"),\n                    true);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"string\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"string\"),\n                    true);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"boolean\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"boolean\"),\n                    true);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"double\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"double\"),\n                    true);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"float\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"float\"),\n                    true);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"char\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"char\"),\n                    true);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"short\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"short\"),\n                    true);\n            assertValuesForEquality(hashmapValues,\n                    xmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties().get(\"byte\"),\n                    outputXmlComponentConfigurations.getConfigurations().get(0).getConfigurationProperties()\n                            .get(\"byte\"),\n                    true);\n\n        } catch (Exception e) {\n\n            e.printStackTrace();\n            fail(e.getMessage());\n        }\n\n    }\n\n    @Test\n    public void testXmlSnapshotIdResultMarshalling() {\n\n        XmlMarshallUnmarshallImpl xmlMarshallerImpl = new XmlMarshallUnmarshallImpl();\n        try {\n            XmlSnapshotIdResult xmlSnapshotIdResult = getSampleXmlSnapshotIdResultObject();\n            String marshalledString = xmlMarshallerImpl.marshal(xmlSnapshotIdResult);\n\n            for (Long value : xmlSnapshotIdResult.getSnapshotIds()) {\n                assertTrue(String.format(missingItemsMessage, value), marshalledString.contains(Long.toString(value)));\n            }\n\n        } catch (Exception e) {\n\n            e.printStackTrace();\n            fail(e.getMessage());\n        }\n\n    }\n\n    @Test\n    public void testXmlDeploymentPackagesMarshalling() {\n        XmlMarshallUnmarshallImpl xmlMarshallerImpl = new XmlMarshallUnmarshallImpl();\n        try {\n\n            SystemDeploymentPackages xmlDeploymentPackages = getSampleXmlDeploymentPackagesObject();\n            String marshalledString = xmlMarshallerImpl.marshal(xmlDeploymentPackages);\n            assertTrue(String.format(missingItemsMessage, xmlDeploymentPackages.getDeploymentPackages()[0].getName()),\n                    marshalledString.contains(xmlDeploymentPackages.getDeploymentPackages()[0].getName()));\n            assertTrue(\n                    String.format(missingItemsMessage, xmlDeploymentPackages.getDeploymentPackages()[0].getVersion()),\n                    marshalledString.contains(xmlDeploymentPackages.getDeploymentPackages()[0].getVersion()));\n            assertTrue(\n                    String.format(missingItemsMessage,\n                            xmlDeploymentPackages.getDeploymentPackages()[0].getBundleInfos()[0].getName()),\n                    marshalledString\n                            .contains(xmlDeploymentPackages.getDeploymentPackages()[0].getBundleInfos()[0].getName()));\n            assertTrue(\n                    String.format(missingItemsMessage,\n                            xmlDeploymentPackages.getDeploymentPackages()[0].getBundleInfos()[0].getVersion()),\n                    marshalledString.contains(\n                            xmlDeploymentPackages.getDeploymentPackages()[0].getBundleInfos()[0].getVersion()));\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(e.getMessage());\n        }\n    }\n\n    @Test\n    public void testXmlBundlesMarshalling() {\n        XmlMarshallUnmarshallImpl xmlMarshallerImpl = new XmlMarshallUnmarshallImpl();\n        try {\n\n            SystemBundles xmlBundles = getSampleBundlesObject();\n            String marshalledString = xmlMarshallerImpl.marshal(xmlBundles);\n            assertTrue(String.format(missingItemsMessage, xmlBundles.getBundles()[0].getId()),\n                    marshalledString.contains(Long.toString(xmlBundles.getBundles()[0].getId())));\n            assertTrue(String.format(missingItemsMessage, xmlBundles.getBundles()[0].getName()),\n                    marshalledString.contains(xmlBundles.getBundles()[0].getName()));\n            assertTrue(String.format(missingItemsMessage, xmlBundles.getBundles()[0].getState()),\n                    marshalledString.contains(xmlBundles.getBundles()[0].getState()));\n            assertTrue(String.format(missingItemsMessage, xmlBundles.getBundles()[0].getVersion()),\n                    marshalledString.contains(xmlBundles.getBundles()[0].getVersion()));\n\n        } catch (Exception e) {\n            e.printStackTrace();\n            fail(e.getMessage());\n        }\n    }\n\n    private static SystemBundles getSampleBundlesObject() {\n\n        SystemBundles xmlBundles = new SystemBundles();\n\n        SystemBundle inputXmlBundle = new SystemBundle(\"raspberry\", \"3.0.1\");\n        inputXmlBundle.setId(1);\n        inputXmlBundle.setState(\"New York\");\n        xmlBundles.setBundles(new SystemBundle[] { inputXmlBundle });\n\n        return xmlBundles;\n    }\n\n    private static SystemDeploymentPackages getSampleXmlDeploymentPackagesObject() {\n\n        SystemDeploymentPackages xmlDeploymentPackages = new SystemDeploymentPackages();\n        SystemBundle inputXmlBundleInfo = new SystemBundle(\"XmlBundleInfo\", \"3.0.1.201\");\n\n        SystemDeploymentPackage inputXmlDeploymentPackage = new SystemDeploymentPackage(\"raspberry\", \"3.0.1\");\n        inputXmlDeploymentPackage.setBundleInfos(new SystemBundle[] { inputXmlBundleInfo });\n\n        xmlDeploymentPackages.setDeploymentPackages(new SystemDeploymentPackage[] { inputXmlDeploymentPackage });\n\n        return xmlDeploymentPackages;\n\n    }\n\n    private static Tocd getSampleTocdObject() {\n\n        Tad tad = new Tad();\n        tad.setCardinality(1);\n        tad.setDefault(\"default\");\n        tad.setDescription(\"This is a sample description for tad\");\n        tad.setId(\"1\");\n        tad.setMax(\"10\");\n        tad.setMin(\"1\");\n        tad.setName(\"Tad\");\n        tad.setRequired(true);\n        tad.setType(Tscalar.PASSWORD);\n\n        Tocd tocd = new Tocd();\n        tocd.setId(\"1\");\n        tocd.setName(\"Tocd\");\n        tocd.setDescription(\"This is a sample description for Tocd\");\n        tocd.addAD(tad);\n\n        return tocd;\n    }\n\n    private static XmlSnapshotIdResult getSampleXmlSnapshotIdResultObject() {\n\n        List<Long> snapshotIds = new ArrayList<>();\n        snapshotIds.add(102540L);\n        snapshotIds.add(27848415L);\n        snapshotIds.add(378485484848L);\n\n        XmlSnapshotIdResult xmlSnapshotIdResult = new XmlSnapshotIdResult();\n        xmlSnapshotIdResult.setSnapshotIds(snapshotIds);\n\n        return xmlSnapshotIdResult;\n    }\n\n    private static XmlComponentConfigurations getSampleXmlComponentConfigurationsObject() {\n\n        Map<String, Object> sampleMap = new HashMap<>();\n\n        sampleMap.put(\"int\", 1);\n        sampleMap.put(\"long\", 2L);\n        sampleMap.put(\"string\", \"StringValue\");\n        sampleMap.put(\"boolean\", true);\n        sampleMap.put(\"double\", 2.2d);\n        sampleMap.put(\"float\", 2.3f);\n        sampleMap.put(\"char\", 'a');\n        sampleMap.put(\"short\", (short) 1);\n        sampleMap.put(\"byte\", (byte) 90);\n        new Password(\"password\".toCharArray());\n\n        ComponentConfigurationImpl componentConfigurationImpl = new ComponentConfigurationImpl();\n        componentConfigurationImpl.setPid(\"8236\");\n        componentConfigurationImpl.setDefinition(getSampleTocdObject());\n        componentConfigurationImpl.setProperties(sampleMap);\n\n        XmlComponentConfigurations xmlComponentConfigurations = new XmlComponentConfigurations();\n        List<ComponentConfiguration> configs = new ArrayList<>();\n        configs.add(componentConfigurationImpl);\n        xmlComponentConfigurations.setConfigurations(configs);\n\n        return xmlComponentConfigurations;\n    }\n\n    private static void assertValuesForEquality(String name, Object orignal, Object unmarshalled,\n            boolean isStringWriter) {\n        String source = isStringWriter ? stringWriter : string;\n\n        assertTrue(String.format(propertyValueDiffersMessage, name, source, orignal, unmarshalled),\n                orignal.equals(unmarshalled));\n    }\n\n    @Test\n    public void testPropertiesMarshallUnmarshall() throws Exception {\n        XmlMarshallUnmarshallImpl xmlMarshallerImpl = new XmlMarshallUnmarshallImpl();\n\n        String pid = \"org.eclipse.kura.cloud.CloudService\";\n        Tocd definition = null;\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"prop.string\", new String(\"prop.value\"));\n        properties.put(\"prop.long\", Long.MAX_VALUE);\n        properties.put(\"prop.double\", Double.MAX_VALUE);\n        properties.put(\"prop.float\", Float.MAX_VALUE);\n        properties.put(\"prop.integer\", Integer.MAX_VALUE);\n        properties.put(\"prop.byte\", Byte.MAX_VALUE);\n        properties.put(\"prop.character\", 'a');\n        properties.put(\"prop.short\", Short.MAX_VALUE);\n\n        XmlComponentConfigurations xcc = new XmlComponentConfigurations();\n        List<ComponentConfiguration> ccis = new ArrayList<>();\n        ComponentConfigurationImpl config = new ComponentConfigurationImpl(pid, definition, properties);\n        ccis.add(config);\n        xcc.setConfigurations(ccis);\n\n        String s = xmlMarshallerImpl.marshal(xcc);\n        logger.info(s);\n\n        XmlComponentConfigurations config1 = xmlMarshallerImpl.unmarshal(s, XmlComponentConfigurations.class);\n        String s1 = xmlMarshallerImpl.marshal(config1);\n        logger.info(s1);\n\n        Map<String, Object> properties1 = config1.getConfigurations().get(0).getConfigurationProperties();\n        assertEquals(properties, properties1);\n    }\n\n    @Test\n    @Ignore\n    public void testOCDMarshallUnmarshall() throws Exception { // This test needs to be done as integration test not\n                                                               // unit.\n        XmlMarshallUnmarshallImpl xmlMarshallerImpl = new XmlMarshallUnmarshallImpl();\n\n        String pid = \"org.eclipse.kura.cloud.CloudService\";\n\n        Tocd definition = ComponentUtil.readObjectClassDefinition(pid);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"prop.string\", new String(\"prop.value\"));\n        properties.put(\"prop.long\", Long.MAX_VALUE);\n        properties.put(\"prop.double\", Double.MAX_VALUE);\n        properties.put(\"prop.float\", Float.MAX_VALUE);\n        properties.put(\"prop.integer\", Integer.MAX_VALUE);\n        properties.put(\"prop.byte\", Byte.MAX_VALUE);\n        properties.put(\"prop.character\", 'a');\n        properties.put(\"prop.short\", Short.MAX_VALUE);\n\n        XmlComponentConfigurations xcc = new XmlComponentConfigurations();\n        List<ComponentConfiguration> ccis = new ArrayList<>();\n        ComponentConfigurationImpl config = new ComponentConfigurationImpl(pid, definition, properties);\n        ccis.add(config);\n        xcc.setConfigurations(ccis);\n\n        String s = xmlMarshallerImpl.marshal(xcc);\n        logger.info(s);\n\n        XmlComponentConfigurations config1 = xmlMarshallerImpl.unmarshal(s, XmlComponentConfigurations.class);\n        String s1 = xmlMarshallerImpl.marshal(config1);\n        logger.info(s1);\n\n        Map<String, Object> properties1 = config1.getConfigurations().get(0).getConfigurationProperties();\n        assertEquals(properties, properties1);\n    }\n    \n    @Test\n    public void testPropertiesMarshallUnmarshallWithStream() throws Exception {\n        XmlMarshallUnmarshallImpl xmlMarshallerImpl = new XmlMarshallUnmarshallImpl();\n\n        String pid = \"org.eclipse.kura.cloud.CloudService\";\n        Tocd definition = null;\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"prop.string\", new String(\"prop.value\"));\n        properties.put(\"prop.long\", Long.MAX_VALUE);\n        properties.put(\"prop.double\", Double.MAX_VALUE);\n        properties.put(\"prop.float\", Float.MAX_VALUE);\n        properties.put(\"prop.integer\", Integer.MAX_VALUE);\n        properties.put(\"prop.byte\", Byte.MAX_VALUE);\n        properties.put(\"prop.character\", 'a');\n        properties.put(\"prop.short\", Short.MAX_VALUE);\n\n        XmlComponentConfigurations xcc = new XmlComponentConfigurations();\n        List<ComponentConfiguration> ccis = new ArrayList<>();\n        ComponentConfigurationImpl config = new ComponentConfigurationImpl(pid, definition, properties);\n        ccis.add(config);\n        xcc.setConfigurations(ccis);\n\n        String s = xmlMarshallerImpl.marshal(xcc);\n        logger.info(s);\n\n        XmlComponentConfigurations config1 = xmlMarshallerImpl.unmarshal(s, XmlComponentConfigurations.class);\n        String s1 = xmlMarshallerImpl.marshal(config1);\n        logger.info(s1);\n\n        Map<String, Object> properties1 = config1.getConfigurations().get(0).getConfigurationProperties();\n        assertEquals(properties, properties1);\n    }\n\n    @Test\n    @Ignore\n    public void testOCDMarshallUnmarshallWithStream() throws Exception { // This test needs to be done as integration test not\n                                                               // unit.\n        XmlMarshallUnmarshallImpl xmlMarshallerImpl = new XmlMarshallUnmarshallImpl();\n\n        String pid = \"org.eclipse.kura.cloud.CloudService\";\n\n        Tocd definition = ComponentUtil.readObjectClassDefinition(pid);\n\n        Map<String, Object> properties = new HashMap<>();\n        properties.put(\"prop.string\", new String(\"prop.value\"));\n        properties.put(\"prop.long\", Long.MAX_VALUE);\n        properties.put(\"prop.double\", Double.MAX_VALUE);\n        properties.put(\"prop.float\", Float.MAX_VALUE);\n        properties.put(\"prop.integer\", Integer.MAX_VALUE);\n        properties.put(\"prop.byte\", Byte.MAX_VALUE);\n        properties.put(\"prop.character\", 'a');\n        properties.put(\"prop.short\", Short.MAX_VALUE);\n\n        XmlComponentConfigurations xcc = new XmlComponentConfigurations();\n        List<ComponentConfiguration> ccis = new ArrayList<>();\n        ComponentConfigurationImpl config = new ComponentConfigurationImpl(pid, definition, properties);\n        ccis.add(config);\n        xcc.setConfigurations(ccis);\n\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        xmlMarshallerImpl.marshal(out, xcc);\n        String marshalString = out.toString();\n        logger.info(marshalString);\n\n        ByteArrayInputStream in = new ByteArrayInputStream(marshalString.getBytes(StandardCharsets.UTF_8));\n        XmlComponentConfigurations config1 = xmlMarshallerImpl.unmarshal(in, XmlComponentConfigurations.class);\n        String s1 = xmlMarshallerImpl.marshal(config1);\n        logger.info(s1);\n\n        Map<String, Object> properties1 = config1.getConfigurations().get(0).getConfigurationProperties();\n        assertEquals(properties, properties1);\n    }\n}\n"
  },
  {
    "path": "kura/test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2016, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>test</artifactId>\n    <packaging>pom</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/..</kura.basedir>\n        <mockito.version>5.21.0</mockito.version>\n        <tycho.surefire.testenv.args>\n            -DbuildingWithTycho=true\n            -Dosgi.locking=none\n            -Dds.showtrace=true\n            -Djava.io.tmpdir=/tmp\n            -Dosgi.configuration.area=${project.basedir}/target/osgi/framework_storage\n            -Dosgi.clean=true\n            -Dkura.home=${project.basedir}/target/kura\n            -Dkura.plugins=${project.basedir}/target/kura/plugins\n            -Dkura.packages=${project.basedir}/target/kura/data/packages\n            -Dkura.data=${project.basedir}/target/kura\n            -Dkura.tmp=${project.basedir}/target/kura/tmp\n            -Dkura.snapshots=${project.basedir}/target/kura/user/snapshots\n            -Dkura.configuration=file:${kura.basedir}/emulator/org.eclipse.kura.emulator/src/main/resources/kura.properties\n            -Dlog4j.configurationFile=file:${kura.basedir}/emulator/org.eclipse.kura.emulator/src/main/resources/log4j.xml\n            -Dorg.eclipse.kura.mode=emulator\n            -Ddpa.configuration=/tmp/kura/dpa.properties\n            -Dosgi.console=5002\n            --add-opens java.base/java.lang=ALL-UNNAMED\n            --add-opens=java.base/java.util=ALL-UNNAMED\n        </tycho.surefire.testenv.args>\n    </properties>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.mockito</groupId>\n                <artifactId>mockito-core</artifactId>\n                <version>${mockito.version}</version>\n                <scope>test</scope>\n            </dependency>\n            <dependency>\n                <groupId>junit</groupId>\n                <artifactId>junit</artifactId>\n                <version>4.13.2</version>\n                <scope>test</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-core</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n    <profiles>\n        <profile>\n            <id>test-debug</id>\n            <build>\n                <pluginManagement>\n                    <plugins>\n                        <plugin>\n                            <groupId>org.eclipse.tycho</groupId>\n                            <artifactId>tycho-surefire-plugin</artifactId>\n                            <configuration>\n                                <debugPort>8000</debugPort>\n                            </configuration>\n                        </plugin>\n                    </plugins>\n                </pluginManagement>\n            </build>\n        </profile>\n    </profiles>\n\n    <build>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-compiler-plugin</artifactId>\n                    <version>${maven-compiler-plugin.version}</version>\n                    <configuration>\n                        <source>${maven.compiler.source}</source>\n                        <target>${maven.compiler.target}</target>\n                        <release>${maven.compiler.release}</release>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-resources-plugin</artifactId>\n                    <version>3.3.1</version>\n                    <executions>\n                        <!--\n                            copy the OSGI-INF directory to a place where it is being detected and\n                            picked up by PDE Launcher as well, supported by M2E in incremental builds\n                            natively\n                        -->\n                        <execution>\n                            <id>prepare-tycho-runtime</id>\n                            <phase>prepare-package</phase>\n                            <goals>\n                                <goal>copy-resources</goal>\n                            </goals>\n                            <configuration>\n                                <outputDirectory>${basedir}/OSGI-INF</outputDirectory>\n                                <resources>\n                                    <resource>\n                                        <directory>${project.build.outputDirectory}/OSGI-INF</directory>\n                                        <filtering>false</filtering>\n                                    </resource>\n                                </resources>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>org.jacoco</groupId>\n                    <artifactId>jacoco-maven-plugin</artifactId>\n                    <version>${jacoco.version}</version>\n                    <configuration>\n                        <append>true</append>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>prepare-agent</goal>\n                            </goals>\n                        </execution>\n                        <execution>\n                            <id>report</id>\n                            <goals>\n                                <goal>report-aggregate</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <artifactId>maven-surefire-plugin</artifactId>\n                    <version>${maven-surefire-plugin.version}</version>\n                    <executions>\n                        <execution>\n                            <id>default-test</id>\n                            <phase>test</phase>\n                            <goals>\n                                <goal>test</goal>\n                            </goals>\n                            <configuration>\n                                <argLine>\n                                    ${tycho.testArgLine}\n                                    -javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar\n                                </argLine>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>tycho-surefire-plugin</artifactId>\n                    <version>${tycho-version}</version>\n                    <configuration>\n                        <failIfNoTests>false</failIfNoTests>\n                        <providerHint>junit4</providerHint>\n                        <useUnlimitedThreads>false</useUnlimitedThreads>\n                        <argLine>\n                            ${tycho.testArgLine}\n                            ${tycho.surefire.testenv.args}\n                            -Dmoquette.path=${project.basedir}/src/main/resources/moquette/config\n                            -javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar\n                        </argLine>\n                        <!-- <appArgLine>-consoleLog -console 5002 -noExit</appArgLine> --> \n                        <dependencies>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>moquette-broker</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.apache.felix.scr</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.equinox.console</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.equinox.io</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.equinox.cm</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.equinox.common</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.equinox.event</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.equinox.metatype</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.equinox.registry</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.equinox.util</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.osgi</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.osgi.util</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.hamcrest.core</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>slf4j.api</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.junit</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.apache.commons.commons-io</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.apache.logging.log4j.api</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.kura.core</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.kura.core.identity</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.kura.core.system</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>com.h2database</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.kura.core.keystore</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.apache.felix.dependencymanager</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.apache.felix.deploymentadmin</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.kura.emulator.position</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.apache.logging.log4j.slf4j2.impl</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.apache.logging.log4j.core</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.kura.db.h2db.provider</artifactId>\n                            </dependency>\n                            <dependency>\n                                <type>p2-installable-unit</type>\n                                <artifactId>org.eclipse.kura.cloud.base.provider</artifactId>\n                            </dependency>\n                        </dependencies>\n                        <bundleStartLevel>\n                            <bundle>\n                                <id>org.apache.aries.spifly.dynamic.bundle</id>\n                                <level>2</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.logging.log4j.slf4j2.impl</id>\n                                <level>2</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>moquette-broker</id>\n                                <level>3</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.felix.scr</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.equinox.io</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.equinox.cm</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.equinox.common</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.equinox.event</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.equinox.metatype</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.equinox.registry</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.equinox.console</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.equinox.util</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.osgi.util</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.hamcrest.core</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>slf4j.api</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>log4j2-api-config</id>\n                                <level>4</level>\n                                <autoStart>false</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.logging.log4j.api</id>\n                                <level>1</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.logging.log4j.core</id>\n                                <level>1</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>mqtt-client</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>com.h2database</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.junit</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.commons.io</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.api</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.core.configuration</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.core.crypto</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.json.marshaller.unmarshaller.provider</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.xml.marshaller.unmarshaller.provider</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>com.sun.xml.bind.jaxb-osgi</id>\n                                <level>1</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.glassfish.hk2.osgi-resource-locator</id>\n                                <level>1</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.camel.camel-core</id>\n                                <autoStart>true</autoStart>\n                                <level>2</level>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.camel</id>\n                                <autoStart>true</autoStart>\n                                <level>3</level>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.core.status</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.core.identity</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.emulator</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.emulator.net</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.emulator.gpio</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.emulator.watchdog</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.emulator.usb</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.http.server.manager</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.felix.useradmin</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.useradmin.store</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.rest.provider</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.felix.dependencymanager</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.felix.deploymentadmin</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.emulator.position</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.cloud.base.provider</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.kura.cloudconnection.kapua.mqtt.provider</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.apache.felix.http.bridge</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.osgitech.rest</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>org.eclipse.osgitech.rest.servlet.whiteboard</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                            <bundle>\n                                <id>jersey-client</id>\n                                <level>4</level>\n                                <autoStart>true</autoStart>\n                            </bundle>\n                        </bundleStartLevel>\n                    </configuration>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.tycho</groupId>\n                    <artifactId>target-platform-configuration</artifactId>\n                    <version>${tycho-version}</version>\n                    <configuration>\n                        <dependency-resolution>\n                            <extraRequirements>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.hamcrest</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>p2-installable-unit</type>\n                                    <id>org.apache.logging.log4j.api</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>p2-installable-unit</type>\n                                    <id>org.apache.logging.log4j.core</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>log4j2-api-config</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>p2-installable-unit</type>\n                                    <id>org.apache.logging.log4j.slf4j2.impl</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>p2-installable-unit</type>\n                                    <id>jakarta.xml.bind-api</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>p2-installable-unit</type>\n                                    <id>jakarta.activation-api</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>p2-installable-unit</type>\n                                    <id>com.sun.xml.bind.jaxb-osgi</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>p2-installable-unit</type>\n                                    <id>org.glassfish.hk2.osgi-resource-locator</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.equinox.cm</id>\n                                    <versionRange>1</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.api</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.emulator</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.emulator.net</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.emulator.watchdog</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.emulator.gpio</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.core.cloud.factory</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.core.comm</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.xml.marshaller.unmarshaller.provider</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.json.marshaller.unmarshaller.provider</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.core</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.core.system</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.core.configuration</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.core.identity</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.core.crypto</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.core.status</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.rest.provider</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.apache.felix.useradmin</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.useradmin.store</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.apache.felix.useradmin</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.core.keystore</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.emulator.position</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.db.h2db.provider</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.cloudconnection.kapua.mqtt.provider</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                                <requirement>\n                                    <type>eclipse-plugin</type>\n                                    <id>org.eclipse.kura.cloud.base.provider</id>\n                                    <versionRange>0.0.0</versionRange>\n                                </requirement>\n                            </extraRequirements>\n                        </dependency-resolution>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-deploy-plugin</artifactId>\n                <version>${maven-deploy-plugin.version}</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <modules>\n        <module>org.eclipse.kura.cloud.base.provider.test</module>\n        <module>org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test</module>\n        <module>org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test</module>\n        <module>org.eclipse.kura.configuration.change.manager.test</module>\n        <module>org.eclipse.kura.container.orchestration.provider.test</module>\n        <module>org.eclipse.kura.container.provider.test</module>\n        <module>org.eclipse.kura.core.certificates.test</module>\n        <module>org.eclipse.kura.core.cloud.factory.test</module>\n        <module>org.eclipse.kura.core.comm.test</module>\n        <module>org.eclipse.kura.core.configuration.test</module>\n        <module>org.eclipse.kura.core.crypto.test</module>\n        <module>org.eclipse.kura.core.identity.test</module>\n        <module>org.eclipse.kura.core.inventory.test</module>\n        <module>org.eclipse.kura.core.keystore.test</module>\n        <module>org.eclipse.kura.core.ssl.test</module>\n        <module>org.eclipse.kura.core.status.test</module>\n        <module>org.eclipse.kura.core.system.test</module>\n        <module>org.eclipse.kura.core.test</module>\n        <module>org.eclipse.kura.core.util.test</module>\n        <module>org.eclipse.kura.db.h2db.provider.test</module>\n        <module>org.eclipse.kura.db.sqlite.provider.test</module>\n        <module>org.eclipse.kura.driver.block.test</module>\n        <module>org.eclipse.kura.driver.helper.test</module>\n        <!-- <module>org.eclipse.kura.emulator.position.test</module> -->\n        <module>org.eclipse.kura.emulator.watchdog.test</module>\n        <module>org.eclipse.kura.event.publisher.test</module>\n        <module>org.eclipse.kura.http.server.manager.test</module>\n        <module>org.eclipse.kura.internal.driver.s7plc.test</module>\n        <module>org.eclipse.kura.json.marshaller.unmarshaller.provider.test</module>\n        <module>org.eclipse.kura.linux.clock.test</module>\n        <module>org.eclipse.kura.linux.usb.test</module>\n        <module>org.eclipse.kura.linux.watchdog.test</module>\n        <module>org.eclipse.kura.log.filesystem.provider.test</module>\n        <module>org.eclipse.kura.message.store.provider.test</module>\n        <module>org.eclipse.kura.protocol.modbus.test</module>\n        <module>org.eclipse.kura.rest.cloudconnection.provider.test</module>\n        <module>org.eclipse.kura.rest.configuration.provider.test</module>\n        <module>org.eclipse.kura.rest.identity.provider.test</module>\n        <module>org.eclipse.kura.rest.inventory.provider.test</module>\n        <module>org.eclipse.kura.rest.keystore.provider.test</module>\n        <module>org.eclipse.kura.rest.provider.test</module>\n        <module>org.eclipse.kura.rest.security.provider.test</module>\n        <module>org.eclipse.kura.rest.service.listing.provider.test</module>\n        <module>org.eclipse.kura.rest.system.provider.test</module>\n        <module>org.eclipse.kura.rest.tamper.detection.provider.test</module>\n        <module>org.eclipse.kura.stress.test</module>\n        <module>org.eclipse.kura.useradmin.store.test</module>\n        <module>org.eclipse.kura.util.test</module>\n        <module>org.eclipse.kura.watchdog.criticaltest</module>\n        <module>org.eclipse.kura.xml.marshaller.unmarshaller.provider.test</module>\n    </modules>\n</project>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.core.testutil\nBundle-SymbolicName: org.eclipse.kura.core.testutil;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nImport-Package: com.eclipsesource.json;version=\"0.9.5\",\n jakarta.servlet;version=\"5.0.0\",\n jakarta.servlet.http;version=\"5.0.0\",\n javax.servlet;version=\"3.1.0\",\n javax.servlet.http;version=\"3.1.0\",\n junit.framework;version=\"4.12.0\",\n org.apache.commons.io;version=\"2.4.0\",\n org.bouncycastle.asn1;version=\"1.78.1\",\n org.bouncycastle.asn1.x500;version=\"1.78.1\",\n org.bouncycastle.asn1.x509;version=\"1.78.1\",\n org.bouncycastle.cert;version=\"1.78.1\",\n org.bouncycastle.cert.bc;version=\"1.78.1\",\n org.bouncycastle.cert.jcajce;version=\"1.78.1\",\n org.bouncycastle.jce.provider;version=\"1.78.1\",\n org.bouncycastle.openssl;version=\"1.78.1\",\n org.bouncycastle.openssl.jcajce;version=\"1.78.1\",\n org.bouncycastle.operator;version=\"1.78.1\",\n org.bouncycastle.operator.jcajce;version=\"1.78.1\",\n org.bouncycastle.x509.extension;version=\"1.78.1\",\n org.eclipse.jetty.ee10.servlet;version=\"[12.0.0,13.0.0)\",\n org.eclipse.jetty.server;version=\"[12.0.0,13.0.0)\",\n org.eclipse.jetty.util;version=\"[12.0.0,13.0.0)\",\n org.eclipse.jetty.util.component;version=\"[12.0.0,13.0.0)\",\n org.eclipse.kura;version=\"[1.6,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.2,2.0)\",\n org.eclipse.kura.core.data.util;version=\"[1.0,2.0)\",\n org.eclipse.kura.crypto;version=\"[1.3,2.0)\",\n org.eclipse.kura.data;version=\"[1.1,2.0)\",\n org.eclipse.kura.data.transport.listener;version=\"[1.0,2.0)\",\n org.eclipse.kura.marshalling;version=\"[1.0,2.0)\",\n org.eclipse.kura.message;version=\"[1.4,2.0)\",\n org.junit;version=\"[4.12.0,5.0.0)\",\n org.junit.rules;version=\"4.12.0\",\n org.junit.runner;version=\"[4.12.0,5.0.0)\",\n org.junit.runners.model;version=\"4.12.0\",\n org.osgi.framework;version=\"1.10.0\",\n org.osgi.service.event;version=\"1.4.0\",\n org.osgi.util.tracker;version=\"1.5.2\",\n org.slf4j;version=\"1.6.4\"\nBundle-ActivationPolicy: lazy\nComment: Unit testing utilities\nExport-Package: org.eclipse.kura.core.testutil;version=\"1.0.0\",\n org.eclipse.kura.core.testutil.event;version=\"1.0.0\",\n org.eclipse.kura.core.testutil.http;version=\"1.0.0\",\n org.eclipse.kura.core.testutil.json;version=\"1.0.0\",\n org.eclipse.kura.core.testutil.pki;version=\"1.2.0\",\n org.eclipse.kura.core.testutil.requesthandler;version=\"1.2.0\",\n org.eclipse.kura.core.testutil.service;version=\"1.0.0\"\nRequire-Bundle: moquette-broker\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/build.properties",
    "content": "#\n# Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\noutput.. = target/classes/\nsource.. = src/main/java/\nbin.includes = about.html,\\\n               META-INF/,\\\n               .\nadditional.bundles = slf4j.api\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2016, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test-util</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.core.testutil</artifactId>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n    \n    <build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/AssumingIsNotJenkins.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil;\n\nimport java.io.File;\n\nimport org.junit.AssumptionViolatedException;\nimport org.junit.rules.TestRule;\nimport org.junit.runner.Description;\nimport org.junit.runners.model.Statement;\n\npublic class AssumingIsNotJenkins implements TestRule {\n\n    @Override\n    public Statement apply(Statement base, Description description) {\n        return new Statement() {\n\n            @Override\n            public void evaluate() throws Throwable {\n                File tempFile = new File(\"/tmp/isJenkins.txt\");\n                if (tempFile.exists()) {\n                    throw new AssumptionViolatedException(\"Jenkins detected. Skipping tests!\");\n                } else {\n                    base.evaluate();\n                }\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/AssumingIsNotMac.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil;\n\nimport org.junit.AssumptionViolatedException;\nimport org.junit.rules.TestRule;\nimport org.junit.runner.Description;\nimport org.junit.runners.model.Statement;\n\npublic class AssumingIsNotMac implements TestRule {\n\n    @Override\n    public Statement apply(Statement base, Description description) {\n        return new Statement() {\n\n            @Override\n            public void evaluate() throws Throwable {\n                if (System.getProperty(\"os.name\").toLowerCase().contains(\"mac\")) {\n                    throw new AssumptionViolatedException(\"Mac OS X not supported. Skipping tests!\");\n                } else {\n                    base.evaluate();\n                }\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/TestUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2016, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Collection of methods for testing private methods and fields.\n */\npublic class TestUtil {\n\n    private static final Logger logger = LoggerFactory.getLogger(TestUtil.class);\n\n    private TestUtil() {\n        // Do nothing...\n    }\n\n    private static Field getField(Object svc, String fieldName) throws NoSuchFieldException {\n        Field field = null;\n        Class clazz = svc.getClass();\n        while (!(clazz == Object.class || field != null)) {\n            try {\n                field = clazz.getDeclaredField(fieldName);\n                break;\n            } catch (NoSuchFieldException e) {\n                // don't worry about it, here\n            }\n            clazz = clazz.getSuperclass();\n        }\n\n        if (field == null) {\n            throw new NoSuchFieldException(String.format(\"Field not found: %s\", fieldName));\n        }\n\n        return field;\n    }\n\n    /**\n     * Returns the current value of a (private) field in an object.\n     *\n     * @param svc\n     * @param fieldName\n     * @return\n     * @throws NoSuchFieldException\n     */\n    public static Object getFieldValue(Object svc, String fieldName) throws NoSuchFieldException {\n        Object result = null;\n\n        Field field = getField(svc, fieldName);\n\n        try {\n            field.setAccessible(true);\n            result = field.get(svc);\n        } catch (IllegalArgumentException e) {\n            logger.warn(e.getMessage(), e);\n        } catch (IllegalAccessException e) {\n            logger.warn(e.getMessage(), e);\n        }\n\n        return result;\n    }\n\n    private static Method getMethod(Object svc, String methodName, Class... paramTypes) throws NoSuchMethodException {\n        Method method = null;\n        Class<?> clazz = svc.getClass();\n        while (!(clazz == Object.class || method != null)) {\n            Method[] methods = clazz.getDeclaredMethods();\n            for (Method m : methods) {\n                if (m.getName().compareTo(methodName) == 0 && checkParameterTypes(m, paramTypes)) {\n                    return m;\n                }\n            }\n            clazz = clazz.getSuperclass();\n        }\n\n        throw new NoSuchMethodException(String.format(\"Method not found: %s\", methodName));\n    }\n\n    private static boolean checkParameterTypes(Method m, Class... paramTypes) {\n        if (paramTypes == null) {\n            return true;\n        }\n\n        if (m.getParameterTypes().length != paramTypes.length) {\n            return false;\n        }\n\n        Class<?>[] foundParamTypes = m.getParameterTypes();\n        for (int i = 0; i < foundParamTypes.length; i++) {\n            if (foundParamTypes[i] != paramTypes[i]) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Invokes a (private) method on an object.\n     *\n     * @param svc\n     * @param methodName\n     * @param paramTypes\n     * @param params\n     * @return\n     * @throws Throwable\n     */\n    public static Object invokePrivate(Object svc, String methodName, Class<?>[] paramTypes, Object... params)\n            throws Throwable {\n\n        Method method = getMethod(svc, methodName, paramTypes);\n\n        method.setAccessible(true);\n\n        try {\n            Object result = method.invoke(svc, params);\n            return result;\n        } catch (IllegalAccessException e) {\n            logger.warn(e.getMessage(), e);\n        } catch (IllegalArgumentException e) {\n            logger.warn(e.getMessage(), e);\n        } catch (InvocationTargetException e) {\n            throw e.getCause();\n        }\n\n        return null;\n    }\n\n    /**\n     * Invokes a (private) method on an object.\n     *\n     * @param svc\n     * @param methodName\n     * @param params\n     * @return\n     * @throws Throwable\n     */\n    public static Object invokePrivate(Object svc, String methodName, Object... params) throws Throwable {\n        return invokePrivate(svc, methodName, null, params);\n    }\n\n    /**\n     * Sets a value of a (private) field.\n     *\n     * @param svc\n     * @param fieldName\n     * @param value\n     * @throws NoSuchFieldException\n     */\n    public static void setFieldValue(Object svc, String fieldName, Object value) throws NoSuchFieldException {\n        Field field = getField(svc, fieldName);\n\n        field.setAccessible(true);\n\n        try {\n            field.set(svc, value);\n        } catch (IllegalArgumentException e) {\n            logger.warn(e.getMessage(), e);\n        } catch (IllegalAccessException e) {\n            logger.warn(e.getMessage(), e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/event/EventAdminUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.event;\n\nimport java.util.Dictionary;\nimport java.util.Hashtable;\nimport java.util.concurrent.CompletableFuture;\n\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.event.Event;\nimport org.osgi.service.event.EventConstants;\nimport org.osgi.service.event.EventHandler;\n\npublic class EventAdminUtil {\n\n    private EventAdminUtil() {\n    }\n\n    public static ServiceRegistration<EventHandler> registerEventHandler(final String[] topics,\n            final EventHandler eventHandler, final BundleContext bundleContext) {\n        final Dictionary<String, Object> properties = new Hashtable<>();\n\n        properties.put(EventConstants.EVENT_TOPIC, topics);\n\n        return bundleContext.registerService(EventHandler.class, eventHandler, properties);\n    }\n\n    public static <T extends Event> CompletableFuture<T> nextEvent(final String[] topics, final Class<T> classz,\n            final BundleContext bundleContext) {\n        final CompletableFuture<T> result = new CompletableFuture<>();\n\n        @SuppressWarnings(\"unchecked\")\n        final ServiceRegistration<?> reg = registerEventHandler(topics, e -> {\n            if (classz.isInstance(e)) {\n                result.complete((T) e);\n            }\n        }, bundleContext);\n\n        return result.whenComplete((ok, ex) -> reg.unregister());\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/http/TestServer.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.http;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.function.Consumer;\n\nimport org.eclipse.jetty.ee10.servlet.ServletContextHandler;\nimport org.eclipse.jetty.ee10.servlet.ServletHolder;\nimport org.eclipse.jetty.server.Server;\nimport org.eclipse.jetty.server.ServerConnector;\n\nimport jakarta.servlet.ServletException;\nimport jakarta.servlet.http.HttpServlet;\nimport jakarta.servlet.http.HttpServletRequest;\nimport jakarta.servlet.http.HttpServletResponse;\n\npublic class TestServer implements Closeable {\n\n    private final Server server;\n    private final Optional<Consumer<String>> downloadListener;\n    private final Map<String, byte[]> resources = new HashMap<>();\n\n    public TestServer(final int port, final Optional<Consumer<String>> downloadListener) throws Exception {\n        this.server = new Server();\n        this.downloadListener = downloadListener;\n\n        final ServerConnector connector = new ServerConnector(server);\n        connector.setPort(port);\n        this.server.setConnectors(new ServerConnector[] { connector });\n\n        final ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);\n        context.setContextPath(\"/\");\n        this.server.setHandler(context);\n\n        context.addServlet(new ServletHolder(new DownloadServlet()), \"/*\");\n        this.server.start();\n    }\n\n    public void setResource(final String path, final byte[] data) {\n        this.resources.put(path, data);\n    }\n\n    private class DownloadServlet extends HttpServlet {\n\n        /**\n         * \n         */\n        private static final long serialVersionUID = -3832275612143600045L;\n\n        @Override\n        protected void doGet(final HttpServletRequest req, final HttpServletResponse resp)\n                throws ServletException, IOException {\n\n            final String uri = req.getRequestURI();\n\n            downloadListener.ifPresent(l -> l.accept(uri));\n\n            final Optional<byte[]> data = Optional.ofNullable(resources.get(uri));\n\n            try {\n                if (data.isPresent()) {\n                    resp.setStatus(200);\n                    resp.setContentType(\"application/pkix-crl\");\n                    final OutputStream out = resp.getOutputStream();\n                    out.write(data.get());\n                    out.flush();\n                } else {\n                    resp.sendError(404);\n                }\n            } catch (final IOException e) {\n                // do nothing\n            }\n        }\n\n    }\n\n    @Override\n    public void close() throws IOException {\n        try {\n            this.server.stop();\n        } catch (final Exception e) {\n            throw new IOException(e);\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/json/JsonProjection.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.json;\n\nimport com.eclipsesource.json.JsonArray;\nimport com.eclipsesource.json.JsonObject;\nimport com.eclipsesource.json.JsonValue;\n\npublic interface JsonProjection {\n\n    public JsonValue apply(final JsonValue element);\n\n    public static JsonProjection self() {\n        return new JsonProjection() {\n\n            @Override\n            public JsonValue apply(JsonValue element) {\n                return element;\n            }\n\n            @Override\n            public String toString() {\n                return \"\";\n            }\n        };\n    }\n\n    public default JsonProjection compose(final JsonProjection other) {\n        final JsonProjection self = this;\n\n        return new JsonProjection() {\n\n            @Override\n            public JsonValue apply(JsonValue element) {\n                return other.apply(self.apply(element));\n            }\n\n            @Override\n            public String toString() {\n                return self.toString() + other.toString();\n            }\n        };\n    }\n\n    public default JsonProjection field(final String name) {\n        return this.compose(new JsonProjection() {\n\n            @Override\n            public JsonValue apply(JsonValue element) {\n                final JsonObject asObject = element.asObject();\n                return asObject.get(name);\n            }\n\n            @Override\n            public String toString() {\n                return \".\" + name;\n            }\n        });\n    }\n\n    public default JsonProjection arrayItem(final int index) {\n        return this.compose(new JsonProjection() {\n\n            @Override\n            public JsonValue apply(JsonValue element) {\n                final JsonArray asArray = element.asArray();\n                try {\n                    return asArray.get(index);\n                } catch (final Exception e) {\n                    return null;\n                }\n            }\n\n            @Override\n            public String toString() {\n                return \"[\" + index + \"]\";\n            }\n        });\n    }\n\n    public default JsonProjection anyArrayItem(final JsonProjection other) {\n        return this.compose(new JsonProjection() {\n\n            @Override\n            public JsonValue apply(JsonValue element) {\n                final JsonArray asArray = element.asArray();\n\n                for (final JsonValue member : asArray) {\n                    try {\n                        final JsonValue value = other.apply(member);\n\n                        if (value != null) {\n                            return value;\n                        }\n                    } catch (final Exception e) {\n                        // continue\n                    }\n                }\n\n                return null;\n            }\n\n            @Override\n            public String toString() {\n                return \"[*]\" + other.toString();\n            }\n        });\n    }\n\n    public default JsonProjection matching(final JsonValue value) {\n        return this.compose(new JsonProjection() {\n\n            @Override\n            public JsonValue apply(JsonValue element) {\n                if (value.equals(element)) {\n                    return element;\n                } else {\n                    return null;\n                }\n            }\n\n            @Override\n            public String toString() {\n                return \"(=\" + value + \")\";\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/pki/TestCA.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.pki;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.math.BigInteger;\nimport java.net.URI;\nimport java.nio.file.Files;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.KeyStore;\nimport java.security.KeyStore.PasswordProtection;\nimport java.security.KeyStore.PrivateKeyEntry;\nimport java.security.KeyStore.ProtectionParameter;\nimport java.security.PrivateKey;\nimport java.security.Security;\nimport java.security.cert.X509CRL;\nimport java.security.cert.X509Certificate;\nimport java.time.Instant;\nimport java.time.temporal.ChronoUnit;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.Random;\n\nimport org.bouncycastle.asn1.DERIA5String;\nimport org.bouncycastle.asn1.x500.X500Name;\nimport org.bouncycastle.asn1.x509.BasicConstraints;\nimport org.bouncycastle.asn1.x509.CRLDistPoint;\nimport org.bouncycastle.asn1.x509.CRLNumber;\nimport org.bouncycastle.asn1.x509.DistributionPoint;\nimport org.bouncycastle.asn1.x509.DistributionPointName;\nimport org.bouncycastle.asn1.x509.Extension;\nimport org.bouncycastle.asn1.x509.GeneralName;\nimport org.bouncycastle.asn1.x509.GeneralNames;\nimport org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;\nimport org.bouncycastle.cert.X509v2CRLBuilder;\nimport org.bouncycastle.cert.bc.BcX509ExtensionUtils;\nimport org.bouncycastle.cert.jcajce.JcaX509CRLConverter;\nimport org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;\nimport org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;\nimport org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\nimport org.bouncycastle.openssl.jcajce.JcaPEMWriter;\nimport org.bouncycastle.operator.ContentSigner;\nimport org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;\n\npublic class TestCA {\n\n    public static final String TEST_KEYSTORE_PASSWORD = \"changeit\";\n\n    private static final Instant DEFAULT_START_INSTANT = Instant.now();\n    private static final Instant DEFAULT_END_INSTANT = DEFAULT_START_INSTANT.plus(365, ChronoUnit.DAYS);\n\n    private BigInteger nextSerial = BigInteger.ONE;\n    private BigInteger nextCrlNumber = BigInteger.ONE;\n    private final KeyPair caKeyPair;\n    private final X500Name caDn;\n    private final List<RevokedCertificate> revokedCertificates = new ArrayList<>();\n    private final X509Certificate certificate;\n\n    static {\n        Security.addProvider(new BouncyCastleProvider());\n    }\n\n    public TestCA(final KeyStore keyStore, final String keyAlias, final String keystorePassword)\n            throws TestCAException {\n        try {\n            final PrivateKeyEntry entry = (PrivateKeyEntry) keyStore.getEntry(keyAlias,\n                    new PasswordProtection(keystorePassword.toCharArray()));\n\n            this.certificate = (X509Certificate) entry.getCertificate();\n            this.caKeyPair = new KeyPair(this.certificate.getPublicKey(), entry.getPrivateKey());\n            this.caDn = new JcaX509CertificateHolder(this.certificate).getSubject();\n        } catch (final Exception e) {\n            throw new TestCAException(e);\n        }\n    }\n\n    public TestCA(final CertificateCreationOptions options) throws TestCAException {\n        this(options, generateKeyPair());\n    }\n\n    public TestCA(final CertificateCreationOptions options, final KeyPair keyPair) throws TestCAException {\n        try {\n            this.caKeyPair = keyPair;\n            this.caDn = options.getDn();\n\n            this.certificate = buildCertificate(options, nextSerial, keyPair, options.getDn(), keyPair);\n\n            this.nextSerial = this.nextSerial.add(BigInteger.ONE);\n        } catch (final TestCAException e) {\n            throw e;\n        } catch (final Exception e) {\n            throw new TestCAException(e);\n        }\n    }\n\n    public static KeyPair generateKeyPair() throws TestCAException {\n        try {\n            KeyPairGenerator keyGen = KeyPairGenerator.getInstance(\"RSA\");\n            keyGen.initialize(2048);\n            return keyGen.generateKeyPair();\n        } catch (final Exception e) {\n            throw new TestCAException(e);\n        }\n    }\n\n    public X509Certificate getCertificate() {\n        return this.certificate;\n    }\n\n    private static X509Certificate buildCertificate(final CertificateCreationOptions options, final BigInteger serial,\n            final KeyPair certPair, final X500Name issuerName, final KeyPair issuerPair) throws TestCAException {\n        try {\n            final ContentSigner contentSigner = new JcaContentSignerBuilder(options.getSignatureAlgorithm())\n                    .build(issuerPair.getPrivate());\n\n            final JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(issuerName, serial,\n                    options.getStartDate().orElseGet(() -> Date.from(DEFAULT_START_INSTANT)),\n                    options.getEndDate().orElseGet(() -> Date.from(DEFAULT_END_INSTANT)), options.getDn(),\n                    certPair.getPublic());\n\n            certBuilder.addExtension(Extension.subjectKeyIdentifier, false, new BcX509ExtensionUtils()\n                    .createSubjectKeyIdentifier(SubjectPublicKeyInfo.getInstance(certPair.getPublic().getEncoded())));\n\n            if (!(issuerName.equals(options.dn))) {\n                certBuilder.addExtension(Extension.authorityKeyIdentifier, false,\n                        new BcX509ExtensionUtils().createAuthorityKeyIdentifier(\n                                SubjectPublicKeyInfo.getInstance(issuerPair.getPublic().getEncoded())));\n            } else {\n                certBuilder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));\n            }\n\n            final Optional<URI> crlDistributionPoint = options.getGetDownloadURL();\n\n            if (crlDistributionPoint.isPresent()) {\n                final GeneralName generalName = new GeneralName(6,\n                        new DERIA5String(crlDistributionPoint.get().toString()));\n                final GeneralNames generalNames = new GeneralNames(generalName);\n                final DistributionPointName dpn = new DistributionPointName(0, generalNames);\n                CRLDistPoint crlDp = new CRLDistPoint(Collections.singletonList(new DistributionPoint(dpn, null, null))\n                        .toArray(new DistributionPoint[0]));\n                certBuilder.addExtension(Extension.cRLDistributionPoints, false, crlDp);\n            }\n\n            return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME)\n                    .getCertificate(certBuilder.build(contentSigner));\n        } catch (final Exception e) {\n            throw new TestCAException(e);\n        }\n    }\n\n    public X509Certificate createAndSignCertificate(final CertificateCreationOptions options) throws TestCAException {\n        return createAndSignCertificate(options, generateKeyPair());\n    }\n\n    public X509Certificate createAndSignCertificate(final CertificateCreationOptions options, final KeyPair keyPair)\n            throws TestCAException {\n        final X509Certificate result = buildCertificate(options, nextSerial, keyPair, this.caDn, this.caKeyPair);\n\n        nextSerial = nextSerial.add(BigInteger.ONE);\n\n        return result;\n    }\n\n    public void revokeCertificate(final X509Certificate certificate) {\n        revokeCertificate(certificate.getSerialNumber());\n    }\n\n    public void revokeCertificate(final BigInteger serial) {\n        if (this.revokedCertificates.stream().noneMatch(c -> c.serial.equals(serial))) {\n            this.revokedCertificates.add(new RevokedCertificate(serial));\n        }\n    }\n\n    public X509CRL generateCRL(final CRLCreationOptions options) throws TestCAException {\n        try {\n            final Date creationDate = options.getStartDate().orElseGet(Date::new);\n\n            final X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(this.caDn, creationDate);\n\n            for (final RevokedCertificate revokedCertificate : this.revokedCertificates) {\n                crlBuilder.addCRLEntry(revokedCertificate.serial, revokedCertificate.revocationDate, 0);\n            }\n\n            final Optional<Date> endDate = options.getEndDate();\n\n            crlBuilder.setNextUpdate(endDate.orElseGet(() -> Date.from(DEFAULT_END_INSTANT)));\n\n            crlBuilder.addExtension(Extension.authorityKeyIdentifier, false,\n                    new BcX509ExtensionUtils().createAuthorityKeyIdentifier(\n                            SubjectPublicKeyInfo.getInstance(this.caKeyPair.getPublic().getEncoded())));\n            crlBuilder.addExtension(Extension.cRLNumber, false, new CRLNumber(this.nextCrlNumber));\n\n            final ContentSigner contentSigner = new JcaContentSignerBuilder(options.getSignatureAlgorithm())\n                    .build(this.caKeyPair.getPrivate());\n\n            return new JcaX509CRLConverter().getCRL(crlBuilder.build(contentSigner));\n        } catch (final Exception e) {\n            throw new TestCAException(e);\n        }\n    }\n\n    public static void encodeToPEM(final X509Certificate certificate, final OutputStream out) throws IOException {\n        try (final JcaPEMWriter pw = new JcaPEMWriter(new OutputStreamWriter(out))) {\n            pw.writeObject(certificate);\n        }\n    }\n\n    public static void encodeToPEM(final X509CRL crl, final OutputStream out) throws IOException {\n        try (final JcaPEMWriter pw = new JcaPEMWriter(new OutputStreamWriter(out))) {\n            pw.writeObject(crl);\n        }\n    }\n\n    public static void encodeToPEM(final PrivateKey privateKey, final OutputStream out) throws IOException {\n        try (final JcaPEMWriter pw = new JcaPEMWriter(new OutputStreamWriter(out))) {\n            pw.writeObject(privateKey);\n        }\n    }\n\n    public static void writeKeystore(final File file, final KeyStore.Entry... entries)\n            throws TestCAException, IOException {\n        try {\n            final KeyStore keyStore = KeyStore.getInstance(\"JKS\");\n            keyStore.load(null, null);\n\n            for (final KeyStore.Entry entry : entries) {\n                final ProtectionParameter param;\n\n                if (entry instanceof PrivateKeyEntry) {\n                    param = new KeyStore.PasswordProtection(TEST_KEYSTORE_PASSWORD.toCharArray());\n\n                } else {\n                    param = null;\n                }\n\n                keyStore.setEntry(Integer.toString(new Random(System.nanoTime()).nextInt()), entry, param);\n            }\n\n            try (final FileOutputStream out = new FileOutputStream(file)) {\n                keyStore.store(out, TEST_KEYSTORE_PASSWORD.toCharArray());\n            }\n        } catch (final IOException e) {\n            throw e;\n        } catch (final Exception e) {\n            throw new TestCAException(e);\n        }\n\n    }\n\n    public static File writeKeystore(final KeyStore.Entry... entries) throws TestCAException, IOException {\n        final File result = Files.createTempFile(null, null).toFile();\n\n        writeKeystore(result, entries);\n\n        return result;\n    }\n\n    private static class RevokedCertificate {\n\n        private final BigInteger serial;\n        private final Date revocationDate;\n\n        public RevokedCertificate(final BigInteger serial) {\n            this.serial = serial;\n            this.revocationDate = new Date();\n        }\n    }\n\n    public static class CRLCreationOptions {\n\n        private final Optional<Date> startDate;\n        private final Optional<Date> endDate;\n        private final String signatureAlgorithm;\n\n        private CRLCreationOptions(final Builder builder) {\n            this.startDate = builder.startDate;\n            this.endDate = builder.endDate;\n            this.signatureAlgorithm = builder.signatureAlgorithm;\n        }\n\n        public Optional<Date> getStartDate() {\n            return startDate;\n        }\n\n        public Optional<Date> getEndDate() {\n            return endDate;\n        }\n\n        public String getSignatureAlgorithm() {\n            return signatureAlgorithm;\n        }\n\n        public static Builder builder() {\n            return new Builder();\n        }\n\n        public static class Builder {\n\n            private Optional<Date> startDate = Optional.empty();\n            private Optional<Date> endDate = Optional.empty();\n            private String signatureAlgorithm = \"SHA256WithRSA\";\n\n            public Builder withStartDate(final Date startDate) {\n                this.startDate = Optional.of(startDate);\n                return this;\n            }\n\n            public Builder withEndDate(final Date endDate) {\n                this.endDate = Optional.of(endDate);\n                return this;\n            }\n\n            public Builder withSignatureAlgorithm(final String signatureAlgorithm) {\n                this.signatureAlgorithm = signatureAlgorithm;\n                return this;\n            }\n\n            public CRLCreationOptions build() {\n                return new CRLCreationOptions(this);\n            }\n        }\n    }\n\n    public static class CertificateCreationOptions {\n\n        private final X500Name dn;\n        private final Optional<Date> startDate;\n        private final Optional<Date> endDate;\n        private final Optional<URI> crlDownloadURL;\n        private final String signatureAlgorithm;\n\n        private CertificateCreationOptions(final Builder builder) {\n            this.dn = builder.dn;\n            this.startDate = builder.startDate;\n            this.endDate = builder.endDate;\n            this.crlDownloadURL = builder.crlDownloadURL;\n            this.signatureAlgorithm = builder.signatureAlgorithm;\n        }\n\n        public static Builder builder(final X500Name dn) {\n            return new Builder(dn);\n        }\n\n        public X500Name getDn() {\n            return dn;\n        }\n\n        public Optional<Date> getStartDate() {\n            return startDate;\n        }\n\n        public Optional<Date> getEndDate() {\n            return endDate;\n        }\n\n        public Optional<URI> getGetDownloadURL() {\n            return crlDownloadURL;\n        }\n\n        public String getSignatureAlgorithm() {\n            return signatureAlgorithm;\n        }\n\n        public static class Builder {\n\n            private final X500Name dn;\n            private Optional<Date> startDate = Optional.empty();\n            private Optional<Date> endDate = Optional.empty();\n            private Optional<URI> crlDownloadURL = Optional.empty();\n            private String signatureAlgorithm = \"SHA256WithRSA\";\n\n            public Builder(final X500Name dn) {\n                this.dn = dn;\n            }\n\n            public Builder withStartDate(final Date startDate) {\n                this.startDate = Optional.of(startDate);\n                return this;\n            }\n\n            public Builder withEndDate(final Date endDate) {\n                this.endDate = Optional.of(endDate);\n                return this;\n            }\n\n            public Builder withCRLDownloadURI(final URI uri) {\n                this.crlDownloadURL = Optional.of(uri);\n                return this;\n            }\n\n            public Builder withSignatureAlgorithm(final String signatureAlgorithm) {\n                this.signatureAlgorithm = signatureAlgorithm;\n                return this;\n            }\n\n            public CertificateCreationOptions build() {\n                return new CertificateCreationOptions(this);\n            }\n        }\n    }\n\n    public static class TestCAException extends Exception {\n\n        /**\n         * \n         */\n        private static final long serialVersionUID = -8997629775984256528L;\n\n        public TestCAException(Throwable cause) {\n            super(cause);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/AbstractRequestHandlerTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.requesthandler;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.net.CookieManager;\nimport java.net.CookieStore;\nimport java.net.HttpCookie;\nimport java.net.URI;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec;\nimport org.eclipse.kura.core.testutil.requesthandler.Transport.Response;\n\nimport com.eclipsesource.json.Json;\nimport com.eclipsesource.json.JsonObject;\n\npublic abstract class AbstractRequestHandlerTest {\n\n    protected final Transport transport;\n    protected Optional<Response> response = Optional.empty();\n    protected final TransportType transportType;\n    protected Map<String, HttpCookie> cookieSnapshot = new HashMap<>();\n\n    protected AbstractRequestHandlerTest(final Transport transport) {\n        this.transport = transport;\n\n        if (this.transport instanceof MqttTransport) {\n            this.transportType = TransportType.MQTT;\n        } else if (this.transport instanceof RestTransport) {\n            this.transportType = TransportType.REST;\n        } else {\n            throw new IllegalArgumentException(\"Transport type must be a REST transport or a MQTT transport\");\n        }\n\n        this.transport.init();\n    }\n\n    protected void givenSnapshotOfCurrentCookies() {\n        final CookieManager cookieManager = expectCookieManager();\n\n        this.cookieSnapshot = cookieManager.getCookieStore().getCookies().stream()\n                .collect(Collectors.toMap(c -> c.getName(), c -> (HttpCookie) c.clone()));\n    }\n\n    protected void givenCookieInSnapshot(final String name) {\n        assertNotNull(\"cookie \" + name + \" is not in captured snapshot\", this.cookieSnapshot.get(name));\n    }\n\n    protected void whenRequestIsPerformed(final MethodSpec method, final String resource) {\n        this.response = Optional.of(this.transport.runRequest(resource, method));\n    }\n\n    protected void whenRequestIsPerformed(final MethodSpec method, final String resource, final String body) {\n        this.response = Optional.of(this.transport.runRequest(resource, method, body));\n    }\n\n    protected void whenCookieIsRestoredFromSnapshot(final String name) {\n        final CookieManager cookieManager = expectCookieManager();\n        final CookieStore cookieStore = cookieManager.getCookieStore();\n\n        final HttpCookie cookie = Optional.ofNullable(this.cookieSnapshot.get(name))\n                .orElseThrow(() -> new IllegalStateException(\"cookie \" + name + \" is not in the captured snapshot\"));\n\n        Optional<URI> targetURI = Optional.empty();\n\n        for (final URI uri : cookieStore.getURIs()) {\n            for (final HttpCookie storedCookie : cookieStore.get(uri)) {\n                if (Objects.equals(storedCookie.getName(), name)) {\n                    targetURI = Optional.of(uri);\n                    break;\n                }\n            }\n        }\n\n        cookieStore.add(targetURI.orElseThrow(() -> new IllegalStateException(\"Cannot determine cookie URI\")), cookie);\n    }\n\n    protected void thenCurrentCookieDiffersFromPreviousSnapshot(final String name) {\n        final Optional<HttpCookie> cookieInSnapshot = Optional.ofNullable(this.cookieSnapshot.get(name));\n        final Optional<HttpCookie> currentCookie = expectCookieManager().getCookieStore().getCookies().stream()\n                .filter(c -> name.equals(c.getName())).findAny();\n\n        assertNotEquals(cookieInSnapshot.map(HttpCookie::getValue), currentCookie.map(HttpCookie::getValue));\n    }\n\n    protected void thenRequestSucceeds() {\n        final Response currentResponse = expectResponse();\n\n        if ((currentResponse.getStatus() / 200) != 1) {\n            fail(\"expected success status, but was: \" + currentResponse.getStatus() + \" body: \"\n                    + currentResponse.getBody());\n        }\n    }\n\n    protected void thenResponseCodeIs(final int expectedResponseCode) {\n        final Response currentResponse = expectResponse();\n\n        if (currentResponse.getStatus() != expectedResponseCode) {\n            fail(\"expected status: \" + expectedResponseCode + \" but was: \" + currentResponse.getStatus() + \" body: \"\n                    + currentResponse.getBody());\n        }\n    }\n\n    protected void thenResponseBodyEqualsJson(final String value) {\n        assertEquals(Json.parse(value), Json.parse(\n                expectResponse().getBody().orElseThrow(() -> new IllegalStateException(\"expected response body\"))));\n    }\n\n    protected void thenResponseBodyIsEmpty() {\n        assertEquals(Optional.empty(), expectResponse().getBody());\n    }\n\n    protected void thenResponseBodyIsNotEmpty() {\n        assertTrue(expectResponse().getBody().isPresent());\n    }\n\n    protected void thenResponseHasCookie(final String name) {\n        final CookieManager cookieManager = expectCookieManager();\n\n        assertTrue(cookieManager.getCookieStore().getCookies().stream().anyMatch(c -> c.getName().equals(name)));\n    }\n\n    protected void thenResponseDoesNotHaveCookie(final String name) {\n        final CookieManager cookieManager = expectCookieManager();\n\n        assertTrue(cookieManager.getCookieStore().getCookies().stream().noneMatch(c -> c.getName().equals(name)));\n    }\n\n    protected CookieManager expectCookieManager() {\n        if (!(this.transport instanceof RestTransport)) {\n            fail(\"cookies are available only with rest transport\");\n        }\n\n        return ((RestTransport) this.transport).getCookieManager();\n    }\n\n    protected Response expectResponse() {\n        return response.orElseThrow(() -> new IllegalStateException(\"response not available\"));\n    }\n\n    protected JsonObject expectJsonResponse() {\n        return Json.parse(\n                expectResponse().getBody().orElseThrow(() -> new IllegalStateException(\"response body is empty\")))\n                .asObject();\n    }\n\n    public TransportType getTransportType() {\n        return this.transportType;\n    }\n\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/MqttTransport.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.requesthandler;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Random;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.data.util.MqttTopicUtil;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.eclipse.kura.data.DataTransportService;\nimport org.eclipse.kura.data.DataTransportToken;\nimport org.eclipse.kura.data.transport.listener.DataTransportListener;\nimport org.eclipse.kura.marshalling.Marshaller;\nimport org.eclipse.kura.marshalling.Unmarshaller;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.moquette.broker.Server;\nimport io.moquette.broker.config.FluentConfig;\nimport io.moquette.broker.config.IConfig;\n\npublic class MqttTransport implements Transport {\n\n    private static final Logger logger = LoggerFactory.getLogger(MqttTransport.class);\n\n    private static final String MQTT_DATA_TRANSPORT_FACTORY_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    private static final String DEFAULT_CLOUD_SERVICE_PID = \"org.eclipse.kura.cloud.CloudService\";\n    private static final String DEFAULT_MQTT_DATA_TRANSPORT_SERVICE_PID = \"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\";\n\n    private static Server mqttBroker;\n\n    private DataTransportInspector observerInspector;\n\n    private Marshaller jsonMarshaller;\n    private Unmarshaller jsonUnmarshaller;\n\n    private String appId;\n\n    private AtomicBoolean initialized = new AtomicBoolean(false);\n\n    public MqttTransport(final String appId) {\n        this.appId = appId;\n    }\n\n    @Override\n    public void init() {\n        if (!initialized.compareAndSet(false, true)) {\n            return;\n        }\n\n        try {\n            startMoquetteBroker();\n\n            final ConfigurationService configurationService = ServiceUtil\n                    .trackService(ConfigurationService.class, Optional.empty()).get(1, TimeUnit.MINUTES);\n            final DataTransportService mqttDataTransport = ServiceUtil\n                    .trackService(DataTransportService.class, Optional.empty()).get(1, TimeUnit.MINUTES);\n            jsonMarshaller = ServiceUtil\n                    .trackService(Marshaller.class,\n                            Optional.of(\"(kura.service.pid=org.eclipse.kura.json.marshaller.unmarshaller.provider)\"))\n                    .get(1, TimeUnit.MINUTES);\n            jsonUnmarshaller = ServiceUtil\n                    .trackService(Unmarshaller.class,\n                            Optional.of(\"(kura.service.pid=org.eclipse.kura.json.marshaller.unmarshaller.provider)\"))\n                    .get(1, TimeUnit.MINUTES);\n\n            ServiceUtil.updateComponentConfiguration(configurationService, DEFAULT_MQTT_DATA_TRANSPORT_SERVICE_PID,\n                    getConfigForLocalBroker(\"test\")).get(30, TimeUnit.SECONDS);\n\n            final Map<String, Object> cloudServiceProperties = new HashMap<>();\n            cloudServiceProperties.put(\"payload.encoding\", \"simple-json\");\n            /*\n             * Set a control topic without $ as prefix: some brokers do not allow access to topics starting with $ (like\n             * moquette, mosquitto)\n             */\n            cloudServiceProperties.put(\"topic.control-prefix\", \"EDC\");\n\n            ServiceUtil.updateComponentConfiguration(configurationService, DEFAULT_CLOUD_SERVICE_PID,\n                    cloudServiceProperties).get(30, TimeUnit.SECONDS);\n\n            final DataTransportService observer = ServiceUtil.createFactoryConfiguration(configurationService,\n                    DataTransportService.class, \"observer-\" + this.appId, MQTT_DATA_TRANSPORT_FACTORY_PID,\n                    getConfigForLocalBroker(\"observer-\" + this.appId)).get(30, TimeUnit.SECONDS);\n            observerInspector = new DataTransportInspector(observer, true);\n            final DataTransportInspector underTestInspector = new DataTransportInspector(mqttDataTransport, false);\n\n            final CompletableFuture<Void> underTestConnected = underTestInspector.connected();\n            mqttDataTransport.connect();\n            underTestConnected.get(1, TimeUnit.MINUTES);\n\n            final CompletableFuture<Void> observerConnected = observerInspector.connected();\n            observer.connect();\n            observerConnected.get(1, TimeUnit.MINUTES);\n\n        } catch (final Exception e) {\n            stopMoquetteBroker();\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public Response runRequest(String resource, MethodSpec method) {\n        return runRequest(resource, method, null);\n    }\n\n    @Override\n    public Response runRequest(String resource, MethodSpec method, String requestBody) {\n        try {\n            final KuraPayload requestPayload = new KuraPayload();\n\n            if (requestBody != null) {\n                requestPayload.setBody(requestBody.getBytes(StandardCharsets.UTF_8));\n            }\n\n            final KuraPayload response = observerInspector.runRequest(adaptResource(resource, method), requestPayload)\n                    .get(10, TimeUnit.SECONDS);\n\n            final int status = (int) (long) response.getMetric(\"response.code\");\n            final Optional<String> body = Optional.ofNullable(response.getBody())\n                    .map(s -> new String(s, StandardCharsets.UTF_8));\n\n            return new Response(status, body);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private String adaptResource(final String resource, final MethodSpec method) {\n        return method.getRequestHandlerMethod() + resource;\n    }\n\n    private Map<String, Object> getConfigForLocalBroker(final String clientId) throws KuraException {\n        final Map<String, Object> properties = new HashMap<>();\n\n        properties.put(\"broker-url\", \"mqtt://localhost:1883/\");\n        properties.put(\"username\", \"mqtt\");\n        properties.put(\"client-id\", clientId);\n        properties.put(\"topic.context.account-name\", \"mqtt\");\n\n        return properties;\n    }\n\n    private static void startMoquetteBroker() throws IOException {\n        if (mqttBroker != null) {\n            logger.info(\"Moquette broker already running\");\n            return;\n        }\n\n        IConfig brokerConfig = new FluentConfig().port(1883).host(\"0.0.0.0\").disablePersistence().build();\n        brokerConfig.setProperty(IConfig.NETTY_MAX_BYTES_PROPERTY_NAME, \"16777216\");\n\n        mqttBroker = new Server();\n        mqttBroker.startServer(brokerConfig);\n\n        Runtime.getRuntime().addShutdownHook(new Thread(MqttTransport::stopMoquetteBroker));\n        logger.info(\"Moquette broker started\");\n    }\n\n    private static void stopMoquetteBroker() {\n        if (mqttBroker != null) {\n            mqttBroker.stopServer();\n            mqttBroker = null;\n            logger.info(\"Moquette broker stopped\");\n        }\n    }\n\n    private class DataTransportInspector {\n\n        private final DataTransportService dataTransportService;\n        private final Random random = new Random();\n\n        private Optional<CompletableFuture<Void>> connectFuture = Optional.empty();\n        private Optional<CompletableFuture<Void>> disconnectFuture = Optional.empty();\n        private Optional<MessageLookup> messageLookup = Optional.empty();\n\n        DataTransportInspector(final DataTransportService dataTransportService, final boolean subscribe) {\n            this.dataTransportService = dataTransportService;\n\n            dataTransportService.addDataTransportListener(new DataTransportListener() {\n\n                @Override\n                public void onConnectionEstablished(boolean newSession) {\n                    if (subscribe) {\n                        try {\n                            dataTransportService.subscribe(\"#\", 0);\n                        } catch (Exception e) {\n                            logger.warn(\"failed to subscribe\", e);\n                        }\n                    }\n                    if (connectFuture.isPresent()) {\n                        connectFuture.get().complete(null);\n                    }\n                    connectFuture = Optional.empty();\n                }\n\n                @Override\n                public void onDisconnecting() {\n                    // do nothing\n                }\n\n                @Override\n                public void onDisconnected() {\n                    if (disconnectFuture.isPresent()) {\n                        disconnectFuture.get().complete(null);\n                    }\n                    disconnectFuture = Optional.empty();\n                }\n\n                @Override\n                public void onConfigurationUpdating(boolean wasConnected) {\n                    // do nothing\n\n                }\n\n                @Override\n                public void onConfigurationUpdated(boolean wasConnected) {\n                    // do nothing\n                }\n\n                @Override\n                public void onConnectionLost(Throwable cause) {\n                    if (disconnectFuture.isPresent()) {\n                        disconnectFuture.get().complete(null);\n                    }\n                    disconnectFuture = Optional.empty();\n                }\n\n                @Override\n                public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {\n                    if (!messageLookup.isPresent()) {\n                        return;\n                    }\n\n                    final MessageLookup lookup = messageLookup.get();\n\n                    if (MqttTopicUtil.isMatched(lookup.topicFilter, topic)) {\n                        lookup.future.complete(payload);\n                        messageLookup = Optional.empty();\n                    }\n                }\n\n                @Override\n                public void onMessageConfirmed(DataTransportToken token) {\n                    // do nothing\n                }\n\n            });\n        }\n\n        private class MessageLookup {\n\n            private final CompletableFuture<byte[]> future;\n            private final String topicFilter;\n\n            public MessageLookup(CompletableFuture<byte[]> future, String topicFilter) {\n                this.future = future;\n                this.topicFilter = topicFilter;\n            }\n        }\n\n        CompletableFuture<Void> connected() {\n            if (dataTransportService.isConnected()) {\n                return CompletableFuture.completedFuture(null);\n            }\n\n            final CompletableFuture<Void> result = new CompletableFuture<>();\n\n            this.connectFuture = Optional.of(result);\n\n            return result;\n        }\n\n        CompletableFuture<KuraPayload> runRequest(final String resource, final KuraPayload request)\n                throws KuraException {\n\n            final String requestId = Integer.toString(random.nextInt());\n\n            request.addMetric(\"requester.client.id\", \"test\");\n            request.addMetric(\"request.id\", requestId);\n\n            final byte[] data = jsonMarshaller.marshal(request).getBytes(StandardCharsets.UTF_8);\n\n            final String topic = \"EDC/mqtt/test/\" + appId + \"/\" + resource;\n\n            final CompletableFuture<byte[]> message = new CompletableFuture<>();\n\n            this.messageLookup = Optional\n                    .of(new MessageLookup(message, \"EDC/mqtt/test/\" + appId + \"/REPLY/\" + requestId));\n\n            dataTransportService.publish(topic, data, 0, false);\n\n            return message.thenApply(d -> {\n                try {\n                    return jsonUnmarshaller.unmarshal(new String(d), KuraPayload.class);\n                } catch (final Exception e) {\n                    throw new RuntimeException(e);\n                }\n            }).whenComplete((ok, ex) -> this.messageLookup = Optional.empty());\n\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/RestTransport.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.requesthandler;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.CookieManager;\nimport java.net.HttpURLConnection;\nimport java.net.Socket;\nimport java.net.URI;\nimport java.net.URISyntaxException;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\nimport java.util.Base64.Encoder;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.stream.Collectors;\n\nimport javax.net.ssl.HttpsURLConnection;\nimport javax.net.ssl.SSLContext;\n\nimport org.apache.commons.io.IOUtils;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.core.testutil.service.ServiceUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class RestTransport implements Transport {\n\n    private static final Encoder ENCODER = Base64.getEncoder();\n    private static final Logger logger = LoggerFactory.getLogger(RestTransport.class);\n\n    private final String baseURL;\n\n    private boolean initialized = false;\n\n    private Optional<String> basicCredentials = Optional.of(\"admin:admin\");\n    private Optional<SSLContext> sslContext = Optional.empty();\n    private boolean isHostnameVerificationEnabled = false;\n    private CookieManager cookieManager = new CookieManager();\n    private final Map<String, String> headers = new HashMap<>();\n\n    public RestTransport(final String servicePath) {\n        this(\"http://localhost:8080/services/\", servicePath);\n    }\n\n    public RestTransport(final String urlPrefix, final String servicePath) {\n        this.baseURL = urlPrefix + servicePath;\n    }\n\n    @Override\n    public void init() {\n        if (initialized) {\n            return;\n        }\n\n        try {\n            final ConfigurationService configurationService = trackService(ConfigurationService.class);\n            Map<String, Object> restServiceConfiguration = initialRestServiceConfiguration();\n\n            ServiceUtil\n                    .trackService(ConfigurableComponent.class,\n                            Optional.of(\"(kura.service.pid=org.eclipse.kura.internal.rest.provider.RestService)\"))\n                    .get(1, TimeUnit.MINUTES);\n\n            ServiceUtil\n                    .updateComponentConfiguration(configurationService,\n                            \"org.eclipse.kura.internal.rest.provider.RestService\", restServiceConfiguration)\n                    .get(30, TimeUnit.SECONDS);\n\n            waitPortOpen(\"localhost\", 8080, 3, TimeUnit.MINUTES);\n\n            ServiceUtil\n                    .trackService(ConfigurableComponent.class,\n                            Optional.of(\"(kura.service.pid=org.eclipse.kura.internal.rest.provider.RestService)\"))\n                    .get(1, TimeUnit.MINUTES);\n\n            Thread.sleep(1000);\n\n            initialized = true;\n        } catch (final InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new IllegalStateException(e);\n        } catch (final Exception e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    private <T> T trackService(final Class<T> classz)\n            throws InterruptedException, ExecutionException, TimeoutException {\n        return ServiceUtil.trackService(classz, Optional.empty()).get(30, TimeUnit.SECONDS);\n    }\n\n    private Map<String, Object> initialRestServiceConfiguration() {\n\n        final Map<String, Object> restServiceConfiguration = new HashMap<>();\n\n        restServiceConfiguration.put(\"allowed.ports\", new Integer[0]);\n\n        return restServiceConfiguration;\n    }\n\n    public static void waitPortOpen(final String host, final int port, final long timeout, final TimeUnit timeoutUnit)\n            throws InterruptedException {\n        final long now = System.nanoTime();\n        int successCount = 0;\n\n        while (System.nanoTime() - now < timeoutUnit.toNanos(timeout)) {\n            try {\n                new Socket(host, port).close();\n                successCount++;\n                if (successCount == 2) {\n                    return;\n                }\n                logger.info(\"port open\");\n            } catch (final Exception e) {\n                logger.warn(\"failed to connect\");\n                successCount = 0;\n            }\n            Thread.sleep(1000);\n        }\n\n        throw new IllegalStateException(\"Port \" + port + \"not open\");\n    }\n\n    public void setSslContext(final SSLContext sslContext) {\n        this.sslContext = Optional.of(sslContext);\n    }\n\n    public void setHostnameVerificationEnabled(final boolean isHostnameVerificationEnabled) {\n        this.isHostnameVerificationEnabled = isHostnameVerificationEnabled;\n    }\n\n    public void setHeader(final String key, final String value) {\n        this.headers.put(key, value);\n    }\n\n    @Override\n    public Response runRequest(String relativeUri, MethodSpec method) {\n        return runRequest(relativeUri, method, null);\n    }\n\n    @Override\n    public Response runRequest(String relativeUri, MethodSpec method, String requestBody) {\n        return runRequest(this.baseURL, relativeUri, method, requestBody);\n    }\n\n    public Response runRequest(final String urlPrefix, final String relativeUri, final MethodSpec method,\n            final String requestBody) {\n        final HttpURLConnection connection;\n\n        try {\n            connection = (HttpURLConnection) new URL(urlPrefix + relativeUri).openConnection();\n            basicCredentials.ifPresent(c -> {\n                final String encoded = ENCODER.encodeToString(c.getBytes(StandardCharsets.UTF_8));\n                connection.setRequestProperty(\"Authorization\", \"Basic \" + encoded);\n            });\n            if (connection instanceof HttpsURLConnection && sslContext.isPresent()) {\n                ((HttpsURLConnection) connection).setSSLSocketFactory(sslContext.get().getSocketFactory());\n                if (!isHostnameVerificationEnabled) {\n                    ((HttpsURLConnection) connection).setHostnameVerifier((h, s) -> true);\n                }\n            }\n\n            connection.setRequestProperty(\"Accept\", \"application/json\");\n            connection.setRequestProperty(\"Connection\", \"close\");\n            setHeaders(connection);\n            setCookies(urlPrefix, relativeUri, connection);\n\n            connection.setRequestMethod(method.getRestMethod());\n\n            if (requestBody != null) {\n                connection.setChunkedStreamingMode(0);\n                connection.setRequestProperty(\"Content-Type\", \"application/json\");\n                connection.setDoOutput(true);\n                uploadBody(requestBody, connection);\n            }\n\n            final int status = connection.getResponseCode();\n\n            final Optional<String> body = getBody(connection);\n            storeCookies(urlPrefix, relativeUri, connection);\n\n            connection.disconnect();\n\n            return new Response(status, body.filter(b -> !b.isEmpty()));\n        } catch (final Exception e) {\n            throw new IllegalStateException(\"request failed\", e);\n        }\n    }\n\n    private void uploadBody(final String requestBody, final HttpURLConnection connection) {\n        try {\n            IOUtils.write(requestBody, connection.getOutputStream());\n        } catch (final Exception e) {\n            logger.warn(\"failed to send body\", e);\n        }\n    }\n\n    private void setHeaders(final HttpURLConnection connection) {\n        for (final Entry<String, String> e : this.headers.entrySet()) {\n            connection.setRequestProperty(e.getKey(), e.getValue());\n        }\n    }\n\n    private void storeCookies(final String urlPrefix, final String relativeUri, final HttpURLConnection connection)\n            throws IOException, URISyntaxException {\n        this.cookieManager.put(new URI(urlPrefix + relativeUri), connection.getHeaderFields());\n    }\n\n    private void setCookies(final String urlPrefix, final String relativeUri, final HttpURLConnection connection)\n            throws IOException, URISyntaxException {\n        for (final Entry<String, List<String>> e : cookieManager\n                .get(new URI(urlPrefix + relativeUri), connection.getRequestProperties()).entrySet()) {\n            if (!e.getValue().isEmpty()) {\n                connection.setRequestProperty(e.getKey(), e.getValue().stream().collect(Collectors.joining(\",\")));\n            }\n        }\n    }\n\n    public void setCookieManager(final CookieManager cookieManager) {\n        this.cookieManager = cookieManager;\n    }\n\n    public CookieManager getCookieManager() {\n        return cookieManager;\n    }\n\n    private Optional<String> getBody(final HttpURLConnection connection) throws IOException {\n        try (final InputStream in = ((connection.getResponseCode() / 200) == 1) ? connection.getInputStream()\n                : connection.getErrorStream()) {\n\n            if (in == null) {\n                return Optional.empty();\n            }\n\n            return Optional.of(IOUtils.toString(in, StandardCharsets.UTF_8));\n        }\n    }\n\n    public void setBasicCredentials(final Optional<String> basicCredentials) {\n        this.basicCredentials = basicCredentials;\n    }\n\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/Transport.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.requesthandler;\n\nimport java.util.Optional;\n\npublic interface Transport {\n\n    public void init();\n\n    public Response runRequest(final String resource, final MethodSpec method);\n\n    public Response runRequest(final String resource, final MethodSpec method, final String body);\n\n    public static class Response {\n\n        private final int status;\n        private final Optional<String> body;\n\n        public Response(int status, Optional<String> body) {\n            this.status = status;\n            this.body = body;\n        }\n\n        public int getStatus() {\n            return status;\n        }\n\n        public Optional<String> getBody() {\n            return body;\n        }\n    }\n\n    public class MethodSpec {\n\n        private final String restMethod;\n        private final String requestHandlerMethod;\n\n        public MethodSpec(final String method) {\n            this.requestHandlerMethod = method;\n            this.restMethod = method;\n\n            if (this.requestHandlerMethod.equalsIgnoreCase(\"DELETE\")) {\n                throw new IllegalArgumentException(\n                        \"Method \" + this.requestHandlerMethod + \" is not allowed for RequestHandler\");\n            }\n        }\n\n        public MethodSpec(final String restMethod, final String requestHandlerMethod) {\n            this.restMethod = restMethod;\n            this.requestHandlerMethod = requestHandlerMethod;\n\n            if (this.requestHandlerMethod.equalsIgnoreCase(\"DELETE\")) {\n                throw new IllegalArgumentException(\n                        \"Method \" + this.requestHandlerMethod + \" is not allowed for RequestHandler\");\n            }\n        }\n\n        public String getRestMethod() {\n            return this.restMethod;\n        }\n\n        public String getRequestHandlerMethod() {\n            return this.requestHandlerMethod;\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/TransportType.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2023 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.requesthandler;\n\npublic enum TransportType {\n\n    MQTT(\"Mqtt\"),\n    REST(\"Rest\");\n\n    private String value;\n\n    TransportType(String value) {\n        this.value = value;\n    }\n\n    public String getValue() {\n        return this.value;\n    }\n\n    @Override\n    public String toString() {\n        return this.value;\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/service/ServiceUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.core.testutil.service;\n\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\n\npublic class ServiceUtil {\n\n    private ServiceUtil() {\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> CompletableFuture<T> trackService(final Class<T> classz, final Optional<String> filter) {\n        return trackService(classz.getName(), filter).thenApply(c -> (T) c);\n    }\n\n    public static CompletableFuture<Object> trackService(final String serviceInterfaceName,\n            final Optional<String> filter) {\n        try {\n            final BundleContext bundleContext = FrameworkUtil.getBundle(ServiceUtil.class).getBundleContext();\n\n            final CompletableFuture<Object> result = new CompletableFuture<>();\n\n            final Filter osgiFilter;\n\n            if (filter.isPresent()) {\n                osgiFilter = FrameworkUtil\n                        .createFilter(\"(&(objectClass=\" + serviceInterfaceName + \")\" + filter.get() + \")\");\n            } else {\n                osgiFilter = FrameworkUtil.createFilter(\"(objectClass=\" + serviceInterfaceName + \")\");\n            }\n\n            final ServiceTracker<Object, Object> tracker = new ServiceTracker<>(bundleContext, osgiFilter,\n                    new ServiceTrackerCustomizer<Object, Object>() {\n\n                        @Override\n                        public Object addingService(final ServiceReference<Object> ref) {\n                            final Object obj = bundleContext.getService(ref);\n\n                            result.complete(obj);\n\n                            return obj;\n\n                        }\n\n                        @Override\n                        public void modifiedService(final ServiceReference<Object> ref, final Object comp) {\n                            // nothing to do\n                        }\n\n                        @Override\n                        public void removedService(final ServiceReference<Object> ref, final Object comp) {\n                            bundleContext.ungetService(ref);\n                        }\n                    });\n\n            tracker.open();\n\n            return result.whenComplete((ok, ex) -> tracker.close());\n        } catch (final Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static <T> CompletableFuture<T> createFactoryConfiguration(final ConfigurationService configurationService,\n            final Class<T> classz, final String pid, final String factoryPid, final Map<String, Object> properties) {\n        try {\n            final BundleContext bundleContext = FrameworkUtil.getBundle(ServiceUtil.class).getBundleContext();\n\n            final CompletableFuture<T> result = new CompletableFuture<>();\n\n            final Filter filter = FrameworkUtil\n                    .createFilter(\"(&(objectClass=\" + classz.getName() + \")(kura.service.pid=\" + pid + \"))\");\n\n            final ServiceTracker<T, T> tracker = new ServiceTracker<>(bundleContext, filter,\n                    new ServiceTrackerCustomizer<T, T>() {\n\n                        @Override\n                        public T addingService(final ServiceReference<T> ref) {\n                            final T obj = bundleContext.getService(ref);\n\n                            result.complete(obj);\n\n                            return obj;\n\n                        }\n\n                        @Override\n                        public void modifiedService(final ServiceReference<T> ref, final T comp) {\n                            // nothing to do\n                        }\n\n                        @Override\n                        public void removedService(final ServiceReference<T> ref, final T comp) {\n                            bundleContext.ungetService(ref);\n                        }\n                    });\n\n            tracker.open();\n\n            configurationService.createFactoryConfiguration(factoryPid, pid, properties, true);\n\n            return result.whenComplete((ok, ex) -> tracker.close());\n        } catch (final Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static CompletableFuture<Void> deleteFactoryConfiguration(final ConfigurationService configurationService,\n            final String pid) {\n\n        try {\n            final BundleContext bundleContext = FrameworkUtil.getBundle(ServiceUtil.class).getBundleContext();\n\n            final CompletableFuture<Void> tracked = new CompletableFuture<>();\n            final CompletableFuture<Void> removed = new CompletableFuture<>();\n\n            final Filter filter = FrameworkUtil.createFilter(\"(kura.service.pid=\" + pid + \")\");\n\n            final ServiceTracker<Object, Object> tracker = new ServiceTracker<>(bundleContext, filter,\n                    new ServiceTrackerCustomizer<Object, Object>() {\n\n                        @Override\n                        public Object addingService(final ServiceReference<Object> ref) {\n                            tracked.complete(null);\n                            return bundleContext.getService(ref);\n                        }\n\n                        @Override\n                        public void modifiedService(final ServiceReference<Object> ref, final Object comp) {\n                            // nothing to do\n                        }\n\n                        @Override\n                        public void removedService(final ServiceReference<Object> ref, final Object comp) {\n                            removed.complete(null);\n                            bundleContext.ungetService(ref);\n                        }\n                    });\n\n            tracker.open();\n\n            try {\n                tracked.get(30, TimeUnit.SECONDS);\n            } catch (final Exception e) {\n                tracker.close();\n                throw e;\n            }\n\n            configurationService.deleteFactoryConfiguration(pid, true);\n\n            return removed.whenComplete((ok, ex) -> tracker.close());\n        } catch (final Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static CompletableFuture<Void> updateComponentConfiguration(final ConfigurationService configurationService,\n            final String pid, final Map<String, Object> properties) throws KuraException, InvalidSyntaxException {\n\n        final CompletableFuture<Void> result = modified(\"(kura.service.pid=\" + pid + \")\");\n\n        configurationService.updateConfiguration(pid, properties);\n\n        return result;\n    }\n\n    public static CompletableFuture<Void> modified(final String filter) throws InvalidSyntaxException {\n\n        final CompletableFuture<Void> result = new CompletableFuture<>();\n        final BundleContext context = FrameworkUtil.getBundle(ServiceUtil.class).getBundleContext();\n\n        final ServiceTracker<?, ?> tracker = new ServiceTracker<>(context, FrameworkUtil.createFilter(filter),\n                new ServiceTrackerCustomizer<Object, Object>() {\n\n                    @Override\n                    public Object addingService(ServiceReference<Object> reference) {\n                        return context.getService(reference);\n                    }\n\n                    @Override\n                    public void modifiedService(ServiceReference<Object> reference, Object service) {\n                        result.complete(null);\n                    }\n\n                    @Override\n                    public void removedService(ServiceReference<Object> reference, Object service) {\n                        context.ungetService(reference);\n                    }\n                });\n\n        tracker.open();\n\n        return result.whenComplete((ok, ex) -> tracker.close());\n    }\n\n    public static CompletableFuture<Void> removed(final String filter) throws InvalidSyntaxException {\n\n        final CompletableFuture<Void> result = new CompletableFuture<>();\n        final BundleContext context = FrameworkUtil.getBundle(ServiceUtil.class).getBundleContext();\n\n        final ServiceTracker<?, ?> tracker = new ServiceTracker<>(context, FrameworkUtil.createFilter(filter),\n                new ServiceTrackerCustomizer<Object, Object>() {\n\n                    @Override\n                    public Object addingService(ServiceReference<Object> reference) {\n                        return context.getService(reference);\n                    }\n\n                    @Override\n                    public void modifiedService(ServiceReference<Object> reference, Object service) {\n                        // no need\n                    }\n\n                    @Override\n                    public void removedService(ServiceReference<Object> reference, Object service) {\n                        context.ungetService(reference);\n                        result.complete(null);\n                    }\n                });\n\n        tracker.open();\n\n        return result.whenComplete((ok, ex) -> tracker.close());\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.test\nBundle-SymbolicName: org.eclipse.kura.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nImport-Package: junit.framework,\n org.eclipse.kura; version=\"[1.0,2.0)\",\n org.eclipse.kura.cloud; version=\"[1.0,2.0)\",\n org.eclipse.kura.message; version=\"[1.0,2.0)\",\n org.eclipse.kura.system; version=\"[1.0,2.0)\",\n org.eclipse.osgi.framework.console;version=\"1.1.0\",\n org.junit,\n org.osgi.framework;version=\"1.5.0\",\n org.osgi.service.cm;version=\"1.4.0\",\n org.osgi.service.component;version=\"1.2.0\",\n org.osgi.util.tracker;version=\"1.5.1\",\n org.slf4j;version=\"1.6.4\"\nExport-Package: org.eclipse.kura.test.annotation; version=\"1.0.0\"\nBundle-ActivationPolicy: lazy\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/OSGI-INF/test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" \n               name=\"org.eclipse.kura.test.RemoteTargetTest\"\n               modified=\"updated\">\n   <implementation class=\"org.eclipse.kura.test.RemoteTargetTest\"/>\n   <reference bind=\"setSystemService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.system.SystemService\" name=\"SystemService\" policy=\"static\" unbind=\"unsetSystemService\"/>\n   <reference bind=\"setCloudService\" cardinality=\"1..1\" interface=\"org.eclipse.kura.cloud.CloudService\" name=\"CloudService\" policy=\"static\" unbind=\"unsetCloudService\"/>\n   <reference bind=\"setConfigAdmin\" cardinality=\"1..1\" interface=\"org.osgi.service.cm.ConfigurationAdmin\" name=\"ConfigurationAdmin\" policy=\"static\" unbind=\"unsetConfigAdmin\"/>\n</scr:component>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/build.properties",
    "content": "#\n#  Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\n\nsource.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsrc.includes = about.html,\\\n               about_files/\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>test-util</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t</parent>\n\n\t<artifactId>org.eclipse.kura.test</artifactId>\n\t<packaging>eclipse-plugin</packaging>\n\n\t<properties>\n\t\t<kura.basedir>${project.basedir}/../..</kura.basedir>\n\t\t<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n\t</properties>\n\t\n\t<build>\n        <plugins>\n\t\t\t<plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>compiletests</id>\n                        <phase>test-compile</phase>\n                        <goals>\n                            <goal>testCompile</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>tycho-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n            \t<groupId>org.apache.maven.plugins</groupId>\n            \t<artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.eclipse.tycho</groupId>\n                <artifactId>target-platform-configuration</artifactId>\n            </plugin>\n\t\t</plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/src/main/java/org/eclipse/kura/test/RemoteTargetTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n ******************************************************************************/\npackage org.eclipse.kura.test;\n\nimport java.util.Dictionary;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ScheduledExecutorService;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.cloud.CloudClient;\nimport org.eclipse.kura.cloud.CloudService;\nimport org.eclipse.kura.message.KuraPayload;\nimport org.eclipse.kura.system.SystemService;\nimport org.eclipse.osgi.framework.console.CommandInterpreter;\nimport org.eclipse.osgi.framework.console.CommandProvider;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleException;\nimport org.osgi.service.cm.Configuration;\nimport org.osgi.service.cm.ConfigurationAdmin;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.util.tracker.BundleTracker;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class RemoteTargetTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(RemoteTargetTest.class);\n\n    private static final String TEST_HEADER = \"Unit-Test\";\n\n    private SystemService systemService;\n    private CloudService cloudService;\n    private CloudClient cloudClient;\n\n    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();\n\n    private ConfigurationAdmin configAdmin;\n    private BundleTracker<?> bundleTracker;\n    private TestExtender testExtender;\n\n    public void setSystemService(SystemService systemService) {\n        this.systemService = systemService;\n    }\n\n    public void unsetSystemService(SystemService systemService) {\n        this.systemService = null;\n    }\n\n    public void setCloudService(CloudService cloudService) {\n        this.cloudService = cloudService;\n        try {\n            this.cloudClient = cloudService.newCloudClient(\"RemoteTargetTest\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public void unsetCloudService(CloudService cloudService) {\n        this.cloudService = null;\n    }\n\n    public void setConfigAdmin(ConfigurationAdmin configAdmin) {\n        this.configAdmin = configAdmin;\n    }\n\n    public void unsetConfigAdmin(ConfigurationAdmin configAdmin) {\n        this.configAdmin = configAdmin;\n    }\n\n    protected void activate(final ComponentContext componentContext) {\n        //\n        // if we are running in the Eclipse JUnit Plugin Test,\n        // then we are running in emulator mode and therefore we\n        // will leverage the JUnit runner available in Eclipse PDE.\n        if (!\"emulator\".equals(System.getProperty(\"org.eclipse.kura.mode\"))) {\n            this.scheduler.submit(new Runnable() {\n\n                @Override\n                public void run() {\n                    runTests(componentContext);\n                }\n            });\n        }\n    }\n\n    private void runTests(ComponentContext componentContext) {\n        logger.debug(\"systemService.getPlatform(): \" + this.systemService.getPlatform());\n        this.testExtender = new TestExtender(this.systemService.getPlatform(), componentContext.getBundleContext());\n\n        this.bundleTracker = new BundleTracker<Object>(componentContext.getBundleContext(),\n                Bundle.RESOLVED | Bundle.ACTIVE | Bundle.INSTALLED, this.testExtender);\n        this.bundleTracker.open();\n\n        Bundle[] currentBundles = this.bundleTracker.getBundles();\n        if (currentBundles != null) {\n            Bundle netAdminBundle = null;\n\n            for (Bundle bundle : this.bundleTracker.getBundles()) {\n                if (\"org.eclipse.kura.net.admin\".equals(bundle.getSymbolicName())) {\n                    netAdminBundle = bundle;\n\n                    logger.debug(\"Disabling network admin bundle\");\n                    try {\n                        netAdminBundle.stop();\n                    } catch (BundleException e) {\n                        logger.warn(\"Could not stop net admin bundle\", e);\n                    }\n                }\n            }\n\n            logger.debug(\"Starting tests\");\n            startingTests();\n\n            for (Bundle bundle : currentBundles) {\n                if (isTestFragment(bundle)) {\n                    this.testExtender.addBundle(bundle.getBundleId(), bundle);\n\n                    if (isAutoTestEnabled(bundle)) {\n                        this.testExtender.test(bundle.getBundleId());\n                    }\n                }\n            }\n\n            finishedTests();\n\n            if (netAdminBundle != null) {\n                logger.debug(\"Re-enabling network admin bundle\");\n                try {\n                    netAdminBundle.start();\n                } catch (BundleException e) {\n                    logger.warn(\"Could not start net admin bundle\", e);\n                }\n            }\n\n            logger.warn(\"Tests finished - shutting down\");\n            System.exit(0);\n        }\n\n        componentContext.getBundleContext().registerService(CommandProvider.class.getName(),\n                new KuraTestCommandProvider(), null);\n    }\n\n    protected void deactivate(ComponentContext componentContext) {\n\n    }\n\n    public static final boolean isTestFragment(Bundle bundle) {\n        String header = bundle.getHeaders().get(TEST_HEADER) + \"\";\n        String fragment = bundle.getHeaders().get(org.osgi.framework.Constants.FRAGMENT_HOST) + \"\";\n        return !\"null\".equals(header) && !\"null\".equals(fragment);\n    }\n\n    public static final boolean isAutoTestEnabled(Bundle bundle) {\n        return \"true\".equals(bundle.getHeaders().get(TEST_HEADER) + \"\");\n    }\n\n    public class KuraTestCommandProvider implements CommandProvider {\n\n        public Object test(CommandInterpreter intp) {\n            String nextArgument = intp.nextArgument();\n            RemoteTargetTest.this.testExtender.test(Long.parseLong(nextArgument));\n            return null;\n        }\n\n        public Object testall(CommandInterpreter intp) {\n            RemoteTargetTest.this.testExtender.testAll();\n            return null;\n        }\n\n        public Object helpTest(CommandInterpreter intp) {\n            String help = getHelp();\n            System.out.println(help);\n            return null;\n        }\n\n        @Override\n        public String getHelp() {\n            StringBuilder buffer = new StringBuilder();\n            buffer.append(\"---Testing commands---\\n\\t\");\n            buffer.append(\"test [bundle id] - test bundle fragment id\\n\\t\");\n            buffer.append(\"testall - test all fragments\\n\\t\");\n            buffer.append(\"help - Print this help\\n\");\n            return buffer.toString();\n        }\n    }\n\n    private void startingTests() {\n        // hijack the settings\n        try {\n            Configuration mqttConfig = this.configAdmin\n                    .getConfiguration(\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\", \"?\");\n            Dictionary<String, Object> mqttProps = mqttConfig.getProperties();\n            mqttProps.put(\"broker-url\", \"mqtt://broker-sandbox.everyware-cloud.com:1883/\");\n            mqttProps.put(\"topic.context.account-name\", \"EDC-KURA-CI\");\n            mqttProps.put(\"username\", \"EDC-KURA-CI\");\n            mqttProps.put(\"password\", \"PYtv3?s@\");\n            mqttConfig.update(mqttProps);\n\n            Configuration dataConfig = this.configAdmin.getConfiguration(\"org.eclipse.kura.data.DataService\", \"?\");\n            Dictionary<String, Object> dataProps = dataConfig.getProperties();\n            dataProps.put(\"connect.auto-on-startup\", true);\n            dataConfig.update(dataProps);\n        } catch (Exception e) {\n            e.printStackTrace();\n            logger.error(\"Failed to reconfigure the broker settings - failing out\");\n            System.exit(-1);\n        }\n\n        // wait for connection?\n        while (!this.cloudService.isConnected()) {\n            logger.warn(\"waiting for the cloud client to connect\");\n            try {\n                Thread.sleep(1000);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n\n        KuraPayload payload = new KuraPayload();\n        try {\n            this.cloudClient.publish(\"test/start\", payload, 1, false);\n        } catch (KuraException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void finishedTests() {\n        // wait for connection??\n        while (!this.cloudService.isConnected()) {\n            logger.warn(\"waiting for the cloud client to connect\");\n            try {\n                Thread.sleep(1000);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n\n        KuraPayload payload = new KuraPayload();\n        try {\n            this.cloudClient.publish(\"test/finished\", payload, 1, false);\n        } catch (KuraException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/src/main/java/org/eclipse/kura/test/Test.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.test;\n\nimport java.lang.reflect.Method;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class Test {\n\n    private Method beforeClass;\n    private Method afterClass;\n    private Method before;\n    private Method after;\n    private final List<Method> tests;\n\n    public Test() {\n        this.tests = new ArrayList<Method>();\n    }\n\n    public Method getBeforeClass() {\n        return this.beforeClass;\n    }\n\n    public void setBeforeClass(Method beforeClass) {\n        this.beforeClass = beforeClass;\n    }\n\n    public Method getAfterClass() {\n        return this.afterClass;\n    }\n\n    public void setAfterClass(Method afterClass) {\n        this.afterClass = afterClass;\n    }\n\n    public Method getBefore() {\n        return this.before;\n    }\n\n    public void setBefore(Method before) {\n        this.before = before;\n    }\n\n    public Method getAfter() {\n        return this.after;\n    }\n\n    public void setAfter(Method after) {\n        this.after = after;\n    }\n\n    public List<Method> getTests() {\n        return this.tests;\n    }\n\n    public void addTest(Method method) {\n        this.tests.add(method);\n    }\n}"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/src/main/java/org/eclipse/kura/test/TestExtender.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n ******************************************************************************/\npackage org.eclipse.kura.test;\n\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.lang.reflect.Method;\nimport java.net.URL;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport org.eclipse.kura.test.annotation.TestTarget;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.BundleEvent;\nimport org.osgi.util.tracker.BundleTrackerCustomizer;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class TestExtender implements BundleTrackerCustomizer<Object> {\n\n    private static final Logger logger = LoggerFactory.getLogger(TestExtender.class);\n\n    private static final String KURA_TEST_REPORT_FILENAME = \"/tmp/kura_test_report.txt\";\n\n    private final Map<Long, Bundle> bundles;\n    private final BundleContext bundleContext;\n    private BufferedWriter reportWriter;\n    private final String platform;\n\n    public TestExtender(String platform, BundleContext bundleContext) {\n        this.bundles = new HashMap<Long, Bundle>();\n        this.bundleContext = bundleContext;\n        this.platform = platform;\n\n        new File(KURA_TEST_REPORT_FILENAME).delete();\n    }\n\n    void addBundle(long bundleId, Bundle bundle) {\n        this.bundles.put(bundleId, bundle);\n    }\n\n    public void testAll() {\n        Set<Map.Entry<Long, Bundle>> entrySet = this.bundles.entrySet();\n        logger.debug(\"Testing all bundles\");\n        for (Entry<Long, Bundle> entry : entrySet) {\n            test(entry.getKey());\n        }\n    }\n\n    public void test(long bundleId) {\n        logger.debug(\"Testing bundle: \" + bundleId);\n\n        List<Class<?>> testClazzs = getTestClass(this.bundles.get(bundleId));\n        for (Class<?> clazz : testClazzs) {\n            try {\n                if (!clazz.isInterface()) {\n                    logger.debug(\"Testing CLASS in bundle with ID: \" + bundleId + \"  : [\" + clazz.getName() + \"]\");\n                    Test inspectClass = inspectClass(clazz);\n                    testClass(clazz.getName(), inspectClass, clazz.newInstance());\n                }\n            } catch (Exception ex) {\n                ex.printStackTrace();\n            }\n        }\n    }\n\n    public Class<?> loadClass(String clazz, Bundle bundleHost) {\n        try {\n            Class<?> loadClass = bundleHost.loadClass(clazz);\n            logger.debug(\"Loaded class: \" + loadClass);\n            return loadClass;\n        } catch (Exception e) {\n            e.printStackTrace();\n            throw new RuntimeException(e);\n        }\n    }\n\n    public Bundle getHostBundle(Bundle bundle) {\n        String fragment = bundle.getHeaders().get(org.osgi.framework.Constants.FRAGMENT_HOST) + \"\";\n        Bundle[] contextBundles = this.bundleContext.getBundles();\n        for (Bundle ibundle : contextBundles) {\n            if (ibundle.getSymbolicName().equals(fragment)) {\n                logger.debug(\"Host bundle is: \" + ibundle.getSymbolicName());\n                return ibundle;\n            }\n        }\n        throw new RuntimeException();\n    }\n\n    public List<Class<?>> getTestClass(Bundle bundle) {\n        try {\n            List<Class<?>> clazzs = new ArrayList<Class<?>>();\n            Enumeration<?> entrs = bundle.findEntries(\"/\", \"*Test.class\", true);\n            if (entrs == null || !entrs.hasMoreElements()) {\n                return Collections.emptyList();\n            }\n            Bundle hostBundle = getHostBundle(bundle);\n            while (entrs.hasMoreElements()) {\n                URL e = (URL) entrs.nextElement();\n                String file = e.getFile();\n\n                String className = file.replaceAll(\"/\", \".\").replaceAll(\".class\", \"\").replaceFirst(\".\", \"\");\n                if (className.startsWith(\"bin.src.main.java.\")) {\n                    className = className.substring(18);\n                } else if (className.startsWith(\"targetes.\")) {\n                    className = className.substring(9);\n                }\n                logger.debug(\"Trying to load class: \" + className);\n                Class<?> clazz = loadClass(className, hostBundle);\n                logger.debug(\"Adding test class: \" + clazz);\n                clazzs.add(clazz);\n            }\n            return clazzs;\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public Test inspectClass(Class<?> clazz) {\n        Test test = new Test();\n        Method[] declaredMethods = clazz.getDeclaredMethods();\n        for (Method method : declaredMethods) {\n\n            if (method.isAnnotationPresent(org.junit.BeforeClass.class)) {\n                logger.debug(\"Adding before class: \" + method);\n                test.setBeforeClass(method);\n            }\n            if (method.isAnnotationPresent(org.junit.AfterClass.class)) {\n                logger.debug(\"Adding after class: \" + method);\n                test.setAfterClass(method);\n            }\n            if (method.isAnnotationPresent(org.junit.Before.class)) {\n                logger.debug(\"Adding before: \" + method);\n                test.setBefore(method);\n            }\n            if (method.isAnnotationPresent(org.junit.After.class)) {\n                logger.debug(\"Adding after: \" + method);\n                test.setAfter(method);\n            }\n            if (method.isAnnotationPresent(org.junit.Test.class)) {\n\n                if (method.isAnnotationPresent(TestTarget.class)) {\n                    TestTarget testTargetAnnotation = method.getAnnotation(TestTarget.class);\n                    String[] potentialPlatforms = testTargetAnnotation.targetPlatforms();\n                    for (String potentialPlatform : potentialPlatforms) {\n                        if (potentialPlatform.equals(TestTarget.PLATFORM_ALL)\n                                || potentialPlatform.equals(this.platform)) {\n                            logger.debug(\"TestTarget found \" + potentialPlatform + \" - Adding test: \" + method);\n                            test.addTest(method);\n                            break;\n                        }\n                    }\n                } else {\n                    logger.debug(\"No TestTarget Annotation present - Adding test: \" + method);\n                    test.addTest(method);\n                }\n            }\n        }\n        return test;\n    }\n\n    public void testClass(String className, Test testClass, Object object) {\n        try {\n            try {\n                if (testClass.getBeforeClass() != null) {\n                    testClass.getBeforeClass().invoke(object, new Object[0]);\n                }\n\n                this.reportWriter = new BufferedWriter(new FileWriter(new File(KURA_TEST_REPORT_FILENAME), true));\n\n                List<Method> tests = testClass.getTests();\n                for (Method method : tests) {\n                    try {\n                        if (testClass.getBefore() != null) {\n                            testClass.getBefore().invoke(object, new Object[0]);\n                        }\n\n                        try {\n                            method.invoke(object, new Object[0]);\n                            logger.info(\"Method : [ \" + className + \".\" + method.getName() + \" ] PASS\");\n\n                            this.reportWriter.write(\"Method : [ \" + className + \".\" + method.getName() + \" ] PASS\\n\");\n                            this.reportWriter.flush();\n                        } catch (Exception ex) {\n                            logger.error(\"Method : [ \" + className + \".\" + method.getName() + \" ] FAIL\", ex);\n                            this.reportWriter = new BufferedWriter(\n                                    new FileWriter(new File(KURA_TEST_REPORT_FILENAME), true));\n                            this.reportWriter.write(\"Method : [ \" + className + \".\" + method.getName() + \" ] FAIL\\n\");\n                            this.reportWriter.flush();\n                        }\n                    } finally {\n                        if (testClass.getAfter() != null) {\n                            testClass.getAfter().invoke(object, new Object[0]);\n                        }\n                    }\n                }\n            } finally {\n                if (testClass.getAfterClass() != null) {\n                    testClass.getAfterClass().invoke(object, new Object[0]);\n                }\n\n                this.reportWriter.close();\n            }\n        } catch (Exception ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @Override\n    public Object addingBundle(Bundle bundle, BundleEvent event) {\n        logger.debug(\"Tracker - Adding Bundle: \" + bundle.getSymbolicName());\n        return bundle;\n    }\n\n    @Override\n    public void modifiedBundle(Bundle bundle, BundleEvent event, Object object) {\n        logger.debug(\"Tracker - Modified Bundle: \" + bundle.getSymbolicName());\n    }\n\n    @Override\n    public void removedBundle(Bundle bundle, BundleEvent event, Object object) {\n        logger.debug(\"Tracker - Removed Bundle: \" + bundle.getSymbolicName());\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.test/src/main/java/org/eclipse/kura/test/annotation/TestTarget.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.test.annotation;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n@Target(ElementType.METHOD)\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface TestTarget {\n\n    public static final String PLATFORM_ALL = \"PLATFORM_ALL\";\n\n    public static final String PLATFORM_DURACOR = \"duracor\";\n    public static final String PLATFORM_DYNACOR = \"dynacor\";\n    public static final String PLATFORM_HELIOS = \"helios\";\n    public static final String PLATFORM_MGW = \"Mini-Gateway\";\n    public static final String PLATFORM_RASPBERRY_PI = \"Raspberr-Pi\";\n    public static final String PLATFORM_RELIAGATE = \"reliagate\";\n\n    public String[] targetPlatforms();\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.test.driver/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: org.eclipse.kura.util.test.driver\nBundle-SymbolicName: org.eclipse.kura.util.test.driver;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: Eclipse Kura\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nService-Component: OSGI-INF/*.xml\nBundle-ClassPath: .\nBundle-ActivationPolicy: lazy\nImport-Package: org.eclipse.kura.channel;version=\"1.2.0\",\n org.eclipse.kura.channel.listener;version=\"1.0.0\",\n org.eclipse.kura.configuration;version=\"1.2.0\",\n org.eclipse.kura.configuration.metatype;version=\"1.1.0\",\n org.eclipse.kura.core.configuration.metatype;version=\"1.0.0\",\n org.eclipse.kura.driver,\n org.slf4j;version=\"1.7.32\"\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.test.driver/OSGI-INF/metatype/org.eclipse.kura.util.test.driver.ChannelDescriptorTestDriver.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<MetaData xmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\" localization=\"en_us\">\n    <OCD id=\"org.eclipse.kura.util.test.driver.ChannelDescriptorTestDriver\" \n         name=\"ChannelDescriptorTestDriver\" \n         description=\"A driver for testing channel descriptor properties\">\n        \n        <AD id=\"test.property\"\n            name=\"Test Property\"\n            type=\"String\"\n            cardinality=\"0\"\n            required=\"true\"\n            default=\"test value\"\n            description=\"A test property\">\n        </AD>\n    </OCD>\n    \n    <Designate factoryPid=\"org.eclipse.kura.util.test.driver.ChannelDescriptorTestDriver\">\n        <Object ocdref=\"org.eclipse.kura.util.test.driver.ChannelDescriptorTestDriver\"/>\n    </Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.test.driver/OSGI-INF/org.eclipse.kura.util.test.driver.ChannelDescriptorTestDriver.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" deactivate=\"deactivate\" modified=\"update\" name=\"org.eclipse.kura.util.test.driver.ChannelDescriptorTestDriver\">\n    <implementation class=\"org.eclipse.kura.util.test.driver.ChannelDescriptorTestDriver\"/>\n    <service>\n       <provide interface=\"org.eclipse.kura.driver.Driver\"/>\n       <provide interface=\"org.eclipse.kura.configuration.ConfigurableComponent\"/>\n    </service>\n</scr:component>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.test.driver/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.test.driver/about_files/epl-v20.html",
    "content": "\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>\n  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n  <title>Eclipse Public License - Version 2.0</title>\n  <style type=\"text/css\">\n    body {\n      margin: 1.5em 3em;\n    }\n    h1{\n      font-size:1.5em;\n    }\n    h2{\n      font-size:1em;\n      margin-bottom:0.5em;\n      margin-top:1em;\n    }\n    p {\n      margin-top:  0.5em;\n      margin-bottom: 0.5em;\n    }\n    ul, ol{\n      list-style-type:none;\n    }\n  </style>\n</head>\n<body>\n<h1>Eclipse Public License - v 2.0</h1>\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\n  PUBLIC LICENSE (&ldquo;AGREEMENT&rdquo;). ANY USE, REPRODUCTION OR DISTRIBUTION\n  OF THE PROGRAM CONSTITUTES RECIPIENT&#039;S ACCEPTANCE OF THIS AGREEMENT.\n</p>\n<h2 id=\"definitions\">1. DEFINITIONS</h2>\n<p>&ldquo;Contribution&rdquo; means:</p>\n<ul>\n  <li>a) in the case of the initial Contributor, the initial content\n    Distributed under this Agreement, and\n  </li>\n  <li>\n    b) in the case of each subsequent Contributor:\n    <ul>\n      <li>i) changes to the Program, and</li>\n      <li>ii) additions to the Program;</li>\n    </ul>\n    where such changes and/or additions to the Program originate from\n    and are Distributed by that particular Contributor. A Contribution\n    &ldquo;originates&rdquo; from a Contributor if it was added to the Program by such\n    Contributor itself or anyone acting on such Contributor&#039;s behalf.\n    Contributions do not include changes or additions to the Program that\n    are not Modified Works.\n  </li>\n</ul>\n<p>&ldquo;Contributor&rdquo; means any person or entity that Distributes the Program.</p>\n<p>&ldquo;Licensed Patents&rdquo; mean patent claims licensable by a Contributor which\n  are necessarily infringed by the use or sale of its Contribution alone\n  or when combined with the Program.\n</p>\n<p>&ldquo;Program&rdquo; means the Contributions Distributed in accordance with this\n  Agreement.\n</p>\n<p>&ldquo;Recipient&rdquo; means anyone who receives the Program under this Agreement\n  or any Secondary License (as applicable), including Contributors.\n</p>\n<p>&ldquo;Derivative Works&rdquo; shall mean any work, whether in Source Code or other\n  form, that is based on (or derived from) the Program and for which the\n  editorial revisions, annotations, elaborations, or other modifications\n  represent, as a whole, an original work of authorship.\n</p>\n<p>&ldquo;Modified Works&rdquo; shall mean any work in Source Code or other form that\n  results from an addition to, deletion from, or modification of the\n  contents of the Program, including, for purposes of clarity any new file\n  in Source Code form that contains any contents of the Program. Modified\n  Works shall not include works that contain only declarations, interfaces,\n  types, classes, structures, or files of the Program solely in each case\n  in order to link to, bind by name, or subclass the Program or Modified\n  Works thereof.\n</p>\n<p>&ldquo;Distribute&rdquo; means the acts of a) distributing or b) making available\n  in any manner that enables the transfer of a copy.\n</p>\n<p>&ldquo;Source Code&rdquo; means the form of a Program preferred for making\n  modifications, including but not limited to software source code,\n  documentation source, and configuration files.\n</p>\n<p>&ldquo;Secondary License&rdquo; means either the GNU General Public License,\n  Version 2.0, or any later versions of that license, including any\n  exceptions or additional permissions as identified by the initial\n  Contributor.\n</p>\n<h2 id=\"grant-of-rights\">2. GRANT OF RIGHTS</h2>\n<ul>\n  <li>a) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free copyright\n    license to reproduce, prepare Derivative Works of, publicly display,\n    publicly perform, Distribute and sublicense the Contribution of such\n    Contributor, if any, and such Derivative Works.\n  </li>\n  <li>b) Subject to the terms of this Agreement, each Contributor hereby\n    grants Recipient a non-exclusive, worldwide, royalty-free patent\n    license under Licensed Patents to make, use, sell, offer to sell,\n    import and otherwise transfer the Contribution of such Contributor,\n    if any, in Source Code or other form. This patent license shall\n    apply to the combination of the Contribution and the Program if,\n    at the time the Contribution is added by the Contributor, such\n    addition of the Contribution causes such combination to be covered\n    by the Licensed Patents. The patent license shall not apply to any\n    other combinations which include the Contribution. No hardware per\n    se is licensed hereunder.\n  </li>\n  <li>c) Recipient understands that although each Contributor grants the\n    licenses to its Contributions set forth herein, no assurances are\n    provided by any Contributor that the Program does not infringe the\n    patent or other intellectual property rights of any other entity.\n    Each Contributor disclaims any liability to Recipient for claims\n    brought by any other entity based on infringement of intellectual\n    property rights or otherwise. As a condition to exercising the rights\n    and licenses granted hereunder, each Recipient hereby assumes sole\n    responsibility to secure any other intellectual property rights needed,\n    if any. For example, if a third party patent license is required to\n    allow Recipient to Distribute the Program, it is Recipient&#039;s\n    responsibility to acquire that license before distributing the Program.\n  </li>\n  <li>d) Each Contributor represents that to its knowledge it has sufficient\n    copyright rights in its Contribution, if any, to grant the copyright\n    license set forth in this Agreement.\n  </li>\n  <li>e) Notwithstanding the terms of any Secondary License, no Contributor\n    makes additional grants to any Recipient (other than those set forth\n    in this Agreement) as a result of such Recipient&#039;s receipt of the\n    Program under the terms of a Secondary License (if permitted under\n    the terms of Section 3).\n  </li>\n</ul>\n<h2 id=\"requirements\">3. REQUIREMENTS</h2>\n<p>3.1 If a Contributor Distributes the Program in any form, then:</p>\n<ul>\n  <li>a) the Program must also be made available as Source Code, in\n    accordance with section 3.2, and the Contributor must accompany\n    the Program with a statement that the Source Code for the Program\n    is available under this Agreement, and informs Recipients how to\n    obtain it in a reasonable manner on or through a medium customarily\n    used for software exchange; and\n  </li>\n  <li>\n    b) the Contributor may Distribute the Program under a license\n    different than this Agreement, provided that such license:\n    <ul>\n      <li>i) effectively disclaims on behalf of all other Contributors all\n        warranties and conditions, express and implied, including warranties\n        or conditions of title and non-infringement, and implied warranties\n        or conditions of merchantability and fitness for a particular purpose;\n      </li>\n      <li>ii) effectively excludes on behalf of all other Contributors all\n        liability for damages, including direct, indirect, special, incidental\n        and consequential damages, such as lost profits;\n      </li>\n      <li>iii) does not attempt to limit or alter the recipients&#039; rights in the\n        Source Code under section 3.2; and\n      </li>\n      <li>iv) requires any subsequent distribution of the Program by any party\n        to be under a license that satisfies the requirements of this section 3.\n      </li>\n    </ul>\n  </li>\n</ul>\n<p>3.2 When the Program is Distributed as Source Code:</p>\n<ul>\n  <li>a) it must be made available under this Agreement, or if the Program (i)\n    is combined with other material in a separate file or files made available\n    under a Secondary License, and (ii) the initial Contributor attached to\n    the Source Code the notice described in Exhibit A of this Agreement,\n    then the Program may be made available under the terms of such\n    Secondary Licenses, and\n  </li>\n  <li>b) a copy of this Agreement must be included with each copy of the Program.</li>\n</ul>\n<p>3.3 Contributors may not remove or alter any copyright, patent, trademark,\n  attribution notices, disclaimers of warranty, or limitations of liability\n  (&lsquo;notices&rsquo;) contained within the Program from any copy of the Program which\n  they Distribute, provided that Contributors may add their own appropriate\n  notices.\n</p>\n<h2 id=\"commercial-distribution\">4. COMMERCIAL DISTRIBUTION</h2>\n<p>Commercial distributors of software may accept certain responsibilities\n  with respect to end users, business partners and the like. While this\n  license is intended to facilitate the commercial use of the Program, the\n  Contributor who includes the Program in a commercial product offering should\n  do so in a manner which does not create potential liability for other\n  Contributors. Therefore, if a Contributor includes the Program in a\n  commercial product offering, such Contributor (&ldquo;Commercial Contributor&rdquo;)\n  hereby agrees to defend and indemnify every other Contributor\n  (&ldquo;Indemnified Contributor&rdquo;) against any losses, damages and costs\n  (collectively &ldquo;Losses&rdquo;) arising from claims, lawsuits and other legal actions\n  brought by a third party against the Indemnified Contributor to the extent\n  caused by the acts or omissions of such Commercial Contributor in connection\n  with its distribution of the Program in a commercial product offering.\n  The obligations in this section do not apply to any claims or Losses relating\n  to any actual or alleged intellectual property infringement. In order to\n  qualify, an Indemnified Contributor must: a) promptly notify the\n  Commercial Contributor in writing of such claim, and b) allow the Commercial\n  Contributor to control, and cooperate with the Commercial Contributor in,\n  the defense and any related settlement negotiations. The Indemnified\n  Contributor may participate in any such claim at its own expense.\n</p>\n<p>For example, a Contributor might include the Program\n  in a commercial product offering, Product X. That Contributor is then a\n  Commercial Contributor. If that Commercial Contributor then makes performance\n  claims, or offers warranties related to Product X, those performance claims\n  and warranties are such Commercial Contributor&#039;s responsibility alone.\n  Under this section, the Commercial Contributor would have to defend claims\n  against the other Contributors related to those performance claims and\n  warranties, and if a court requires any other Contributor to pay any damages\n  as a result, the Commercial Contributor must pay those damages.\n</p>\n<h2 id=\"warranty\">5. NO WARRANTY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN &ldquo;AS IS&rdquo; BASIS, WITHOUT\n  WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\n  WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\n  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is\n  solely responsible for determining the appropriateness of using and\n  distributing the Program and assumes all risks associated with its\n  exercise of rights under this Agreement, including but not limited to the\n  risks and costs of program errors, compliance with applicable laws, damage\n  to or loss of data, programs or equipment, and unavailability or\n  interruption of operations.\n</p>\n<h2 id=\"disclaimer\">6. DISCLAIMER OF LIABILITY</h2>\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED\n  BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY\n  LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,\n  OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS),\n  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n  OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS\n  GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n</p>\n<h2 id=\"general\">7. GENERAL</h2>\n<p>If any provision of this Agreement is invalid or unenforceable under\n  applicable law, it shall not affect the validity or enforceability of the\n  remainder of the terms of this Agreement, and without further action by the\n  parties hereto, such provision shall be reformed to the minimum extent\n  necessary to make such provision valid and enforceable.\n</p>\n<p>If Recipient institutes patent litigation against any entity (including a\n  cross-claim or counterclaim in a lawsuit) alleging that the Program itself\n  (excluding combinations of the Program with other software or hardware)\n  infringes such Recipient&#039;s patent(s), then such Recipient&#039;s rights granted\n  under Section 2(b) shall terminate as of the date such litigation is filed.\n</p>\n<p>All Recipient&#039;s rights under this Agreement shall terminate if it fails to\n  comply with any of the material terms or conditions of this Agreement and\n  does not cure such failure in a reasonable period of time after becoming\n  aware of such noncompliance. If all Recipient&#039;s rights under this Agreement\n  terminate, Recipient agrees to cease use and distribution of the Program\n  as soon as reasonably practicable. However, Recipient&#039;s obligations under\n  this Agreement and any licenses granted by Recipient relating to the\n  Program shall continue and survive.\n</p>\n<p>Everyone is permitted to copy and distribute copies of this Agreement,\n  but in order to avoid inconsistency the Agreement is copyrighted and may\n  only be modified in the following manner. The Agreement Steward reserves\n  the right to publish new versions (including revisions) of this Agreement\n  from time to time. No one other than the Agreement Steward has the right\n  to modify this Agreement. The Eclipse Foundation is the initial Agreement\n  Steward. The Eclipse Foundation may assign the responsibility to serve as\n  the Agreement Steward to a suitable separate entity. Each new version of\n  the Agreement will be given a distinguishing version number. The Program\n  (including Contributions) may always be Distributed subject to the version\n  of the Agreement under which it was received. In addition, after a new\n  version of the Agreement is published, Contributor may elect to Distribute\n  the Program (including its Contributions) under the new version.\n</p>\n<p>Except as expressly stated in Sections 2(a) and 2(b) above, Recipient\n  receives no rights or licenses to the intellectual property of any\n  Contributor under this Agreement, whether expressly, by implication,\n  estoppel or otherwise. All rights in the Program not expressly granted\n  under this Agreement are reserved. Nothing in this Agreement is intended\n  to be enforceable by any entity that is not a Contributor or Recipient.\n  No third-party beneficiary rights are created under this Agreement.\n</p>\n<h2 id=\"exhibit-a\">Exhibit A &ndash; Form of Secondary Licenses Notice</h2>\n<p>&ldquo;This Source Code may also be made available under the following\n  Secondary Licenses when the conditions for such availability set forth\n  in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),\n  version(s), and exceptions or additional permissions here}.&rdquo;\n</p>\n<blockquote>\n  <p>Simply including a copy of this Agreement, including this Exhibit A\n    is not sufficient to license the Source Code under Secondary Licenses.\n  </p>\n  <p>If it is not possible or desirable to put the notice in a particular file,\n    then You may include the notice in a location (such as a LICENSE file in a\n    relevant directory) where a recipient would be likely to look for\n    such a notice.\n  </p>\n  <p>You may add additional accurate notices of copyright ownership.</p>\n</blockquote>\n</body>\n</html>"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.test.driver/build.properties",
    "content": "#\n# Copyright (c) 2022 Eurotech and/or its affiliates and others\n# \n# This program and the accompanying materials are made\n# available under the terms of the Eclipse Public License 2.0\n# which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n# SPDX-License-Identifier: EPL-2.0\n# \n# Contributors:\n#  Eurotech\n#\nbin.includes = .,\\\n               META-INF/,\\\n               OSGI-INF/,\\\n               about.html,\\\n               about_files/\nsource.. = src/main/java/\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.test.driver/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>test-util</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.kura.util.test.driver</artifactId>\n    <packaging>eclipse-plugin</packaging>\n\n    <properties>\n        <kura.basedir>${project.basedir}/../..</kura.basedir>\n        <sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <build>\n        <plugins>\n        <plugin>\n            <groupId>de.dentrassi.maven</groupId>\n            <artifactId>osgi-dp</artifactId>\n            <version>${osgi-dp-plugin-version}</version>\n            <executions>\n                <execution>\n                    <goals>\n                        <goal>build</goal>\n                    </goals>\n                </execution>\n            </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.test.driver/src/main/java/org/eclipse/kura/util/test/driver/ChannelDescriptorTestDriver.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2022 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *  Red Hat Inc\n ******************************************************************************/\npackage org.eclipse.kura.util.test.driver;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\nimport org.eclipse.kura.channel.ChannelRecord;\nimport org.eclipse.kura.channel.listener.ChannelListener;\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.configuration.metatype.AD;\nimport org.eclipse.kura.core.configuration.metatype.Tad;\nimport org.eclipse.kura.core.configuration.metatype.Toption;\nimport org.eclipse.kura.core.configuration.metatype.Tscalar;\nimport org.eclipse.kura.driver.ChannelDescriptor;\nimport org.eclipse.kura.driver.Driver;\nimport org.eclipse.kura.driver.PreparedRead;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ChannelDescriptorTestDriver implements Driver, ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(ChannelDescriptorTestDriver.class);\n\n    public void activate() {\n        logger.info(\"activating\");\n    }\n\n    public void update() {\n        logger.info(\"updating\");\n    }\n\n    public void deactivate() {\n        logger.info(\"deactivating\");\n    }\n\n    @Override\n    public void connect() throws ConnectionException {\n        throw new ConnectionException(\"Connection is not supported\");\n    }\n\n    @Override\n    public void disconnect() throws ConnectionException {\n        throw new ConnectionException(\"Disconnection is not supported\");\n    }\n\n    @Override\n    public ChannelDescriptor getChannelDescriptor() {\n        return new ChannelDescriptorImpl();\n    }\n\n    @Override\n    public void read(List<ChannelRecord> records) throws ConnectionException {\n        throw new ConnectionException(\"Read is not supported\");\n\n    }\n\n    @Override\n    public void registerChannelListener(Map<String, Object> channelConfig, ChannelListener listener)\n            throws ConnectionException {\n        throw new ConnectionException(\"Register channle listener is not supported\");\n\n    }\n\n    @Override\n    public void unregisterChannelListener(ChannelListener listener) throws ConnectionException {\n        throw new ConnectionException(\"Unregister channle listener is not supported\");\n\n    }\n\n    @Override\n    public void write(List<ChannelRecord> records) throws ConnectionException {\n        throw new ConnectionException(\"Write is not supported\");\n\n    }\n\n    @Override\n    public PreparedRead prepareRead(List<ChannelRecord> records) {\n        return new PreparedRead() {\n\n            @Override\n            public void close() throws Exception {\n                // nothing to close\n            }\n\n            @Override\n            public List<ChannelRecord> getChannelRecords() {\n                return records;\n            }\n\n            @Override\n            public List<ChannelRecord> execute() throws ConnectionException {\n                read(records);\n                return records;\n            }\n        };\n    }\n\n    private static class ChannelDescriptorImpl implements ChannelDescriptor {\n\n        private final List<AD> ads = new ArrayList<>();\n\n        public ChannelDescriptorImpl() {\n            generateAds(Tscalar.STRING, \"foo\", \"bar\", \"foo\");\n            generateAds(Tscalar.BOOLEAN, \"true\");\n            generateAds(Tscalar.BYTE, \"10\", \"20\", \"15\");\n            generateAds(Tscalar.CHAR, \"b\", \"l\", \"c\");\n            generateAds(Tscalar.DOUBLE, \"13.5\", \"20.5\", \"16\");\n            generateAds(Tscalar.FLOAT, \"13.5\", \"20.5\", \"16\");\n            generateAds(Tscalar.INTEGER, \"-200000\", \"300000\", \"10\");\n            generateAds(Tscalar.LONG, \"\" + ((long) Integer.MIN_VALUE - 10000), \"\" + ((long) Integer.MAX_VALUE + 10000),\n                    \"2\");\n            // generateAds(Tscalar.PASSWORD, \"foo\", \"bar\", \"foo\");\n            generateAds(Tscalar.SHORT, \"-20000\", \"20000\", \"1\");\n\n            generateOptionAd(Tscalar.STRING, \"foo\", \"bar\", \"baz\");\n            generateOptionAd(Tscalar.BYTE, \"10\", \"20\", \"30\");\n            generateOptionAd(Tscalar.CHAR, \"a\", \"b\", \"c\");\n            generateOptionAd(Tscalar.DOUBLE, \"-10.21\", \"20.123123\", \"30.23123\");\n            generateOptionAd(Tscalar.FLOAT, \"10.4\", \"-12.4\", \"0.5\");\n            generateOptionAd(Tscalar.INTEGER, \"-200000\", \"300000\", \"10\");\n            generateOptionAd(Tscalar.LONG, \"\" + ((long) Integer.MIN_VALUE - 10000),\n                    \"\" + ((long) Integer.MAX_VALUE + 10000), \"-34\");\n            generateOptionAd(Tscalar.SHORT, \"-20000\", \"20000\", \"1\");\n        }\n\n        private AdBuilder createBuilder(final Tscalar type, final String defaultValue) {\n            return new AdBuilder(type + \".prop\", type).withName(type + \" property\")\n                    .withDescription(\"A \" + type + \" property\").withDefaultValue(defaultValue);\n        }\n\n        private void generateAds(final Tscalar type, final String defaultValue) {\n            final AdBuilder builder = createBuilder(type, defaultValue);\n\n            ads.add(builder.build());\n\n            ads.add(builder.duplicate().withId(builder.id + \"not.required\")\n                    .withName(builder.name.orElse(\"\") + \" not required\")\n                    .withDescription(builder.description.orElse(\"\") + \" not required\").withoutRequired()\n                    .withoutDefaultValue().build());\n\n        }\n\n        private void generateAds(final Tscalar type, final String min, final String max, final String defaultValue) {\n            generateAds(type, defaultValue);\n\n            final AdBuilder builder = createBuilder(type, defaultValue);\n\n            ads.add(builder.duplicate().withId(builder.id + \".min.max\")\n                    .withName(builder.name.orElse(\"\") + \" with min and max\")\n                    .withDescription(builder.description.orElse(\"\") + \" with min : \" + min + \" and max : \" + max)\n                    .withMin(min).withMax(max).build());\n        }\n\n        private void generateOptionAd(final Tscalar type, final String... values) {\n            final AdBuilder builder = new AdBuilder(type + \".options\", type).withDefaultValue(values[0])\n                    .withName(type + \" property with options\").withDescription(\"A \" + type + \" property wit options\")\n                    .withDefaultValue(values[0]);\n\n            for (int i = 0; i < values.length; i++) {\n                builder.withOption(\"Choice \" + i + \", value : \" + values[i], values[i]);\n            }\n\n            ads.add(builder.build());\n        }\n\n        @Override\n        public Object getDescriptor() {\n            return ads;\n        }\n\n    }\n\n    private static class AdBuilder {\n\n        private String id;\n        private Tscalar type;\n        private Optional<Integer> cardinality = Optional.empty();\n        private Optional<String> defaultValue = Optional.empty();\n        private Optional<String> description = Optional.empty();\n        private Optional<String> max = Optional.empty();\n        private Optional<String> min = Optional.empty();\n        private Optional<String> name = Optional.empty();\n        private List<Toption> options = new ArrayList<>();\n        private Optional<Boolean> required = Optional.empty();\n\n        public AdBuilder(final String id, final Tscalar type) {\n            this.id = id;\n            this.type = type;\n        }\n\n        public AdBuilder(final AdBuilder other) {\n            this.id = other.id;\n            this.type = other.type;\n            this.cardinality = other.cardinality;\n            this.defaultValue = other.defaultValue;\n            this.description = other.description;\n            this.max = other.max;\n            this.min = other.min;\n            this.name = other.name;\n            this.options = other.options;\n            this.required = other.required;\n        }\n\n        public AdBuilder withId(final String id) {\n            this.id = id;\n            return this;\n        }\n\n        public AdBuilder withType(final Tscalar type) {\n            this.type = type;\n            return this;\n        }\n\n        public AdBuilder withCardinality(final int cardinality) {\n            this.cardinality = Optional.of(cardinality);\n            return this;\n        }\n\n        public AdBuilder withoutCardinality() {\n            this.cardinality = Optional.empty();\n            return this;\n        }\n\n        public AdBuilder withDefaultValue(final String defaultValue) {\n            this.defaultValue = Optional.of(defaultValue);\n            return this;\n        }\n\n        public AdBuilder withoutDefaultValue() {\n            this.defaultValue = Optional.empty();\n            return this;\n        }\n\n        public AdBuilder withDescription(final String description) {\n            this.description = Optional.of(description);\n            return this;\n        }\n\n        public AdBuilder withoutDescription() {\n            this.description = Optional.empty();\n            return this;\n        }\n\n        public AdBuilder withMax(final String max) {\n            this.max = Optional.of(max);\n            return this;\n        }\n\n        public AdBuilder witoutMax() {\n            this.max = Optional.empty();\n            return this;\n        }\n\n        public AdBuilder withMin(final String min) {\n            this.max = Optional.of(min);\n            return this;\n        }\n\n        public AdBuilder withoutMin() {\n            this.max = Optional.empty();\n            return this;\n        }\n\n        public AdBuilder withName(final String name) {\n            this.name = Optional.of(name);\n            return this;\n        }\n\n        public AdBuilder withoutName() {\n            this.name = Optional.empty();\n            return this;\n        }\n\n        public AdBuilder withOption(final String label, final String value) {\n            final Toption option = new Toption();\n\n            option.setLabel(label);\n            option.setValue(value);\n            options.add(option);\n\n            return this;\n        }\n\n        public AdBuilder withRequired(final boolean required) {\n            this.required = Optional.of(required);\n            return this;\n        }\n\n        public AdBuilder withoutRequired() {\n            this.required = Optional.empty();\n            return this;\n        }\n\n        public AdBuilder duplicate() {\n            return new AdBuilder(this);\n        }\n\n        public AD build() {\n            final Tad ad = new Tad();\n\n            ad.setId(id);\n            ad.setType(type);\n\n            cardinality.ifPresent(ad::setCardinality);\n            defaultValue.ifPresent(ad::setDefault);\n            description.ifPresent(ad::setDescription);\n            max.ifPresent(ad::setMax);\n            min.ifPresent(ad::setMin);\n            name.ifPresent(ad::setName);\n            ad.getOption().addAll(this.options);\n            required.ifPresent(ad::setRequired);\n\n            return ad;\n        }\n    }\n\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.wire.test/META-INF/MANIFEST.MF",
    "content": "Manifest-Version: 1.0\nBundle-ManifestVersion: 2\nBundle-Name: Wire Component test utilities\nBundle-SymbolicName: org.eclipse.kura.util.wire.test;singleton:=true\nBundle-Version: 6.0.0.qualifier\nBundle-Vendor: EUROTECH\nBundle-Category: Kura Wires\nRequire-Capability: osgi.ee;filter:=\"(&(osgi.ee=JavaSE)(version=21))\"\nBundle-ActivationPolicy: lazy\nBundle-ClassPath: .\nImport-Package: org.eclipse.kura;version=\"[1.5,2.0)\",\n org.eclipse.kura.configuration;version=\"[1.1,2.0)\",\n org.eclipse.kura.configuration.metatype;version=\"[1.1,2.0)\",\n org.eclipse.kura.type;version=\"1.1.0\",\n org.eclipse.kura.util.wire.test;version=\"1.1.0\",\n org.eclipse.kura.wire;version=\"[2.0,3.0)\",\n org.eclipse.kura.wire.graph;version=\"1.0.0\",\n org.osgi.framework;version=\"1.8.0\",\n org.osgi.service.cm;version=\"1.5.0\",\n org.osgi.service.component;version=\"1.3.0\",\n org.osgi.service.wireadmin;version=\"1.0.1\",\n org.osgi.util.tracker;version=\"1.5.0\",\n org.slf4j;version=\"1.7.25\"\nService-Component: OSGI-INF/*.xml\nExport-Package: org.eclipse.kura.util.wire.test;version=\"1.1.0\"\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.wire.test/OSGI-INF/TestEmitterReceiver.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2020 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<scr:component xmlns:scr=\"http://www.osgi.org/xmlns/scr/v1.1.0\" activate=\"activate\" configuration-policy=\"require\" enabled=\"true\" immediate=\"true\" modified=\"updated\" name=\"org.eclipse.kura.util.wire.test.TestEmitterReceiver\">\n\t<implementation\n\t\tclass=\"org.eclipse.kura.util.wire.test.TestEmitterReceiver\" />\n\t<property\n\t\tname=\"service.pid\"\n\t\tvalue=\"com.eurotech.framework.wire.AvroSerializer\" />\n\t<property\n\t\tname=\"kura.ui.service.hide\"\n\t\ttype=\"Boolean\"\n\t\tvalue=\"true\" />\n\t<property\n\t\tname=\"input.cardinality.minimum\"\n\t\ttype=\"Integer\"\n\t\tvalue=\"1\" />\n\t<property\n\t\tname=\"input.cardinality.maximum\"\n\t\ttype=\"Integer\"\n\t\tvalue=\"1\" />\n\t<property\n\t\tname=\"input.cardinality.default\"\n\t\ttype=\"Integer\"\n\t\tvalue=\"1\" />\n\t<property\n\t\tname=\"output.cardinality.minimum\"\n\t\ttype=\"Integer\"\n\t\tvalue=\"1\" />\n\t<property\n\t\tname=\"output.cardinality.maximum\"\n\t\ttype=\"Integer\"\n\t\tvalue=\"1\" />\n\t<property\n\t\tname=\"output.cardinality.default\"\n\t\ttype=\"Integer\"\n\t\tvalue=\"1\" />\n\n\t<service>\n\t\t<provide\n\t\t\tinterface=\"org.eclipse.kura.configuration.ConfigurableComponent\" />\n\t\t<provide interface=\"org.eclipse.kura.wire.WireComponent\" />\n\t\t<provide interface=\"org.osgi.service.wireadmin.Consumer\" />\n\t\t<provide interface=\"org.osgi.service.wireadmin.Producer\" />\n\t</service>\n\t<reference\n\t\tbind=\"bindWireHelperService\"\n\t\tcardinality=\"1..1\"\n\t\tinterface=\"org.eclipse.kura.wire.WireHelperService\"\n\t\tname=\"WireHelperService\"\n\t\tpolicy=\"static\" />\n</scr:component>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.wire.test/OSGI-INF/metatype/org.eclipse.kura.util.wire.test.TestEmitterReceiver.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2020 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<MetaData\n\txmlns=\"http://www.osgi.org/xmlns/metatype/v1.2.0\"\n\tlocalization=\"en_us\">\n\t<OCD\n\t\tid=\"org.eclipse.kura.util.wire.test.TestEmitterReceiver\"\n\t\tname=\"Test Emitter Receiver\">\n\n\t</OCD>\n\t<Designate\n\t\tfactoryPid=\"org.eclipse.kura.util.wire.test.TestEmitterReceiver\">\n\t\t<Object\n\t\t\tocdref=\"org.eclipse.kura.util.wire.test.TestEmitterReceiver\" />\n\t</Designate>\n</MetaData>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.wire.test/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.wire.test/build.properties",
    "content": "#\n#  Copyright (c) 2020, 2020 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#   Eurotech\n#\nsource.. = src/main/java/\nbin.includes = META-INF/,\\\n               OSGI-INF/,\\\n               .\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.wire.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2020, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n   xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>org.eclipse.kura</groupId>\n    <artifactId>test-util</artifactId>\n    <version>6.0.0-SNAPSHOT</version>\n  </parent>\n\n  <artifactId>org.eclipse.kura.util.wire.test</artifactId>\n  <packaging>eclipse-plugin</packaging>\n\n  <properties>\n    <kura.basedir>${project.basedir}/../..</kura.basedir>\n  </properties>\n\n</project>\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.wire.test/src/main/java/org/eclipse/kura/util/wire/test/GraphBuilder.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.util.wire.test;\n\nimport static org.eclipse.kura.util.wire.test.WireTestUtil.componentsActivated;\nimport static org.eclipse.kura.util.wire.test.WireTestUtil.wiresConnected;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.stream.Collectors;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ComponentConfiguration;\nimport org.eclipse.kura.configuration.metatype.OCD;\nimport org.eclipse.kura.wire.graph.MultiportWireConfiguration;\nimport org.eclipse.kura.wire.graph.WireComponentConfiguration;\nimport org.eclipse.kura.wire.graph.WireGraphConfiguration;\nimport org.eclipse.kura.wire.graph.WireGraphService;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.service.cm.ConfigurationAdmin;\n\npublic class GraphBuilder {\n\n    private static final String TEST_EMITTER_RECEIVER_FACTORY_PID = \"org.eclipse.kura.util.wire.test.TestEmitterReceiver\";\n\n    private static final String PROP_WIRE_COMP_POS_X = \"position.x\";\n    private static final String PROP_WIRE_COMP_POS_Y = \"position.y\";\n    private static final String PROP_WIRE_COMP_IN_CNT = \"inputPortCount\";\n    private static final String PROP_WIRE_COMP_OUT_CNT = \"outputPortCount\";\n\n    private final List<WireComponentConfiguration> configurations = new ArrayList<>();\n    private final Set<MultiportWireConfiguration> wires = new HashSet<>();\n\n    private final Map<String, Object> trackedObjects = new HashMap<>();\n\n    public GraphBuilder addTestEmitterReceiver(final String pid) {\n        return addWireComponent(pid, TEST_EMITTER_RECEIVER_FACTORY_PID);\n    }\n\n    public GraphBuilder addWireComponent(final String pid, final String factoryPid) {\n        return addWireComponent(pid, factoryPid, Collections.emptyMap(), 1, 1);\n    }\n\n    public GraphBuilder addWireComponent(final String pid, final String factoryPid, final int inputPortCount,\n            final int outputPortCount) {\n        return addWireComponent(pid, factoryPid, Collections.emptyMap(), inputPortCount, outputPortCount);\n    }\n\n    public GraphBuilder addWireComponent(final String pid, final String factoryPid,\n            final Map<String, Object> configuration, final int inputPortCount, final int outputPortCount) {\n        Map<String, Object> props = new HashMap<>();\n        props.put(PROP_WIRE_COMP_POS_X, 0f);\n        props.put(PROP_WIRE_COMP_POS_Y, 0f);\n        props.put(PROP_WIRE_COMP_IN_CNT, inputPortCount);\n        props.put(PROP_WIRE_COMP_OUT_CNT, outputPortCount);\n        return addWireComponent(pid, factoryPid, configuration, props);\n    }\n\n    public GraphBuilder addWireComponent(final String pid, final String factoryPid,\n            final Map<String, Object> configuration, final Map<String, Object> renderingProperties) {\n\n        final ComponentConfiguration componentConfiguration = new ComponentConfiguration() {\n\n            @Override\n            public String getPid() {\n                return pid;\n            }\n\n            @Override\n            public OCD getDefinition() {\n                return null;\n            }\n\n            @Override\n            public Map<String, Object> getConfigurationProperties() {\n                Map<String, Object> properties = new HashMap<>(configuration);\n                properties.put(ConfigurationAdmin.SERVICE_FACTORYPID, factoryPid);\n                return properties;\n            }\n        };\n\n        final WireComponentConfiguration wireComponentConfiguration = new WireComponentConfiguration(\n                componentConfiguration, renderingProperties);\n\n        this.configurations.add(wireComponentConfiguration);\n\n        return this;\n    }\n\n    public GraphBuilder addWire(final String emitterPid, final String receiverPid) {\n        return addWire(emitterPid, 0, receiverPid, 0);\n    }\n\n    public GraphBuilder addWire(final String emitterPid, final String receiverPid, final int receiverPort) {\n        return addWire(emitterPid, 0, receiverPid, receiverPort);\n    }\n\n    public GraphBuilder addWire(final String emitterPid, final int emitterPort, final String receiverPid,\n            final int receiverPort) {\n        final MultiportWireConfiguration multiportWireConfiguration = new MultiportWireConfiguration(emitterPid,\n                receiverPid, emitterPort, receiverPort);\n        wires.add(multiportWireConfiguration);\n\n        return this;\n    }\n\n    public CompletableFuture<Void> replaceExistingGraph(final BundleContext context,\n            final WireGraphService wireGraphService) throws KuraException {\n\n        final WireGraphConfiguration wireGraph = new WireGraphConfiguration(this.configurations,\n                new ArrayList<>(this.wires));\n\n        wireGraphService.delete();\n\n        final Set<String> expectedPids = this.configurations.stream().map(c -> c.getConfiguration().getPid())\n                .collect(Collectors.toSet());\n\n        final CompletableFuture<Void> result = wiresConnected(context, this.wires)\n                .thenCompose(ok -> componentsActivated(context, expectedPids, trackedObjects::put));\n\n        wireGraphService.update(wireGraph);\n\n        return result;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public <T> T getTrackedWireComponent(final String pid) {\n        return (T) trackedObjects.get(pid);\n    }\n\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.wire.test/src/main/java/org/eclipse/kura/util/wire/test/TestEmitterReceiver.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.util.wire.test;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.function.Consumer;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.eclipse.kura.type.TypedValue;\nimport org.eclipse.kura.wire.WireComponent;\nimport org.eclipse.kura.wire.WireEmitter;\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.eclipse.kura.wire.WireHelperService;\nimport org.eclipse.kura.wire.WireReceiver;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.eclipse.kura.wire.graph.MultiportWireSupport;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.service.component.ComponentContext;\nimport org.osgi.service.wireadmin.Wire;\nimport org.slf4j.LoggerFactory;\n\npublic class TestEmitterReceiver implements WireEmitter, WireReceiver, ConfigurableComponent {\n\n    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestEmitterReceiver.class);\n\n    private WireHelperService wireHelperService;\n    private MultiportWireSupport wireSupport;\n\n    private Consumer<WireEnvelope> consumer;\n\n    protected void activate(final ComponentContext componentContext, final Map<String, Object> properties) {\n        logger.info(\"activating...\");\n        this.wireSupport = (MultiportWireSupport) this.wireHelperService.newWireSupport(this,\n                getWireComponentServiceReference(componentContext));\n        logger.info(\"activating...done\");\n    }\n\n    public void updated(final Map<String, Object> properties) {\n        logger.info(\"updating...\");\n        logger.info(\"updating...done\");\n    }\n\n    protected void bindWireHelperService(WireHelperService wireHelperService) {\n        this.wireHelperService = wireHelperService;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private ServiceReference<WireComponent> getWireComponentServiceReference(ComponentContext componentContext) {\n        return (ServiceReference<WireComponent>) componentContext.getServiceReference();\n    }\n\n    @Override\n    public void consumersConnected(Wire[] arg0) {\n        this.wireSupport.consumersConnected(arg0);\n    }\n\n    @Override\n    public Object polled(Wire arg0) {\n        return this.wireSupport.polled(arg0);\n    }\n\n    @Override\n    public void producersConnected(Wire[] arg0) {\n        this.wireSupport.producersConnected(arg0);\n    }\n\n    @Override\n    public void updated(Wire arg0, Object arg1) {\n        this.wireSupport.updated(arg0, arg1);\n    }\n\n    @Override\n    public void onWireReceive(WireEnvelope arg0) {\n        this.consumer.accept(arg0);\n    }\n\n    public MultiportWireSupport getWireSupport() {\n        return this.wireSupport;\n    }\n\n    public void setConsumer(Consumer<WireEnvelope> consumer) {\n        this.consumer = consumer;\n    }\n\n    public CompletableFuture<WireEnvelope> nextEnvelope() {\n        final CompletableFuture<WireEnvelope> result = new CompletableFuture<>();\n\n        setConsumer(result::complete);\n\n        return result;\n    }\n\n    public void emit(final WireEnvelope envelope, final int port) {\n        this.wireSupport.getEmitterPorts().get(port).emit(envelope);\n    }\n\n    public void emit(final WireEnvelope envelope) {\n        this.emit(envelope, 0);\n    }\n\n    public void emit(final List<WireRecord> records, final int port) {\n        this.emit(this.wireSupport.createWireEnvelope(records), port);\n    }\n\n    public void emit(final List<WireRecord> records) {\n        this.emit(records, 0);\n    }\n\n    public void emit(final WireRecord record, final int port) {\n        this.emit(Collections.singletonList(record), port);\n    }\n\n    public void emit(final WireRecord record) {\n        this.emit(record, 0);\n    }\n\n    public void emit(final Map<String, TypedValue<?>> recordProperties, final int port) {\n        this.emit(Collections.singletonList(new WireRecord(recordProperties)), port);\n    }\n\n    public void emit(final Map<String, TypedValue<?>> recordProperties) {\n        this.emit(recordProperties, 0);\n    }\n\n    public void emit(final String propertyKey, final TypedValue<?> value, final int port) {\n        this.emit(Collections.singletonMap(propertyKey, value), port);\n    }\n\n    public void emit(final String propertyKey, final TypedValue<?> value) {\n        this.emit(propertyKey, value, 0);\n    }\n\n    public void emit(final int port) {\n        this.emit(Collections.emptyMap(), port);\n    }\n\n    public void emit() {\n        this.emit(0);\n    }\n}\n"
  },
  {
    "path": "kura/test-util/org.eclipse.kura.util.wire.test/src/main/java/org/eclipse/kura/util/wire/test/WireTestUtil.java",
    "content": "/*******************************************************************************\n * Copyright (c) 2020, 2021 Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n ******************************************************************************/\npackage org.eclipse.kura.util.wire.test;\n\nimport java.util.Dictionary;\nimport java.util.HashSet;\nimport java.util.Hashtable;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\nimport java.util.function.BiConsumer;\n\nimport org.eclipse.kura.KuraException;\nimport org.eclipse.kura.configuration.ConfigurationService;\nimport org.eclipse.kura.type.TypedValue;\nimport org.eclipse.kura.wire.WireComponent;\nimport org.eclipse.kura.wire.WireEnvelope;\nimport org.eclipse.kura.wire.WireRecord;\nimport org.eclipse.kura.wire.graph.Constants;\nimport org.eclipse.kura.wire.graph.MultiportWireConfiguration;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.Filter;\nimport org.osgi.framework.FrameworkUtil;\nimport org.osgi.framework.InvalidSyntaxException;\nimport org.osgi.framework.ServiceReference;\nimport org.osgi.framework.ServiceRegistration;\nimport org.osgi.service.wireadmin.Wire;\nimport org.osgi.service.wireadmin.WireAdminEvent;\nimport org.osgi.service.wireadmin.WireAdminListener;\nimport org.osgi.service.wireadmin.WireConstants;\nimport org.osgi.util.tracker.ServiceTracker;\nimport org.osgi.util.tracker.ServiceTrackerCustomizer;\n\npublic final class WireTestUtil {\n\n    private WireTestUtil() {\n    }\n\n    public static CompletableFuture<Void> updateWireComponentConfiguration(\n            final ConfigurationService configurationService, final String pid, final Map<String, Object> properties) {\n\n        try {\n            final BundleContext bundleContext = FrameworkUtil.getBundle(WireTestUtil.class).getBundleContext();\n\n            final CompletableFuture<Void> result = new CompletableFuture<>();\n\n            final Filter filter = FrameworkUtil\n                    .createFilter(\"(&(objectClass=org.eclipse.kura.wire.WireComponent)(kura.service.pid=\" + pid + \"))\");\n\n            final ServiceTracker<WireComponent, WireComponent> tracker = new ServiceTracker<>(bundleContext, filter,\n                    new ServiceTrackerCustomizer<WireComponent, WireComponent>() {\n\n                        @Override\n                        public WireComponent addingService(final ServiceReference<WireComponent> ref) {\n                            return bundleContext.getService(ref);\n                        }\n\n                        @Override\n                        public void modifiedService(final ServiceReference<WireComponent> ref,\n                                final WireComponent comp) {\n                            result.complete(null);\n                        }\n\n                        @Override\n                        public void removedService(final ServiceReference<WireComponent> ref,\n                                final WireComponent comp) {\n                            bundleContext.ungetService(ref);\n                        }\n                    });\n\n            tracker.open();\n\n            configurationService.updateConfiguration(pid, properties);\n\n            return result.whenComplete((ok, ex) -> tracker.close());\n        } catch (final Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static CompletableFuture<Void> updateComponentConfiguration(final ConfigurationService configurationService,\n            final String pid, final Map<String, Object> properties) throws KuraException, InvalidSyntaxException {\n\n        final CompletableFuture<Void> result = modified(\"(kura.service.pid=\" + pid + \")\");\n\n        configurationService.updateConfiguration(pid, properties);\n\n        return result;\n    }\n\n    public static CompletableFuture<Void> modified(final String filter) throws KuraException, InvalidSyntaxException {\n\n        final CompletableFuture<Void> result = new CompletableFuture<Void>();\n        final BundleContext context = FrameworkUtil.getBundle(WireTestUtil.class).getBundleContext();\n\n        final ServiceTracker<?, ?> tracker = new ServiceTracker<Object, Object>(context,\n                FrameworkUtil.createFilter(filter), new ServiceTrackerCustomizer<Object, Object>() {\n\n                    @Override\n                    public Object addingService(ServiceReference<Object> reference) {\n                        return context.getService(reference);\n                    }\n\n                    @Override\n                    public void modifiedService(ServiceReference<Object> reference, Object service) {\n                        result.complete(null);\n                    }\n\n                    @Override\n                    public void removedService(ServiceReference<Object> reference, Object service) {\n                        context.ungetService(reference);\n                    }\n                });\n\n        tracker.open();\n\n        return result.whenComplete((ok, ex) -> tracker.close());\n    }\n\n    public static <T> CompletableFuture<T> trackService(final Class<T> classz, final Optional<String> filterString)\n            throws KuraException, InvalidSyntaxException {\n\n        final Filter filter;\n\n        if (filterString.isPresent()) {\n            filter = FrameworkUtil.createFilter(\"(&\" + filterString.get() + \"(objectClass=\" + classz.getName() + \"))\");\n        } else {\n            filter = FrameworkUtil.createFilter(\"(objectClass=\" + classz.getName() + \")\");\n        }\n\n        final CompletableFuture<T> result = new CompletableFuture<>();\n        final BundleContext context = FrameworkUtil.getBundle(WireTestUtil.class).getBundleContext();\n\n        final ServiceTracker<T, T> tracker = new ServiceTracker<T, T>(context, filter,\n                new ServiceTrackerCustomizer<T, T>() {\n\n                    @Override\n                    public T addingService(ServiceReference<T> reference) {\n                        final T service = context.getService(reference);\n\n                        result.complete(service);\n\n                        return service;\n                    }\n\n                    @Override\n                    public void modifiedService(ServiceReference<T> reference, T service) {\n                        // do nothing\n                    }\n\n                    @Override\n                    public void removedService(ServiceReference<T> reference, T service) {\n                        context.ungetService(reference);\n                    }\n                });\n\n        tracker.open();\n\n        return result.whenComplete((ok, ex) -> tracker.close());\n    }\n\n    public static <T> CompletableFuture<T> createFactoryConfiguration(final ConfigurationService configurationService,\n            final Class<T> classz, final String pid, final String factoryPid, final Map<String, Object> properties) {\n        try {\n            final BundleContext bundleContext = FrameworkUtil.getBundle(WireTestUtil.class).getBundleContext();\n\n            final CompletableFuture<T> result = new CompletableFuture<>();\n\n            final Filter filter = FrameworkUtil\n                    .createFilter(\"(&(objectClass=\" + classz.getName() + \")(kura.service.pid=\" + pid + \"))\");\n\n            final ServiceTracker<T, T> tracker = new ServiceTracker<>(bundleContext, filter,\n                    new ServiceTrackerCustomizer<T, T>() {\n\n                        @Override\n                        public T addingService(final ServiceReference<T> ref) {\n                            final T obj = bundleContext.getService(ref);\n\n                            result.complete(obj);\n\n                            return obj;\n\n                        }\n\n                        @Override\n                        public void modifiedService(final ServiceReference<T> ref, final T comp) {\n                            // nothing to do\n                        }\n\n                        @Override\n                        public void removedService(final ServiceReference<T> ref, final T comp) {\n                            bundleContext.ungetService(ref);\n                        }\n                    });\n\n            tracker.open();\n\n            configurationService.createFactoryConfiguration(factoryPid, pid, properties, false);\n\n            return result.whenComplete((ok, ex) -> tracker.close());\n        } catch (final Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static CompletableFuture<Void> deleteFactoryConfiguration(final ConfigurationService configurationService,\n            final String pid) {\n\n        try {\n            final BundleContext bundleContext = FrameworkUtil.getBundle(WireTestUtil.class).getBundleContext();\n\n            final CompletableFuture<Void> tracked = new CompletableFuture<>();\n            final CompletableFuture<Void> removed = new CompletableFuture<>();\n\n            final Filter filter = FrameworkUtil.createFilter(\"(kura.service.pid=\" + pid + \")\");\n\n            final ServiceTracker<Object, Object> tracker = new ServiceTracker<>(bundleContext, filter,\n                    new ServiceTrackerCustomizer<Object, Object>() {\n\n                        @Override\n                        public Object addingService(final ServiceReference<Object> ref) {\n                            tracked.complete(null);\n                            return bundleContext.getService(ref);\n                        }\n\n                        @Override\n                        public void modifiedService(final ServiceReference<Object> ref, final Object comp) {\n                            // nothing to do\n                        }\n\n                        @Override\n                        public void removedService(final ServiceReference<Object> ref, final Object comp) {\n                            removed.complete(null);\n                            bundleContext.ungetService(ref);\n                        }\n                    });\n\n            tracker.open();\n\n            try {\n                tracked.get(30, TimeUnit.SECONDS);\n            } catch (final Exception e) {\n                tracker.close();\n                throw e;\n            }\n\n            configurationService.deleteFactoryConfiguration(pid, false);\n\n            return removed.whenComplete((ok, ex) -> tracker.close());\n        } catch (final Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static WireEnvelope unwrapEnvelope(final Future<WireEnvelope> wireEnvelope)\n            throws InterruptedException, ExecutionException, TimeoutException {\n        return wireEnvelope.get(30, TimeUnit.SECONDS);\n    }\n\n    private static WireRecord unwrapRecord(final Future<WireEnvelope> wireEnvelope, final int index)\n            throws InterruptedException, ExecutionException, TimeoutException {\n        return unwrapEnvelope(wireEnvelope).getRecords().get(index);\n    }\n\n    public static TypedValue<?> unwrapProperty(final Future<WireEnvelope> envelope, final String key)\n            throws InterruptedException, ExecutionException, TimeoutException {\n        return unwrapRecord(envelope, 0).getProperties().get(key);\n    }\n\n    public static CompletableFuture<Void> componentsActivated(final BundleContext context,\n            final Set<String> expectedPids, final BiConsumer<String, Object> trackedObjectConsumer) {\n\n        if (expectedPids.isEmpty()) {\n            return CompletableFuture.completedFuture(null);\n        }\n\n        final Set<String> tracked = new HashSet<>();\n\n        final CompletableFuture<Void> result = new CompletableFuture<>();\n\n        final ServiceTracker<WireComponent, WireComponent> tracker = new ServiceTracker<>(context, WireComponent.class,\n                new ServiceTrackerCustomizer<WireComponent, WireComponent>() {\n\n                    @Override\n                    public WireComponent addingService(final ServiceReference<WireComponent> ref) {\n\n                        final WireComponent comp = context.getService(ref);\n\n                        final String kuraServicePid = (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID);\n\n                        tracked.add(kuraServicePid);\n                        trackedObjectConsumer.accept(kuraServicePid, comp);\n\n                        if (tracked.containsAll(expectedPids)) {\n                            result.complete(null);\n                        }\n\n                        return comp;\n                    }\n\n                    @Override\n                    public void modifiedService(final ServiceReference<WireComponent> ref, final WireComponent comp) {\n                        // no need\n                    }\n\n                    @Override\n                    public void removedService(final ServiceReference<WireComponent> ref, final WireComponent comp) {\n                        context.ungetService(ref);\n                    }\n                });\n\n        tracker.open();\n\n        return result.whenComplete((ok, ex) -> tracker.close());\n    }\n\n    public static CompletableFuture<Void> wiresConnected(final BundleContext context,\n            final Set<MultiportWireConfiguration> expected) {\n\n        if (expected.isEmpty()) {\n            return CompletableFuture.completedFuture(null);\n        }\n\n        final Set<MultiportWireConfiguration> tracked = new HashSet<>();\n\n        final CompletableFuture<Void> result = new CompletableFuture<>();\n\n        final WireAdminListener listener = e -> {\n            final Wire wire = e.getWire();\n\n            if (e.getType() != WireAdminEvent.WIRE_CONNECTED) {\n                return;\n            }\n\n            tracked.add(fromWire(wire));\n\n            if (tracked.containsAll(expected)) {\n                result.complete(null);\n            }\n\n        };\n\n        final Dictionary<String, Object> listenerProperties = new Hashtable<>();\n        listenerProperties.put(WireConstants.WIREADMIN_EVENTS, WireAdminEvent.WIRE_CONNECTED);\n\n        final ServiceRegistration<WireAdminListener> registration = context.registerService(WireAdminListener.class,\n                listener, listenerProperties);\n\n        return result.whenComplete((ok, ex) -> registration.unregister());\n\n    }\n\n    private static MultiportWireConfiguration fromWire(final Wire wire) {\n        @SuppressWarnings(\"unchecked\")\n        final Dictionary<String, ?> properties = wire.getProperties();\n\n        final String emitterPid = (String) properties.get(Constants.EMITTER_KURA_SERVICE_PID_PROP_NAME.value());\n        final int emitterPort = (Integer) properties.get(Constants.WIRE_EMITTER_PORT_PROP_NAME.value());\n        final String receiverPid = (String) properties.get(Constants.RECEIVER_KURA_SERVICE_PID_PROP_NAME.value());\n        final int receiverPort = (Integer) properties.get(Constants.WIRE_RECEIVER_PORT_PROP_NAME.value());\n\n        return new MultiportWireConfiguration(emitterPid, receiverPid, emitterPort, receiverPort);\n    }\n\n}\n"
  },
  {
    "path": "kura/test-util/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2020, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n   xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n\n  <parent>\n    <groupId>org.eclipse.kura</groupId>\n    <artifactId>kura</artifactId>\n    <version>6.0.0-SNAPSHOT</version>\n  </parent>\n\n  <artifactId>test-util</artifactId>\n  <packaging>pom</packaging>\n\n  <properties>\n    <kura.basedir>${project.basedir}/../..</kura.basedir>\n  </properties>\n\n  <modules>\n    <module>org.eclipse.kura.util.wire.test</module>\n    <module>org.eclipse.kura.core.testutil</module>\n    <module>org.eclipse.kura.test</module>\n    <module>org.eclipse.kura.util.test.driver</module>\n  </modules>\n</project>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/.gitignore",
    "content": "!src/main/resources/archetype-resources/**/MANIFEST.MF\n.vscode"
  },
  {
    "path": "kura/tools/kura-addon-archetype/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>tools</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n        <relativePath>../pom.xml</relativePath>\n    </parent>\n\n    <artifactId>kura-addon-archetype</artifactId>\n    <packaging>maven-archetype</packaging>\n\n    <build>\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n                <filtering>true</filtering>\n                <includes>\n                    <include>archetype-resources/tests/test-env/framework/kura.properties</include>\n                    <include>META-INF/maven/archetype-metadata.xml</include>\n                </includes>\n            </resource>\n            <resource>\n                <directory>src/main/resources</directory>\n                <filtering>false</filtering>\n                <excludes>\n                    <exclude>archetype-resources/tests/test-env/framework/kura.properties</exclude>\n                    <exclude>META-INF/maven/archetype-metadata.xml</exclude>\n                </excludes>\n            </resource>\n        </resources>\n\n        <extensions>\n            <extension>\n                <groupId>org.apache.maven.archetype</groupId>\n                <artifactId>archetype-packaging</artifactId>\n                <version>3.3.1</version>\n            </extension>\n        </extensions>\n\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-resources-plugin</artifactId>\n                <version>3.3.1</version>\n                <configuration>\n                    <includeEmptyDirs>true</includeEmptyDirs>\n                    <!-- needed to include .gitignore -->\n                    <useDefaultExcludes>false</useDefaultExcludes>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-archetype-plugin</artifactId>\n                <version>3.3.1</version>\n                <configuration>\n                    <!-- needed to include .gitignore -->\n                    <useDefaultExcludes>false</useDefaultExcludes>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>build-helper-maven-plugin</artifactId>\n                <version>3.6.1</version>\n                <executions>\n                    <execution>\n                        <id>timestamp-property</id>\n                        <goals>\n                            <goal>timestamp-property</goal>\n                        </goals>\n                        <phase>validate</phase>\n                        <configuration>\n                            <name>year</name>\n                            <pattern>yyyy</pattern>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/META-INF/maven/archetype-metadata.xml",
    "content": "<!--\n    Copyright (c) 2026 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<archetype-descriptor\n    xmlns=\"http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd\"\n    partial=\"true\">\n\n    <requiredProperties>\n        <requiredProperty key=\"mainBundleVendor\">\n            <defaultValue>Eclipse Kura</defaultValue>\n        </requiredProperty>\n        <requiredProperty key=\"version\">\n            <defaultValue>1.0.0-SNAPSHOT</defaultValue>\n        </requiredProperty>\n        <requiredProperty key=\"kuraVersion\">\n            <defaultValue>${project.version}</defaultValue>\n        </requiredProperty>\n        <requiredProperty key=\"year\">\n            <defaultValue>${year}</defaultValue>\n        </requiredProperty>\n    </requiredProperties>\n\n    <fileSets>\n        <fileSet filtered=\"true\" encoding=\"UTF-8\">\n            <directory>bom</directory>\n        </fileSet>\n        <fileSet filtered=\"true\" encoding=\"UTF-8\">\n            <directory>distrib</directory>\n        </fileSet>\n        <!-- exclude keystores from filtering, otherwise they get corrupted -->\n        <fileSet filtered=\"true\" encoding=\"UTF-8\">\n            <directory>tests/test-env</directory>\n            <excludes>\n                <exclude>**/*.ks</exclude>\n            </excludes>\n        </fileSet>\n        <!-- include keystores without filtering -->\n        <fileSet filtered=\"false\">\n            <directory>tests/test-env</directory>\n            <includes>\n                <include>**/*.ks</include>\n            </includes>\n        </fileSet>\n        <!-- include bundles and tests without java file, they are selected as packaged below -->\n        <fileSet filtered=\"true\" encoding=\"UTF-8\">\n            <directory>__package__</directory>\n            <excludes>\n                <exclude>**/*.java</exclude>\n            </excludes>\n        </fileSet>\n        <fileSet filtered=\"true\" encoding=\"UTF-8\">\n            <!-- <directory>./</directory> -->\n            <excludes>\n                <exclude>**/*.bndrun</exclude>\n                <exclude>**/*.java</exclude>\n                <exclude>**/src/main/java/test</exclude>\n                <exclude>**/src/test/java/test</exclude>\n            </excludes>\n        </fileSet>\n\n        <fileSet filtered=\"false\" packaged=\"false\">\n            <directory>tests</directory>\n            <includes>\n                <include>__package__.test/integration-test.bndrun</include>\n            </includes>\n        </fileSet>\n\n        <fileSet filtered=\"true\" packaged=\"true\">\n            <directory>__package__/src/main/java</directory>\n        </fileSet>\n        <fileSet filtered=\"true\" packaged=\"true\">\n            <directory>tests/__package__.test/src/main/java</directory>\n        </fileSet>\n        <fileSet filtered=\"true\" packaged=\"true\">\n            <directory>tests/__package__.test/src/test/java</directory>\n        </fileSet>\n        <fileSet encoding=\"UTF-8\">\n            <directory></directory>\n            <includes>\n                <include>.gitignore</include>\n            </includes>\n        </fileSet>\n    </fileSets>\n\n</archetype-descriptor>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/.gitignore",
    "content": ".DS_Store*\n*~\nclasses\ntarget\nRemoteSystemsTempFiles\n.metadata\n.recommenders\n.sonarlint\n.classpath\n.project\n.settings\n.vscode\nOSGI-INF\n.flattened-pom.xml\n.tycho-consumer-pom.xml\nlib/\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/__package__/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) ${year} Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>${groupId}</groupId>\n        <artifactId>${artifactId}</artifactId>\n        <version>${version}</version>\n    </parent>\n\n    <artifactId>${package}</artifactId>\n    <description>${package} plugin</description>\n\n    <properties>\n        <sonar.coverage.jacoco.xmlReportPaths>\n            ${project.basedir}/../tests/*/target/site/jacoco-aggregate/jacoco.xml\n        </sonar.coverage.jacoco.xmlReportPaths>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.component.annotations</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.metatype.annotations</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>biz.aQute.bnd</groupId>\n                <artifactId>bnd-maven-plugin</artifactId>\n                <configuration>\n                    <includeClassesDir>true</includeClassesDir>\n                    <bnd><![CDATA[\n                        Bundle-SymbolicName: ${project.artifactId};singleton:=true\n                        Bundle-ActivationPolicy: lazy\n                        ]]></bnd>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-deploy-plugin</artifactId>\n                <configuration>\n                    <skip>false</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n\n</project>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/__package__/src/main/java/ExampleComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) ${year} Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage ${package};\n\nimport java.util.Map;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.ConfigurationPolicy;\nimport org.osgi.service.component.annotations.Deactivate;\nimport org.osgi.service.component.annotations.Modified;\nimport org.osgi.service.component.annotations.Reference;\nimport org.osgi.service.metatype.annotations.Designate;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Component(immediate = true, //\n        configurationPolicy = ConfigurationPolicy.REQUIRE, //\n        property = { \"kura.service.pid=${package}.ExampleComponent\" } //\n)\n@Designate(ocd = ExampleComponentOCD.class, factory = false)\npublic class ExampleComponent implements ConfigurableComponent {\n\n    private static final Logger logger = LoggerFactory.getLogger(ExampleComponent.class);\n\n    private ExampleComponentOptions options;\n\n    @Reference\n    private ExampleDependencyService exampleDependencyService;\n\n    @Reference\n    public void setExampleDependencyService(ExampleDependencyService exampleDependencyService) {\n        this.exampleDependencyService = exampleDependencyService;\n    }\n\n    /*\n     * In the in activate, modified, deactivate methods it is possible to provide\n     * the ComponentContext and the ExampleComponentOCD as parameters.\n     * All parameters in activate, modified, deactivate are optional and can be\n     * removed if not needed\n     * \n     * Examples:\n     * \n     * public void activate()\n     * public void activate(ExampleComponentOCD configuration)\n     * public void activate(ComponentContext componentContext, final Map<String, Object> properties, final\n     * ExampleComponentOCD configuration)\n     */\n    @Activate\n    public void activate(final Map<String, Object> properties) {\n        logger.info(\"Activating\");\n\n        updated(properties);\n\n        logger.info(\"Activated\");\n    }\n\n    @Modified\n    public void updated(final Map<String, Object> properties) {\n        logger.info(\"Updating\");\n\n        logger.debug(\"Updating with properties: {}\", properties);\n        this.options = new ExampleComponentOptions(properties);\n\n        this.exampleDependencyService.run();\n\n        logger.info(\"Updated\");\n    }\n\n    @Deactivate\n    public synchronized void deactivate() {\n        logger.info(\"Deactivating\");\n        logger.info(\"Deactivated\");\n    }\n\n    public ExampleComponentOptions getOptions() {\n        return this.options;\n    }\n\n}\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/__package__/src/main/java/ExampleComponentOCD.java",
    "content": "/*******************************************************************************\n * Copyright (c) ${year} Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage ${package};\n\nimport org.osgi.service.metatype.annotations.AttributeDefinition;\nimport org.osgi.service.metatype.annotations.ObjectClassDefinition;\n\n// allow using _ in method names, it is needed for having ids containing '.'\n@SuppressWarnings(\"checkstyle:MethodName\")\n@ObjectClassDefinition(id = \"${package}.ExampleComponent\", //\n    name = \"ExampleComponent\", //\n    description = \"An example configurable component implementation.\" //\n)\npublic interface ExampleComponentOCD {\n\n    @AttributeDefinition(\n        name = \"An example property\", //\n        defaultValue = \"foo\", //\n        description = \"An example string property.\", //\n        required = true, //\n        cardinality = 0 //\n    )\n    public String example_property();\n\n}"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/__package__/src/main/java/ExampleComponentOptions.java",
    "content": "/*******************************************************************************\n * Copyright (c) ${year} Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage ${package};\n\nimport java.util.Map;\n\npublic class ExampleComponentOptions {\n\n    private static final Property<String> EXAMPLE_PROPERTY = new Property<>(\"example.property\", \"example\");\n\n    private final String exampleProperty;\n\n    public ExampleComponentOptions(final Map<String, Object> properties) {\n        this.exampleProperty = EXAMPLE_PROPERTY.getOrDefault(properties);\n    }\n\n    public String getExampleProperty() {\n        return this.exampleProperty;\n    }\n\n}\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/__package__/src/main/java/ExampleDependencyService.java",
    "content": "/*******************************************************************************\n * Copyright (c) ${year} Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage ${package};\n\npublic interface ExampleDependencyService {\n\n    public void run();\n}\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/__package__/src/main/java/ExampleDependencyServiceComponent.java",
    "content": "/*******************************************************************************\n * Copyright (c) ${year} Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage ${package};\n\nimport org.osgi.service.component.annotations.Component;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Component(service = ExampleDependencyService.class, immediate = true)\npublic class ExampleDependencyServiceComponent implements ExampleDependencyService {\n\n    private static final Logger logger = LoggerFactory.getLogger(ExampleDependencyServiceComponent.class);\n\n    @Override\n    public void run() {\n        logger.info(\"Running ExampleDependencyServiceComponent\");\n    }\n\n}\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/__package__/src/main/java/Property.java",
    "content": "/*******************************************************************************\n * Copyright (c) ${year} Eurotech and/or its affiliates and others\n * \n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage ${package};\n\nimport java.util.Map;\n\nclass Property<T> {\n\n    protected final String key;\n    protected final Class<T> valueType;\n    protected final T defaultValue;\n\n    @SuppressWarnings(\"unchecked\")\n    public Property(final String key, final T defaultValue) {\n        this.key = key;\n        this.valueType = (Class<T>) defaultValue.getClass();\n        this.defaultValue = defaultValue;\n    }\n\n    public T get(final Map<String, Object> properties) {\n\n        return getInternal(properties.get(key));\n    }\n\n    public T getOrDefault(final Map<String, Object> properties) {\n        try {\n            return get(properties);\n        } catch (final Exception e) {\n            return defaultValue;\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T getInternal(final Object value) {\n        if (valueType.isInstance(value)) {\n            return (T) value;\n        }\n\n        if (!(value instanceof String)) {\n            throw new IllegalArgumentException(\"Parameter \" + key + \" cannot be retrieved from properties\");\n        }\n\n        return parse((String) value);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T parse(final String valueString) {\n        final Object result;\n\n        if (valueType == Boolean.class) {\n            result = Boolean.parseBoolean(valueString);\n        } else if (valueType == Short.class) {\n            result = Short.parseShort(valueString);\n        } else if (valueType == Integer.class) {\n            result = Integer.parseInt(valueString);\n        } else if (valueType == Long.class) {\n            result = Long.parseLong(valueString);\n        } else if (valueType == Float.class) {\n            result = Float.parseFloat(valueString);\n        } else if (valueType == Double.class) {\n            result = Double.parseDouble(valueString);\n        } else {\n            throw new IllegalArgumentException(\"Cannot parse \" + valueType + \" from string\");\n        }\n\n        return (T) result;\n    }\n}\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/bom/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) ${year} Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>${groupId}</groupId>\n    <artifactId>${artifactId}-bom</artifactId>\n    <version>${version}</version>\n    <packaging>pom</packaging>\n    <description>${artifactId} bill of materials</description>\n\n    <!-- bundles of this project that will be deployed -->\n    <!-- on release/rc build: use latest released version, do not use -SNAPSHOT artifacts -->\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>${groupId}</groupId>\n                <artifactId>${package}</artifactId>\n                <version>${version}</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <distributionManagement>\n        <repository>\n            <id>repo.eclipse.org</id>\n            <name>Eclipse Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </repository>\n        <snapshotRepository>\n            <id>repo.eclipse.org</id>\n            <name>Eclipse Kura Repository - Snapshots</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </snapshotRepository>\n    </distributionManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>flatten-maven-plugin</artifactId>\n                <version>1.7.3</version>\n                <configuration>\n                    <updatePomFile>true</updatePomFile>\n                    <flattenMode>bom</flattenMode>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>flatten</id>\n                        <phase>process-resources</phase>\n                        <goals>\n                            <goal>flatten</goal>\n                        </goals>\n                    </execution>\n                    <execution>\n                        <id>flatten.clean</id>\n                        <phase>clean</phase>\n                        <goals>\n                            <goal>clean</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/distrib/deb/control/control",
    "content": "Package: [[package.name]]\nVersion: [[package.version]]-[[package.revision]]\nSection: admin\nPriority: optional\nDepends: kura-core (>= 6.0.0~), kura-core(<< 7.0.0~)\nArchitecture: [[deb.architecture]]\nMaintainer: [[deb.maintainer]]\nDescription: [[summary]]\n  [[long.description]]\nHomepage: [[deb.docs]]\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/distrib/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) ${year} Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>${groupId}</groupId>\n        <artifactId>${artifactId}</artifactId>\n        <version>${version}</version>\n    </parent>\n\n    <artifactId>${artifactId}-distrib</artifactId>\n    <packaging>pom</packaging>\n    <description>${artifactId} distribution packaging</description>\n\n    <!-- Insert your bundles as dependencies -->\n    <dependencies>\n        <dependency>\n            <groupId>${groupId}</groupId>\n            <artifactId>${package}</artifactId>\n        </dependency>\n    </dependencies>\n\n    <properties>\n        <addon.installation.dir>/opt/eclipse/kura/plugins</addon.installation.dir>\n\n        <!--\n            Available DEB architectures:\n            all, amd64, arm64\n        -->\n        <deb.architecture>all</deb.architecture>\n        <deb.maintainer>${project.organization.name} &lt;${project.developers[0].email}&gt;</deb.maintainer>\n        <deb.docs>${project.url}</deb.docs>\n\n        <!-- final name of the generated debian package -->\n        <package.name>${artifactId}</package.name>\n        <package.revision>1</package.revision>\n\n        <!-- properties used for artifact upload on artifactory repository -->\n        <kura.repo.distribution>CHANGEME</kura.repo.distribution>\n        <kura.repo.module>CHANGEME</kura.repo.module>\n\n        <!-- edit following fields and file deb/control/control -->\n        <summary>Summary line (do not end this line with a dot, max 60 chars)</summary>\n        <long.description>Here goes the long description of the packages, in this case this is an example addon for the Eclipse Kura Framework.</long.description>\n    </properties>\n\n    <profiles>\n        <!-- Internal profile: FOR INTERNAL USE ONLY - active if -DreleaseBuild is *not* specified. -->\n        <profile>\n            <id>debugBuild</id>\n            <activation>\n                <property>\n                    <name>!releaseBuild</name>\n                </property>\n            </activation>\n            <properties>\n                <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format>\n                <package.snapshot>git${maven.build.timestamp}.${git.commit.id.abbrev}</package.snapshot>\n\n                <package.version>${release.version}~${package.snapshot}</package.version>\n            </properties>\n        </profile>\n        <!-- Internal profile: FOR INTERNAL USE ONLY - active if -DreleaseBuild *is* specified. -->\n        <profile>\n            <id>releaseBuild</id>\n            <activation>\n                <property>\n                    <name>releaseBuild</name>\n                </property>\n            </activation>\n            <properties>\n                <package.version>${release.version}</package.version>\n            </properties>\n            <build>\n                <plugins>\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-enforcer-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <id>enforce-no-snapshots</id>\n                                <goals>\n                                    <goal>enforce</goal>\n                                </goals>\n                                <configuration>\n                                    <rules>\n                                        <requireReleaseVersion>\n                                            <message>No snapshots allowed for release builds!</message>\n                                        </requireReleaseVersion>\n                                    </rules>\n                                    <fail>true</fail>\n                                </configuration>\n                            </execution>\n                        </executions>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n    </profiles>\n\n    <build>\n        <plugins>\n            <!-- Responsible for removing the \"-SNAPSHOT\" from the project.version -->\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>build-helper-maven-plugin</artifactId>\n                <version>3.6.1</version>\n                <executions>\n                    <execution>\n                        <id>regex-property</id>\n                        <goals>\n                            <goal>regex-property</goal>\n                        </goals>\n                        <configuration>\n                            <name>release.version</name>\n                            <value>${project.version}</value>\n                            <regex>-SNAPSHOT</regex>\n                            <replacement></replacement>\n                            <failIfNoMatch>false</failIfNoMatch>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <!-- Responsible for retrieving the short git commit (defaults to length 7) -->\n            <plugin>\n                <groupId>io.github.git-commit-id</groupId>\n                <artifactId>git-commit-id-maven-plugin</artifactId>\n                <version>9.0.2</version>\n                <executions>\n                    <execution>\n                        <id>get-the-git-infos</id>\n                        <goals>\n                            <goal>revision</goal>\n                        </goals>\n                        <phase>initialize</phase>\n                    </execution>\n                </executions>\n                <configuration>\n                    <injectAllReactorProjects>true</injectAllReactorProjects>\n                    <generateGitPropertiesFile>false</generateGitPropertiesFile>\n                    <skipPoms>false</skipPoms>\n                    <includeOnlyProperties>\n                        <includeOnlyProperty>^git.commit.id.abbrev$</includeOnlyProperty>\n                    </includeOnlyProperties>\n                </configuration>\n            </plugin>\n            \n            <!--\n                Responsible for copying the dependencies into a known location.\n\n                If multiple bundles need to be installed in separate start levels,\n                repeat this section to cover all start levels\n\n                With n being the start level, config.ini will be populated depending on which plugins directory the bundle is put:\n                n => bundle.name:@n;\n                ns => bundle.name:@n:start;\n            -->\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>copy-deps</id>\n                        <phase>generate-resources</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <excludeTypes>pom</excludeTypes>\n                            <excludeClassifiers>sources</excludeClassifiers>\n                            <excludeTransitive>true</excludeTransitive>\n                            <outputDirectory>${project.build.directory}/plugins/6s</outputDirectory>\n                            <includeArtifactIds>\n                                ${package}\n                            </includeArtifactIds>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <groupId>org.vafer</groupId>\n                <artifactId>jdeb</artifactId>\n                <version>1.14</version>\n                <executions>\n                    <execution>\n                        <id>generate-deb</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jdeb</goal>\n                        </goals>\n                        <configuration>\n                            <verbose>true</verbose>\n                            <deb>${basedir}/target/deb/${package.name}_${package.version}-${package.revision}_${deb.architecture}.deb</deb>\n                            <controlDir>${project.basedir}/deb/control</controlDir>\n                            <skipPOMs>false</skipPOMs>\n                            <dataSet>\n                                <!-- Repeat this section for each start level -->\n                                <data>\n                                    <src>${project.build.directory}/plugins/6s</src>\n                                    <type>directory</type>\n                                    <mapper>\n                                        <type>perm</type>\n                                        <prefix>${addon.installation.dir}/6s</prefix>\n                                        <user>kurad</user>\n                                        <group>kurad</group>\n                                        <filemode>600</filemode>\n                                    </mapper>\n                                </data>\n                            </dataSet>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-deploy-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) ${year} Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n    child.project.url.inherit.append.path=\"false\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>${groupId}</groupId>\n    <artifactId>${artifactId}</artifactId>\n    <version>${version}</version>\n    <packaging>pom</packaging>\n\n    <!-- Change this if your metadata is different -->\n    <organization>\n        <name>Eclipse Kura</name>\n        <url>https://eclipse.dev/kura/</url>\n    </organization>\n    <developers>\n        <developer>\n            <id>kura-dev</id>\n            <name>Eclipse Kura Developers</name>\n            <email>kura-dev@eclipse.org</email>\n            <organization>Eclipse Foundation</organization>\n            <url>https://www.eclipse.org/</url>\n        </developer>\n    </developers>\n    <licenses>\n        <license>\n            <name>Eclipse Public License - v 2.0</name>\n            <url>https://www.eclipse.org/legal/epl-2.0/</url>\n        </license>\n    </licenses>\n    <!-- Documentation URL -->\n    <url>https://eclipse-kura.github.io/kura</url>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <maven.compiler.release>21</maven.compiler.release>\n        <bnd.version>7.2.2</bnd.version>\n    </properties>\n\n    <modules>\n        <module>bom</module>\n        <module>${package}</module>\n        <module>distrib</module>\n        <module>tests</module>\n    </modules>\n\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>${groupId}</groupId>\n                <artifactId>${artifactId}-bom</artifactId>\n                <version>${project.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <!-- All of the external dependencies that are needed for your bundle -->\n            <!-- If using non-Kura dependencies, try to match the ones that are defined in target platform-->\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>kura</artifactId>\n                <version>${kuraVersion}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>target-platform</artifactId>\n                <version>${kuraVersion}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n\n    <repositories>\n        <repository>\n            <id>kura-releases</id>\n            <name>Eclipse Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </repository>\n        <repository>\n            <id>kura-snapshots</id>\n            <name>Eclipse Kura Repository - Snapshots</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </repository>\n        <repository>\n            <id>kura-addons</id>\n            <name>Kura Addons Maven Repository</name>\n            <url>https://artifactory.dev.everyware.io/artifactory/kura-addons</url>\n        </repository>\n        <repository>\n            <!-- moquette-broker -->\n            <id>jitpack.io</id>\n            <url>https://jitpack.io</url>\n        </repository>\n    </repositories>\n\n    <pluginRepositories>\n        <pluginRepository>\n            <id>kura-releases</id>\n            <name>Eclipse Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </pluginRepository>\n        <pluginRepository>\n            <id>kura-snapshots</id>\n            <name>Eclipse Kura Repository - Snapshots</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </pluginRepository>\n    </pluginRepositories>\n\n    <distributionManagement>\n        <repository>\n            <id>repo.eclipse.org</id>\n            <name>Eclipse Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </repository>\n        <snapshotRepository>\n            <id>repo.eclipse.org</id>\n            <name>Eclipse Kura Repository - Snapshots</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </snapshotRepository>\n    </distributionManagement>\n\n    <build>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>biz.aQute.bnd</groupId>\n                    <artifactId>bnd-maven-plugin</artifactId>\n                    <version>${bnd.version}</version>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>bnd-process</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <!-- Required to make the maven-jar-plugin pick up the bnd\n                    generated manifest. Also avoid packaging empty Jars -->\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-jar-plugin</artifactId>\n                    <version>3.5.0</version>\n                    <configuration>\n                        <archive>\n                            <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>\n                        </archive>\n                        <skipIfEmpty>true</skipIfEmpty>\n                    </configuration>\n                </plugin>\n\n                <!-- Define the version of the export plugin we should use -->\n                <plugin>\n                    <groupId>biz.aQute.bnd</groupId>\n                    <artifactId>bnd-export-maven-plugin</artifactId>\n                    <version>${bnd.version}</version>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>export</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <!-- Setup the indexer for running and testing -->\n                <plugin>\n                    <groupId>biz.aQute.bnd</groupId>\n                    <artifactId>bnd-indexer-maven-plugin</artifactId>\n                    <version>${bnd.version}</version>\n                    <configuration>\n                        <localURLs>REQUIRED</localURLs>\n                        <attach>false</attach>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <id>index</id>\n                            <goals>\n                                <goal>index</goal>\n                            </goals>\n                            <configuration>\n                                <indexName>${project.artifactId}</indexName>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <!-- Define the version of the resolver plugin we use -->\n                <plugin>\n                    <groupId>biz.aQute.bnd</groupId>\n                    <artifactId>bnd-resolver-maven-plugin</artifactId>\n                    <version>${bnd.version}</version>\n                    <configuration>\n                        <failOnChanges>false</failOnChanges>\n                        <bndruns>\n                        </bndruns>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>resolve</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <!-- Define the version of the testing plugin that we use -->\n                <plugin>\n                    <groupId>biz.aQute.bnd</groupId>\n                    <artifactId>bnd-testing-maven-plugin</artifactId>\n                    <version>${bnd.version}</version>\n                    <configuration>\n                        <reportsDir>${project.build.directory}/surefire-reports</reportsDir>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>testing</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <!-- Define the version of the baseline plugin we use and\n                    avoid failing when no baseline jar exists. (for example before the first\n                    release) -->\n                <plugin>\n                    <groupId>biz.aQute.bnd</groupId>\n                    <artifactId>bnd-baseline-maven-plugin</artifactId>\n                    <version>${bnd.version}</version>\n                    <configuration>\n                        <failOnMissing>false</failOnMissing>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>baseline</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <plugin>\n                    <groupId>org.honton.chas</groupId>\n                    <artifactId>exists-maven-plugin</artifactId>\n                    <version>0.15.2</version>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>remote</goal>\n                            </goals>\n                            <configuration>\n                                <artifact>${project.artifactId}-${project.version}.jar</artifact>\n                                <skipIfSnapshot>true</skipIfSnapshot>\n                                <failIfExists>true</failIfExists>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <plugin>\n                    <groupId>org.codehaus.mojo</groupId>\n                    <artifactId>flatten-maven-plugin</artifactId>\n                    <version>1.7.3</version>\n                    <configuration>\n                        <updatePomFile>true</updatePomFile>\n                        <flattenMode>oss</flattenMode>\n                    </configuration>\n                    <executions>\n                        <execution>\n                            <id>flatten</id>\n                            <phase>process-resources</phase>\n                            <goals>\n                                <goal>flatten</goal>\n                            </goals>\n                        </execution>\n                        <execution>\n                            <id>flatten.clean</id>\n                            <phase>clean</phase>\n                            <goals>\n                                <goal>clean</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-enforcer-plugin</artifactId>\n                    <version>3.6.2</version>\n                    <dependencies>\n                        <dependency>\n                            <groupId>org.eclipse.kura</groupId>\n                            <artifactId>maven-enforcer-rules</artifactId>\n                            <version>1.0.0</version>\n                        </dependency>\n                    </dependencies>\n                    <executions>\n                        <execution>\n                            <id>enforce</id>\n                            <configuration>\n                                <rules>\n                                    <bannedPluginsAdvanced>\n                                        <message>Please use copy-dependencies goal instead of copy</message>\n                                        <bannedPlugins>\n                                            <bannedPlugin>\n                                                <groupId>org.apache.maven.plugins</groupId>\n                                                <artifactId>maven-dependency-plugin</artifactId>\n                                                <goal>copy</goal>\n                                            </bannedPlugin>\n                                        </bannedPlugins>\n                                    </bannedPluginsAdvanced>\n                                </rules>\n                            </configuration>\n                            <goals>\n                                <goal>enforce</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-deploy-plugin</artifactId>\n                    <version>3.1.4</version>\n                </plugin>\n\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-compiler-plugin</artifactId>\n                    <version>3.15.0</version>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n\n        <plugins>\n            <plugin>\n                <groupId>biz.aQute.bnd</groupId>\n                <artifactId>bnd-maven-plugin</artifactId>\n            </plugin>\n            <!-- by default, skip deploy -->\n            <!-- bundles that want to deploy must override this configuration -->\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-deploy-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.codehaus.mojo</groupId>\n                <artifactId>flatten-maven-plugin</artifactId>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-enforcer-plugin</artifactId>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/tests/__package__.test/integration-test.bndrun",
    "content": "index: target/index.xml\n\n-standalone: ${index}\n\n-resolve.effective: active\n\n-runfw: org.eclipse.osgi\n\n-runee: JavaSE-21\n\n# Run all integration tests which are named xyzTest\nTest-Cases: ${classes;CONCRETE;PUBLIC;NAMED;*Test}\n\n-runproperties: \\\n    osgi.console=5002,\\\n    osgi.signedcontent.support=all,\\\n    org.eclipse.kura.mode=emulator,\\\n    org.osgi.framework.trust.repositories=${kura.workdir}/user/security/.certificates.ks,\\\n    kura.configuration=file:${kura.workdir}/framework/kura.properties,\\\n    dpa.configuration=${kura.workdir}/data/dpa.properties,\\\n    kura.data=${kura.workdir}/data,\\\n    kura.snapshots=${kura.workdir}/user/snapshots,\\\n    log4j.configurationFile=file:${kura.workdir}/log4j/log4j.xml\n\n# Inject JaCoCo agent args produced by maven (prepare-agent)\n-runvm: \\\n\t${argLine}\n\n# Used by Objenesis/Mockito and not actually optional\n-runsystempackages: sun.reflect\n\n# Require Kura Emulator\n-runrequires.emulator: \\\n    osgi.identity;filter:='(osgi.identity=moquette-broker)',\\\n    osgi.identity;filter:='(osgi.identity=org.apache.logging.log4j.api)',\\\n    osgi.identity;filter:='(osgi.identity=org.apache.logging.log4j.core)',\\\n    osgi.identity;filter:='(osgi.identity=org.apache.logging.log4j.slf4j2.impl)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.equinox.cm)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.equinox.common)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.equinox.console)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.equinox.event)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.equinox.metatype)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.equinox.registry)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.api)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.core)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.core.configuration)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.core.crypto)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.core.identity)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.core.inventory)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.core.status)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.core.system)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.core.testutil)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.emulator)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.emulator.clock)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.emulator.gpio)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.emulator.gpio)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.emulator.net)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.emulator.net)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.emulator.position)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.emulator.usb)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.emulator.watchdog)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.json.marshaller.unmarshaller.provider)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.rest.provider)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.useradmin.store)',\\\n    osgi.identity;filter:='(osgi.identity=org.eclipse.kura.xml.marshaller.unmarshaller.provider)',\\\n\n# Require Testing bundle\n-runrequires: \\\n    osgi.identity;filter:='(osgi.identity=${project.artifactId})',\\\n\n#\n# Runbundles automatically populated by bnd-resolver\n#\n-runbundles: ${error;Integration test bundles must be resolved. Enable the resolve-integration-tests Maven profile and rebuild.}\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/tests/__package__.test/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) ${year} Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>${groupId}</groupId>\n        <artifactId>${artifactId}-tests</artifactId>\n        <version>${version}</version>\n    </parent>\n\n    <artifactId>${package}.test</artifactId>\n    <description>Tests of ${package}</description>\n\n    <!-- Insert your bundles as dependencies -->\n    <dependencies>\n        <dependency>\n            <groupId>${groupId}</groupId>\n            <artifactId>${package}</artifactId>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>prepare-test-resources</id>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-antrun-plugin</artifactId>\n            </plugin>\n\n            <plugin>\n                <groupId>org.jacoco</groupId>\n                <artifactId>jacoco-maven-plugin</artifactId>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-surefire-plugin</artifactId>\n            </plugin>\n\n            <plugin>\n                <groupId>biz.aQute.bnd</groupId>\n                <artifactId>bnd-maven-plugin</artifactId>\n                <configuration>\n                    <bndfile>integration-test.bndrun</bndfile>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>biz.aQute.bnd</groupId>\n                <artifactId>bnd-indexer-maven-plugin</artifactId>\n                <configuration>\n                    <includeJar>true</includeJar>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>biz.aQute.bnd</groupId>\n                <artifactId>bnd-testing-maven-plugin</artifactId>\n                <configuration>\n                    <bndruns>\n                        <bndrun>integration-test.bndrun</bndrun>\n                    </bndruns>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>biz.aQute.bnd</groupId>\n                <artifactId>bnd-resolver-maven-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>osgi-integration-resolving</id>\n                        <goals>\n                            <goal>resolve</goal>\n                        </goals>\n                        <configuration>\n                            <bndruns>\n                                <bndrun>integration-test.bndrun</bndrun>\n                            </bndruns>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/tests/__package__.test/src/main/java/test/ExampleComponentItTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) ${year} Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage ${package}.test;\n\nimport static org.junit.Assert.assertNotNull;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.kura.configuration.ConfigurableComponent;\nimport org.junit.AfterClass;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.osgi.framework.Bundle;\nimport org.osgi.framework.BundleContext;\nimport org.osgi.framework.BundleException;\nimport org.osgi.service.component.annotations.Activate;\nimport org.osgi.service.component.annotations.Component;\nimport org.osgi.service.component.annotations.Reference;\nimport org.osgi.service.component.annotations.ReferenceCardinality;\nimport org.osgi.service.component.annotations.ReferencePolicy;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n@Component(immediate = true)\npublic class ExampleComponentItTest {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(ExampleComponentItTest.class);\n\n    private static final CountDownLatch dependencies = new CountDownLatch(1);\n\n    // needs to be static for being available to JUnit Runner\n    private static ConfigurableComponent exampleComponent;\n    private static BundleContext bundleContext;\n\n    @Activate\n    public void activate(BundleContext context) {\n        bundleContext = context;\n    }\n\n    @Reference(cardinality = ReferenceCardinality.MANDATORY, //\n        policy = ReferencePolicy.STATIC, //\n        target = \"(kura.service.pid=${package}.ExampleComponent)\" //\n    )\n    public void setExampleComponent(final ConfigurableComponent componentUnderTest) {\n        exampleComponent = componentUnderTest;\n        dependencies.countDown();\n        logger.info(\"Got service reference {}\", exampleComponent.getClass().getSimpleName());\n    }\n\n    @BeforeClass\n    public static void awaitDependencies() throws InterruptedException {\n        if (!dependencies.await(30, TimeUnit.SECONDS)) {\n            throw new IllegalStateException(\"dependencies not resolved in 30 seconds\");\n        }\n    }\n\n    @AfterClass\n    public static void cleanupFramework() {\n        logger.info(\"Shutting down OSGi framework...\");\n        if (bundleContext != null) {\n            try {\n                Bundle systemBundle = bundleContext.getBundle(0);\n                systemBundle.stop();\n            } catch (BundleException e) {\n                logger.error(\"Error stopping framework\", e);\n            }\n        }\n    }\n\n    @Test\n    public void shouldHaveTrackedExampleComponent() {\n    \tassertNotNull(exampleComponent);\n    }\n\n}\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/tests/__package__.test/src/test/java/test/ExampleComponentTest.java",
    "content": "/*******************************************************************************\n * Copyright (c) ${year} Eurotech and/or its affiliates and others\n *\n * This program and the accompanying materials are made\n * available under the terms of the Eclipse Public License 2.0\n * which is available at https://www.eclipse.org/legal/epl-2.0/\n *\n * SPDX-License-Identifier: EPL-2.0\n *\n * Contributors:\n *  Eurotech\n *******************************************************************************/\npackage ${package}.test;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.mockito.Mockito.doAnswer;\nimport static org.mockito.Mockito.mock;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.Test;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport ${package}.ExampleComponent;\nimport ${package}.ExampleDependencyService;\n\npublic class ExampleComponentTest {\n\n    private static final Logger logger = LoggerFactory.getLogger(ExampleComponent.class);\n\n    private ExampleComponent exampleComponent = new ExampleComponent();\n    private Map<String, Object> properties = new HashMap<>();\n    private ExampleDependencyService dependencyService;\n\n    @Test\n    public void shouldActivate() {\n        givenDependencyService();\n        givenExampleComponent();\n        givenProperties(\"example.property\", \"test\");\n\n        whenActivatingExampleComponent();\n\n        thenExampleOptionIs(\"test\");\n    }\n\n    private void givenDependencyService() {\n        this.dependencyService = mock(ExampleDependencyService.class);\n        doAnswer(answer -> {\n            logger.info(\"I'm in a mock ExampleDependencyService\");\n            return null;\n        }).when(this.dependencyService).run();\n    }\n\n    private void givenExampleComponent() {\n        this.exampleComponent = new ExampleComponent();\n        this.exampleComponent.setExampleDependencyService(this.dependencyService);\n    }\n\n    private void givenProperties(String key, Object value) {\n        this.properties.put(key, value);\n    }\n\n    private void whenActivatingExampleComponent() {\n        this.exampleComponent.activate(this.properties);\n    }\n\n    private void thenExampleOptionIs(String examplePropertyValue) {\n        assertEquals(examplePropertyValue, this.exampleComponent.getOptions().getExampleProperty());\n    }\n\n}"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/tests/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) ${year} Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>${groupId}</groupId>\n        <artifactId>${artifactId}</artifactId>\n        <version>${version}</version>\n    </parent>\n\n    <artifactId>${artifactId}-tests</artifactId>\n    <packaging>pom</packaging>\n    <description>Tests aggregator project of ${artifactId}</description>\n\n    <properties>\n        <kura.workdir>${project.build.directory}/test-env</kura.workdir>\n        <mockito.version>5.23.0</mockito.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-core</artifactId>\n            <version>${mockito.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.2</version>\n        </dependency>\n\n        <!-- This OSGi bundle wraps junit 4.13.2 jar file. -->\n        <dependency>\n            <groupId>org.apache.servicemix.bundles</groupId>\n            <artifactId>org.apache.servicemix.bundles.junit</artifactId>\n            <version>4.13.2_1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.github.moquette-io.moquette</groupId>\n            <artifactId>moquette-broker</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>kura-pde-deps</artifactId>\n            <version>${kuraVersion}</version>\n            <type>pom</type>\n        </dependency>\n\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>target-platform-pde-deps</artifactId>\n            <version>${kuraVersion}</version>\n            <type>pom</type>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-resources-plugin</artifactId>\n                    <version>3.5.0</version>\n                    <executions>\n                        <execution>\n                            <id>generate-test-env</id>\n                            <phase>generate-test-resources</phase>\n                            <goals>\n                                <goal>copy-resources</goal>\n                            </goals>\n                            <configuration>\n                                <includeEmptyDirs>true</includeEmptyDirs>\n                                <outputDirectory>${kura.workdir}</outputDirectory>\n                                <resources>\n                                    <resource>\n                                        <directory>../test-env</directory>\n                                        <includes>\n                                            <include>data</include>\n                                            <include>framework/*</include>\n                                            <include>log4j/*</include>\n                                            <include>user/**/*</include>\n                                        </includes>\n                                        <filtering>false</filtering>\n                                    </resource>\n                                </resources>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <plugin>\n                    <groupId>org.apache.maven.plugins</groupId>\n                    <artifactId>maven-antrun-plugin</artifactId>\n                    <executions>\n                        <execution>\n                            <id>prepare-test-env</id>\n                            <phase>process-test-resources</phase>\n                            <goals>\n                                <goal>run</goal>\n                            </goals>\n                            <configuration>\n                                <target>\n                                    <replace\n                                        file=\"${kura.workdir}/framework/kura.properties\"\n                                        token=\"/tmp/kura\"\n                                        value=\"${kura.workdir}\" />\n                                    <replace\n                                        file=\"${kura.workdir}/user/snapshots/snapshot_0.xml\"\n                                        token=\"/tmp/kura\"\n                                        value=\"${kura.workdir}\" />\n                                </target>\n                            </configuration>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <plugin>\n                    <groupId>org.jacoco</groupId>\n                    <artifactId>jacoco-maven-plugin</artifactId>\n                    <version>0.8.14</version>\n                    <executions>\n                        <execution>\n                            <goals>\n                                <goal>prepare-agent</goal>\n                            </goals>\n                        </execution>\n                        <execution>\n                            <id>report</id>\n                            <phase>verify</phase>\n                            <goals>\n                                <goal>report-aggregate</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                </plugin>\n\n                <plugin>\n                    <artifactId>maven-surefire-plugin</artifactId>\n                    <version>3.5.5</version>\n                    <executions>\n                        <execution>\n                            <id>default-test</id>\n                            <phase>test</phase>\n                            <goals>\n                                <goal>test</goal>\n                            </goals>\n                        </execution>\n                    </executions>\n                    <configuration/>\n                </plugin>\n\n                <plugin>\n                    <groupId>biz.aQute.bnd</groupId>\n                    <artifactId>bnd-resolver-maven-plugin</artifactId>\n                    <executions>\n                        <execution>\n                            <id>osgi-integration-resolving</id>\n                            <phase>none</phase>\n                        </execution>\n                    </executions>\n                </plugin>\n\n            </plugins>\n        </pluginManagement>\n    </build>\n\n    <!-- This profile is used to resolve the OSGi integration test dependencies before running the tests. -->\n    <profiles>\n        <profile>\n            <id>resolve-integration-tests</id>\n            <build>\n                <pluginManagement>\n                    <plugins>\n                        <plugin>\n                            <groupId>biz.aQute.bnd</groupId>\n                            <artifactId>bnd-resolver-maven-plugin</artifactId>\n                            <executions>\n                                <execution>\n                                    <id>osgi-integration-resolving</id>\n                                    <phase>pre-integration-test</phase>\n                                </execution>\n                            </executions>\n                        </plugin>\n                    </plugins>\n                </pluginManagement>\n            </build>\n        </profile>\n    </profiles>\n\n    <modules>\n        <module>${package}.test</module>\n    </modules>\n\n</project>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/tests/test-env/data/.gitkeep",
    "content": ""
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/tests/test-env/framework/kura.properties",
    "content": "#\n#    Copyright (c) ${year} Eurotech and/or its affiliates and others\n#  \n#    This program and the accompanying materials are made\n#    available under the terms of the Eclipse Public License 2.0\n#    which is available at https://www.eclipse.org/legal/epl-2.0/\n# \n#    SPDX-License-Identifier: EPL-2.0\n#\n#    Contributors:\n#     Eurotech\n#\n\nkura.name=Kura\nkura.version=${project.version}\nkura.marketplace.compatibility.version=KURA_${project.version}\nkura.company=Eurotech\nkura.project=Dev\nkura.platform=Development\nkura.device.name=DevEmulator\nkura.model.id=DevModelId\nkura.model.name=DevModelName\nkura.partNumber=DevPartNumber\nkura.serialNumber=DevSerialNumber\nkura.bios.version=DevBiosVersion\nkura.firmware.version=DevFirmwareVersion\n\n# kura.mac.address= Fetch from Java\nkura.home=/tmp/kura\nkura.framework.config=/tmp/kura/framework\nkura.user.config=/tmp/kura/user\nkura.plugins=/tmp/kura/plugins\nkura.packages=/tmp/kura/packages\nkura.data=/tmp/kura/data\nkura.tmp=/tmp/kura/tmp\nkura.snapshots=/tmp/kura/user/snapshots\nkura.snapshots.count=10\nkura.have.net.admin=false\n\n# os.arch= Fetch from Java\n# os.name= Fetch from Java\n# os.version= Fetch from Java\nos.distribution=DevOsDitribution\nos.distribution.version=DevOsDitributionVersion\n# java.version= Fetch from Java\n# java.vendor= Fetch from Java\n# java.vm.name= Fetch from Java\n# java.vm.version= Fetch from Java\n# java.home= Fetch from Java\n# file.separator= Fetch from Java\n\n## -----------------------------------------------------------------------------\n## File upload settings\n## -----------------------------------------------------------------------------\n# default 10240\nfile.upload.in.memory.size.threshold=10240\n# -1: unlimited (default)\nfile.upload.size.max=-1\nfile.command.zip.max.size=100\nfile.command.zip.max.number=1024\n\n## -----------------------------------------------------------------------------\n## Deployment Agent settings\n## -----------------------------------------------------------------------------\n# see copyURLToFile() http://commons.apache.org/proper/commons-io/javadocs/api-2.4/index.html\ndpa.connection.timeout = 60000\ndpa.read.timeout = 60000\n\n## -----------------------------------------------------------------------------\n## Cloud Connection Status settings\n## -----------------------------------------------------------------------------\n\n#1. Cloud Connection Status on system log\n#The Cloud Connection Status will be indicated in the log files, and nowere else\nccs.status.notification.url=ccs:log\n\n#2. Cloud Connection Status on LED\n#The Cloud Connection Status will be indicated by a blinking LED connected to the system GPIOs\n#The URL should identify the GPIO to be used, either by name or by terminal index as defined by Kura GpioService.\n# Syntax for using GPIO terminal index:\n#ccs.status.notification.url=ccs:led:16\n#ccs.status.notification.url=ccs:led:terminal:16\n# Syntax for using GPIO name:\n#ccs.status.notification.url=ccs:led:name:LED_1\nccs.status.notification.url=ccs:led:16\n\n#3. Cloud Connection Status disabled\n#Disables the Cloud Connection Status service\n#ccs.status.notification.url=ccs:none"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/tests/test-env/log4j/log4j.xml",
    "content": "<Configuration status=\"warn\" strict=\"true\" name=\"KuraConfig\" monitorInterval=\"30\">\n\n    <Filter type=\"ThresholdFilter\" level=\"trace\" />\n\n    <Appenders>\n        <Console name=\"Console\" target=\"SYSTEM_OUT\">\n            <PatternLayout>\n                <Pattern>%d{ISO8601} [%t] %-5p %c{1.} - %m%n%throwable{full}</Pattern>\n            </PatternLayout>\n        </Console>\n    </Appenders>\n\n    <Loggers>\n        <Root level=\"info\">\n            <AppenderRef ref=\"Console\" />\n        </Root>\n    </Loggers>\n\n</Configuration>\n"
  },
  {
    "path": "kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/tests/test-env/user/snapshots/snapshot_0.xml",
    "content": "<esf:configurations xmlns:ocd=\"http://www.osgi.org/xmlns/metatype/v1.2.0\"\n    xmlns:esf=\"http://eurotech.com/esf/2.0\">\n    <esf:configuration pid=\"org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport\">\n        <esf:properties>\n            <esf:property name=\"clean-session\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"username\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>username</esf:value>\n            </esf:property>\n            <esf:property name=\"topic.context.account-name\" array=\"false\" encrypted=\"false\"\n                type=\"String\">\n                <esf:value>account-name</esf:value>\n            </esf:property>\n            <esf:property name=\"broker-url\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>mqtt://broker-url:1883/</esf:value>\n            </esf:property>\n            <esf:property name=\"lwt.retain\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property name=\"in-flight.persistence\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>file</esf:value>\n            </esf:property>\n            <esf:property name=\"lwt.topic\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>$EDC/#account-name/#client-id/MQTT/LWT</esf:value>\n            </esf:property>\n            <esf:property name=\"keep-alive\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>30</esf:value>\n            </esf:property>\n            <esf:property name=\"service.pid\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport</esf:value>\n            </esf:property>\n            <esf:property name=\"password\" array=\"false\" encrypted=\"false\" type=\"Password\">\n                <esf:value>password</esf:value>\n            </esf:property>\n            <esf:property name=\"timeout\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>20</esf:value>\n            </esf:property>\n            <esf:property name=\"lwt.qos\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>0</esf:value>\n            </esf:property>\n            <esf:property name=\"protocol-version\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>4</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.data.DataService\">\n        <esf:properties>\n            <esf:property name=\"in-flight-messages.congestion-timeout\" array=\"false\"\n                encrypted=\"false\" type=\"Integer\">\n                <esf:value>0</esf:value>\n            </esf:property>\n            <esf:property name=\"store.purge-age\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>60</esf:value>\n            </esf:property>\n            <esf:property name=\"in-flight-messages.republish-on-new-session\" array=\"false\"\n                encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"store.capacity\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>1000</esf:value>\n            </esf:property>\n            <esf:property name=\"disconnect.quiesce-timeout\" array=\"false\" encrypted=\"false\"\n                type=\"Integer\">\n                <esf:value>10</esf:value>\n            </esf:property>\n            <esf:property name=\"connect.auto-on-startup\" array=\"false\" encrypted=\"false\"\n                type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property name=\"connect.retry-interval\" array=\"false\" encrypted=\"false\"\n                type=\"Integer\">\n                <esf:value>60</esf:value>\n            </esf:property>\n            <esf:property name=\"service.pid\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>org.eclipse.kura.data.DataService</esf:value>\n            </esf:property>\n            <esf:property name=\"in-flight-messages.max-number\" array=\"false\" encrypted=\"false\"\n                type=\"Integer\">\n                <esf:value>9</esf:value>\n            </esf:property>\n            <esf:property name=\"store.housekeeper-interval\" array=\"false\" encrypted=\"false\"\n                type=\"Integer\">\n                <esf:value>900</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.cloud.CloudService\">\n        <esf:properties>\n            <esf:property name=\"encode.gzip\" array=\"false\" encrypted=\"false\" type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property name=\"device.display-name\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>Kura Emulator</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"users.config\" type=\"String\">\n                <esf:value>\n                    [{\"name\":\"kura.user.admin\",\"credentials\":{\"kura.password\":\"jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg=\"}}]</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"groups.config\" type=\"String\">\n                <esf:value>[{\"name\":\"kura.permission.kura.admin\",\"basicMembers\":[\"kura.user.admin\"]},{\"name\":\"kura.permission.kura.cloud.connection.admin\"},{\"name\":\"kura.permission.kura.device\"},{\"name\":\"kura.permission.kura.maintenance\"},{\"name\":\"kura.permission.kura.packages.admin\"},{\"name\":\"kura.permission.kura.wires.admin\"},{\"name\":\"kura.permission.rest.assets\"},{\"name\":\"kura.permission.rest.cloudconnection\"},{\"name\":\"kura.permission.rest.command\"},{\"name\":\"kura.permission.rest.configuration\"},{\"name\":\"kura.permission.rest.deploy\"},{\"name\":\"kura.permission.rest.identity\"},{\"name\":\"kura.permission.rest.inventory\"},{\"name\":\"kura.permission.rest.keystores\"},{\"name\":\"kura.permission.rest.position\"},{\"name\":\"kura.permission.rest.security\"},{\"name\":\"kura.permission.rest.system\"},{\"name\":\"kura.permission.rest.tamper.detection\"},{\"name\":\"kura.permission.rest.wires.admin\"}]</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.ssl.SslManagerService\">\n        <esf:properties>\n            <esf:property name=\"ssl.default.protocol\" array=\"false\" encrypted=\"false\" type=\"String\">\n                <esf:value>TLSv1.2</esf:value>\n            </esf:property>\n            <esf:property name=\"ssl.hostname.verification\" array=\"false\" encrypted=\"false\"\n                type=\"Boolean\">\n                <esf:value>true</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"KeystoreService.target\"\n                type=\"String\">\n                <esf:value>(kura.service.pid=SSLKeystore)</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.ssl.SslManagerService</esf:value>\n            </esf:property>\n            <esf:property name=\"service.ranking\" array=\"false\" encrypted=\"false\" type=\"Integer\">\n                <esf:value>100</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"SSLKeystore\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"keystore.path\" type=\"String\">\n                <esf:value>/tmp/kura/user/security/cacerts.ks</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"true\" name=\"keystore.password\" type=\"Password\">\n                <esf:value>Y2hhbmdlaXQ=</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"randomize.password\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>SSLKeystore</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.http.server.manager.HttpService\">\n        <esf:properties>\n            <esf:property array=\"true\" encrypted=\"false\" name=\"http.ports\" type=\"Integer\">\n                <esf:value>8080</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.provisioning.ProvisioningService\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.provisioning.ProvisioningService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"CloudConnectionManager.target\"\n                type=\"String\">\n                <esf:value>(kura.service.pid=org.eclipse.kura.cloud.CloudService)</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.provisioning.ProvisioningService</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.internal.rest.provider.RestService\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"auth.basic.enabled\" type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"auth.certificate.stateless.enabled\"\n                type=\"Boolean\">\n                <esf:value>false</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.internal.rest.provider.RestService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.internal.rest.provider.RestService</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n    <esf:configuration pid=\"org.eclipse.kura.db.H2DbService\">\n        <esf:properties>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.user\" type=\"String\">\n                <esf:value>SA</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.connection.pool.max.size\" type=\"Integer\">\n                <esf:value>10</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.connector.url\" type=\"String\">\n                <esf:value>jdbc:h2:mem:kuradb</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"service.factoryPid\" type=\"String\">\n                <esf:value>org.eclipse.kura.core.db.H2DbService</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"db.checkpoint.interval.seconds\" type=\"Integer\">\n                <esf:value>900</esf:value>\n            </esf:property>\n            <esf:property array=\"false\" encrypted=\"false\" name=\"kura.service.pid\" type=\"String\">\n                <esf:value>org.eclipse.kura.db.H2DbService</esf:value>\n            </esf:property>\n        </esf:properties>\n    </esf:configuration>\n</esf:configurations>\n"
  },
  {
    "path": "kura/tools/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>kura</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>tools</artifactId>\n    <packaging>pom</packaging>\n    <name>tools</name>\n\n    <modules>\n        <module>kura-addon-archetype</module>\n    </modules>\n\n</project>"
  },
  {
    "path": "kura/tools/update-cert.sh",
    "content": "#!/bin/bash\n\n#\n#  Copyright (c) 2025 Eurotech and/or its affiliates and others\n#\n#  This program and the accompanying materials are made\n#  available under the terms of the Eclipse Public License 2.0\n#  which is available at https://www.eclipse.org/legal/epl-2.0/\n#\n#  SPDX-License-Identifier: EPL-2.0\n#\n#  Contributors:\n#     Eurotech\n#\n\nset -e\n\nif [ \"$#\" -lt 4 ]; then\n    echo \"Usage: $0 <host:port> <keystore_path> <alias> <keystore_password>\"\n    echo \"Example: $0 marketplace.eclipse.org:443 /path/to/keystore.jks marketplace changeit\"\n    exit 1\nfi\n\nHOST_PORT=\"$1\"\nKEYSTORE_PATH=\"$2\"\nALIAS=\"$3\"\nKEYSTORE_PASSWORD=\"$4\"\n\nHOST=$(echo \"$HOST_PORT\" | cut -d':' -f1)\nPORT=$(echo \"$HOST_PORT\" | cut -d':' -f2)\n\nif [ -z \"$PORT\" ]; then\n    echo \"Error: Port not specified. Use format host:port\"\n    exit 1\nfi\n\nCERT_FILE=$(mktemp /tmp/cert_XXXXXX.pem)\n\necho \"Retrieving certificate from $HOST:$PORT...\"\nopenssl s_client -showcerts -connect \"$HOST:$PORT\" </dev/null 2>/dev/null | \\\n    sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' | \\\n    sed -n '1,/-----END CERTIFICATE-----/p' > \"$CERT_FILE\"\n\nif [ ! -s \"$CERT_FILE\" ]; then\n    echo \"Error: Failed to retrieve certificate\"\n    rm -f \"$CERT_FILE\"\n    exit 1\nfi\n\necho \"Certificate retrieved successfully\"\n\necho \"Removing existing alias '$ALIAS' from keystore (if exists)...\"\nkeytool -delete -alias \"$ALIAS\" -keystore \"$KEYSTORE_PATH\" -storepass \"$KEYSTORE_PASSWORD\" 2>/dev/null || true\n\necho \"Importing certificate with alias '$ALIAS'...\"\nkeytool -import -noprompt -alias \"$ALIAS\" -file \"$CERT_FILE\" -keystore \"$KEYSTORE_PATH\" -storepass \"$KEYSTORE_PASSWORD\"\n\nrm -f \"$CERT_FILE\"\n\necho \"Certificate updated successfully in keystore\"\n"
  },
  {
    "path": "suppressions.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!DOCTYPE suppressions PUBLIC \"-//Puppy Crawl//DTD Suppressions 1.1//EN\" \"http://checkstyle.sourceforge.net/dtds/suppressions_1_1.dtd\">\n\n<suppressions>\n    <suppress checks=\".*\" files=\".*generated-sources[\\\\/]\"/>\n    <suppress checks=\"FileLength\" files=\"NetworkConfiguration.java\"/>\n    <suppress checks=\"InterfaceIsType\" files=\"FirewallConfigurationServiceIPv6.java\"/>\n    <suppress checks=\"LineLength\" files=\"LoginBannerServiceOptions.java\"/>\n\n    <!-- suppress checks on autogenerated dbus interfacing sources -->\n    <suppress checks=\".\" files=\"kura[\\\\/]org.eclipse.kura.nm[\\\\/]src[\\\\/]main[\\\\/]java[\\\\/]org[\\\\/]freedesktop[\\\\/]\"/>\n    <suppress checks=\".\" files=\"kura[\\\\/]org.eclipse.kura.nm[\\\\/]src[\\\\/]main[\\\\/]java[\\\\/]fi[\\\\/]w1[\\\\/]\"/>\n</suppressions>\n\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n\t\t\n\t\t<h3>Third Party Content</h3>\n\t\t<p>The Content includes items that have been sourced from third parties as set out below. If you \n\t\tdid not receive this Content directly from the Eclipse Foundation, the following is provided \n\t\tfor informational purposes only, and you should look to the Redistributor's license for \n\t\tterms and conditions of use.</p>\n\t\t<p><em>\n\t\t<strong>com.codeminders.hidapi_1.1.0.jar</strong> <br/><br/>\n\t\tNew BSD license\n\t\t</em></p>\n\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/about_files/LICENSE-bsd.txt",
    "content": "Copyright (c) 2010, Alan Ott, Signal 11 Software\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Signal 11 Software nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/build.properties",
    "content": "source.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               src/main/lib/\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/build.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!--\n\n    Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n  \n    Contributors:\n     Eurotech\n \n-->\n<project basedir=\".\" default=\"build\" name=\"hidapi\" xmlns:artifact=\"antlib:org.apache.maven.artifact.ant\">\n  \n    <path id=\"maven-ant-tasks.classpath\" path=\"lib/maven-ant-tasks-2.1.3.jar\" />\n    <typedef resource=\"org/apache/maven/artifact/ant/antlib.xml\"\n           uri=\"antlib:org.apache.maven.artifact.ant\"\n           classpathref=\"maven-ant-tasks.classpath\" />\n  \n    <property name=\"debuglevel\" value=\"source,lines,vars\"/>\n    <property name=\"target\" value=\"1.6\"/>\n    <property name=\"source\" value=\"1.6\"/>\n    \n    <property name=\"src\" location=\"src\" />\n    <property name=\"build\" location=\"build\" />\n    <property name=\"dist\" location=\"dist\" />\n    \n    <!-- define Maven coordinates -->\n    <property name=\"groupId\" value=\"com.codeminders\" />\n    <property name=\"artifactId\" value=\"hidapi\" />\n    <property name=\"version\" value=\"1.1\" />\n\n    <!-- define artifacts' name, which follows the convention of Maven -->\n    <property name=\"maven-jar\" value=\"${dist}/lib/${artifactId}-${version}.jar\" />\n    <property name=\"maven-javadoc-jar\" value=\"${dist}/lib/${artifactId}-${version}-javadoc.jar\" />\n    <property name=\"maven-sources-jar\" value=\"${dist}/lib/${artifactId}-${version}-sources.jar\" />\n\n    <!-- defined maven snapshots and staging repository id and url -->\n    <property name=\"maven-snapshots-repository-id\" value=\"sonatype-nexus-snapshots\" />\n    <property name=\"maven-snapshots-repository-url\" value=\"https://oss.sonatype.org/content/repositories/snapshots\" />\n    <property name=\"maven-staging-repository-id\" value=\"sonatype-nexus-staging\" />\n    <property name=\"maven-staging-repository-url\" value=\"https://oss.sonatype.org/service/local/staging/deploy/maven2/\" />\n\n    <path id=\"hidapi.classpath\">\n        <pathelement location=\"bin\"/>\n        <pathelement location=\"${ANT_HOME}\"/>\n    </path>\n\n    <target name=\"init\">\n        <mkdir dir=\"${build}\" />\n\t<mkdir dir=\"${dist}/lib\" />\n        <copy includeemptydirs=\"false\" todir=\"${build}\">\n            <fileset dir=\"src\">\n                <exclude name=\"**/*.launch\"/>\n                <exclude name=\"**/*.java\"/>\n            </fileset>\n        </copy>\n    </target>\n\n    <target name=\"clean\">\n        <delete dir=\"${build}\"/>\n\t<delete dir=\"${dist}\"/>\n    </target>\n\n    <target depends=\"clean\" name=\"cleanall\"/>\n    <target depends=\"build-subprojects,build-project\" name=\"build\"/>\n    <target name=\"build-subprojects\"/>\n\n    <target depends=\"init\" name=\"build-project\">\n        <echo message=\"${ant.project.name}: ${ant.file}\"/>\n        <javac includeantruntime=\"true\" debug=\"true\" debuglevel=\"${debuglevel}\" destdir=\"${build}\" source=\"${source}\" target=\"${target}\">\n            <src path=\"src\"/>\n            <classpath refid=\"hidapi.classpath\"/>\n        </javac>\n    </target>\n\n    <target name=\"jni-stubs\" depends=\"build-project\">\n      <javah destdir=\"jni-stubs\" classpath=\"bin\">\n        <class name=\"com.codeminders.hidapi.HIDManager\"/>\n        <class name=\"com.codeminders.hidapi.HIDDevice\"/>\n        <class name=\"com.codeminders.hidapi.HIDDeviceInfo\"/>\n      </javah>    \n    </target>\n\n    <target name=\"print-jni-types\" depends=\"build-project\">\n      <exec executable=\"javap\">\n        <arg value=\"-private\" />\n        <arg value=\"-s\" />\n        <arg value=\"-classpath\" />\n        <arg value=\"${build}\" />\n        <arg value=\"com.codeminders.hidapi.HIDDevice\" />\n      </exec>\n\n      <exec executable=\"javap\">\n        <arg value=\"-private\" />\n        <arg value=\"-s\" />\n        <arg value=\"-classpath\" />\n        <arg value=\"${build}\" />\n        <arg value=\"com.codeminders.hidapi.HIDManager\" />\n      </exec>\n\n      <exec executable=\"javap\">\n        <arg value=\"-private\" />\n        <arg value=\"-s\" />\n        <arg value=\"-classpath\" />\n        <arg value=\"${build}\" />\n        <arg value=\"com.codeminders.hidapi.HIDDeviceInfo\" />\n      </exec>\n\n    </target>\n\n    <target name=\"run\" depends=\"build-project\">\n        <java classname=\"com.codeminders.hidapi.HIDAPITest\" failonerror=\"true\" fork=\"yes\">\n            <classpath refid=\"hidapi.classpath\"/>\n            <jvmarg value=\"-Djava.library.path=${basedir}/mac\"/>\n        </java>\n    </target>\n    \n    <target name=\"dist\" depends=\"build-project\" description=\"generate the distribution\">\n\n      <javadoc\n         destdir=\"${dist}/javadoc\"\n         author=\"true\"\n         version=\"true\"\n         use=\"true\"\n         windowtitle=\"HID API\">\n        <fileset dir=\"src\" defaultexcludes=\"yes\">\n          <include name=\"com/codeminders/hidapi/**\"/>\n          <exclude name=\"com/codeminders/hidapi/*Test*\"/>\n        </fileset>\n      </javadoc>\n      \n      <jar jarfile=\"${dist}/lib/${artifactId}-${version}-javadoc.jar\">\n          <fileset dir=\"${dist}/javadoc\" />\n      </jar>\n      \n      <!-- build the main artifact -->\n      <jar destfile=\"${dist}/lib/${artifactId}-${version}.jar\"\n           basedir=\"${build}\"\n           includes=\"com/codeminders/hidapi/**\"\n           excludes=\"**/HIDAPITest.class\"\n           >\n           <fileset dir=\"${basedir}/lib\">\n\t      <exclude name=\"*.jar\"/>\n\t   </fileset>  \n      </jar>\n      <!-- build the sources artifact -->\n      <jar destfile=\"${dist}/lib/${artifactId}-${version}-sources.jar\">\n          <fileset dir=\"src\" includes=\"**/*.java\"/>\n      </jar>\n    </target>\n    \n    <target name=\"deploy\" depends=\"dist\" description=\"deploy snapshot version to Maven snapshot repository\">\n\t\t<artifact:mvn>\n\t\t\t<arg value=\"org.apache.maven.plugins:maven-deploy-plugin:2.6:deploy-file\" />\n\t\t\t<arg value=\"-Durl=${maven-snapshots-repository-url}\" />\n\t\t\t<arg value=\"-DrepositoryId=${maven-snapshots-repository-id}\" />\n\t\t\t<arg value=\"-DpomFile=pom.xml\" />\n\t\t\t<arg value=\"-Dfile=${maven-jar}\" />\n\t\t</artifact:mvn>\n        </target>\n\n        <!-- before this, update project version (both build.xml and pom.xml) from SNAPSHOT to RELEASE -->\n\t<target name=\"stage\" depends=\"dist\" description=\"deploy release version to Maven staging repository\">\n\t\t<!-- sign and deploy the main artifact -->\n\t\t<artifact:mvn>\n\t\t\t<arg value=\"org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file\" />\n\t\t\t<arg value=\"-Durl=${maven-staging-repository-url}\" />\n\t\t\t<arg value=\"-DrepositoryId=${maven-staging-repository-id}\" />\n\t\t\t<arg value=\"-DpomFile=pom.xml\" />\n\t\t\t<arg value=\"-Dfile=${maven-jar}\" />\n                        <arg value=\"-Pgpg\" />\n\t\t</artifact:mvn>\n\n\t\t<!-- sign and deploy the sources artifact -->\n\t\t<artifact:mvn>\n\t\t\t<arg value=\"org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file\" />\n\t\t\t<arg value=\"-Durl=${maven-staging-repository-url}\" />\n\t\t\t<arg value=\"-DrepositoryId=${maven-staging-repository-id}\" />\n\t\t\t<arg value=\"-DpomFile=pom.xml\" />\n\t\t\t<arg value=\"-Dfile=${maven-sources-jar}\" />\n\t\t\t<arg value=\"-Dclassifier=sources\" />\n                        <arg value=\"-Pgpg\" />\n\t\t</artifact:mvn>\n\n\t\t<!-- sign and deploy the javadoc artifact -->\n\t\t<artifact:mvn>\n\t\t\t<arg value=\"org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file\" />\n\t\t\t<arg value=\"-Durl=${maven-staging-repository-url}\" />\n\t\t\t<arg value=\"-DrepositoryId=${maven-staging-repository-id}\" />\n\t\t\t<arg value=\"-DpomFile=pom.xml\" />\n\t\t\t<arg value=\"-Dfile=${maven-javadoc-jar}\" />\n\t\t\t<arg value=\"-Dclassifier=javadoc\" />\n                        <arg value=\"-Pgpg\" />\n\t\t</artifact:mvn>\n\t</target>\n\n</project>\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n  \n    Contributors:\n     Eurotech\n \n-->\n\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n    xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>com.codeminders.hidapi-parent</artifactId>\n        <version>2.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>com.codeminders.hidapi</artifactId>\n    <packaging>bundle</packaging>\n\n    <name>Java API for working with Human Interface USB Devices (HID)</name>\n    <description>JNI wrapper around C/C++ HIDAPI library providing simple java API to work with devices such as USB gamepads, joysticks, keyboards etc.</description>\n    <url>http://code.google.com/p/javahidapi</url>\n\n    <licenses>\n        <license>\n            <name>New BSD License</name>\n            <url>http://opensource.org/licenses/BSD-3-Clause</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n    <scm>\n        <connection>scm:hg:http://code.google.com/p/javahidapi</connection>\n        <developerConnection>scm:hg:https://code.google.com/p/javahidapi</developerConnection>\n        <url>http://code.google.com/p/javahidapi</url>\n    </scm>\n    <developers>\n        <developer>\n            <id>lord</id>\n            <name>Vadim Zaliva</name>\n            <email>lord@codeminders.com</email>\n        </developer>\n        <developer>\n            <id>Alexander Sova</id>\n            <name>Vadim Zaliva</name>\n            <email>bird@codeminders.com</email>\n        </developer>\n        <developer>\n            <id>dshmyga</id>\n            <name>Denis Shmyga</name>\n            <email>dshmyga@codeminders.com</email>\n        </developer>\n    </developers>\n\n    <dependencies>\n        <dependency>\n\t\t\t<groupId>org.eclipse.platform</groupId>\n\t\t\t<artifactId>org.eclipse.osgi</artifactId>\n\t\t\t<version>3.12.50</version>\n\t\t</dependency>\n    </dependencies>\n\n    <build>\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>.</directory>\n                <includes>\n                    <include>plugin.xml</include>\n                </includes>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>${maven-bundle-plugin.version}</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Include-Resource>\n                            ${project.basedir}/about.html,\n                            about_files=${project.basedir}/about_files/\n                        </Include-Resource>\n                        <Export-Package>\n                            com.codeminders.hidapi\n                        </Export-Package>\n                    </instructions>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>${maven-dependency-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n        </plugins>\n        <pluginManagement>\n            <plugins>\n                <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>${lifecycle-mapping.version}</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.apache.maven.plugins\n                                        </groupId>\n                                        <artifactId>\n                                            maven-dependency-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [2.1,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>\n                                                copy-dependencies\n                                            </goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/AUTHORS.txt",
    "content": "\nHIDAPI Authors:\n\nAlan Ott <alan@signal11.us>:\n\tOriginal Author and Maintainer\n\tLinux, Windows, and Mac implementations\n\nLudovic Rousseau <rousseau@debian.org>:\n\tFormatting for Doxygen documentation\n\tBug fixes\n\tCorrectness fixes\n\n\nFor a comprehensive list of contributions, see the commit list at github:\n\thttp://github.com/signal11/hidapi/commits/master\n\n\nJava binding Authors:\n\nVadim Zaliva <lord@crocodile.org>\nAlex Sova <bird@codeminders.com>\n\ndevelopemnt of Java bindings sponsored Codeminders: www.codeminders.com\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/LICENSE-bsd.txt",
    "content": "Copyright (c) 2010, Alan Ott, Signal 11 Software\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Signal 11 Software nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/LICENSE-gpl3.txt",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/LICENSE-orig.txt",
    "content": " HIDAPI - Multi-Platform library for\n communication with HID devices.\n\n Copyright 2009, Alan Ott, Signal 11 Software.\n All Rights Reserved.\n \n This software may be used by anyone for any reason so\n long as the copyright notice in the source files\n remains intact.\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/LICENSE.txt",
    "content": "HIDAPI can be used under one of three licenses.\n\n1. The GNU Public License, version 3.0, in LICENSE-gpl3.txt\n2. A BSD-Style License, in LICENSE-bsd.txt.\n3. The more liberal original HIDAPI license. LICENSE-orig.txt\n\nThe license chosen is at the discretion of the user of HIDAPI. For example:\n1. An author of GPL software would likely use HIDAPI under the terms of the\nGPL.\n\n2. An author of commercial closed-source software would likely use HIDAPI\nunder the terms of the BSD-style license or the original HIDAPI license.\n\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/hidapi/hidapi.h",
    "content": "/*******************************************************\n HIDAPI - Multi-Platform library for\n communication with HID devices.\n\n Alan Ott\n Signal 11 Software\n\n 8/22/2009\n\n Copyright 2009, All Rights Reserved.\n\n At the discretion of the user of this library,\n this software may be licensed under the terms of the\n GNU Public License v3, a BSD-Style license, or the\n original HIDAPI license as outlined in the LICENSE.txt,\n LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt\n files located at the root of the source distribution.\n These files may also be found in the public source\n code repository located at:\n        http://github.com/signal11/hidapi .\n********************************************************/\n\n/** @file\n * @defgroup API hidapi API\n */\n\n#ifndef HIDAPI_H__\n#define HIDAPI_H__\n\n#include <wchar.h>\n\n#ifdef _WIN32\n      #define HID_API_EXPORT __declspec(dllexport)\n      #define HID_API_CALL\n#else\n      #define HID_API_EXPORT /**< API export macro */\n      #define HID_API_CALL /**< API call macro */\n#endif\n\n#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n        struct hid_device_;\n        typedef struct hid_device_ hid_device; /**< opaque hidapi structure */\n\n        /** hidapi info structure */\n        struct hid_device_info {\n            /** Platform-specific device path */\n            char *path;\n            /** Device Vendor ID */\n            unsigned short vendor_id;\n            /** Device Product ID */\n            unsigned short product_id;\n            /** Serial Number */\n            wchar_t *serial_number;\n            /** Device Release Number in binary-coded decimal,\n                also known as Device Version Number */\n            unsigned short release_number;\n            /** Manufacturer String */\n            wchar_t *manufacturer_string;\n            /** Product string */\n            wchar_t *product_string;\n            /** Usage Page for this Device/Interface\n                (Windows/Mac only). */\n            unsigned short usage_page;\n            /** Usage for this Device/Interface\n                (Windows/Mac only).*/\n            unsigned short usage;\n            /** The USB interface which this logical device\n                represents. Valid on both Linux implementations\n                in all cases, and valid on the Windows implementation\n                only if the device contains more than one interface. */\n            int interface_number;\n\n            /** Pointer to the next device */\n            struct hid_device_info *next;\n        };\n\n\n        /** @brief Initialize the HIDAPI library.\n\n            This function initializes the HIDAPI library. Calling it is not\n            strictly necessary, as it will be called automatically by\n            hid_enumerate() and any of the hid_open_*() functions if it is\n            needed.  This function should be called at the beginning of\n            execution however, if there is a chance of HIDAPI handles\n            being opened by different threads simultaneously.\n            \n            @ingroup API\n\n            @returns\n                This function returns 0 on success and -1 on error.\n        */\n        int HID_API_EXPORT HID_API_CALL hid_init(void);\n\n        /** @brief Finalize the HIDAPI library.\n\n            This function frees all of the static data associated with\n            HIDAPI. It should be called at the end of execution to avoid\n            memory leaks.\n\n            @ingroup API\n\n            @returns\n                This function returns 0 on success and -1 on error.\n        */\n        int HID_API_EXPORT HID_API_CALL hid_exit(void);\n\n        /** @brief Enumerate the HID Devices.\n\n            This function returns a linked list of all the HID devices\n            attached to the system which match vendor_id and product_id.\n            If @p vendor_id and @p product_id are both set to 0, then\n            all HID devices will be returned.\n\n            @ingroup API\n            @param vendor_id The Vendor ID (VID) of the types of device\n                to open.\n            @param product_id The Product ID (PID) of the types of\n                device to open.\n\n            @returns\n                This function returns a pointer to a linked list of type\n                struct #hid_device, containing information about the HID devices\n                attached to the system, or NULL in the case of failure. Free\n                this linked list by calling hid_free_enumeration().\n        */\n        struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);\n\n        /** @brief Free an enumeration Linked List\n\n            This function frees a linked list created by hid_enumerate().\n\n            @ingroup API\n            @param devs Pointer to a list of struct_device returned from\n                      hid_enumerate().\n        */\n        void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);\n\n        /** @brief Open a HID device using a Vendor ID (VID), Product ID\n            (PID) and optionally a serial number.\n\n            If @p serial_number is NULL, the first device with the\n            specified VID and PID is opened.\n\n            @ingroup API\n            @param vendor_id The Vendor ID (VID) of the device to open.\n            @param product_id The Product ID (PID) of the device to open.\n            @param serial_number The Serial Number of the device to open\n                               (Optionally NULL).\n\n            @returns\n                This function returns a pointer to a #hid_device object on\n                success or NULL on failure.\n        */\n\t\tHID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);\n\n        /** @brief Open a HID device by its path name.\n\n            The path name be determined by calling hid_enumerate(), or a\n            platform-specific path name can be used (eg: /dev/hidraw0 on\n            Linux).\n\n            @ingroup API\n            @param path The path name of the device to open\n\n            @returns\n                This function returns a pointer to a #hid_device object on\n                success or NULL on failure.\n        */\n        HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);\n\n        /** @brief Write an Output report to a HID device.\n\n            The first byte of @p data[] must contain the Report ID. For\n            devices which only support a single report, this must be set\n            to 0x0. The remaining bytes contain the report data. Since\n            the Report ID is mandatory, calls to hid_write() will always\n            contain one more byte than the report contains. For example,\n            if a hid report is 16 bytes long, 17 bytes must be passed to\n            hid_write(), the Report ID (or 0x0, for devices with a\n            single report), followed by the report data (16 bytes). In\n            this example, the length passed in would be 17.\n\n            hid_write() will send the data on the first OUT endpoint, if\n            one exists. If it does not, it will send the data through\n            the Control Endpoint (Endpoint 0).\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param data The data to send, including the report number as\n                the first byte.\n            @param length The length in bytes of the data to send.\n\n            @returns\n                This function returns the actual number of bytes written and\n                -1 on error.\n        */\n        int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);\n    \n        /** @brief Read an Input report from a HID device with timeout.\n\n            Input reports are returned\n            to the host through the INTERRUPT IN endpoint. The first byte will\n            contain the Report number if the device uses numbered reports.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param data A buffer to put the read data into.\n            @param length The number of bytes to read. For devices with\n                multiple reports, make sure to read an extra byte for\n                the report number.\n            @param milliseconds timeout in milliseconds or -1 for blocking wait.\n\n            @returns\n                This function returns the actual number of bytes read and\n                -1 on error.\n        */\n        int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);\n\n        /** @brief Read an Input report from a HID device.\n\n            Input reports are returned\n            to the host through the INTERRUPT IN endpoint. The first byte will\n            contain the Report number if the device uses numbered reports.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param data A buffer to put the read data into.\n            @param length The number of bytes to read. For devices with\n                multiple reports, make sure to read an extra byte for\n                the report number.\n\n            @returns\n                This function returns the actual number of bytes read and\n                -1 on error.\n        */\n        int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);\n\n        /** @brief Set the device handle to be non-blocking.\n\n            In non-blocking mode calls to hid_read() will return\n            immediately with a value of 0 if there is no data to be\n            read. In blocking mode, hid_read() will wait (block) until\n            there is data to read before returning.\n\n            Nonblocking can be turned on and off at any time.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param nonblock enable or not the nonblocking reads\n             - 1 to enable nonblocking\n             - 0 to disable nonblocking.\n\n            @returns\n                This function returns 0 on success and -1 on error.\n        */\n        int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);\n\n        /** @brief Send a Feature report to the device.\n\n            Feature reports are sent over the Control endpoint as a\n            Set_Report transfer.  The first byte of @p data[] must\n            contain the Report ID. For devices which only support a\n            single report, this must be set to 0x0. The remaining bytes\n            contain the report data. Since the Report ID is mandatory,\n            calls to hid_send_feature_report() will always contain one\n            more byte than the report contains. For example, if a hid\n            report is 16 bytes long, 17 bytes must be passed to\n            hid_send_feature_report(): the Report ID (or 0x0, for\n            devices which do not use numbered reports), followed by the\n            report data (16 bytes). In this example, the length passed\n            in would be 17.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param data The data to send, including the report number as\n                the first byte.\n            @param length The length in bytes of the data to send, including\n                the report number.\n\n            @returns\n                This function returns the actual number of bytes written and\n                -1 on error.\n        */\n        int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);\n\n        /** @brief Get a feature report from a HID device.\n\n            Make sure to set the first byte of @p data[] to the Report\n            ID of the report to be read.  Make sure to allow space for\n            this extra byte in @p data[].\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param data A buffer to put the read data into, including\n                the Report ID. Set the first byte of @p data[] to the\n                Report ID of the report to be read.\n            @param length The number of bytes to read, including an\n                extra byte for the report ID. The buffer can be longer\n                than the actual report.\n\n            @returns\n                This function returns the number of bytes read and\n                -1 on error.\n        */\n        int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);\n\n        /** @brief Close a HID device.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n        */\n        void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);\n\n        /** @brief Get The Manufacturer String from a HID device.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param string A wide string buffer to put the data into.\n            @param maxlen The length of the buffer in multiples of wchar_t.\n\n            @returns\n                This function returns 0 on success and -1 on error.\n        */\n        int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);\n\n        /** @brief Get The Product String from a HID device.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param string A wide string buffer to put the data into.\n            @param maxlen The length of the buffer in multiples of wchar_t.\n\n            @returns\n                This function returns 0 on success and -1 on error.\n        */\n        int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);\n\n        /** @brief Get The Serial Number String from a HID device.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param string A wide string buffer to put the data into.\n            @param maxlen The length of the buffer in multiples of wchar_t.\n\n            @returns\n                This function returns 0 on success and -1 on error.\n        */\n        int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);\n\n        /** @brief Get a string from a HID device, based on its string index.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n            @param string_index The index of the string to get.\n            @param string A wide string buffer to put the data into.\n            @param maxlen The length of the buffer in multiples of wchar_t.\n\n            @returns\n                This function returns 0 on success and -1 on error.\n        */\n        int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);\n\n        /** @brief Get a string describing the last error which occurred.\n\n            @ingroup API\n            @param device A device handle returned from hid_open().\n\n            @returns\n                This function returns a string containing the last error\n                which occurred or NULL if none has occurred.\n        */\n        HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/hidtest/hidtest.cpp",
    "content": "/*******************************************************\n Windows HID simplification\n\n Alan Ott\n Signal 11 Software\n\n 8/22/2009\n\n Copyright 2009, All Rights Reserved.\n \n This contents of this file may be used by anyone\n for any reason without any conditions and may be\n used as a starting point for your own applications\n which use HIDAPI.\n********************************************************/\n\n#include <stdio.h>\n#include <wchar.h>\n#include <string.h>\n#include <stdlib.h>\n#include \"hidapi.h\"\n\n// Headers needed for sleeping.\n#ifdef _WIN32\n\t#include <windows.h>\n#else\n\t#include <unistd.h>\n#endif\n\nint main(int argc, char* argv[])\n{\n\tint res;\n\tunsigned char buf[256];\n\t#define MAX_STR 255\n\twchar_t wstr[MAX_STR];\n\thid_device *handle;\n\tint i;\n\n#ifdef WIN32\n\tUNREFERENCED_PARAMETER(argc);\n\tUNREFERENCED_PARAMETER(argv);\n#endif\n\n\tstruct hid_device_info *devs, *cur_dev;\n\t\n\tdevs = hid_enumerate(0x0, 0x0);\n\tcur_dev = devs;\t\n\twhile (cur_dev) {\n\t\tprintf(\"Device Found\\n  type: %04hx %04hx\\n  path: %s\\n  serial_number: %ls\", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);\n\t\tprintf(\"\\n\");\n\t\tprintf(\"  Manufacturer: %ls\\n\", cur_dev->manufacturer_string);\n\t\tprintf(\"  Product:      %ls\\n\", cur_dev->product_string);\n\t\tprintf(\"  Release:      %hx\\n\", cur_dev->release_number);\n\t\tprintf(\"  Interface:    %d\\n\",  cur_dev->interface_number);\n\t\tprintf(\"\\n\");\n\t\tcur_dev = cur_dev->next;\n\t}\n\thid_free_enumeration(devs);\n\n\t// Set up the command buffer.\n\tmemset(buf,0x00,sizeof(buf));\n\tbuf[0] = 0x01;\n\tbuf[1] = 0x81;\n\t\n\n\t// Open the device using the VID, PID,\n\t// and optionally the Serial number.\n\t////handle = hid_open(0x4d8, 0x3f, L\"12345\");\n\thandle = hid_open(0x54c, 0x268, NULL);\n\tif (!handle) {\n\t\tprintf(\"unable to open device\\n\");\n \t\treturn 1;\n\t}\n\n\t// Read the Manufacturer String\n\twstr[0] = 0x0000;\n\tres = hid_get_manufacturer_string(handle, wstr, MAX_STR);\n\tif (res < 0)\n\t\tprintf(\"Unable to read manufacturer string\\n\");\n\tprintf(\"Manufacturer String: %ls\\n\", wstr);\n\n\t// Read the Product String\n\twstr[0] = 0x0000;\n\tres = hid_get_product_string(handle, wstr, MAX_STR);\n\tif (res < 0)\n\t\tprintf(\"Unable to read product string\\n\");\n\tprintf(\"Product String: %ls\\n\", wstr);\n\n\t// Read the Serial Number String\n\twstr[0] = 0x0000;\n\tres = hid_get_serial_number_string(handle, wstr, MAX_STR);\n\tif (res < 0)\n\t\tprintf(\"Unable to read serial number string\\n\");\n\tprintf(\"Serial Number String: (%d) %ls\", wstr[0], wstr);\n\tprintf(\"\\n\");\n\n\t// Read Indexed String 1\n\twstr[0] = 0x0000;\n\tres = hid_get_indexed_string(handle, 1, wstr, MAX_STR);\n\tif (res < 0)\n\t\tprintf(\"Unable to read indexed string 1\\n\");\n\tprintf(\"Indexed String 1: %ls\\n\", wstr);\n\n\t// Set the hid_read() function to be non-blocking.\n\thid_set_nonblocking(handle, 1);\n\n\tmemset(buf,0,sizeof(buf));\n\t\n\t// Read requested state. hid_read() has been set to be\n\t// non-blocking by the call to hid_set_nonblocking() above.\n\t// This loop demonstrates the non-blocking nature of hid_read().\n\tres = 0;\n\twhile (res == 0) {\n\t\tres = hid_read(handle, buf, sizeof(buf));\n\t\tif (res == 0)\n\t\t\tprintf(\"waiting...\\n\");\n\t\tif (res < 0)\n\t\t\tprintf(\"Unable to read()\\n\");\n\t\t#ifdef WIN32\n\t\tSleep(500);\n\t\t#else\n\t\tusleep(500*1000);\n\t\t#endif\n\t}\n\n\tprintf(\"Data read:\\n   \");\n\t// Print out the returned buffer.\n\tfor (i = 0; i < res; i++)\n\t\tprintf(\"%02hhx \", buf[i]);\n\tprintf(\"\\n\");\n\n\thid_close(handle);\n\n\t/* Free static HIDAPI objects. */\n\thid_exit();\n\n#ifdef WIN32\n\tsystem(\"pause\");\n#endif\n\n\treturn 0;\n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/jni-impl/HIDDevice.cpp",
    "content": "#include <stdio.h>\n#include <assert.h>\n#include <stdlib.h>\n\n#include <jni-stubs/com_codeminders_hidapi_HIDDevice.h>\n#include \"hidapi/hidapi.h\"\n#include \"hid-java.h\"\n\n#define MAX_BUFFER_SIZE 2014\n\nstatic hid_device* getPeer(JNIEnv *env, jobject self)\n{\n    jclass cls = env->FindClass(DEV_CLASS);\n    assert(cls!=NULL);\n    if (cls == NULL) \n        return NULL;\n    jfieldID fid = env->GetFieldID(cls, \"peer\", \"J\");\n    return (hid_device*)(env->GetLongField(self, fid));\n}\n\nstatic void setPeer(JNIEnv *env, jobject self, hid_device *peer)\n{\n    jclass cls = env->FindClass(DEV_CLASS);\n    assert(cls!=NULL);\n    if (cls == NULL) \n        return; //TODO: exception will be raised by FindClass\n    jfieldID fid = env->GetFieldID(cls, \"peer\", \"J\");\n    jlong peerj = (jlong)peer;\n    env->SetLongField(self, fid, peerj);     \n}\n\nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_close\n  (JNIEnv *env, jobject self)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer) \n    {\n        throwIOException(env, peer);\n        return; /* not an error, freed previously */ \n    }\n    hid_close(peer);\n    setPeer(env, self, NULL);\n}\n\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_write\n  (JNIEnv *env, jobject self, jbyteArray data)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer) \n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n\n    jsize bufsize = env->GetArrayLength(data);\n    jbyte *buf = env->GetByteArrayElements(data, NULL);\n    int res = hid_write(peer, (const unsigned char*) buf, bufsize);\n    env->ReleaseByteArrayElements(data, buf, JNI_ABORT);\n    if(res==-1)\n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n    return res;\n}\n\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_read\n  (JNIEnv *env, jobject self, jbyteArray data)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer) \n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n\n    jsize bufsize = env->GetArrayLength(data);\n    jbyte *buf = env->GetByteArrayElements(data, NULL);\n    int read = hid_read(peer, (unsigned char*) buf, bufsize);\n    env->ReleaseByteArrayElements(data, buf, read==-1?JNI_ABORT:0);\n    if(read==-1)\n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n    return read;\n}\n\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_readTimeout\n(JNIEnv *env, jobject self, jbyteArray data, jint milliseconds )\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer) \n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n    \n    jsize bufsize = env->GetArrayLength(data);\n    jbyte *buf = env->GetByteArrayElements(data, NULL);\n    int read = hid_read_timeout(peer, (unsigned char*) buf, bufsize, milliseconds);\n    env->ReleaseByteArrayElements(data, buf, read==-1?JNI_ABORT:0);\n    if(read == 0) /* time out */\n    {\n        return 0;\n    }\n    else if(read == -1)\n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n    return read;\n}\n\nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_enableBlocking\n  (JNIEnv *env, jobject self)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer)\n    {\n        throwIOException(env, peer);\n        return; /* not an error, freed previously */ \n    }\n    int res = hid_set_nonblocking(peer,0);\n    if(res!=0)\n    {\n        throwIOException(env, peer);\n        return; /* not an error, freed previously */ \n    }\n}\n\nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_disableBlocking\n  (JNIEnv *env, jobject self)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer)\n    {\n        throwIOException(env, peer);\n        return; /* not an error, freed previously */ \n    }\n    int res = hid_set_nonblocking(peer, 1);\n    if(res!=0)\n    {\n        throwIOException(env, peer);\n        return; /* not an error, freed previously */ \n    }\n}\n\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_sendFeatureReport\n  (JNIEnv *env, jobject self, jbyteArray data)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer)\n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n    jsize bufsize = env->GetArrayLength(data);\n    jbyte *buf = env->GetByteArrayElements(data, NULL);\n    int res = hid_send_feature_report(peer, (const unsigned char*) buf, bufsize);\n    env->ReleaseByteArrayElements(data, buf, JNI_ABORT);\n    if(res==-1)\n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n    \n    return res;\n}\n\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_getFeatureReport\n  (JNIEnv *env, jobject self, jbyteArray data)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer)\n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n\n    jsize bufsize = env->GetArrayLength(data);\n    jbyte *buf = env->GetByteArrayElements(data, NULL);\n    int res = hid_get_feature_report(peer, (unsigned char*) buf, bufsize);\n    env->ReleaseByteArrayElements(data, buf, res==-1?JNI_ABORT:0);\n    if(res==-1)\n    {\n        throwIOException(env, peer);\n        return 0; /* not an error, freed previously */ \n    }\n    \n    return res;\n}\n\nJNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getManufacturerString\n  (JNIEnv *env, jobject self)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer)\n    {\n        throwIOException(env, peer);\n        return NULL; /* not an error, freed previously */ \n    }\n\n    wchar_t data[MAX_BUFFER_SIZE];\n    int res = hid_get_manufacturer_string(peer, data, MAX_BUFFER_SIZE);\n    if(res < 0)\n    {\n        /* We decided not to treat this as an error, but return an empty string in this case\n           throwIOException(env, peer);\n           return NULL;\n        */\n        data[0] = 0;\n    }\n        \n    char *u8 = convertToUTF8(env, data);\n    jstring string = env->NewStringUTF(u8);\n    free(u8);\n    \n    return string;\n}\n\n#include <stdlib.h>\n\nJNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getProductString\n  (JNIEnv *env, jobject self)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer)\n    {\n        throwIOException(env, peer);\n        return NULL; /* not an error, freed previously */ \n    }\n\n    wchar_t data[MAX_BUFFER_SIZE];\n    int res = hid_get_product_string(peer, data, MAX_BUFFER_SIZE);\n    if(res < 0)\n    {\n        /* We decided not to treat this as an error, but return an empty string in this case\n        throwIOException(env, peer);\n        return NULL;\n        */\n        data[0] = 0;\n    }\n       \n    char *u8 = convertToUTF8(env, data);\n    jstring string = env->NewStringUTF(u8);\n    free(u8);\n    \n    return string;\n}\n\nJNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getSerialNumberString\n  (JNIEnv *env, jobject self)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer)\n    {\n        throwIOException(env, peer);\n        return NULL; /* not an error, freed previously */ \n    }\n\n    wchar_t data[MAX_BUFFER_SIZE];\n    int res = hid_get_serial_number_string(peer, data, MAX_BUFFER_SIZE);\n    if(res < 0)\n    {\n        /* We decided not to treat this as an error, but return an empty string in this case\n        throwIOException(env, peer);\n        return NULL;\n        */\n        data[0] = 0;\n    }\n        \n    char *u8 = convertToUTF8(env, data);\n    jstring string = env->NewStringUTF(u8);\n    free(u8);\n    \n    return string;\n}\n    \nJNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getIndexedString\n  (JNIEnv *env, jobject self, jint index)\n{\n    hid_device *peer = getPeer(env, self);\n    if(!peer)\n    {\n        throwIOException(env, peer);\n        return NULL; /* not an error, freed previously */ \n    }\n\n    wchar_t data[MAX_BUFFER_SIZE];\n    int res = hid_get_indexed_string(peer, index, data, MAX_BUFFER_SIZE);\n    if(res < 0)\n    {\n        /* We decided not to treat this as an error, but return an empty string in this case\n        throwIOException(env, peer);\n        return NULL;\n        */\n        data[0] = 0;\n    }\n        \n    char *u8 = convertToUTF8(env, data);\n    jstring string = env->NewStringUTF(u8);\n    free(u8);\n    \n    return string;\n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/jni-impl/HIDDeviceInfo.cpp",
    "content": "\n#include \"jni-stubs/com_codeminders_hidapi_HIDDeviceInfo.h\"\n#include \"hidapi/hidapi.h\"\n#include \"hid-java.h\"\n\nJNIEXPORT jobject JNICALL Java_com_codeminders_hidapi_HIDDeviceInfo_open\n  (JNIEnv *env, jobject obj)\n{\n    jclass thiscls = env->FindClass(DEVINFO_CLASS);\n    if (!thiscls)\n        return NULL;\n    \n    jfieldID path_field_id = env->GetFieldID(thiscls, \"path\", \"Ljava/lang/String;\");\n    jstring jpathstr = (jstring) env->GetObjectField(obj, path_field_id);\n\n    const char *jpathbytes = env->GetStringUTFChars(jpathstr, NULL);\n    if(!jpathbytes)\n        return NULL;\n    \n    hid_device *dev = hid_open_path(jpathbytes);\n    env->ReleaseStringUTFChars(jpathstr, jpathbytes); \n    if(!dev)\n        return NULL;\n    \n    jlong peer = (jlong)dev;\n    // Construct and return object\n    jclass cls = env->FindClass(DEV_CLASS);\n    if (cls == NULL) {\n        return NULL; /* exception thrown */\n    }\n\n    jmethodID cid = env->GetMethodID(cls,\n                                        \"<init>\", \"(J)V\");\n    if (cid == NULL) {\n        return NULL; /* exception thrown */\n    }\n    return env->NewObject(cls, cid, peer);\n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/jni-impl/HIDManager.cpp",
    "content": "\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"jni-stubs/com_codeminders_hidapi_HIDManager.h\"\n#include \"hidapi/hidapi.h\"\n#include \"hid-java.h\"\n\n#ifdef MAC_OS_X\n#include <CoreFoundation/CoreFoundation.h>\n#include <unistd.h>\n#include <pthread.h>\n#endif\n\n#ifdef MAC_OS_X\n#define HID_RUN_LOOP\n#endif\n\n#define JNI_DEBUG 0\n\n\nstatic JNIEnv *m_env = NULL;\nstatic JavaVM *m_vm = NULL;\n\n/* JNI reference count */\nstatic int jni_ref_count = 0;\n\n#ifdef  HID_RUN_LOOP \n#define SLEEP_TIME    100 * 1000\nstatic volatile int squit = 0;\nstatic int hid_mgr_init = 0;\nstatic int cond = FALSE;\nstatic pthread_cond_t condition;\nstatic pthread_t runloop_thread = NULL;\nstatic CFRunLoopRef run_loop = NULL;\nstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;\n\n#endif\n\nstatic int init_hid_mgr()\n{\n#ifdef HID_RUN_LOOP \n    if(hid_mgr_init)\n    {\n        pthread_mutex_lock(&mutex);\n        while(cond == FALSE){\n            pthread_cond_wait(&condition, &mutex);\n        }\n        pthread_mutex_unlock(&mutex);\n        return 1;\n    }\n    return 0;\n#else\n    return 1;\n#endif\n}\n\n#ifdef  HID_RUN_LOOP \n\nstatic void *hid_runloop_thread(void *param)\n{\n    SInt32 code = 0;\n    \n    if( NULL == m_env )\n        return NULL;\n    \n    int res = m_vm->AttachCurrentThread( (void**) &m_env, NULL );\n    if(res < 0){\n    #if JNI_DEBUG        \n        printf(\"Attached failed\\n\");\n    #endif\n        return NULL;\n    }  \n    \n    run_loop = CFRunLoopGetCurrent();\n   \n    pthread_mutex_lock(&mutex);\n    \n    if(hid_init() == -1){\n        pthread_cond_destroy(&condition);\n        hid_mgr_init = 0;\n        return NULL;\n    }\n  \n    cond = true;\n    pthread_cond_signal(&condition);\n    pthread_mutex_unlock(&mutex);\n    while(!squit)\n    {\n        code = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false);\n        if( code == kCFRunLoopRunFinished ||  code == kCFRunLoopRunStopped )\n        {\n            break;\n        }\n#if JNI_DEBUG        \n        printf(\"HID run loop thread\\n\");\n#endif\n        usleep(SLEEP_TIME);\n    }\n    if(m_vm){\n       m_vm->DetachCurrentThread();\n    }\n    return NULL;\n}\n\nstatic int hid_runloop_startup()\n{  \n    if(hid_mgr_init)\n        return 0;\n    \n    hid_mgr_init = 1;\n    \n    if(squit)\n    { \n        pthread_cond_destroy(&condition);\n        pthread_join(runloop_thread, NULL);\n        squit = 0;\n    }\n    else \n    {\n        pthread_attr_t attr;\n        pthread_attr_init( &attr );\n        pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED );\n        pthread_cond_init(&condition, NULL);\n        squit = 0;\n        pthread_create(&runloop_thread, &attr, hid_runloop_thread, NULL);\n    }\n    hid_mgr_init = 1;\n    return 0;\n}\n\nstatic void hid_runloop_exit()\n{\n    squit = 1;\n    pthread_cond_destroy(&condition);\n    pthread_join(runloop_thread, NULL);\n    m_env = NULL;\n    m_vm = NULL;\n}\n\nstatic int hid_init_loop()\n{\n    return hid_runloop_startup();\n}\n\nstatic int hid_exit_loop()\n{\n    if(init_hid_mgr()){\n       hid_runloop_exit();\n       hid_mgr_init = 0;\n    }\n    return 0;\n}\n\n#endif\n\nstatic jobject getPeer(JNIEnv *env, jobject self)\n{\n    jclass cls = env->FindClass(HID_MANAGER_CLASS);\n    assert(cls!=NULL);\n    if (cls == NULL) \n        return NULL;\n    jfieldID fid = env->GetFieldID(cls, \"peer\", \"J\");\n    return (jobject)(env->GetLongField(self, fid));\n}\n\nstatic void setPeer(JNIEnv *env, jobject self, jobject peer)\n{\n    jclass cls = env->FindClass(HID_MANAGER_CLASS);\n    assert(cls!=NULL);\n    if (cls == NULL) \n        return; \n    jfieldID fid = env->GetFieldID(cls, \"peer\", \"J\");\n    jlong peerj = (jlong)peer;\n    env->SetLongField(self, fid, peerj);     \n}\n\nstatic void setIntField(JNIEnv *env,\n                        jclass cls,\n                        jobject obj,\n                        const char *name,\n                        int val)\n{\n    jfieldID fid = env->GetFieldID(cls, name, \"I\");\n    env->SetIntField(obj, fid, val);\n}\n\nstatic void setStringField(JNIEnv *env,\n                           jclass cls,\n                           jobject obj,\n                           const char *name,\n                           const char *val)\n{\n    jfieldID fid = env->GetFieldID(cls, name, \"Ljava/lang/String;\");\n    env->SetObjectField(obj, fid,  val ? env->NewStringUTF(val) : NULL);\n}\n\nstatic void setUStringField(JNIEnv *env,\n                           jclass cls,\n                           jobject obj,\n                           const char *name,\n                           const wchar_t *val)\n{\n    jfieldID fid = env->GetFieldID(cls, name, \"Ljava/lang/String;\");\n\n    if(val)\n    {\n        char *u8 = convertToUTF8(env, val);\n        env->SetObjectField(obj, fid, env->NewStringUTF(u8));\n        free(u8);\n    }\n    else\n        env->SetObjectField(obj, fid, NULL);\n}\n\n\nstatic jobject createHIDDeviceInfo(JNIEnv *env, jclass cls, struct hid_device_info *dev)\n{\n    jmethodID cid = env->GetMethodID(cls, \"<init>\", \"()V\");\n    if (cid == NULL) \n        return NULL; /* exception thrown. */ \n    \n    if (dev == NULL)\n        return NULL;\n\n    jobject result = env->NewObject(cls, cid);\n\n    setIntField(env, cls, result, \"vendor_id\", dev->vendor_id);\n    setIntField(env, cls, result, \"product_id\", dev->product_id);\n    setIntField(env, cls, result, \"release_number\", dev->release_number);\n    setIntField(env, cls, result, \"usage_page\", dev->usage_page);\n    setIntField(env, cls, result, \"usage\", dev->usage);\n    setIntField(env, cls, result, \"interface_number\", dev->interface_number);\n    \n    setStringField(env, cls, result, \"path\", dev->path);\n    setUStringField(env, cls, result, \"serial_number\", dev->serial_number);\n    setUStringField(env, cls, result, \"manufacturer_string\", dev->manufacturer_string);\n    setUStringField(env, cls, result, \"product_string\", dev->product_string);\n\n    return result;\n}\nJNIEXPORT jobjectArray JNICALL\nJava_com_codeminders_hidapi_HIDManager_listDevices(JNIEnv *env, jobject obj)\n{\n    struct hid_device_info *devs, *cur_dev;\n    int res = 0;\n    \n#ifdef HID_RUN_LOOP    \n    res = hid_init_loop(); \n#else\n    res = hid_init();\n#endif    \n    if(res != 0){\n        throwIOException(env, NULL);\n        return NULL;\n    }\n    if(!init_hid_mgr())\n    {\n        throwIOException(env, NULL);\n        return NULL;\n    }\n    \n    devs = hid_enumerate(0x0, 0x0);\n    if(devs == NULL)\n    {\n     /* no exception thrown */\n     //throwIOException(env, NULL);\n#if JNI_DEBUG        \n      printf(\"No attached devices\\n\");\n#endif\n       return NULL;\n    }\n    \n    cur_dev = devs;\n    int size=0;\n    while(cur_dev)\n    {\n       size++;\n       cur_dev = cur_dev->next;\n    }\n\n    jclass infoCls = env->FindClass(DEVINFO_CLASS);\n    if (infoCls == NULL) {\n        return NULL; /* exception thrown */\n    }\n    jobjectArray result= env->NewObjectArray(size, infoCls, NULL);\n    cur_dev = devs;\n    int i=0;\n    while(cur_dev)\n    {\n        jobject x = createHIDDeviceInfo(env, infoCls, cur_dev);\n        if(x == NULL)\n           return NULL; /* exception thrown */ \n\n        env->SetObjectArrayElement(result, i, x);\n        env->DeleteLocalRef(x);\n        i++;\n        cur_dev = cur_dev->next;\n    }\n    hid_free_enumeration(devs);\n    \n    return result;\n}\n\nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDManager_init(JNIEnv *env, jobject obj)\n{\n    int res = 0;\n    jobject jobjRef = 0;\n    if(NULL == m_env)\n    {\n      m_env = env;\n      m_env->GetJavaVM( &m_vm );\n    }\n    \n    if(jni_ref_count == 0)\n    {\n#ifdef HID_RUN_LOOP    \n    res = hid_init_loop(); \n#else\n    res = hid_init();\n#endif    \n    } \n    if(res !=0 )\n    {\n       throwIOException(env, NULL);\n       return;\n    }\n    \n    jobjRef = env->NewGlobalRef(obj);\n    setPeer(env, obj, jobjRef);\n#if JNI_DEBUG        \n    printf(\"JNI - init peer(objRef) =  %p \\n\", jobjRef);\n#endif\n        \n    jni_ref_count++;\n}\n    \nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDManager_release(JNIEnv *env, jobject obj )\n{\n    int res = 0;\n    jobject jobjRef = (jobject)getPeer(env, obj);\n#if JNI_DEBUG        \n    printf(\"JNI - release peer(jobjRef) =  %p \\n\", jobjRef);\n#endif\n    if(jobjRef){\n        env->DeleteGlobalRef(jobjRef);\n        setPeer(env,obj,0);\n        jni_ref_count--;\n    }\n#if JNI_DEBUG        \n    printf(\"jni_ref_count = %d\\n\", jni_ref_count);\n#endif\n    if(jni_ref_count>0){ \n       return;     \n    }\n#ifdef HID_RUN_LOOP    \n    res = hid_exit_loop(); \n#else\n    res = hid_exit();\n#endif\n    if(res !=0 )\n    {\n       throwIOException(env, NULL);\n    }\n#if JNI_DEBUG        \n    printf(\"JNI Release library!\\n\");\n#endif\n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/jni-impl/hid-java.cpp",
    "content": "#include <stdlib.h>\n#include <assert.h>\n#include <jni.h>\n\n#ifdef _WIN32\n#include <windows.h>\n#else\n#include <iconv.h>\n#endif\n\n#include \"hidapi/hidapi.h\"\n#include \"hid-java.h\"\n\nvoid throwIOException(JNIEnv *env, hid_device *device)\n{\n    jclass exceptionClass;\n    char *message = NULL;\n    \n    exceptionClass = env->FindClass(\"java/io/IOException\");\n    if (exceptionClass == NULL) \n    {\n        /* Unable to find the exception class, give up. */\n        assert(0);\n        return;\n    }\n    \n    if(device)\n    {\n        const wchar_t *error = hid_error(device);\n        if(error) \n            message = convertToUTF8(env, error);\n    }\n    \n    env->ThrowNew(exceptionClass, message ? message : \"\"); \n    \n    free(message);\n}\n\nchar* convertToUTF8(JNIEnv *env, const wchar_t *str)\n{\n#ifdef _WIN32\n    int sz = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);    \n    char *ret = (char *) malloc(sz + 1); \n    WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, sz, NULL, NULL);    \n    return ret;\n#else\n    iconv_t cd = iconv_open (\"UTF-8\", \"WCHAR_T\");\n    if (cd == (iconv_t) -1)\n    {\n        /* Something went wrong. We could not recover from this  */\n        \n        jclass exceptionClass = env->FindClass(\"java/lang/Error\");\n        if (exceptionClass == NULL) \n        {\n            /* Unable to find the exception class, give up. */\n            assert(0);\n            return NULL;\n        }\n    \n        env->ThrowNew(exceptionClass, \"iconv_open failed\"); \n        return NULL;\n    }\n    size_t len = wcslen(str);\n    size_t ulen = len*sizeof(wchar_t);\n    char *uval = (char *)str;\n    \n    size_t u8l = len*6+3; //BOM+chars\n    char *u8 = (char *) malloc(u8l+1);\n    char *u8p = u8;\n    int nconv = iconv(cd, &uval, &ulen, &u8p, &u8l);\n    if(nconv == (size_t)-1)\n    {\n        iconv_close(cd);\n        free(u8);\n        jclass exceptionClass = env->FindClass(\"java/lang/Error\");\n        if (exceptionClass == NULL) \n        {\n            /* Unable to find the exception class, give up. */\n            assert(0);\n            return NULL;\n        }\n        env->ThrowNew(exceptionClass, \"iconv failed\"); \n        return NULL;\n    }\n    *u8p='\\0';\n\n    iconv_close(cd);\n    return u8;\n#endif\n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/jni-impl/hid-java.h",
    "content": "#ifndef __HID_JAVA_H__\n#define __HID_JAVA_H__\n\n#define DEV_CLASS \"com/codeminders/hidapi/HIDDevice\"\n#define DEVINFO_CLASS \"com/codeminders/hidapi/HIDDeviceInfo\"\n#define HID_MANAGER_CLASS \"com/codeminders/hidapi/HIDManager\"\n\n\n#if defined(__APPLE__)\n#define MAC_OS_X\n#endif\n\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nvoid throwIOException(JNIEnv *env, hid_device *device);\n\n/* this call allocate buffer dynamically. return value should be\n   released with free() routine */\nchar* convertToUTF8(JNIEnv *env, const wchar_t *str); \n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // __HID_JAVA_H__\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/jni-stubs/com_codeminders_hidapi_HIDDevice.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n/* Header for class com_codeminders_hidapi_HIDDevice */\n\n#ifndef _Included_com_codeminders_hidapi_HIDDevice\n#define _Included_com_codeminders_hidapi_HIDDevice\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    close\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_close\n  (JNIEnv *, jobject);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    write\n * Signature: ([B)I\n */\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_write\n  (JNIEnv *, jobject, jbyteArray);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    read\n * Signature: ([B)I\n */\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_read\n  (JNIEnv *, jobject, jbyteArray);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    readTimeout\n * Signature: ([BI)I\n */\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_readTimeout\n  (JNIEnv *, jobject, jbyteArray, jint);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    enableBlocking\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_enableBlocking\n  (JNIEnv *, jobject);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    disableBlocking\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDDevice_disableBlocking\n  (JNIEnv *, jobject);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    sendFeatureReport\n * Signature: ([B)I\n */\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_sendFeatureReport\n  (JNIEnv *, jobject, jbyteArray);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    getFeatureReport\n * Signature: ([B)I\n */\nJNIEXPORT jint JNICALL Java_com_codeminders_hidapi_HIDDevice_getFeatureReport\n  (JNIEnv *, jobject, jbyteArray);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    getManufacturerString\n * Signature: ()Ljava/lang/String;\n */\nJNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getManufacturerString\n  (JNIEnv *, jobject);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    getProductString\n * Signature: ()Ljava/lang/String;\n */\nJNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getProductString\n  (JNIEnv *, jobject);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    getSerialNumberString\n * Signature: ()Ljava/lang/String;\n */\nJNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getSerialNumberString\n  (JNIEnv *, jobject);\n\n/*\n * Class:     com_codeminders_hidapi_HIDDevice\n * Method:    getIndexedString\n * Signature: (I)Ljava/lang/String;\n */\nJNIEXPORT jstring JNICALL Java_com_codeminders_hidapi_HIDDevice_getIndexedString\n  (JNIEnv *, jobject, jint);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/jni-stubs/com_codeminders_hidapi_HIDDeviceInfo.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n/* Header for class com_codeminders_hidapi_HIDDeviceInfo */\n\n#ifndef _Included_com_codeminders_hidapi_HIDDeviceInfo\n#define _Included_com_codeminders_hidapi_HIDDeviceInfo\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     com_codeminders_hidapi_HIDDeviceInfo\n * Method:    open\n * Signature: ()Lcom/codeminders/hidapi/HIDDevice;\n */\nJNIEXPORT jobject JNICALL Java_com_codeminders_hidapi_HIDDeviceInfo_open\n  (JNIEnv *, jobject);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/jni-stubs/com_codeminders_hidapi_HIDManager.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n/* Header for class com_codeminders_hidapi_HIDManager */\n\n#ifndef _Included_com_codeminders_hidapi_HIDManager\n#define _Included_com_codeminders_hidapi_HIDManager\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/* Inaccessible static: instance */\n/*\n * Class:     com_codeminders_hidapi_HIDManager\n * Method:    listDevices\n * Signature: ()[Lcom/codeminders/hidapi/HIDDeviceInfo;\n */\nJNIEXPORT jobjectArray JNICALL Java_com_codeminders_hidapi_HIDManager_listDevices\n  (JNIEnv *, jobject);\n\n/*\n * Class:     com_codeminders_hidapi_HIDManager\n * Method:    init\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDManager_init\n  (JNIEnv *, jobject);\n\n/*\n * Class:     com_codeminders_hidapi_HIDManager\n * Method:    release\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_com_codeminders_hidapi_HIDManager_release\n  (JNIEnv *, jobject);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/linux/Makefile",
    "content": "###########################################\n# Simple Makefile for HIDAPI test program\n#\n# Alan Ott\n# Signal 11 Software\n# 2010-06-01\n###########################################\n\n\nJNIOBJS=HIDManager.o HIDDeviceInfo.o HIDDevice.o hid-java.o\nJAVA5HEADERS=-I/opt/jdk1.5.0/include/ -I/opt/jdk1.5.0/include/linux\nJAVA6HEADERS=-I/usr/lib/jvm/java-6-openjdk/include/ -I/usr/lib/jvm/java-6-openjdk/include/linux\nJAVA7HEADERS=-I/usr/lib/jvm/jdk1.7.0/include/ -I/usr/lib/jvm/jdk1.7.0/include/linux\nJNIINCLUDES=-I.. -I../jni-impl $(JAVA5HEADERS) $(JAVA6HEADERS) $(JAVA7HEADERS)\nJNILIBS=\nJNISHAREDLIB=libhidapi-jni.so\nJNISHAREDLIBVER=1.0\n\nCC=gcc\nCXX=g++\nCOBJS=hid-libusb.o\nCPPOBJS=../hidtest/hidtest.o\nOBJS=$(COBJS) $(CPPOBJS) $(JNIOBJS)\nCFLAGS+=-fPIC -I../hidapi -g -c `pkg-config libusb-1.0 --cflags` $(JNIINCLUDES)\nLIBS=`pkg-config libusb-1.0 libudev --libs` -ludev -lpthread $(JNILIBS)\n\nall: hidtest $(JNISHAREDLIB)\n\n$(JNISHAREDLIB): $(OBJS)\n\t$(CXX) -shared $(COBJS) $(JNIOBJS) $(LIBS) -o $(JNISHAREDLIB)\n\nhidtest: $(OBJS)\n\tg++ -Wall -g $^ $(LIBS) -o hidtest\n\n%.o: ../jni-impl/%.cpp\n\t$(CXX) $(CFLAGS) $< -o $@\n\n$(COBJS): %.o: %.c\n\t$(CC) $(CFLAGS) $< -o $@\n\n$(CPPOBJS): %.o: %.cpp\n\t$(CXX) $(CFLAGS) $< -o $@\n\nclean:\n\trm -f $(OBJS) hidtest $(JNISHAREDLIB)\n\n.PHONY: clean\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/linux/README.txt",
    "content": "\nThere are two implementations of HIDAPI for Linux. One (hid.c) uses the\nLinux hidraw driver, and the other (hid-libusb.c) uses libusb. Which one you\nuse depends on your application. Complete functionality of the hidraw\nversion depends on patches to the Linux kernel which are not currently in\nthe mainline. These patches have to do with sending and receiving feature\nreports. The libusb implementation uses libusb to talk directly to the\ndevice, bypassing any Linux HID driver. The disadvantage of the libusb\nversion is that it will only work with USB devices, while the hidraw\nimplementation will work with Bluetooth devices as well.\n\nTo use HIDAPI, simply drop either hid.c or hid-libusb.c into your\napplication and build using the build parameters in the Makefile.\n\nBy default, on Linux, the Makefile in this directory is configured to use\nthe libusb implementation. To switch to the hidraw implementation, simply\nchange hid-libusb.c to hid.c in the Makefile.\n\n\nLibusb Implementation notes\n----------------------------\nFor the libusb implementation, libusb-1.0 must be installed. Libusb 1.0 is\ndifferent than the legacy libusb 0.1 which is installed on many systems.  To\ninstall libusb-1.0 on Ubuntu and other Debian-based systems, run:\n\tsudo apt-get install libusb-1.0-0-dev\n\n\nHidraw Implementation notes\n----------------------------\nFor the hidraw implementation, libudev headers and libraries are required to\nbuild hidapi programs.  To install libudev libraries on Ubuntu,\nand other Debian-based systems, run:\n\tsudo apt-get install libudev-dev\n\nOn Redhat-based systems, run the following as root:\n\tyum install libudev-devel\n\nUnfortunately, the hidraw driver, which the linux version of hidapi is based\non, contains bugs in kernel versions < 2.6.36, which the client application\nshould be aware of.\n\nBugs (hidraw implementation only):\n-----------------------------------\nOn Kernel versions < 2.6.34, if your device uses numbered reports, an extra\nbyte will be returned at the beginning of all reports returned from read()\nfor hidraw devices. This is worked around in the libary. No action should be\nnecessary in the client library.\n\nOn Kernel versions < 2.6.35, reports will only be sent using a Set_Report\ntransfer on the CONTROL endpoint. No data will ever be sent on an Interrupt\nOut endpoint if one exists. This is fixed in 2.6.35. In 2.6.35, OUTPUT\nreports will be sent to the device on the first INTERRUPT OUT endpoint if it\nexists; If it does not exist, OUTPUT reports will be sent on the CONTROL\nendpoint.\n\nOn Kernel versions < 2.6.36, add an extra byte containing the report number\nto sent reports if numbered reports are used, and the device does not\ncontain an INTERRPUT OUT endpoint for OUTPUT transfers.  For example, if\nyour device uses numbered reports and wants to send {0x2 0xff 0xff 0xff} to\nthe device (0x2 is the report number), you must send {0x2 0x2 0xff 0xff\n0xff}. If your device has the optional Interrupt OUT endpoint, this does not\napply (but really on 2.6.35 only, because 2.6.34 won't use the interrupt\nout endpoint).\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/linux/hid-libusb.c",
    "content": "/*******************************************************\n HIDAPI - Multi-Platform library for\n communication with HID devices.\n\n Alan Ott\n Signal 11 Software\n\n 8/22/2009\n Linux Version - 6/2/2010\n Libusb Version - 8/13/2010\n FreeBSD Version - 11/1/2011\n\n Copyright 2009, All Rights Reserved.\n \n At the discretion of the user of this library,\n this software may be licensed under the terms of the\n GNU Public License v3, a BSD-Style license, or the\n original HIDAPI license as outlined in the LICENSE.txt,\n LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt\n files located at the root of the source distribution.\n These files may also be found in the public source\n code repository located at:\n        http://github.com/signal11/hidapi .\n********************************************************/\n\n#define _GNU_SOURCE // needed for wcsdup() before glibc 2.10\n\n/* C */\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <locale.h>\n#include <errno.h>\n\n/* Unix */\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/ioctl.h>\n#include <sys/utsname.h>\n#include <fcntl.h>\n#include <pthread.h>\n#include <wchar.h>\n\n/* GNU / LibUSB */\n#include \"libusb.h\"\n#include \"iconv.h\"\n\n#include \"hidapi.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef DEBUG_PRINTF\n#define LOG(...) fprintf(stderr, __VA_ARGS__)\n#else\n#define LOG(...) do {} while (0)\n#endif\n\n#ifndef __FreeBSD__\n#define DETACH_KERNEL_DRIVER\n#endif\n\n/* Uncomment to enable the retrieval of Usage and Usage Page in\nhid_enumerate(). Warning, on platforms different from FreeBSD\nthis is very invasive as it requires the detach\nand re-attach of the kernel driver. See comments inside hid_enumerate().\nlibusb HIDAPI programs are encouraged to use the interface number\ninstead to differentiate between interfaces on a composite HID device. */\n/*#define INVASIVE_GET_USAGE*/\n\n/* Linked List of input reports received from the device. */\nstruct input_report {\n\tuint8_t *data;\n\tsize_t len;\n\tstruct input_report *next;\n};\n\n\nstruct hid_device_ {\n\t/* Handle to the actual device. */\n\tlibusb_device_handle *device_handle;\n\t\n\t/* Endpoint information */\n\tint input_endpoint;\n\tint output_endpoint;\n\tint input_ep_max_packet_size;\n\n\t/* The interface number of the HID */\t\n\tint interface;\n\t\n\t/* Indexes of Strings */\n\tint manufacturer_index;\n\tint product_index;\n\tint serial_index;\n\t\n\t/* Whether blocking reads are used */\n\tint blocking; /* boolean */\n\t\n\t/* Read thread objects */\n\tpthread_t thread;\n\tpthread_mutex_t mutex; /* Protects input_reports */\n\tpthread_cond_t condition;\n\tpthread_barrier_t barrier; /* Ensures correct startup sequence */\n\tint shutdown_thread;\n\tstruct libusb_transfer *transfer;\n\n\t/* List of received input reports. */\n\tstruct input_report *input_reports;\n};\n\nstatic libusb_context *usb_context = NULL;\n\nuint16_t get_usb_code_for_current_locale(void);\nstatic int return_data(hid_device *dev, unsigned char *data, size_t length);\n\nstatic hid_device *new_hid_device(void)\n{\n\thid_device *dev = calloc(1, sizeof(hid_device));\n\tdev->blocking = 1;\n\t\n\tpthread_mutex_init(&dev->mutex, NULL);\n\tpthread_cond_init(&dev->condition, NULL);\n\tpthread_barrier_init(&dev->barrier, NULL, 2);\n\t\n\treturn dev;\n}\n\nstatic void free_hid_device(hid_device *dev)\n{\n\t/* Clean up the thread objects */\n\tpthread_barrier_destroy(&dev->barrier);\n\tpthread_cond_destroy(&dev->condition);\n\tpthread_mutex_destroy(&dev->mutex);\n\n\t/* Free the device itself */\n\tfree(dev);\n}\n\n#if 0\n//TODO: Implement this funciton on hidapi/libusb..\nstatic void register_error(hid_device *device, const char *op)\n{\n\n}\n#endif\n\n#ifdef INVASIVE_GET_USAGE\n/* Get bytes from a HID Report Descriptor.\n   Only call with a num_bytes of 0, 1, 2, or 4. */\nstatic uint32_t get_bytes(uint8_t *rpt, size_t len, size_t num_bytes, size_t cur)\n{\n\t/* Return if there aren't enough bytes. */\n\tif (cur + num_bytes >= len)\n\t\treturn 0;\n\n\tif (num_bytes == 0)\n\t\treturn 0;\n\telse if (num_bytes == 1) {\n\t\treturn rpt[cur+1];\n\t}\n\telse if (num_bytes == 2) {\n\t\treturn (rpt[cur+2] * 256 + rpt[cur+1]);\n\t}\n\telse if (num_bytes == 4) {\n\t\treturn (rpt[cur+4] * 0x01000000 +\n\t\t        rpt[cur+3] * 0x00010000 +\n\t\t        rpt[cur+2] * 0x00000100 +\n\t\t        rpt[cur+1] * 0x00000001);\n\t}\n\telse\n\t\treturn 0;\n}\n\n/* Retrieves the device's Usage Page and Usage from the report\n   descriptor. The algorithm is simple, as it just returns the first\n   Usage and Usage Page that it finds in the descriptor.\n   The return value is 0 on success and -1 on failure. */\nstatic int get_usage(uint8_t *report_descriptor, size_t size,\n                     unsigned short *usage_page, unsigned short *usage)\n{\n\tint i = 0;\n\tint size_code;\n\tint data_len, key_size;\n\tint usage_found = 0, usage_page_found = 0;\n\t\n\twhile (i < size) {\n\t\tint key = report_descriptor[i];\n\t\tint key_cmd = key & 0xfc;\n\n\t\t//printf(\"key: %02hhx\\n\", key);\n\t\t\n\t\tif ((key & 0xf0) == 0xf0) {\n\t\t\t/* This is a Long Item. The next byte contains the\n\t\t\t   length of the data section (value) for this key.\n\t\t\t   See the HID specification, version 1.11, section\n\t\t\t   6.2.2.3, titled \"Long Items.\" */\n\t\t\tif (i+1 < size)\n\t\t\t\tdata_len = report_descriptor[i+1];\n\t\t\telse\n\t\t\t\tdata_len = 0; /* malformed report */\n\t\t\tkey_size = 3;\n\t\t}\n\t\telse {\n\t\t\t/* This is a Short Item. The bottom two bits of the\n\t\t\t   key contain the size code for the data section\n\t\t\t   (value) for this key.  Refer to the HID\n\t\t\t   specification, version 1.11, section 6.2.2.2,\n\t\t\t   titled \"Short Items.\" */\n\t\t\tsize_code = key & 0x3;\n\t\t\tswitch (size_code) {\n\t\t\tcase 0:\n\t\t\tcase 1:\n\t\t\tcase 2:\n\t\t\t\tdata_len = size_code;\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tdata_len = 4;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t/* Can't ever happen since size_code is & 0x3 */\n\t\t\t\tdata_len = 0;\n\t\t\t\tbreak;\n\t\t\t};\n\t\t\tkey_size = 1;\n\t\t}\n\t\t\n\t\tif (key_cmd == 0x4) {\n\t\t\t*usage_page  = get_bytes(report_descriptor, size, data_len, i);\n\t\t\tusage_page_found = 1;\n\t\t\t//printf(\"Usage Page: %x\\n\", (uint32_t)*usage_page);\n\t\t}\n\t\tif (key_cmd == 0x8) {\n\t\t\t*usage = get_bytes(report_descriptor, size, data_len, i);\n\t\t\tusage_found = 1;\n\t\t\t//printf(\"Usage: %x\\n\", (uint32_t)*usage);\n\t\t}\n\n\t\tif (usage_page_found && usage_found)\n\t\t\treturn 0; /* success */\n\t\t\n\t\t/* Skip over this key and it's associated data */\n\t\ti += data_len + key_size;\n\t}\n\t\n\treturn -1; /* failure */\n}\n#endif // INVASIVE_GET_USAGE\n\n#ifdef __FreeBSD__\n/* The FreeBSD version of libusb doesn't have this funciton. In mainline\n   libusb, it's inlined in libusb.h. This function will bear a striking\n   resemblence to that one, because there's about one way to code it.\n\n   Note that the data parameter is Unicode in UTF-16LE encoding.\n   Return value is the number of bytes in data, or LIBUSB_ERROR_*.\n */\nstatic inline int libusb_get_string_descriptor(libusb_device_handle *dev,\n\tuint8_t descriptor_index, uint16_t lang_id,\n\tunsigned char *data, int length)\n{\n\treturn libusb_control_transfer(dev,\n\t\tLIBUSB_ENDPOINT_IN | 0x0, /* Endpoint 0 IN */\n\t\tLIBUSB_REQUEST_GET_DESCRIPTOR,\n\t\t(LIBUSB_DT_STRING << 8) | descriptor_index,\n\t\tlang_id, data, (uint16_t) length, 1000);\n}\n\n#endif\n\n\n/* Get the first language the device says it reports. This comes from\n   USB string #0. */\nstatic uint16_t get_first_language(libusb_device_handle *dev)\n{\n\tuint16_t buf[32];\n\tint len;\n\t\n\t/* Get the string from libusb. */\n\tlen = libusb_get_string_descriptor(dev,\n\t\t\t0x0, /* String ID */\n\t\t\t0x0, /* Language */\n\t\t\t(unsigned char*)buf,\n\t\t\tsizeof(buf));\n\tif (len < 4)\n\t\treturn 0x0;\n\t\n\treturn buf[1]; // First two bytes are len and descriptor type.\n}\n\nstatic int is_language_supported(libusb_device_handle *dev, uint16_t lang)\n{\n\tuint16_t buf[32];\n\tint len;\n\tint i;\n\t\n\t/* Get the string from libusb. */\n\tlen = libusb_get_string_descriptor(dev,\n\t\t\t0x0, /* String ID */\n\t\t\t0x0, /* Language */\n\t\t\t(unsigned char*)buf,\n\t\t\tsizeof(buf));\n\tif (len < 4)\n\t\treturn 0x0;\n\t\n\t\n\tlen /= 2; /* language IDs are two-bytes each. */\n\t/* Start at index 1 because there are two bytes of protocol data. */\n\tfor (i = 1; i < len; i++) {\n\t\tif (buf[i] == lang)\n\t\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\n\n/* This function returns a newly allocated wide string containing the USB\n   device string numbered by the index. The returned string must be freed\n   by using free(). */\nstatic wchar_t *get_usb_string(libusb_device_handle *dev, uint8_t idx)\n{\n\tchar buf[512];\n\tint len;\n\twchar_t *str = NULL;\n\twchar_t wbuf[256];\n\n\t/* iconv variables */\n\ticonv_t ic;\n\tsize_t inbytes;\n\tsize_t outbytes;\n\tsize_t res;\n#ifdef __FreeBSD__\n\tconst char *inptr;\n#else\n\tchar *inptr;\n#endif\n\tchar *outptr;\n\n\t/* Determine which language to use. */\n\tuint16_t lang;\n\tlang = get_usb_code_for_current_locale();\n\tif (!is_language_supported(dev, lang))\n\t\tlang = get_first_language(dev);\n\t\t\n\t/* Get the string from libusb. */\n\tlen = libusb_get_string_descriptor(dev,\n\t\t\tidx,\n\t\t\tlang,\n\t\t\t(unsigned char*)buf,\n\t\t\tsizeof(buf));\n\tif (len < 0)\n\t\treturn NULL;\n\t\n\t/* buf does not need to be explicitly NULL-terminated because\n\t   it is only passed into iconv() which does not need it. */\n\t\n\t/* Initialize iconv. */\n\tic = iconv_open(\"WCHAR_T\", \"UTF-16LE\");\n\tif (ic == (iconv_t)-1) {\n\t\tLOG(\"iconv_open() failed\\n\");\n\t\treturn NULL;\n\t}\n\t\n\t/* Convert to native wchar_t (UTF-32 on glibc/BSD systems).\n\t   Skip the first character (2-bytes). */\n\tinptr = buf+2;\n\tinbytes = len-2;\n\toutptr = (char*) wbuf;\n\toutbytes = sizeof(wbuf);\n\tres = iconv(ic, &inptr, &inbytes, &outptr, &outbytes);\n\tif (res == (size_t)-1) {\n\t\tLOG(\"iconv() failed\\n\");\n\t\tgoto err;\n\t}\n\n\t/* Write the terminating NULL. */\n\twbuf[sizeof(wbuf)/sizeof(wbuf[0])-1] = 0x00000000;\n\tif (outbytes >= sizeof(wbuf[0]))\n\t\t*((wchar_t*)outptr) = 0x00000000;\n\t\n\t/* Allocate and copy the string. */\n\tstr = wcsdup(wbuf);\n\nerr:\n\ticonv_close(ic);\n\t\n\treturn str;\n}\n\nstatic char *make_path(libusb_device *dev, int interface_number)\n{\n\tchar str[64];\n\tsnprintf(str, sizeof(str), \"%04x:%04x:%02x\",\n\t\tlibusb_get_bus_number(dev),\n\t\tlibusb_get_device_address(dev),\n\t\tinterface_number);\n\tstr[sizeof(str)-1] = '\\0';\n\t\n\treturn strdup(str);\n}\n\n\nint HID_API_EXPORT hid_init(void)\n{\n\tif (!usb_context) {\n\t\tconst char *locale;\n\n\t\t/* Init Libusb */\n\t\tif (libusb_init(&usb_context))\n\t\t\treturn -1;\n\n\t\t/* Set the locale if it's not set. */\n\t\tlocale = setlocale(LC_CTYPE, NULL);\n\t\tif (!locale)\n\t\t\tsetlocale(LC_CTYPE, \"\");\n\t}\n\n\treturn 0;\n}\n\nint HID_API_EXPORT hid_exit(void)\n{\n\tif (usb_context) {\n\t\tlibusb_exit(usb_context);\n\t\tusb_context = NULL;\n\t}\n\n\treturn 0;\n}\n\nstruct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)\n{\n\tlibusb_device **devs;\n\tlibusb_device *dev;\n\tlibusb_device_handle *handle;\n\tssize_t num_devs;\n\tint i = 0;\n\t\n\tstruct hid_device_info *root = NULL; // return object\n\tstruct hid_device_info *cur_dev = NULL;\n\t\n\thid_init();\n\n\tnum_devs = libusb_get_device_list(usb_context, &devs);\n\tif (num_devs < 0)\n\t\treturn NULL;\n\twhile ((dev = devs[i++]) != NULL) {\n\t\tstruct libusb_device_descriptor desc;\n\t\tstruct libusb_config_descriptor *conf_desc = NULL;\n\t\tint j, k;\n\t\tint interface_num = 0;\n\n\t\tint res = libusb_get_device_descriptor(dev, &desc);\n\t\tunsigned short dev_vid = desc.idVendor;\n\t\tunsigned short dev_pid = desc.idProduct;\n\t\t\n\t\t/* HID's are defined at the interface level. */\n\t\tif (desc.bDeviceClass != LIBUSB_CLASS_PER_INTERFACE)\n\t\t\tcontinue;\n\n\t\tres = libusb_get_active_config_descriptor(dev, &conf_desc);\n\t\tif (res < 0)\n\t\t\tlibusb_get_config_descriptor(dev, 0, &conf_desc);\n\t\tif (conf_desc) {\n\t\t\tfor (j = 0; j < conf_desc->bNumInterfaces; j++) {\n\t\t\t\tconst struct libusb_interface *intf = &conf_desc->interface[j];\n\t\t\t\tfor (k = 0; k < intf->num_altsetting; k++) {\n\t\t\t\t\tconst struct libusb_interface_descriptor *intf_desc;\n\t\t\t\t\tintf_desc = &intf->altsetting[k];\n\t\t\t\t\tif (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {\n\t\t\t\t\t\tinterface_num = intf_desc->bInterfaceNumber;\n\n\t\t\t\t\t\t/* Check the VID/PID against the arguments */\n\t\t\t\t\t\tif ((vendor_id == 0x0 && product_id == 0x0) ||\n\t\t\t\t\t\t    (vendor_id == dev_vid && product_id == dev_pid)) {\n\t\t\t\t\t\t\tstruct hid_device_info *tmp;\n\n\t\t\t\t\t\t\t/* VID/PID match. Create the record. */\n\t\t\t\t\t\t\ttmp = calloc(1, sizeof(struct hid_device_info));\n\t\t\t\t\t\t\tif (cur_dev) {\n\t\t\t\t\t\t\t\tcur_dev->next = tmp;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\troot = tmp;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcur_dev = tmp;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t/* Fill out the record */\n\t\t\t\t\t\t\tcur_dev->next = NULL;\n\t\t\t\t\t\t\tcur_dev->path = make_path(dev, interface_num);\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\tres = libusb_open(dev, &handle);\n\n\t\t\t\t\t\t\tif (res >= 0) {\n\t\t\t\t\t\t\t\t/* Serial Number */\n\t\t\t\t\t\t\t\tif (desc.iSerialNumber > 0)\n\t\t\t\t\t\t\t\t\tcur_dev->serial_number =\n\t\t\t\t\t\t\t\t\t\tget_usb_string(handle, desc.iSerialNumber);\n\n\t\t\t\t\t\t\t\t/* Manufacturer and Product strings */\n\t\t\t\t\t\t\t\tif (desc.iManufacturer > 0)\n\t\t\t\t\t\t\t\t\tcur_dev->manufacturer_string =\n\t\t\t\t\t\t\t\t\t\tget_usb_string(handle, desc.iManufacturer);\n\t\t\t\t\t\t\t\tif (desc.iProduct > 0)\n\t\t\t\t\t\t\t\t\tcur_dev->product_string =\n\t\t\t\t\t\t\t\t\t\tget_usb_string(handle, desc.iProduct);\n\n#ifdef INVASIVE_GET_USAGE\n\t\t\t\t\t\t\t/*\n\t\t\t\t\t\t\tThis section is removed because it is too\n\t\t\t\t\t\t\tinvasive on the system. Getting a Usage Page\n\t\t\t\t\t\t\tand Usage requires parsing the HID Report\n\t\t\t\t\t\t\tdescriptor. Getting a HID Report descriptor\n\t\t\t\t\t\t\tinvolves claiming the interface. Claiming the\n\t\t\t\t\t\t\tinterface involves detaching the kernel driver.\n\t\t\t\t\t\t\tDetaching the kernel driver is hard on the system\n\t\t\t\t\t\t\tbecause it will unclaim interfaces (if another\n\t\t\t\t\t\t\tapp has them claimed) and the re-attachment of\n\t\t\t\t\t\t\tthe driver will sometimes change /dev entry names.\n\t\t\t\t\t\t\tIt is for these reasons that this section is\n\t\t\t\t\t\t\t#if 0. For composite devices, use the interface\n\t\t\t\t\t\t\tfield in the hid_device_info struct to distinguish\n\t\t\t\t\t\t\tbetween interfaces. */\n\t\t\t\t\t\t\t\tunsigned char data[256];\n#ifdef DETACH_KERNEL_DRIVER\n\t\t\t\t\t\t\t\tint detached = 0;\n\t\t\t\t\t\t\t\t/* Usage Page and Usage */\n\t\t\t\t\t\t\t\tres = libusb_kernel_driver_active(handle, interface_num);\n\t\t\t\t\t\t\t\tif (res == 1) {\n\t\t\t\t\t\t\t\t\tres = libusb_detach_kernel_driver(handle, interface_num);\n\t\t\t\t\t\t\t\t\tif (res < 0)\n\t\t\t\t\t\t\t\t\t\tLOG(\"Couldn't detach kernel driver, even though a kernel driver was attached.\");\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tdetached = 1;\n\t\t\t\t\t\t\t\t}\n#endif\n\t\t\t\t\t\t\t\tres = libusb_claim_interface(handle, interface_num);\n\t\t\t\t\t\t\t\tif (res >= 0) {\n\t\t\t\t\t\t\t\t\t/* Get the HID Report Descriptor. */\n\t\t\t\t\t\t\t\t\tres = libusb_control_transfer(handle, LIBUSB_ENDPOINT_IN|LIBUSB_RECIPIENT_INTERFACE, LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_REPORT << 8)|interface_num, 0, data, sizeof(data), 5000);\n\t\t\t\t\t\t\t\t\tif (res >= 0) {\n\t\t\t\t\t\t\t\t\t\tunsigned short page=0, usage=0;\n\t\t\t\t\t\t\t\t\t\t/* Parse the usage and usage page\n\t\t\t\t\t\t\t\t\t\t   out of the report descriptor. */\n\t\t\t\t\t\t\t\t\t\tget_usage(data, res,  &page, &usage);\n\t\t\t\t\t\t\t\t\t\tcur_dev->usage_page = page;\n\t\t\t\t\t\t\t\t\t\tcur_dev->usage = usage;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tLOG(\"libusb_control_transfer() for getting the HID report failed with %d\\n\", res);\n\n\t\t\t\t\t\t\t\t\t/* Release the interface */\n\t\t\t\t\t\t\t\t\tres = libusb_release_interface(handle, interface_num);\n\t\t\t\t\t\t\t\t\tif (res < 0)\n\t\t\t\t\t\t\t\t\t\tLOG(\"Can't release the interface.\\n\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\tLOG(\"Can't claim interface %d\\n\", res);\n#ifdef DETACH_KERNEL_DRIVER\n\t\t\t\t\t\t\t\t/* Re-attach kernel driver if necessary. */\n\t\t\t\t\t\t\t\tif (detached) {\n\t\t\t\t\t\t\t\t\tres = libusb_attach_kernel_driver(handle, interface_num);\n\t\t\t\t\t\t\t\t\tif (res < 0)\n\t\t\t\t\t\t\t\t\t\tLOG(\"Couldn't re-attach kernel driver.\\n\");\n\t\t\t\t\t\t\t\t}\n#endif\n\n#endif // INVASIVE_GET_USAGE\n\n\t\t\t\t\t\t\t\tlibusb_close(handle);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/* VID/PID */\n\t\t\t\t\t\t\tcur_dev->vendor_id = dev_vid;\n\t\t\t\t\t\t\tcur_dev->product_id = dev_pid;\n\n\t\t\t\t\t\t\t/* Release Number */\n\t\t\t\t\t\t\tcur_dev->release_number = desc.bcdDevice;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t/* Interface Number */\n\t\t\t\t\t\t\tcur_dev->interface_number = interface_num;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} /* altsettings */\n\t\t\t} /* interfaces */\n\t\t\tlibusb_free_config_descriptor(conf_desc);\n\t\t}\n\t}\n\n\tlibusb_free_device_list(devs, 1);\n\n\treturn root;\n}\n\nvoid  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)\n{\n\tstruct hid_device_info *d = devs;\n\twhile (d) {\n\t\tstruct hid_device_info *next = d->next;\n\t\tfree(d->path);\n\t\tfree(d->serial_number);\n\t\tfree(d->manufacturer_string);\n\t\tfree(d->product_string);\n\t\tfree(d);\n\t\td = next;\n\t}\n}\n\nhid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)\n{\n\tstruct hid_device_info *devs, *cur_dev;\n\tconst char *path_to_open = NULL;\n\thid_device *handle = NULL;\n\t\n\tdevs = hid_enumerate(vendor_id, product_id);\n\tcur_dev = devs;\n\twhile (cur_dev) {\n\t\tif (cur_dev->vendor_id == vendor_id &&\n\t\t    cur_dev->product_id == product_id) {\n\t\t\tif (serial_number) {\n\t\t\t\tif (wcscmp(serial_number, cur_dev->serial_number) == 0) {\n\t\t\t\t\tpath_to_open = cur_dev->path;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpath_to_open = cur_dev->path;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcur_dev = cur_dev->next;\n\t}\n\n\tif (path_to_open) {\n\t\t/* Open the device */\n\t\thandle = hid_open_path(path_to_open);\n\t}\n\n\thid_free_enumeration(devs);\n\t\n\treturn handle;\n}\n\nstatic void read_callback(struct libusb_transfer *transfer)\n{\n\thid_device *dev = transfer->user_data;\n\tint res;\n\t\n\tif (transfer->status == LIBUSB_TRANSFER_COMPLETED) {\n\n\t\tstruct input_report *rpt = malloc(sizeof(*rpt));\n\t\trpt->data = malloc(transfer->actual_length);\n\t\tmemcpy(rpt->data, transfer->buffer, transfer->actual_length);\n\t\trpt->len = transfer->actual_length;\n\t\trpt->next = NULL;\n\n\t\tpthread_mutex_lock(&dev->mutex);\n\n\t\t/* Attach the new report object to the end of the list. */\n\t\tif (dev->input_reports == NULL) {\n\t\t\t/* The list is empty. Put it at the root. */\n\t\t\tdev->input_reports = rpt;\n\t\t\tpthread_cond_signal(&dev->condition);\n\t\t}\n\t\telse {\n\t\t\t/* Find the end of the list and attach. */\n\t\t\tstruct input_report *cur = dev->input_reports;\n\t\t\tint num_queued = 0;\n\t\t\twhile (cur->next != NULL) {\n\t\t\t\tcur = cur->next;\n\t\t\t\tnum_queued++;\n\t\t\t}\n\t\t\tcur->next = rpt;\n\t\t\t\n\t\t\t/* Pop one off if we've reached 30 in the queue. This\n\t\t\t   way we don't grow forever if the user never reads\n\t\t\t   anything from the device. */\n\t\t\tif (num_queued > 30) {\n\t\t\t\treturn_data(dev, NULL, 0);\n\t\t\t}\t\t\t\n\t\t}\n\t\tpthread_mutex_unlock(&dev->mutex);\n\t}\n\telse if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {\n\t\tdev->shutdown_thread = 1;\n\t\treturn;\n\t}\n\telse if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {\n\t\tdev->shutdown_thread = 1;\n\t\treturn;\n\t}\n\telse if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) {\n\t\t//LOG(\"Timeout (normal)\\n\");\n\t}\n\telse {\n\t\tLOG(\"Unknown transfer code: %d\\n\", transfer->status);\n\t}\n\t\n\t/* Re-submit the transfer object. */\n\tres = libusb_submit_transfer(transfer);\n\tif (res != 0) {\n\t\tLOG(\"Unable to submit URB. libusb error code: %d\\n\", res);\n\t\tdev->shutdown_thread = 1;\n\t}\n}\n\n\nstatic void *read_thread(void *param)\n{\n\thid_device *dev = param;\n\tunsigned char *buf;\n\tconst size_t length = dev->input_ep_max_packet_size;\n\n\t/* Set up the transfer object. */\n\tbuf = malloc(length);\n\tdev->transfer = libusb_alloc_transfer(0);\n\tlibusb_fill_interrupt_transfer(dev->transfer,\n\t\tdev->device_handle,\n\t\tdev->input_endpoint,\n\t\tbuf,\n\t\tlength,\n\t\tread_callback,\n\t\tdev,\n\t\t5000/*timeout*/);\n\t\n\t/* Make the first submission. Further submissions are made\n\t   from inside read_callback() */\n\tlibusb_submit_transfer(dev->transfer);\n\n\t// Notify the main thread that the read thread is up and running.\n\tpthread_barrier_wait(&dev->barrier);\n\t\n\t/* Handle all the events. */\n\twhile (!dev->shutdown_thread) {\n\t\tint res;\n\t\tres = libusb_handle_events(usb_context);\n\t\tif (res < 0) {\n\t\t\t/* There was an error. */\n\t\t\tLOG(\"read_thread(): libusb reports error # %d\\n\", res);\n\n\t\t\t/* Break out of this loop only on fatal error.*/\n\t\t\tif (res != LIBUSB_ERROR_BUSY &&\n\t\t\t    res != LIBUSB_ERROR_TIMEOUT &&\n\t\t\t    res != LIBUSB_ERROR_OVERFLOW &&\n\t\t\t    res != LIBUSB_ERROR_INTERRUPTED) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t/* Cancel any transfer that may be pending. This call will fail\n\t   if no transfers are pending, but that's OK. */\n\tif (libusb_cancel_transfer(dev->transfer) == 0) {\n\t\t/* The transfer was cancelled, so wait for its completion. */\n\t\tlibusb_handle_events(usb_context);\n\t}\n\t\n\t/* Now that the read thread is stopping, Wake any threads which are\n\t   waiting on data (in hid_read_timeout()). Do this under a mutex to\n\t   make sure that a thread which is about to go to sleep waiting on\n\t   the condition acutally will go to sleep before the condition is\n\t   signaled. */\n\tpthread_mutex_lock(&dev->mutex);\n\tpthread_cond_broadcast(&dev->condition);\n\tpthread_mutex_unlock(&dev->mutex);\n\n\t/* The dev->transfer->buffer and dev->transfer objects are cleaned up\n\t   in hid_close(). They are not cleaned up here because this thread\n\t   could end either due to a disconnect or due to a user\n\t   call to hid_close(). In both cases the objects can be safely\n\t   cleaned up after the call to pthread_join() (in hid_close()), but\n\t   since hid_close() calls libusb_cancel_transfer(), on these objects,\n\t   they can not be cleaned up here. */\n\t\n\treturn NULL;\n}\n\n\nhid_device * HID_API_EXPORT hid_open_path(const char *path)\n{\n\thid_device *dev = NULL;\n\n\tdev = new_hid_device();\n\n\tlibusb_device **devs;\n\tlibusb_device *usb_dev;\n\tssize_t num_devs;\n\tint res;\n\tint d = 0;\n\tint good_open = 0;\n\t\n\thid_init();\n\n\tnum_devs = libusb_get_device_list(usb_context, &devs);\n\twhile ((usb_dev = devs[d++]) != NULL) {\n\t\tstruct libusb_device_descriptor desc;\n\t\tstruct libusb_config_descriptor *conf_desc = NULL;\n\t\tint i,j,k;\n\t\tlibusb_get_device_descriptor(usb_dev, &desc);\n\n\t\tif (libusb_get_active_config_descriptor(usb_dev, &conf_desc) < 0)\n\t\t\tcontinue;\n\t\tfor (j = 0; j < conf_desc->bNumInterfaces; j++) {\n\t\t\tconst struct libusb_interface *intf = &conf_desc->interface[j];\n\t\t\tfor (k = 0; k < intf->num_altsetting; k++) {\n\t\t\t\tconst struct libusb_interface_descriptor *intf_desc;\n\t\t\t\tintf_desc = &intf->altsetting[k];\n\t\t\t\tif (intf_desc->bInterfaceClass == LIBUSB_CLASS_HID) {\n\t\t\t\t\tchar *dev_path = make_path(usb_dev, intf_desc->bInterfaceNumber);\n\t\t\t\t\tif (!strcmp(dev_path, path)) {\n\t\t\t\t\t\t/* Matched Paths. Open this device */\n\n\t\t\t\t\t\t// OPEN HERE //\n\t\t\t\t\t\tres = libusb_open(usb_dev, &dev->device_handle);\n\t\t\t\t\t\tif (res < 0) {\n\t\t\t\t\t\t\tLOG(\"can't open device\\n\");\n\t\t\t\t\t\t\tfree(dev_path);\n \t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tgood_open = 1;\n#ifdef DETACH_KERNEL_DRIVER\n\t\t\t\t\t\t/* Detach the kernel driver, but only if the\n\t\t\t\t\t\t   device is managed by the kernel */\n\t\t\t\t\t\tif (libusb_kernel_driver_active(dev->device_handle, intf_desc->bInterfaceNumber) == 1) {\n\t\t\t\t\t\t\tres = libusb_detach_kernel_driver(dev->device_handle, intf_desc->bInterfaceNumber);\n\t\t\t\t\t\t\tif (res < 0) {\n\t\t\t\t\t\t\t\tlibusb_close(dev->device_handle);\n\t\t\t\t\t\t\t\tLOG(\"Unable to detach Kernel Driver\\n\");\n\t\t\t\t\t\t\t\tfree(dev_path);\n\t\t\t\t\t\t\t\tgood_open = 0;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n#endif\n\t\t\t\t\t\tres = libusb_claim_interface(dev->device_handle, intf_desc->bInterfaceNumber);\n\t\t\t\t\t\tif (res < 0) {\n\t\t\t\t\t\t\tLOG(\"can't claim interface %d: %d\\n\", intf_desc->bInterfaceNumber, res);\n\t\t\t\t\t\t\tfree(dev_path);\n\t\t\t\t\t\t\tlibusb_close(dev->device_handle);\n\t\t\t\t\t\t\tgood_open = 0;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/* Store off the string descriptor indexes */\n\t\t\t\t\t\tdev->manufacturer_index = desc.iManufacturer;\n\t\t\t\t\t\tdev->product_index      = desc.iProduct;\n\t\t\t\t\t\tdev->serial_index       = desc.iSerialNumber;\n\n\t\t\t\t\t\t/* Store off the interface number */\n\t\t\t\t\t\tdev->interface = intf_desc->bInterfaceNumber;\n\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t/* Find the INPUT and OUTPUT endpoints. An\n\t\t\t\t\t\t   OUTPUT endpoint is not required. */\n\t\t\t\t\t\tfor (i = 0; i < intf_desc->bNumEndpoints; i++) {\n\t\t\t\t\t\t\tconst struct libusb_endpoint_descriptor *ep\n\t\t\t\t\t\t\t\t= &intf_desc->endpoint[i];\n\n\t\t\t\t\t\t\t/* Determine the type and direction of this\n\t\t\t\t\t\t\t   endpoint. */\n\t\t\t\t\t\t\tint is_interrupt =\n\t\t\t\t\t\t\t\t(ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)\n\t\t\t\t\t\t\t      == LIBUSB_TRANSFER_TYPE_INTERRUPT;\n\t\t\t\t\t\t\tint is_output = \n\t\t\t\t\t\t\t\t(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)\n\t\t\t\t\t\t\t      == LIBUSB_ENDPOINT_OUT;\n\t\t\t\t\t\t\tint is_input = \n\t\t\t\t\t\t\t\t(ep->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK)\n\t\t\t\t\t\t\t      == LIBUSB_ENDPOINT_IN;\n\n\t\t\t\t\t\t\t/* Decide whether to use it for intput or output. */\n\t\t\t\t\t\t\tif (dev->input_endpoint == 0 &&\n\t\t\t\t\t\t\t    is_interrupt && is_input) {\n\t\t\t\t\t\t\t\t/* Use this endpoint for INPUT */\n\t\t\t\t\t\t\t\tdev->input_endpoint = ep->bEndpointAddress;\n\t\t\t\t\t\t\t\tdev->input_ep_max_packet_size = ep->wMaxPacketSize;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (dev->output_endpoint == 0 &&\n\t\t\t\t\t\t\t    is_interrupt && is_output) {\n\t\t\t\t\t\t\t\t/* Use this endpoint for OUTPUT */\n\t\t\t\t\t\t\t\tdev->output_endpoint = ep->bEndpointAddress;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tpthread_create(&dev->thread, NULL, read_thread, dev);\n\t\t\t\t\t\t\n\t\t\t\t\t\t// Wait here for the read thread to be initialized.\n\t\t\t\t\t\tpthread_barrier_wait(&dev->barrier);\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\tfree(dev_path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tlibusb_free_config_descriptor(conf_desc);\n\n\t}\n\n\tlibusb_free_device_list(devs, 1);\n\t\n\t// If we have a good handle, return it.\n\tif (good_open) {\n\t\treturn dev;\n\t}\n\telse {\n\t\t// Unable to open any devices.\n\t\tfree_hid_device(dev);\n\t\treturn NULL;\n\t}\n}\n\n\nint HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)\n{\n\tint res;\n\tint report_number = data[0];\n\tint skipped_report_id = 0;\n\n\tif (report_number == 0x0) {\n\t\tdata++;\n\t\tlength--;\n\t\tskipped_report_id = 1;\n\t}\n\n\n\tif (dev->output_endpoint <= 0) {\n\t\t/* No interrput out endpoint. Use the Control Endpoint */\n\t\tres = libusb_control_transfer(dev->device_handle,\n\t\t\tLIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,\n\t\t\t0x09/*HID Set_Report*/,\n\t\t\t(2/*HID output*/ << 8) | report_number,\n\t\t\tdev->interface,\n\t\t\t(unsigned char *)data, length,\n\t\t\t1000/*timeout millis*/);\n\t\t\n\t\tif (res < 0)\n\t\t\treturn -1;\n\t\t\n\t\tif (skipped_report_id)\n\t\t\tlength++;\n\t\t\n\t\treturn length;\n\t}\n\telse {\n\t\t/* Use the interrupt out endpoint */\n\t\tint actual_length;\n\t\tres = libusb_interrupt_transfer(dev->device_handle,\n\t\t\tdev->output_endpoint,\n\t\t\t(unsigned char*)data,\n\t\t\tlength,\n\t\t\t&actual_length, 1000);\n\t\t\n\t\tif (res < 0)\n\t\t\treturn -1;\n\t\t\n\t\tif (skipped_report_id)\n\t\t\tactual_length++;\n\t\t\n\t\treturn actual_length;\n\t}\n}\n\n/* Helper function, to simplify hid_read().\n   This should be called with dev->mutex locked. */\nstatic int return_data(hid_device *dev, unsigned char *data, size_t length)\n{\n\t/* Copy the data out of the linked list item (rpt) into the\n\t   return buffer (data), and delete the liked list item. */\n\tstruct input_report *rpt = dev->input_reports;\n\tsize_t len = (length < rpt->len)? length: rpt->len;\n\tif (len > 0)\n\t\tmemcpy(data, rpt->data, len);\n\tdev->input_reports = rpt->next;\n\tfree(rpt->data);\n\tfree(rpt);\n\treturn len;\n}\n\nstatic void cleanup_mutex(void *param)\n{\n\thid_device *dev = param;\n\tpthread_mutex_unlock(&dev->mutex);\n}\n\n\nint HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)\n{\n\tint bytes_read = -1;\n\n#if 0\n\tint transferred;\n\tint res = libusb_interrupt_transfer(dev->device_handle, dev->input_endpoint, data, length, &transferred, 5000);\n\tLOG(\"transferred: %d\\n\", transferred);\n\treturn transferred;\n#endif\n\n\tpthread_mutex_lock(&dev->mutex);\n\tpthread_cleanup_push(&cleanup_mutex, dev);\n\n\t/* There's an input report queued up. Return it. */\n\tif (dev->input_reports) {\n\t\t/* Return the first one */\n\t\tbytes_read = return_data(dev, data, length);\n\t\tgoto ret;\n\t}\n\t\n\tif (dev->shutdown_thread) {\n\t\t/* This means the device has been disconnected.\n\t\t   An error code of -1 should be returned. */\n\t\tbytes_read = -1;\n\t\tgoto ret;\n\t}\n\t\n\tif (milliseconds == -1) {\n\t\t/* Blocking */\n\t\twhile (!dev->input_reports && !dev->shutdown_thread) {\n\t\t\tpthread_cond_wait(&dev->condition, &dev->mutex);\n\t\t}\n\t\tif (dev->input_reports) {\n\t\t\tbytes_read = return_data(dev, data, length);\n\t\t}\n\t}\n\telse if (milliseconds > 0) {\n\t\t/* Non-blocking, but called with timeout. */\n\t\tint res;\n\t\tstruct timespec ts;\n\t\tclock_gettime(CLOCK_REALTIME, &ts);\n\t\tts.tv_sec += milliseconds / 1000;\n\t\tts.tv_nsec += (milliseconds % 1000) * 1000000;\n\t\tif (ts.tv_nsec >= 1000000000L) {\n\t\t\tts.tv_sec++;\n\t\t\tts.tv_nsec -= 1000000000L;\n\t\t}\n\t\t\n\t\twhile (!dev->input_reports && !dev->shutdown_thread) {\n\t\t\tres = pthread_cond_timedwait(&dev->condition, &dev->mutex, &ts);\n\t\t\tif (res == 0) {\n\t\t\t\tif (dev->input_reports) {\n\t\t\t\t\tbytes_read = return_data(dev, data, length);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* If we're here, there was a spurious wake up\n\t\t\t\t   or the read thread was shutdown. Run the\n\t\t\t\t   loop again (ie: don't break). */\n\t\t\t}\n\t\t\telse if (res == ETIMEDOUT) {\n\t\t\t\t/* Timed out. */\n\t\t\t\tbytes_read = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t/* Error. */\n\t\t\t\tbytes_read = -1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\t/* Purely non-blocking */\n\t\tbytes_read = 0;\n\t}\n\nret:\n\tpthread_mutex_unlock(&dev->mutex);\n\tpthread_cleanup_pop(0);\n\n\treturn bytes_read;\n}\n\nint HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)\n{\n\treturn hid_read_timeout(dev, data, length, dev->blocking ? -1 : 0);\n}\n\nint HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)\n{\n\tdev->blocking = !nonblock;\n\t\n\treturn 0;\n}\n\n\nint HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)\n{\n\tint res = -1;\n\tint skipped_report_id = 0;\n\tint report_number = data[0];\n\n\tif (report_number == 0x0) {\n\t\tdata++;\n\t\tlength--;\n\t\tskipped_report_id = 1;\n\t}\n\n\tres = libusb_control_transfer(dev->device_handle,\n\t\tLIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,\n\t\t0x09/*HID set_report*/,\n\t\t(3/*HID feature*/ << 8) | report_number,\n\t\tdev->interface,\n\t\t(unsigned char *)data, length,\n\t\t1000/*timeout millis*/);\n\t\n\tif (res < 0)\n\t\treturn -1;\n\t\n\t/* Account for the report ID */\n\tif (skipped_report_id)\n\t\tlength++;\n\t\n\treturn length;\n}\n\nint HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)\n{\n\tint res = -1;\n\tint skipped_report_id = 0;\n\tint report_number = data[0];\n\n\tif (report_number == 0x0) {\n\t\t/* Offset the return buffer by 1, so that the report ID\n\t\t   will remain in byte 0. */\n\t\tdata++;\n\t\tlength--;\n\t\tskipped_report_id = 1;\n\t}\n\tres = libusb_control_transfer(dev->device_handle,\n\t\tLIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,\n\t\t0x01/*HID get_report*/,\n\t\t(3/*HID feature*/ << 8) | report_number,\n\t\tdev->interface,\n\t\t(unsigned char *)data, length,\n\t\t1000/*timeout millis*/);\n\t\n\tif (res < 0)\n\t\treturn -1;\n\n\tif (skipped_report_id)\n\t\tres++;\n\t\n\treturn res;\n}\n\n\nvoid HID_API_EXPORT hid_close(hid_device *dev)\n{\n\tif (!dev)\n\t\treturn;\n\t\n\t/* Cause read_thread() to stop. */\n\tdev->shutdown_thread = 1;\n\tlibusb_cancel_transfer(dev->transfer);\n\n\t/* Wait for read_thread() to end. */\n\tpthread_join(dev->thread, NULL);\n\t\n\t/* Clean up the Transfer objects allocated in read_thread(). */\n\tfree(dev->transfer->buffer);\n\tlibusb_free_transfer(dev->transfer);\n\t\n\t/* release the interface */\n\tlibusb_release_interface(dev->device_handle, dev->interface);\n\t\n\t/* Close the handle */\n\tlibusb_close(dev->device_handle);\n\t\n\t/* Clear out the queue of received reports. */\n\tpthread_mutex_lock(&dev->mutex);\n\twhile (dev->input_reports) {\n\t\treturn_data(dev, NULL, 0);\n\t}\n\tpthread_mutex_unlock(&dev->mutex);\n\t\n\tfree_hid_device(dev);\n}\n\n\nint HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)\n{\n\treturn hid_get_indexed_string(dev, dev->manufacturer_index, string, maxlen);\n}\n\nint HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)\n{\n\treturn hid_get_indexed_string(dev, dev->product_index, string, maxlen);\n}\n\nint HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)\n{\n\treturn hid_get_indexed_string(dev, dev->serial_index, string, maxlen);\n}\n\nint HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)\n{\n\twchar_t *str;\n\n\tstr = get_usb_string(dev->device_handle, string_index);\n\tif (str) {\n\t\twcsncpy(string, str, maxlen);\n\t\tstring[maxlen-1] = L'\\0';\n\t\tfree(str);\n\t\treturn 0;\n\t}\n\telse\n\t\treturn -1;\n}\n\n\nHID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)\n{\n\treturn NULL;\n}\n\n\nstruct lang_map_entry {\n\tconst char *name;\n\tconst char *string_code;\n\tuint16_t usb_code;\n};\n\n#define LANG(name,code,usb_code) { name, code, usb_code }\nstatic struct lang_map_entry lang_map[] = {\n\tLANG(\"Afrikaans\", \"af\", 0x0436),\n\tLANG(\"Albanian\", \"sq\", 0x041C),\n\tLANG(\"Arabic - United Arab Emirates\", \"ar_ae\", 0x3801),\n\tLANG(\"Arabic - Bahrain\", \"ar_bh\", 0x3C01),\n\tLANG(\"Arabic - Algeria\", \"ar_dz\", 0x1401),\n\tLANG(\"Arabic - Egypt\", \"ar_eg\", 0x0C01),\n\tLANG(\"Arabic - Iraq\", \"ar_iq\", 0x0801),\n\tLANG(\"Arabic - Jordan\", \"ar_jo\", 0x2C01),\n\tLANG(\"Arabic - Kuwait\", \"ar_kw\", 0x3401),\n\tLANG(\"Arabic - Lebanon\", \"ar_lb\", 0x3001),\n\tLANG(\"Arabic - Libya\", \"ar_ly\", 0x1001),\n\tLANG(\"Arabic - Morocco\", \"ar_ma\", 0x1801),\n\tLANG(\"Arabic - Oman\", \"ar_om\", 0x2001),\n\tLANG(\"Arabic - Qatar\", \"ar_qa\", 0x4001),\n\tLANG(\"Arabic - Saudi Arabia\", \"ar_sa\", 0x0401),\n\tLANG(\"Arabic - Syria\", \"ar_sy\", 0x2801),\n\tLANG(\"Arabic - Tunisia\", \"ar_tn\", 0x1C01),\n\tLANG(\"Arabic - Yemen\", \"ar_ye\", 0x2401),\n\tLANG(\"Armenian\", \"hy\", 0x042B),\n\tLANG(\"Azeri - Latin\", \"az_az\", 0x042C),\n\tLANG(\"Azeri - Cyrillic\", \"az_az\", 0x082C),\n\tLANG(\"Basque\", \"eu\", 0x042D),\n\tLANG(\"Belarusian\", \"be\", 0x0423),\n\tLANG(\"Bulgarian\", \"bg\", 0x0402),\n\tLANG(\"Catalan\", \"ca\", 0x0403),\n\tLANG(\"Chinese - China\", \"zh_cn\", 0x0804),\n\tLANG(\"Chinese - Hong Kong SAR\", \"zh_hk\", 0x0C04),\n\tLANG(\"Chinese - Macau SAR\", \"zh_mo\", 0x1404),\n\tLANG(\"Chinese - Singapore\", \"zh_sg\", 0x1004),\n\tLANG(\"Chinese - Taiwan\", \"zh_tw\", 0x0404),\n\tLANG(\"Croatian\", \"hr\", 0x041A),\n\tLANG(\"Czech\", \"cs\", 0x0405),\n\tLANG(\"Danish\", \"da\", 0x0406),\n\tLANG(\"Dutch - Netherlands\", \"nl_nl\", 0x0413),\n\tLANG(\"Dutch - Belgium\", \"nl_be\", 0x0813),\n\tLANG(\"English - Australia\", \"en_au\", 0x0C09),\n\tLANG(\"English - Belize\", \"en_bz\", 0x2809),\n\tLANG(\"English - Canada\", \"en_ca\", 0x1009),\n\tLANG(\"English - Caribbean\", \"en_cb\", 0x2409),\n\tLANG(\"English - Ireland\", \"en_ie\", 0x1809),\n\tLANG(\"English - Jamaica\", \"en_jm\", 0x2009),\n\tLANG(\"English - New Zealand\", \"en_nz\", 0x1409),\n\tLANG(\"English - Phillippines\", \"en_ph\", 0x3409),\n\tLANG(\"English - Southern Africa\", \"en_za\", 0x1C09),\n\tLANG(\"English - Trinidad\", \"en_tt\", 0x2C09),\n\tLANG(\"English - Great Britain\", \"en_gb\", 0x0809),\n\tLANG(\"English - United States\", \"en_us\", 0x0409),\n\tLANG(\"Estonian\", \"et\", 0x0425),\n\tLANG(\"Farsi\", \"fa\", 0x0429),\n\tLANG(\"Finnish\", \"fi\", 0x040B),\n\tLANG(\"Faroese\", \"fo\", 0x0438),\n\tLANG(\"French - France\", \"fr_fr\", 0x040C),\n\tLANG(\"French - Belgium\", \"fr_be\", 0x080C),\n\tLANG(\"French - Canada\", \"fr_ca\", 0x0C0C),\n\tLANG(\"French - Luxembourg\", \"fr_lu\", 0x140C),\n\tLANG(\"French - Switzerland\", \"fr_ch\", 0x100C),\n\tLANG(\"Gaelic - Ireland\", \"gd_ie\", 0x083C),\n\tLANG(\"Gaelic - Scotland\", \"gd\", 0x043C),\n\tLANG(\"German - Germany\", \"de_de\", 0x0407),\n\tLANG(\"German - Austria\", \"de_at\", 0x0C07),\n\tLANG(\"German - Liechtenstein\", \"de_li\", 0x1407),\n\tLANG(\"German - Luxembourg\", \"de_lu\", 0x1007),\n\tLANG(\"German - Switzerland\", \"de_ch\", 0x0807),\n\tLANG(\"Greek\", \"el\", 0x0408),\n\tLANG(\"Hebrew\", \"he\", 0x040D),\n\tLANG(\"Hindi\", \"hi\", 0x0439),\n\tLANG(\"Hungarian\", \"hu\", 0x040E),\n\tLANG(\"Icelandic\", \"is\", 0x040F),\n\tLANG(\"Indonesian\", \"id\", 0x0421),\n\tLANG(\"Italian - Italy\", \"it_it\", 0x0410),\n\tLANG(\"Italian - Switzerland\", \"it_ch\", 0x0810),\n\tLANG(\"Japanese\", \"ja\", 0x0411),\n\tLANG(\"Korean\", \"ko\", 0x0412),\n\tLANG(\"Latvian\", \"lv\", 0x0426),\n\tLANG(\"Lithuanian\", \"lt\", 0x0427),\n\tLANG(\"F.Y.R.O. Macedonia\", \"mk\", 0x042F),\n\tLANG(\"Malay - Malaysia\", \"ms_my\", 0x043E),\n\tLANG(\"Malay – Brunei\", \"ms_bn\", 0x083E),\n\tLANG(\"Maltese\", \"mt\", 0x043A),\n\tLANG(\"Marathi\", \"mr\", 0x044E),\n\tLANG(\"Norwegian - Bokml\", \"no_no\", 0x0414),\n\tLANG(\"Norwegian - Nynorsk\", \"no_no\", 0x0814),\n\tLANG(\"Polish\", \"pl\", 0x0415),\n\tLANG(\"Portuguese - Portugal\", \"pt_pt\", 0x0816),\n\tLANG(\"Portuguese - Brazil\", \"pt_br\", 0x0416),\n\tLANG(\"Raeto-Romance\", \"rm\", 0x0417),\n\tLANG(\"Romanian - Romania\", \"ro\", 0x0418),\n\tLANG(\"Romanian - Republic of Moldova\", \"ro_mo\", 0x0818),\n\tLANG(\"Russian\", \"ru\", 0x0419),\n\tLANG(\"Russian - Republic of Moldova\", \"ru_mo\", 0x0819),\n\tLANG(\"Sanskrit\", \"sa\", 0x044F),\n\tLANG(\"Serbian - Cyrillic\", \"sr_sp\", 0x0C1A),\n\tLANG(\"Serbian - Latin\", \"sr_sp\", 0x081A),\n\tLANG(\"Setsuana\", \"tn\", 0x0432),\n\tLANG(\"Slovenian\", \"sl\", 0x0424),\n\tLANG(\"Slovak\", \"sk\", 0x041B),\n\tLANG(\"Sorbian\", \"sb\", 0x042E),\n\tLANG(\"Spanish - Spain (Traditional)\", \"es_es\", 0x040A),\n\tLANG(\"Spanish - Argentina\", \"es_ar\", 0x2C0A),\n\tLANG(\"Spanish - Bolivia\", \"es_bo\", 0x400A),\n\tLANG(\"Spanish - Chile\", \"es_cl\", 0x340A),\n\tLANG(\"Spanish - Colombia\", \"es_co\", 0x240A),\n\tLANG(\"Spanish - Costa Rica\", \"es_cr\", 0x140A),\n\tLANG(\"Spanish - Dominican Republic\", \"es_do\", 0x1C0A),\n\tLANG(\"Spanish - Ecuador\", \"es_ec\", 0x300A),\n\tLANG(\"Spanish - Guatemala\", \"es_gt\", 0x100A),\n\tLANG(\"Spanish - Honduras\", \"es_hn\", 0x480A),\n\tLANG(\"Spanish - Mexico\", \"es_mx\", 0x080A),\n\tLANG(\"Spanish - Nicaragua\", \"es_ni\", 0x4C0A),\n\tLANG(\"Spanish - Panama\", \"es_pa\", 0x180A),\n\tLANG(\"Spanish - Peru\", \"es_pe\", 0x280A),\n\tLANG(\"Spanish - Puerto Rico\", \"es_pr\", 0x500A),\n\tLANG(\"Spanish - Paraguay\", \"es_py\", 0x3C0A),\n\tLANG(\"Spanish - El Salvador\", \"es_sv\", 0x440A),\n\tLANG(\"Spanish - Uruguay\", \"es_uy\", 0x380A),\n\tLANG(\"Spanish - Venezuela\", \"es_ve\", 0x200A),\n\tLANG(\"Southern Sotho\", \"st\", 0x0430),\n\tLANG(\"Swahili\", \"sw\", 0x0441),\n\tLANG(\"Swedish - Sweden\", \"sv_se\", 0x041D),\n\tLANG(\"Swedish - Finland\", \"sv_fi\", 0x081D),\n\tLANG(\"Tamil\", \"ta\", 0x0449),\n\tLANG(\"Tatar\", \"tt\", 0X0444),\n\tLANG(\"Thai\", \"th\", 0x041E),\n\tLANG(\"Turkish\", \"tr\", 0x041F),\n\tLANG(\"Tsonga\", \"ts\", 0x0431),\n\tLANG(\"Ukrainian\", \"uk\", 0x0422),\n\tLANG(\"Urdu\", \"ur\", 0x0420),\n\tLANG(\"Uzbek - Cyrillic\", \"uz_uz\", 0x0843),\n\tLANG(\"Uzbek – Latin\", \"uz_uz\", 0x0443),\n\tLANG(\"Vietnamese\", \"vi\", 0x042A),\n\tLANG(\"Xhosa\", \"xh\", 0x0434),\n\tLANG(\"Yiddish\", \"yi\", 0x043D),\n\tLANG(\"Zulu\", \"zu\", 0x0435),\n\tLANG(NULL, NULL, 0x0),\t\n};\n\nuint16_t get_usb_code_for_current_locale(void)\n{\n\tchar *locale;\n\tchar search_string[64];\n\tchar *ptr;\n\t\n\t/* Get the current locale. */\n\tlocale = setlocale(0, NULL);\n\tif (!locale)\n\t\treturn 0x0;\n\t\n\t/* Make a copy of the current locale string. */\n\tstrncpy(search_string, locale, sizeof(search_string));\n\tsearch_string[sizeof(search_string)-1] = '\\0';\n\t\n\t/* Chop off the encoding part, and make it lower case. */\n\tptr = search_string;\n\twhile (*ptr) {\n\t\t*ptr = tolower(*ptr);\n\t\tif (*ptr == '.') {\n\t\t\t*ptr = '\\0';\n\t\t\tbreak;\n\t\t}\n\t\tptr++;\n\t}\n\n\t/* Find the entry which matches the string code of our locale. */\n\tstruct lang_map_entry *lang = lang_map;\n\twhile (lang->string_code) {\n\t\tif (!strcmp(lang->string_code, search_string)) {\n\t\t\treturn lang->usb_code;\n\t\t}\t\n\t\tlang++;\n\t}\n\t\n\t/* There was no match. Find with just the language only. */\n\t/* Chop off the variant. Chop it off at the '_'. */\n\tptr = search_string;\n\twhile (*ptr) {\n\t\t*ptr = tolower(*ptr);\n\t\tif (*ptr == '_') {\n\t\t\t*ptr = '\\0';\n\t\t\tbreak;\n\t\t}\n\t\tptr++;\n\t}\n\t\n#if 0 // TODO: Do we need this?\n\t/* Find the entry which matches the string code of our language. */\n\tlang = lang_map;\n\twhile (lang->string_code) {\n\t\tif (!strcmp(lang->string_code, search_string)) {\n\t\t\treturn lang->usb_code;\n\t\t}\t\n\t\tlang++;\n\t}\n#endif\n\t\n\t/* Found nothing. */\n\treturn 0x0;\n}\n\n#ifdef __cplusplus\n}\n#endif\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/linux/hid.c",
    "content": "/*******************************************************\n HIDAPI - Multi-Platform library for\n communication with HID devices.\n\n Alan Ott\n Signal 11 Software\n\n 8/22/2009\n Linux Version - 6/2/2009\n\n Copyright 2009, All Rights Reserved.\n \n At the discretion of the user of this library,\n this software may be licensed under the terms of the\n GNU Public License v3, a BSD-Style license, or the\n original HIDAPI license as outlined in the LICENSE.txt,\n LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt\n files located at the root of the source distribution.\n These files may also be found in the public source\n code repository located at:\n        http://github.com/signal11/hidapi .\n********************************************************/\n\n/* C */\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <locale.h>\n#include <errno.h>\n\n/* Unix */\n#include <unistd.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n#include <sys/ioctl.h>\n#include <sys/utsname.h>\n#include <fcntl.h>\n#include <poll.h>\n\n/* Linux */\n#include <linux/hidraw.h>\n#include <linux/version.h>\n#include <linux/input.h>\n#include <libudev.h>\n\n#include \"hidapi.h\"\n\n/* Definitions from linux/hidraw.h. Since these are new, some distros\n   may not have header files which contain them. */\n#ifndef HIDIOCSFEATURE\n#define HIDIOCSFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)\n#endif\n#ifndef HIDIOCGFEATURE\n#define HIDIOCGFEATURE(len)    _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)\n#endif\n\n\n/* USB HID device property names */\nconst char *device_string_names[] = {\n\t\"manufacturer\",\n\t\"product\",\n\t\"serial\",\n};\n\n/* Symbolic names for the properties above */\nenum device_string_id {\n\tDEVICE_STRING_MANUFACTURER,\n\tDEVICE_STRING_PRODUCT,\n\tDEVICE_STRING_SERIAL,\n\n\tDEVICE_STRING_COUNT,\n};\n\nstruct hid_device_ {\n\tint device_handle;\n\tint blocking;\n\tint uses_numbered_reports;\n};\n\n\nstatic __u32 kernel_version = 0;\n\nhid_device *new_hid_device()\n{\n\thid_device *dev = calloc(1, sizeof(hid_device));\n\tdev->device_handle = -1;\n\tdev->blocking = 1;\n\tdev->uses_numbered_reports = 0;\n\n\treturn dev;\n}\n\nstatic void register_error(hid_device *device, const char *op)\n{\n\n}\n\n/* The caller must free the returned string with free(). */\nstatic wchar_t *utf8_to_wchar_t(const char *utf8)\n{\n\twchar_t *ret = NULL;\n\n\tif (utf8) {\n\t\tsize_t wlen = mbstowcs(NULL, utf8, 0);\n\t\tif (wlen < 0) {\n\t\t\treturn wcsdup(L\"\");\n\t\t}\n\t\tret = calloc(wlen+1, sizeof(wchar_t));\n\t\tmbstowcs(ret, utf8, wlen+1);\n\t\tret[wlen] = 0x0000;\n\t}\n\n\treturn ret;\n}\n\n/* Get an attribute value from a udev_device and return it as a whar_t\n   string. The returned string must be freed with free() when done.*/\nstatic wchar_t *copy_udev_string(struct udev_device *dev, const char *udev_name)\n{\n\treturn utf8_to_wchar_t(udev_device_get_sysattr_value(dev, udev_name));\n}\n\n/* uses_numbered_reports() returns 1 if report_descriptor describes a device\n   which contains numbered reports. */ \nstatic int uses_numbered_reports(__u8 *report_descriptor, __u32 size) {\n\tint i = 0;\n\tint size_code;\n\tint data_len, key_size;\n\t\n\twhile (i < size) {\n\t\tint key = report_descriptor[i];\n\n\t\t/* Check for the Report ID key */\n\t\tif (key == 0x85/*Report ID*/) {\n\t\t\t/* This device has a Report ID, which means it uses\n\t\t\t   numbered reports. */\n\t\t\treturn 1;\n\t\t}\n\t\t\n\t\t//printf(\"key: %02hhx\\n\", key);\n\t\t\n\t\tif ((key & 0xf0) == 0xf0) {\n\t\t\t/* This is a Long Item. The next byte contains the\n\t\t\t   length of the data section (value) for this key.\n\t\t\t   See the HID specification, version 1.11, section\n\t\t\t   6.2.2.3, titled \"Long Items.\" */\n\t\t\tif (i+1 < size)\n\t\t\t\tdata_len = report_descriptor[i+1];\n\t\t\telse\n\t\t\t\tdata_len = 0; /* malformed report */\n\t\t\tkey_size = 3;\n\t\t}\n\t\telse {\n\t\t\t/* This is a Short Item. The bottom two bits of the\n\t\t\t   key contain the size code for the data section\n\t\t\t   (value) for this key.  Refer to the HID\n\t\t\t   specification, version 1.11, section 6.2.2.2,\n\t\t\t   titled \"Short Items.\" */\n\t\t\tsize_code = key & 0x3;\n\t\t\tswitch (size_code) {\n\t\t\tcase 0:\n\t\t\tcase 1:\n\t\t\tcase 2:\n\t\t\t\tdata_len = size_code;\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tdata_len = 4;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t/* Can't ever happen since size_code is & 0x3 */\n\t\t\t\tdata_len = 0;\n\t\t\t\tbreak;\n\t\t\t};\n\t\t\tkey_size = 1;\n\t\t}\n\t\t\n\t\t/* Skip over this key and it's associated data */\n\t\ti += data_len + key_size;\n\t}\n\t\n\t/* Didn't find a Report ID key. Device doesn't use numbered reports. */\n\treturn 0;\n}\n\n/*\n * The caller is responsible for free()ing the (newly-allocated) character\n * strings pointed to by serial_number_utf8 and product_name_utf8 after use.\n */\nint\nparse_uevent_info(const char *uevent, int *bus_type,\n\tunsigned short *vendor_id, unsigned short *product_id,\n\tchar **serial_number_utf8, char **product_name_utf8)\n{\n\tchar *tmp = strdup(uevent);\n\tchar *saveptr = NULL;\n\tchar *line;\n\tchar *key;\n\tchar *value;\n\n\tint found_id = 0;\n\tint found_serial = 0;\n\tint found_name = 0;\n\n\tline = strtok_r(tmp, \"\\n\", &saveptr);\n\twhile (line != NULL) {\n\t\t/* line: \"KEY=value\" */\n\t\tkey = line;\n\t\tvalue = strchr(line, '=');\n\t\tif (!value) {\n\t\t\tgoto next_line;\n\t\t}\n\t\t*value = '\\0';\n\t\tvalue++;\n\n\t\tif (strcmp(key, \"HID_ID\") == 0) {\n\t\t\t/**\n\t\t\t *        type vendor   product\n\t\t\t * HID_ID=0003:000005AC:00008242\n\t\t\t **/\n\t\t\tint ret = sscanf(value, \"%x:%hx:%hx\", bus_type, vendor_id, product_id);\n\t\t\tif (ret == 3) {\n\t\t\t\tfound_id = 1;\n\t\t\t}\n\t\t} else if (strcmp(key, \"HID_NAME\") == 0) {\n\t\t\t/* The caller has to free the product name */\n\t\t\t*product_name_utf8 = strdup(value);\n\t\t\tfound_name = 1;\n\t\t} else if (strcmp(key, \"HID_UNIQ\") == 0) {\n\t\t\t/* The caller has to free the serial number */\n\t\t\t*serial_number_utf8 = strdup(value);\n\t\t\tfound_serial = 1;\n\t\t}\n\nnext_line:\n\t\tline = strtok_r(NULL, \"\\n\", &saveptr);\n\t}\n\n\tfree(tmp);\n\treturn (found_id && found_name && found_serial);\n}\n\n\nstatic int get_device_string(hid_device *dev, enum device_string_id key, wchar_t *string, size_t maxlen)\n{\n\tstruct udev *udev;\n\tstruct udev_device *udev_dev, *parent, *hid_dev;\n\tstruct stat s;\n\tint ret = -1;\n\n\t/* Create the udev object */\n\tudev = udev_new();\n\tif (!udev) {\n\t\tprintf(\"Can't create udev\\n\");\n\t\treturn -1;\n\t}\n\n\t/* Get the dev_t (major/minor numbers) from the file handle. */\n\tfstat(dev->device_handle, &s);\n\t/* Open a udev device from the dev_t. 'c' means character device. */\n\tudev_dev = udev_device_new_from_devnum(udev, 'c', s.st_rdev);\n\tif (udev_dev) {\n\t\thid_dev = udev_device_get_parent_with_subsystem_devtype(\n\t\t\tudev_dev,\n\t\t\t\"hid\",\n\t\t\tNULL);\n\t\tif (hid_dev) {\n\t\t\tunsigned short dev_vid;\n\t\t\tunsigned short dev_pid;\n\t\t\tchar *serial_number_utf8 = NULL;\n\t\t\tchar *product_name_utf8 = NULL;\n\t\t\tint bus_type;\n\n\t\t\tret = parse_uevent_info(\n\t\t\t           udev_device_get_sysattr_value(hid_dev, \"uevent\"),\n\t\t\t           &bus_type,\n\t\t\t           &dev_vid,\n\t\t\t           &dev_pid,\n\t\t\t           &serial_number_utf8,\n\t\t\t           &product_name_utf8);\n\n\t\t\tif (bus_type == BUS_BLUETOOTH) {\n\t\t\t\tswitch (key) {\n\t\t\t\t\tcase DEVICE_STRING_MANUFACTURER:\n\t\t\t\t\t\twcsncpy(string, L\"\", maxlen);\n\t\t\t\t\t\tret = 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DEVICE_STRING_PRODUCT:\n\t\t\t\t\t\tret = mbstowcs(string, product_name_utf8, maxlen);\n\t\t\t\t\t\tret = (ret == (size_t)-1)? -1: 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase DEVICE_STRING_SERIAL:\n\t\t\t\t\t\tret = mbstowcs(string, serial_number_utf8, maxlen);\n\t\t\t\t\t\tret = (ret == (size_t)-1)? -1: 0;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tret = -1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t/* This is a USB device. Find its parent USB Device node. */\n\t\t\t\tparent = udev_device_get_parent_with_subsystem_devtype(\n\t\t\t\t\t   udev_dev,\n\t\t\t\t\t   \"usb\",\n\t\t\t\t\t   \"usb_device\");\n\t\t\t\tif (parent) {\n\t\t\t\t\tconst char *str;\n\t\t\t\t\tconst char *key_str = NULL;\n\n\t\t\t\t\tif (key >= 0 && key < DEVICE_STRING_COUNT) {\n\t\t\t\t\t\tkey_str = device_string_names[key];\n\t\t\t\t\t} else {\n\t\t\t\t\t\tret = -1;\n\t\t\t\t\t\tgoto end;\n\t\t\t\t\t}\n\n\t\t\t\t\tstr = udev_device_get_sysattr_value(parent, key_str);\n\t\t\t\t\tif (str) {\n\t\t\t\t\t\t/* Convert the string from UTF-8 to wchar_t */\n\t\t\t\t\t\tret = mbstowcs(string, str, maxlen);\n\t\t\t\t\t\tret = (ret == (size_t)-1)? -1: 0;\n\t\t\t\t\t\tgoto end;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfree(serial_number_utf8);\n\t\t\tfree(product_name_utf8);\n\t\t}\n\t}\n\nend:\n\tudev_device_unref(udev_dev);\n\t// parent and hid_dev don't need to be (and can't be) unref'd.\n\t// I'm not sure why, but they'll throw double-free() errors.\n\tudev_unref(udev);\n\n\treturn ret;\n}\n\nint HID_API_EXPORT hid_init(void)\n{\n\tconst char *locale;\n\n\t/* Set the locale if it's not set. */\n\tlocale = setlocale(LC_CTYPE, NULL);\n\tif (!locale)\n\t\tsetlocale(LC_CTYPE, \"\");\n\n\treturn 0;\n}\n\nint HID_API_EXPORT hid_exit(void)\n{\n\t/* Nothing to do for this in the Linux/hidraw implementation. */\n\treturn 0;\n}\n\n\nstruct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)\n{\n\tstruct udev *udev;\n\tstruct udev_enumerate *enumerate;\n\tstruct udev_list_entry *devices, *dev_list_entry;\n\t\n\tstruct hid_device_info *root = NULL; // return object\n\tstruct hid_device_info *cur_dev = NULL;\n\tstruct hid_device_info *prev_dev = NULL; // previous device\n\n\thid_init();\n\n\t/* Create the udev object */\n\tudev = udev_new();\n\tif (!udev) {\n\t\tprintf(\"Can't create udev\\n\");\n\t\treturn NULL;\n\t}\n\n\t/* Create a list of the devices in the 'hidraw' subsystem. */\n\tenumerate = udev_enumerate_new(udev);\n\tudev_enumerate_add_match_subsystem(enumerate, \"hidraw\");\n\tudev_enumerate_scan_devices(enumerate);\n\tdevices = udev_enumerate_get_list_entry(enumerate);\n\t/* For each item, see if it matches the vid/pid, and if so\n\t   create a udev_device record for it */\n\tudev_list_entry_foreach(dev_list_entry, devices) {\n\t\tconst char *sysfs_path;\n\t\tconst char *dev_path;\n\t\tconst char *str;\n\t\tstruct udev_device *raw_dev; // The device's hidraw udev node.\n\t\tstruct udev_device *hid_dev; // The device's HID udev node.\n\t\tstruct udev_device *usb_dev; // The device's USB udev node.\n\t\tstruct udev_device *intf_dev; // The device's interface (in the USB sense).\n\t\tunsigned short dev_vid;\n\t\tunsigned short dev_pid;\n\t\tchar *serial_number_utf8 = NULL;\n\t\tchar *product_name_utf8 = NULL;\n\t\tint bus_type;\n\t\tint result;\n\n\t\t/* Get the filename of the /sys entry for the device\n\t\t   and create a udev_device object (dev) representing it */\n\t\tsysfs_path = udev_list_entry_get_name(dev_list_entry);\n\t\traw_dev = udev_device_new_from_syspath(udev, sysfs_path);\n\t\tdev_path = udev_device_get_devnode(raw_dev);\n\n\t\thid_dev = udev_device_get_parent_with_subsystem_devtype(\n\t\t\traw_dev,\n\t\t\t\"hid\",\n\t\t\tNULL);\n\n\t\tif (!hid_dev) {\n\t\t\t/* Unable to find parent hid device. */\n\t\t\tgoto next;\n\t\t}\n\n\t\tresult = parse_uevent_info(\n\t\t\tudev_device_get_sysattr_value(hid_dev, \"uevent\"),\n\t\t\t&bus_type,\n\t\t\t&dev_vid,\n\t\t\t&dev_pid,\n\t\t\t&serial_number_utf8,\n\t\t\t&product_name_utf8);\n\n\t\tif (!result) {\n\t\t\t/* parse_uevent_info() failed for at least one field. */\n\t\t\tgoto next;\n\t\t}\n\n\t\tif (bus_type != BUS_USB && bus_type != BUS_BLUETOOTH) {\n\t\t\t/* We only know how to handle USB and BT devices. */\n\t\t\tgoto next;\n\t\t}\n\n\t\t/* Check the VID/PID against the arguments */\n\t\tif ((vendor_id == 0x0 && product_id == 0x0) ||\n\t\t    (vendor_id == dev_vid && product_id == dev_pid)) {\n\t\t\tstruct hid_device_info *tmp;\n\n\t\t\t/* VID/PID match. Create the record. */\n\t\t\ttmp = malloc(sizeof(struct hid_device_info));\n\t\t\tif (cur_dev) {\n\t\t\t\tcur_dev->next = tmp;\n\t\t\t}\n\t\t\telse {\n\t\t\t\troot = tmp;\n\t\t\t}\n\t\t\tprev_dev = cur_dev;\n\t\t\tcur_dev = tmp;\n\n\t\t\t/* Fill out the record */\n\t\t\tcur_dev->next = NULL;\n\t\t\tcur_dev->path = dev_path? strdup(dev_path): NULL;\n\n\t\t\t/* VID/PID */\n\t\t\tcur_dev->vendor_id = dev_vid;\n\t\t\tcur_dev->product_id = dev_pid;\n\n\t\t\t/* Serial Number */\n\t\t\tcur_dev->serial_number = utf8_to_wchar_t(serial_number_utf8);\n\n\t\t\t/* Release Number */\n\t\t\tcur_dev->release_number = 0x0;\n\n\t\t\t/* Interface Number */\n\t\t\tcur_dev->interface_number = -1;\n\n\t\t\tswitch (bus_type) {\n\t\t\t\tcase BUS_USB:\n\t\t\t\t\t/* The device pointed to by raw_dev contains information about\n\t\t\t\t\t   the hidraw device. In order to get information about the\n\t\t\t\t\t   USB device, get the parent device with the\n\t\t\t\t\t   subsystem/devtype pair of \"usb\"/\"usb_device\". This will\n\t\t\t\t\t   be several levels up the tree, but the function will find\n\t\t\t\t\t   it. */\n\t\t\t\t\tusb_dev = udev_device_get_parent_with_subsystem_devtype(\n\t\t\t\t\t\t\traw_dev,\n\t\t\t\t\t\t\t\"usb\",\n\t\t\t\t\t\t\t\"usb_device\");\n\n\t\t\t\t\tif (!usb_dev) {\n\t\t\t\t\t\t/* Free this device */\n\t\t\t\t\t\tfree(cur_dev->serial_number);\n\t\t\t\t\t\tfree(cur_dev->path);\n\t\t\t\t\t\tfree(cur_dev);\n\n\t\t\t\t\t\t/* Take it off the device list. */\n\t\t\t\t\t\tif (prev_dev) {\n\t\t\t\t\t\t\tprev_dev->next = NULL;\n\t\t\t\t\t\t\tcur_dev = prev_dev;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tcur_dev = root = NULL;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgoto next;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* Manufacturer and Product strings */\n\t\t\t\t\tcur_dev->manufacturer_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_MANUFACTURER]);\n\t\t\t\t\tcur_dev->product_string = copy_udev_string(usb_dev, device_string_names[DEVICE_STRING_PRODUCT]);\n\n\t\t\t\t\t/* Release Number */\n\t\t\t\t\tstr = udev_device_get_sysattr_value(usb_dev, \"bcdDevice\");\n\t\t\t\t\tcur_dev->release_number = (str)? strtol(str, NULL, 16): 0x0;\n\n\t\t\t\t\t/* Get a handle to the interface's udev node. */\n\t\t\t\t\tintf_dev = udev_device_get_parent_with_subsystem_devtype(\n\t\t\t\t\t\t\traw_dev,\n\t\t\t\t\t\t\t\"usb\",\n\t\t\t\t\t\t\t\"usb_interface\");\n\t\t\t\t\tif (intf_dev) {\n\t\t\t\t\t\tstr = udev_device_get_sysattr_value(intf_dev, \"bInterfaceNumber\");\n\t\t\t\t\t\tcur_dev->interface_number = (str)? strtol(str, NULL, 16): -1;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase BUS_BLUETOOTH:\n\t\t\t\t\t/* Manufacturer and Product strings */\n\t\t\t\t\tcur_dev->manufacturer_string = wcsdup(L\"\");\n\t\t\t\t\tcur_dev->product_string = utf8_to_wchar_t(product_name_utf8);\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\t/* Unknown device type - this should never happen, as we\n\t\t\t\t\t * check for USB and Bluetooth devices above */\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\tnext:\n\t\tfree(serial_number_utf8);\n\t\tfree(product_name_utf8);\n\t\tudev_device_unref(raw_dev);\n\t\t/* hid_dev, usb_dev and intf_dev don't need to be (and can't be)\n\t\t   unref()d.  It will cause a double-free() error.  I'm not\n\t\t   sure why.  */\n\t}\n\t/* Free the enumerator and udev objects. */\n\tudev_enumerate_unref(enumerate);\n\tudev_unref(udev);\n\t\n\treturn root;\n}\n\nvoid  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)\n{\n\tstruct hid_device_info *d = devs;\n\twhile (d) {\n\t\tstruct hid_device_info *next = d->next;\n\t\tfree(d->path);\n\t\tfree(d->serial_number);\n\t\tfree(d->manufacturer_string);\n\t\tfree(d->product_string);\n\t\tfree(d);\n\t\td = next;\n\t}\n}\n\nhid_device * hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)\n{\n\tstruct hid_device_info *devs, *cur_dev;\n\tconst char *path_to_open = NULL;\n\thid_device *handle = NULL;\n\t\n\tdevs = hid_enumerate(vendor_id, product_id);\n\tcur_dev = devs;\n\twhile (cur_dev) {\n\t\tif (cur_dev->vendor_id == vendor_id &&\n\t\t    cur_dev->product_id == product_id) {\n\t\t\tif (serial_number) {\n\t\t\t\tif (wcscmp(serial_number, cur_dev->serial_number) == 0) {\n\t\t\t\t\tpath_to_open = cur_dev->path;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpath_to_open = cur_dev->path;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcur_dev = cur_dev->next;\n\t}\n\n\tif (path_to_open) {\n\t\t/* Open the device */\n\t\thandle = hid_open_path(path_to_open);\n\t}\n\n\thid_free_enumeration(devs);\n\t\n\treturn handle;\n}\n\nhid_device * HID_API_EXPORT hid_open_path(const char *path)\n{\n\thid_device *dev = NULL;\n\n\thid_init();\n\n\tdev = new_hid_device();\n\n\tif (kernel_version == 0) {\n\t\tstruct utsname name;\n\t\tint major, minor, release;\n\t\tint ret;\n\t\tuname(&name);\n\t\tret = sscanf(name.release, \"%d.%d.%d\", &major, &minor, &release);\n\t\tif (ret == 3) {\n\t\t\tkernel_version = major << 16 | minor << 8 | release;\n\t\t\t//printf(\"Kernel Version: %d\\n\", kernel_version);\n\t\t}\n\t\telse {\n\t\t\tprintf(\"Couldn't sscanf() version string %s\\n\", name.release);\n\t\t}\n\t}\n\n\t// OPEN HERE //\n\tdev->device_handle = open(path, O_RDWR);\n\n\t// If we have a good handle, return it.\n\tif (dev->device_handle > 0) {\n\n\t\t/* Get the report descriptor */\n\t\tint res, desc_size = 0;\n\t\tstruct hidraw_report_descriptor rpt_desc;\n\n\t\tmemset(&rpt_desc, 0x0, sizeof(rpt_desc));\n\n\t\t/* Get Report Descriptor Size */\n\t\tres = ioctl(dev->device_handle, HIDIOCGRDESCSIZE, &desc_size);\n\t\tif (res < 0)\n\t\t\tperror(\"HIDIOCGRDESCSIZE\");\n\n\n\t\t/* Get Report Descriptor */\n\t\trpt_desc.size = desc_size;\n\t\tres = ioctl(dev->device_handle, HIDIOCGRDESC, &rpt_desc);\n\t\tif (res < 0) {\n\t\t\tperror(\"HIDIOCGRDESC\");\n\t\t} else {\n\t\t\t/* Determine if this device uses numbered reports. */\n\t\t\tdev->uses_numbered_reports =\n\t\t\t\tuses_numbered_reports(rpt_desc.value,\n\t\t\t\t                      rpt_desc.size);\n\t\t}\n\t\t\n\t\treturn dev;\n\t}\n\telse {\n\t\t// Unable to open any devices.\n\t\tfree(dev);\n\t\treturn NULL;\n\t}\n}\n\n\nint HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)\n{\n\tint bytes_written;\n\n\tbytes_written = write(dev->device_handle, data, length);\n\n\treturn bytes_written;\n}\n\n\nint HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)\n{\n\tint bytes_read;\n\n\tif (milliseconds != 0) {\n\t\t/* milliseconds is -1 or > 0. In both cases, we want to\n\t\t   call poll() and wait for data to arrive. -1 means\n\t\t   INFINITE. */\n\t\tint ret;\n\t\tstruct pollfd fds;\n\n\t\tfds.fd = dev->device_handle;\n\t\tfds.events = POLLIN;\n\t\tfds.revents = 0;\n\t\tret = poll(&fds, 1, milliseconds);\n\t\tif (ret == -1 || ret == 0)\n\t\t\t/* Error or timeout */\n\t\t\treturn ret;\n\t}\n\n\tbytes_read = read(dev->device_handle, data, length);\n\tif (bytes_read < 0 && errno == EAGAIN)\n\t\tbytes_read = 0;\n\t\n\tif (bytes_read >= 0 &&\n\t    kernel_version < KERNEL_VERSION(2,6,34) &&\n\t    dev->uses_numbered_reports) {\n\t\t/* Work around a kernel bug. Chop off the first byte. */\n\t\tmemmove(data, data+1, bytes_read);\n\t\tbytes_read--;\n\t}\n\n\treturn bytes_read;\n}\n\nint HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)\n{\n\treturn hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);\n}\n\nint HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)\n{\n\tint flags, res;\n\n\tflags = fcntl(dev->device_handle, F_GETFL, 0);\n\tif (flags >= 0) {\n\t\tif (nonblock)\n\t\t\tres = fcntl(dev->device_handle, F_SETFL, flags | O_NONBLOCK);\n\t\telse\n\t\t\tres = fcntl(dev->device_handle, F_SETFL, flags & ~O_NONBLOCK);\n\t}\n\telse\n\t\treturn -1;\n\n\tif (res < 0) {\n\t\treturn -1;\n\t}\n\telse {\n\t\tdev->blocking = !nonblock;\n\t\treturn 0; /* Success */\n\t}\n}\n\n\nint HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)\n{\n\tint res;\n\n\tres = ioctl(dev->device_handle, HIDIOCSFEATURE(length), data);\n\tif (res < 0)\n\t\tperror(\"ioctl (SFEATURE)\");\n\n\treturn res;\n}\n\nint HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)\n{\n\tint res;\n\n\tres = ioctl(dev->device_handle, HIDIOCGFEATURE(length), data);\n\tif (res < 0)\n\t\tperror(\"ioctl (GFEATURE)\");\n\n\n\treturn res;\n}\n\n\nvoid HID_API_EXPORT hid_close(hid_device *dev)\n{\n\tif (!dev)\n\t\treturn;\n\tclose(dev->device_handle);\n\tfree(dev);\n}\n\n\nint HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)\n{\n\treturn get_device_string(dev, DEVICE_STRING_MANUFACTURER, string, maxlen);\n}\n\nint HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)\n{\n\treturn get_device_string(dev, DEVICE_STRING_PRODUCT, string, maxlen);\n}\n\nint HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)\n{\n\treturn get_device_string(dev, DEVICE_STRING_SERIAL, string, maxlen);\n}\n\nint HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)\n{\n\treturn -1;\n}\n\n\nHID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)\n{\n\treturn NULL;\n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/mac/Makefile",
    "content": "###########################################\n# Simple Makefile for HIDAPI test program\n#\n# Alan Ott\n# Signal 11 Software\n# 2010-07-03\n###########################################\n\n#ARCHFLAGS=-m32\n\nJNIOBJS=HIDManager.o HIDDeviceInfo.o HIDDevice.o hid-java.o\nJNIINCLUDES=-I.. -I../jni-impl -I/System/Library/Frameworks/JavaVM.framework/Headers \nJNILIBS=-l iconv\nJNISHAREDLIB=libhidapi-jni.jnilib\nJNISHAREDLIBVER=1.0\n\nCC=gcc\nCXX=g++\nCOBJS=hid.o\nCPPOBJS=../hidtest/hidtest.o\nOBJS=$(COBJS) $(CPPOBJS) $(JNIOBJS)\nCFLAGS+=$(ARCHFLAGS) -I../hidapi -g -c $(JNIINCLUDES)\nLIBS=-framework IOKit -framework CoreFoundation $(JNILIBS)\n\nall: hidtest $(JNISHAREDLIB)\n\n$(JNISHAREDLIB): $(OBJS)\n\t$(CXX) $(ARCHFLAGS) -dynamiclib -current_version $(JNISHAREDLIBVER) $(COBJS) $(JNIOBJS) $(LIBS) -o $(JNISHAREDLIB)\n\nhidtest: $(OBJS)\n\t$(CXX) $(ARCHFLAGS) -g $^ $(LIBS) -o hidtest\n\n%.o: ../jni-impl/%.cpp\n\t$(CXX) $(CFLAGS) $< -o $@\n\n$(COBJS): %.o: %.c\n\t$(CC) $(CFLAGS) $< -o $@\n\n$(CPPOBJS): %.o: %.cpp\n\t$(CXX) $(CFLAGS) $< -o $@\n\nclean:\n\trm -f *.o hidtest $(CPPOBJS) $(JNISHAREDLIB)\n\n.PHONY: clean\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/mac/hid.c",
    "content": "/*******************************************************\n HIDAPI - Multi-Platform library for\n communication with HID devices.\n \n Alan Ott\n Signal 11 Software\n\n 2010-07-03\n\n Copyright 2010, All Rights Reserved.\n \n At the discretion of the user of this library,\n this software may be licensed under the terms of the\n GNU Public License v3, a BSD-Style license, or the\n original HIDAPI license as outlined in the LICENSE.txt,\n LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt\n files located at the root of the source distribution.\n These files may also be found in the public source\n code repository located at:\n        http://github.com/signal11/hidapi .\n********************************************************/\n\n/* See Apple Technical Note TN2187 for details on IOHidManager. */\n\n#include <IOKit/hid/IOHIDManager.h>\n#include <IOKit/hid/IOHIDKeys.h>\n#include <CoreFoundation/CoreFoundation.h>\n#include <wchar.h>\n#include <locale.h>\n#include <pthread.h>\n#include <sys/time.h>\n#include <unistd.h>\n\n#include \"hidapi.h\"\n\n/* Barrier implementation because Mac OSX doesn't have pthread_barrier.\n   It also doesn't have clock_gettime(). So much for POSIX and SUSv2.\n   This implementation came from Brent Priddy and was posted on\n   StackOverflow. It is used with his permission. */\ntypedef int pthread_barrierattr_t;\ntypedef struct pthread_barrier {\n    pthread_mutex_t mutex;\n    pthread_cond_t cond;\n    int count;\n    int trip_count;\n} pthread_barrier_t;\n\nstatic int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)\n{\n\tif(count == 0) {\n\t\terrno = EINVAL;\n\t\treturn -1;\n\t}\n\t\n\tif(pthread_mutex_init(&barrier->mutex, 0) < 0) {\n\t\treturn -1;\n\t}\n\tif(pthread_cond_init(&barrier->cond, 0) < 0) {\n\t\tpthread_mutex_destroy(&barrier->mutex);\n\t\treturn -1;\n\t}\n\tbarrier->trip_count = count;\n\tbarrier->count = 0;\n\n\treturn 0;\n}\n\nstatic int pthread_barrier_destroy(pthread_barrier_t *barrier)\n{\n\tpthread_cond_destroy(&barrier->cond);\n\tpthread_mutex_destroy(&barrier->mutex);\n\treturn 0;\n}\n\nstatic int pthread_barrier_wait(pthread_barrier_t *barrier)\n{\n\tpthread_mutex_lock(&barrier->mutex);\n\t++(barrier->count);\n\tif(barrier->count >= barrier->trip_count)\n\t{\n\t\tbarrier->count = 0;\n\t\tpthread_cond_broadcast(&barrier->cond);\n\t\tpthread_mutex_unlock(&barrier->mutex);\n\t\treturn 1;\n\t}\n\telse\n\t{\n\t\tpthread_cond_wait(&barrier->cond, &(barrier->mutex));\n\t\tpthread_mutex_unlock(&barrier->mutex);\n\t\treturn 0;\n\t}\n}\n\nstatic int return_data(hid_device *dev, unsigned char *data, size_t length);\n\n/* Linked List of input reports received from the device. */\nstruct input_report {\n\tuint8_t *data;\n\tsize_t len;\n\tstruct input_report *next;\n};\n\nstruct hid_device_ {\n\tIOHIDDeviceRef device_handle;\n\tint blocking;\n\tint uses_numbered_reports;\n\tint disconnected;\n\tCFStringRef run_loop_mode;\n\tCFRunLoopRef run_loop;\n\tCFRunLoopSourceRef source;\n\tuint8_t *input_report_buf;\n\tCFIndex max_input_report_len;\n\tstruct input_report *input_reports;\n\n\tpthread_t thread;\n\tpthread_mutex_t mutex; /* Protects input_reports */\n\tpthread_cond_t condition;\n\tpthread_barrier_t barrier; /* Ensures correct startup sequence */\n\tpthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */\n\tint shutdown_thread;\n\t\n\thid_device *next;\n};\n\n/* Static list of all the devices open. This way when a device gets\n   disconnected, its hid_device structure can be marked as disconnected\n   from hid_device_removal_callback(). */\nstatic hid_device *device_list = NULL;\nstatic pthread_mutex_t device_list_mutex = PTHREAD_MUTEX_INITIALIZER;\n\nstatic hid_device *new_hid_device(void)\n{\n\thid_device *dev = calloc(1, sizeof(hid_device));\n\tdev->device_handle = NULL;\n\tdev->blocking = 1;\n\tdev->uses_numbered_reports = 0;\n\tdev->disconnected = 0;\n\tdev->run_loop_mode = NULL;\n\tdev->run_loop = NULL;\n\tdev->source = NULL;\n\tdev->input_report_buf = NULL;\n\tdev->input_reports = NULL;\n\tdev->shutdown_thread = 0;\n\tdev->next = NULL;\n\n\t/* Thread objects */\n\tpthread_mutex_init(&dev->mutex, NULL);\n\tpthread_cond_init(&dev->condition, NULL);\n\tpthread_barrier_init(&dev->barrier, NULL, 2);\n\tpthread_barrier_init(&dev->shutdown_barrier, NULL, 2);\n\t\n\t/* Add the new record to the device_list. */\n\tpthread_mutex_lock(&device_list_mutex);\n\tif (!device_list)\n\t\tdevice_list = dev;\n\telse {\n\t\thid_device *d = device_list;\n\t\twhile (d) {\n\t\t\tif (!d->next) {\n\t\t\t\td->next = dev;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\td = d->next;\n\t\t}\n\t}\n\tpthread_mutex_unlock(&device_list_mutex);\n\t\n\treturn dev;\n}\n\nstatic void free_hid_device(hid_device *dev)\n{\n\tif (!dev)\n\t\treturn;\n\t\n\t/* Delete any input reports still left over. */\n\tstruct input_report *rpt = dev->input_reports;\n\twhile (rpt) {\n\t\tstruct input_report *next = rpt->next;\n\t\tfree(rpt->data);\n\t\tfree(rpt);\n\t\trpt = next;\n\t}\n\n\t/* Free the string and the report buffer. The check for NULL\n\t   is necessary here as CFRelease() doesn't handle NULL like\n\t   free() and others do. */\n\tif (dev->run_loop_mode)\n\t\tCFRelease(dev->run_loop_mode);\n\tif (dev->source)\n\t\tCFRelease(dev->source);\n\tfree(dev->input_report_buf);\n\n\t/* Clean up the thread objects */\n\tpthread_barrier_destroy(&dev->shutdown_barrier);\n\tpthread_barrier_destroy(&dev->barrier);\n\tpthread_cond_destroy(&dev->condition);\n\tpthread_mutex_destroy(&dev->mutex);\n\n\t/* Remove it from the device list. */\n\tpthread_mutex_lock(&device_list_mutex);\n\thid_device *d = device_list;\n\tif (d == dev) {\n\t\tdevice_list = d->next;\n\t}\n\telse {\n\t\twhile (d) {\n\t\t\tif (d->next == dev) {\n\t\t\t\td->next = d->next->next;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\td = d->next;\n\t\t}\n\t}\n\tpthread_mutex_unlock(&device_list_mutex);\n\n\t/* Free the structure itself. */\n\tfree(dev);\n}\n\nstatic \tIOHIDManagerRef hid_mgr = 0x0;\n\n\n#if 0\nstatic void register_error(hid_device *device, const char *op)\n{\n\n}\n#endif\n\n\nstatic int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key)\n{\n\tCFTypeRef ref;\n\tint32_t value;\n\t\n\tref = IOHIDDeviceGetProperty(device, key);\n\tif (ref) {\n\t\tif (CFGetTypeID(ref) == CFNumberGetTypeID()) {\n\t\t\tCFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value);\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn 0;\n}\n\nstatic unsigned short get_vendor_id(IOHIDDeviceRef device)\n{\n\treturn get_int_property(device, CFSTR(kIOHIDVendorIDKey));\n}\n\nstatic unsigned short get_product_id(IOHIDDeviceRef device)\n{\n\treturn get_int_property(device, CFSTR(kIOHIDProductIDKey));\n}\n\n\nstatic int32_t get_max_report_length(IOHIDDeviceRef device)\n{\n\treturn get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey));\n}\n\nstatic int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len)\n{\n\tCFStringRef str;\n\t\n\tif (!len)\n\t\treturn 0;\n\n\tstr = IOHIDDeviceGetProperty(device, prop);\n\n\tbuf[0] = 0;\n\n\tif (str) {\n\t\tlen --;\n\n\t\tCFIndex str_len = CFStringGetLength(str);\n\t\tCFRange range;\n\t\trange.location = 0;\n\t\trange.length = (str_len > len)? len: str_len;\n\t\tCFIndex used_buf_len;\n\t\tCFIndex chars_copied;\n\t\tchars_copied = CFStringGetBytes(str,\n\t\t\trange,\n\t\t\tkCFStringEncodingUTF32LE,\n\t\t\t(char)'?',\n\t\t\tFALSE,\n\t\t\t(UInt8*)buf,\n\t\t\tlen,\n\t\t\t&used_buf_len);\n\n\t\tbuf[chars_copied] = 0;\n\t\treturn 0;\n\t}\n\telse\n\t\treturn -1;\n\t\t\n}\n\nstatic int get_string_property_utf8(IOHIDDeviceRef device, CFStringRef prop, char *buf, size_t len)\n{\n\tCFStringRef str;\n\tif (!len)\n\t\treturn 0;\n\n\tstr = IOHIDDeviceGetProperty(device, prop);\n\n\tbuf[0] = 0;\n\n\tif (str) {\n\t\tlen--;\n\n\t\tCFIndex str_len = CFStringGetLength(str);\n\t\tCFRange range;\n\t\trange.location = 0;\n\t\trange.length = (str_len > len)? len: str_len;\n\t\tCFIndex used_buf_len;\n\t\tCFIndex chars_copied;\n\t\tchars_copied = CFStringGetBytes(str,\n\t\t\trange,\n\t\t\tkCFStringEncodingUTF8,\n\t\t\t(char)'?',\n\t\t\tFALSE,\n\t\t\t(UInt8*)buf,\n\t\t\tlen,\n\t\t\t&used_buf_len);\n\n\t\tbuf[chars_copied] = 0;\n\t\treturn used_buf_len;\n\t}\n\telse\n\t\treturn 0;\n}\n\n\nstatic int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len)\n{\n\treturn get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len);\n}\n\nstatic int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)\n{\n\treturn get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len);\n}\n\nstatic int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)\n{\n\treturn get_string_property(device, CFSTR(kIOHIDProductKey), buf, len);\n}\n\n\n/* Implementation of wcsdup() for Mac. */\nstatic wchar_t *dup_wcs(const wchar_t *s)\n{\n\tsize_t len = wcslen(s);\n\twchar_t *ret = malloc((len+1)*sizeof(wchar_t));\n\twcscpy(ret, s);\n\n\treturn ret;\n}\n\n\nstatic int make_path(IOHIDDeviceRef device, char *buf, size_t len)\n{\n\tint res;\n\tunsigned short vid, pid;\n\tchar transport[32];\n\n\tbuf[0] = '\\0';\n\n\tres = get_string_property_utf8(\n\t\tdevice, CFSTR(kIOHIDTransportKey),\n\t\ttransport, sizeof(transport));\n\t\n\tif (!res)\n\t\treturn -1;\n\n\tvid = get_vendor_id(device);\n\tpid = get_product_id(device);\n\n\tres = snprintf(buf, len, \"%s_%04hx_%04hx_%p\",\n\t                   transport, vid, pid, device);\n\t\n\t\n\tbuf[len-1] = '\\0';\n\treturn res+1;\n}\n\n/* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */\nstatic int init_hid_manager(void)\n{\n\tIOReturn res;\n\t\n\t/* Initialize all the HID Manager Objects */\n\thid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);\n\tif (hid_mgr) {\n\t\tIOHIDManagerSetDeviceMatching(hid_mgr, NULL);\n\t\tIOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);\n\t\treturn 0;\n\t}\n\t\n\treturn -1;\n}\n\n/* Initialize the IOHIDManager if necessary. This is the public function, and\n   it is safe to call this function repeatedly. Return 0 for success and -1\n   for failure. */\nint HID_API_EXPORT hid_init(void)\n{\n\tif (!hid_mgr) {\n\t\treturn init_hid_manager();\n\t}\n\n\t/* Already initialized. */\n\treturn 0;\n}\n\nint HID_API_EXPORT hid_exit(void)\n{\n\tif (hid_mgr) {\n\t\t/* Close the HID manager. */\n\t\tIOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);\n\t\tCFRelease(hid_mgr);\n\t\thid_mgr = NULL;\n\t}\n\t\t\n\treturn 0;\n}\n\nstatic void process_pending_events() {\n\tSInt32 res;\n\tdo {\n\t\tres = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE);\n\t} while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);\n}\n\nstruct hid_device_info  HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)\n{\n\tstruct hid_device_info *root = NULL; // return object\n\tstruct hid_device_info *cur_dev = NULL;\n\tCFIndex num_devices;\n\tint i;\n\t\n\t/* Set up the HID Manager if it hasn't been done */\n\tif (hid_init() < 0)\n\t\treturn NULL;\n\t\n\t/* give the IOHIDManager a chance to update itself */\n\tprocess_pending_events();\n\n\t/* Get a list of the Devices */\n\tCFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);\n\n\t/* Convert the list into a C array so we can iterate easily. */\t\n\tnum_devices = CFSetGetCount(device_set);\n\tIOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));\n\tCFSetGetValues(device_set, (const void **) device_array);\n\n\t/* Iterate over each device, making an entry for it. */\t\n\tfor (i = 0; i < num_devices; i++) {\n\t\tunsigned short dev_vid;\n\t\tunsigned short dev_pid;\n\t\t#define BUF_LEN 256\n\t\twchar_t buf[BUF_LEN];\n\t\tchar cbuf[BUF_LEN];\n\n\t\tIOHIDDeviceRef dev = device_array[i];\n\n        if (!dev) {\n            continue;\n        }\n\t\tdev_vid = get_vendor_id(dev);\n\t\tdev_pid = get_product_id(dev);\n\n\t\t/* Check the VID/PID against the arguments */\n\t\tif ((vendor_id == 0x0 && product_id == 0x0) ||\n\t\t    (vendor_id == dev_vid && product_id == dev_pid)) {\n\t\t\tstruct hid_device_info *tmp;\n\t\t\tsize_t len;\n\n\t\t    \t/* VID/PID match. Create the record. */\n\t\t\ttmp = malloc(sizeof(struct hid_device_info));\n\t\t\tif (cur_dev) {\n\t\t\t\tcur_dev->next = tmp;\n\t\t\t}\n\t\t\telse {\n\t\t\t\troot = tmp;\n\t\t\t}\n\t\t\tcur_dev = tmp;\n\n\t\t\t// Get the Usage Page and Usage for this device.\n\t\t\tcur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));\n\t\t\tcur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));\n\n\t\t\t/* Fill out the record */\n\t\t\tcur_dev->next = NULL;\n\t\t\tlen = make_path(dev, cbuf, sizeof(cbuf));\n\t\t\tcur_dev->path = strdup(cbuf);\n\n\t\t\t/* Serial Number */\n\t\t\tget_serial_number(dev, buf, BUF_LEN);\n\t\t\tcur_dev->serial_number = dup_wcs(buf);\n\n\t\t\t/* Manufacturer and Product strings */\n\t\t\tget_manufacturer_string(dev, buf, BUF_LEN);\n\t\t\tcur_dev->manufacturer_string = dup_wcs(buf);\n\t\t\tget_product_string(dev, buf, BUF_LEN);\n\t\t\tcur_dev->product_string = dup_wcs(buf);\n\t\t\t\n\t\t\t/* VID/PID */\n\t\t\tcur_dev->vendor_id = dev_vid;\n\t\t\tcur_dev->product_id = dev_pid;\n\n\t\t\t/* Release Number */\n\t\t\tcur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));\n\n\t\t\t/* Interface Number (Unsupported on Mac)*/\n\t\t\tcur_dev->interface_number = -1;\n\t\t}\n\t}\n\t\n\tfree(device_array);\n\tCFRelease(device_set);\n\t\n\treturn root;\n}\n\nvoid  HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)\n{\n\t/* This function is identical to the Linux version. Platform independent. */\n\tstruct hid_device_info *d = devs;\n\twhile (d) {\n\t\tstruct hid_device_info *next = d->next;\n\t\tfree(d->path);\n\t\tfree(d->serial_number);\n\t\tfree(d->manufacturer_string);\n\t\tfree(d->product_string);\n\t\tfree(d);\n\t\td = next;\n\t}\n}\n\nhid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)\n{\n\t/* This function is identical to the Linux version. Platform independent. */\n\tstruct hid_device_info *devs, *cur_dev;\n\tconst char *path_to_open = NULL;\n\thid_device * handle = NULL;\n\t\n\tdevs = hid_enumerate(vendor_id, product_id);\n\tcur_dev = devs;\n\twhile (cur_dev) {\n\t\tif (cur_dev->vendor_id == vendor_id &&\n\t\t    cur_dev->product_id == product_id) {\n\t\t\tif (serial_number) {\n\t\t\t\tif (wcscmp(serial_number, cur_dev->serial_number) == 0) {\n\t\t\t\t\tpath_to_open = cur_dev->path;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tpath_to_open = cur_dev->path;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tcur_dev = cur_dev->next;\n\t}\n\n\tif (path_to_open) {\n\t\t/* Open the device */\n\t\thandle = hid_open_path(path_to_open);\n\t}\n\n\thid_free_enumeration(devs);\n\t\n\treturn handle;\n}\n\nstatic void hid_device_removal_callback(void *context, IOReturn result,\n                                        void *sender, IOHIDDeviceRef dev_ref)\n{\n\t/* Stop the Run Loop for this device. */\n\tpthread_mutex_lock(&device_list_mutex);\n\thid_device *d = device_list;\n\twhile (d) {\n\t\tif (d->device_handle == dev_ref) {\n\t\t\td->disconnected = 1;\n\t\t\tCFRunLoopStop(d->run_loop);\n\t\t}\n\t\t\n\t\td = d->next;\n\t}\n\tpthread_mutex_unlock(&device_list_mutex);\n}\n\n/* The Run Loop calls this function for each input report received.\n   This function puts the data into a linked list to be picked up by\n   hid_read(). */\nstatic void hid_report_callback(void *context, IOReturn result, void *sender,\n                         IOHIDReportType report_type, uint32_t report_id,\n                         uint8_t *report, CFIndex report_length)\n{\n\tstruct input_report *rpt;\n\thid_device *dev = context;\n\n\t/* Make a new Input Report object */\n\trpt = calloc(1, sizeof(struct input_report));\n\trpt->data = calloc(1, report_length);\n\tmemcpy(rpt->data, report, report_length);\n\trpt->len = report_length;\n\trpt->next = NULL;\n\n\t/* Lock this section */\n\tpthread_mutex_lock(&dev->mutex);\n\t\n\t/* Attach the new report object to the end of the list. */\n\tif (dev->input_reports == NULL) {\n\t\t/* The list is empty. Put it at the root. */\n\t\tdev->input_reports = rpt;\n\t}\n\telse {\n\t\t/* Find the end of the list and attach. */\n\t\tstruct input_report *cur = dev->input_reports;\n\t\tint num_queued = 0;\n\t\twhile (cur->next != NULL) {\n\t\t\tcur = cur->next;\n\t\t\tnum_queued++;\n\t\t}\n\t\tcur->next = rpt;\n\n\t\t/* Pop one off if we've reached 30 in the queue. This\n\t\t   way we don't grow forever if the user never reads\n\t\t   anything from the device. */\n\t\tif (num_queued > 30) {\n\t\t\treturn_data(dev, NULL, 0);\n\t\t}\n\t}\n\n\t/* Signal a waiting thread that there is data. */\n\tpthread_cond_signal(&dev->condition);\n\n\t/* Unlock */\n\tpthread_mutex_unlock(&dev->mutex);\n\n}\n\n/* This gets called when the read_thred's run loop gets signaled by\n   hid_close(), and serves to stop the read_thread's run loop. */\nstatic void perform_signal_callback(void *context)\n{\n\thid_device *dev = context;\n\tCFRunLoopStop(dev->run_loop); //TODO: CFRunLoopGetCurrent()\n}\n\nstatic void *read_thread(void *param)\n{\n\thid_device *dev = param;\n\t\n\t/* Move the device's run loop to this thread. */\n\tIOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);\n\n\t/* Create the RunLoopSource which is used to signal the\n\t   event loop to stop when hid_close() is called. */\n\tCFRunLoopSourceContext ctx;\n\tmemset(&ctx, 0, sizeof(ctx));\n\tctx.version = 0;\n\tctx.info = dev;\n\tctx.perform = &perform_signal_callback;\n\tdev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx);\n\tCFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);\n\t\n\t/* Store off the Run Loop so it can be stopped from hid_close()\n\t   and on device disconnection. */\n\tdev->run_loop = CFRunLoopGetCurrent();\n\n\t/* Notify the main thread that the read thread is up and running. */\n\tpthread_barrier_wait(&dev->barrier);\n\n\t/* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input\n\t   reports into the hid_report_callback(). */\n\tSInt32 code;\n\twhile (!dev->shutdown_thread && !dev->disconnected) {\n\t\tcode = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE);\n\t\t/* Return if the device has been disconnected */\n\t\tif (code == kCFRunLoopRunFinished) {\n\t\t\tdev->disconnected = 1;\n\t\t\tbreak;\n\t\t}\n\n\n\t\t/* Break if The Run Loop returns Finished or Stopped. */\n\t\tif (code != kCFRunLoopRunTimedOut &&\n\t\t    code != kCFRunLoopRunHandledSource) {\n\t\t\t/* There was some kind of error. Setting\n\t\t\t   shutdown seems to make sense, but\n\t\t\t   there may be something else more appropriate */\n\t\t\tdev->shutdown_thread = 1;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/* Now that the read thread is stopping, Wake any threads which are\n\t   waiting on data (in hid_read_timeout()). Do this under a mutex to\n\t   make sure that a thread which is about to go to sleep waiting on\n\t   the condition acutally will go to sleep before the condition is\n\t   signaled. */\n\tpthread_mutex_lock(&dev->mutex);\n\tpthread_cond_broadcast(&dev->condition);\n\tpthread_mutex_unlock(&dev->mutex);\n\n\t/* Wait here until hid_close() is called and makes it past\n\t   the call to CFRunLoopWakeUp(). This thread still needs to\n\t   be valid when that function is called on the other thread. */\n\tpthread_barrier_wait(&dev->shutdown_barrier);\n\n\treturn NULL;\n}\n\nhid_device * HID_API_EXPORT hid_open_path(const char *path)\n{\n  \tint i;\n\thid_device *dev = NULL;\n\tCFIndex num_devices;\n\t\n\tdev = new_hid_device();\n\n\t/* Set up the HID Manager if it hasn't been done */\n\tif (hid_init() < 0)\n\t\treturn NULL;\n\n\t/* give the IOHIDManager a chance to update itself */\n\tprocess_pending_events();\n\n\tCFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);\n\t\n\tnum_devices = CFSetGetCount(device_set);\n\tIOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));\n\tCFSetGetValues(device_set, (const void **) device_array);\t\n\tfor (i = 0; i < num_devices; i++) {\n\t\tchar cbuf[BUF_LEN];\n\t\tsize_t len;\n\t\tIOHIDDeviceRef os_dev = device_array[i];\n\t\t\n\t\tlen = make_path(os_dev, cbuf, sizeof(cbuf));\n\t\tif (!strcmp(cbuf, path)) {\n\t\t\t// Matched Paths. Open this Device.\n\t\t\tIOReturn ret = IOHIDDeviceOpen(os_dev, kIOHIDOptionsTypeNone);\n\t\t\tif (ret == kIOReturnSuccess) {\n\t\t\t\tchar str[32];\n\n\t\t\t\tfree(device_array);\n\t\t\t\tCFRetain(os_dev);\n\t\t\t\tCFRelease(device_set);\n\t\t\t\tdev->device_handle = os_dev;\n\t\t\t\t\n\t\t\t\t/* Create the buffers for receiving data */\n\t\t\t\tdev->max_input_report_len = (CFIndex) get_max_report_length(os_dev);\n\t\t\t\tdev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t));\n\t\t\t\t\n\t\t\t\t/* Create the Run Loop Mode for this device.\n\t\t\t\t   printing the reference seems to work. */\n\t\t\t\tsprintf(str, \"HIDAPI_%p\", os_dev);\n\t\t\t\tdev->run_loop_mode = \n\t\t\t\t\tCFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);\n\t\t\t\t\n\t\t\t\t/* Attach the device to a Run Loop */\n\t\t\t\tIOHIDDeviceRegisterInputReportCallback(\n\t\t\t\t\tos_dev, dev->input_report_buf, dev->max_input_report_len,\n\t\t\t\t\t&hid_report_callback, dev);\n\t\t\t\tIOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, hid_device_removal_callback, NULL);\n\t\t\t\t\n\t\t\t\t/* Start the read thread */\n\t\t\t\tpthread_create(&dev->thread, NULL, read_thread, dev);\n\n\t\t\t\t/* Wait here for the read thread to be initialized. */\n\t\t\t\tpthread_barrier_wait(&dev->barrier);\n\t\t\t\t\n\t\t\t\treturn dev;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tgoto return_error;\n\t\t\t}\n\t\t}\n\t}\n\nreturn_error:\n\tfree(device_array);\n\tCFRelease(device_set);\n\tfree_hid_device(dev);\n\treturn NULL;\n}\n\nstatic int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length)\n{\n\tconst unsigned char *data_to_send;\n\tsize_t length_to_send;\n\tIOReturn res;\n\n\t/* Return if the device has been disconnected. */\n   \tif (dev->disconnected)\n   \t\treturn -1;\n\n\tif (data[0] == 0x0) {\n\t\t/* Not using numbered Reports.\n\t\t   Don't send the report number. */\n\t\tdata_to_send = data+1;\n\t\tlength_to_send = length-1;\n\t}\n\telse {\n\t\t/* Using numbered Reports.\n\t\t   Send the Report Number */\n\t\tdata_to_send = data;\n\t\tlength_to_send = length;\n\t}\n\t\n\tif (!dev->disconnected) {\n\t\tres = IOHIDDeviceSetReport(dev->device_handle,\n\t\t\t\t\t   type,\n\t\t\t\t\t   data[0], /* Report ID*/\n\t\t\t\t\t   data_to_send, length_to_send);\n\t\n\t\tif (res == kIOReturnSuccess) {\n\t\t\treturn length;\n\t\t}\n\t\telse\n\t\t\treturn -1;\n\t}\n\t\n\treturn -1;\n}\n\nint HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)\n{\n\treturn set_report(dev, kIOHIDReportTypeOutput, data, length);\n}\n\n/* Helper function, so that this isn't duplicated in hid_read(). */\nstatic int return_data(hid_device *dev, unsigned char *data, size_t length)\n{\n\t/* Copy the data out of the linked list item (rpt) into the\n\t   return buffer (data), and delete the liked list item. */\n\tstruct input_report *rpt = dev->input_reports;\n\tsize_t len = (length < rpt->len)? length: rpt->len;\n\tmemcpy(data, rpt->data, len);\n\tdev->input_reports = rpt->next;\n\tfree(rpt->data);\n\tfree(rpt);\n\treturn len;\n}\n\nstatic int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)\n{\n\twhile (!dev->input_reports) {\n\t\tint res = pthread_cond_wait(cond, mutex);\n\t\tif (res != 0)\n\t\t\treturn res;\n\n\t\t/* A res of 0 means we may have been signaled or it may\n\t\t   be a spurious wakeup. Check to see that there's acutally\n\t\t   data in the queue before returning, and if not, go back\n\t\t   to sleep. See the pthread_cond_timedwait() man page for\n\t\t   details. */\n\t\t\n\t\tif (dev->shutdown_thread || dev->disconnected)\n\t\t\treturn -1;\n\t}\n\t\n\treturn 0;\n}\n\nstatic int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)\n{\n\twhile (!dev->input_reports) {\n\t\tint res = pthread_cond_timedwait(cond, mutex, abstime);\n\t\tif (res != 0)\n\t\t\treturn res;\n\n\t\t/* A res of 0 means we may have been signaled or it may\n\t\t   be a spurious wakeup. Check to see that there's acutally\n\t\t   data in the queue before returning, and if not, go back\n\t\t   to sleep. See the pthread_cond_timedwait() man page for\n\t\t   details. */\n\t\t\n\t\tif (dev->shutdown_thread || dev->disconnected)\n\t\t\treturn -1;\n\t}\n\t\n\treturn 0;\n\n}\n\nint HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)\n{\n\tint bytes_read = -1;\n\n\t/* Lock the access to the report list. */\n\tpthread_mutex_lock(&dev->mutex);\n\t\n\t/* There's an input report queued up. Return it. */\n\tif (dev->input_reports) {\n\t\t/* Return the first one */\n\t\tbytes_read = return_data(dev, data, length);\n\t\tgoto ret;\n\t}\n\n\t/* Return if the device has been disconnected. */\n\tif (dev->disconnected) {\n\t\tbytes_read = -1;\n\t\tgoto ret;\n\t}\n\t\n\tif (dev->shutdown_thread) {\n\t\t/* This means the device has been closed (or there\n\t\t   has been an error. An error code of -1 should\n\t\t   be returned. */\n\t\tbytes_read = -1;\n\t\tgoto ret;\n\t}\n\n\t/* There is no data. Go to sleep and wait for data. */\n\t\n\tif (milliseconds == -1) {\n\t\t/* Blocking */\n\t\tint res;\n\t\tres = cond_wait(dev, &dev->condition, &dev->mutex);\n\t\tif (res == 0)\n\t\t\tbytes_read = return_data(dev, data, length);\n\t\telse {\n\t\t\t/* There was an error, or a device disconnection. */\n\t\t\tbytes_read = -1;\n\t\t}\n\t}\n\telse if (milliseconds > 0) {\n\t\t/* Non-blocking, but called with timeout. */\n\t\tint res;\n\t\tstruct timespec ts;\n\t\tstruct timeval tv;\n\t\tgettimeofday(&tv, NULL);\n\t\tTIMEVAL_TO_TIMESPEC(&tv, &ts);\n\t\tts.tv_sec += milliseconds / 1000;\n\t\tts.tv_nsec += (milliseconds % 1000) * 1000000;\n\t\tif (ts.tv_nsec >= 1000000000L) {\n\t\t\tts.tv_sec++;\n\t\t\tts.tv_nsec -= 1000000000L;\n\t\t}\n\t\t\n\t\tres = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);\n\t\tif (res == 0)\n\t\t\tbytes_read = return_data(dev, data, length);\n\t\telse if (res == ETIMEDOUT)\n\t\t\tbytes_read = 0;\n\t\telse\n\t\t\tbytes_read = -1;\n\t}\n\telse {\n\t\t/* Purely non-blocking */\n\t\tbytes_read = 0;\n\t}\n\nret:\n\t/* Unlock */\n\tpthread_mutex_unlock(&dev->mutex);\n\treturn bytes_read;\n}\n\nint HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)\n{\n\treturn hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);\n}\n\nint HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)\n{\n\t/* All Nonblocking operation is handled by the library. */\n\tdev->blocking = !nonblock;\n\t\n\treturn 0;\n}\n\nint HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)\n{\n\treturn set_report(dev, kIOHIDReportTypeFeature, data, length);\n}\n\nint HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)\n{\n\tCFIndex len = length;\n\tIOReturn res;\n\n\t/* Return if the device has been unplugged. */\n\tif (dev->disconnected)\n\t\treturn -1;\n\n\tres = IOHIDDeviceGetReport(dev->device_handle,\n\t                           kIOHIDReportTypeFeature,\n\t                           data[0], /* Report ID */\n\t                           data, &len);\n\tif (res == kIOReturnSuccess)\n\t\treturn len;\n\telse\n\t\treturn -1;\n}\n\n\nvoid HID_API_EXPORT hid_close(hid_device *dev)\n{\n\tif (!dev)\n\t\treturn;\n\n\t/* Disconnect the report callback before close. */\n\tif (!dev->disconnected) {\n\t\tIOHIDDeviceRegisterInputReportCallback(\n\t\t\tdev->device_handle, dev->input_report_buf, dev->max_input_report_len,\n\t\t\tNULL, dev);\n\t\tIOHIDManagerRegisterDeviceRemovalCallback(hid_mgr, NULL, dev);\n\t\tIOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);\n\t\tIOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);\n\t}\n\t\n\t/* Cause read_thread() to stop. */\n\tdev->shutdown_thread = 1;\n\t\n\t/* Wake up the run thread's event loop so that the thread can exit. */\n\tCFRunLoopSourceSignal(dev->source);\n\tCFRunLoopWakeUp(dev->run_loop);\n\t\n\t/* Notify the read thread that it can shut down now. */\n\tpthread_barrier_wait(&dev->shutdown_barrier);\n\n\t/* Wait for read_thread() to end. */\n\tpthread_join(dev->thread, NULL);\n\n\t/* Close the OS handle to the device, but only if it's not\n\t   been unplugged. If it's been unplugged, then calling\n\t   IOHIDDeviceClose() will crash. */\n\tif (!dev->disconnected) {\n\t\tIOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeNone);\n\t}\n\t\n\t/* Clear out the queue of received reports. */\n\tpthread_mutex_lock(&dev->mutex);\n\twhile (dev->input_reports) {\n\t\treturn_data(dev, NULL, 0);\n\t}\n\tpthread_mutex_unlock(&dev->mutex);\n\tCFRelease(dev->device_handle);\n\n\tfree_hid_device(dev);\n}\n\nint HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)\n{\n\treturn get_manufacturer_string(dev->device_handle, string, maxlen);\n}\n\nint HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)\n{\n\treturn get_product_string(dev->device_handle, string, maxlen);\n}\n\nint HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)\n{\n\treturn get_serial_number(dev->device_handle, string, maxlen);\n}\n\nint HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)\n{\n\t// TODO:\n\n\treturn 0;\n}\n\n\nHID_API_EXPORT const wchar_t * HID_API_CALL  hid_error(hid_device *dev)\n{\n\t// TODO:\n\n\treturn NULL;\n}\n\n\n\n\n\n\n#if 0\nstatic int32_t get_location_id(IOHIDDeviceRef device)\n{\n\treturn get_int_property(device, CFSTR(kIOHIDLocationIDKey));\n}\n\nstatic int32_t get_usage(IOHIDDeviceRef device)\n{\n\tint32_t res;\n\tres = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));\n\tif (!res)\n\t\tres = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));\n\treturn res;\n}\n\nstatic int32_t get_usage_page(IOHIDDeviceRef device)\n{\n\tint32_t res;\n\tres = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));\n\tif (!res)\n\t\tres = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));\n\treturn res;\n}\n\nstatic int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len)\n{\n\treturn get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);\n}\n\n\nint main(void)\n{\n\tIOHIDManagerRef mgr;\n\tint i;\n\t\n\tmgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);\n\tIOHIDManagerSetDeviceMatching(mgr, NULL);\n\tIOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);\n\t\n\tCFSetRef device_set = IOHIDManagerCopyDevices(mgr);\n\t\n\tCFIndex num_devices = CFSetGetCount(device_set);\n\tIOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));\n\tCFSetGetValues(device_set, (const void **) device_array);\n\t\n\tfor (i = 0; i < num_devices; i++) {\n\t\tIOHIDDeviceRef dev = device_array[i];\n\t\tprintf(\"Device: %p\\n\", dev);\n\t\tprintf(\"  %04hx %04hx\\n\", get_vendor_id(dev), get_product_id(dev));\n\n\t\twchar_t serial[256], buf[256];\n\t\tchar cbuf[256];\n\t\tget_serial_number(dev, serial, 256);\n\n\t\t\n\t\tprintf(\"  Serial: %ls\\n\", serial);\n\t\tprintf(\"  Loc: %ld\\n\", get_location_id(dev));\n\t\tget_transport(dev, buf, 256);\n\t\tprintf(\"  Trans: %ls\\n\", buf);\n\t\tmake_path(dev, cbuf, 256);\n\t\tprintf(\"  Path: %s\\n\", cbuf);\n\t\t\n\t}\n\t\n\treturn 0;\n}\n#endif\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/main/java/com/codeminders/hidapi/ClassPathLibraryLoader.java",
    "content": "package com.codeminders.hidapi;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n\npublic class ClassPathLibraryLoader {\n\n    private static final String[] HID_LIB_NAMES = {\n\t        \"/native/linux/libhidapi-jni-64.so\",\n\t        \"/native/linux/libhidapi-jni-32.so\",\n\t        \"/native/mac/libhidapi-jni-64.jnilib\",\n\t        \"/native/mac/libhidapi-jni-32.jnilib\",\n\t        \"/native/win/hidapi-jni-64.dll\",\n\t        \"/native/win/hidapi-jni-32.dll\"\n\t};\n\t  \n\tpublic static boolean loadNativeHIDLibrary()\n        {\n\t\t  boolean isHIDLibLoaded = false;\n\t\t  \n    \t  for(String path : HID_LIB_NAMES)\n          {\n\t\t        try {\n\t\t                // have to use a stream\n\t\t                InputStream in = ClassPathLibraryLoader.class.getResourceAsStream(path);\n\t\t                if (in != null) {\n\t\t                \ttry {\n\t\t\t\t                // always write to different location\n\t\t\t\t                String tempName = path.substring(path.lastIndexOf('/') + 1);\n\t\t\t\t                File fileOut = File.createTempFile(tempName.substring(0, tempName.lastIndexOf('.')), tempName.substring(tempName.lastIndexOf('.'), tempName.length()));\n\t\t\t\t                fileOut.deleteOnExit();\n\t\t\t\t                \n\t\t\t\t                OutputStream out = new FileOutputStream(fileOut);\n\t\t\t\t                byte[] buf = new byte[1024];\n\t\t\t\t                int len;\n\t\t\t\t                while ((len = in.read(buf)) > 0){            \n\t\t\t\t                \tout.write(buf, 0, len);\n\t\t\t\t                }\n\t\t\t\t                \n\t\t\t\t                out.close();\n\t\t\t\t                Runtime.getRuntime().load(fileOut.toString());\n\t\t\t\t                isHIDLibLoaded = true;\n\t\t                \t} finally {\n\t\t                \t\tin.close();\n\t\t                \t}\n\t\t                }\t                \n\t\t        } catch (Exception e) {\n\t\t        \t  // ignore\n\t\t        } catch (UnsatisfiedLinkError e) {\n\t\t        \t  // ignore\n\t\t        }\n\t\t        \n\t\t        if (isHIDLibLoaded) {\n\t\t        \tbreak;\n\t\t        }\n        }\n    \t  \n    \treturn isHIDLibLoaded;  \n    }\n\n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/main/java/com/codeminders/hidapi/HIDAPITest.java",
    "content": "package com.codeminders.hidapi;\n\nimport java.io.IOException;\n\n\n/**\n * This class demonstrates enumeration, reading and getting\n * notifications when a HID device is connected/disconnected.\n */\npublic class HIDAPITest\n{\n    private static final long READ_UPDATE_DELAY_MS = 50L;\n\n    static\n    {\n        System.loadLibrary(\"hidapi-jni\");\n    }\n\n    // \"Afterglow\" controller for PS3\n    static final int VENDOR_ID = 3695;\n    static final int PRODUCT_ID = 25346;\n    private static final int BUFSIZE = 2048;\n        \n    /**\n     * @param args input strings value.\n     */\n    public static void main(String[] args) throws IOException\n    {\n        listDevices();\n        readDevice();\n    }\n    \n    /**\n     * Static function to read an input report to a HID device.\n     */\n    private static void readDevice()\n    {\n        HIDDevice dev;\n        try\n        {\n        \tHIDManager hid_mgr = HIDManager.getInstance();\n            dev = hid_mgr.openById(VENDOR_ID, PRODUCT_ID, null);\n            System.err.print(\"Manufacturer: \" + dev.getManufacturerString() + \"\\n\");\n            System.err.print(\"Product: \" + dev.getProductString() + \"\\n\");\n            System.err.print(\"Serial Number: \" + dev.getSerialNumberString() + \"\\n\");\n            try\n            {\n                byte[] buf = new byte[BUFSIZE];\n                dev.enableBlocking();\n                while(true)\n                {\n                    int n = dev.read(buf);\n                    for(int i=0; i<n; i++)\n                    {\n                        int v = buf[i];\n                        if (v<0) v = v+256;\n                        String hs = Integer.toHexString(v);\n                        if (v<16) \n                            System.err.print(\"0\");\n                        System.err.print(hs + \" \");\n                    }\n                    System.err.println(\"\");\n                    \n                    try\n                    {\n                        Thread.sleep(READ_UPDATE_DELAY_MS);\n                    } catch(InterruptedException e)\n                    {\n                        //Ignore\n                        e.printStackTrace();\n                    }\n                }\n            } finally\n            {\n                dev.close();\n                hid_mgr.release();    \n                System.gc();\n            }\n            \n        } \n        catch(IOException e)\n        {\n            e.printStackTrace();\n        }\n    }\n    \n    /**\n     * Static function to find the list of all the HID devices\n     * attached to the system.\n     */\n    private static void listDevices()\n    {\n        String property = System.getProperty(\"java.library.path\");\n        System.err.println(property);\n        try\n        {\n           \n            HIDManager manager = HIDManager.getInstance();\n            HIDDeviceInfo[] devs = manager.listDevices();\n            System.err.println(\"Devices:\\n\\n\");\n            for(int i=0;i<devs.length;i++)\n            {\n                System.err.println(\"\"+i+\".\\t\"+devs[i]);\n                System.err.println(\"---------------------------------------------\\n\");\n            }\n            System.gc();\n        }\n        catch(IOException e)\n        {\n            System.err.println(e.getMessage());\n            e.printStackTrace();\n        }\n    }\n\n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/main/java/com/codeminders/hidapi/HIDDevice.java",
    "content": "\npackage com.codeminders.hidapi;\n\nimport java.io.IOException;\n\n/**\n * Instance of this class represents an open HID device.\n *\n * @author lord\n */\npublic class HIDDevice\n{\n    protected long peer;\n   \n    /**\n     * Set peer to object.\n     * @param peer a peer value \n     */\n    protected HIDDevice(long peer)\n    {\n        this.peer = peer;\n    }\n    \n    /**\n     * Destructor to destroy the <code>HIDDevice</code> object.\n     * Calls the close() native method.\n     * @throws Throwable\n     */\n    protected void finalize() throws Throwable\n    {\n        // It is important to call close() if user forgot to do so,\n        // since it frees pointer to internal data structure.\n        try\n        {\n           close();\n        } finally\n        {\n           super.finalize();\n        }\n    }\n    \n    /**\n     * Method to compare <code>HIDDevice</code> object instances.\n     * \n     * @param  obj <code>HIDDevice<code> object reference \n     * @return <code>true</code> if the <code>HIDDevice</code> object represent the same value; <code>false</code> otherwise\n     */\n    public boolean equals(Object obj) \n    {\n        if(!(obj instanceof HIDDevice))\n            return false;\n        return ((HIDDevice)obj).peer == peer;\n    }\n   \n    /**\n     * Returns a hash code for this <code>HIDDevice</code> object.\n     * @return a hash code value for this object\n     */\n    public int hashCode()\n    {\n       // Same hash code calculation as in Long\n        return  (int)(peer^(peer>>>32));\n    }\n\n    /**\n     * Close open device. Multiple calls allowed - id device was\n     * already closed no exception will be thrown.\n     * \n     * @throws IOException if error occured opening this device\n     */\n    public native void close() throws IOException;\n   \n    /**\n     * Write an Output Report to a HID device.\n     *\n     * @param data the data to send, including the report number as the first byte\n     * @return the actual number of bytes written\n     * @throws IOException if write error occured\n     */\n    public native int write(byte[] data) throws IOException;\n        \n    /**\n     * Read an Input Report to a HID device.\n     *\n     * @param buf a buffer to put the read data into\n     * @return the actual number of bytes read \n     * @throws IOException if read error occured\n     */\n    public native int read(byte[] buf) throws IOException;\n    \n    /**\n     * Read an Input report from a HID device with timeout.\n     *\n     * @param buf a buffer to put the read data into.\n     * @param milliseconds a timeout in milliseconds or -1 for blocking wait.\n     * @return the number of bytes to read. For devices with\n     * multiple reports, make sure to read an extra byte for\n     * the report number.\n     */\n    public native int readTimeout(byte[] buf, int milliseconds);\n    \n    /** \n     * Enable blocking reads for this <code>HIDDevice</code> object.\n     */\n    public native void enableBlocking() throws IOException;\n    \n    /**\n     * Disable blocking reads for this <code>HIDDevice</code> object.\n     */\n    public native void disableBlocking() throws IOException;\n\n    /**\n     * Send a Feature Report to the HID device.\n     * @param data The data to send, including the report number as the first byte\n     * @return the actual number of bytes written\n     * @throws IOException\n     */\n    public native int sendFeatureReport(byte[] data) throws IOException;\n    \n    /** \n     * Get a Feature Report from a HID device.\n     * @param buf a buffer to put the read data into\n     * @return the actual number of bytes read and  -1 on error\n     * @throws IOException\n     */\n    public native int getFeatureReport(byte[] buf) throws IOException;\n    \n    /**\n     * Get The Manufacturer String from a HID device.\n     * @return the string buffer to put the data into\n     * @throws IOException\n     */\n    public native String getManufacturerString() throws IOException;\n\n    /**\n     * Get The Product String from a HID device.\n     * @return the string buffer to put the data into\n     * @throws IOException\n     */\n    public native String getProductString() throws IOException;\n\n    /** \n     * Get The Serial Number String from a HID device.\n     * @return the string buffer to put the data into\n     * @throws IOException\n     */\n    public native String getSerialNumberString() throws IOException;\n\n    /**\n     * Get a string from a HID device, based on its string index.\n     * @param string_index The index of the string to get.\n     * @return the string buffer to put the data into\n     * @throws IOException\n     */\n    public native String getIndexedString(int string_index) throws IOException;\n    \n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/main/java/com/codeminders/hidapi/HIDDeviceInfo.java",
    "content": "\npackage com.codeminders.hidapi;\n\nimport java.io.IOException;\n\n/**\n * Container class which contains HID device properties.\n *\n * @author lord\n */\npublic class HIDDeviceInfo\n{\n    private String path;\n    private int    vendor_id;\n    private int    product_id;\n    private String serial_number;\n    private int    release_number;\n    private String manufacturer_string;\n    private String product_string;\n    private int    usage_page;\n    private int    usage;\n    private int    interface_number;\n\n    /**\n     * Protected constructor, used from JNI Allocates a new\n     * <code>HIDDeviceInfo<code> object.\n     */\n    HIDDeviceInfo()\n    {\n    }\n    \n    /** \n     * Get the platform-specific device path. \n     * @return the string value\n     */\n    public String getPath()\n    {\n        return path;\n    }\n    \n    /** \n     * Get the device USB vendor ID. \n     * @return integer value\n     */\n    public int getVendor_id()\n    {\n        return vendor_id;\n    }\n    \n    /** \n     * Get the device USB product ID.\n     * @return the integer value\n     */\n    public int getProduct_id()\n    {\n        return product_id;\n    }\n    \n    /** \n     * Get the device serial number.\n     * @return the string value\n     */\n    public String getSerial_number()\n    {\n        return serial_number;\n    }\n    \n    /** \n     * Get the device release number in binary-coded decimal,\n     * also known as device version number. \n     * @return the integer value\n     */\n    public int getRelease_number()\n    {\n        return release_number;\n    }\n    \n    /** \n     * Get the device manufacturer string. \n     * @return the string value\n     */\n    public String getManufacturer_string()\n    {\n        return manufacturer_string;\n    }\n    \n    /** \n     * Get the device product string\n     * @return the integer value\n     */\n    public String getProduct_string()\n    {\n        return product_string;\n    }\n    \n    /** \n     * Get the device usage page (Windows/Mac only).\n     * @return the integer value\n     */\n    public int getUsage_page()\n    {\n        return usage_page;\n    }\n    \n    /** \n     * Get the device usage (Windows/Mac only).\n     * @return the integer value\n     */\n    public int getUsage()\n    {\n        return usage;\n    }\n    \n    /**\n     * Get the USB interface which this logical device\n     * represents. Valid on both Linux implementations in all cases,\n     * and valid on the Windows implementation only if the device\n     * contains more than one interface.\n     * @return the integer value\n     */\n    public int getInterface_number()\n    {\n        return interface_number;\n    }\n    \n    /**\n     *  Open a HID device using a path name from this class.  \n     *  Used from JNI.\n     *\n     * @return return a reference to the <code>HIDDevice<code> object\n     * @throws IOException\n     */\n    public native HIDDevice open() throws IOException;\n    \n    /**\n     *  Override method for conversion this object to <code>String<code> object.\n     *\n     * @return return a reference to the <code>String<code> object\n     */\n    @Override\n    public String toString()\n    {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"HIDDeviceInfo [path=\");\n        builder.append(path);\n        builder.append(\", vendor_id=\");\n        builder.append(vendor_id);\n        builder.append(\", product_id=\");\n        builder.append(product_id);\n        builder.append(\", serial_number=\");\n        builder.append(serial_number);\n        builder.append(\", release_number=\");\n        builder.append(release_number);\n        builder.append(\", manufacturer_string=\");\n        builder.append(manufacturer_string);\n        builder.append(\", product_string=\");\n        builder.append(product_string);\n        builder.append(\", usage_page=\");\n        builder.append(usage_page);\n        builder.append(\", usage=\");\n        builder.append(usage);\n        builder.append(\", interface_number=\");\n        builder.append(interface_number);\n        builder.append(\"]\");\n        return builder.toString();\n    }\n    \n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/main/java/com/codeminders/hidapi/HIDDeviceNotFoundException.java",
    "content": "package com.codeminders.hidapi;\n\nimport java.io.IOException;\n\n/**\n * Thrown if HID Device with given criteria could not be found\n *\n * @author lord\n */\npublic class HIDDeviceNotFoundException extends IOException\n{\n    /**\n     * Constructs a <code>HIDDeviceNotFoundException</code> with no detailed error message.\n     */\n    public HIDDeviceNotFoundException()\n    {\n    }\n    \n    /**\n     * Constructs a <code>HIDDeviceNotFoundException</code> with the specified error message.\n     */\n    public HIDDeviceNotFoundException(String message)\n    {\n        super(message);\n    }\n}"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/main/java/com/codeminders/hidapi/HIDManager.java",
    "content": "\npackage com.codeminders.hidapi;\n\nimport java.io.IOException;\n\n/**\n * HIDManager.java \n * High-level interface to enumerate, find , open HID devices and \n * get connect/disconnect notifications.\n *\n * @version 1.0 \n * @author lord\n * \n */\npublic class HIDManager\n{\n\tstatic {\n\t\t System.loadLibrary(\"hidapi\");\n\t}\n\n\tprivate static HIDManager instance = null;\n\t  \n    protected long peer;\n\n    /**\n     * Get list of all the HID devices attached to the system.\n     *\n     * @return list of devices\n     * @throws IOException\n     */\n    public native HIDDeviceInfo[] listDevices() throws IOException;\n\n    /**\n     * Initializing the underlying HID layer.\n     *\n     * @throws IOException\n     */\n    private native void init() throws IOException;\n\n    /**\n     * Release underlying HID layer. This method must be called when\n     * <code>HIDManager<code> object is no longer needed. Failure to\n     * do so could cause memory leaks or unterminated threads. It is\n     * safe to call this method multiple times.\n     *\n     */\n    public native void release();\n    \n    /**\n     * Constructor to create HID object manager. It must be invoked\n     * from subclass constructor to ensure proper initialization.\n     *\n     * @throws IOException\n     */\n    private HIDManager() throws IOException\n    {\n        init();\n    }\n\n    /**\n     * Release HID manager. Will call release().\n     *\n     * @throws Throwable\n     */\n    protected void finalize() throws Throwable\n    {\n        // It is important to call release() if user forgot to do so,\n        // since it frees pointer internal data structures and stops\n        // thread under MacOS\n        try\n        {\n           release();\n        } finally\n        {\n           super.finalize();\n        }\n    }\n\n    /**\n     * Convenience method to find and open device by path\n     * \n     * @param path USB device path\n     * @return open device reference <code>HIDDevice<code> object\n     * @throws IOException in case of internal error\n     * @throws HIDDeviceNotFoundException if devive was not found\n     */\n    public HIDDevice openByPath(String path) throws IOException, HIDDeviceNotFoundException\n    {\n        HIDDeviceInfo[] devs = listDevices();\n        for(HIDDeviceInfo d : devs)\n        {\n            if(d.getPath().equals(path))\n                return d.open();\n        }\n        throw new HIDDeviceNotFoundException(); \n    }\n\n    /**\n     * Convenience method to open a HID device using a Vendor ID\n     * (VID), Product ID (PID) and optionally a serial number.\n     * \n     * @param vendor_id USB vendor ID\n     * @param product_id USB product ID\n     * @param serial_number USB device serial number (could be <code>null<code>)\n     * @return open device\n     * @throws IOException in case of internal error\n     * @throws HIDDeviceNotFoundException if devive was not found\n     */\n    public HIDDevice openById(int vendor_id, int product_id, String serial_number) throws IOException, HIDDeviceNotFoundException\n    {\n        HIDDeviceInfo[] devs = listDevices();\n        for(HIDDeviceInfo d : devs)\n        {\n            if(d.getVendor_id() == vendor_id && d.getProduct_id() == product_id\n                    && (serial_number == null || d.getSerial_number().equals(serial_number)))\n                return d.open();\n        }\n        throw new HIDDeviceNotFoundException(); \n    }\n\n    public static HIDManager getInstance() throws IOException {\n        if(instance == null) {\n        \tsynchronized (HIDManager.class) {\n        \t\tif (null == instance) {\n        \t\t\tinstance = new HIDManager();\n        \t\t}\n\t\t\t}\n        }\n        return instance;\n     }\n}\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi/src/main/java/com/codeminders/hidapplet/HidApplet.java",
    "content": "package com.codeminders.hidapplet;\n\nimport com.codeminders.hidapi.HIDDeviceInfo;\nimport com.codeminders.hidapi.HIDManager;\n\nimport javax.swing.*;\nimport java.awt.*;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class HidApplet extends JApplet\n{\n    /**\n\t * \n\t */\n\tprivate static final long serialVersionUID = 619732094067421147L;\n\tHIDManager hid_mgr = null;\n    @Override\n    public void init()\n    {\n        String os = System.getProperty(\"os.name\", \"win\").toLowerCase();\n        String arch = System.getProperty(\"os.arch\", \"x86\");\n        boolean x64 = arch.indexOf(\"_64\") != -1;\n        String library;\n        if (os.indexOf(\"win\") != -1)\n        {\n            library = \"hidapi-windows.dll\";\n        } else if (os.indexOf(\"mac\") != -1)\n        {\n            library = \"hidapi-mac.so\";\n        } else\n        {\n            library = \"hidapi-unix.so\";\n        }\n        System.out.println(\"Using library: \" + library);\n        try\n        {\n            InputStream libSrc = Thread.currentThread().getContextClassLoader().getResourceAsStream(\"native/\" + library);\n            if (libSrc == null) {\n                System.err.println(\"No library found\");\n                return;\n            }\n                    \n            File libFile = File.createTempFile(\"hdapi\", \".lib\");\n            System.out.println(\"Copying library to: \" + libFile.getAbsolutePath());\n            \n            byte buf[] = new byte[16384];\n            OutputStream libDest = new FileOutputStream(libFile);\n            int l;\n            while ((l = libSrc.read(buf)) > 0)\n                libDest.write(buf, 0, l);\n            \n            libSrc.close();\n            libDest.close();\n            System.out.println(\"Loading native library\");\n            System.load(libFile.getAbsolutePath());\n            System.out.println(\"Native library loaded\");\n            System.out.println(\"Listing HID devices\");\n            \n            JTextArea results = new JTextArea();\n            results.setEditable(false);\n            results.setEnabled(false);\n            setLayout(new BorderLayout());\n            add(new JScrollPane(results), BorderLayout.CENTER);\n            StringBuilder b = new StringBuilder();\n            hid_mgr = HIDManager.getInstance();\n            for (HIDDeviceInfo info : hid_mgr.listDevices())\n                 b.append(info).append('\\n');\n            results.setText(b.toString());\n        \n        } catch (Exception ex)\n        {\n            ex.printStackTrace();\n        }\n        \n    }\n    public void destroy() {\n        if(null!=hid_mgr)\n            hid_mgr.release();\n    }\n} \n\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi.aarch64/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n\t\t\n\t\t<h3>Third Party Content</h3>\n\t\t<p>The Content includes items that have been sourced from third parties as set out below. If you \n\t\tdid not receive this Content directly from the Eclipse Foundation, the following is provided \n\t\tfor informational purposes only, and you should look to the Redistributor's license for \n\t\tterms and conditions of use.</p>\n\t\t<p><em>\n\t\t<strong>com.codeminders.hidapi_1.1.0.jar</strong> <br/><br/>\n\t\tNew BSD license\n\t\t</em></p>\n\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi.aarch64/about_files/LICENSE-bsd.txt",
    "content": "Copyright (c) 2010, Alan Ott, Signal 11 Software\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Signal 11 Software nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi.aarch64/build.properties",
    "content": "source.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               src/main/lib/\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi.aarch64/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n  \n    Contributors:\n     Eurotech\n     Cavium\n\n-->\n\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n    xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>com.codeminders.hidapi-parent</artifactId>\n        <version>2.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>com.codeminders.hidapi.aarch64</artifactId>\n    <packaging>bundle</packaging>\n\n    <name>Native libraries for 'com.codeminders.hidapi' on ARM 64 bits</name>\n\n    <licenses>\n        <license>\n            <name>New BSD License</name>\n            <url>http://opensource.org/licenses/BSD-3-Clause</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n    <scm>\n        <connection>scm:hg:http://code.google.com/p/javahidapi</connection>\n        <developerConnection>scm:hg:https://code.google.com/p/javahidapi</developerConnection>\n        <url>http://code.google.com/p/javahidapi</url>\n    </scm>\n    <developers>\n        <developer>\n            <id>lord</id>\n            <name>Vadim Zaliva</name>\n            <email>lord@codeminders.com</email>\n        </developer>\n        <developer>\n            <id>Alexander Sova</id>\n            <name>Vadim Zaliva</name>\n            <email>bird@codeminders.com</email>\n        </developer>\n        <developer>\n            <id>dshmyga</id>\n            <name>Denis Shmyga</name>\n            <email>dshmyga@codeminders.com</email>\n        </developer>\n    </developers>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>${maven-surefire-plugin.version}</version>\n                <configuration>\n                    <systemPropertyVariables>\n                        <java.library.path>${project.basedir}/src/main/lib/linux</java.library.path>\n                    </systemPropertyVariables>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>${maven-bundle-plugin.version}</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Include-Resource>\n                            lib=${project.basedir}/src/main/lib/linux,\n                            ${project.basedir}/about.html,\n                            about_files=${project.basedir}/about_files/\n                        </Include-Resource>\n                        <Bundle-NativeCode>\n                            lib/libhidapi.so; osname=Linux; processor=AARCH64\n                        </Bundle-NativeCode>\n                        <Fragment-Host>com.codeminders.hidapi;bundle-version=\"[2.0.0,3.0.0)\"</Fragment-Host>\n                    </instructions>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>${maven-dependency-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n        </plugins>\n        <pluginManagement>\n            <plugins>\n                <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>${lifecycle-mapping.version}</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.apache.maven.plugins\n                                        </groupId>\n                                        <artifactId>\n                                            maven-dependency-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [2.1,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>\n                                                copy-dependencies\n                                            </goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi.x86_64/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n\t\t\n\t\t<h3>Third Party Content</h3>\n\t\t<p>The Content includes items that have been sourced from third parties as set out below. If you \n\t\tdid not receive this Content directly from the Eclipse Foundation, the following is provided \n\t\tfor informational purposes only, and you should look to the Redistributor's license for \n\t\tterms and conditions of use.</p>\n\t\t<p><em>\n\t\t<strong>com.codeminders.hidapi_1.1.0.jar</strong> <br/><br/>\n\t\tNew BSD license\n\t\t</em></p>\n\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi.x86_64/about_files/LICENSE-bsd.txt",
    "content": "Copyright (c) 2010, Alan Ott, Signal 11 Software\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright notice,\n      this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of Signal 11 Software nor the names of its\n      contributors may be used to endorse or promote products derived from\n      this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi.x86_64/build.properties",
    "content": "source.. = src/main/java/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               src/main/lib/\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/com.codeminders.hidapi.x86_64/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n  \n    Contributors:\n     Eurotech\n \n-->\n\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\"\n    xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>com.codeminders.hidapi-parent</artifactId>\n        <version>2.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>com.codeminders.hidapi.x86_64</artifactId>\n    <packaging>bundle</packaging>\n\n    <name>Native libraries for 'com.codeminders.hidapi' on x86_64</name>\n\n    <licenses>\n        <license>\n            <name>New BSD License</name>\n            <url>http://opensource.org/licenses/BSD-3-Clause</url>\n            <distribution>repo</distribution>\n        </license>\n    </licenses>\n    <scm>\n        <connection>scm:hg:http://code.google.com/p/javahidapi</connection>\n        <developerConnection>scm:hg:https://code.google.com/p/javahidapi</developerConnection>\n        <url>http://code.google.com/p/javahidapi</url>\n    </scm>\n    <developers>\n        <developer>\n            <id>lord</id>\n            <name>Vadim Zaliva</name>\n            <email>lord@codeminders.com</email>\n        </developer>\n        <developer>\n            <id>Alexander Sova</id>\n            <name>Vadim Zaliva</name>\n            <email>bird@codeminders.com</email>\n        </developer>\n        <developer>\n            <id>dshmyga</id>\n            <name>Denis Shmyga</name>\n            <email>dshmyga@codeminders.com</email>\n        </developer>\n    </developers>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>${maven-surefire-plugin.version}</version>\n                <configuration>\n                    <systemPropertyVariables>\n                        <java.library.path>${project.basedir}/src/main/lib/linux</java.library.path>\n                    </systemPropertyVariables>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>${maven-bundle-plugin.version}</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Include-Resource>\n                            lib=${project.basedir}/src/main/lib/linux,\n                            ${project.basedir}/about.html,\n                            about_files=${project.basedir}/about_files/\n                        </Include-Resource>\n                        <Bundle-NativeCode>\n                            lib/libhidapi.so; osname=Linux; processor=x86-64\n                        </Bundle-NativeCode>\n                        <Fragment-Host>com.codeminders.hidapi;bundle-version=\"[2.0.0,3.0.0)\"</Fragment-Host>\n                    </instructions>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>${maven-dependency-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n        </plugins>\n        <pluginManagement>\n            <plugins>\n                <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>${lifecycle-mapping.version}</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.apache.maven.plugins\n                                        </groupId>\n                                        <artifactId>\n                                            maven-dependency-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [2.1,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>\n                                                copy-dependencies\n                                            </goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/com.codeminders.hidapi-parent/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n  \n    Contributors:\n     Eurotech\n     Cavium\n\n-->\n\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>target-platform</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n        <relativePath>..</relativePath>\n    </parent>\n\n    <artifactId>com.codeminders.hidapi-parent</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>pom</packaging>\n\n    <modules>\n        <module>com.codeminders.hidapi</module>\n        <module>com.codeminders.hidapi.x86_64</module>\n        <module>com.codeminders.hidapi.aarch64</module>\n    </modules>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <build>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.apache.felix</groupId>\n                    <artifactId>maven-bundle-plugin</artifactId>\n                    <version>${maven-bundle-plugin.version}</version>\n                    <extensions>true</extensions>\n                    <configuration>\n                        <instructions>\n                            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                            <Require-Capability>\n                                osgi.ee;filter:=\"(&amp;(osgi.ee=JavaSE)(version=21))\"\n                            </Require-Capability>\n                        </instructions>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n\n        <plugins>\n        \t<plugin>\n         \t\t<groupId>org.apache.maven.plugins</groupId>\n         \t\t<artifactId>maven-checkstyle-plugin</artifactId>\n                <version>${maven-checkstyle-plugin.version}</version>\n         \t\t<configuration>\n         \t\t\t<skip>true</skip>\n         \t\t</configuration>\n         \t</plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>${maven-compiler-plugin.version}</version>\n                <configuration>\n                    <release>${maven.compiler.release}</release>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "target-platform/log4j2-api-config/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n\t\t\n\t\t<h3>Third Party Content</h3>\n\t\t<p>The Content includes items that have been sourced from third parties as set out below. If you \n\t\tdid not receive this Content directly from the Eclipse Foundation, the following is provided \n\t\tfor informational purposes only, and you should look to the Redistributor's license for \n\t\tterms and conditions of use.</p>\n\t\t<p><em>\n\t\t<strong>log4j-provider.properties</strong> <br/><br/>\n\t\t<a href=\"https://www.apache.org/licenses/LICENSE-2.0.html\">Apache 2.0 License</a>\n\t\t</em></p>\n\n\n</body>\n</html>\n"
  },
  {
    "path": "target-platform/log4j2-api-config/log4j-provider.properties",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one or more\n# contributor license agreements.  See the NOTICE file distributed with\n# this work for additional information regarding copyright ownership.\n# The ASF licenses this file to You under the Apache License, Version 2.0\n# (the \"License\"); you may not use this file except in compliance with\n# the License.  You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nLoggerContextFactory = org.apache.logging.log4j.core.impl.Log4jContextFactory\nLog4jAPIVersion = 2.23.1\nFactoryPriority= 10\n"
  },
  {
    "path": "target-platform/log4j2-api-config/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <artifactId>log4j2-api-config</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>bundle</packaging>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>target-platform</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <version>${maven-checkstyle-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>checkstyle-validation</id>\n                        <phase>process-sources</phase>\n                        <configuration>\n                            <skip>true</skip>\n                        </configuration>\n                        <goals>\n                            <goal>check</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>${maven-bundle-plugin.version}</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Name>${project.artifactId}</Bundle-Name>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Fragment-Host>org.apache.logging.log4j.api</Fragment-Host>\n                        <DynamicImport-Package>\n                            *;resolution:=optional\n                        </DynamicImport-Package>\n                        <Require-Capability>\n                            osgi.ee;filter:=\"(&amp;(osgi.ee=JavaSE)(version=21))\"\n                        </Require-Capability>\n                    </instructions>\n                </configuration>\n            </plugin>\n        </plugins>\n        <resources>\n            <resource>\n                <directory>./</directory>\n                <includes>\n                    <include>log4j-provider.properties</include>\n                </includes>\n                <targetPath>META-INF</targetPath>\n            </resource>\n            <resource>\n                <directory>./</directory>\n                <includes>\n                    <include>about.html</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/org.eclipse.kura.camel.sun.misc/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "target-platform/org.eclipse.kura.camel.sun.misc/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!-- \n  Copyright (c) 2016, 2024 Red Hat Inc and others\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n \n  Contributors:\n      Red Hat Inc\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t\n\t<parent>\n\t\t<groupId>org.eclipse.kura</groupId>\n\t\t<artifactId>target-platform</artifactId>\n\t\t<version>6.0.0-SNAPSHOT</version>\n\t\t<relativePath>..</relativePath>\n\t</parent>\n\t\n\t<artifactId>org.eclipse.kura.camel.sun.misc</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\t\n\t<name>Camel :: Core :: Import sun.misc</name>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>3.0.0</version><!-- must stay below 3.0.1 due to an issue with m2eclipse -->\n\t\t\t\t<configuration>\n\t\t\t\t\t<forceCreation>true</forceCreation>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Import-Package>sun.misc</Import-Package>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.felix</groupId>\n\t\t\t\t<artifactId>maven-bundle-plugin</artifactId>\n\t\t\t\t<version>${maven-bundle-plugin.version}</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>bundle-manifest</id>\n\t\t\t\t\t\t<phase>process-classes</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>manifest</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<instructions>\n\t\t\t\t\t\t<Fragment-Host>org.apache.camel.camel-core;bundle-version=\"[2.16.0,2.26.0)\"</Fragment-Host>>\n\t\t\t\t\t\t<Require-Capability>\n\t\t\t\t\t\t\tosgi.ee;filter:=\"(&amp;(osgi.ee=JavaSE)(version=21))\"\n\t\t\t\t\t\t</Require-Capability>\n\t\t\t\t\t</instructions>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>${maven-compiler-plugin.version}</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<release>${maven.compiler.release}</release>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<version>${maven-deploy-plugin.version}</version>\n\t\t\t\t<configuration>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n</project>\n"
  },
  {
    "path": "target-platform/org.eclipse.kura.camel.sun.misc/src/main/resources/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/org.eclipse.kura.sun.misc/.gitignore",
    "content": "/bin/\n"
  },
  {
    "path": "target-platform/org.eclipse.kura.sun.misc/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Copyright (c) 2016, 2024 Red Hat Inc\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n      Jens Reimann <jreimann@redhat.com> - Initial file\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t\n\t<parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>target-platform</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n\t<groupId>org.eclipse.kura</groupId>\n\t<artifactId>org.eclipse.kura.sun.misc</artifactId>\n\t<version>2.0.0-SNAPSHOT</version>\n\t<packaging>jar</packaging>\n\n\t<name>System extension fragment for 'sun.misc'</name>\n\n\t<properties>\n\t\t<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n\t</properties>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<version>3.0.0</version><!-- must stay below 3.0.1 due to an issue with m2eclipse -->\n\t\t\t\t<configuration>\n\t\t\t\t\t<forceCreation>true</forceCreation>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>\n\t\t\t\t\t\t<manifestEntries>\n\t\t\t\t\t\t\t<Export-Package>sun.misc, com.sun</Export-Package>\n\t\t\t\t\t\t</manifestEntries>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.felix</groupId>\n\t\t\t\t<artifactId>maven-bundle-plugin</artifactId>\n\t\t\t\t<version>${maven-bundle-plugin.version}</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>bundle-manifest</id>\n\t\t\t\t\t\t<phase>process-classes</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>manifest</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t\t<configuration>\n\t\t\t\t\t<instructions>\n\t\t\t\t\t\t<Fragment-Host>system.bundle; extension:=framework</Fragment-Host>\n\t\t\t\t\t\t<Bundle-Vendor>Eclipse Kura</Bundle-Vendor>\n\t\t\t\t\t\t<Require-Capability>\n              osgi.ee;filter:=\"(&amp;(osgi.ee=JavaSE)(version=21))\"\n            </Require-Capability>\n\t\t\t\t\t</instructions>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>${maven-compiler-plugin.version}</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>${maven.compiler.source}</source>\n\t\t\t\t\t<target>${maven.compiler.target}</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-deploy-plugin</artifactId>\n\t\t\t\t<version>${maven-deploy-plugin.version}</version>\n\t\t\t\t<configuration>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\n</project>\n"
  },
  {
    "path": "target-platform/org.eclipse.kura.sun.misc/src/main/resources/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/OSGI-INF/l10n/bundle.properties",
    "content": "#########################################################################\n# Copyright (c) 2007, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nbundle.copyright=Copyright (c) 2007, 2009 IBM.\nbundle.description=Comm\nbundle.name=Comm (Incubation)\nbundle.vendor=Eclipse.org\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/OSGI-INF/l10n/bundle_en.properties",
    "content": "#########################################################################\n# Copyright (c) 2007, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nbundle.copyright=Copyright (c) 2007, 2009 IBM.\nbundle.description=Comm\nbundle.name=Comm (Incubation)\nbundle.vendor=Eclipse.org\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/TooManyListenersException.java",
    "content": "\npackage java.util;\n\n/*\n * Licensed Materials - Property of IBM,\n * (c) Copyright IBM Corp. 1998, 2002  All Rights Reserved\n */\n\n/**\n * This exception is thrown when an attempt is made to add\n * more than one listener to an event source which only\n * supports a single listener. It is also thrown when the\n * same listener is added more than once.\n *\n * @author\t\tOTI\n * @version\t\tinitial\n *\n * @see\t\tjava.lang.Exception\n */\npublic class TooManyListenersException extends Exception {\n\n\tstatic final long serialVersionUID = 5074640544770687831L;\n\n/**\n * Constructs a new instance of this class with its\n * walkback filled in.\n *\n * @author\t\tOTI\n * @version\t\tinitial\n */\npublic TooManyListenersException () {\n\tsuper();\n}\n\n/**\n * Constructs a new instance of this class with its\n * walkback and message filled in.\n *\n * @author\t\tOTI\n * @version\t\tinitial\n *\n * @param\t\tdetailMessage String\n *\t\t\t\tThe detail message for the exception.\n */\npublic TooManyListenersException (String detailMessage) {\n\tsuper(detailMessage);\n}\n\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/about_files/epl-v10.html",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n<title>Eclipse Public License - Version 1.0</title>\n<style type=\"text/css\">\n  body {\n    size: 8.5in 11.0in;\n    margin: 0.25in 0.5in 0.25in 0.5in;\n    tab-interval: 0.5in;\n    }\n  p {  \t\n    margin-left: auto;\n    margin-top:  0.5em;\n    margin-bottom: 0.5em;\n    }\n  p.list {\n  \tmargin-left: 0.5in;\n    margin-top:  0.05em;\n    margin-bottom: 0.05em;\n    }\n  </style>\n\n</head>\n\n<body lang=\"EN-US\">\n\n<h2>Eclipse Public License - v 1.0</h2>\n\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\nPUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR\nDISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS\nAGREEMENT.</p>\n\n<p><b>1. DEFINITIONS</b></p>\n\n<p>&quot;Contribution&quot; means:</p>\n\n<p class=\"list\">a) in the case of the initial Contributor, the initial\ncode and documentation distributed under this Agreement, and</p>\n<p class=\"list\">b) in the case of each subsequent Contributor:</p>\n<p class=\"list\">i) changes to the Program, and</p>\n<p class=\"list\">ii) additions to the Program;</p>\n<p class=\"list\">where such changes and/or additions to the Program\noriginate from and are distributed by that particular Contributor. A\nContribution 'originates' from a Contributor if it was added to the\nProgram by such Contributor itself or anyone acting on such\nContributor's behalf. Contributions do not include additions to the\nProgram which: (i) are separate modules of software distributed in\nconjunction with the Program under their own license agreement, and (ii)\nare not derivative works of the Program.</p>\n\n<p>&quot;Contributor&quot; means any person or entity that distributes\nthe Program.</p>\n\n<p>&quot;Licensed Patents&quot; mean patent claims licensable by a\nContributor which are necessarily infringed by the use or sale of its\nContribution alone or when combined with the Program.</p>\n\n<p>&quot;Program&quot; means the Contributions distributed in accordance\nwith this Agreement.</p>\n\n<p>&quot;Recipient&quot; means anyone who receives the Program under\nthis Agreement, including all Contributors.</p>\n\n<p><b>2. GRANT OF RIGHTS</b></p>\n\n<p class=\"list\">a) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free copyright license to reproduce, prepare derivative works\nof, publicly display, publicly perform, distribute and sublicense the\nContribution of such Contributor, if any, and such derivative works, in\nsource code and object code form.</p>\n\n<p class=\"list\">b) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free patent license under Licensed Patents to make, use, sell,\noffer to sell, import and otherwise transfer the Contribution of such\nContributor, if any, in source code and object code form. This patent\nlicense shall apply to the combination of the Contribution and the\nProgram if, at the time the Contribution is added by the Contributor,\nsuch addition of the Contribution causes such combination to be covered\nby the Licensed Patents. The patent license shall not apply to any other\ncombinations which include the Contribution. No hardware per se is\nlicensed hereunder.</p>\n\n<p class=\"list\">c) Recipient understands that although each Contributor\ngrants the licenses to its Contributions set forth herein, no assurances\nare provided by any Contributor that the Program does not infringe the\npatent or other intellectual property rights of any other entity. Each\nContributor disclaims any liability to Recipient for claims brought by\nany other entity based on infringement of intellectual property rights\nor otherwise. As a condition to exercising the rights and licenses\ngranted hereunder, each Recipient hereby assumes sole responsibility to\nsecure any other intellectual property rights needed, if any. For\nexample, if a third party patent license is required to allow Recipient\nto distribute the Program, it is Recipient's responsibility to acquire\nthat license before distributing the Program.</p>\n\n<p class=\"list\">d) Each Contributor represents that to its knowledge it\nhas sufficient copyright rights in its Contribution, if any, to grant\nthe copyright license set forth in this Agreement.</p>\n\n<p><b>3. REQUIREMENTS</b></p>\n\n<p>A Contributor may choose to distribute the Program in object code\nform under its own license agreement, provided that:</p>\n\n<p class=\"list\">a) it complies with the terms and conditions of this\nAgreement; and</p>\n\n<p class=\"list\">b) its license agreement:</p>\n\n<p class=\"list\">i) effectively disclaims on behalf of all Contributors\nall warranties and conditions, express and implied, including warranties\nor conditions of title and non-infringement, and implied warranties or\nconditions of merchantability and fitness for a particular purpose;</p>\n\n<p class=\"list\">ii) effectively excludes on behalf of all Contributors\nall liability for damages, including direct, indirect, special,\nincidental and consequential damages, such as lost profits;</p>\n\n<p class=\"list\">iii) states that any provisions which differ from this\nAgreement are offered by that Contributor alone and not by any other\nparty; and</p>\n\n<p class=\"list\">iv) states that source code for the Program is available\nfrom such Contributor, and informs licensees how to obtain it in a\nreasonable manner on or through a medium customarily used for software\nexchange.</p>\n\n<p>When the Program is made available in source code form:</p>\n\n<p class=\"list\">a) it must be made available under this Agreement; and</p>\n\n<p class=\"list\">b) a copy of this Agreement must be included with each\ncopy of the Program.</p>\n\n<p>Contributors may not remove or alter any copyright notices contained\nwithin the Program.</p>\n\n<p>Each Contributor must identify itself as the originator of its\nContribution, if any, in a manner that reasonably allows subsequent\nRecipients to identify the originator of the Contribution.</p>\n\n<p><b>4. COMMERCIAL DISTRIBUTION</b></p>\n\n<p>Commercial distributors of software may accept certain\nresponsibilities with respect to end users, business partners and the\nlike. While this license is intended to facilitate the commercial use of\nthe Program, the Contributor who includes the Program in a commercial\nproduct offering should do so in a manner which does not create\npotential liability for other Contributors. Therefore, if a Contributor\nincludes the Program in a commercial product offering, such Contributor\n(&quot;Commercial Contributor&quot;) hereby agrees to defend and\nindemnify every other Contributor (&quot;Indemnified Contributor&quot;)\nagainst any losses, damages and costs (collectively &quot;Losses&quot;)\narising from claims, lawsuits and other legal actions brought by a third\nparty against the Indemnified Contributor to the extent caused by the\nacts or omissions of such Commercial Contributor in connection with its\ndistribution of the Program in a commercial product offering. The\nobligations in this section do not apply to any claims or Losses\nrelating to any actual or alleged intellectual property infringement. In\norder to qualify, an Indemnified Contributor must: a) promptly notify\nthe Commercial Contributor in writing of such claim, and b) allow the\nCommercial Contributor to control, and cooperate with the Commercial\nContributor in, the defense and any related settlement negotiations. The\nIndemnified Contributor may participate in any such claim at its own\nexpense.</p>\n\n<p>For example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those\nperformance claims and warranties, and if a court requires any other\nContributor to pay any damages as a result, the Commercial Contributor\nmust pay those damages.</p>\n\n<p><b>5. NO WARRANTY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS\nPROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS\nOF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,\nANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY\nOR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely\nresponsible for determining the appropriateness of using and\ndistributing the Program and assumes all risks associated with its\nexercise of rights under this Agreement , including but not limited to\nthe risks and costs of program errors, compliance with applicable laws,\ndamage to or loss of data, programs or equipment, and unavailability or\ninterruption of operations.</p>\n\n<p><b>6. DISCLAIMER OF LIABILITY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT\nNOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING\nWITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR\nDISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED\nHEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>\n\n<p><b>7. GENERAL</b></p>\n\n<p>If any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further action\nby the parties hereto, such provision shall be reformed to the minimum\nextent necessary to make such provision valid and enforceable.</p>\n\n<p>If Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other\nsoftware or hardware) infringes such Recipient's patent(s), then such\nRecipient's rights granted under Section 2(b) shall terminate as of the\ndate such litigation is filed.</p>\n\n<p>All Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of time\nafter becoming aware of such noncompliance. If all Recipient's rights\nunder this Agreement terminate, Recipient agrees to cease use and\ndistribution of the Program as soon as reasonably practicable. However,\nRecipient's obligations under this Agreement and any licenses granted by\nRecipient relating to the Program shall continue and survive.</p>\n\n<p>Everyone is permitted to copy and distribute copies of this\nAgreement, but in order to avoid inconsistency the Agreement is\ncopyrighted and may only be modified in the following manner. The\nAgreement Steward reserves the right to publish new versions (including\nrevisions) of this Agreement from time to time. No one other than the\nAgreement Steward has the right to modify this Agreement. The Eclipse\nFoundation is the initial Agreement Steward. The Eclipse Foundation may\nassign the responsibility to serve as the Agreement Steward to a\nsuitable separate entity. Each new version of the Agreement will be\ngiven a distinguishing version number. The Program (including\nContributions) may always be distributed subject to the version of the\nAgreement under which it was received. In addition, after a new version\nof the Agreement is published, Contributor may elect to distribute the\nProgram (including its Contributions) under the new version. Except as\nexpressly stated in Sections 2(a) and 2(b) above, Recipient receives no\nrights or licenses to the intellectual property of any Contributor under\nthis Agreement, whether expressly, by implication, estoppel or\notherwise. All rights in the Program not expressly granted under this\nAgreement are reserved.</p>\n\n<p>This Agreement is governed by the laws of the State of New York and\nthe intellectual property laws of the United States of America. No party\nto this Agreement will bring a legal action under this Agreement more\nthan one year after the cause of action arose. Each party waives its\nrights to a jury trial in any resulting litigation.</p>\n\n</body>\n\n</html>"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/build.properties",
    "content": "#########################################################################\n# Copyright (c) 2006, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nadditional.bundles=org.eclipse.osgi,org.eclipse.osgi.services\nbin.includes=.,META-INF/,copyright.txt,lib/,OSGI-INF/,OSGI-INF/l10n/,about.html\noutput..=bin/\nsource..=src/\nsrc.includes=copyright.txt\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/build_native.sh",
    "content": "#!/bin/bash\n#\n# This script is used to build the KURA Native DLLs on Windows based systems. It relies on\n# mingw64 to do the build. If mingw64 is not installed it skips the build without error so that the pre built binary will be used\n#\n# It's called with one of two arguments 'clean' in which case the object files are deleted, or 'build' in which case the files are\n# rebuilt. Take care here to make sure that the required build tools are installed, i686-w64-mingw32-gcc for the 32 bit version\n# and x86_64-w64-mingw32-gcc for the 64 bit version. These should all be installed with the mingw64 package.\n\n#==============================================================================================================================\n# First check to see what make we have, if it's Windows it will probably be mingw32-make, if it's Linux it's probably just make\n# either way set the MAKECMD variable accordingly. If we can't find either issue an warning message and exit the script with\n# code 0. This will stop maven from showing an error but will leave the pre built binary in place.\n#\nif [ -x \"$(command -v mingw32-make)\" ] || [ -x \"$(command -v make)\" ]; then\n\tif [ -x \"$(command -v make)\" ]; then\n\t\tMAKECMD=\"make\"\n\telse\n\t\tMAKECMD=\"mingw32-make\"\n\tfi\nelse\n\techo \"  WARNING: No viable 'make' command installed. SODA.DK.COMM Native will not be rebuilt\"\n\texit 0\nfi\n\n#===============================================================================================================================\n# If the argument is 'clean' just work through all the files in the Objs directory and delete them.\n#\nif [ \"$1\" == \"clean\" ]; then\n\tfor f in src/main/c/Objs/x86*; do\n\t\tif [ -f \"$f\" ]; then\n\t\t\techo Deleting $f\n\t\t\trm $f\n\t\tfi\n\tdone\n\tfor f in src/main/c/Objs/x64*; do\n\t\tif [ -f \"$f\" ]; then\n\t\t\techo Deleting $f\n\t\t\trm $f\n\t\tfi\n\tdone\nfi\n\n#===============================================================================================================================\n# If the argument is 'build' change to the source directory, create the Objs and Release directories if required, then check to\n# see if we have viable 32 bit compiler if so call make with the 32 bit target. Next check for 64 bit compiler and run make with\n# the 64 bit target. If the compilers are not found just issue a warning and continue without doing anything. This will leave the\n# pre built binaries in the Release directory to be used in the final installer. This should mean that you get a working installer\n# even if you don't have mingw installed\n#\nif [ \"$1\" == \"build\" ]; then\n\t\t\n\t\tcd src/main/c\n\t\tif [ ! -d Objs/x86 ]; then\n\t\t\tmkdir Objs/x86\n\t\tfi\n\n\t\tif [ ! -d Objs/x64 ]; then\n\t\t\tmkdir Objs/x64\n\t\tfi\n\n\t\tif [ ! -d Release/win32/x86 ]; then\n\t\t\tmkdir -p Release/win32/x86\n\t\tfi\n\n\t\tif [ ! -d Release/win32/x64 ]; then\n\t\t\tmkdir -p Release/win32/x64\n\t\tfi\n\n\t\tif [ -x \"$(command -v i686-w64-mingw32-gcc)\" ]; then\n\t\t\t$MAKECMD SodaDkComm32\n\t\telse\n\t\t\techo \"  WARNING: No viable 32 bit 'mingw' compiler installed. 32 bit SODA.DK.COMM Native will not be rebuilt\"\n\t\tfi\n\n\t\tif [ -x \"$(command -v x86_64-w64-mingw32-gcc)\" ]; then\n\t\t\t$MAKECMD SodaDkComm64\n\t\telse\n\t\t\techo \"  WARNING: No viable 64 bit 'mingw' compiler installed. 64 bit SODA.DK.COMM Native will not be rebuilt\"\n\t\tfi\nfi\n\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/copyright.txt",
    "content": "Copyright (c) 1999, 2009 IBM.\nAll rights reserved. This program and the accompanying materials\nare made available under the terms of the Eclipse Public License v1.0\nwhich accompanies this distribution, and is available at\nhttp://www.eclipse.org/legal/epl-v10.html\n\nContributors:\n    IBM - initial API and implementation"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\n    Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n  \n    Contributors:\n     Eurotech\n \n-->\n\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>org.eclipse.soda.dk.comm-parent</artifactId>\n        <version>2.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.soda.dk.comm</artifactId>\n    <packaging>bundle</packaging>\n\n    <name>Serial Device based on SODA DK comm</name>\n    <description>An implementation of the serialdevice.api, based on SODA DK comm</description>\n\n    <dependencies>\n        <dependency>\n\t\t\t<groupId>org.eclipse.platform</groupId>\n\t\t\t<artifactId>org.eclipse.osgi</artifactId>\n\t\t</dependency>\n    </dependencies>\n\n    <build>\n        <resources>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>.</directory>\n                <includes>\n                    <include>plugin.xml</include>\n                </includes>\n            </resource>\n        </resources>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>${maven-bundle-plugin.version}</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Bundle-Activator>org.eclipse.soda.dk.comm.bundle.Activator</Bundle-Activator>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Name>%bundle.name</Bundle-Name>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Bundle-Localization>OSGI-INF/l10n/bundle</Bundle-Localization>\n                        <Bundle-Vendor>%bundle.vendor</Bundle-Vendor>\n                        <Bundle-Copyright>%bundle.copyright</Bundle-Copyright>\n                        <Include-Resource>\n                            ${project.basedir}/about.html,\n                            OSGI-INF=${project.basedir}/OSGI-INF,\n                            about_files=${project.basedir}/about_files/\n                        </Include-Resource>\n                        <Import-Package>\n                            org.osgi.framework;version=\"[1.5.0,2.0.0)\"\n                        </Import-Package>\n                        <Export-Package>\n                            javax.comm;version=\"1.2.0\",\n                            org.eclipse.soda.dk.comm;version=\"1.2.0\",\n                            org.eclipse.soda.dk.comm.bundle;version=\"1.2.0\",\n                            org.eclipse.soda.dk.comm.internal;version=\"1.2.0\"\n                        </Export-Package>\n                    </instructions>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>${maven-dependency-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n        </plugins>\n        <pluginManagement>\n            <plugins>\n        \t\t<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>${lifecycle-mapping.version}</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.apache.maven.plugins\n                                        </groupId>\n                                        <artifactId>\n                                            maven-dependency-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [2.1,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>\n                                                copy-dependencies\n                                            </goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/.gitignore",
    "content": "*.map\n*.obj\n*.lib\n*.pdb\n*.exp\n*.o\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/CommPortIdentifier.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#ifdef WIN32\n#include \"javax_comm_CommPortIdentifier.h\"\nextern int w32CommPortIdentifier_monitorInterJVMDeviceAccessNC( JNIEnv *, jobject, jobject );\n#else\n#if _WIN32_WCE>=400\n#include \"javax_comm_CommPortIdentifier.h\"\nextern int w32CommPortIdentifier_monitorInterJVMDeviceAccessNC( JNIEnv *, jobject, jobject );\n#else //linux\n#include <javax_comm_CommPortIdentifier.h>\n#endif //_WIN32_WCE>=400\n#endif //WIN32\n/*\n * Class:     javax_comm_CommPortIdentifier\n * Method:    monitorInterJVMDeviceAccessNC\n * Signature: (Ljava/lang/Thread;)I\n *\n * Currenty not Supported on Posix Devices\n */\nJNIEXPORT jint JNICALL Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC\n\t\t\t\t(JNIEnv *jenv, jobject jobj, jobject jtho) {\n#ifdef WIN32\n    return w32CommPortIdentifier_monitorInterJVMDeviceAccessNC( jenv, jobj, jtho );\n#else\n#if _WIN32_WCE>=400\n    return w32CommPortIdentifier_monitorInterJVMDeviceAccessNC( jenv, jobj, jtho );\n#else\n    return cygCommPortIdentifier_monitorInterJVMDeviceAccessNC( jenv, jobj, jtho );\n#endif\n#endif\n} /* Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/Javaxcommnatives.vpj",
    "content": "<!DOCTYPE Project SYSTEM \"http://www.slickedit.com/dtd/vse/10.0/vpj.dtd\">\n<Project\n\tVersion=\"10.0\"\n\tVendorName=\"SlickEdit\"\n\tWorkingDir=\".\">\n\t<Config\n\t\tName=\"Release\"\n\t\tOutputFile=\"\"\n\t\tCompilerConfigName=\"Latest Version\">\n\t\t<Menu>\n\t\t\t<Target\n\t\t\t\tName=\"Compile\"\n\t\t\t\tMenuCaption=\"&amp;Compile\"\n\t\t\t\tCaptureOutputWith=\"ProcessBuffer\"\n\t\t\t\tSaveOption=\"SaveCurrent\"\n\t\t\t\tRunFromDir=\"%rw\">\n\t\t\t\t<Exec/>\n\t\t\t</Target>\n\t\t\t<Target\n\t\t\t\tName=\"Build\"\n\t\t\t\tMenuCaption=\"&amp;Build\"\n\t\t\t\tCaptureOutputWith=\"ProcessBuffer\"\n\t\t\t\tSaveOption=\"SaveWorkspaceFiles\"\n\t\t\t\tRunFromDir=\"%rw\">\n\t\t\t\t<Exec/>\n\t\t\t</Target>\n\t\t\t<Target\n\t\t\t\tName=\"Rebuild\"\n\t\t\t\tMenuCaption=\"&amp;Rebuild\"\n\t\t\t\tCaptureOutputWith=\"ProcessBuffer\"\n\t\t\t\tSaveOption=\"SaveWorkspaceFiles\"\n\t\t\t\tRunFromDir=\"%rw\">\n\t\t\t\t<Exec/>\n\t\t\t</Target>\n\t\t\t<Target\n\t\t\t\tName=\"Debug\"\n\t\t\t\tMenuCaption=\"&amp;Debug\"\n\t\t\t\tSaveOption=\"SaveNone\"\n\t\t\t\tRunFromDir=\"%rw\">\n\t\t\t\t<Exec/>\n\t\t\t</Target>\n\t\t\t<Target\n\t\t\t\tName=\"Execute\"\n\t\t\t\tMenuCaption=\"E&amp;xecute\"\n\t\t\t\tSaveOption=\"SaveNone\"\n\t\t\t\tRunFromDir=\"%rw\">\n\t\t\t\t<Exec CmdLine='\"Javaxcommnatives.exe\"'/>\n\t\t\t</Target>\n\t\t</Menu>\n\t</Config>\n\t<Files>\n\t\t<Folder\n\t\t\tName=\"Source Files\"\n\t\t\tFilters=\"*.c;*.C;*.cc;*.cpp;*.cp;*.cxx;*.prg;*.pas;*.dpr;*.asm;*.s;*.bas;*.java;*.cs;*.sc;*.e;*.cob;*.html;*.rc;*.tcl;*.py;*.pl\">\n\t\t\t<F N=\"CommPortIdentifier.c\"/>\n\t\t\t<F N=\"cygCommDriver.c\"/>\n\t\t\t<F N=\"cygCommPortIdentifier.c\"/>\n\t\t\t<F N=\"cygDeviceInputStream.c\"/>\n\t\t\t<F N=\"cygDeviceOutputStream.c\"/>\n\t\t\t<F N=\"cygParallelErrorEventThread.c\"/>\n\t\t\t<F N=\"cygParallelPort.c\"/>\n\t\t\t<F N=\"cygSerialDataEventThread.c\"/>\n\t\t\t<F N=\"cygSerialPort.c\"/>\n\t\t\t<F N=\"cygSerialStatusEventThread.c\"/>\n\t\t\t<F N=\"NSCommDriver.c\"/>\n\t\t\t<F N=\"NSCommLOG.c\"/>\n\t\t\t<F N=\"NSDeviceInputStream.c\"/>\n\t\t\t<F N=\"NSDeviceOutputStream.c\"/>\n\t\t\t<F N=\"NSParallelPort.c\"/>\n\t\t\t<F N=\"NSSerialPort.c\"/>\n\t\t\t<F N=\"ParallelErrorEventThread.c\"/>\n\t\t\t<F N=\"SerialDataEventThread.c\"/>\n\t\t\t<F N=\"SerialStatusEventThread.c\"/>\n\t\t\t<F N=\"SysVStyleSemaphore.c\"/>\n\t\t\t<F N=\"w32CommDriver.c\"/>\n\t\t\t<F N=\"w32CommPortIdentifier.c\"/>\n\t\t\t<F N=\"w32DeviceInputStream.c\"/>\n\t\t\t<F N=\"w32DeviceOutputStream.c\"/>\n\t\t\t<F N=\"w32ParallelErrorEventThread.c\"/>\n\t\t\t<F N=\"w32ParallelPort.c\"/>\n\t\t\t<F N=\"w32SerialDataEventThread.c\"/>\n\t\t\t<F N=\"w32SerialPort.c\"/>\n\t\t\t<F N=\"w32SerialStatusEventThread.c\"/>\n\t\t</Folder>\n\t\t<Folder\n\t\t\tName=\"Header Files\"\n\t\t\tFilters=\"*.h;*.H;*.hh;*.hpp;*.hxx;*.inc;*.sh;*.cpy;*.if\">\n\t\t\t<F N=\"org_eclipse_soda_dk_comm_NSCommDriver.h\"/>\n\t\t\t<F N=\"org_eclipse_soda_dk_comm_NSDeviceInputStream.h\"/>\n\t\t\t<F N=\"org_eclipse_soda_dk_comm_NSDeviceOutputStream.h\"/>\n\t\t\t<F N=\"org_eclipse_soda_dk_comm_NSParallelPort.h\"/>\n\t\t\t<F N=\"org_eclipse_soda_dk_comm_NSSerialPort.h\"/>\n\t\t\t<F N=\"org_eclipse_soda_dk_comm_ParallelErrorEventThread.h\"/>\n\t\t\t<F N=\"org_eclipse_soda_dk_comm_SerialDataEventThread.h\"/>\n\t\t\t<F N=\"org_eclipse_soda_dk_comm_SerialStatusEventThread.h\"/>\n\t\t\t<F N=\"org_eclipse_soda_dk_comm.h\"/>\n\t\t\t<F N=\"javax_comm_CommPortIdentifier.h\"/>\n\t\t\t<F N=\"NSCommLOG.h\"/>\n\t\t\t<F N=\"SysVStyleSemaphore.h\"/>\n\t\t\t<F N=\"w32ParallePort.h\"/>\n\t\t\t<F N=\"w32SerialPort.h\"/>\n\t\t</Folder>\n\t\t<Folder\n\t\t\tName=\"Resource Files\"\n\t\t\tFilters=\"*.ico;*.cur;*.dlg\"/>\n\t\t<Folder\n\t\t\tName=\"Bitmaps\"\n\t\t\tFilters=\"*.bmp\"/>\n\t\t<Folder\n\t\t\tName=\"Other Files\"\n\t\t\tFilters=\"\">\n\t\t\t<F\n\t\t\t\tN=\"makefile\"\n\t\t\t\tType=\"Makefile\"/>\n\t\t\t<F N=\"makefile.linux\"/>\n\t\t\t<F N=\"makefile.qnx\"/>\n\t\t\t<F N=\"makefile.win32\"/>\n\t\t\t<F N=\"makefile.win32_down\"/>\n\t\t\t<F N=\"makefile.wince\"/>\n\t\t</Folder>\n\t</Files>\n</Project>\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/Javaxcommnatives.vpw",
    "content": "<!DOCTYPE Workspace SYSTEM \"http://www.slickedit.com/dtd/vse/10.0/vpw.dtd\">\n<Workspace Version=\"10.0\" VendorName=\"SlickEdit\">\n\t<Projects>\n\t\t<Project File=\"Javaxcommnatives.vpj\"/>\n\t</Projects>\n</Workspace>\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/Javaxcommnatives.vpwhist",
    "content": "[Global]\nCurrentProject=Javaxcommnatives.vpj\n[ProjectDates]\nJavaxcommnatives.vpj=20051005132710000\n[ActiveConfig]\nJavaxcommnatives.vpj=Release\n[State]\nSCREEN: 1400 1050 66 87 1050 719 0 0 M 0 0 0 0 1373 824\nCWD: ..\\natives\nBUFFER: BN=\"C:\\j9dev\\win\\j9win\\include\\j9port.h\"\nBI: MA=1 74 1  TABS=1 5  WWS=1 IWT=0 ST=0 IN=2 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C\tHM=0 MF=608 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 E=0 ESBU2=-1\nVIEW: LN=.730 CL=14 LE=0 CX=13 CY=24 WI=5 BI=12 HT=0 HN=0 HF=0 HC=4\nBUFFER: BN=\"C:\\j9dev\\win\\j9win\\include\\jni.h\"\nBI: MA=1 74 1  TABS=1 5  WWS=1 IWT=0 ST=0 IN=2 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=C\tHM=0 MF=608 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 E=0 ESBU2=-1\nVIEW: LN=.3266 CL=26 LE=0 CX=25 CY=15 WI=5 BI=14 HT=0 HN=0 HF=0 HC=4\nBUFFER: BN=\"..\\..\\gary\\j9win\\SerialPortTest.java\"\nBI: MA=1 74 1  TABS=1 9  WWS=1 IWT=0 ST=0 IN=2 BW=0 US=32000 RO=0 SE=1 SN=0 BIN=0 MN=Java\tHM=0 MF=608 TL=0 MLL=0 ASE=0 LNL=6 LCF=0 CAPS=0 E=0 ESBU2=-1\nVIEW: LN=.0 CL=1 LE=0 CX=0 CY=0 WI=5 BI=15 HT=0 HN=0 HF=0 HC=4\nWINDOW: 44 58 1175 563 -1 -1 N  WF=0 WT=3 \"Default Fixed Font,10,0,1\"\nBUFFER: BN=\"C:\\j9dev\\win\\j9win\\include\\jni.h\"\nVIEW: LN=.3266 CL=26 LE=0 CX=25 CY=15 WI=89 BI=14 HT=0 HN=0 HF=0 HC=4\nWINDOW: 22 29 1175 563 -1 -1 N  WF=0 WT=2 \"Default Fixed Font,10,0,1\"\nBUFFER: BN=\"C:\\j9dev\\win\\j9win\\include\\j9port.h\"\nVIEW: LN=.730 CL=14 LE=0 CX=13 CY=24 WI=87 BI=12 HT=0 HN=0 HF=0 HC=4\nWINDOW: 66 87 1175 563 -1 -1 M  WF=0 WT=1 \"Default Fixed Font,10,0,1\"\nBUFFER: BN=\"..\\..\\gary\\j9win\\SerialPortTest.java\"\nVIEW: LN=.1984 CL=68 LE=0 CX=67 CY=35 WI=91 BI=15 HT=0 HN=0 HF=0 HC=4\nFILEHIST: 9\nC:\\Ravi\\stocks\\earncal.txt\nC:\\Ravi\\stocks\\zacks.txt\nC:\\j9dev\\vxworks\\j9vxworksppcjit-SR1-d\\codegen_common\\Options.cpp\n..\\..\\gary\\j9win\\SimpleSerial.java\n..\\..\\gary\\j9win\\TestComm.java\nC:\\Documents and Settings\\Administrator\\My Documents\\IBM\\wsdd571\\workspace\\JavaCommAPIBuild\\javaxcomm-rhel-20051004-0527.zip\nC:\\j9dev\\win\\j9win\\include\\j9port.h\nC:\\j9dev\\win\\j9win\\include\\jni.h\n..\\..\\gary\\j9win\\SerialPortTest.java\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/NSCommDriver.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#ifdef WIN32\n#include \"org_eclipse_soda_dk_comm_NSCommDriver.h\"\nextern  w32CommDriver_discoverDevicesNC(jenv, jobj);\n#else\n#if _WIN32_WCE>=400\n#include \"org_eclipse_soda_dk_comm_NSCommDriver.h\"\nextern  w32CommDriver_discoverDevicesNC(jenv, jobj);\n#else\n#include <org_eclipse_soda_dk_comm_NSCommDriver.h>\n#endif\n#endif\n/*\n * Class:     com.ibm.comm.NSCommDriver\n * Method:    discoverDevicesNC\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_NSCommDriver_discoverDevicesNC\n  (JNIEnv *jenv, jobject jobj) {\n#ifdef WIN32\n    w32CommDriver_discoverDevicesNC(jenv, jobj);\n#else\n#if _WIN32_WCE>=400\n    w32CommDriver_discoverDevicesNC(jenv, jobj);\n#else\n    cygCommDriver_discoverDevicesNC(jenv, jobj);\n#endif\n#endif\n    return;\n}\t// Java_org_eclipse_soda_dk_comm_NSCommDriver_discoverDevicesNC\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/NSCommLOG.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include <windows.h>\n#include \"org_eclipse_soda_dk_comm_NSSerialPort.h\"\n#include \"NSCommLOG.h\"\n/*------------------------------------------------------------------\n * \n *------------------------------------------------------------------*/\n#if 0 \nvoid ivelog(char *format, ...) {\n\tva_list    varArgs;\n\tFILE      *file;\n\ttime_t     timeNow;\n\tstruct tm *tmNow;\n\tchar       timeString[32];\n\tchar      *logFileName;\n\tlogFileName = \"c:\\\\projects\\\\javaxcomm_win\\\\iveser.log\";\n//\tfile = fopen(logFileName,\"w\");\n\tfile = fopen(logFileName,\"a+w\");\n\tif (NULL == file) return;\n\ttimeNow = time(NULL);\n\ttmNow   = localtime(&timeNow);\n\tstrftime(timeString,sizeof(timeString)-1,\"%Y/%m/%d %H:%M:%S\",tmNow);\n\tfprintf(file,\"%s : \",timeString);\n\tva_start(varArgs,format);\n\tvfprintf(file,format,varArgs);\n\tva_end(varArgs);\n\tfprintf(file,\"\\n\");\n\tfclose(file);\n}\n#endif\n/*------------------------------------------------------------------\n * throw an exception\n *------------------------------------------------------------------*/\nvoid iveSerThrow( JNIEnv *env, char *message, int rc ) {\n\tjclass clazz;\n\t\n\tLOG((\"iveSerThrow(%s)\",message));\n\tswitch (rc){\n\t\tcase J9_ERROR_ACCESS_DENIED:\n\t\t\tclazz = (*env)->FindClass(env, \"javax/comm/PortInUseException\");\n\t\t\tbreak;\n\t\tcase J9_ERROR_FILE_NOT_FOUND:\n\t\t\tclazz = (*env)->FindClass(env, \"javax/comm/NoSuchPortException\");\t\t\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tclazz = (*env)->FindClass(env, \"javax/comm/SerialPortException\");\t\t\t\n\t}\n\tif (!clazz) {\n\t\tLOG((\"couldn't find exception class\"));\n\t\treturn;\n\t}\n\t(*env)->ThrowNew(env,clazz,message);\n}\n/*------------------------------------------------------------------\n * \n *------------------------------------------------------------------*/\nvoid iveSerThrowWin(\n\tJNIEnv *env, \n\tchar   *msg,\n\tint     rc\n\t) {\n\tchar message[256];\n\tchar rcBuffer[128];\n\t\n\tLOG((\"iveSerThrowWin(%s,%d)\",msg,rc));\n\tFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,0,rc,0,rcBuffer,sizeof(rcBuffer)-1,0);\n\tsprintf(message,\"%s; rc=%d, %s\",msg,rc,rcBuffer);\n\t\n\tswitch (rc){\n\t\tcase ERROR_ACCESS_DENIED:\n\t\t\tiveSerThrow(env,message, J9_ERROR_ACCESS_DENIED);\n\t\t\tbreak;\n\t\tcase ERROR_FILE_NOT_FOUND:\n\t\t\tiveSerThrow(env,message, J9_ERROR_FILE_NOT_FOUND);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tiveSerThrow(env,message, J9_UNKNOWN_ERROR);\n\t\t\tbreak;\n\t\t\t\n\t}\n}\n/*------------------------------------------------------------------\n * clear comm errors\n *------------------------------------------------------------------*/\nvoid iveSerClearCommErrors(\n\tHANDLE osHandle\n\t) {\n\tCOMSTAT comStat;\n\tDWORD   dwErrors;\n\tClearCommError(osHandle,&dwErrors,&comStat);\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/NSCommLOG.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#if defined(NSLOGGING_AVAILABLE)\n#define LOG(x) ivelog x\n#else\n#define LOG(x)\n#endif\n#define  J9_ERROR_ACCESS_DENIED 100\n#define  J9_ERROR_FILE_NOT_FOUND 101\n#define J9_UNKNOWN_ERROR 102\nvoid ivelog(char *format, ...);\nvoid iveSerThrow( JNIEnv *, char *, int );\nvoid iveSerThrowWin( JNIEnv *, char *, int\t);\nvoid iveSerClearCommErrors( HANDLE );\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/NSDeviceInputStream.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#ifdef WIN32\n#include \"org_eclipse_soda_dk_comm_NSDeviceInputStream.h\"\nextern int w32DeviceInputStream_readDeviceOneByteNC(JNIEnv *, jobject);\nextern int w32DeviceInputStream_readDeviceNC(JNIEnv *, jobject, jbyteArray, jint, jint);\nextern int w32DeviceInputStream_getReadCountNC(JNIEnv *, jobject);\n#else\n#if _WIN32_WCE>=400\n#include \"org_eclipse_soda_dk_comm_NSDeviceInputStream.h\"\nextern int w32DeviceInputStream_readDeviceOneByteNC(JNIEnv *, jobject);\nextern int w32DeviceInputStream_readDeviceNC(JNIEnv *, jobject, jbyteArray, jint, jint);\nextern int w32DeviceInputStream_getReadCountNC(JNIEnv *, jobject);\n#else\n#include <org_eclipse_soda_dk_comm_NSDeviceInputStream.h>\n#endif\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceInputStream\n * Method:    readDeviceOneByteNC\n * Signature: ()I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSDeviceInputStream_readDeviceOneByteNC\n  (JNIEnv *jenv, jobject jobj) {\n#ifdef WIN32\n\treturn /*(int)(unsigned char)*/w32DeviceInputStream_readDeviceOneByteNC(jenv, jobj);\n#else\n#if _WIN32_WCE>=400\n\treturn (int)(unsigned char)w32DeviceInputStream_readDeviceOneByteNC(jenv, jobj);\n#else\n    return (int)(unsigned char)cygDeviceInputStream_readDeviceOneByteNC(jenv, jobj);\n#endif\n#endif\n}\t/* cygDeviceInputStream_readDeviceOneByteNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceInputStream\n * Method:    readDeviceNC\n * Signature: ([BII)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSDeviceInputStream_readDeviceNC\n  (JNIEnv *jenv, jobject jobj, jbyteArray jba, jint off, jint len) {\n#ifdef WIN32\n\treturn w32DeviceInputStream_readDeviceNC(jenv, jobj, jba, off, len);\n#else\n#if _WIN32_WCE>=400\n\treturn w32DeviceInputStream_readDeviceNC(jenv, jobj, jba, off, len);\n#else\n    return cygDeviceInputStream_readDeviceNC(jenv, jobj, jba, off, len);\n#endif\n#endif\n}\t/* cygDeviceInputStream_readDeviceNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceInputStream\n * Method:    getReadCountNC\n * Signature: ()I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSDeviceInputStream_getReadCountNC\n  (JNIEnv *jenv, jobject jobj) {\n#ifdef WIN32\n  return w32DeviceInputStream_getReadCountNC(jenv, jobj);\n#else\n#if _WIN32_WCE>=400\n  return w32DeviceInputStream_getReadCountNC(jenv, jobj);\n#else\n  return cygDeviceInputStream_getReadCountNC(jenv, jobj);\n#endif\n#endif\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/NSDeviceOutputStream.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#ifdef WIN32\n#include \"org_eclipse_soda_dk_comm_NSDeviceOutputStream.h\"\nextern int w32DeviceOutputStream_writeDeviceNC(JNIEnv *, jobject, jbyteArray, jint, jint);\n#else\n#if _WIN32_WCE>=400\n#include \"org_eclipse_soda_dk_comm_NSDeviceOutputStream.h\"\nextern int w32DeviceOutputStream_writeDeviceNC(JNIEnv *, jobject, jbyteArray, jint, jint);\n#else\n#include <org_eclipse_soda_dk_comm_NSDeviceOutputStream.h>\n#endif\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceOutputStream\n * Method:    writeDeviceNC\n * Signature: ([BII)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSDeviceOutputStream_writeDeviceNC\n  (JNIEnv *jenv, jobject jobj, jbyteArray jbuf, jint off, jint len) {\n#ifdef WIN32\n    return w32DeviceOutputStream_writeDeviceNC(jenv, jobj, jbuf, off, len);\n#else\n#if _WIN32_WCE>=400\n    return w32DeviceOutputStream_writeDeviceNC(jenv, jobj, jbuf, off, len);\n#else\n    return cygDeviceOutputStream_writeDeviceNC(jenv, jobj, jbuf, off, len);\n#endif\n#endif\n}\t/*/ Java_org_eclipse_soda_dk_comm_NSDeviceOutputStream_writeDeviceNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/NSParallelPort.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#ifdef WIN32\n#include \"org_eclipse_soda_dk_comm_NSParallelPort.h\"\n#include \"w32ParallePort.h\"\n#else\n#include <org_eclipse_soda_dk_comm_NSParallelPort.h>\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    closeDeviceNC\n * Signature: (II)I\n */\nJNIEXPORT jint JNICALL  Java_org_eclipse_soda_dk_comm_NSParallelPort_closeDeviceNC\n  (JNIEnv *jenv, jobject jobj, jint fd, jint semId)\n{\n#ifdef WIN32\n\treturn w32ParallelPort_closeDeviceNC(jenv, jobj, fd, semId);\n#else\n//    return cyg32ParallelPort_closeDeviceNC(jenv, jobj, fd, semId);\n    return cygParallelPort_closeDeviceNC(jenv, jobj, fd, semId);\n#endif\n}\t/* Java_org_eclipse_soda_dk_comm_NSParallelPort_closeDeviceNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    openDeviceNC\n * Signature: (Ljava/lang/String;I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_openDeviceNC\n  (JNIEnv *jenv, jobject jobj, jstring name, jint semId)\n{\n#ifdef WIN32\n    return w32ParallelPort_openDeviceNC(jenv, jobj, name, semId);\n#else\n    return cygParallelPort_openDeviceNC(jenv, jobj, name, semId);\n#endif\n}   /* Java_org_eclipse_soda_dk_comm_NSParallelPort_openDeviceNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPaperOutNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPaperOutNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef WIN32\n\treturn 1;\n//    return w32ParallelPort_isPaperOutNC(jenv, jobj, jfd);\n#else\n    return cygParallelPort_isPaperOutNC(jenv, jobj, jfd);\n#endif\n}\t/* Java_org_eclipse_soda_dk_comm_NSParallelPort_isPaperOutNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterBusyNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterBusyNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef WIN32\n\treturn 1;\n//    return w32ParallelPort_isPrinterBusyNC(jenv, jobj, jfd);\n#else\n    return cygParallelPort_isPrinterBusyNC(jenv, jobj, jfd);\n#endif\n}\t/* Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterBusyNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterSelectedNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterSelectedNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef WIN32\n\treturn 1;\n//    return w32ParallelPort_isPrinterSelectedNC(jenv, jobj, jfd);\n#else\n    return cygParallelPort_isPrinterSelectedNC(jenv, jobj, jfd);\n#endif\n}\t/* Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterSelectedNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterTimedOutNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterTimedOutNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef WIN32\n\treturn 1;\n//    return w32ParallelPort_isPrinterTimedOutNC(jenv, jobj, jfd);\n#else\n    return cygParallelPort_isPrinterTimedOutNC(jenv, jobj, jfd);\n#endif\n}\t/* Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterTimedOutNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterErrorNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterErrorNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef WIN32\n\treturn 1;\n//    return w32ParallelPort_isPrinterErrorNC(jenv, jobj, jfd);\n#else\n    return cygParallelPort_isPrinterErrorNC(jenv, jobj, jfd);\n#endif\n}\t/* Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterErrorNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/NSSerialPort.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#ifdef WIN32\n#include \"org_eclipse_soda_dk_comm_NSSerialPort.h\"\n#include \"w32SerialPort.h\"\n#else\n#if _WIN32_WCE>=400\n#include \"org_eclipse_soda_dk_comm_NSSerialPort.h\"\n#include \"w32SerialPort.h\"\n#else\n#include <org_eclipse_soda_dk_comm_NSSerialPort.h>\n#endif\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    closeDeviceNC\n * Signature: (Ljava/lang/String;I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_closeDeviceNC\n  (JNIEnv *jenv, jobject jobj, jint fd, jint semId)\n{\n#ifdef WIN32\n    return w32SerialPort_closeDeviceNC(jenv, jobj, fd, semId);\n#else\n#if _WIN32_WCE>=400\n\treturn w32SerialPort_closeDeviceNC(jenv, jobj, fd, semId);\n#else\n    return cygSerialPort_closeDeviceNC(jenv, jobj, fd, semId);\n#endif\n#endif\n}\t/* Java_org_eclipse_soda_dk_comm_NSSerialPort_closeDeviceNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    openDeviceNC\n * Signature: (Ljava/lang/String;I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_openDeviceNC\n  (JNIEnv *jenv, jobject jobj, jstring name, jint semId)\n{\n#ifdef WIN32\n    return w32SerialPort_openDeviceNC((JNIEnv *)jenv, jobj, name, semId);\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_openDeviceNC((JNIEnv *)jenv, jobj, name, semId);\n#else\n    return cygSerialPort_openDeviceNC(jenv, jobj, name, semId);\n#endif\n#endif\n}   /* Java_org_eclipse_soda_dk_comm_NSSerialPort_openDeviceNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setFlowControlModeNC\n * Signature: (Ljava/lang/String;I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_setFlowControlModeNC\n  (JNIEnv *jenv, jobject jobj, jint fd, jint fc )\n{\n#ifdef WIN32\n    return w32SerialPort_setFlowControlModeNC(jenv, jobj, fd, fc );\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_setFlowControlModeNC(jenv, jobj, fd, fc );\n#else\n    return cygSerialPort_setFlowControlModeNC(jenv, jobj, fd, fc );\n#endif\n#endif\n}   /* Java_org_eclipse_soda_dk_comm_NSSerialPort_setFlowControlModeNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getFlowControlModeNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getFlowControlModeNC\n  (JNIEnv *jenv, jobject jobj, jint fd )\n{\n#ifdef WIN32\n    return w32SerialPort_getFlowControlModeNC(jenv, jobj, fd );\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_getFlowControlModeNC(jenv, jobj, fd );\n#else\n    return cygSerialPort_getFlowControlModeNC(jenv, jobj, fd );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_getFlowControlModeNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getBaudRateNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getBaudRateNC\n  (JNIEnv *jenv, jobject jobj, jint fd)\n{\n#ifdef WIN32\n    return w32SerialPort_getBaudRateNC(jenv, jobj, fd);\n#else\n#if _WI32_WCE>=400\n    return w32SerialPort_getBaudRateNC(jenv, jobj, fd);\n#else\n    return cygSerialPort_getBaudRateNC(jenv, jobj, fd);\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_getBaudRateNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getDataBitsNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getDataBitsNC\n  (JNIEnv *jenv, jobject jobj, jint fd)\n{\n#ifdef WIN32\n    return w32SerialPort_getDataBitsNC(jenv, jobj, fd);\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_getDataBitsNC(jenv, jobj, fd);\n#else\n    return cygSerialPort_getDataBitsNC(jenv, jobj, fd);\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_getDataBitsNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getStopBitsNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getStopBitsNC\n  (JNIEnv *jenv, jobject jobj, jint fd)\n{\n#ifdef WIN32\n    return w32SerialPort_getStopBitsNC( jenv, jobj, fd );\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_getStopBitsNC( jenv, jobj, fd );\n#else\n    return cygSerialPort_getStopBitsNC( jenv, jobj, fd );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_getStopBitsNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getParityNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getParityNC\n  (JNIEnv *jenv, jobject jobj, jint fd)\n{\n#ifdef WIN32\n    return w32SerialPort_getParityNC( jenv, jobj, fd );\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_getParityNC( jenv, jobj, fd );\n#else\n    return cygSerialPort_getParityNC( jenv, jobj, fd );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_getParityNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setDTRNC\n * Signature: (Z)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_setDTRNC\n  (JNIEnv *jenv, jobject jobj, jboolean bool)\n{\n#ifdef WIN32\n    w32SerialPort_setDTRNC( jenv, jobj, bool );\n#else\n#if _WIN32_WCE>=400\n    w32SerialPort_setDTRNC( jenv, jobj, bool );\n#else\n    cygSerialPort_setDTRNC( jenv, jobj, bool );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_setDTRNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isDTRNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isDTRNC\n  (JNIEnv *jenv, jobject jobj)\n{\n#ifdef WIN32\n    return w32SerialPort_isDTRNC( jenv, jobj );\n#else\n#if _WIN32_WCE\n    return w32SerialPort_isDTRNC( jenv, jobj );\n#else\n    return cygSerialPort_isDTRNC( jenv, jobj );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_isDTRNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setRTSNC\n * Signature: (Z)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_setRTSNC\n  (JNIEnv *jenv, jobject jobj, jboolean bool)\n{\n#ifdef WIN32\n    w32SerialPort_setRTSNC( jenv, jobj, bool );\n#else\n#if _WIN32_WCE>=400\n    w32SerialPort_setRTSNC( jenv, jobj, bool );\n#else\n    cygSerialPort_setRTSNC( jenv, jobj, bool );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_setRTSNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isRTSNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isRTSNC\n  (JNIEnv *jenv, jobject jobj)\n{\n#ifdef WIN32\n    return w32SerialPort_isRTSNC( jenv, jobj );\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_isRTSNC( jenv, jobj );\n#else\n    return cygSerialPort_isRTSNC( jenv, jobj );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_isRTSNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isCTSNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isCTSNC\n  (JNIEnv *jenv, jobject jobj)\n{\n#ifdef WIN32\n    return w32SerialPort_isCTSNC( jenv, jobj );\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_isCTSNC( jenv, jobj );\n#else\n    return cygSerialPort_isCTSNC( jenv, jobj );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_isCTSNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isDSRNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isDSRNC\n  (JNIEnv *jenv, jobject jobj)\n{\n#ifdef WIN32\n    return w32SerialPort_isDSRNC( jenv, jobj );\n#else\n#ifdef _WIN32_WCE>=400\n    return w32SerialPort_isDSRNC( jenv, jobj );\n#else\n    return cygSerialPort_isDSRNC( jenv, jobj );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_isDSRNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isRINC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isRINC\n  (JNIEnv *jenv, jobject jobj)\n{\n#ifdef WIN32\n    return w32SerialPort_isRINC( jenv, jobj );\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_isRINC( jenv, jobj );\n#else\n    return cygSerialPort_isRINC( jenv, jobj );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_isRINC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isCDNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isCDNC\n  (JNIEnv *jenv, jobject jobj)\n{\n#ifdef WIN32\n    return w32SerialPort_isCDNC( jenv, jobj );\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_isCDNC( jenv, jobj );\n#else\n    return cygSerialPort_isCDNC( jenv, jobj );\n#endif\n#endif\n}  /* Java_org_eclipse_soda_dk_comm_NSSerialPort_isCDNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    sendBreakNC\n * Signature: (II)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_sendBreakNC\n  (JNIEnv *jenv, jobject jobj, jint jfd, jint jmillis) {\n#ifdef WIN32\n\treturn 1;\n//    return w32SerialPort_sendBreakNC( jenv, jobj, jfd, jmillis );\n#else\n#if _WIN32_WCE>=400\n\treturn 1;\n#else\n    return cygSerialPort_sendBreakNC( jenv, jobj, jfd, jmillis );\n#endif\n#endif\n} /* Java_org_eclipse_soda_dk_comm_NSSerialPort_sendBreakNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setSerialPortParamsNC\n * Signature: (IIIII)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_setSerialPortParamsNC\n  (JNIEnv *jenv, jobject jobj, jint jfd, jint jbd, jint jdb, jint jsb, jint jpar) {\n#ifdef WIN32\n    return w32SerialPort_setSerialPortParamsNC( jenv, jobj, jfd, jbd, jdb, jsb, jpar );\n#else\n#if _WIN32_WCE>=400\n    return w32SerialPort_setSerialPortParamsNC( jenv, jobj, jfd, jbd, jdb, jsb, jpar );\n#else\n    return cygSerialPort_setSerialPortParamsNC( jenv, jobj, jfd, jbd, jdb, jsb, jpar );\n#endif\n#endif\n} /* Java_org_eclipse_soda_dk_comm_NSSerialPort_setSerialPortParamsNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/ParallelErrorEventThread.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#ifdef WIN32\n#include \"org_eclipse_soda_dk_comm_ParallelErrorEventThread.h\"\n#else\n#include <org_eclipse_soda_dk_comm_ParallelErrorEventThread.h>\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_ParallelErrorEventThread\n * Method:    monitorParallelErrorNC\n * Signature: (I)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_ParallelErrorEventThread_monitorParallelErrorNC\n(JNIEnv *jenv, jobject jobj, jint jfd) {\n#ifdef WIN32\n\treturn;\n//    return w32ParallelErrorEventThread_monitorParallelErrorNC(jenv, jobj, jfd);\n#else\n    return;\n//    return cygParallelErrorEventThread_monitorParallelErrorNC(jenv, jobj, jfd);\n#endif\n} /* Java_org_eclipse_soda_dk_comm_ParallelErrorEventThread_monitorParallelErrorNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/SerialDataEventThread.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#ifdef WIN32\n#include \"org_eclipse_soda_dk_comm_SerialDataEventThread.h\"\nextern void w32SerialDataEventThread_monitorSerialDataNC(JNIEnv *, jobject, jint);\n#else\n#if _WIN32_WCE>=400\n#include \"org_eclipse_soda_dk_comm_SerialDataEventThread.h\"\nextern void w32SerialDataEventThread_monitorSerialDataNC(JNIEnv *, jobject, jint);\n#else\n#include <org_eclipse_soda_dk_comm_SerialDataEventThread.h>\n#endif\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_SerialDataEventThread\n * Method:    monitorSerialDataNC\n * Signature: (I)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_SerialDataEventThread_monitorSerialDataNC\n  (JNIEnv *jenv, jobject jobj, jint jfd) {\n#ifdef WIN32\n    w32SerialDataEventThread_monitorSerialDataNC( jenv, jobj, jfd );\n#else\n#if _WIN32_WCE>=400\n    w32SerialDataEventThread_monitorSerialDataNC( jenv, jobj, jfd );\n#else\n    cygSerialDataEventThread_monitorSerialDataNC( jenv, jobj, jfd );\n#endif\n#endif\n} /* Java_org_eclipse_soda_dk_comm_SerialDataEventThread_monitorSerialDataNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/SerialStatusEventThread.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#ifdef WIN32\n#include \"org_eclipse_soda_dk_comm_SerialStatusEventThread.h\"\nextern void w32SerialStatusEventThread_monitorSerialStatusNC(JNIEnv *, jobject, jint);\n#else\n#if _WIN32_WCE>=400\n#include \"org_eclipse_soda_dk_comm_SerialStatusEventThread.h\"\nextern void w32SerialStatusEventThread_monitorSerialStatusNC(JNIEnv *, jobject, jint);\n#else\n#include <org_eclipse_soda_dk_comm_SerialStatusEventThread.h>\n#endif\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_SerialStatusEventThread\n * Method:    monitorSerialStatusNC\n * Signature: (I)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_SerialStatusEventThread_monitorSerialStatusNC\n(JNIEnv *jenv, jobject jobj, jint jfd) {\n#ifdef WIN32\n\tw32SerialStatusEventThread_monitorSerialStatusNC(jenv, jobj, jfd);\n#else\n#if _WIN32_WCE>=400\n\tw32SerialStatusEventThread_monitorSerialStatusNC(jenv, jobj, jfd);\n#else\n    cygSerialStatusEventThread_monitorSerialStatusNC(jenv, jobj, jfd);\n#endif\n#endif\n} /* Java_org_eclipse_soda_dk_comm_SerialStatusEventThread_monitorSerialStatusNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/SysVStyleSemaphore.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <fcntl.h>\n#include \"SysVStyleSemaphore.h\"\n/* created to allow sysV type lookup of semaphore by a unique integer ID\n*/\nstatic int sem_count = 0;\nstatic sem_entry sem_tbl[SEM_TBL_SIZE];\n/* Looks up a POSIX semaphore by an integer identifyer.\n\tUsed to circumvent sysV type semaphores */\nsem_t* sem_lookup(int semID) {\n   return sem_tbl[semID].semaphore;\n}\n/* Creates a POSIX semaphore and adds it to sem_tbl.\n\tReturns the semaphore id or -1 for error.*/\nint sem_create(int semID, int initialSize) {\n   \n\tint i;\n\tfor(i = 0; i < SEM_TBL_SIZE; i++){\n\t\t\n      if(i >= sem_count) {\n\t  \t\t/* Create semaphore name from semID */\n\t  \t\tchar semName[15];\n\t\t\tsprintf(semName, \"%d\", semID);\n\t\t\tsem_count++;\t\t\t\t\t\t\t\t\t  /* increment count */\n\t\t\t// Previous method using memory mapped semaphores. Not\n\t\t\t// supported by OSX.\n\t\t\t//sem_init(sem_lookup(i), 0, initialSize); /* init semaphore */\n\t\t\t\n\t\t\t// New method using named semaphores\n\t\t\tsem_t * sem;\n\t\t\tsem = sem_open(semName, O_CREAT, 0666, 1);\n\t\t\tsem_post(sem); // Try to open if semaphore already exists\n\t\t\tsem_tbl[i].semaphore = sem;\n\t\t\tsem_tbl[i].id = semID; \t\t\t\t\t     /* set the id */\n\t\t return i;\n\t\t} else if(sem_tbl[i].id == semID){\n         return i;\n\t\t}\n   }\n   \n\treturn -1;\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/SysVStyleSemaphore.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#ifndef _SysVStyleSemaphore_h_\n#define _SysVStyleSemaphore_h_\n#include <semaphore.h>\n#ifdef NCI\n#define SEM_TBL_SIZE 5\n#else\n#define SEM_TBL_SIZE 8\n#endif\ntypedef struct {\n\tsem_t * semaphore;\n\tint id;\n\tint pid; /* currently not used */\n} sem_entry;\n/* Looks up a POSIX semaphore by an integer identifyer.\n\tUsed to circumvent sysV type semaphores */\nsem_t* sem_lookup(int semID);\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \n/* Creates a POSIX semaphore and adds it to sem_tbl.\n\tReturns the semaphore id or -1 for error.*/\nint sem_create(int semID, int initialSize);\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/build-mingw-win.bat",
    "content": "@REM MUST HAVE mingw32 and mingw-w64 in PATH\ndel Objs\\x86\\*.o\ndel Objs\\x64\\*.o\nmkdir Objs\\x86\nmkdir Objs\\x64\ndel Release\\win32\\x86\\*.dll\ndel Release\\win32\\x64\\*.dll\nmkdir Release\\win32\\x86\nmkdir Release\\win32\\x64\n\nmingw32-make.exe -f makefile.mingw SodaDkComm32\nmingw32-make.exe -f makefile.mingw SodaDkComm64\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/build-win.bat",
    "content": "call \"C:\\Program Files\\Microsoft Visual Studio 11.0\\VC\\vcvarsall.bat\" x86\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\vcvarsall.bat\" x86\n\n@REM set path to SDK include if VS used doesn't include Win32.Mak\nset INCLUDE=%INCLUDE%;c:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Include\n\nnmake -f makefile.win32"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/build-win64.bat",
    "content": "call \"C:\\Program Files\\Microsoft Visual Studio 11.0\\VC\\vcvarsall.bat\" x64\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\vcvarsall.bat\" x64\n\n@REM set path to SDK include if VS used doesn't include Win32.Mak\nset INCLUDE=%INCLUDE%;c:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Include\n\nnmake -f makefile.win32_x64\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/cygCommDriver.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <org_eclipse_soda_dk_comm_NSCommDriver.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <unistd.h>\n#ifdef _POSIX_SEMAPHORES\n#include <semaphore.h>\n#include \"SysVStyleSemaphore.h\"\n#else \n#include <sys/ipc.h> \n#include <sys/sem.h> \n#endif \n#include <stdlib.h>\n#define assert(s) if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); return;}\n#define CREAT_PERMS\t(0666)\n// for unix only\n// #define KERNEL_2200\t\"kernel.2200\"\n// #define KERNEL_1000\t\"kernel.1000\"\ntypedef struct port_s {\n\tchar\t\t*portName;\n\tint\t\tportType;\n\tchar\t\t*deviceName;\n\tint\t\tsemKey;\n} port_t;\nvoid cygCommDriver_discoverDevicesNC(JNIEnv *jenv, jobject jobj) {\n  jclass\tjc;\n  jmethodID\tjm;\n  const int\tPORT_SERIAL = 1;\t// should match with CommPortIdentifier\n  const int\tPORT_PARALLEL = 2;\t// should match with CommPortIdentifier\n  struct stat\tsbuf;\n  jstring\tpName;\n  jstring\tdName;\n  jthrowable\tjt;\n  port_t\tport_tbl[] =\n\t\t{\n#ifdef NCI\n\t\t\t{ \"LPT1\", PORT_PARALLEL, \"/dev/lpt0\" , 0x11223344 },\n\t\t\t{ \"COM1\", PORT_SERIAL  , \"/dev/tty00\", 0x11223345 },\n\t\t\t{ \"SC\"  , PORT_SERIAL  , \"/dev/sc\"   , 0x11223346 }, // ????\n\t\t\t{ \"COM2\", PORT_SERIAL  , \"/dev/tty01\", 0x11223347 },\n\t\t\t{ \"COM3\", PORT_SERIAL  , \"/dev/tty02\", 0x11223348 },\n\t\t\t{ \"COM4\", PORT_SERIAL  , \"/dev/tty03\", 0x11223349 },\n\t\t\t{ \"COM5\", PORT_SERIAL  , \"/dev/tty04\", 0x11223350 },\n\t\t\t{ \"COM6\", PORT_SERIAL  , \"/dev/tty05\", 0x11223351 },\n#endif\t/* NCI */\n#if defined(__linux__) || defined(__osx__)\n\t\t\t{ \"LPT1\", PORT_PARALLEL, \"/dev/lp0\"  , 0x11223344 },\n\t\t\t{ \"/dev/ttyS0\", PORT_SERIAL  , \"/dev/ttyS0\", 0x11223345 },\n\t\t\t{ \"/dev/ttyS1\", PORT_SERIAL  , \"/dev/ttyS1\", 0x11223347 },\n\t\t\t{ \"/dev/ttyS2\", PORT_SERIAL  , \"/dev/ttyS2\", 0x11223348 },\n\t\t\t{ \"/dev/ttyS3\", PORT_SERIAL  , \"/dev/ttyS3\", 0x11223349 },\n\t\t\t{ \"/dev/ttyS4\", PORT_SERIAL  , \"/dev/ttyS4\", 0x11223350 },\n\t\t\t{ \"/dev/ttyS5\", PORT_SERIAL  , \"/dev/ttyS5\", 0x11223351 },\n\t\t\t{ \"/dev/ttyS6\", PORT_SERIAL  , \"/dev/ttyS6\", 0x11223352 },\n\t\t\t{ \"/dev/ttyS7\", PORT_SERIAL  , \"/dev/ttyS7\", 0x11223353 },\n\t\t\t{ \"/dev/ttyS8\", PORT_SERIAL  , \"/dev/ttyS8\", 0x11223354 },\n\t\t\t{ \"/dev/ttyS9\", PORT_SERIAL  , \"/dev/ttyS9\", 0x11223355 },\n\t\t\t{ \"/dev/ttyO4\", PORT_SERIAL  , \"/dev/ttyO4\", 0x11223356 },\n\t\t\t{ \"/dev/ttyO5\", PORT_SERIAL  , \"/dev/ttyO5\", 0x11223357 },\n\t\t\t{ \"/dev/modem\", PORT_SERIAL  , \"/dev/modem\", 0x11223358 },\n\t\t\t{ \"/dev/ttyUSB0\", PORT_SERIAL  , \"/dev/ttyUSB0\", 0x11223359 },\n\t\t\t{ \"/dev/ttyUSB1\", PORT_SERIAL  , \"/dev/ttyUSB1\", 0x11223360 },\n\t\t\t{ \"/dev/ttyUSB2\", PORT_SERIAL  , \"/dev/ttyUSB2\", 0x11223361 },\n\t\t\t{ \"/dev/ttyUSB3\", PORT_SERIAL  , \"/dev/ttyUSB3\", 0x11223362 },\n\t\t\t{ \"/dev/ttyUSB4\", PORT_SERIAL  , \"/dev/ttyUSB4\", 0x11223363 },\n\t\t\t{ \"/dev/ttyUSB5\", PORT_SERIAL  , \"/dev/ttyUSB5\", 0x11223364 },\n\t\t\t{ \"/dev/ttyUSB6\", PORT_SERIAL  , \"/dev/ttyUSB6\", 0x11223365 },\n\t\t\t{ \"/dev/ttyUSB7\", PORT_SERIAL  , \"/dev/ttyUSB7\", 0x11223366 },\n\t\t\t{ \"/dev/ttyUSB8\", PORT_SERIAL  , \"/dev/ttyUSB8\", 0x11223367 },\n\t\t\t{ \"/dev/ttyUSB9\", PORT_SERIAL  , \"/dev/ttyUSB9\", 0x11223368 },\n\t\t\t{ \"/dev/ttyUSB10\", PORT_SERIAL  , \"/dev/ttyUSB10\", 0x11223369 },\n\t\t\t{ \"/dev/ttyUSB11\", PORT_SERIAL  , \"/dev/ttyUSB11\", 0x11223370 },\n\t\t\t{ \"/dev/ttyUSB12\", PORT_SERIAL  , \"/dev/ttyUSB12\", 0x11223371 },\n\t\t\t{ \"/dev/ttyUSB13\", PORT_SERIAL  , \"/dev/ttyUSB13\", 0x11223372 },\n\t\t\t{ \"/dev/ttyUSB14\", PORT_SERIAL  , \"/dev/ttyUSB14\", 0x11223373 },\n\t\t\t{ \"/dev/ttyUSB15\", PORT_SERIAL  , \"/dev/ttyUSB15\", 0x11223374 },\n\t\t\t{ \"/dev/ttyUSB16\", PORT_SERIAL  , \"/dev/ttyUSB16\", 0x11223375 },\n\t\t\t{ \"/dev/ttyUSB17\", PORT_SERIAL  , \"/dev/ttyUSB17\", 0x11223376 },\n\t\t\t{ \"/dev/ttyUSB18\", PORT_SERIAL  , \"/dev/ttyUSB18\", 0x11223377 },\n\t\t\t{ \"/dev/ttyUSB19\", PORT_SERIAL  , \"/dev/ttyUSB19\", 0x11223378 },\n\t\t\t{ \"/dev/ttyACM0\", PORT_SERIAL  , \"/dev/ttyACM0\", 0x11223379 },\n\t\t\t{ \"/dev/ttyACM1\", PORT_SERIAL  , \"/dev/ttyACM1\", 0x11223380 },\n\t\t\t{ \"/dev/ttyACM2\", PORT_SERIAL  , \"/dev/ttyACM2\", 0x11223381 },\n\t\t\t{ \"/dev/ttyACM3\", PORT_SERIAL  , \"/dev/ttyACM3\", 0x11223382 },\n\t\t\t{ \"/dev/ttyACM4\", PORT_SERIAL  , \"/dev/ttyACM4\", 0x11223383 },\n\t\t\t{ \"/dev/ttyACM5\", PORT_SERIAL  , \"/dev/ttyACM5\", 0x11223384 },\n\t\t\t{ \"/dev/ttyACM6\", PORT_SERIAL  , \"/dev/ttyACM6\", 0x11223385 },\n\t\t\t{ \"/dev/ttyACM7\", PORT_SERIAL  , \"/dev/ttyACM7\", 0x11223386 },\n\t\t\t{ \"/dev/ttyACM8\", PORT_SERIAL  , \"/dev/ttyACM8\", 0x11223387 },\n\t\t\t{ \"/dev/ttyACM9\", PORT_SERIAL  , \"/dev/ttyACM9\", 0x11223388 },\n\t\t\t{ \"/dev/ttyO0\",   PORT_SERIAL  , \"/dev/ttyO0\", 0x11223389 },\n\t\t\t{ \"/dev/ttyO1\",   PORT_SERIAL  , \"/dev/ttyO1\", 0x11223390 },\n\t\t\t{ \"/dev/ttyO2\",   PORT_SERIAL  , \"/dev/ttyO2\", 0x11223391 },\n\t\t\t{ \"/dev/ttyO3\",   PORT_SERIAL  , \"/dev/ttyO3\", 0x11223392 },\n\t\t\t{ \"/dev/ttyAMA0\",    PORT_SERIAL  , \"/dev/ttyAMA0\", 0x11223393 },\n\t\t\t{ \"/dev/tty.usbserial\", PORT_SERIAL , \"/dev/tty.usbserial\", 0x11223394 },\n\t\t\t{ \"/dev/ttymxc0\",   PORT_SERIAL  , \"/dev/ttymxc0\", 0x11223395 },\n\t\t\t{ \"/dev/ttymxc1\",   PORT_SERIAL  , \"/dev/ttymxc1\", 0x11223396 },\n\t\t\t{ \"/dev/ttymxc2\",   PORT_SERIAL  , \"/dev/ttymxc2\", 0x11223397 },\n\t\t\t{ \"/dev/ttymxc3\",   PORT_SERIAL  , \"/dev/ttymxc3\", 0x11223398 },\n\t\t\t{ \"/dev/ttymxc4\",   PORT_SERIAL  , \"/dev/ttymxc4\", 0x11223399 },\n#endif\t/* __linux__ */\n#ifdef QNX\n\t\t\t{ \"LPT1\", PORT_PARALLEL, \"/dev/par1\"  , 0x11223344 },\n\t\t\t{ \"COM1\", PORT_SERIAL  , \"/dev/ser1\", 0x11223345 },\n\t\t\t{ \"COM2\", PORT_SERIAL  , \"/dev/ser2\", 0x11223347 },\n\t\t\t{ \"COM3\", PORT_SERIAL  , \"/dev/ser3\", 0x11223348 },\n\t\t\t{ \"COM4\", PORT_SERIAL  , \"/dev/ser4\", 0x11223349 },\n\t\t\t{ \"COM5\", PORT_SERIAL  , \"/dev/ser5\", 0x11223350 },\n\t\t\t{ \"COM6\", PORT_SERIAL  , \"/dev/ser6\", 0x11223351 },\n\t\t\t{ \"COM7\", PORT_SERIAL  , \"/dev/ser7\", 0x11223352 },\n\t\t\t{ \"COM8\", PORT_SERIAL  , \"/dev/ser8\", 0x11223353 },\n\t\t\t{ \"COM9\", PORT_SERIAL  , \"/dev/ser9\", 0x11223354 },\n\t\t\t{ \"COM10\", PORT_SERIAL  , \"/dev/ser10\", 0x11223355 },\n\t\t\t{ \"COM11\", PORT_SERIAL  , \"/dev/ser11\", 0x11223356 },\n\t\t\t{ \"COM12\", PORT_SERIAL  , \"/dev/ser12\", 0x11223357 },\n#endif\t/* QNX  */\n\t\t};\n  port_t\t*pp;\n  // Get access to the method to add a port.\n  jc = (*jenv)->GetObjectClass(jenv, jobj);\n  assert(jc);\n  jm = (*jenv)->GetMethodID(jenv, jc, \"addDeviceToList\",\n\t\t\t    \"(Ljava/lang/String;ILjava/lang/String;I)V\");\n  assert(jm);\n  // Determine if we're running on a badger.  If so, use the alternate list.\n  // For UNIX only\n  //{\n  // char  *envp =  getenv(\"BOOT_KERNEL\");\n  //\n  // if (envp && *envp) {\n  //    if (!strcmp(envp, KERNEL_2200)) {\n  //       port_tbl = port_tbl_2200;\n  //       port_tbl_noentries = sizeof(port_tbl_2200)/sizeof(port_tbl_2200[0]);\n  //    }\n  //    else if (!strcmp(envp, KERNEL_1000)) {\n  //       port_tbl = port_tbl_1000;\n  //       port_tbl_noentries = sizeof(port_tbl_1000)/sizeof(port_tbl_1000[0]);\n  //    }\n  // }\n  //}\n  // For all the pre-defined ports, check to see which ones exist, and add\n  // them selectively.\n  for (pp = port_tbl;\n       pp < port_tbl+(sizeof(port_tbl)/sizeof(port_tbl[0]));\n       ++pp) {\n       if (stat(pp->deviceName, &sbuf) != -1) {\n\t\tint\t\tsemID;\n\t\t\n\t\tpName = (*jenv)->NewStringUTF(jenv, pp->portName);\n\t\tif (!pName)\n\t\t\tcontinue;\n\t\tdName = (*jenv)->NewStringUTF(jenv, pp->deviceName);\n\t\tif (!dName)\n\t\t\tcontinue;\n\t\t/* Obtain/create a semaphore for the device in consideration.\n\t\t   If it fails, don't lock/unlock it later on. */\n#ifdef _POSIX_SEMAPHORES\n\t\tsemID = sem_create(pp->semKey, 1);\n#else\n\t\tsemID = semget((key_t)pp->semKey, 1, IPC_CREAT | CREAT_PERMS);\n#endif\n#ifdef DEBUG\n       printf( \"%s ( %s ) semID %d\\n\", pName, dName, semID );\n       fflush( stdout );\n#endif\n\t\n\t\t(*jenv)->CallVoidMethod(jenv, jobj, jm,\n\t\t\t\t\tpName, pp->portType, dName, semID);\n\t\tjt = (*jenv)->ExceptionOccurred(jenv);\n\t\tif (jt) {\n\t\t\t(*jenv)->ExceptionDescribe(jenv);\n\t\t\t(*jenv)->ExceptionClear(jenv);\n\t\t}\n       }\n  }\n  return;\n}\t// Java_org_eclipse_soda_dk_comm_NSCommDriver_discoverDevicesNC\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/cygCommPortIdentifier.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include \"dkcomm.h\"\n#include <stdio.h>\n#include <string.h>\n#include <errno.h>\n#include <sys/types.h>\n#include <unistd.h>\n#ifdef _POSIX_SEMAPHORES\n#include <semaphore.h>\n#include \"SysVStyleSemaphore.h\"\n#else \n#include <sys/ipc.h> \n#include <sys/sem.h> \n#endif \n  \n#include <javax_comm_CommPortIdentifier.h>\n#define assertexc(s)       if (!s) {fprintf(stderr, \"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return(-1);}\n#define NOOF_ELEMS(s)\t((sizeof(s))/(sizeof(s[0])))\ntypedef struct port_s {\n\tchar\t\t*portName;\n\tint\t\tsemKey;\n} port_t;\n#ifndef _POSIX_SEMAPHORES\nstatic struct sembuf\tdev_wait[] = {\n\t\t{ 0, 0, 0 }\t/* wait until it is free */\n};\n#endif\nstatic int\tgetPollingTime(JNIEnv *jenv) {\n  int\t\tptime = 5;\n  jclass\tcic;\n  jfieldID\tptID;\n  jint\t\tpt;\n  do {\n\tcic = (*jenv)->FindClass(jenv, \"javax/comm/CommPortIdentifier\");\n\tif (!cic) break;\n\tptID = (*jenv)->GetStaticFieldID(jenv, cic, \"pollingTime\", \"I\");\n\tif (!ptID) break;\n\tpt = (*jenv)->GetStaticIntField(jenv, cic, ptID);\n\tif (pt > 0)\n\t\tptime = pt;\n  } while (0);\n  return ptime;\n}\t// getPollingTime()\nstatic int GetSemID(const char *pnm) {\n  int\t\tsemID = -1;\n  port_t\tport_tbl[] =  \n\t  {\n\t\t\t{ \"LPT1\", 0x11223344 },\n\t\t\t{ \"COM1\", 0x11223345 },\n#ifdef NCI\n\t\t\t{ \"SC\",   0x11223346 }, // ????\n#endif\t/* NCI */\n\t\t\t{ \"COM2\", 0x11223347 },\n\t\t\t{ \"COM3\", 0x11223348 },\n\t\t\t{ \"COM4\", 0x11223349 },\n#ifdef NCI\n\t\t\t{ \"COM5\", 0x11223350 },\n\t\t\t{ \"COM6\", 0x11223351 },\n#endif\t/* NCI */\n#ifdef QNX\n\t\t\t{ \"COM5\", 0x11223350 },\n\t\t\t{ \"COM6\", 0x11223351 },\n\t\t\t{ \"COM7\", 0x11223352 },\n\t\t\t{ \"COM8\", 0x11223353 },\n\t\t\t{ \"COM9\", 0x11223354 },\n\t\t\t{ \"COM10\", 0x11223355 },\n\t\t\t{ \"COM11\", 0x11223356 },\n\t\t\t{ \"COM12\", 0x11223357 },\n#endif /* QNX */\n\t\t};\n  port_t\t*pp;\n  int\t\tkeyFound = 0;\n  /* Find the semaphore key for the corresponding port name. */\n  for (pp = port_tbl;\n       pp < port_tbl+NOOF_ELEMS(port_tbl);\n       ++pp) {\n      if (!strcmp(pp->portName, pnm)) {\n\t  keyFound++;\n\t  break;\n      }\n  }\n  if (!keyFound)\n      return semID;\n#ifndef _POSIX_SEMAPHORES\n  /* Get the semaphore ID for the key obtained. */\n  semID = semget((key_t)pp->semKey, 1, 0);\n#else\n\t/* don't worry about return value for right now */\n  semID = sem_create(pp->semKey, 1);\n#endif /* _POSIX_SEMAPHORES */\n  return semID;\n}\t// GetSemID()\n/*\n * Class:     javax_comm_CommPortIdentifier\n * Method:    monitorInterJVMDeviceAccessNC\n * Signature: (Ljava/lang/Thread;)I\n *\n * Currenty not Supported on Posix Devices\n */\nint cygCommPortIdentifier_monitorInterJVMDeviceAccessNC\n(JNIEnv *jenv, jobject jobj, jobject jtho) {\n\tint\t\tpollingTime;\t/* seconds */\n\tint\t\toldVal, newVal;\n\tjclass\t\tjc;\n\tjmethodID\tjm;\n\tjfieldID\tpnameID;\n\tjstring\t\tpname;\n\tconst char\t*pnamec;\n\tjboolean\tisInterruptedReturn;\n\tjclass\t\tjcpoc;\t\t/* CommPortOwnershipListener interf */\n\tjfieldID\tcpoPOID;\t/* PORT_OWNED ID */\n\tjfieldID\tcpoPUID;\t/* PORT_UNOWNED ID */\n\tjfieldID\tcpoPRID;\t/* PORT_OWNERSHIP_REQUESTED ID */\n\tjint\t\tcpoPO;\t\t/* PORT_OWNED value */\n\tjint\t\tcpoPU;\t\t/* PORT_UNOWNED value */\n\tjint\t\tcpoPR;\t\t/* PORT_OWNERSHIP_REQUESTED value */\n\tjmethodID\tjintMethod;\n\tjclass\t\tjthreadClass;\n\tint\t\tsemID;\n\tunion semuni\tscarg;\n\tint\t\tmypid = getpid();\n\tint\t\tscpid;\n\tpollingTime = getPollingTime(jenv);\n\t/* Get the class ID of the CommPortIdentifier object.*/\n\tjc = (*jenv)->GetObjectClass(jenv, jobj);\n\tassertexc(jc);\n\t/* Get the id of the method to report a change-ownership event. */\n\tjm = (*jenv)->GetMethodID(jenv, jc, \"fireOwnershipEvent\", \"(I)V\");\n\tassertexc(jm);\n\t/* Get the const values for the CommPortOwnershipListener events.*/\n\tjcpoc = (*jenv)->FindClass(jenv, \"javax/comm/CommPortOwnershipListener\");\n\tassertexc(jcpoc);\n\tcpoPOID = (*jenv)->GetStaticFieldID(jenv, jcpoc, \"PORT_OWNED\", \"I\");\n\tassertexc(cpoPOID);\n\tcpoPO = (*jenv)->GetStaticIntField(jenv, jcpoc, cpoPOID);\n\tcpoPUID = (*jenv)->GetStaticFieldID(jenv, jcpoc, \"PORT_UNOWNED\", \"I\");\n\tassertexc(cpoPUID);\n\tcpoPU = (*jenv)->GetStaticIntField(jenv, jcpoc, cpoPUID);\n\tcpoPRID = (*jenv)->GetStaticFieldID(jenv, jcpoc, \"PORT_OWNERSHIP_REQUESTED\", \"I\");\n\tassertexc(cpoPRID);\n\tcpoPR = (*jenv)->GetStaticIntField(jenv, jcpoc, cpoPRID);\n\t/* Get the port name. */\n\tpnameID = (*jenv)->GetFieldID(jenv, jc, \"name\", \"Ljava/lang/String;\");\n\tassertexc(pnameID);\n\tpname = (*jenv)->GetObjectField(jenv, jobj, pnameID);\n\tassertexc(pname);\n  \tpnamec = (*jenv)->GetStringUTFChars(jenv, pname, 0);\n\t/* Get the corresponding semaphore ID for the port name. */\n\tsemID = GetSemID(pnamec);\n  \t(*jenv)->ReleaseStringUTFChars(jenv, pname, pnamec);\n\tif (semID == -1)\n\t\treturn -1;\n\t/* Get access to the interrupted method. */\n\tjthreadClass = (*jenv)->FindClass(jenv, \"java/lang/Thread\");\n\tassertexc(jthreadClass);\n\tjintMethod = (*jenv)->GetMethodID(jenv, jthreadClass, \"isInterrupted\", \"()Z\");\n\tassertexc(jintMethod);\n\t(void)memset(&scarg, 0, sizeof(scarg));\n/* what is this for? */\n\t/* Get the current value of the semaphore. */\n#ifdef  _POSIX_SEMAPHORES\n\tif ((sem_getvalue(sem_lookup(semID), &oldVal)) < 0) {\n#else\n\tif ((oldVal = semctl(semID, 0, GETVAL, scarg)) < 0) {\n#endif\t\t\n\t\t(void)fprintf(stderr, \"Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC: semctl error %d!\\n\", errno);\n\t\treturn -1;\n\t}\n/* !!!!!!!!!!!!!! */\n\twhile(1)\n\t{\n\t\t/* Check to see if this thread has been interrupted. */\n\t\tisInterruptedReturn = (*jenv)->CallBooleanMethod(jenv, jtho, jintMethod);\n\t\tif(isInterruptedReturn == JNI_TRUE)\n\t\t\tbreak;\n\t\t/* If the semaphore was locked the last time, wait until it\n\t\t   gets unlocked.  Else, catch some breath.\n\t\t */\n#ifdef NCI\n\t\tif (oldVal) {\n#ifdef  _POSIX_SEMAPHORES\n\t\t\tif(sem_wait(sem_lookup(semID)) <0){\n#else\n\t\t\tif (semop(semID, dev_wait, NOOF_ELEMS(dev_wait)) < 0) {\n#endif\t\t\t\t\n\t\t\t\t(void)fprintf(stderr, \"Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC: semop error %d!\\n\", errno);\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t\telse\n#endif\t/* NCI */\n\t\t\tsleep(pollingTime);\n\t\t/* Get the new value of the semaphore. */\n\t\t\t/* Get the current value of the semaphore. */\n#ifdef  _POSIX_SEMAPHORES\n\t\tif ((sem_getvalue(sem_lookup(semID), &oldVal)) < 0) {\n#else\n\t\tif ((oldVal = semctl(semID, 0, GETVAL, scarg)) < 0) {\n#endif\t\t\n\t\t\t(void)fprintf(stderr, \"Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC: semctl error %d!\\n\", errno);\n\t\t\treturn -1;\n\t\t}\n\t\tif (newVal == oldVal)\n\t\t\tcontinue;\n\t\t/* Get PID of the last process that changed the semaphore.\n\t\t   If it is the same JVM, ignore this change.\n\t\t */\n\t\t\t/* Get the current value of the semaphore. */\n#ifndef  _POSIX_SEMAPHORES\n   /* DLS HACK needs to be changed */\n\t\tif ((scpid = semctl(semID, 0, GETPID, scarg)) < 0) {\n\t\t\t(void)fprintf(stderr, \"Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC: semctl error %d!\\n\", errno);\n\t\t\treturn -1;\n\t\t}\n\t\tif (scpid != mypid) {\n\t\t\t/* If locked, send a PORT_OWNED event.\n\t\t\t   Else, send a PORT_UNOWNED event.\n\t\t\t */\n\t\t\t(*jenv)->CallVoidMethod(jenv, jobj, jm,\n\t\t\t\t\t\tnewVal ? cpoPO : cpoPU);\n\t\t}\n#endif\n\t\toldVal = newVal;\n\t}\t/* end of while() */\n} /* Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/cygDeviceInputStream.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <signal.h>\n#include <errno.h>\n#include <sys/ioctl.h>\n#include <org_eclipse_soda_dk_comm_NSDeviceInputStream.h>\n#include <sys/time.h>\n#ifndef FALSE\n#define FALSE 0\n#endif\n#ifndef TRUE\n#define TRUE 1\n#endif\n#define assert(s) if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); return(-1);}\n#define assertexc(s) if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); (*jenv)->ThrowNew(jenv, ec, \"\");}\n#if defined(__linux__) || defined(__osx__)\nstatic volatile int\ttimeoutOccurred = FALSE;\nstatic struct itimerval\tapptimer;\nstatic struct sigaction\tappsa;\n// static void\t\t(*apphandler)();\nint\t\t\ttimerflag;\nstatic void alarm_handler(int sig)\n{\n\t timeoutOccurred = TRUE; \n}\nstatic void start_read_timer(int tmovalue)\n{\n   struct itimerval\ttm;\n   struct sigaction\tnewsa;\n   /* Suspend the app's timer and save it. */\n   (void)memset(&tm, 0, sizeof(tm));\n   (void)setitimer(ITIMER_REAL, &tm, &apptimer);\n   /* Replace the app's signal handler with ours. */\n   (void)memset(&newsa, 0, sizeof(newsa));\n   newsa.sa_handler = alarm_handler;\n   (void)sigaction(SIGALRM, &newsa, &appsa);\n   // apphandler = signal(SIGALRM, alarm_handler);\n   /* Start our timer. */\n   (void)memset(&tm, 0, sizeof(tm));\n   tm.it_value.tv_usec = tmovalue * 1000;  // convert millisec into microsec\n   (void)setitimer(ITIMER_REAL, &tm, NULL);\n   timerflag = TRUE;\n}\t/* start_read_timer() */\nstatic void stop_read_timer()\n{\n   struct itimerval\ttm;\n   if (!timerflag)\n      return;\n   /* Stop our ticking timer. */\n   (void)memset(&tm, 0, sizeof(tm));\n   (void)setitimer(ITIMER_REAL, &tm, NULL);\n   /* Restore the app's signal handler. */\n   (void)sigaction(SIGALRM, &appsa, NULL);\n   // (void)signal(SIGALRM, apphandler);\n   /* Restore the app's timer */\n   (void)setitimer(ITIMER_REAL, &apptimer, NULL);\n   timerflag = FALSE;\n}\t/* stop_read_timer */\n#endif /* __linux__ */\nint cygDeviceInputStream_readDeviceOneByteNC\n  (JNIEnv *jenv, jobject jobj) {\n  jclass\tjc;\n  jclass\tec;\n  jfieldID\tjf;\n  jint \t\tfd = -1;\n  int\t\trc;\n  int\t\tdc;\n  char\t\tbuf[1];\n  jfieldID\ttmof;\n  int\t\ttmo;\n  int\t\tserrno;\n\t\n  // Get the exception class.\n  ec = (*jenv)->FindClass(jenv, \"java/io/IOException\");\n  assert(ec);\n  // Get the file descriptor.\n  jc = (*jenv)->GetObjectClass(jenv, jobj);\n  assertexc(jc);\n  jf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n  assertexc(jf);\n  fd = (*jenv)->GetIntField(jenv, jobj, jf);\n  if (fd == -1) {\n\t(*jenv)->ThrowNew(jenv, ec, \"\");\n  }\n  tmof = (*jenv)->GetFieldID(jenv, jc, \"tmo\", \"I\");\n  assert(tmof);\n  tmo = (*jenv)->GetIntField(jenv, jobj, tmof);\n  \n#ifdef QNX\n\t// Read data - QNX with timeout\n\tif (tmo <100 & tmo>0) {\n\t\ttmo=100;\n\t}\n\tdc=readcond(fd, buf, 1, 1, 0, tmo/100); //10th of a second instead of microSecs\n\tif (dc<1) {\n\t\t//dc=-1; //return fake error\n\t}\n#endif /* QNX */\n#if defined(__linux__) || defined(__osx__)\n  // Start the timer.\n  timeoutOccurred = FALSE;\n  if (tmo > 0)\n\tstart_read_timer(tmo);\n  // Read data.\n  buf[0] = 0;\n  dc = read(fd, buf, 1);\n  serrno = errno;\n  // Stop the timer.\n  if (tmo > 0)\n\tstop_read_timer();\n  if (dc < 0 && !(serrno == EINTR || serrno == EAGAIN)) {\n\t(*jenv)->ThrowNew(jenv, ec, \"\");\n  }\n#endif /* __linux__ */\n  // If timeout had occurred, or if nil data was received, return -1.\n  if (dc <= 0)\n\treturn -1;\n  return (int)(unsigned char)buf[0];\n}\t/* cygDeviceInputStream_readDeviceOneByteNC */\nint cygDeviceInputStream_readDeviceNC\n  (JNIEnv *jenv, jobject jobj, jbyteArray jba, jint off, jint len) {\n  jclass\tjc;\n  jfieldID\tjf;\n  jint \t\tfd = -1;\n  int\t\trc;\n  int\t\tdc = 0;\n  char\t\t*cbuf;\n  jfieldID\ttmof;\n  int\t\ttmo;\n  jfieldID\ttmoDonef;\n  \n  cbuf = malloc(len);\n  \n  assert(cbuf);\n  // Get the file descriptor.\n  jc = (*jenv)->GetObjectClass(jenv, jobj);\n  assert(jc);\n  jf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n  assert(jf);\n  fd = (*jenv)->GetIntField(jenv, jobj, jf);\n  if (fd == -1) {\n\treturn -1;\n  }\n  tmof = (*jenv)->GetFieldID(jenv, jc, \"tmo\", \"I\");\n  assert(tmof);\n  tmoDonef = (*jenv)->GetFieldID(jenv, jc, \"tmoDone\", \"Z\");\n  assert(tmoDonef);\n  tmo = (*jenv)->GetIntField(jenv, jobj, tmof);\n#ifdef QNX\n\t// Read data - QNX with timeout\n\tif (tmo <100 & tmo>0) {\n\t\ttmo=100;\n\t}\n\t\n\tdc=readcond(fd, cbuf, len, len, tmo/100, tmo/100); //10th of a second instead of microSecs\n\tif (dc<len) {\n\t\t(*jenv)->SetBooleanField(jenv, jobj, tmoDonef, (jboolean)JNI_TRUE);\n\t\t//dc=-1; //return fake error\n\t}\n#endif /* QNX */\n#if defined(__linux__) || defined(__osx__) \n  // Start the timer.\n  timeoutOccurred = FALSE;\n  if (tmo > 0)\n\tstart_read_timer(tmo);\n  \n    //Read data\n   dc = read(fd, cbuf, len);\n\t\n  // If the timer had already expired, set the field tmoDone.\n  // Else, stop the timer.\n    if (timeoutOccurred) {\n    \tdc = 0; // Bug fix for PR#117959\n\t\t(*jenv)->SetBooleanField(jenv, jobj, tmoDonef, (jboolean)JNI_TRUE);\n  \t}\n  if (tmo > 0)\n    stop_read_timer();\n#endif /*__linux__*/\n  // Copy back the data into the java buffer.\n  if (dc > 0)\n\t(*jenv)->SetByteArrayRegion(jenv, jba, off, dc, (jbyte*)cbuf);\n  free(cbuf);\n  return dc;\n}\t/* cygDeviceInputStream_readDeviceNC */\nint cygDeviceInputStream_getReadCountNC\n  (JNIEnv *jenv, jobject jobj) {\n  jclass\tjc;\n  jclass\tec;\n  jfieldID\tjf;\n  jint \t\tfd = -1;\n  int\t\trc;\n  int\t\tdc = 0;\n  // Get the exception class.\n  ec = (*jenv)->FindClass(jenv, \"java/io/IOException\");\n  assert(ec);\n  // Get the file descriptor.\n  jc = (*jenv)->GetObjectClass(jenv, jobj);\n  assertexc(jc);\n  jf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n  assertexc(jf);\n  fd = (*jenv)->GetIntField(jenv, jobj, jf);\n  if (fd == -1) {\n\t(*jenv)->ThrowNew(jenv, ec, \"\");\n  }\n  // Now query the device stream for any data to be read.\n  if ((rc = ioctl(fd, FIONREAD, &dc)) == -1)\n\t(*jenv)->ThrowNew(jenv, ec, \"\");\n  return dc;\n} /* cygDeviceInputStream_getReadCountNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/cygDeviceOutputStream.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <org_eclipse_soda_dk_comm_NSDeviceOutputStream.h>\n#define assert(s) if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); return(-1);}\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceOutputStream\n * Method:    writeDeviceNC\n * Signature: ([BII)I\n */\nint cygDeviceOutputStream_writeDeviceNC\n  (JNIEnv *jenv, jobject jobj, jbyteArray jbuf, jint off, jint len) {\n  jclass\tjc;\n  jfieldID\tjf;\n  jint \t\tfd = -1;\n  jbyte\t\t*cbuf;\n  jboolean\tisCopy;\n  int\t\twc = 0;\n  jbyte\t\t*cb;\n  int\t\trc;\n  if (!len)\n\treturn wc;\n  // Get the file descriptor.\n  jc = (*jenv)->GetObjectClass(jenv, jobj);\n  assert(jc);\n  jf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n  assert(jf);\n  fd = (*jenv)->GetIntField(jenv, jobj, jf);\n  if (fd == -1)\n\treturn -1;\n  // Convert the java byte array buffer into c byte buffer.\n  cbuf =  (*jenv)->GetByteArrayElements(jenv, jbuf, &isCopy);\n  // Write the data out to the device.\n  for ( cb = cbuf+off; len; len -= rc, wc += rc, cb += rc ) {\n\tif ((rc = write(fd, cb, len)) < 0)\n\t\tbreak;\n  }\n  // Should we throw some exception in the event of a write error ????\n  // Free the c byte buffer.\n  (*jenv)->ReleaseByteArrayElements(jenv, jbuf, cbuf, JNI_ABORT);\n  return wc;\n}\t/* cygDeviceOutputStream_writeDeviceNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/cygParallelErrorEventThread.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <errno.h>\n#include <sys/ioctl.h>\n#ifdef NCI\n#include <dev/ic/lptioctl.h>\n#include <dev/ic/lptreg.h>\n#endif\t/* NCI */\n#ifdef __linux__\n//#define __KERNEL__  /* For printer error definitions */\n#include <linux/lp.h>\n#endif\t/* __linux__ */\n#include <org_eclipse_soda_dk_comm_ParallelErrorEventThread.h>\n#define assertexc(s)       if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return;}\nstatic int\tgetPollingTime(JNIEnv *jenv) {\n  int\t\tptime = 5;\n  jclass\tcic;\n  jfieldID\tptID;\n  jint\t\tpt;\n  do {\n\tcic = (*jenv)->FindClass(jenv, \"javax/comm/CommPortIdentifier\");\n\tif (!cic) break;\n\tptID = (*jenv)->GetStaticFieldID(jenv, cic, \"pollingTime\", \"I\");\n\tif (!ptID) break;\n\tpt = (*jenv)->GetStaticIntField(jenv, cic, ptID);\n\tif (pt > 0)\n\t\tptime = pt;\n  } while (0);\n  return ptime;\n}\t/* getPollingTime() */\nstatic int getStopThreadFlag(JNIEnv *jenv, jobject jobj)\n{\n\tjclass cls;\n\tjfieldID fid;\n\tjint stopThreadFlag;\n\t\n\tcls = (*jenv)->GetObjectClass(jenv, jobj);\n\tif (!cls) (*jenv)->FatalError(jenv, \"Missing class\");\n\t\n\tfid = (*jenv)->GetFieldID(jenv, cls, \"stopThreadFlag\", \"I\");\n\tif (fid == NULL) (*jenv)->FatalError(jenv, \"Missing field\");\n\t\n\tstopThreadFlag = (*jenv)->GetIntField(jenv, jobj, fid);\n\t\n\treturn stopThreadFlag;\t\n} \n/*\n * Class:     org_eclipse_soda_dk_comm_ParallelErrorEventThread\n * Method:    monitorParallelErrorNC\n * Signature: (I)V\n */\nvoid cygParallelErrorEventThread_monitorParallelErrorNC\n    (JNIEnv *jenv, jobject jobj, jint jfd) {\n\tint\t\tpollingTime;\t/* seconds */\n\tint\t\toldStatus, newStatus;\n\tjfieldID\tnotifyOnErrorID;\n\tjboolean\tnotifyOnErrorFlag = JNI_TRUE;\n\tjclass\t\tjc;\n\tjmethodID\tjm;\n\tjclass\t\tjppc;\n\tjfieldID\tppID;\n\tjobject\t\tjpp;\n\tjboolean\tisInterruptedReturn;\n\tjclass\t\tjppec;\t\t/* parallel port event class */\n\tjfieldID\tppeErrorID;\t/* field ID */\n\tjint\t\tppeError;\t/* field value */\n\tjmethodID\tjintMethod;\n\tjclass\t\tjthreadClass;\n\t\n\tjint \t\tstopThreadFlag;\n\tpollingTime = getPollingTime(jenv);\n\t/* Get the const value for the parallel port error event type.*/\n\tjppec = (*jenv)->FindClass(jenv, \"javax/comm/ParallelPortEvent\");\n\tassertexc(jppec);\n\tppeErrorID = (*jenv)->GetStaticFieldID(jenv, jppec, \"PAR_EV_ERROR\", \"I\");\n\tassertexc(ppeErrorID);\n\tppeError = (*jenv)->GetStaticIntField(jenv, jppec, ppeErrorID);\n\t/* Get the parallel port object.*/\n\tjc = (*jenv)->GetObjectClass(jenv, jobj);\n\tassertexc(jc);\n\tppID = (*jenv)->GetFieldID(jenv, jc, \"pp\", \"Lorg/eclipse/soda/dk/comm/NSParallelPort;\");\n\tassertexc(ppID);\n\tjpp = (*jenv)->GetObjectField(jenv, jobj, ppID);\n\tassertexc(jpp);\n\t/* Get the class ID of the parallel port object.*/\n\tjppc = (*jenv)->GetObjectClass(jenv, jpp);\n\tassertexc(jppc);\n\t/* Get the notify flag field ID of the parallel port object. */\n\tnotifyOnErrorID = (*jenv)->GetFieldID(jenv, jppc, \"notifyOnErrorFlag\", \"Z\");\n\tassertexc(notifyOnErrorID);\n\t/* Get access to the method to report a parallel event.*/\n\tjm = (*jenv)->GetMethodID(jenv, jppc, \"reportParallelEvent\", \"(IZZ)V\");\n\tassertexc(jm);\n\t/* Get access to the interrupted method.*/\n\tjthreadClass = (*jenv)->FindClass(jenv, \"java/lang/Thread\");\n\tassertexc(jthreadClass);\n\tjintMethod = (*jenv)->GetMethodID(jenv, jthreadClass, \"isInterrupted\", \"()Z\");\n\tassertexc(jintMethod);\n#ifdef NCI\n\tif (ioctl(jfd, PIOCSTATUS, &oldStatus) < 0) {\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n        oldStatus = 0;\n\tif (0) {\n#endif\t/* __osx__ */\n#ifdef __linux__\n\tif (ioctl(jfd, LPGETSTATUS, &oldStatus) < 0) {\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n        oldStatus = 0;\n\tif (0) {\n#endif\t/* QNX */\n\t\t(void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_ParallelErrorEventThread_monitorParallelErrorNC: ioctl error %d!\\n\", errno);\n\t\treturn;\n\t}\n\twhile(1)\n\t{\n\t\tsleep(pollingTime);\n\t\tstopThreadFlag = getStopThreadFlag(jenv, jobj);\n\t\tif (stopThreadFlag)\n\t\t\tbreak;\n\t\t\t\n\t\t/* check to see if this thread has been interrupted */\n\t\tisInterruptedReturn = (*jenv)->CallBooleanMethod(jenv, jobj, jintMethod);\n\t\tif(isInterruptedReturn == JNI_TRUE)\n\t\t\tbreak;\n\t\t/* Get the notify error flag. If not set, skip error checks. */\n\t\tnotifyOnErrorFlag = (*jenv)->GetBooleanField(jenv, jpp, notifyOnErrorID);\n\t\tif (notifyOnErrorFlag != JNI_TRUE)\n\t\t\tcontinue;\n#ifdef NCI\n\t\tif (ioctl(jfd, PIOCSTATUS, &newStatus) < 0) {\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n                newStatus = 0;\n\t        if (0) {\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\tif (ioctl(jfd, LPGETSTATUS, &newStatus) < 0) {\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n                newStatus = 0;\n\t        if (0) {\n#endif\t/* QNX */\n\t\t\t(void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_ParallelErrorEventThread_monitorParallelErrorNC: ioctl error %d!\\n\", errno);\n\t\t\treturn;\n\t\t}\n\t\tif (newStatus == oldStatus)\n\t\t\tcontinue;\n#ifdef NCI\n\t\tif((newStatus & LPS_NERR) != (oldStatus & LPS_NERR))\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t        if (0)\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\tif((newStatus & LP_PERRORP) != (oldStatus & LP_PERRORP))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_NERR)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_NERR)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_PERRORP)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_PERRORP)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n#ifdef NCI\n\t\tif((newStatus & LPS_SELECT) != (oldStatus & LPS_SELECT))\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t        if (0)\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\tif((newStatus & LP_PSELECD) != (oldStatus & LP_PSELECD))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_SELECT)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_SELECT)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_PSELECD)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_PSELECD)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n#ifdef NCI\n\t\tif((newStatus & LPS_NOPAPER) != (oldStatus & LPS_NOPAPER))\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t        if (0)\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\tif((newStatus & LP_POUTPA) != (oldStatus & LP_POUTPA))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_NOPAPER)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_NOPAPER)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_POUTPA)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_POUTPA)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n#ifdef NCI\n\t\tif((newStatus & LPS_NACK) != (oldStatus & LPS_NACK))\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t        if (0)\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\tif((newStatus & LP_PACK) != (oldStatus & LP_PACK))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_NACK)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_NACK)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_PACK)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_PACK)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n#ifdef NCI\n\t\tif((newStatus & LPS_NBSY) != (oldStatus & LPS_NBSY))\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t        if (0)\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\tif((newStatus & LP_PBUSY) != (oldStatus & LP_PBUSY))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_NBSY)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_NBSY)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __osx__      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* __osx__ */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_PBUSY)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_PBUSY)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n\t\toldStatus = newStatus;\n\t}\t/* end of while() */\n} /* cygParallelErrorEventThread_monitorParallelErrorNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/cygParallelPort.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include \"dkcomm.h\"\n#include <stdio.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <sys/types.h>\n#include <sys/ipc.h>\n#include <sys/sem.h>\n#include <sys/ioctl.h>\n#ifdef NCI\n#include <dev/ic/lptioctl.h>\n#include <dev/ic/lptreg.h>\n#endif\t/* NCI */\n#ifdef __linux__\n//#define __KERNEL__ /* To get the definitions for printer errors */\n#include <linux/lp.h>\n#endif\t/* __linux__ */\n#ifdef _POSIX_SEMAPHORES\n#include <semaphore.h>\n#include \"SysVStyleSemaphore.h\"\n#else \n#include <sys/ipc.h> \n#include <sys/sem.h> \n#endif \n#include <org_eclipse_soda_dk_comm_NSParallelPort.h>\n#define NOOF_ELEMS(s)\t((sizeof(s))/(sizeof(s[0])))\n#ifndef _POSIX_SEMAPHORES\nstatic struct sembuf\tdev_test[] = {\n\t\t{ 0, 0, IPC_NOWAIT }\t/* test to see if it is free */\n};\nstatic struct sembuf\tdev_lock[] = {\n\t\t{ 0, 0, 0 },\t/* wait for the semaphore to be free */\n\t\t{ 0, 1, SEM_UNDO }\t/* lock it */\n};\nstatic struct sembuf\tdev_unlock[] = {\n\t\t{ 0, -1, (IPC_NOWAIT | SEM_UNDO) }\t/* unlock it */\n};\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    closeDeviceNC\n * Signature: (II)I\n */\nint cygParallelPort_closeDeviceNC\n  (JNIEnv *jenv, jobject jobj, jint fd, jint semId)\n{\n  /* If the semaphore was locked, unlock it. */\n  if (semId != -1) {\n  /* fix debug for POSIX semaphores later */\n#if defined(DEBUG) && !(_POSIX_SEMAPHORES)\n    int iRet;\n\t iRet = semop(semId, dev_unlock, NOOF_ELEMS(dev_unlock));\n    printf( \"Unlock semID %d return value: %d\\n\", semId, iRet );\n     {\n        union semuni scarg;\n        int iVal = 0;\n\t     (void)memset(&scarg, 0, sizeof(scarg));\n   \t  iVal = semctl(semId, 0, GETVAL, scarg);\n        printf( \"semID %d value %d\\n\", semId, iVal );\n        //fflush( stdout );\n     }\n#else\n#ifndef _POSIX_SEMAPHORES\n\t(void)semop(semId, dev_unlock, NOOF_ELEMS(dev_unlock));\n#else\n \t /* don't worry about return right now */\n\t (void)sem_post(sem_lookup(semId));\n#endif /* _POSIX_SEMAPHORES */\n#endif\n  }\n  /* Drain any remaining data. */\n#ifdef NCI\n  (void)ioctl(fd, TIOCDRAIN, NULL);\n#endif\t/* NCI */\n#ifdef __osx__\n  (void)tcdrain(fd);\n#endif\t/* __osx__ */\n#ifdef __linux__\n  (void)tcdrain(fd);\n#endif\t/* __linux__ */\n# ifdef QNX\n  /*** BugBug: tcdrain hangs with parallel. Need to fix.\n  (void)tcdrain(fd);\n   ***/\n#endif /* QNX */\n  return close(fd);\n}\t/* cygParallelPort_closeDeviceNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    openDeviceNC\n * Signature: (Ljava/lang/String;I)I\n */\nint cygParallelPort_openDeviceNC\n  (JNIEnv *jenv, jobject jobj, jstring name, jint semId)\n{\n  const char * dname = NULL;\n  int fd = -1;\n  int sts;\n  dname = (*jenv)->GetStringUTFChars(jenv, name, 0);\n  if( dname == NULL )\n  {\n#ifdef DEBUG\n    printf( \"Can not open port because get NULL name\\n\" );\n#endif\n    return fd;\n  }\n  /* Test the semaphore to see if it is free. If so, lock it.  Else, return\n     a failure. */\n  if (semId != -1) {\n#ifdef _POSIX_SEMAPHORES\n   if(sem_trywait(sem_lookup(semId)) == -1){\n#else \n\tif (semop(semId, dev_test, NOOF_ELEMS(dev_test)) < 0 ||\n\t    semop(semId, dev_lock, NOOF_ELEMS(dev_lock)) < 0) {\n#endif\n#if defined(DEBUG) && !(_POSIX_SEMAPHORES)\n     {\n        union semuni scarg;\n        int iVal = 0;\n\t     (void)memset(&scarg, 0, sizeof(scarg));\n   \t  iVal = semctl(semId, 0, GETVAL, scarg);\n        printf( \"semID %d was locked or can not be locked(value %d)\\n\", semId, iVal );\n        /* fflush( stdout ); */\n     }\n#endif\n\t\t(*jenv)->ReleaseStringUTFChars(jenv, name, dname);\n\t\treturn fd;\n\t}\n  }\n#ifdef DEBUG\n  (void)fprintf(stderr, \"Before opening %s\\n\", dname);\n#endif /* DEBUG */\n  fd = open( dname, O_RDWR | O_NONBLOCK );\n#ifdef DEBUG\n  (void)fprintf(stderr, \"After opening %s; fd = %d\\n\", dname, fd);\n#endif /* DEBUG */\n  /* Turn on blocking mode for the device. */\n  if (fd != -1) {\n     if ((sts = fcntl(fd, F_GETFL, 0)) != -1) {\n\tsts &= ~O_NONBLOCK;\n\t(void)fcntl(fd, F_SETFL, sts);\n     }\n  }\n  (*jenv)->ReleaseStringUTFChars(jenv, name, dname);\n  /* If the open has failed and the semaphore was locked, unlock it. */\n  if (fd == -1 && semId != -1) {\n#ifdef _POSIX_SEMAPHORES\n\t(void) sem_post(sem_lookup(semId));\n#else \n\t(void)semop(semId, dev_unlock, NOOF_ELEMS(dev_unlock));\n#endif\n  }\n  return fd;\n}   /* win32ParallelPort_openDeviceNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPaperOutNC\n * Signature: (I)Z\n */\njboolean cygParallelPort_isPaperOutNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n  int\t\tstatus;\n#ifdef NCI\n  if (ioctl(jfd, PIOCSTATUS, &status) < 0) {\n#endif\t/* NCI */\n#ifdef __osx__          /* ToDo: implement */\n  if (0) {\n#endif\t/* __osx__ */\n#ifdef __linux__\n  if (ioctl(jfd, LPGETSTATUS, &status) < 0) {\n#endif\t/* __linux__ */\n#ifdef QNX          /* ToDo: implement */\n  if (0) {\n#endif /* QNX*/\t\n     (void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_NSParallelPort_isPaperOutNC: ioctl error %d!\\n\", errno);\n     return JNI_FALSE;\n  }\n#ifdef NCI\n  return status & LPS_NOPAPER ? JNI_TRUE : JNI_FALSE;\n#endif\t/* NCI */\n#ifdef __osx__          /* ToDo: implement */\n  return JNI_FALSE;\n#endif\t/* __osx__ */\n#ifdef __linux__\n  return status & LP_POUTPA ? JNI_TRUE : JNI_FALSE;\n#endif\t/* __linux__ */\n#ifdef QNX          /* ToDo: implement */\n  return JNI_FALSE;\n#endif /* QNX*/\t\n}\t/* cygParallelPort_isPaperOutNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterBusyNC\n * Signature: (I)Z\n */\njboolean cygParallelPort_isPrinterBusyNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n  int\t\tstatus;\n#ifdef NCI\n  if (ioctl(jfd, PIOCSTATUS, &status) < 0) {\n#endif\t/* NCI */\n#ifdef __osx__          /* ToDo: implement */\n  if (0) {\n#endif\t/* __osx__ */\n#ifdef __linux__\n  if (ioctl(jfd, LPGETSTATUS, &status) < 0) {\n#endif\t/* __linux__ */\n#ifdef QNX          /* ToDo: implement */\n  if (0) {\n#endif /* QNX*/\t\n     (void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterBusyNC: ioctl error %d!\\n\", errno);\n     return JNI_FALSE;\n  }\n#ifdef NCI\n  return status & LPS_NBSY ? JNI_FALSE : JNI_TRUE;\t/* converse */\n#endif\t/* NCI */\n#ifdef __osx__          /* ToDo: implement */\n  return JNI_FALSE;\n#endif\t/* __osx__ */\n#ifdef __linux__\n  return status & LP_PBUSY ? JNI_FALSE : JNI_TRUE;\t/* converse */\n#endif\t/* __linux__ */\n#ifdef QNX          /* ToDo: implement */\n  return JNI_FALSE;\n#endif /* QNX*/\t\n}\t/* cygParallelPort_isPrinterBusyNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterSelectedNC\n * Signature: (I)Z\n */\njboolean cygParallelPort_isPrinterSelectedNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n  int\t\tstatus;\n#ifdef NCI\n  if (ioctl(jfd, PIOCSTATUS, &status) < 0) {\n#endif\t/* NCI */\n#ifdef __osx__          /* ToDo: implement */\n  if (0) {\n#endif\t/* __osx__ */\n#ifdef __linux__\n  if (ioctl(jfd, LPGETSTATUS, &status) < 0) {\n#endif\t/* __linux__ */\n#ifdef QNX          /* ToDo: implement */\n  if (0) {\n#endif /* QNX*/\t\n     (void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterSelectedNC: ioctl error %d!\\n\", errno);\n     return JNI_FALSE;\n  }\n#ifdef NCI\n  return status & LPS_SELECT ? JNI_FALSE : JNI_TRUE;\t/* converse */\n#endif\t/* NCI */\n#ifdef __osx__          /* ToDo: implement */\n  return JNI_TRUE;\n#endif\t/* __osx__ */\n#ifdef __linux__\n  return status & LP_PSELECD ? JNI_FALSE : JNI_TRUE;\t/* converse */\n#endif\t/* __linux__ */\n#ifdef QNX          /* ToDo: implement */\n  return JNI_TRUE;\n#endif /* QNX*/\t\n}\t/* cygParallelPort_isPrinterSelectedNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterTimedOutNC\n * Signature: (I)Z\n */\njboolean cygParallelPort_isPrinterTimedOutNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n  return JNI_FALSE;\n}\t/* cygParallelPort_isPrinterTimedOutNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterErrorNC\n * Signature: (I)Z\n */\njboolean cygParallelPort_isPrinterErrorNC\n  (JNIEnv *jenv, jobject jobj, jint jfd)\n{\n  int\t\tstatus;\n#ifdef NCI\n  if (ioctl(jfd, PIOCSTATUS, &status) < 0) {\n#endif\t/* NCI */\n#ifdef __osx__          /* ToDo: implement */\n  if (0) {\n#endif\t/* __osx__ */\n#ifdef __linux__\n  if (ioctl(jfd, LPGETSTATUS, &status) < 0) {\n#endif\t/* __linux__ */\n#ifdef QNX          /* ToDo: implement */\n  if (0) {\n#endif /* QNX*/\t\n     (void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterErrorNC: ioctl error %d!\\n\", errno);\n     return JNI_FALSE;\n  }\n#ifdef NCI\n  return status & LPS_NERR ? JNI_FALSE : JNI_TRUE;\t/* converse */\n#endif\t/* NCI */\n#ifdef __osx__          /* ToDo: implement */\n  return JNI_FALSE;\n#endif\t/* __osx__ */\n#ifdef __linux__\n  return status & LP_PERRORP ? JNI_FALSE : JNI_TRUE;\t/* converse */\n#endif\t/* __linux__ */\n#ifdef QNX          /* ToDo: implement */\n  return JNI_FALSE;\n#endif /* QNX*/\t\n}\t/* cygParallelPort_isPrinterErrorNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/cygSerialDataEventThread.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <string.h>\n#include <sys/time.h>\n#include <sys/select.h>\n#include <sys/types.h>\n#include <errno.h>\n#include <unistd.h>\n#include <org_eclipse_soda_dk_comm_SerialDataEventThread.h>\n#define assertexc(s)       if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return;}\nstatic int\tgetPollingTime(JNIEnv *jenv) {\n  int\t\tptime = 5;\n  jclass\tcic;\n  jfieldID\tptID;\n  jint\t\tpt;\n  do {\n\tcic = (*jenv)->FindClass(jenv, \"javax/comm/CommPortIdentifier\");\n\tif (!cic) break;\n\tptID = (*jenv)->GetStaticFieldID(jenv, cic, \"pollingTime\", \"I\");\n\tif (!ptID) break;\n\tpt = (*jenv)->GetStaticIntField(jenv, cic, ptID);\n\tif (pt > 0)\n\t\tptime = pt;\n  } while (0);\n  return ptime;\n}\t// getPollingTime()\nstatic int getStopThreadFlag(JNIEnv *jenv, jobject jobj)\n{\n\tjclass cls;\n\tjfieldID fid;\n\tjint stopThreadFlag;\n\t\n\tcls = (*jenv)->GetObjectClass(jenv, jobj);\n\tif (!cls) (*jenv)->FatalError(jenv, \"Missing class\");\n\t\n\tfid = (*jenv)->GetFieldID(jenv, cls, \"stopThreadFlag\", \"I\");\n\tif (fid == NULL) (*jenv)->FatalError(jenv, \"Missing field\");\n\t\n\tstopThreadFlag = (*jenv)->GetIntField(jenv, jobj, fid);\n\t\n\treturn stopThreadFlag;\t\n} \n/*\n * Class:     org_eclipse_soda_dk_comm_SerialDataEventThread\n * Method:    monitorSerialDataNC\n * Signature: (I)V\n */\nvoid cygSerialDataEventThread_monitorSerialDataNC\n  (JNIEnv *jenv, jobject jobj, jint jfd) {\n    jclass   jspec; /* serial port event class */\n    fd_set  r_mask;\n    jfieldID   data_available_id;      /* field ID */\n        jint   data_available_event;  /* field value */\n        jclass        jc;\n        jmethodID     jm;\n        jfieldID         spID;\n        jobject  jsp;\n        jclass   jspc;\n        jfieldID notifyOnDataAvailableID;\n        jboolean notifyOnDataAvailableFlag = JNI_FALSE;\n        int result;\n\tint\t\tpollingTime;\t/* seconds */\n\tstruct timeval\ttv;\n\tjboolean\t isInterruptedReturn;\n\tjclass\t jthreadClass;\n\tjmethodID\t jintMethod;\n\tjint \t\tstopThreadFlag;\n\tpollingTime = getPollingTime(jenv);\n        jspec = (*jenv)->FindClass(jenv, \"javax/comm/SerialPortEvent\");\n        assertexc(jspec);\n        data_available_id = (*jenv)->GetStaticFieldID(jenv, jspec, \"DATA_AVAILABLE\", \"I\");\n        assertexc(data_available_id);\n        data_available_event = (*jenv)->GetStaticIntField(jenv, jspec, data_available_id);\n        /* Get the serial port object.*/\n        jc = (*jenv)->GetObjectClass(jenv, jobj);\n        assertexc(jc);\n        spID = (*jenv)->GetFieldID(jenv, jc, \"serialPort\", \"Lorg/eclipse/soda/dk/comm/NSSerialPort;\");\n        assertexc(spID);\n        jsp = (*jenv)->GetObjectField(jenv, jobj, spID);\n        assertexc(jsp);\n        /* Get the class ID of the serial port object.*/\n        jspc = (*jenv)->GetObjectClass(jenv, jsp);\n        assertexc(jspc);\n        /* Get access to the method to add a port.*/\n        jm = (*jenv)->GetMethodID(jenv, jspc, \"reportSerialEvent\", \"(IZZ)V\");\n        assertexc(jm);\n        notifyOnDataAvailableID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnDataFlag\", \"Z\");\n        assertexc(notifyOnDataAvailableID);\n\t/* Get access to the interrupted method.*/\n\tjthreadClass = (*jenv)->FindClass(jenv, \"java/lang/Thread\");\n\tassertexc(jthreadClass);\n\tjintMethod = (*jenv)->GetMethodID(jenv, jthreadClass, \"isInterrupted\", \"()Z\");\n\tassertexc(jintMethod);\n   while(1)\n\t {\n\t \t\n\t\tstopThreadFlag = getStopThreadFlag(jenv, jobj);\n\t\tif (stopThreadFlag)\n\t\t\tbreak;\n\t \t\n\t/* check to see if this thread has been interrupted */\n\tisInterruptedReturn = (*jenv)->CallBooleanMethod(jenv,jobj,jintMethod);\n\tif(isInterruptedReturn == JNI_TRUE)\n\t\tbreak;\n\t(void)memset(&tv, 0, sizeof(tv));\n\ttv.tv_sec = pollingTime;\n        FD_ZERO(&r_mask);\n        FD_SET(jfd, &r_mask);\n        result = select(jfd + 1, &r_mask, NULL, NULL, &tv);\n        if (result == -1 && errno != EINTR)\n\t\tbreak;\n\tif (!result)\t// time out\n\t\tcontinue;\n       if (FD_ISSET(jfd, &r_mask))\n\t{\n        notifyOnDataAvailableFlag = (*jenv)->GetBooleanField(jenv, jsp, notifyOnDataAvailableID);\n         if(notifyOnDataAvailableFlag)\n           (*jenv)->CallVoidMethod(jenv, jsp, jm, data_available_event, JNI_TRUE, JNI_TRUE);\n        }\n    }\n} /* cygSerialDataEventThread_monitorSerialDataNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/cygSerialPort.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include \"dkcomm.h\"\n#include <stdio.h>\n#include <string.h>\n#include <fcntl.h>\n#include <errno.h>\n#include <unistd.h>\n#ifdef QNX\n #include <sys/ioctl.h>\n #include <termios.h>\n#endif\n#ifdef NCI\n #include <termios.h>\n#endif\t/* NCI */\n#ifdef __osx__\n #include <sys/ioctl.h>\n #include <termios.h>\n#endif\t/* __osx__ */\n#ifdef __linux__\n //#include <asm/ioctls.h>\n #include <sys/ioctl.h>\n //#include <asm/termios.h>\n #include <termios.h>\n #endif\t/* __linux__ */\n#include <sys/types.h>\n#ifdef _POSIX_SEMAPHORES\n#include <semaphore.h>\n#include \"SysVStyleSemaphore.h\"\n#else \n#include <sys/ipc.h> \n#include <sys/sem.h> \n#endif \n#include <org_eclipse_soda_dk_comm_NSSerialPort.h>\n#define assertexc(s) if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); return(-1);}\n#define NOOF_ELEMS(s)\t((sizeof(s))/(sizeof(s[0])))\n#define DEBUG\n#ifndef _POSIX_SEMAPHORES\nstatic struct sembuf\tdev_test[] = {\n\t\t{ 0, 0, IPC_NOWAIT }\t/* test to see if it is free */\n};\nstatic struct sembuf\tdev_lock[] = {\n\t\t{ 0, 0, 0 },\t/* wait for the semaphore to be free */\n\t\t{ 0, 1, SEM_UNDO }\t/* lock it */\n};\nstatic struct sembuf\tdev_unlock[] = {\n\t\t// { 0, -1, (IPC_NOWAIT | SEM_UNDO) }\t/* unlock it */\n\t\t{ 0, -1,  0  }   \t/* wait til unlock it */\n};\n#endif\nstatic jint getfd(JNIEnv *jenv, jobject jobj)\n  {\n    jclass        jc;\n    jfieldID      jf;\n    jint          fd = -1;\n    // Get the file descriptor.\n    jc = (*jenv)->GetObjectClass(jenv, jobj);\n    assertexc(jc);\n    jf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n    assertexc(jf);\n    fd = (*jenv)->GetIntField(jenv, jobj, jf);\n    return fd;\n  }\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    openDeviceNC\n * Signature: (Ljava/lang/String;I)I\n */\nint cygSerialPort_closeDeviceNC\n  (JNIEnv *jenv, jobject jobj, jint fd, jint semId)\n{\n  /* If the semaphore was locked, unlock it. */\n  if (semId != -1) {\n  /* fix debug for POSIX semaphores later */\n#if defined(DEBUG) && !(_POSIX_SEMAPHORES)\n    int iRet;\n\t iRet = semop(semId, dev_unlock, NOOF_ELEMS(dev_unlock));\n    printf( \"Unlock semID %d return value: %d\\n\", semId, iRet );\n     {\n        union semuni scarg;\n        int iVal = 0;\n\t     (void)memset(&scarg, 0, sizeof(scarg));\n   \t  iVal = semctl(semId, 0, GETVAL, scarg);\n        printf( \"semID %d value %d\\n\", semId, iVal );\n        //fflush( stdout );\n     }\n#else\n#ifndef _POSIX_SEMAPHORES\n\t (void)semop(semId, dev_unlock, NOOF_ELEMS(dev_unlock));\n#else\n \t /* don't worry about return right now */\n\t (void)sem_post(sem_lookup(semId));\n#endif /* _POSIX_SEMAPHORES */\n#endif\n  }\n  /* Drain any remaining data. */\n#ifdef NCI\n  (void)ioctl(fd, TIOCDRAIN, NULL);\n#endif\t/* NCI */\n#if defined(__linux__) || defined(__osx__)\n  (void)tcdrain(fd);\n#endif\t/* __linux__ */\n# ifdef QNX\n  (void)tcdrain(fd);\n#endif /* QNX */\n  return close(fd);\n}\t/* cygSerialPort_closeDeviceNC */\nint cygSerialPort_openDeviceNC\n  (JNIEnv *jenv, jobject jobj, jstring name, jint semId)\n{\n  sem_t * local_sem;\n  const char * dname = NULL;\n  int fd = -1;\n  int sts;\n  dname = (*jenv)->GetStringUTFChars(jenv, name, 0);\n  if( dname == NULL )\n  {\n\n    printf( \"Can not open port because get NULL name\\n\" );\n\n    return fd;\n  }\n  /* Test the semaphore to see if it is free. If so, lock it.  Else, return\n     a failure. */\n  if (semId != -1) {\n#ifdef _POSIX_SEMAPHORES\n   if(sem_trywait(sem_lookup(semId)) == -1){\n#else \n\tif (semop(semId, dev_test, NOOF_ELEMS(dev_test)) < 0 ||\n\t    semop(semId, dev_lock, NOOF_ELEMS(dev_lock)) < 0) {\n#endif\n#if defined(DEBUG) && !(_POSIX_SEMAPHORES)\n     {\n        union semuni scarg;\n        int iVal = 0;\n\t     (void)memset(&scarg, 0, sizeof(scarg));\n   \t  iVal = semctl(semId, 0, GETVAL, scarg);\n        printf( \"semID %d was locked or can not be locked(value %d)\\n\", semId, iVal );\n        /* fflush( stdout ); */\n     }\n#endif\n\t\t(*jenv)->ReleaseStringUTFChars(jenv, name, dname);\n\t\treturn fd;\n\t}\n  }\n\n  printf(\"Before opening %s\\n\", dname);\n\n  fd = open( dname, O_RDWR | O_NONBLOCK );\n\n  printf(\"After opening %s; fd = %d\\n\", dname, fd);\n\n  /* Turn on blocking mode for the device. */\n  if (fd != -1) {\n     if ((sts = fcntl(fd, F_GETFL, 0)) != -1) {\n\t\tsts &= ~O_NONBLOCK;\n\t\t(void)fcntl(fd, F_SETFL, sts);\n     }\n  }\n#define SMARTCARD\n#ifdef SMARTCARD\n  /* For SmartCard, set it to clocal, enable reader and turn off\n     flow control. */\n  if (fd != -1) {\n\tstruct termios\t\tio;\n\tif (tcgetattr(fd, &io) == -1)\n\t\t\tprintf(\"tcgetattr() failed on %s(%d)!\\n\", dname, errno);\n\telse {\n   \t\tio.c_iflag &= ~(IXOFF | IXON | INLCR | ICRNL | IGNCR);\n   \t\tio.c_oflag &= ~(OPOST | OCRNL | ONLCR | ONOCR | ONLRET);\n#ifdef NCI\n   \t\tio.c_cflag &= ~(CRTS_IFLOW | CCTS_OFLOW);\n#endif\t/* NCI */\n#ifdef __linux__\n   \t\tio.c_cflag &= ~(CRTSCTS);\n#endif\t/* __linux__ */\n#ifdef __osx__\n\t\tio.c_cflag &= ~(CRTSCTS);\n#endif\n#ifdef QNX\n\t\tio.c_cflag &=~(IHFLOW | OHFLOW);\n#endif /* QNX */\t\t\n\t\tio.c_cflag |= (CLOCAL | CREAD);\n\t\tio.c_lflag &= ~ICANON;\t/* turn off cannonical processing */\n\t\t/* turn off echoing */\n\t\tio.c_lflag &= ~(ECHO | ECHOKE | ECHOE | ECHOCTL);\n\t\tio.c_lflag &= ~ISIG;\n\t\tio.c_cc[VMIN] = 1;\n\t\tio.c_cc[VTIME] = 0;\n\t\tif (tcsetattr(fd, TCSANOW, &io) == -1)\n\t\t\tprintf(\"tcsetattr() failed on %s!\\n\", dname);\n#if 0\n\t\telse\n\t\t\tprintf(\"tcsetattr() set clocal, cread and no flow control on %s!\\n\", dname);\n\t\t\t/*fprintf(stderr, \"tcsetattr() set clocal, cread and no flow control on %s!\\n\", dname); */\n\t\t\t\n#endif\t/* 0 */\n\t}\n  }\n#endif\n  (*jenv)->ReleaseStringUTFChars(jenv, name, dname);\n  /* If the open has failed and the semaphore was locked, unlock it. */\n  if (fd == -1 && semId != -1) {\n#ifdef _POSIX_SEMAPHORES\n\t(void)sem_post(sem_lookup(semId));\n#else \n\t(void)semop(semId, dev_unlock, NOOF_ELEMS(dev_unlock));\n#endif  \n  }\n  return fd;\n}    /* cygSerialPort_openDeviceNC */\nint cygSerialPort_setFlowControlModeNC\n  (JNIEnv *jenv, jobject jobj, jint fd, jint fc )\n{\n  int\t\t\tfm = -1;\n  int\t\t\trc;\n  struct termios\tios;\n  if ((rc = tcgetattr(fd, &ios)) == -1)\n     return fm;\n  /* Now set the desired flow control.  Turn off the other exclusive flow\n     control mode.\n   */\n  /* In fact, set the flow control completely based on the flags just passed\n     in.   That means, turn off all flow control modes that were set earlier.\n   */\n  ios.c_iflag &= ~(IXOFF | IXON);\n#ifdef NCI\n  ios.c_cflag &= ~(CRTS_IFLOW | CCTS_OFLOW);\n#endif\t/* NCI */\n#if defined(__linux__) || defined(__osx__)\n  ios.c_cflag &= ~(CRTSCTS);\n#endif\t/* __linux__ */\n#ifdef QNX\n  ios.c_cflag &=~(IHFLOW | OHFLOW);\n#endif /* QNX */  \n  if (fc == 0) {\t\t\t// NONE\n     /* Do nothing, as all the flow control modes are already turned off now. */\n  }\n  else {\n     if (fc & 1) {\t\t// RTSCTS_IN\n\t// ios.c_iflag &= ~IXOFF;\n#ifdef NCI\n\tios.c_cflag |= CRTS_IFLOW;\n#endif\t/* NCI */\n#if defined(__linux__) || defined(__osx__)\n\tios.c_cflag |= CRTSCTS;\n#endif\t/* __linux__ */\n#ifdef QNX\n\tios.c_cflag |=IHFLOW;\n#endif /* QNX */\t\n     }\n     if (fc & 2) {\t\t// RTSCTS_OUT\n\t// ios.c_iflag &= ~IXON;\n#ifdef NCI\n\tios.c_cflag |= CCTS_OFLOW;\n#endif\t/* NCI */\n#if defined(__linux__) || defined(__osx__)\n\tios.c_cflag |= CRTSCTS;\n#endif\t/* __linux__ */\n#ifdef QNX\n\tios.c_cflag |= OHFLOW;\n#endif /* QNX*/\t\n     }\n     if (fc & 4) {\t\t// XONXOFF_IN\n\t// ios.c_cflag &= ~CRTS_IFLOW;\n\tios.c_iflag |= IXOFF;\n     }\n     if (fc & 8) {\t\t// XONXOFF_OUT\n\t// ios.c_cflag &= ~CCTS_OFLOW;\n\tios.c_iflag |= IXON;\n     }\n  }\n  if ((rc = tcsetattr(fd, TCSANOW, &ios)) != -1)\n     fm = fc;\n  return fm;\n}   /* cygSerialPort_setFlowControlModeNC */\nint cygSerialPort_getFlowControlModeNC\n  (JNIEnv *jenv, jobject jobj, jint fd )\n{\n  struct termios \tios;\n  int\t\t\trc;\n  int\t\t\tfm = -1;\n  if ((rc = tcgetattr(fd, &ios)) == -1)\n     return fm;\n  // Determine the flow control.\n#ifdef NCI \n  if ((!(ios.c_cflag & CRTS_IFLOW) && !(ios.c_cflag & CCTS_OFLOW)) &&\n#endif\t/* NCI */\n#ifdef __osx__\n  if ((!(ios.c_cflag & CRTSCTS)) &&\n#endif\t/* __osx__ */\n#ifdef __linux__ \n  if ((!(ios.c_cflag & CRTSCTS)) &&\n#endif\t/* __linux__ */\n#ifdef QNX\n  if ((!(ios.c_cflag & IHFLOW) && !(ios.c_cflag & OHFLOW)) &&\n#endif /* QNX */\n      (!(ios.c_iflag & IXON) && !(ios.c_iflag & IXOFF)))\n     fm = 0;\t\t\t\t// NONE\n  else {\n     fm = 0;\n#ifdef NCI\n     if (ios.c_cflag & CRTS_IFLOW)\t// RTSCTS_IN\n#endif\t/* NCI */\n#ifdef __osx__\n     if (ios.c_cflag & CRTSCTS)\t\t// RTSCTS_IN\n#endif\t/* __osx__ */\n#ifdef __linux__ \n     if (ios.c_cflag & CRTSCTS)\t\t// RTSCTS_IN\n#endif\t/* __linux__ */\n#ifdef QNX\n     if (ios.c_cflag & IHFLOW)\n#endif /* QNX */     \n        fm |= 1;\n#ifdef NCI\n     if (ios.c_cflag & CCTS_OFLOW)\t// RTSCTS_OUT\n#endif\t/* NCI */\n#ifdef __osx__ \n     if (ios.c_cflag & CRTSCTS)\t\t// RTSCTS_IN\n#endif\t/* __osx__ */\n#ifdef __linux__ \n     if (ios.c_cflag & CRTSCTS)\t\t// RTSCTS_IN\n#endif\t/* __linux__ */\n#ifdef QNX\n     if (ios.c_cflag & OHFLOW)\n#endif /* QNX */     \n        fm |= 2;\n     if (ios.c_iflag & IXOFF)\t\t// XONXOFF_IN\n        fm |= 4;\n     if (ios.c_iflag & IXON)\t\t// XONXOFF_OUT\n        fm |= 8;\n  }\n  \n  return fm;\n}   /* cygSerialPort_getFlowControlModeNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getBaudRateNC\n * Signature: (I)I\n */\nint cygSerialPort_getBaudRateNC\n  (JNIEnv *jenv, jobject jobj, jint fd)\n{\n  struct termios ios;\n  int rc = -1;\n  speed_t sp;\n#ifdef DEBUG\n  printf( \"getBaudRateNC\\n\" );\n  /* fflush( stdout ); */\n#endif\n (void)memset(&ios, 0, sizeof(ios));\n#ifdef DEBUG\n  printf( \"tcgetattr()\\n\" );\n  /* fflush( stdout ); */\n#endif\n rc = tcgetattr(fd, &ios);\n if ( rc ==  -1 ) return rc;\n#ifdef DEBUG\n  printf( \"cfgetospeed()\\n\" );\n  /* fflush( stdout ); */\n#endif\n sp = cfgetospeed( &ios );\n#if defined(__linux__) || defined(__osx__)\n /* Map the internal value to external speed. */\n#ifdef DEBUG\n  printf( \"sp %d\\n\",sp);\n  /*fflush( stdout ); */\n#endif\n switch((int)sp) {\n    case B50:\t\tsp = 50; break;\n    case B75:\t\tsp = 75; break;\n    case B110:\t\tsp = 110; break;\n    case B134:\t\tsp = 134; break;\n    case B150:\t\tsp = 150; break;\n    case B200:\t\tsp = 200; break;\n    case B300:\t\tsp = 300; break;\n    case B600:\t\tsp = 600; break;\n    case B1200:\t\tsp = 1200; break;\n    case B1800:\t\tsp = 1800; break;\n    case B2400:\t\tsp = 2400; break;\n    case B4800:\t\tsp = 4800; break;\n    case B9600:\t\tsp = 9600; break;\n    case B19200:\tsp = 19200; break;\n    case B38400:\tsp = 38400; break;\n    case B57600:\tsp = 57600; break;\n    case B115200:\tsp = 115200; break;\n    case B230400:\tsp = 230400; break;\n }\n#ifdef DEBUG\n  printf( \" new sp %d\\n\", sp);\n  /* fflush( stdout ); */\n#endif\n#endif\t/* __linux__ */\n return (jint) sp;\n}   /* cygSerialPort_getFlowControlModeNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getDataBitsNC\n * Signature: (I)I\n */\nint cygSerialPort_getDataBitsNC(JNIEnv *jenv, jobject jobj, jint fd)\n{\n  struct termios ios;\n  int rc = -1;\n  rc = tcgetattr(fd, &ios);\n  if ( rc ==  -1 ) return (jint) rc;\n  rc = ios.c_cflag & CSIZE;\n  switch ( rc )\n  {\n    case CS5:\n      return (jint) 5;\n    break;\n    case CS6:\n      return (jint) 6;\n    break;\n    case CS7:\n      return (jint) 7;\n    break;\n    case CS8:\n      return (jint) 8;\n    break;\n    default:\n      return (jint) -1;\n  }\n  return (jint) rc;\n} /* cygSerialPort_getDataBitsNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getStopBitsNC\n * Signature: (I)I\n */\nint cygSerialPort_getStopBitsNC(JNIEnv *jenv, jobject jobj, jint fd)\n{\n  struct termios ios;\n  int rc = -1;\n  rc = tcgetattr(fd, &ios);\n  if ( rc ==  -1 ) return (jint) rc;\n  if ( ios.c_cflag & CSTOPB )\n    rc = 2;\n  else\n    rc = 1;\n  return (jint) rc;\n}  /* cygSerialPort_getStopBitsNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getParityNC\n * Signature: (I)I\n */\nint cygSerialPort_getParityNC(JNIEnv *jenv, jobject jobj, jint fd)\n{\n  struct termios ios;\n  int rc = -1;\n  int NONE = 0, ODD = 1, EVEN = 2;\n  rc = tcgetattr(fd, &ios);\n  if ( rc ==  -1 ) return (jint) rc;\n  if ( ios.c_cflag & PARENB )\n  {\n    if ( ios.c_cflag & PARODD )\n      rc = ODD;\n    else\n      rc = EVEN;\n  } else\n    rc = NONE; // PARITY_NONE\n#ifdef DEBUG\n  /*fprintf(stderr, \"getParityNC:  parity = %d\\n\", rc); */\n#endif /* DEBUG */\n  return (jint) rc;\n}  /* cygSerialPort_getParityNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setDTRNC\n * Signature: (Z)V\n */\nvoid cygSerialPort_setDTRNC(JNIEnv *jenv, jobject jobj, jint fd, jboolean bool)\n{\n    int jdtr;\n    int rc = -1;\n    fd = -1;\n    fd = getfd( jenv, jobj );\n    rc = ioctl( fd, TIOCMGET, &jdtr );\n    if ( rc ==  -1 ) return;\n    if ( bool == JNI_TRUE )\n      jdtr |= TIOCM_DTR;\n    else\n      jdtr &= ~TIOCM_DTR;\n    rc = ioctl( fd, TIOCMSET, &jdtr );\n}  /* cygSerialPort_setDTRNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isDTRNC\n * Signature: ()Z\n */\njboolean cygSerialPort_isDTRNC(JNIEnv *jenv, jobject jobj)\n{\n    int jdtr;\n    int rc = -1;\n    jint fd = -1;\n    fd = getfd( jenv, jobj );\n    rc = ioctl( fd, TIOCMGET, &jdtr );\n    if ( rc ==  -1 ) return (jboolean)JNI_FALSE;\n    if ( jdtr & TIOCM_DTR )\n      return (jboolean)JNI_TRUE;\n    else\n      return (jboolean)JNI_FALSE;\n}  /* cygSerialPort_isDTRNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setRTSNC\n * Signature: (Z)V\n */\nvoid cygSerialPort_setRTSNC(JNIEnv *jenv, jobject jobj, jboolean bool)\n{\n    int jrts;\n    int rc = -1;\n    jint fd = -1;\n    fd = getfd( jenv, jobj );\n    rc = ioctl( fd, TIOCMGET, &jrts );\n    if ( rc ==  -1 ) return;\n    if ( bool == JNI_TRUE )\n      jrts |= TIOCM_RTS;\n    else\n      jrts &= ~TIOCM_RTS;\n    rc = ioctl( fd, TIOCMSET, &jrts );\n}  /* cygSerialPort_setRTSNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isRTSNC\n * Signature: ()Z\n */\njboolean cygSerialPort_isRTSNC(JNIEnv *jenv, jobject jobj)\n{\n    int jrts;\n    int rc = -1;\n    jint fd = -1;\n    fd = getfd( jenv, jobj );\n    rc = ioctl( fd, TIOCMGET, &jrts );\n    if ( rc ==  -1 ) return (jboolean) JNI_FALSE;\n    if ( jrts & TIOCM_RTS )\n      return (jboolean) JNI_TRUE;\n    else\n      return (jboolean) JNI_FALSE;\n}  /* cygSerialPort_isRTSNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isCTSNC\n * Signature: ()Z\n */\njboolean cygSerialPort_isCTSNC(JNIEnv *jenv, jobject jobj)\n{\n    int jcts;\n    int rc = -1;\n    jint fd = -1;\n    fd = getfd( jenv, jobj );\n    rc = ioctl( fd, TIOCMGET, &jcts );\n    if ( rc ==  -1 ) return (jboolean) JNI_FALSE;\n    if ( jcts & TIOCM_CTS )\n      return (jboolean) JNI_TRUE;\n    else\n      return (jboolean) JNI_FALSE;\n}  /* cygSerialPort_isCTSNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isDSRNC\n * Signature: ()Z\n */\njboolean cygSerialPort_isDSRNC(JNIEnv *jenv, jobject jobj)\n{\n    int jdsr;\n    int rc = -1;\n    jint fd = -1;\n    fd = getfd( jenv, jobj );\n    rc = ioctl( fd, TIOCMGET, &jdsr );\n    if ( rc ==  -1 ) return (jboolean) JNI_FALSE;\n    if ( jdsr & TIOCM_CTS )\n      return (jboolean) JNI_TRUE;\n    else\n      return (jboolean) JNI_FALSE;\n}  /* cygSerialPort_isDSRNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isRINC\n * Signature: ()Z\n */\njboolean cygSerialPort_isRINC(JNIEnv *jenv, jobject jobj)\n{\n    int jrng;\n    int rc = -1;\n    jint fd = -1;\n    fd = getfd( jenv, jobj );\n    rc = ioctl( fd, TIOCMGET, &jrng );\n    if ( rc ==  -1 ) return (jboolean) JNI_FALSE;\n    if ( jrng & TIOCM_RNG )\n      return (jboolean) JNI_TRUE;\n    else\n      return (jboolean) JNI_FALSE;\n}  /* cygSerialPort_isRINC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isCDNC\n * Signature: ()Z\n */\njboolean cygSerialPort_isCDNC(JNIEnv *jenv, jobject jobj)\n{\n    int jcd;\n    int rc = -1;\n    jint fd = -1;\n    fd = getfd( jenv, jobj );\n    rc = ioctl( fd, TIOCMGET, &jcd );\n    if ( rc ==  -1 ) return (jboolean) JNI_FALSE;\n    if ( jcd & TIOCM_CD )\n      return (jboolean) JNI_TRUE;\n    else\n      return (jboolean) JNI_FALSE;\n}  /* cygSerialPort_isCDNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    sendBreakNC\n * Signature: (II)I\n */\nint cygSerialPort_sendBreakNC(JNIEnv *jenv, jobject jobj, jint jfd, jint jmillis) {\n   (void)tcsendbreak(jfd, jmillis);\n} /* Java_org_eclipse_soda_dk_comm_NSSerialPort_sendBreakNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setSerialPortParamsNC\n * Signature: (IIIII)I\n */\nint cygSerialPort_setSerialPortParamsNC\n  (JNIEnv *jenv, jobject jobj, jint jfd, jint jbd, jint jdb, jint jsb, jint jpar) {\n  int\t\t\trc;\n  struct termios \tios;\n  speed_t\t\tspd;\n  if ((rc = tcgetattr(jfd, &ios)) == -1)\n     return rc;\n  // Set the baud rate.\n  spd = jbd;\n#ifdef QNX  /* put in by daniel */\n   if ((rc = cfsetospeed(&ios, spd)) == -1)\n     return rc;\n\tif ((rc = cfsetispeed(&ios, spd)) == -1)\n     return rc;\n#else\n  if ((rc = cfsetspeed(&ios, spd)) == -1)\n     return rc;\n#endif \n  // Set the data bits.\n  switch(jdb) {\n     case 5:\t\t// DATABITS_5\n\tios.c_cflag &= ~CSIZE;\n\tios.c_cflag |= CS5;\n\tbreak;\n     case 6:\t\t// DATABITS_6\n\tios.c_cflag &= ~CSIZE;\n\tios.c_cflag |= CS6;\n\tbreak;\n     case 7:\t\t// DATABITS_7\n\tios.c_cflag &= ~CSIZE;\n\tios.c_cflag |= CS7;\n\tbreak;\n     case 8:\t\t// DATABITS_8\n\tios.c_cflag &= ~CSIZE;\n\tios.c_cflag |= CS8;\n\tbreak;\n  }\n  // Set the stop bits. 1.5 is not supported.\n  switch (jsb) {\n     case 1:\t\t// STOPBITS_1\n\tios.c_cflag &= ~CSTOPB;\n\tbreak;\n     case 2:\t\t// STOPBITS_2\n\tios.c_cflag |= CSTOPB;\n\tbreak;\n  }\n  // Set the parity.  MARK and SPACE are not supported.\n  switch (jpar) {\n     case 0:\t\t// PARITY_NONE\n#ifdef DEBUG\n\t/* fprintf(stderr, \"setSerialPortParamsNC: parity set to %s\\n\", \"NONE\"); */\n#endif /* DEBUG */\n\tios.c_cflag &= ~PARENB;\n\tbreak;\n     case 1:\t\t// PARITY_ODD\n#ifdef DEBUG\n\t/* fprintf(stderr, \"setSerialPortParamsNC: parity set to %s\\n\", \"ODD\"); */\n#endif /* DEBUG */\n\tios.c_cflag |= PARENB;\n\tios.c_cflag |= PARODD;\n\tbreak;\n     case 2:\t\t// PARITY_EVEN\n#ifdef DEBUG\n\t/* fprintf(stderr, \"setSerialPortParamsNC: parity set to %s\\n\", \"EVEN\"); */\n#endif /* DEBUG */\n\tios.c_cflag |= PARENB;\n\tios.c_cflag &= ~PARODD;\n  }\n  // Now set the desired communication characteristics.\n  rc = tcsetattr(jfd, TCSANOW, &ios);\n  return rc;\n} /* cygSerialPort_setSerialPortParamsNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/cygSerialStatusEventThread.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <errno.h>\n#include <sys/ioctl.h>\n#include <org_eclipse_soda_dk_comm_SerialStatusEventThread.h>\n#define assertexc(s)       if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return;}\nstatic int\tgetPollingTime(JNIEnv *jenv) {\n  int\t\tptime = 5;\n  jclass\tcic;\n  jfieldID\tptID;\n  jint\t\tpt;\n  do {\n\tcic = (*jenv)->FindClass(jenv, \"javax/comm/CommPortIdentifier\");\n\tif (!cic) break;\n\tptID = (*jenv)->GetStaticFieldID(jenv, cic, \"pollingTime\", \"I\");\n\tif (!ptID) break;\n\tpt = (*jenv)->GetStaticIntField(jenv, cic, ptID);\n\tif (pt > 0)\n\t\tptime = pt;\n  } while (0);\n  return ptime;\n}\t// getPollingTime()\nstatic int getStopThreadFlag(JNIEnv *jenv, jobject jobj)\n{\n\tjclass cls;\n\tjfieldID fid;\n\tjint stopThreadFlag;\n\t\n\tcls = (*jenv)->GetObjectClass(jenv, jobj);\n\tif (!cls) (*jenv)->FatalError(jenv, \"Missing class\");\n\t\n\tfid = (*jenv)->GetFieldID(jenv, cls, \"stopThreadFlag\", \"I\");\n\tif (fid == NULL) (*jenv)->FatalError(jenv, \"Missing field\");\n\t\n\tstopThreadFlag = (*jenv)->GetIntField(jenv, jobj, fid);\n\t\n\treturn stopThreadFlag;\t\n} \n/*\n * Class:     org_eclipse_soda_dk_comm_SerialStatusEventThread\n * Method:    monitorSerialStatusNC\n * Signature: (I)V\n */\nvoid cygSerialStatusEventThread_monitorSerialStatusNC(JNIEnv *jenv, jobject jobj, jint jfd) {\n\tint\t\tpollingTime;\t/* seconds */\n\tint oldStatus, newStatus;\n\tjfieldID notifyOnCDID, notifyOnCTSID;\n\tjfieldID notifyOnDSRID, notifyOnRIID;\n\tjboolean notifyOnCDFlag = JNI_FALSE;\n\tjboolean notifyOnCTSFlag = JNI_FALSE;\n\tjboolean notifyOnDSRFlag = JNI_FALSE;\n\tjboolean notifyOnRIFlag = JNI_FALSE;\n\tjclass        jc;\n\tjmethodID     jm;\n\tjclass\t jspc;\n\tjfieldID \t spID;\n\tjobject\t jsp;\n\tjboolean\t isInterruptedReturn;\n\tjclass\t jspec;\t/* serial port event class */\n\tjfieldID\t speCDID,speCTSID, speDSRID, speRIID ;\t/* field ID */\n\tjint\t\t speCD, speCTS, speDSR, speRI;\t/* field value */\n\tjmethodID\t jintMethod;\n\tjclass\t jthreadClass;\n\tjint \t\tstopThreadFlag;\n\t\n\tpollingTime = getPollingTime(jenv);\n\t/* Get the const values for all the serial port event types.*/\n\tjspec = (*jenv)->FindClass(jenv, \"javax/comm/SerialPortEvent\");\n\tassertexc(jspec);\n\tspeCDID = (*jenv)->GetStaticFieldID(jenv, jspec, \"CD\", \"I\");\n\tassertexc(speCDID);\n\tspeCD = (*jenv)->GetStaticIntField(jenv, jspec, speCDID);\n\tspeCTSID = (*jenv)->GetStaticFieldID(jenv, jspec, \"CTS\", \"I\");\n\tassertexc(speCTSID);\n\tspeCTS = (*jenv)->GetStaticIntField(jenv, jspec, speCTSID);\n\tspeDSRID = (*jenv)->GetStaticFieldID(jenv, jspec, \"DSR\", \"I\");\n\tassertexc(speDSRID);\n\tspeDSR = (*jenv)->GetStaticIntField(jenv, jspec, speDSRID);\n\tspeRIID = (*jenv)->GetStaticFieldID(jenv, jspec, \"RI\", \"I\");\n\tassertexc(speRIID);\n\tspeRI = (*jenv)->GetStaticIntField(jenv, jspec, speRIID);\n\t/* Get the serial port object.*/\n\tjc = (*jenv)->GetObjectClass(jenv, jobj);\n\tassertexc(jc);\n\tspID = (*jenv)->GetFieldID(jenv, jc, \"serialPort\", \"Lorg/eclipse/soda/dk/comm/NSSerialPort;\");\n\tassertexc(spID);\n\tjsp = (*jenv)->GetObjectField(jenv, jobj, spID);\n\tassertexc(jsp);\n\t/* Get the class ID of the serial port object.*/\n\tjspc = (*jenv)->GetObjectClass(jenv, jsp);\n\tassertexc(jspc);\n\tnotifyOnCDID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnCDFlag\", \"Z\");\n\tassertexc(notifyOnCDID);\n\tnotifyOnCTSID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnCTSFlag\", \"Z\");\n\tassertexc(notifyOnCTSID);\n\tnotifyOnDSRID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnDSRFlag\", \"Z\");\n\tassertexc(notifyOnDSRID);\n\tnotifyOnRIID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnRIFlag\", \"Z\");\n\tassertexc(notifyOnRIID);\n\t/* Get access to the method to add a port.*/\n\tjm = (*jenv)->GetMethodID(jenv, jspc, \"reportSerialEvent\", \"(IZZ)V\");\n\tassertexc(jm);\n\t/* Get access to the interrupted method.*/\n\tjthreadClass = (*jenv)->FindClass(jenv, \"java/lang/Thread\");\n\tassertexc(jthreadClass);\n\tjintMethod = (*jenv)->GetMethodID(jenv, jthreadClass, \"isInterrupted\", \"()Z\");\n\tassertexc(jintMethod);\n\tif (ioctl(jfd, TIOCMGET, &oldStatus) < 0) {\n\t\t(void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_SerialStatusEventThread_monitorSerialStatusNC: ioctl error %d!\\n\", errno);\n\t\treturn;\n\t}\n\twhile(1)\n\t{\n\t\tsleep(pollingTime);\n\t\tstopThreadFlag = getStopThreadFlag(jenv, jobj);\n\t\tif (stopThreadFlag)\n\t\t\tbreak;\n\t\t/* check to see if this thread has been interrupted */\n\t\tisInterruptedReturn = (*jenv)->CallBooleanMethod(jenv,jobj,jintMethod);\n\t\tif(isInterruptedReturn == JNI_TRUE)\n\t\t\tbreak;\n\t\tnotifyOnCDFlag = (*jenv)->GetBooleanField(jenv, jsp, notifyOnCDID);\n\t\tnotifyOnCTSFlag = (*jenv)->GetBooleanField(jenv, jsp, notifyOnCTSID);\n\t\tnotifyOnDSRFlag = (*jenv)->GetBooleanField(jenv, jsp, notifyOnDSRID);\n\t\tnotifyOnRIFlag = (*jenv)->GetBooleanField(jenv, jsp, notifyOnRIID);\n\t\tif (ioctl(jfd, TIOCMGET, &newStatus) < 0) {\n\t\t\t(void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_SerialStatusEventThread_monitorSerialStatusNC: ioctl error %d!\\n\", errno);\n\t\t\treturn;\n\t\t}\n\t\tif (newStatus == oldStatus)\n\t\t\tcontinue;\n\t\tif((newStatus & TIOCM_CD) != (oldStatus & TIOCM_CD))\n\t\t{\n\t\t\tif(notifyOnCDFlag)        /* need to use jsp to access this field */\n\t\t\t\t(*jenv)->CallVoidMethod(jenv, jsp, jm, speCD,\n\t\t\t\t    (oldStatus & TIOCM_CD)? JNI_TRUE:JNI_FALSE,(newStatus & TIOCM_CD)? JNI_TRUE:JNI_FALSE);\n\t\t}\n\t\tif((newStatus & TIOCM_CTS) != (oldStatus & TIOCM_CTS))\n\t\t{\n\t\t\tif(notifyOnCTSFlag)\n\t\t\t\t(*jenv)->CallVoidMethod(jenv, jsp, jm, speCTS,\n\t\t\t\t    (oldStatus & TIOCM_CTS)? JNI_TRUE:JNI_FALSE,(newStatus & TIOCM_CTS)? JNI_TRUE:JNI_FALSE);\n\t\t}\n\t\tif((newStatus & TIOCM_DSR) != (oldStatus & TIOCM_DSR))\n\t\t{\n\t\t\tif(notifyOnDSRFlag)\n\t\t\t\t(*jenv)->CallVoidMethod(jenv, jsp, jm, speDSR,\n\t\t\t\t    (oldStatus & TIOCM_DSR)? JNI_TRUE:JNI_FALSE,(newStatus & TIOCM_DSR)? JNI_TRUE:JNI_FALSE);\n\t\t}\n\t\tif((newStatus & TIOCM_RI) != (oldStatus & TIOCM_RI))\n\t\t{\n\t\t\tif(notifyOnRIFlag)\n\t\t\t\t(*jenv)->CallVoidMethod(jenv, jsp, jm, speRI,\n\t\t\t\t    (oldStatus & TIOCM_RI)? JNI_TRUE:JNI_FALSE,(newStatus & TIOCM_RI)? JNI_TRUE:JNI_FALSE);\n\t\t}\n\t\toldStatus = newStatus;\n\t}\t/* end of while() */\n} /* cygSerialStatusEventThread_monitorSerialStatusNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/dkcomm.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nunion semuni {\n  int val;                   /* value for SETVAL             */\n  struct semid_ds *buf;      /* buffer for IPC_STAT, IPC_SET */\n  unsigned short int *array; /* array for GETALL, SETALL     */\n  struct seminfo *__buf;     /* buffer for IPC_INFO          */\n};\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/dkcomm22.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nunion semuni {\n  int val;                   /* value for SETVAL             */\n  struct semid_ds *buf;      /* buffer for IPC_STAT, IPC_SET */\n  unsigned short int *array; /* array for GETALL, SETALL     */\n  struct seminfo *__buf;     /* buffer for IPC_INFO          */\n};\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/javax_comm_CommPortIdentifier.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <jni.h>\n/* Header for class javax_comm_CommPortIdentifier */\n#ifndef _Included_javax_comm_CommPortIdentifier\n#define _Included_javax_comm_CommPortIdentifier\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#undef javax_comm_CommPortIdentifier_pollingTime\n#define javax_comm_CommPortIdentifier_pollingTime 1L\n#undef javax_comm_CommPortIdentifier_PORT_SERIAL\n#define javax_comm_CommPortIdentifier_PORT_SERIAL 1L\n#undef javax_comm_CommPortIdentifier_PORT_PARALLEL\n#define javax_comm_CommPortIdentifier_PORT_PARALLEL 2L\n/*\n * Class:     javax_comm_CommPortIdentifier\n * Method:    monitorInterVMDeviceAccessNC\n * Signature: (Ljava/lang/Runnable;)I\n */\nJNIEXPORT jint JNICALL Java_javax_comm_CommPortIdentifier_monitorInterVMDeviceAccessNC\n  (JNIEnv *, jobject, jobject);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nDLLNAME=Release/win32/x86/dkcomm22.dll\nall: \n\t@echo \"Usage: make platform\"    ;\n\t@echo \"\tWhere platform = linux | qnx\" ;\nlinux:\n\t$(MAKE) -f makefile.linux\nqnx:\n\t$(MAKE) -f makefile.qnx\n\t\nclean:\n\trm -f *.o\n\trm -f *.obj\n\trm -f $(DLLNAME)\n\t\t\n\t\n\t\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.linux",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nMAKEFILE = makefile.linux\n############################################################################################################\n#       Configure your OS, CPUTYPE and COMPILER \n############################################################################################################\nOS  = Linux\n##OS=Qnx\nCPUTYPE = i386\n##CPUTYPE = powerpc\n##CPUTYPE = ppc82xx\n##CPUTYPE = ppc440gp\n##CPUTYPE = xscale\n##CPUTYPE = mips\n##CPUTYPE = sh4\n##CPUTYPE = ibm44gp\nLIBTYPE = so                   \n##LIBTYPE = a\nDATATYPE = le\n##DATATYPE = be\n##COMPILER = kenati\n##COMPILER = ydog\n##COMPILER = mvlpee31\n##COMPILER = mvlcee31\n##COMPILER = mvlarm\n##COMPILER = coyote\n##BOARDTYPE = Mainstone\n##BOARDTYPE = Walnut\n##BOARDTYPE = Malta\n##BOARDTYPE = Sandpoint\n##BOARDTYPE = Solution\n############################################################################################################\n#\n#       Release the libdkcomm.so file place\n#\n############################################################################################################\nDLLNAME=Release/$(OS)/$(CPUTYPE)_$(COMPILER)/libdkcomm.$(LIBTYPE)\nBUILDFILES1 = CommPortIdentifier.o NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\nBUILDFILES2 = cygCommDriver.o cygDeviceInputStream.o cygDeviceOutputStream.o cygSerialPort.o\nBUILDFILES3 = SerialDataEventThread.o SerialStatusEventThread.o SysVStyleSemaphore.o\nBUILDFILES4 = NSParallelPort.o ParallelErrorEventThread.o cygSerialDataEventThread.o cygSerialStatusEventThread.o\nBUILDFILES5 = cygParallelPort.o cygParallelErrorEventThread.o cygCommPortIdentifier.o\nC_OBJECTS   = $(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) $(BUILDFILES5)\n# For Linux ARM BE - Coyote \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_coyote\"\nTOOL_DIR  = /opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/bin\nCROSSCOMP = xscale_be-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I/opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/include -I. -I/phx4f/team/ravi/JavaCommAPI-J9/j9lnxarmbesf-beta22/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# For Linux i386 \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"i386_\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I. -I/usr/comm/osgimin11/bin/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# Yellow Dog Linux for Power PC\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_ydog\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I.\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nendif\n# Kenati Linux gcc for Power PC \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_kenati\"\nCROSSCOMP = powerpc-uclibc-\nTOOL_DIR  = /opt/kenati/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nAS        = $(TOOL_DIR)/$(CROSSCOMP)as\nASFLAGS   = -c $(VMASMDEBUG)\nifeq \"$(LIBTYPE)\"\"a\"\nCFLAGS   = -D__linux__ -DLINUXPPC -DJ9VM_STATIC_LINKAGE -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include -fno-exceptions\nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS = rcv \nelse\n#CFLAGS   = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include  -I. -I/phx4f/team/ravi/j9lnxppc/include\nCFLAGS   = -shared -fPIC -D__linux__ -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include \nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\nendif\n# Montavista PEE 3.1 for the ppc82xx Sandpoint Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc82xx_mvlpee31\"\nTOOL_DIR  = /opt/montavista_x86_ppc82xx/montavista/pro/devkit/ppc/82xx/bin\nCROSSCOMP = ppc_82xx-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-sandpoint/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the MIPS LE/BE Malta Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"mips_mvlpee31\"\nCROSSCOMP = mips_fp_$(DATATYPE)-\nTOOL_DIR  = /opt/montavista/pro/devkit/mips/fp_$(DATATYPE)/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mipsle/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the Hitachi SH-4 Solution Board\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"sh4_mvlpee31\"\nTOOL_DIR  = /opt/montavista/pro/devkit/sh/sh4_$(DATATYPE)/bin\nCROSSCOMP = sh_sh4_$(DATATYPE)-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mvl-sh4/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the IBM 440GP Walnut Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc440gp_mvlpee31\"\nCROSSCOMP = ppc_440-\nTOOL_DIR  = /opt/montavista_ppc_440gp/montavista/pro/devkit/ppc/440/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__  -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-walnut/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista CEE 3.1 for the xscale Mainstone Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlcee31\"\nCROSSCOMP = iwmmxt_le-\nTOOL_DIR  = /opt/montavista/cee/devkit/arm/iwmmxt_le/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx4f/team/ravi/gary/j9lnxarmhhmjit-mpn/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS  = rcv\nendif\n# Montavista Linux gcc for the xscale \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlarm\"\nCROSSCOMP = arm_sa_le-\nTOOL_DIR  = /opt/montavista/pro/devkit/arm/sa_le/bin \nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/xscale/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n.SUFFIXES:.cpp\n.cpp.o:\n\t$(CC) $(CFLAGS) -I. -fno-exceptions -fno-rtti -c $<\nall:      $(DLLNAME) messages\nBUILDLIB: $(DLLNAME)\n$(DLLNAME): \\\n\t$(C_OBJECTS)\n\t$(LINKER) $(LNKFLAGS) $(DLLNAME) \\\n        $(C_OBJECTS)\nmessages:         \n\t@echo \"================================================\";\n\t@echo \" === It is for $(CPUTYPE)($(DATATYPE)) $(COMPILER) $(BOARDTYPE) ===\";\n\t@echo \"================================================\";\n        \nclean:\n\trm $(DLLNAME)\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.linux.arm_hf",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nMAKEFILE = makefile.linux\n############################################################################################################\n#       Configure your OS, CPUTYPE and COMPILER \n############################################################################################################\nOS  = Linux\n##OS=Qnx\nCPUTYPE = arm\n##CPUTYPE = powerpc\n##CPUTYPE = ppc82xx\n##CPUTYPE = ppc440gp\n##CPUTYPE = xscale\n##CPUTYPE = mips\n##CPUTYPE = sh4\n##CPUTYPE = ibm44gp\nLIBTYPE = so                   \n##LIBTYPE = a\nDATATYPE = le\n##DATATYPE = be\n##COMPILER = kenati\n##COMPILER = ydog\n##COMPILER = mvlpee31\n##COMPILER = mvlcee31\n##COMPILER = mvlarm\n##COMPILER = coyote\n##BOARDTYPE = Mainstone\n##BOARDTYPE = Walnut\n##BOARDTYPE = Malta\n##BOARDTYPE = Sandpoint\n##BOARDTYPE = Solution\n############################################################################################################\n#\n#       Release the libdkcomm.so file place\n#\n############################################################################################################\nDLLNAME=Release/$(OS)/$(CPUTYPE)_$(COMPILER)/libdkcomm.$(LIBTYPE)\nBUILDFILES1 = CommPortIdentifier.o NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\nBUILDFILES2 = cygCommDriver.o cygDeviceInputStream.o cygDeviceOutputStream.o cygSerialPort.o\nBUILDFILES3 = SerialDataEventThread.o SerialStatusEventThread.o SysVStyleSemaphore.o\nBUILDFILES4 = NSParallelPort.o ParallelErrorEventThread.o cygSerialDataEventThread.o cygSerialStatusEventThread.o\nBUILDFILES5 = cygParallelPort.o cygParallelErrorEventThread.o cygCommPortIdentifier.o\nC_OBJECTS   = $(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) $(BUILDFILES5)\n# For Linux ARM BE - Coyote \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_coyote\"\nTOOL_DIR  = /opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/bin\nCROSSCOMP = xscale_be-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I/opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/include -I. -I/phx4f/team/ravi/JavaCommAPI-J9/j9lnxarmbesf-beta22/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# For Linux ARM  \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"arm_\"\n#TOOL_DIR  = /usr/bin\n#CROSSCOMP =\nJAVA_HOME  = /usr/lib/jvm/jdk-7-oracle-armhf\n#CC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCC         = arm-linux-gnueabihf-gcc\nCFLAGS    += -O -shared -D__linux__ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I../include -I.\n#AS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nAS\t   = $(CC)\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(CC)\nLNKFLAGS = -shared -o\nendif\n# For Linux i386 \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"i386_\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I. -I/usr/comm/osgimin11/bin/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# Yellow Dog Linux for Power PC\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_ydog\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I.\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nendif\n# Kenati Linux gcc for Power PC \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_kenati\"\nCROSSCOMP = powerpc-uclibc-\nTOOL_DIR  = /opt/kenati/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nAS        = $(TOOL_DIR)/$(CROSSCOMP)as\nASFLAGS   = -c $(VMASMDEBUG)\nifeq \"$(LIBTYPE)\"\"a\"\nCFLAGS   = -D__linux__ -DLINUXPPC -DJ9VM_STATIC_LINKAGE -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include -fno-exceptions\nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS = rcv \nelse\n#CFLAGS   = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include  -I. -I/phx4f/team/ravi/j9lnxppc/include\nCFLAGS   = -shared -fPIC -D__linux__ -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include \nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\nendif\n# Montavista PEE 3.1 for the ppc82xx Sandpoint Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc82xx_mvlpee31\"\nTOOL_DIR  = /opt/montavista_x86_ppc82xx/montavista/pro/devkit/ppc/82xx/bin\nCROSSCOMP = ppc_82xx-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-sandpoint/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the MIPS LE/BE Malta Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"mips_mvlpee31\"\nCROSSCOMP = mips_fp_$(DATATYPE)-\nTOOL_DIR  = /opt/montavista/pro/devkit/mips/fp_$(DATATYPE)/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mipsle/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the Hitachi SH-4 Solution Board\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"sh4_mvlpee31\"\nTOOL_DIR  = /opt/montavista/pro/devkit/sh/sh4_$(DATATYPE)/bin\nCROSSCOMP = sh_sh4_$(DATATYPE)-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mvl-sh4/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the IBM 440GP Walnut Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc440gp_mvlpee31\"\nCROSSCOMP = ppc_440-\nTOOL_DIR  = /opt/montavista_ppc_440gp/montavista/pro/devkit/ppc/440/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__  -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-walnut/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista CEE 3.1 for the xscale Mainstone Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlcee31\"\nCROSSCOMP = iwmmxt_le-\nTOOL_DIR  = /opt/montavista/cee/devkit/arm/iwmmxt_le/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx4f/team/ravi/gary/j9lnxarmhhmjit-mpn/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS  = rcv\nendif\n# Montavista Linux gcc for the xscale \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlarm\"\nCROSSCOMP = arm_sa_le-\nTOOL_DIR  = /opt/montavista/pro/devkit/arm/sa_le/bin \nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/xscale/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n.SUFFIXES:.cpp\n.cpp.o:\n\t$(CC) $(CFLAGS) -I. -fno-exceptions -fno-rtti -c $<\nall:      $(DLLNAME) messages\nBUILDLIB: $(DLLNAME)\n$(DLLNAME): \\\n\t$(C_OBJECTS)\n\tmkdir -p `dirname $(DLLNAME)`\n\t$(LINKER) $(LNKFLAGS) $(DLLNAME) \\\n        $(C_OBJECTS)\nmessages:         \n\t@echo \"================================================\";\n\t@echo \" === It is for $(CPUTYPE)($(DATATYPE)) $(COMPILER) $(BOARDTYPE) ===\";\n\t@echo \"================================================\";\n        \nclean:\n\trm $(DLLNAME)\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.linux.poky.arm_sf",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nMAKEFILE = makefile.linux\n############################################################################################################\n#       Configure your OS, CPUTYPE and COMPILER \n############################################################################################################\nOS  = Linux\n##OS=Qnx\nCPUTYPE = arm\n##CPUTYPE = powerpc\n##CPUTYPE = ppc82xx\n##CPUTYPE = ppc440gp\n##CPUTYPE = xscale\n##CPUTYPE = mips\n##CPUTYPE = sh4\n##CPUTYPE = ibm44gp\nLIBTYPE = so                   \n##LIBTYPE = a\nDATATYPE = le\n##DATATYPE = be\n##COMPILER = kenati\n##COMPILER = ydog\n##COMPILER = mvlpee31\n##COMPILER = mvlcee31\n##COMPILER = mvlarm\n##COMPILER = coyote\n##BOARDTYPE = Mainstone\n##BOARDTYPE = Walnut\n##BOARDTYPE = Malta\n##BOARDTYPE = Sandpoint\n##BOARDTYPE = Solution\n############################################################################################################\n#\n#       Release the libdkcomm.so file place\n#\n############################################################################################################\nDLLNAME=Release/$(OS)/$(CPUTYPE)_$(COMPILER)/libdkcomm.$(LIBTYPE)\nBUILDFILES1 = CommPortIdentifier.o NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\nBUILDFILES2 = cygCommDriver.o cygDeviceInputStream.o cygDeviceOutputStream.o cygSerialPort.o\nBUILDFILES3 = SerialDataEventThread.o SerialStatusEventThread.o SysVStyleSemaphore.o\nBUILDFILES4 = NSParallelPort.o ParallelErrorEventThread.o cygSerialDataEventThread.o cygSerialStatusEventThread.o\nBUILDFILES5 = cygParallelPort.o cygParallelErrorEventThread.o cygCommPortIdentifier.o\nC_OBJECTS   = $(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) $(BUILDFILES5)\n# For Linux ARM BE - Coyote \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_coyote\"\nTOOL_DIR  = /opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/bin\nCROSSCOMP = xscale_be-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I/opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/include -I. -I/phx4f/team/ravi/JavaCommAPI-J9/j9lnxarmbesf-beta22/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# For Linux ARM (using poky toolchain) \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"arm_\"\n#TOOL_DIR  = /usr/bin\n#CROSSCOMP =\n#CC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    += -msoft-float -shared -D__linux__ -I$(JAVA_HOME)/include -I../include -I.\n#AS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(CXX)\nLNKFLAGS = -shared -o\nendif\n# For Linux i386 \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"i386_\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I. -I/usr/comm/osgimin11/bin/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# Yellow Dog Linux for Power PC\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_ydog\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I.\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nendif\n# Kenati Linux gcc for Power PC \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_kenati\"\nCROSSCOMP = powerpc-uclibc-\nTOOL_DIR  = /opt/kenati/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nAS        = $(TOOL_DIR)/$(CROSSCOMP)as\nASFLAGS   = -c $(VMASMDEBUG)\nifeq \"$(LIBTYPE)\"\"a\"\nCFLAGS   = -D__linux__ -DLINUXPPC -DJ9VM_STATIC_LINKAGE -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include -fno-exceptions\nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS = rcv \nelse\n#CFLAGS   = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include  -I. -I/phx4f/team/ravi/j9lnxppc/include\nCFLAGS   = -shared -fPIC -D__linux__ -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include \nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\nendif\n# Montavista PEE 3.1 for the ppc82xx Sandpoint Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc82xx_mvlpee31\"\nTOOL_DIR  = /opt/montavista_x86_ppc82xx/montavista/pro/devkit/ppc/82xx/bin\nCROSSCOMP = ppc_82xx-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-sandpoint/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the MIPS LE/BE Malta Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"mips_mvlpee31\"\nCROSSCOMP = mips_fp_$(DATATYPE)-\nTOOL_DIR  = /opt/montavista/pro/devkit/mips/fp_$(DATATYPE)/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mipsle/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the Hitachi SH-4 Solution Board\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"sh4_mvlpee31\"\nTOOL_DIR  = /opt/montavista/pro/devkit/sh/sh4_$(DATATYPE)/bin\nCROSSCOMP = sh_sh4_$(DATATYPE)-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mvl-sh4/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the IBM 440GP Walnut Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc440gp_mvlpee31\"\nCROSSCOMP = ppc_440-\nTOOL_DIR  = /opt/montavista_ppc_440gp/montavista/pro/devkit/ppc/440/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__  -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-walnut/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista CEE 3.1 for the xscale Mainstone Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlcee31\"\nCROSSCOMP = iwmmxt_le-\nTOOL_DIR  = /opt/montavista/cee/devkit/arm/iwmmxt_le/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx4f/team/ravi/gary/j9lnxarmhhmjit-mpn/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS  = rcv\nendif\n# Montavista Linux gcc for the xscale \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlarm\"\nCROSSCOMP = arm_sa_le-\nTOOL_DIR  = /opt/montavista/pro/devkit/arm/sa_le/bin \nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/xscale/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n.SUFFIXES:.cpp\n.cpp.o:\n\t$(CC) $(CFLAGS) -I. -fno-exceptions -fno-rtti -c $<\nall:      $(DLLNAME) messages\nBUILDLIB: $(DLLNAME)\n$(DLLNAME): \\\n\t$(C_OBJECTS)\n\tmkdir -p `dirname $(DLLNAME)`\n\t$(LINKER) $(LNKFLAGS) $(DLLNAME) \\\n        $(C_OBJECTS)\nmessages:         \n\t@echo \"================================================\";\n\t@echo \" === It is for $(CPUTYPE)($(DATATYPE)) $(COMPILER) $(BOARDTYPE) ===\";\n\t@echo \"================================================\";\n        \nclean:\n\trm $(DLLNAME)\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.linux.poky.i586",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nMAKEFILE = makefile.linux\n############################################################################################################\n#       Configure your OS, CPUTYPE and COMPILER \n############################################################################################################\nOS  = Linux\n##OS=Qnx\nCPUTYPE = i386\n##CPUTYPE = powerpc\n##CPUTYPE = ppc82xx\n##CPUTYPE = ppc440gp\n##CPUTYPE = xscale\n##CPUTYPE = mips\n##CPUTYPE = sh4\n##CPUTYPE = ibm44gp\nLIBTYPE = so                   \n##LIBTYPE = a\nDATATYPE = le\n##DATATYPE = be\n##COMPILER = kenati\n##COMPILER = ydog\n##COMPILER = mvlpee31\n##COMPILER = mvlcee31\n##COMPILER = mvlarm\n##COMPILER = coyote\n##BOARDTYPE = Mainstone\n##BOARDTYPE = Walnut\n##BOARDTYPE = Malta\n##BOARDTYPE = Sandpoint\n##BOARDTYPE = Solution\n############################################################################################################\n#\n#       Release the libdkcomm.so file place\n#\n############################################################################################################\nDLLNAME=Release/$(OS)/$(CPUTYPE)_$(COMPILER)/libdkcomm.$(LIBTYPE)\nBUILDFILES1 = CommPortIdentifier.o NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\nBUILDFILES2 = cygCommDriver.o cygDeviceInputStream.o cygDeviceOutputStream.o cygSerialPort.o\nBUILDFILES3 = SerialDataEventThread.o SerialStatusEventThread.o SysVStyleSemaphore.o\nBUILDFILES4 = NSParallelPort.o ParallelErrorEventThread.o cygSerialDataEventThread.o cygSerialStatusEventThread.o\nBUILDFILES5 = cygParallelPort.o cygParallelErrorEventThread.o cygCommPortIdentifier.o\nC_OBJECTS   = $(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) $(BUILDFILES5)\n# For Linux ARM BE - Coyote \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_coyote\"\nTOOL_DIR  = /opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/bin\nCROSSCOMP = xscale_be-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I/opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/include -I. -I/phx4f/team/ravi/JavaCommAPI-J9/j9lnxarmbesf-beta22/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# For Linux i386 (yocto toolchain)\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"i386_\"\n#TOOL_DIR  = /usr/bin\n#CROSSCOMP =\n#CC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    += -shared -D__linux__ -I$(JAVA_HOME)/include -I../include -I. \n#AS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(CXX)\nLNKFLAGS = -shared -o\nendif\n# Yellow Dog Linux for Power PC\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_ydog\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I.\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nendif\n# Kenati Linux gcc for Power PC \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_kenati\"\nCROSSCOMP = powerpc-uclibc-\nTOOL_DIR  = /opt/kenati/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nAS        = $(TOOL_DIR)/$(CROSSCOMP)as\nASFLAGS   = -c $(VMASMDEBUG)\nifeq \"$(LIBTYPE)\"\"a\"\nCFLAGS   = -D__linux__ -DLINUXPPC -DJ9VM_STATIC_LINKAGE -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include -fno-exceptions\nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS = rcv \nelse\n#CFLAGS   = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include  -I. -I/phx4f/team/ravi/j9lnxppc/include\nCFLAGS   = -shared -fPIC -D__linux__ -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include \nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\nendif\n# Montavista PEE 3.1 for the ppc82xx Sandpoint Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc82xx_mvlpee31\"\nTOOL_DIR  = /opt/montavista_x86_ppc82xx/montavista/pro/devkit/ppc/82xx/bin\nCROSSCOMP = ppc_82xx-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-sandpoint/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the MIPS LE/BE Malta Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"mips_mvlpee31\"\nCROSSCOMP = mips_fp_$(DATATYPE)-\nTOOL_DIR  = /opt/montavista/pro/devkit/mips/fp_$(DATATYPE)/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mipsle/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the Hitachi SH-4 Solution Board\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"sh4_mvlpee31\"\nTOOL_DIR  = /opt/montavista/pro/devkit/sh/sh4_$(DATATYPE)/bin\nCROSSCOMP = sh_sh4_$(DATATYPE)-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mvl-sh4/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the IBM 440GP Walnut Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc440gp_mvlpee31\"\nCROSSCOMP = ppc_440-\nTOOL_DIR  = /opt/montavista_ppc_440gp/montavista/pro/devkit/ppc/440/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__  -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-walnut/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista CEE 3.1 for the xscale Mainstone Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlcee31\"\nCROSSCOMP = iwmmxt_le-\nTOOL_DIR  = /opt/montavista/cee/devkit/arm/iwmmxt_le/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx4f/team/ravi/gary/j9lnxarmhhmjit-mpn/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS  = rcv\nendif\n# Montavista Linux gcc for the xscale \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlarm\"\nCROSSCOMP = arm_sa_le-\nTOOL_DIR  = /opt/montavista/pro/devkit/arm/sa_le/bin \nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/xscale/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n.SUFFIXES:.cpp\n.cpp.o:\n\t$(CC) $(CFLAGS) -I. -fno-exceptions -fno-rtti -c $<\nall:      $(DLLNAME) messages\nBUILDLIB: $(DLLNAME)\n$(DLLNAME): \\\n\t$(C_OBJECTS)\n\tmkdir -p `dirname $(DLLNAME)`\n\t$(LINKER) $(LNKFLAGS) $(DLLNAME) \\\n        $(C_OBJECTS)\nmessages:         \n\t@echo \"================================================\";\n\t@echo \" === It is for $(CPUTYPE)($(DATATYPE)) $(COMPILER) $(BOARDTYPE) ===\";\n\t@echo \"================================================\";\n        \nclean:\n\trm $(DLLNAME)\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.linux.poky.x86_64",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nMAKEFILE = makefile.linux\n############################################################################################################\n#       Configure your OS, CPUTYPE and COMPILER \n############################################################################################################\nOS  = Linux\n##OS=Qnx\nCPUTYPE = x86-64\n##CPUTYPE = powerpc\n##CPUTYPE = ppc82xx\n##CPUTYPE = ppc440gp\n##CPUTYPE = xscale\n##CPUTYPE = mips\n##CPUTYPE = sh4\n##CPUTYPE = ibm44gp\nLIBTYPE = so                   \n##LIBTYPE = a\nDATATYPE = le\n##DATATYPE = be\n##COMPILER = kenati\n##COMPILER = ydog\n##COMPILER = mvlpee31\n##COMPILER = mvlcee31\n##COMPILER = mvlarm\n##COMPILER = coyote\n##BOARDTYPE = Mainstone\n##BOARDTYPE = Walnut\n##BOARDTYPE = Malta\n##BOARDTYPE = Sandpoint\n##BOARDTYPE = Solution\n############################################################################################################\n#\n#       Release the dkcomm.so file place\n#\n############################################################################################################\nDLLNAME=Release/$(OS)/$(CPUTYPE)_$(COMPILER)/dkcomm.$(LIBTYPE)\nBUILDFILES1 = CommPortIdentifier.o NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\nBUILDFILES2 = cygCommDriver.o cygDeviceInputStream.o cygDeviceOutputStream.o cygSerialPort.o\nBUILDFILES3 = SerialDataEventThread.o SerialStatusEventThread.o SysVStyleSemaphore.o\nBUILDFILES4 = NSParallelPort.o ParallelErrorEventThread.o cygSerialDataEventThread.o cygSerialStatusEventThread.o\nBUILDFILES5 = cygParallelPort.o cygParallelErrorEventThread.o cygCommPortIdentifier.o\nC_OBJECTS   = $(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) $(BUILDFILES5)\n# For Linux ARM BE - Coyote \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_coyote\"\nTOOL_DIR  = /opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/bin\nCROSSCOMP = xscale_be-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I/opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/include -I. -I/phx4f/team/ravi/JavaCommAPI-J9/j9lnxarmbesf-beta22/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# For Linux i386 (yocto toolchain)\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"i386_\"\n#TOOL_DIR  = /usr/bin\n#CROSSCOMP =\n#CC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    += -shared -D__linux__ -I$(JAVA_HOME)/include -I../include -I. \n#AS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(CXX)\nLNKFLAGS = -shared -o\nendif\n# For Linux x86_64 (yocto toolchain)\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"x86-64_\"\n#TOOL_DIR  = /usr/bin\n#CROSSCOMP =\n#CC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    += -shared -D__linux__ -I$(JAVA_HOME)/include -I../include -I. -fPIC \n#AS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(CXX)\nLNKFLAGS = -shared -o\nendif\n# Yellow Dog Linux for Power PC\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_ydog\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I.\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nendif\n# Kenati Linux gcc for Power PC \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_kenati\"\nCROSSCOMP = powerpc-uclibc-\nTOOL_DIR  = /opt/kenati/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nAS        = $(TOOL_DIR)/$(CROSSCOMP)as\nASFLAGS   = -c $(VMASMDEBUG)\nifeq \"$(LIBTYPE)\"\"a\"\nCFLAGS   = -D__linux__ -DLINUXPPC -DJ9VM_STATIC_LINKAGE -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include -fno-exceptions\nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS = rcv \nelse\n#CFLAGS   = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include  -I. -I/phx4f/team/ravi/j9lnxppc/include\nCFLAGS   = -shared -fPIC -D__linux__ -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include \nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\nendif\n# Montavista PEE 3.1 for the ppc82xx Sandpoint Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc82xx_mvlpee31\"\nTOOL_DIR  = /opt/montavista_x86_ppc82xx/montavista/pro/devkit/ppc/82xx/bin\nCROSSCOMP = ppc_82xx-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-sandpoint/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the MIPS LE/BE Malta Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"mips_mvlpee31\"\nCROSSCOMP = mips_fp_$(DATATYPE)-\nTOOL_DIR  = /opt/montavista/pro/devkit/mips/fp_$(DATATYPE)/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mipsle/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the Hitachi SH-4 Solution Board\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"sh4_mvlpee31\"\nTOOL_DIR  = /opt/montavista/pro/devkit/sh/sh4_$(DATATYPE)/bin\nCROSSCOMP = sh_sh4_$(DATATYPE)-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mvl-sh4/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the IBM 440GP Walnut Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc440gp_mvlpee31\"\nCROSSCOMP = ppc_440-\nTOOL_DIR  = /opt/montavista_ppc_440gp/montavista/pro/devkit/ppc/440/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__  -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-walnut/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista CEE 3.1 for the xscale Mainstone Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlcee31\"\nCROSSCOMP = iwmmxt_le-\nTOOL_DIR  = /opt/montavista/cee/devkit/arm/iwmmxt_le/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx4f/team/ravi/gary/j9lnxarmhhmjit-mpn/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS  = rcv\nendif\n# Montavista Linux gcc for the xscale \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlarm\"\nCROSSCOMP = arm_sa_le-\nTOOL_DIR  = /opt/montavista/pro/devkit/arm/sa_le/bin \nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/xscale/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n.SUFFIXES:.cpp\n.cpp.o:\n\t$(CC) $(CFLAGS) -I. -fno-exceptions -fno-rtti -c $<\nall:      $(DLLNAME) messages\nBUILDLIB: $(DLLNAME)\n$(DLLNAME): \\\n\t$(C_OBJECTS)\n\tmkdir -p `dirname $(DLLNAME)` \n\t$(LINKER) $(LNKFLAGS) $(DLLNAME) \\\n        $(C_OBJECTS)\nmessages:         \n\t@echo \"================================================\";\n\t@echo \" === It is for $(CPUTYPE)($(DATATYPE)) $(COMPILER) $(BOARDTYPE) ===\";\n\t@echo \"================================================\";\n        \nclean:\n\trm $(DLLNAME)\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.mingw",
    "content": "CFLAGS=-Wall -O0 -g -Wl,--subsystem,windows -I \"$(JAVA_HOME)\\include\" -I \"$(JAVA_HOME)\\include\\win32\"\nLFLAGS=-Wl,--subsystem,windows -shared\nRELEASE32=Release/win32/x86/dkcomm.dll\nRELEASE64=Release/win32/x64/dkcomm.dll\n\nSodaDkComm32 : $(RELEASE32)\nSodaDkComm64 : $(RELEASE64)\n\nObjs/x86/CommPortIdentifier.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c CommPortIdentifier.c -o $@\nObjs/x86/NSCommDriver.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c NSCommDriver.c -o $@\nObjs/x86/NSDeviceInputStream.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c NSDeviceInputStream.c -o $@\nObjs/x86/NSDeviceOutputStream.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c NSDeviceOutputStream.c -o $@\nObjs/x86/NSSerialPort.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c NSSerialPort.c -o $@\nObjs/x86/SerialDataEventThread.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c SerialDataEventThread.c -o $@\nObjs/x86/SerialStatusEventThread.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c SerialStatusEventThread.c -o $@\nObjs/x86/w32CommDriver.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c w32CommDriver.c -o $@\nObjs/x86/w32CommPortIdentifier.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c w32CommPortIdentifier.c -o $@\nObjs/x86/w32DeviceInputStream.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c w32DeviceInputStream.c -o $@\nObjs/x86/w32DeviceOutputStream.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c w32DeviceOutputStream.c -o $@\nObjs/x86/w32SerialDataEventThread.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c w32SerialDataEventThread.c -o $@\nObjs/x86/w32SerialPort.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c w32SerialPort.c -o $@\nObjs/x86/w32SerialStatusEventThread.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c w32SerialStatusEventThread.c -o $@\nObjs/x86/NSCommLOG.o:\n\ti686-w64-mingw32-gcc $(CFLAGS) -c NSCommLOG.c -o $@\n\nObjs/x64/CommPortIdentifier.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c CommPortIdentifier.c -o $@\nObjs/x64/NSCommDriver.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c NSCommDriver.c -o $@\nObjs/x64/NSDeviceInputStream.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c NSDeviceInputStream.c -o $@\nObjs/x64/NSDeviceOutputStream.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c NSDeviceOutputStream.c -o $@\nObjs/x64/NSSerialPort.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c NSSerialPort.c -o $@\nObjs/x64/SerialDataEventThread.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c SerialDataEventThread.c -o $@\nObjs/x64/SerialStatusEventThread.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c SerialStatusEventThread.c -o $@\nObjs/x64/w32CommDriver.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c w32CommDriver.c -o $@\nObjs/x64/w32CommPortIdentifier.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c w32CommPortIdentifier.c -o $@\nObjs/x64/w32DeviceInputStream.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c w32DeviceInputStream.c -o $@\nObjs/x64/w32DeviceOutputStream.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c w32DeviceOutputStream.c -o $@\nObjs/x64/w32SerialDataEventThread.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c w32SerialDataEventThread.c -o $@\nObjs/x64/w32SerialPort.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c w32SerialPort.c -o $@\nObjs/x64/w32SerialStatusEventThread.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c w32SerialStatusEventThread.c -o $@\nObjs/x64/NSCommLOG.o:\n\tx86_64-w64-mingw32-gcc -m64 $(CFLAGS) -c NSCommLOG.c -o $@\n\n$(RELEASE32): Objs/x86/CommPortIdentifier.o Objs/x86/NSCommDriver.o Objs/x86/NSDeviceInputStream.o Objs/x86/NSDeviceOutputStream.o Objs/x86/NSSerialPort.o\\\n              Objs/x86/SerialDataEventThread.o Objs/x86/SerialStatusEventThread.o Objs/x86/w32CommDriver.o Objs/x86/w32CommPortIdentifier.o\\\n              Objs/x86/w32DeviceInputStream.o Objs/x86/w32DeviceOutputStream.o Objs/x86/w32SerialDataEventThread.o\\\n              Objs/x86/w32SerialPort.o Objs/x86/w32SerialStatusEventThread.o Objs/x86/NSCommLOG.o\n\ti686-w64-mingw32-gcc $(LFLAGS) -o $@ $^ -lws2_32\n\n$(RELEASE64): Objs/x64/CommPortIdentifier.o Objs/x64/NSCommDriver.o Objs/x64/NSDeviceInputStream.o Objs/x64/NSDeviceOutputStream.o Objs/x64/NSSerialPort.o\\\n              Objs/x64/SerialDataEventThread.o Objs/x64/SerialStatusEventThread.o Objs/x64/w32CommDriver.o Objs/x64/w32CommPortIdentifier.o\\\n              Objs/x64/w32DeviceInputStream.o Objs/x64/w32DeviceOutputStream.o Objs/x64/w32SerialDataEventThread.o\\\n              Objs/x64/w32SerialPort.o Objs/x64/w32SerialStatusEventThread.o Objs/x64/NSCommLOG.o\n\tx86_64-w64-mingw32-gcc $(LFLAGS) -o $@ $^ -lws2_32\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.mingw_win32",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nTARGETNAME=dkcomm\nDLLFILENAME=$(TARGETNAME).dll\nDLLPATH=Release\\win32\\x86\nDLLNAME=$(DLLPATH)\\$(DLLFILENAME)\nCC=gcc\nCFLAGS=-m32 -Wall -O0 -g -Wl,--subsystem,windows -I \"$(JAVA_HOME)\\include\" -I \"$(JAVA_HOME)\\include\\win32\"\nLFLAGS=-Wl,--subsystem,windows -shared\nBUILDFILES = CommPortIdentifier.o NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\\\n             SerialDataEventThread.o SerialStatusEventThread.o w32CommDriver.o w32CommPortIdentifier.o\\\n             w32DeviceInputStream.o w32DeviceOutputStream.o w32SerialDataEventThread.o\\\n             w32SerialPort.o w32SerialStatusEventThread.o NSCommLOG.o\n.c.o: \n\t$(CC) $(CFLAGS) -c $<\n\n$(DLLNAME): $(BUILDFILES)\n\t$(CC) $(LFLAGS) -o $@ $^ -lws2_32\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.mingw_win32_x64",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nTARGETNAME=dkcomm\nDLLFILENAME=$(TARGETNAME).dll\nDLLPATH=Release\\win32\\x64\nDLLNAME=$(DLLPATH)\\$(DLLFILENAME)\nCC=gcc\nCFLAGS=-m64 -Wall -O0 -g -Wl,--subsystem,windows -I \"$(JAVA_HOME)\\include\" -I \"$(JAVA_HOME)\\include\\win32\"\nLFLAGS=-Wl,--subsystem,windows -shared\nBUILDFILES = CommPortIdentifier.o NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\\\n             SerialDataEventThread.o SerialStatusEventThread.o w32CommDriver.o w32CommPortIdentifier.o\\\n             w32DeviceInputStream.o w32DeviceOutputStream.o w32SerialDataEventThread.o\\\n             w32SerialPort.o w32SerialStatusEventThread.o NSCommLOG.o\n.c.o: \n\t$(CC) $(CFLAGS) -c $<\n\n$(DLLNAME): $(BUILDFILES)\n\t$(CC) $(LFLAGS) -o $@ $^ -lws2_32\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.osx",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nMAKEFILE = makefile.linux\n############################################################################################################\n#       Configure your OS, CPUTYPE and COMPILER \n############################################################################################################\n##OS  = Linux\nOS  = OSX\n##OS=Qnx\nCPUTYPE = x86\n##CPUTYPE = i386\n##CPUTYPE = powerpc\n##CPUTYPE = ppc82xx\n##CPUTYPE = ppc440gp\n##CPUTYPE = xscale\n##CPUTYPE = mips\n##CPUTYPE = sh4\n##CPUTYPE = ibm44gp\n##LIBTYPE = so                   \nLIBTYPE = jnilib                   \n##LIBTYPE = a\nDATATYPE = le\n##DATATYPE = be\n##COMPILER = kenati\n##COMPILER = ydog\n##COMPILER = mvlpee31\n##COMPILER = mvlcee31\n##COMPILER = mvlarm\n##COMPILER = coyote\nCOMPILER = macosx\n##BOARDTYPE = Mainstone\n##BOARDTYPE = Walnut\n##BOARDTYPE = Malta\n##BOARDTYPE = Sandpoint\n##BOARDTYPE = Solution\n############################################################################################################\n#\n#       Release the libdkcomm.so file place\n#\n############################################################################################################\nDLLNAME=Release/$(OS)/$(CPUTYPE)_$(COMPILER)/libdkcomm.$(LIBTYPE)\nBUILDFILES1 = CommPortIdentifier.o NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\nBUILDFILES2 = cygCommDriver.o cygDeviceInputStream.o cygDeviceOutputStream.o cygSerialPort.o\nBUILDFILES3 = SerialDataEventThread.o SerialStatusEventThread.o SysVStyleSemaphore.o\nBUILDFILES4 = NSParallelPort.o ParallelErrorEventThread.o cygSerialDataEventThread.o cygSerialStatusEventThread.o\nBUILDFILES5 = cygParallelPort.o cygParallelErrorEventThread.o cygCommPortIdentifier.o\nC_OBJECTS   = $(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) $(BUILDFILES5)\n# For Linux ARM BE - Coyote \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_coyote\"\nTOOL_DIR  = /opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/bin\nCROSSCOMP = xscale_be-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I/opt/montavista_xscale_be/montavista/pro/devkit/arm/xscale_be/include -I. -I/phx4f/team/ravi/JavaCommAPI-J9/j9lnxarmbesf-beta22/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# For Linux i386 \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"i386_\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I. -I/usr/comm/osgimin11/bin/include\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# For Mac x86 \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"x86_macosx\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__osx__ -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/darwin -I../include -I/usr/include -I. -I/usr/comm/osgimin11/bin/include -lpthread\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\n# Yellow Dog Linux for Power PC\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_ydog\"\nTOOL_DIR  = /usr/bin\nCROSSCOMP =\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/usr/include -I.\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nendif\n# Kenati Linux gcc for Power PC \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"powerpc_kenati\"\nCROSSCOMP = powerpc-uclibc-\nTOOL_DIR  = /opt/kenati/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nAS        = $(TOOL_DIR)/$(CROSSCOMP)as\nASFLAGS   = -c $(VMASMDEBUG)\nifeq \"$(LIBTYPE)\"\"a\"\nCFLAGS   = -D__linux__ -DLINUXPPC -DJ9VM_STATIC_LINKAGE -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include -fno-exceptions\nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS = rcv \nelse\n#CFLAGS   = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include  -I. -I/phx4f/team/ravi/j9lnxppc/include\nCFLAGS   = -shared -fPIC -D__linux__ -mcpu=$(CPUTYPE) -I../include -I. -I/phx4f/team/ravi/j9lnxppc/include \nLINKER   = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS = -shared -o\nendif\nendif\n# Montavista PEE 3.1 for the ppc82xx Sandpoint Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc82xx_mvlpee31\"\nTOOL_DIR  = /opt/montavista_x86_ppc82xx/montavista/pro/devkit/ppc/82xx/bin\nCROSSCOMP = ppc_82xx-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-sandpoint/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the MIPS LE/BE Malta Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"mips_mvlpee31\"\nCROSSCOMP = mips_fp_$(DATATYPE)-\nTOOL_DIR  = /opt/montavista/pro/devkit/mips/fp_$(DATATYPE)/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mipsle/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the Hitachi SH-4 Solution Board\nifeq \"$(CPUTYPE)_$(COMPILER)\"\"sh4_mvlpee31\"\nTOOL_DIR  = /opt/montavista/pro/devkit/sh/sh4_$(DATATYPE)/bin\nCROSSCOMP = sh_sh4_$(DATATYPE)-\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/mvl-sh4/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista PEE 3.1 for the IBM 440GP Walnut Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"ppc440gp_mvlpee31\"\nCROSSCOMP = ppc_440-\nTOOL_DIR  = /opt/montavista_ppc_440gp/montavista/pro/devkit/ppc/440/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__  -I../include -I/phx4f/team/tjfang/runtimes/2005-2.2.1SR1/j9lnxppc-walnut/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n# Montavista CEE 3.1 for the xscale Mainstone Board \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlcee31\"\nCROSSCOMP = iwmmxt_le-\nTOOL_DIR  = /opt/montavista/cee/devkit/arm/iwmmxt_le/bin\nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx4f/team/ravi/gary/j9lnxarmhhmjit-mpn/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)ar\nLNKFLAGS  = rcv\nendif\n# Montavista Linux gcc for the xscale \nifeq \"$(CPUTYPE)_$(COMPILER)\"\"xscale_mvlarm\"\nCROSSCOMP = arm_sa_le-\nTOOL_DIR  = /opt/montavista/pro/devkit/arm/sa_le/bin \nCC        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nCFLAGS    = -shared -D__linux__ -mcpu=$(CPUTYPE) -I../include -I/phx5f/projects/TCK/cert22/runtimes/0706/mvl/31/xscale/bin/include -I. -fPIC\nAS        = $(TOOL_DIR)/$(CROSSCOMP)gcc\nASFLAGS   = -c $(VMASMDEBUG) -shared\nLINKER    = $(TOOL_DIR)/$(CROSSCOMP)gcc\nLNKFLAGS  = -shared -o\nendif\n.SUFFIXES:.cpp\n.cpp.o:\n\t$(CC) $(CFLAGS) -I. -fno-exceptions -fno-rtti -c $<\nall:      $(DLLNAME) messages\nBUILDLIB: $(DLLNAME)\n$(DLLNAME): \\\n\t$(C_OBJECTS)\n\t$(LINKER) $(LNKFLAGS) $(DLLNAME) \\\n        $(C_OBJECTS)\nmessages:         \n\t@echo \"================================================\";\n\t@echo \" === It is for $(CPUTYPE)($(DATATYPE)) $(COMPILER) $(BOARDTYPE) ===\";\n\t@echo \"================================================\";\n        \nclean:\n\trm $(DLLNAME)\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.qnx",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nDLLNAME=../libibmcomm.so# declaration\nBUILDFILES1 = CommPortIdentifier.o NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\nBUILDFILES2 = SerialDataEventThread.o SerialStatusEventThread.o SysVStyleSemaphore.o NSParallelPort.o ParallelErrorEventThread.o\nCC=qcc\nCFLAGS=-O -Vgcc_ntox86 -DQNX -DNEUTRINO -shared -DX86 -I../include -I/usr/include -I.\n.SUFFIXES:.cpp\n.cpp.o:\n\t$(CC) $(CFLAGS) -I. -fno-exceptions -fno-rtti -c $<\nAS=qcc\nASFLAGS=-Vgcc_ntox86 -c $(VMASMDEBUG) \nall:  BUILDLIB\nBUILDLIB: $(DLLNAME)\n \n$(DLLNAME):\\\n\t$(BUILDFILES1) $(BUILDFILES2) \n\t qcc -L. -W l,-s -W l,-x -Vgcc_ntox86 -shared  -o $(DLLNAME) \\\n\t$(BUILDFILES1) $(BUILDFILES2) -W l,--start-group \\\n\t-W l,--end-group \n\t\t \n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.win32",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nAPPVER=4.0\nTARGETOS=WIN95\nSEHMAP = TRUE\n!include <win32.mak>\nDLLFILENAME=dkcomm.dll# declaration\nDLLPATH = Release\\win32\\x86\nDLLNAME= $(DLLPATH)\\dkcomm.dll# declaration\nLIBNAME=dkcomm# declaration\nLIBPATH=.\\# declaration\n.c.obj:\n\t$(cc) -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 $(cflags) -D_MT -D_DLL -MD -D_WINSOCKAPI_ -DWIN32 -Ogityb1 -Gs -GF -Zm400 -Zi  /I\"$(JAVA_HOME)\\include\" /I\"$(JAVA_HOME)\\include\\win32\" $*.c\n#/IC:\\IBM\\osgimin11\\bin\\include\n.cpp.obj:\n\t$(cc) -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 $(cflags) -D_MT -D_DLL -MD -D_WINSOCKAPI_ -DWIN32 -Ogityb1 -Gs -GF -Zm400 -Zi  $*.cpp\n.rc.res:\n\trc $<\nBUILDFILES1 = CommPortIdentifier.obj NSCommDriver.obj NSDeviceInputStream.obj NSDeviceOutputStream.obj NSSerialPort.obj\nBUILDFILES2 = SerialDataEventThread.obj SerialStatusEventThread.obj w32CommDriver.obj w32CommPortIdentifier.obj\nBUILDFILES3 = w32DeviceInputStream.obj w32DeviceOutputStream.obj w32SerialDataEventThread.obj\nBUILDFILES4 = w32SerialPort.obj w32SerialStatusEventThread.obj NSCommLOG.obj\n#NSParallelPort.obj ParallelErrorEventThread.obj NSCommLOG.obj\nSYSLIBFILES1 = ws2_32.lib\nMDLLIBFILES1 =\nall: \\\n\t $(LIBPATH)$(LIBNAME).lib $(DLLNAME)\nBUILDLIB: $(LIBPATH)$(LIBNAME).lib\n$(LIBPATH)$(LIBNAME).lib:\\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) \\\n\t$(MDLLIBFILES1)\n\t$(implib) -subsystem:windows -out:$(LIBPATH)$(LIBNAME).lib -machine:$(CPU) \\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) \\\n\t$(MDLLIBFILES1)\n$(DLLNAME): $(LIBPATH)$(LIBNAME).lib \\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) \\\n\t$(MDLLIBFILES1)\n\tlink $(VMLINK) /debug /opt:icf /opt:ref /INCREMENTAL:NO /NOLOGO -entry:_DllMainCRTStartup@12 -dll /BASE:0x11300000 -machine:$(CPU) \\\n\t-subsystem:windows -out:$(DLLNAME) -map:$(LIBNAME).map \\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) \\\n\t$(MDLLIBFILES1) $(SYSLIBFILES1)  \\\n\tkernel32.lib  ws2_32.lib advapi32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib winmm.lib\nstatic:\n\t$(MAKE) -f makefile.static\nquick:\n\t$(MAKE)\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.win32_down",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\n!include <win32.mak>\nDLLNAME=../libibmcomm.dll# declaration\nBUILDFILES1 = CommPortIdentifier.obj NSCommDriver.o NSDeviceInputStream.o NSDeviceOutputStream.o NSSerialPort.o\nBUILDFILES2 = SerialDataEventThread.o SerialStatusEventThread.o SysVStyleSemaphore.o\nBUILDFILES3 = NSParallelPort.o ParallelErrorEventThread.o NSCommLOG.o\nBUILDFILES4 = w32SerialPort.o\nCC=gcc\nCFLAGS=-shared -DWIN32 -DDLL -DDEBUG -I../include -I/usr/include -I.\n.SUFFIXES:.cpp\n.cpp.o:\n\t$(CC) $(CFLAGS) -I. -fno-exceptions -fno-rtti -c $<\nAS=gcc\nASFLAGS=-c $(VMASMDEBUG) -shared\nall: \\\n\t $(DLLNAME)\nBUILDLIB: $(DLLNAME)\n$(DLLNAME):\\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4)\n\t gcc -shared -o $(DLLNAME) $(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4)\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.win32_x64",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nAPPVER=4.0\nTARGETOS=WIN95\nSEHMAP = TRUE\n!include <win32.mak>\nDLLFILENAME=dkcomm.dll# declaration\nDLLPATH = Release\\win32\\x64\nDLLNAME= $(DLLPATH)\\dkcomm.dll# declaration\nLIBNAME=dkcomm# declaration\nLIBPATH=.\\# declaration\n.c.obj:\n\t$(cc) -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 $(cflags) -D_MT -D_DLL -MD -D_WINSOCKAPI_ -DWIN32 -Ogityb1 -Gs -GF -Zm400 -Zi  /I\"$(JAVA_HOME)\\include\" /I\"$(JAVA_HOME)\\include\\win32\" $*.c\n#/IC:\\IBM\\osgimin11\\bin\\include\n.cpp.obj:\n\t$(cc) -DWINVER=0x0400 -D_WIN32_WINNT=0x0400 $(cflags) -D_MT -D_DLL -MD -D_WINSOCKAPI_ -DWIN32 -Ogityb1 -Gs -GF -Zm400 -Zi  $*.cpp\n.rc.res:\n\trc $<\nBUILDFILES1 = CommPortIdentifier.obj NSCommDriver.obj NSDeviceInputStream.obj NSDeviceOutputStream.obj NSSerialPort.obj\nBUILDFILES2 = SerialDataEventThread.obj SerialStatusEventThread.obj w32CommDriver.obj w32CommPortIdentifier.obj\nBUILDFILES3 = w32DeviceInputStream.obj w32DeviceOutputStream.obj w32SerialDataEventThread.obj\nBUILDFILES4 = w32SerialPort.obj w32SerialStatusEventThread.obj NSCommLOG.obj\n#NSParallelPort.obj ParallelErrorEventThread.obj NSCommLOG.obj\nSYSLIBFILES1 = ws2_32.lib\nMDLLIBFILES1 =\nall: \\\n\t $(LIBPATH)$(LIBNAME).lib $(DLLNAME)\nBUILDLIB: $(LIBPATH)$(LIBNAME).lib\n$(LIBPATH)$(LIBNAME).lib:\\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) \\\n\t$(MDLLIBFILES1)\n\t$(implib) -subsystem:windows -out:$(LIBPATH)$(LIBNAME).lib -machine:$(CPU) \\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) \\\n\t$(MDLLIBFILES1)\n$(DLLNAME): $(LIBPATH)$(LIBNAME).lib \\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) \\\n\t$(MDLLIBFILES1)\n\tlink $(VMLINK) /debug /opt:icf /opt:ref /INCREMENTAL:NO /NOLOGO -entry:_DllMainCRTStartup -dll /BASE:0x11300000 -machine:$(CPU) \\\n\t-subsystem:windows -out:$(DLLNAME) -map:$(LIBNAME).map \\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4) \\\n\t$(MDLLIBFILES1) $(SYSLIBFILES1)  \\\n\tkernel32.lib  ws2_32.lib advapi32.lib user32.lib gdi32.lib comdlg32.lib winspool.lib winmm.lib\nstatic:\n\t$(MAKE) -f makefile.static\nquick:\n\t$(MAKE)\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/makefile.wince",
    "content": "#########################################################################\n# Copyright (c) 2001, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\n.SUFFIXES: .s\nCPU=ARM\nCC=clarm\nDLLNAME=Release/Windows/WinCE/libibmcomm.dll# declaration\nLIBNAME=Release/Windows/WinCE/libibmcomm# declaration\nLIBPATH=\"C:\\Program Files\\Windows CE Tools\\wce420\\POCKET PC 2003\\Lib\\armv4\"\nBUILDFILES1 = CommPortIdentifier.obj NSCommDriver.obj          NSDeviceInputStream.obj   NSDeviceOutputStream.obj\nBUILDFILES2 = NSSerialPort.obj       NSCommLOG.obj             SerialDataEventThread.obj SerialStatusEventThread.obj \nBUILDFILES3 = w32SerialPort.obj      w32DeviceInputStream.obj  w32DeviceOutputStream.obj w32SerialDataEventThread.obj\nBUILDFILES4 = w32CommDriver.obj      w32CommPortIdentifier.obj w32SerialStatusEventThread.obj \nCFLAGS =-DWINVER=0x0400 -D_WIN32_WINNT=0x0400 /nologo /c -DJ9WINCE -DJ9POCKETPC /W3 -DIPV4_WINCE -D_WIN32_WCE=300 \nCFLAGS+=-D\"MS Pocket PC\" /DUNDER_CE=300 /D\"UNICODE\" /D \"_MBCS\" /Zm400 -DFIXUP_UNALIGNED -D$(CPU) -D_$(CPU)_ -Ogitb1 \nCFLAGS+=-GF -DTR_HOST_32BIT -DTR_TARGET_$(CPU) -DNewFrameShape -DTR_HOST_$(CPU) -DSMALL -DTR_TARGET_32BIT \nCFLAGS+=-I ../include -I. \nCFLAGS+=-I \"C:\\Program Files\\IBM\\DeviceDeveloper\\wsdd5.0\\ive-2.2\\bin\\include\"\nCFLAGS+=-I \"C:\\Program Files\\Windows CE Tools\\wce420\\POCKET PC 2003\\Include\\armv4\"\n##CFLAGS=-shared -DWIN32 -DDLL -DDEBUG -I../include -I/usr/include -I.\n%.obj : %.c\n\t$(CC) $(CFLAGS) $< -o $@\n%.obj : %.cpp\n\t$(CC) -c $(CFLAGS) $< -o $@\nAS=armasm\nASFLAGS=$(VMASMDEBUG) -shared\n%.obj : %.s\n\t$(AS) -c $(ASFLAGS) $< -o $@\nall: \\\n\t $(DLLNAME)\nBUILDLIB: $(DLLNAME)\n$(LIBNAME).lib:\\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4)\n\tlib -subsystem:windowsce,3.0 -out:$(LIBNAME).lib -machine:$(CPU) \\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4)\n$(DLLNAME):$(LIBNAME).lib\\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4)\n\tlink $(VMLINK)  /INCREMENTAL:NO /NOLOGO -machine:$(CPU) \\\n\t-subsystem:windowsce,3.0 -out:$(DLLNAME) -map:$(LIBNAME).map \\\n\t$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4)  \\\n        $(LIBPATH)/corelibc.lib $(LIBPATH)/coredll.lib\n\t##-subsystem:windowsce,3.0 -out:$(DLLNAME) -map:$(LIBNAME).map /dll \\ ##/entry:\"_DllMainCRTStartup\"  \\\n        ##$(LIBPATH)/corelibc.lib \n\t##$(BUILDFILES1) $(BUILDFILES2) $(BUILDFILES3) $(BUILDFILES4)\n\t##/dll /entry:\"_DllMainCRTStartup\" corelibc.lib coredll.lib commctrl.lib aygshell.lib $(LIBPATH)$(LIBNAME).exp\n         \n         \n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/org_eclipse_soda_dk_comm_NSCommDriver.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <jni.h>\n/* Header for class org_eclipse_soda_dk_comm_NSCommDriver */\n#ifndef _Included_org_eclipse_soda_dk_comm_NSCommDriver\n#define _Included_org_eclipse_soda_dk_comm_NSCommDriver\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_NSCommDriver\n * Method:    discoverDevicesNC\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_NSCommDriver_discoverDevicesNC\n  (JNIEnv *, jobject);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/org_eclipse_soda_dk_comm_NSDeviceInputStream.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <jni.h>\n/* Header for class org_eclipse_soda_dk_comm_NSDeviceInputStream */\n#ifndef _Included_org_eclipse_soda_dk_comm_NSDeviceInputStream\n#define _Included_org_eclipse_soda_dk_comm_NSDeviceInputStream\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceInputStream\n * Method:    readDeviceOneByteNC\n * Signature: ()I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSDeviceInputStream_readDeviceOneByteNC\n  (JNIEnv *, jobject);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceInputStream\n * Method:    readDeviceNC\n * Signature: ([BII)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSDeviceInputStream_readDeviceNC\n  (JNIEnv *, jobject, jbyteArray, jint, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceInputStream\n * Method:    getReadCountNC\n * Signature: ()I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSDeviceInputStream_getReadCountNC\n  (JNIEnv *, jobject);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/org_eclipse_soda_dk_comm_NSDeviceOutputStream.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <jni.h>\n/* Header for class org_eclipse_soda_dk_comm_NSDeviceOutputStream */\n#ifndef _Included_org_eclipse_soda_dk_comm_NSDeviceOutputStream\n#define _Included_org_eclipse_soda_dk_comm_NSDeviceOutputStream\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceOutputStream\n * Method:    writeDeviceNC\n * Signature: ([BII)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSDeviceOutputStream_writeDeviceNC\n  (JNIEnv *, jobject, jbyteArray, jint, jint);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/org_eclipse_soda_dk_comm_NSParallelPort.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <jni.h>\n/* Header for class org_eclipse_soda_dk_comm_NSParallelPort */\n#ifndef _Included_org_eclipse_soda_dk_comm_NSParallelPort\n#define _Included_org_eclipse_soda_dk_comm_NSParallelPort\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_ANY\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_ANY 0L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_SPP\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_SPP 1L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_PS2\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_PS2 2L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_EPP\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_EPP 3L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_ECP\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_ECP 4L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_NIBBLE\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_NIBBLE 5L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_ANY\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_ANY 0L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_SPP\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_SPP 1L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_PS2\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_PS2 2L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_EPP\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_EPP 3L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_ECP\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_ECP 4L\n#undef org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_NIBBLE\n#define org_eclipse_soda_dk_comm_NSParallelPort_LPT_MODE_NIBBLE 5L\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    openDeviceNC\n * Signature: (Ljava/lang/String;I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_openDeviceNC\n  (JNIEnv *, jobject, jstring, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    closeDeviceNC\n * Signature: (II)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_closeDeviceNC\n  (JNIEnv *, jobject, jint, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPaperOutNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPaperOutNC\n  (JNIEnv *, jobject, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterBusyNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterBusyNC\n  (JNIEnv *, jobject, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterSelectedNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterSelectedNC\n  (JNIEnv *, jobject, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterTimedOutNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterTimedOutNC\n  (JNIEnv *, jobject, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterErrorNC\n * Signature: (I)Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSParallelPort_isPrinterErrorNC\n  (JNIEnv *, jobject, jint);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/org_eclipse_soda_dk_comm_NSSerialPort.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <jni.h>\n/* Header for class org_eclipse_soda_dk_comm_NSSerialPort */\n#ifndef _Included_org_eclipse_soda_dk_comm_NSSerialPort\n#define _Included_org_eclipse_soda_dk_comm_NSSerialPort\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#undef org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_5\n#define org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_5 5L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_6\n#define org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_6 6L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_7\n#define org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_7 7L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_8\n#define org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_8 8L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_1\n#define org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_1 1L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_2\n#define org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_2 2L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_1_5\n#define org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_1_5 3L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_NONE\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_NONE 0L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_ODD\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_ODD 1L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_EVEN\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_EVEN 2L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_MARK\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_MARK 3L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_SPACE\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_SPACE 4L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_NONE\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_NONE 0L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_RTSCTS_IN\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_RTSCTS_IN 1L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_RTSCTS_OUT\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_RTSCTS_OUT 2L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_XONXOFF_IN\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_XONXOFF_IN 4L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_XONXOFF_OUT\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_XONXOFF_OUT 8L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_5\n#define org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_5 5L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_6\n#define org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_6 6L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_7\n#define org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_7 7L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_8\n#define org_eclipse_soda_dk_comm_NSSerialPort_DATABITS_8 8L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_1\n#define org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_1 1L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_2\n#define org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_2 2L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_1_5\n#define org_eclipse_soda_dk_comm_NSSerialPort_STOPBITS_1_5 3L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_NONE\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_NONE 0L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_ODD\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_ODD 1L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_EVEN\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_EVEN 2L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_MARK\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_MARK 3L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_PARITY_SPACE\n#define org_eclipse_soda_dk_comm_NSSerialPort_PARITY_SPACE 4L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_NONE\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_NONE 0L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_RTSCTS_IN\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_RTSCTS_IN 1L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_RTSCTS_OUT\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_RTSCTS_OUT 2L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_XONXOFF_IN\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_XONXOFF_IN 4L\n#undef org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_XONXOFF_OUT\n#define org_eclipse_soda_dk_comm_NSSerialPort_FLOWCONTROL_XONXOFF_OUT 8L\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    openDeviceNC\n * Signature: (Ljava/lang/String;I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_openDeviceNC\n  (JNIEnv *, jobject, jstring, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    closeDeviceNC\n * Signature: (II)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_closeDeviceNC\n  (JNIEnv *, jobject, jint, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setFlowControlModeNC\n * Signature: (II)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_setFlowControlModeNC\n  (JNIEnv *, jobject, jint, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getFlowControlModeNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getFlowControlModeNC\n  (JNIEnv *, jobject, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    sendBreakNC\n * Signature: (II)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_sendBreakNC\n  (JNIEnv *, jobject, jint, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getBaudRateNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getBaudRateNC\n  (JNIEnv *, jobject, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getDataBitsNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getDataBitsNC\n  (JNIEnv *, jobject, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getStopBitsNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getStopBitsNC\n  (JNIEnv *, jobject, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    getParityNC\n * Signature: (I)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_getParityNC\n  (JNIEnv *, jobject, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setDTRNC\n * Signature: (Z)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_setDTRNC\n  (JNIEnv *, jobject, jboolean);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setRTSNC\n * Signature: (Z)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_setRTSNC\n  (JNIEnv *, jobject, jboolean);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    setSerialPortParamsNC\n * Signature: (IIIII)I\n */\nJNIEXPORT jint JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_setSerialPortParamsNC\n  (JNIEnv *, jobject, jint, jint, jint, jint, jint);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isDTRNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isDTRNC\n  (JNIEnv *, jobject);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isRTSNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isRTSNC\n  (JNIEnv *, jobject);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isCTSNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isCTSNC\n  (JNIEnv *, jobject);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isDSRNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isDSRNC\n  (JNIEnv *, jobject);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isRINC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isRINC\n  (JNIEnv *, jobject);\n/*\n * Class:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    isCDNC\n * Signature: ()Z\n */\nJNIEXPORT jboolean JNICALL Java_org_eclipse_soda_dk_comm_NSSerialPort_isCDNC\n  (JNIEnv *, jobject);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/org_eclipse_soda_dk_comm_ParallelErrorEventThread.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <jni.h>\n/* Header for class org_eclipse_soda_dk_comm_ParallelErrorEventThread */\n#ifndef _Included_org_eclipse_soda_dk_comm_ParallelErrorEventThread\n#define _Included_org_eclipse_soda_dk_comm_ParallelErrorEventThread\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#undef org_eclipse_soda_dk_comm_ParallelErrorEventThread_MAX_PRIORITY\n#define org_eclipse_soda_dk_comm_ParallelErrorEventThread_MAX_PRIORITY 10L\n#undef org_eclipse_soda_dk_comm_ParallelErrorEventThread_MIN_PRIORITY\n#define org_eclipse_soda_dk_comm_ParallelErrorEventThread_MIN_PRIORITY 1L\n#undef org_eclipse_soda_dk_comm_ParallelErrorEventThread_NORM_PRIORITY\n#define org_eclipse_soda_dk_comm_ParallelErrorEventThread_NORM_PRIORITY 5L\n#undef org_eclipse_soda_dk_comm_ParallelErrorEventThread_NANOS_MAX\n#define org_eclipse_soda_dk_comm_ParallelErrorEventThread_NANOS_MAX 999999L\n#undef org_eclipse_soda_dk_comm_ParallelErrorEventThread_INITIAL_LOCAL_STORAGE_CAPACITY\n#define org_eclipse_soda_dk_comm_ParallelErrorEventThread_INITIAL_LOCAL_STORAGE_CAPACITY 5L\n#undef org_eclipse_soda_dk_comm_ParallelErrorEventThread_NO_REF\n#define org_eclipse_soda_dk_comm_ParallelErrorEventThread_NO_REF 0L\n/*\n * Class:     org_eclipse_soda_dk_comm_ParallelErrorEventThread\n * Method:    monitorParallelErrorNC\n * Signature: (I)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_ParallelErrorEventThread_monitorParallelErrorNC\n  (JNIEnv *, jobject, jint);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/org_eclipse_soda_dk_comm_SerialDataEventThread.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <jni.h>\n/* Header for class org_eclipse_soda_dk_comm_SerialDataEventThread */\n#ifndef _Included_org_eclipse_soda_dk_comm_SerialDataEventThread\n#define _Included_org_eclipse_soda_dk_comm_SerialDataEventThread\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#undef org_eclipse_soda_dk_comm_SerialDataEventThread_MAX_PRIORITY\n#define org_eclipse_soda_dk_comm_SerialDataEventThread_MAX_PRIORITY 10L\n#undef org_eclipse_soda_dk_comm_SerialDataEventThread_MIN_PRIORITY\n#define org_eclipse_soda_dk_comm_SerialDataEventThread_MIN_PRIORITY 1L\n#undef org_eclipse_soda_dk_comm_SerialDataEventThread_NORM_PRIORITY\n#define org_eclipse_soda_dk_comm_SerialDataEventThread_NORM_PRIORITY 5L\n#undef org_eclipse_soda_dk_comm_SerialDataEventThread_NANOS_MAX\n#define org_eclipse_soda_dk_comm_SerialDataEventThread_NANOS_MAX 999999L\n#undef org_eclipse_soda_dk_comm_SerialDataEventThread_INITIAL_LOCAL_STORAGE_CAPACITY\n#define org_eclipse_soda_dk_comm_SerialDataEventThread_INITIAL_LOCAL_STORAGE_CAPACITY 5L\n#undef org_eclipse_soda_dk_comm_SerialDataEventThread_NO_REF\n#define org_eclipse_soda_dk_comm_SerialDataEventThread_NO_REF 0L\n/*\n * Class:     org_eclipse_soda_dk_comm_SerialDataEventThread\n * Method:    monitorSerialDataNC\n * Signature: (I)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_SerialDataEventThread_monitorSerialDataNC\n  (JNIEnv *, jobject, jint);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/org_eclipse_soda_dk_comm_SerialStatusEventThread.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <jni.h>\n/* Header for class org_eclipse_soda_dk_comm_SerialStatusEventThread */\n#ifndef _Included_org_eclipse_soda_dk_comm_SerialStatusEventThread\n#define _Included_org_eclipse_soda_dk_comm_SerialStatusEventThread\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#undef org_eclipse_soda_dk_comm_SerialStatusEventThread_MAX_PRIORITY\n#define org_eclipse_soda_dk_comm_SerialStatusEventThread_MAX_PRIORITY 10L\n#undef org_eclipse_soda_dk_comm_SerialStatusEventThread_MIN_PRIORITY\n#define org_eclipse_soda_dk_comm_SerialStatusEventThread_MIN_PRIORITY 1L\n#undef org_eclipse_soda_dk_comm_SerialStatusEventThread_NORM_PRIORITY\n#define org_eclipse_soda_dk_comm_SerialStatusEventThread_NORM_PRIORITY 5L\n#undef org_eclipse_soda_dk_comm_SerialStatusEventThread_NANOS_MAX\n#define org_eclipse_soda_dk_comm_SerialStatusEventThread_NANOS_MAX 999999L\n#undef org_eclipse_soda_dk_comm_SerialStatusEventThread_INITIAL_LOCAL_STORAGE_CAPACITY\n#define org_eclipse_soda_dk_comm_SerialStatusEventThread_INITIAL_LOCAL_STORAGE_CAPACITY 5L\n#undef org_eclipse_soda_dk_comm_SerialStatusEventThread_NO_REF\n#define org_eclipse_soda_dk_comm_SerialStatusEventThread_NO_REF 0L\n/*\n * Class:     org_eclipse_soda_dk_comm_SerialStatusEventThread\n * Method:    monitorSerialStatusNC\n * Signature: (I)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_SerialStatusEventThread_monitorSerialStatusNC\n  (JNIEnv *, jobject, jint);\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32CommDriver.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <stdlib.h>\n#ifndef _WIN32_WCE\n#include <sys/stat.h>\n#include <sys/types.h>\n#endif\n#include \"org_eclipse_soda_dk_comm_NSCommDriver.h\"\n#include \"NSCommLOG.h\"\n#if 0 //t.j\n#include <unistd.h>\n#ifdef _POSIX_SEMAPHORES\n#include <semaphore.h>\n#include \"SysVStyleSemaphore.h\"\n#else \n#include <sys/ipc.h> \n#include <sys/sem.h> \n#endif \n#endif //t.j\n#define assert(s)       if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return;}\n#define CREAT_PERMS\t(0666)\ntypedef struct port_s {\n\tchar\t*portName;\n\tint\t\tportType;\n\tchar\t*deviceName;\n\tint\t\tsemKey;\n} port_t;\nvoid w32CommDriver_discoverDevicesNC(JNIEnv *jenv, jobject jobj) {\n\tjclass\tjc;\n\tjmethodID\tjm;\n\tconst int\tPORT_SERIAL   = 1;\t// should match with CommPortIdentifier\n\tconst int\tPORT_PARALLEL = 2;\t// should match with CommPortIdentifier\n//\tstruct stat\tsbuf;\n\tjstring\t\tpName, dName=NULL;\n\tjthrowable\tjt;\n\tint\t\t\tsemID=0x11223344;\n  port_t\tport_tbl[] =\n\t\t{\n\t\t\t{ \"LPT1\", PORT_PARALLEL, \"LPT1\", 0x11223344 },\n\t\t\t{ \"COM1\", PORT_SERIAL  , \"COM1\", 0x11223345 },\n\t\t\t{ \"COM2\", PORT_SERIAL  , \"COM2\", 0x11223347 },\n\t\t\t{ \"COM3\", PORT_SERIAL  , \"COM3\", 0x11223348 },\n\t\t\t{ \"COM4\", PORT_SERIAL  , \"COM4\", 0x11223349 },\n\t\t\t{ \"COM5\", PORT_SERIAL  , \"COM5\", 0x11223350 },\n\t\t\t{ \"COM6\", PORT_SERIAL  , \"COM6\", 0x11223351 },\n\t\t\t{ \"COM7\", PORT_SERIAL  , \"COM7\", 0x11223352 },\n\t\t\t{ \"COM8\", PORT_SERIAL  , \"COM8\", 0x11223353 },\n\t\t\t{ \"COM9\", PORT_SERIAL  , \"COM9\", 0x11223354 },\n\t\t\t{ \"COM10\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM10\", 0x11223355 },\n\t\t\t{ \"COM11\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM11\", 0x11223356 },\n\t\t\t{ \"COM12\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM12\", 0x11223357 },\n\t\t\t{ \"COM13\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM13\", 0x11223358 },\n\t\t\t{ \"COM14\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM14\", 0x11223359 },\n\t\t\t{ \"COM15\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM15\", 0x11223360 },\n\t\t\t{ \"COM16\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM16\", 0x11223361 },\n\t\t\t{ \"COM17\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM17\", 0x11223362 },\n\t\t\t{ \"COM18\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM18\", 0x11223363 },\n\t\t\t{ \"COM19\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM19\", 0x11223364 },\n\t\t\t{ \"COM20\", PORT_SERIAL  , \"\\\\\\\\.\\\\COM20\", 0x11223365 },\n\t\t};\n  port_t\t*pp;\n  // Get access to the method to add a port.\n  jc = (*jenv)->GetObjectClass(jenv, jobj);\n  assert(jc);\n  jm = (*jenv)->GetMethodID(jenv, jc, \"addDeviceToList\",\n\t\t\t    \"(Ljava/lang/String;ILjava/lang/String;I)V\");\n  assert(jm);\n  // For all the pre-defined ports, check to see which ones exist, and add\n  // them selectively.\n  for (pp = port_tbl; pp < port_tbl+(sizeof(port_tbl)/sizeof(port_tbl[0])); ++pp) {\n\tpName = (*jenv)->NewStringUTF(jenv, pp->portName);\n\tif (!pName) continue;\n    \n\tdName = (*jenv)->NewStringUTF(jenv, pp->deviceName);\n\tif (!dName) continue;\n#if 0 //t.j\n\t\t/* Obtain/create a semaphore for the device in consideration.\n\t\t   If it fails, don't lock/unlock it later on. */\n#ifdef _POSIX_SEMAPHORES\n\t\tsemID = sem_create(pp->semKey, 1);\n#else\n\t\tsemID = semget((key_t)pp->semKey, 1, IPC_CREAT | CREAT_PERMS);\n#endif\n#endif\n#ifdef DEBUG\n//       LOG( (\"pName: %s, %s, dName: %s, semID %d\\n\", pName,pp->portName, dName, semID) );\n       printf( \"pName: %s %s, dNama: %s semID %d\\n\", pName, pp->portName, dName, semID );\n       fflush( stdout );\n#endif\n\t\t\n\t (*jenv)->CallVoidMethod(jenv, jobj, jm,\n\t\t\t\t\tpName, pp->portType, dName, semID);\n\t jt = (*jenv)->ExceptionOccurred(jenv);\n\t if (jt) {\n\t   \t(*jenv)->ExceptionDescribe(jenv);\n\t   \t(*jenv)->ExceptionClear(jenv);\n\t }\n  }\n  return;\n}\t/* Java_org_eclipse_soda_dk_comm_NSCommDriver_discoverDevicesNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32CommPortIdentifier.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include <windows.h>\n#include <winbase.h>\n#ifndef _WIN32_WCE\n#include <sys/types.h>\n#endif\n#include \"javax_comm_CommPortIdentifier.h\"\n#define assertexc(s)  if (!s) {fprintf(stderr, \"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return(-1);}\n#define NOOF_ELEMS(s)\t((sizeof(s))/(sizeof(s[0])))\ntypedef struct port_s {\n\tchar\t*portName;\n\tint\t\tsemKey;\n} port_t;\n//#ifndef _POSIX_SEMAPHORES\n//static struct sembuf\tdev_wait[] = {\n//\t\t{ 0, 0, 0 }\t/* wait until it is free */\n//};\n//#endif\nstatic int\tgetPollingTime(JNIEnv *jenv) {\n  int\t\tptime = 5;\n  jclass\tcic;\n  jfieldID\tptID;\n  jint\t\tpt;\n  do {\n\tcic = (*jenv)->FindClass(jenv, \"javax/comm/CommPortIdentifier\");\n\tif (!cic) break;\n\tptID = (*jenv)->GetStaticFieldID(jenv, cic, \"pollingTime\", \"I\");\n\tif (!ptID) break;\n\tpt = (*jenv)->GetStaticIntField(jenv, cic, ptID);\n\tif (pt > 0)\n\t\tptime = pt;\n  } while (0);\n  return ptime;\n}\t/* getPollingTime() */\n#if 0 //t.j\nstatic int GetSemID(const char *pnm) {\n  int\t\tsemID = -1;\n  port_t\tport_tbl[] =  \n\t  {\n\t\t\t{ \"LPT1\", 0x11223344 },\n\t\t\t{ \"COM1\", 0x11223345 },\n\t\t\t{ \"COM2\", 0x11223347 },\n\t\t\t{ \"COM3\", 0x11223348 },\n\t\t\t{ \"COM4\", 0x11223349 },\n\t\t\t{ \"COM5\", 0x11223350 },\n\t\t\t{ \"COM6\", 0x11223351 },\n\t\t\t{ \"COM7\", 0x11223352 },\n\t\t\t{ \"COM8\", 0x11223353 },\n\t\t\t{ \"COM9\", 0x11223354 },\n\t\t\t{ \"COM10\", 0x11223355 },\n\t\t\t{ \"COM11\", 0x11223356 },\n\t\t\t{ \"COM12\", 0x11223357 },\n\t\t\t{ \"COM13\", 0x11223358 },\n\t\t\t{ \"COM14\", 0x11223359 },\n\t\t\t{ \"COM15\", 0x11223360 },\n\t\t\t{ \"COM16\", 0x11223361 },\n\t\t\t{ \"COM17\", 0x11223362 },\n\t\t\t{ \"COM18\", 0x11223363 },\n\t\t\t{ \"COM19\", 0x11223364 },\n\t\t\t{ \"COM20\", 0x11223365 },\n\t\t};\n  port_t\t*pp;\n  int\t\tkeyFound = 0;\n  /* Find the semaphore key for the corresponding port name. */\n  for (pp = port_tbl;\n       pp < port_tbl+NOOF_ELEMS(port_tbl);\n       ++pp) {\n      if (!strcmp(pp->portName, pnm)) {\n\t  keyFound++;\n\t  break;\n      }\n  }\n  if (!keyFound)\n      return semID;\n#ifndef _POSIX_SEMAPHORES\n  /* Get the semaphore ID for the key obtained. */\n  semID = semget((key_t)pp->semKey, 1, 0);\n#else\n\t/* don't worry about return value for right now */\n  semID = sem_create(pp->semKey, 1);\n#endif /* _POSIX_SEMAPHORES */\n  return semID;\n}\t/* GetSemID() */\n#endif //t.j\n/*\n * Class:     javax_comm_CommPortIdentifier\n * Method:    monitorInterJVMDeviceAccessNC\n * Signature: (Ljava/lang/Thread;)I\n *\n * Currenty not Supported on Posix Devices\n */\nint w32CommPortIdentifier_monitorInterJVMDeviceAccessNC\n\t\t(JNIEnv *jenv, jobject jobj, jobject jtho) {\n\tint\t\tpollingTime;\t/* seconds */\n\tint\t\toldVal, newVal;\n\tjclass\t\tjc;\n\tjmethodID\tjm;\n\tjfieldID\tpnameID;\n\tjstring\t\tpname;\n\tconst char\t*pnamec;\n\tjboolean\tisInterruptedReturn;\n\tjclass\t\tjcpoc;\t\t/* CommPortOwnershipListener interf */\n\tjfieldID\tcpoPOID;\t/* PORT_OWNED ID */\n\tjfieldID\tcpoPUID;\t/* PORT_UNOWNED ID */\n\tjfieldID\tcpoPRID;\t/* PORT_OWNERSHIP_REQUESTED ID */\n\tjint\t\tcpoPO;\t\t/* PORT_OWNED value */\n\tjint\t\tcpoPU;\t\t/* PORT_UNOWNED value */\n\tjint\t\tcpoPR;\t\t/* PORT_OWNERSHIP_REQUESTED value */\n\tjmethodID\tjintMethod;\n\tjclass\t\tjthreadClass;\n//t.j\tint\t\tsemID;\n//t.j\tunion semuni\tscarg;\n//\tint\t\tmypid = getpid();\n//\tint\t\tscpid;\n\tpollingTime = getPollingTime(jenv);\n\t/* Get the class ID of the CommPortIdentifier object.*/\n\tjc = (*jenv)->GetObjectClass(jenv, jobj);\n\tassertexc(jc);\n\t/* Get the id of the method to report a change-ownership event. */\n\tjm = (*jenv)->GetMethodID(jenv, jc, \"fireOwnershipEvent\", \"(I)V\");\n\tassertexc(jm);\n\t/* Get the const values for the CommPortOwnershipListener events.*/\n\tjcpoc = (*jenv)->FindClass(jenv, \"javax/comm/CommPortOwnershipListener\");\n\tassertexc(jcpoc);\n\tcpoPOID = (*jenv)->GetStaticFieldID(jenv, jcpoc, \"PORT_OWNED\", \"I\");\n\tassertexc(cpoPOID);\n\tcpoPO = (*jenv)->GetStaticIntField(jenv, jcpoc, cpoPOID);\n\tcpoPUID = (*jenv)->GetStaticFieldID(jenv, jcpoc, \"PORT_UNOWNED\", \"I\");\n\tassertexc(cpoPUID);\n\tcpoPU = (*jenv)->GetStaticIntField(jenv, jcpoc, cpoPUID);\n\tcpoPRID = (*jenv)->GetStaticFieldID(jenv, jcpoc, \"PORT_OWNERSHIP_REQUESTED\", \"I\");\n\tassertexc(cpoPRID);\n\tcpoPR = (*jenv)->GetStaticIntField(jenv, jcpoc, cpoPRID);\n\t/* Get the port name. */\n\tpnameID = (*jenv)->GetFieldID(jenv, jc, \"name\", \"Ljava/lang/String;\");\n\tassertexc(pnameID);\n\tpname = (*jenv)->GetObjectField(jenv, jobj, pnameID);\n\tassertexc(pname);\n  \tpnamec = (*jenv)->GetStringUTFChars(jenv, pname, 0);\n\t/* Get the corresponding semaphore ID for the port name. */\n//t.j\tsemID = GetSemID(pnamec);\n//\tif (semID == -1)\n//t.j\t\treturn -1;\n\t(*jenv)->ReleaseStringUTFChars(jenv, pname, pnamec);\n\t/* Get access to the interrupted method. */\n\tjthreadClass = (*jenv)->FindClass(jenv, \"java/lang/Thread\");\n\tassertexc(jthreadClass);\n\tjintMethod = (*jenv)->GetMethodID(jenv, jthreadClass, \"isInterrupted\", \"()Z\");\n\tassertexc(jintMethod);\n#if 0 //t.j\n\t(void)memset(&scarg, 0, sizeof(scarg));\n/* what is this for? */\n\t/* Get the current value of the semaphore. */\n#ifdef  _POSIX_SEMAPHORES\n\tif ((sem_getvalue(sem_lookup(semID), &oldVal)) < 0) {\n#else\n\tif ((oldVal = semctl(semID, 0, GETVAL, scarg)) < 0) {\n#endif\t\n\t\t(void)fprintf(stderr, \"Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC: semctl error %d!\\n\", errno);\n\t\treturn -1;\n\t}\n#endif //t.j\t\t\n/* !!!!!!!!!!!!!! */\n\twhile(1)\n\t{\n\t\t/* Check to see if this thread has been interrupted. */\n\t\tisInterruptedReturn = (*jenv)->CallBooleanMethod(jenv, jtho, jintMethod);\n\t\tif(isInterruptedReturn == JNI_TRUE)\n\t\t\tbreak;\n\t\t/* If the semaphore was locked the last time, wait until it\n\t\t   gets unlocked.  Else, catch some breath.\n\t\t */\n\t\tSleep(pollingTime);\n\t\t/* Get the new value of the semaphore. */\n\t\t\t/* Get the current value of the semaphore. */\n#if 0 //t.j\n#ifdef  _POSIX_SEMAPHORES\n\t\tif ((sem_getvalue(sem_lookup(semID), &oldVal)) < 0) {\n#else\n\t\tif ((oldVal = semctl(semID, 0, GETVAL, scarg)) < 0) {\n#endif\t\t\n\t\t\t(void)fprintf(stderr, \"Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC: semctl error %d!\\n\", errno);\n\t\t\treturn -1;\n\t\t}\n\t\tif (newVal == oldVal)\n\t\t\tcontinue;\n\t\t/* Get PID of the last process that changed the semaphore.\n\t\t   If it is the same JVM, ignore this change.\n\t\t */\n\t\t\t/* Get the current value of the semaphore. */\n#ifndef  _POSIX_SEMAPHORES\n   /* DLS HACK needs to be changed */\n\t\tif ((scpid = semctl(semID, 0, GETPID, scarg)) < 0) {\n\t\t\t(void)fprintf(stderr, \"Java_javax_comm_CommPortIdentifier_monitorInterJVMDeviceAccessNC: semctl error %d!\\n\", errno);\n\t\t\treturn -1;\n\t\t}\n\t\tif (scpid != mypid) {\n\t\t\t/* If locked, send a PORT_OWNED event.\n\t\t\t   Else, send a PORT_UNOWNED event.\n\t\t\t */\n\t\t\t(*jenv)->CallVoidMethod(jenv, jobj, jm,\n\t\t\t\t\t\tnewVal ? cpoPO : cpoPU);\n\t\t}\n#endif\n#endif //t.j\t\t\n\t\toldVal = newVal;\n\t}\t/* end of while() */\n\treturn 0;\n} /* w32CommPortIdentifier_monitorInterJVMDeviceAccessNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32DeviceInputStream.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include <windows.h>\n#ifndef _WIN32_WCE\n#include <sys/types.h>\n#endif\n#include \"org_eclipse_soda_dk_comm_NSDeviceInputStream.h\"\n#include \"NSCommLOG.h\"\n#ifndef FALSE\n#define FALSE 0\n#endif\n#ifndef TRUE\n#define TRUE 1\n#endif\n#define READ_TIMEOUT 500\t\t/* milliseconds */\n#define assert(s)  if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return(-1);}\n#define assertexc(s)    if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t (*jenv)->ThrowNew(jenv, ec, \"\");}\n/*\n * Function:   w32DeviceInputStream_readDeviceOneByteNC\n * Purpose:    Read one byte from serial port device \n * Signature: ()I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32DeviceInputStream_readDeviceOneByteNC(JNIEnv *jenv, jobject jobj) {\n    HANDLE      osHandle;\n    BOOL        success;\n    OVERLAPPED  overlap; \n    DWORD       lastRc;\n    DWORD       actualBytes = 0;\n\tjclass\t\tjc;\n\tjclass\t\tec;\n\tjfieldID\tjf;\n\tjint \t\tfd = -1;\n\tchar\t\tbuf[1];\n\t\n#ifdef DEBUG\n    printf(\"w32DeviceOutputStream_writeDeviceNC() entered\\n\");\n#endif /* DEBUG */\n\t/* Get the exception class. */\n\tec = (*jenv)->FindClass(jenv, \"java/io/IOException\");\n\tassert(ec);\n\t/* Get the file descriptor. */\n\tjc = (*jenv)->GetObjectClass(jenv, jobj);\n\tassertexc(jc);\n\tjf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n\tassertexc(jf);\n\tfd = (*jenv)->GetIntField(jenv, jobj, jf);\n\tif (fd == -1) return -1;                    \n    osHandle = (HANDLE) fd;\n    iveSerClearCommErrors(osHandle);\n    memset(&overlap,0,sizeof(overlap));\n    overlap.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);\n    if (NULL == overlap.hEvent) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"Error creating event semaphore\",lastRc);\n        return -1;\n    }\n\tsuccess = ReadFile(osHandle, buf, 1, &actualBytes, &overlap);\n\tif(success) {\n\t\tCloseHandle(overlap.hEvent);\n\t\treturn (int)(unsigned char)buf[0];\n\t} else {\n\t\tlastRc = GetLastError();\n\t\tif (ERROR_IO_PENDING != lastRc) {\n\t\t\tCloseHandle(overlap.hEvent);\n\t\t\tiveSerThrowWin(jenv,\"Error reading data\",lastRc);\n\t\t\treturn -1;\n\t\t}\n\t}\n\tbuf[0] = 0;\n\tactualBytes = 0;\n#ifndef _WIN32_WCE\n\tif (WaitForSingleObject(overlap.hEvent,500) == WAIT_OBJECT_0) {\n\t\tsuccess = GetOverlappedResult(osHandle,&overlap,&actualBytes,TRUE);\n\t}\n\telse {\n\t\tsuccess = FALSE;\n        }\n#endif\n\tif ( success && actualBytes ) {\n\t\tlastRc = (int)(unsigned char)(buf[0]);\n\t} else {\n\t\tlastRc = -1;/*GetLastError();*/\n\t}\n\tCloseHandle(overlap.hEvent);\n\treturn lastRc;\n}\t/* w32DeviceInputStream_readDeviceOneByteNC */\n/*\n * Function:   w32DeviceInputStream_readDeviceNC\n * Purpose:    Read Serial Port Device\n * Signature: ([BII)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32DeviceInputStream_readDeviceNC\n  (JNIEnv *jenv, jobject jobj, jbyteArray jba, jint off, jint len) {\n    HANDLE      osHandle;\n    BOOL        success;\n    OVERLAPPED  overlap; \n    DWORD       lastRc;\n    DWORD       actualBytes = 0;\n\tjclass\t\tjc;\n\tjfieldID\tjf;\n\tjint \t\tfd = -1;\n\tjbyte\t\t*cbuf;\n    jboolean\tisCopy;\n    jfieldID\ttmof;\n    int\t\t    tmo;\n    jfieldID\ttmoDonef;\n\tDWORD eventMask;\n    HGLOBAL     hglob;\n    hglob = GlobalAlloc(GMEM_MOVEABLE, len);\n    if (!hglob)\n    {\n        return (void *) 0;\n    }\n    cbuf = GlobalLock(hglob);\n    if (!cbuf) {\n        GlobalFree(hglob);\n    }\n#ifdef DEBUG\n    printf(\"w32DeviceInputStream_readDeviceNC() entered\\n\");\n#endif /* DEBUG */\n\t/* Get the file descriptor. */\n\tjc = (*jenv)->GetObjectClass(jenv, jobj);\n\tassert(jc);\n\tjf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n\tassert(jf);\n\tfd = (*jenv)->GetIntField(jenv, jobj, jf);\n\tif (fd == -1) return -1;\n\tosHandle = (HANDLE) fd;\n    tmof = (*jenv)->GetFieldID(jenv, jc, \"tmo\", \"I\");\n    assert(tmof);\n    tmoDonef = (*jenv)->GetFieldID(jenv, jc, \"tmoDone\", \"Z\");\n    assert(tmoDonef);\n    tmo = (*jenv)->GetIntField(jenv, jobj, tmof);\n    iveSerClearCommErrors(osHandle);\n    memset(&overlap,0,sizeof(overlap));\n    overlap.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);\n    if (NULL == overlap.hEvent) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"Error creating event semaphore\",lastRc);\n        \n        // Free the bufffer memory\n        hglob = GlobalHandle( cbuf );\n        if (hglob) {\n            GlobalUnlock( hglob );\n            GlobalFree( hglob );\n        }   \t\n        return lastRc;\n    }\n    success = ReadFile(osHandle, cbuf, len, &actualBytes, &overlap);\n\tif(success) {\n\t  // Copy back the data into the java buffer.\n\t  if (actualBytes > 0)\n\t\t(*jenv)->SetByteArrayRegion(jenv, jba, off, actualBytes, (jbyte*)cbuf);\n        // Free the bufffer memory\n        hglob = GlobalHandle( cbuf );\n        if (hglob) {\n            GlobalUnlock( hglob );\n            GlobalFree( hglob );\n        }   \t\n\t\tCloseHandle(overlap.hEvent);\n\t\treturn actualBytes;\n\t} else {\n\t\tlastRc = GetLastError();\n\t\tif (ERROR_IO_PENDING != lastRc) {\n\t\t\tCloseHandle(overlap.hEvent);\n\t\t\tiveSerThrowWin(jenv,\"Error reading data\",lastRc);\n\t\t\t(*jenv)->SetBooleanField(jenv, jobj, tmoDonef, (jboolean)JNI_TRUE);\n\t\n        // Free the bufffer memory\n\t        hglob = GlobalHandle( cbuf );\n\t        if (hglob) {\n\t            GlobalUnlock( hglob );\n\t            GlobalFree( hglob );\n\t        } \n\t\t\t\t\n\t\t\treturn lastRc;\n\t\t}\n\t}\n\t\n\tactualBytes = 0;\n#ifndef _WIN32_WCE\n\tsuccess = GetOverlappedResult(osHandle,&overlap,&actualBytes,TRUE);\n#endif\n\tif (success) {\n\t  // Copy back the data into the java buffer.\n\t  if (actualBytes > 0)\n\t\t(*jenv)->SetByteArrayRegion(jenv, jba, off, actualBytes, (jbyte*)cbuf);\n\t\t\n\t\tlastRc = actualBytes;\n\t} else {\n\t\tlastRc = GetLastError();\n\t}\n\t//Free the bufffer memory\n    hglob = GlobalHandle( cbuf );\n    if (hglob) {\n        GlobalUnlock( hglob );\n        GlobalFree( hglob );\n    }   \n    CloseHandle(overlap.hEvent);\n\treturn lastRc;\n}  /* w32DeviceInputStream_readDeviceNC() */\n/*\n * Function:   w32DeviceInputStream_getReadCountNC\n * Purpose:    Check serial port device event \n * Signature: ()I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32DeviceInputStream_getReadCountNC(JNIEnv *jenv, jobject jobj)\n{\n    DWORD\tdwCommEvent = 0;\n\tHANDLE  osHandle;\n\t\n\tjclass\t\tjc;\n\tjclass\t\tec;\n\tjfieldID\tjf;\n\tjint \t\tfd = -1;\n\tint\t\t\tdc = 0;\n\t// Get the exception class.\n\tec = (*jenv)->FindClass(jenv, \"java/io/IOException\");\n\tassert(ec);\n\t// Get the file descriptor.\n\tjc = (*jenv)->GetObjectClass(jenv, jobj);\n\tassertexc(jc);\n\tjf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n\tassertexc(jf);\n\tfd = (*jenv)->GetIntField(jenv, jobj, jf);\n\tif (fd == -1) {\n\t\t(*jenv)->ThrowNew(jenv, ec, \"\");\n\t}\n\tosHandle = (HANDLE)fd;\n\tif(!GetCommMask( osHandle, &dwCommEvent ))\n\t\treturn GetLastError();\n\t\n\tdwCommEvent |= EV_RXCHAR;\n\tif( !SetCommMask( osHandle, dwCommEvent ))\n\t\treturn GetLastError();\n\tif( !WaitCommEvent( osHandle, &dwCommEvent, NULL ))\n\t\treturn GetLastError();\n\treturn (dwCommEvent&EV_RXCHAR);\n}  /* w32DeviceInputStream_getReadCountNC() */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32DeviceOutputStream.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include <windows.h>\n#ifndef _WIN32_WCE\n#include <sys/types.h>\n#endif\n#include \"org_eclipse_soda_dk_comm_NSDeviceOutputStream.h\"\n#include \"NSCommLOG.h\"\n#define assert(s) if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t     return(-1);}\n/*\n * Class:     org_eclipse_soda_dk_comm_NSDeviceOutputStream\n * Method:    writeDeviceNC\n * Signature: ([BII)I\n */\nint w32DeviceOutputStream_writeDeviceNC\n  (JNIEnv *jenv, jobject jobj, jbyteArray jbuf, jint offset, jint length) {\n    HANDLE      osHandle;\n    BOOL        success;\n#ifndef _WIN32_WCE\n    OVERLAPPED  overlap; \n#endif\n#if _WIN32_WCE>=400\n\tHANDLE\t\tevent;\n#endif\n    DWORD       lastRc;\n    DWORD       actualBytes = 0;\n    jclass\t    jc;\n    jfieldID\tjf;\n    jint \t\tfd = -1;\n    jbyte\t\t*cbuf;\n    jboolean\tisCopy;\n    int\t\t    writecnt = 0;\n    jbyte\t\t*cb;\n#ifdef DEBUG\n    printf(\"w32DeviceOutputStream_writeDeviceNC() entered\\n\");\n#endif /* DEBUG */\n    if (!length) return writecnt;\n    /* Get the file descriptor. */\n    jc = (*jenv)->GetObjectClass(jenv, jobj);\n    assert(jc);\n    jf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n    assert(jf);\n    fd = (*jenv)->GetIntField(jenv, jobj, jf);\n    if (fd == -1) return -1;                    \n    osHandle = (HANDLE) fd;\n    iveSerClearCommErrors(osHandle);\n#if _WIN32_WCE>=400\n    memset(&event,0,sizeof(event));\n    event = CreateEvent(NULL,TRUE,FALSE,NULL);\n    if (event == NULL) {\n        lastRc = GetLastError();\n        LOG((\"iveSerWrite: error creating event semaphore: %d\",lastRc));\n        iveSerThrowWin(jenv,\"Error creating event semaphore\",lastRc);\n        return 0;\n    }\n#else\n    memset(&overlap,0,sizeof(overlap));\n    overlap.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);\n    if (NULL == overlap.hEvent) {\n        lastRc = GetLastError();\n        LOG((\"iveSerWrite: error creating event semaphore: %d\",lastRc));\n        iveSerThrowWin(jenv,\"Error creating event semaphore\",lastRc);\n        return 0;\n    }\n#endif //_WIN32_WCE>=400\n    /* Convert the java byte array buffer into c byte buffer. */\n    cbuf =  (*jenv)->GetByteArrayElements(jenv, jbuf, &isCopy);\n    /* Write the data out to the device. */\n    for ( cb = cbuf+offset; length; length -= actualBytes, writecnt += actualBytes, cb += actualBytes ) {\n#if _WIN32_WCE>=400\n        success = WriteFile(osHandle, cb, length, &actualBytes, 0);\n#else\n        success = WriteFile(osHandle, cb, length, &actualBytes, &overlap);\n#endif //_WIN32_WCE\n        if (success) {\n#ifdef DEBUG\n            printf(\"w32DeviceOutputStream_writeDeviceNC(): write completed successfully without blocking\\n\");\n#endif /* DEBUG */\n#if _WIN32_WCE>=400\n            CloseHandle(event);\n#else\n            CloseHandle(overlap.hEvent);\n#endif //_WIN32_WCE\n            return actualBytes;\n        }\n        lastRc = GetLastError();\n        if (ERROR_IO_PENDING != lastRc) {\n#ifdef DEBUG\n            printf(\"w32DeviceOutputStream_writeDeviceNC(): write failed: %d\\n\", lastRc);\n#endif /* DEBUG */\n#if _WIN32_WCE>=400\n            CloseHandle(event);\n#else\n            CloseHandle(overlap.hEvent);\n#endif //_WIN32_WCE\n            iveSerThrowWin(jenv,\"Error writing data\",lastRc);\n            return 0;\n        }\n        actualBytes = 0;\n#ifndef _WIN32_WCE\n        success = GetOverlappedResult(osHandle,&overlap,&actualBytes,TRUE);\n#endif //_WIN32_WCE\n        if (success) {\n#ifdef DEBUG\n            printf(\"w32DeviceOutputStream_writeDeviceNC(): getOverlappedResult completed successfully\\n\");\n#endif /* DEBUG */\n#if _WIN32_WCE>=400\n            CloseHandle(event);\n#else\n            CloseHandle(overlap.hEvent);\n#endif //_WIN32_WCE\n            return actualBytes;\n        }\n        lastRc = GetLastError();\n#ifdef DEBUG\n        printf(\"w32DeviceOutputStream_writeDeviceNC(): getOverlappedResult failed: %d\\n\",lastRc);\n#endif /* DEBUG */\n#if _WIN32_WCE>=400\n            CloseHandle(event);\n#else\n            CloseHandle(overlap.hEvent);\n#endif //_WIN32_WCE\n        iveSerThrowWin(jenv,\"Error writing pending data\",lastRc);\n    }\n    /* Should we throw some exception in the event of a write error ???? */\n    /* Free the c byte buffer. */\n    (*jenv)->ReleaseByteArrayElements(jenv, jbuf, cbuf, JNI_ABORT);\n    return writecnt;\n}\t/* w32DeviceOutputStream_writeDeviceNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32ParallePort.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nint w32ParallelPort_closeDeviceNC( JNIEnv *, jobject, jint, jint );\nint w32ParallelPort_openDeviceNC( JNIEnv *, jobject, jstring, jint );\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32ParallelErrorEventThread.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <errno.h>\n#include <sys/ioctl.h>\n#ifdef NCI\n#include <dev/ic/lptioctl.h>\n#include <dev/ic/lptreg.h>\n#endif\t/* NCI */\n#ifdef __linux__\n#define __KERNEL__  /* For printer error definitions */\n#include <linux/lp.h>\n#endif\t/* __linux__ */\n#include <org_eclipse_soda_dk_comm_ParallelErrorEventThread.h>\n#define assertexc(s)       if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return;}\nstatic int\tgetPollingTime(JNIEnv *jenv) {\n  int\t\tptime = 5;\n  jclass\tcic;\n  jfieldID\tptID;\n  jint\t\tpt;\n  do {\n\tcic = (*jenv)->FindClass(jenv, \"javax/comm/CommPortIdentifier\");\n\tif (!cic) break;\n\tptID = (*jenv)->GetStaticFieldID(jenv, cic, \"pollingTime\", \"I\");\n\tif (!ptID) break;\n\tpt = (*jenv)->GetStaticIntField(jenv, cic, ptID);\n\tif (pt > 0)\n\t\tptime = pt;\n  } while (0);\n  return ptime;\n}\t// getPollingTime()\n/*\n * Class:     org_eclipse_soda_dk_comm_ParallelErrorEventThread\n * Method:    monitorParallelErrorNC\n * Signature: (I)V\n */\nJNIEXPORT void JNICALL Java_org_eclipse_soda_dk_comm_ParallelErrorEventThread_monitorParallelErrorNC\n(JNIEnv *jenv, jobject jobj, jint jfd) {\n\tint\t\tpollingTime;\t/* seconds */\n\tint\t\toldStatus, newStatus;\n\tjfieldID\tnotifyOnErrorID;\n\tjboolean\tnotifyOnErrorFlag = JNI_TRUE;\n\tjclass\t\tjc;\n\tjmethodID\tjm;\n\tjclass\t\tjppc;\n\tjfieldID\tppID;\n\tjobject\t\tjpp;\n\tjboolean\tisInterruptedReturn;\n\tjclass\t\tjppec;\t\t/* parallel port event class */\n\tjfieldID\tppeErrorID;\t/* field ID */\n\tjint\t\tppeError;\t/* field value */\n\tjmethodID\tjintMethod;\n\tjclass\t\tjthreadClass;\n\tpollingTime = getPollingTime(jenv);\n\t/* Get the const value for the parallel port error event type.*/\n\tjppec = (*jenv)->FindClass(jenv, \"javax/comm/ParallelPortEvent\");\n\tassertexc(jppec);\n\tppeErrorID = (*jenv)->GetStaticFieldID(jenv, jppec, \"PAR_EV_ERROR\", \"I\");\n\tassertexc(ppeErrorID);\n\tppeError = (*jenv)->GetStaticIntField(jenv, jppec, ppeErrorID);\n\t/* Get the parallel port object.*/\n\tjc = (*jenv)->GetObjectClass(jenv, jobj);\n\tassertexc(jc);\n\tppID = (*jenv)->GetFieldID(jenv, jc, \"pp\", \"Lorg/eclipse/soda/dk/comm/NSParallelPort;\");\n\tassertexc(ppID);\n\tjpp = (*jenv)->GetObjectField(jenv, jobj, ppID);\n\tassertexc(jpp);\n\t/* Get the class ID of the parallel port object.*/\n\tjppc = (*jenv)->GetObjectClass(jenv, jpp);\n\tassertexc(jppc);\n\t/* Get the notify flag field ID of the parallel port object. */\n\tnotifyOnErrorID = (*jenv)->GetFieldID(jenv, jppc, \"notifyOnErrorFlag\", \"Z\");\n\tassertexc(notifyOnErrorID);\n\t/* Get access to the method to report a parallel event.*/\n\tjm = (*jenv)->GetMethodID(jenv, jppc, \"reportParallelEvent\", \"(IZZ)V\");\n\tassertexc(jm);\n\t/* Get access to the interrupted method.*/\n\tjthreadClass = (*jenv)->FindClass(jenv, \"java/lang/Thread\");\n\tassertexc(jthreadClass);\n\tjintMethod = (*jenv)->GetMethodID(jenv, jthreadClass, \"isInterrupted\", \"()Z\");\n\tassertexc(jintMethod);\n#ifdef NCI\n\tif (ioctl(jfd, PIOCSTATUS, &oldStatus) < 0) {\n#endif\t/* NCI */\n#ifdef __linux__\n\tif (ioctl(jfd, LPGETSTATUS, &oldStatus) < 0) {\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n        oldStatus = 0;\n\tif (0) {\n#endif\t/* QNX */\n\t\t(void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_ParallelErrorEventThread_monitorParallelErrorNC: ioctl error %d!\\n\", errno);\n\t\treturn;\n\t}\n\twhile(1)\n\t{\n\t\tsleep(pollingTime);\n\t\t/* check to see if this thread has been interrupted */\n\t\tisInterruptedReturn = (*jenv)->CallBooleanMethod(jenv, jobj, jintMethod);\n\t\tif(isInterruptedReturn == JNI_TRUE)\n\t\t\tbreak;\n\t\t/* Get the notify error flag. If not set, skip error checks. */\n\t\tnotifyOnErrorFlag = (*jenv)->GetBooleanField(jenv, jpp, notifyOnErrorID);\n\t\tif (notifyOnErrorFlag != JNI_TRUE)\n\t\t\tcontinue;\n#ifdef NCI\n\t\tif (ioctl(jfd, PIOCSTATUS, &newStatus) < 0) {\n#endif\t/* NCI */\n#ifdef __linux__\n\t\tif (ioctl(jfd, LPGETSTATUS, &newStatus) < 0) {\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n                newStatus = 0;\n\t        if (0) {\n#endif\t/* QNX */\n\t\t\t(void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_ParallelErrorEventThread_monitorParallelErrorNC: ioctl error %d!\\n\", errno);\n\t\t\treturn;\n\t\t}\n\t\tif (newStatus == oldStatus)\n\t\t\tcontinue;\n#ifdef NCI\n\t\tif((newStatus & LPS_NERR) != (oldStatus & LPS_NERR))\n#endif\t/* NCI */\n#ifdef __linux__\n\t\tif((newStatus & LP_PERRORP) != (oldStatus & LP_PERRORP))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_NERR)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_NERR)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_PERRORP)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_PERRORP)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n#ifdef NCI\n\t\tif((newStatus & LPS_SELECT) != (oldStatus & LPS_SELECT))\n#endif\t/* NCI */\n#ifdef __linux__\n\t\tif((newStatus & LP_PSELECD) != (oldStatus & LP_PSELECD))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_SELECT)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_SELECT)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_PSELECD)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_PSELECD)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n#ifdef NCI\n\t\tif((newStatus & LPS_NOPAPER) != (oldStatus & LPS_NOPAPER))\n#endif\t/* NCI */\n#ifdef __linux__\n\t\tif((newStatus & LP_POUTPA) != (oldStatus & LP_POUTPA))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_NOPAPER)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_NOPAPER)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_POUTPA)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_POUTPA)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n#ifdef NCI\n\t\tif((newStatus & LPS_NACK) != (oldStatus & LPS_NACK))\n#endif\t/* NCI */\n#ifdef __linux__\n\t\tif((newStatus & LP_PACK) != (oldStatus & LP_PACK))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_NACK)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_NACK)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_PACK)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_PACK)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n#ifdef NCI\n\t\tif((newStatus & LPS_NBSY) != (oldStatus & LPS_NBSY))\n#endif\t/* NCI */\n#ifdef __linux__\n\t\tif((newStatus & LP_PBUSY) != (oldStatus & LP_PBUSY))\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t        if (0)\n#endif\t/* QNX */\n\t\t{\n\t\t\t(*jenv)->CallVoidMethod(jenv, jpp, jm, ppeError,\n#ifdef NCI\n\t\t\t\t    (oldStatus & LPS_NBSY)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LPS_NBSY)? JNI_TRUE:JNI_FALSE);\n#endif\t/* NCI */\n#ifdef __linux__\n\t\t\t\t    (oldStatus & LP_PBUSY)? JNI_TRUE:JNI_FALSE,\n\t\t\t\t    (newStatus & LP_PBUSY)? JNI_TRUE:JNI_FALSE);\n#endif\t/* __linux__ */\n#ifdef QNX      /* ToDo: implement */\n\t                            JNI_FALSE, JNI_FALSE);\n#endif\t/* QNX */\n\t\t\toldStatus = newStatus;\n\t\t\tcontinue;\n\t\t}\n\t\toldStatus = newStatus;\n\t}\t/* end of while() */\n} /* Java_org_eclipse_soda_dk_comm_ParallelErrorEventThread_monitorParallelErrorNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32ParallelPort.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include <windows.h>\n#include <winbase.h>\n#include <winspool.h>\n#include <sys/types.h>\n#include \"org_eclipse_soda_dk_comm_NSParallelPort.h\"\n#include \"NSCommLOG.h\"\n#define NOOF_ELEMS(s)\t((sizeof(s))/(sizeof(s[0])))\n#define _PRINTER_\nBOOL w32ParallelPort_GetJobs( HANDLE, JOB_INFO_2 **, int *, DWORD * );\n/*\n * Function:   w32ParallelPort_closeDeviceNC\n * Purpose:    Close a parallel I/O Device\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\n */\nint w32ParallelPort_closeDeviceNC\n  (JNIEnv *jenv, jobject jobj, jint fd, jint semId)\n{\n\tHANDLE osHandle = (HANDLE) fd;\n\tjenv;\n#ifdef _PRINTER_\n\treturn ClosePrinter(osHandle);\n#else\n\treturn CloseHandle(osHandle);\n#endif\n}\t/* w32ParallelPort_closeDeviceNC */\n/*\n * Function:   w32ParallelPort_openDeviceNC\n * Purpose:    Open a parallel I/O Device\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - device handle\n */\nint w32ParallelPort_openDeviceNC(JNIEnv *jenv, jobject jobj, jstring name, jint semId)\n{\n\tchar\t* portName = NULL;\n\tint\t\t  fd = -1;\n\tHANDLE\t  osHandle = (HANDLE)fd;\n\tportName = (CHAR *)(*jenv)->GetStringUTFChars(jenv, name, 0);\n\tif( portName == NULL )  {\n#ifdef DEBUG\n\t\tprintf( \"Can not open port because get NULL name\\n\" );\n#endif\n\t\treturn (int)osHandle;\n\t}\n#ifdef _PRINTER_\n\tfd = OpenPrinter( portName,\t\t\t\t/* printer or server name\t*/\n\t\t\t\t\t  &osHandle,\t\t\t/* printer or server handle\t*/\n\t\t\t\t\t  NULL );\t\t\t\t/* printer defaults\t\t\t*/\n\tif(fd == -1) {\n\t\tfd = GetLastError();\n        iveSerThrowWin(jenv,\"parallel port exception: the port isn't valid.\\n\",fd);\n\t\treturn 0;\n\t}\n#else\n\tosHandle =\tCreateFile( portName,\n\t\t\t\t\t\t\tGENERIC_WRITE,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tOPEN_EXISTING,\n\t\t\t\t\t\t\tFILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,\n\t\t\t\t\t\t\t0);\n\tif (INVALID_HANDLE_VALUE == osHandle) {\n\t\tfd = GetLastError();\n\t\tiveSerThrowWin(jenv,\"Error opening file\",fd);\n\t\treturn 0;\n\t}\n#endif\n\t\n\t(*jenv)->ReleaseStringUTFChars(jenv, name, portName);\n\t\n\treturn (int)osHandle;\n}  /* w32ParallelPort_openDeviceNC */\n/*\n * Function:   w32ParallelPort_isPaperOutNC\n * Purpose:    Check the print paper out status\n * Signature:  (I)Z\n * Return:     TRUE, FALSE\n */\nBOOL w32ParallelPort_isPaperOutNC(JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef _PRINTER_\n\tHANDLE\t\t osHandle = (HANDLE)jfd;\n\tJOB_INFO_2  *pJobs;\n\tint\t\t\t cJobs;\n\tDWORD\t\t dwPrinterStatus;\n    /*\n     *  Get the state information for the Printer Queue and\n     *  the jobs in the Printer Queue.\n     */ \n    if (!w32ParallelPort_GetJobs(osHandle, &pJobs, &cJobs, &dwPrinterStatus))\n\t\treturn FALSE;\n    if (dwPrinterStatus & (PRINTER_STATUS_ERROR     |\n\t\t\t\t\t\t   PRINTER_STATUS_PAPER_JAM | \n\t\t\t\t\t\t   PRINTER_STATUS_PAPER_OUT |\n\t\t\t\t\t\t   PRINTER_STATUS_PAPER_PROBLEM )) {\n\t\tfree( pJobs );\n\t\treturn TRUE;\n\t} else\n\treturn FALSE;\n#else\n\treturn FALSE;\n#endif\n}\t/* w32ParallelPort_isPaperOutNC */\n/*\n * Function:   w32ParallelPort_isPrinterBusyNC\n * Purpose:    Check the print busy status\n * Signature:  (I)Z\n * Return:     TRUE, FALSE\n */\nBOOL w32ParallelPort_isPrinterBusyNC(JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef _PRINTER_\n\tHANDLE\t\t osHandle = (HANDLE)jfd;\n\tJOB_INFO_2  *pJobs;\n\tint\t\t\t cJobs;\n\tDWORD\t\t dwPrinterStatus;\n    /*\n     *  Get the state information for the Printer Queue and\n     *  the jobs in the Printer Queue.\n     */ \n    if (!w32ParallelPort_GetJobs(osHandle, &pJobs, &cJobs, &dwPrinterStatus))\n\t\treturn FALSE;\n    if (dwPrinterStatus & (PRINTER_STATUS_ERROR | \n\t\tPRINTER_STATUS_BUSY )) {\n\t\tfree( pJobs );\n\t\treturn TRUE;\n\t} else\n\t\treturn FALSE;\n#else\n\treturn TFALSE;\n#endif\n}\t/* w32ParallelPort_isPrinterBusyNC */\n/*\n * Function:   w32ParallelPort_isPrinterBusyNC\n * Purpose:    Check the print select status\n * Signature:  (I)Z\n * Return:     TRUE, FALSE\n */\nBOOL w32ParallelPort_isPrinterSelectedNC(JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef _PRINTER_\n\tHANDLE\t\t osHandle = (HANDLE)jfd;\n\tJOB_INFO_2  *pJobs;\n\tint\t\t\t cJobs;\n\tDWORD\t\t dwPrinterStatus;\n    /*\n     *  Get the state information for the Printer Queue and\n     *  the jobs in the Printer Queue.\n     */ \n    if (!w32ParallelPort_GetJobs(osHandle, &pJobs, &cJobs, &dwPrinterStatus))\n\t\treturn FALSE;\n    if (dwPrinterStatus & PRINTER_STATUS_PROCESSING ) {\n\t\tfree( pJobs );\n\t\treturn TRUE;\n\t} else\n\t\treturn FALSE;\n#else\n\treturn TFALSE;\n#endif\n}\t/* w32ParallelPort_isPrinterSelectedNC */\n\t\n/*\n * Function:   w32ParallelPort_isPrinterBusyNC\n * Purpose:    Check the printer out status\n * Signature:  (I)Z\n * Return:     TRUE, FALSE\n */\nBOOL w32ParallelPort_isPrinterTimedOutNC(JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef _PRINTER_\n\tHANDLE\t\t osHandle = (HANDLE)jfd;\n\tJOB_INFO_2  *pJobs;\n\tint\t\t\t cJobs;\n\tDWORD\t\t dwPrinterStatus;\n    /*\n     *  Get the state information for the Printer Queue and\n     *  the jobs in the Printer Queue.\n     */ \n    if (!w32ParallelPort_GetJobs(osHandle, &pJobs, &cJobs, &dwPrinterStatus))\n\t\treturn FALSE;\n    if (dwPrinterStatus & PRINTER_STATUS_PENDING_DELETION ) {\n\t\tfree( pJobs );\n\t\treturn TRUE;\n\t} else\n\t\treturn FALSE;\n#else\n\treturn TFALSE;\n#endif\n}\t/* w32ParallelPort_isPrinterTimedOutNC */\n/*\n * Class:     org_eclipse_soda_dk_comm_NSParallelPort\n * Method:    isPrinterErrorNC\n * Signature: (I)Z\n * Return:     TRUE, FALSE\n */\nBOOL w32ParallelPort_isPrinterErrorNC(JNIEnv *jenv, jobject jobj, jint jfd)\n{\n#ifdef _PRINTER_\n\tHANDLE\t\tosHandle = (HANDLE)jfd;\n    DWORD       dwPrinterStatus;\n    JOB_INFO_2  *pJobs;\n    int         cJobs, i;\n    /*\n     *  Get the state information for the Printer Queue and\n     *  the jobs in the Printer Queue.\n     */ \n    if (!w32ParallelPort_GetJobs(osHandle, &pJobs, &cJobs, &dwPrinterStatus))\n\t\treturn FALSE;\n    if (dwPrinterStatus & (PRINTER_STATUS_ERROR |\n\t\t\t\t\t\t   PRINTER_STATUS_PAPER_JAM |\n\t\t\t\t\t\t   PRINTER_STATUS_PAPER_OUT |\n\t\t\t\t\t\t   PRINTER_STATUS_PAPER_PROBLEM |\n\t\t\t\t\t\t   PRINTER_STATUS_OUTPUT_BIN_FULL |\n\t\t\t\t\t\t   PRINTER_STATUS_NOT_AVAILABLE |\n\t\t\t\t\t\t   PRINTER_STATUS_NO_TONER |\n\t\t\t\t\t\t   PRINTER_STATUS_OUT_OF_MEMORY |\n\t\t\t\t\t\t   PRINTER_STATUS_OFFLINE |\n\t\t\t\t\t\t   PRINTER_STATUS_DOOR_OPEN)) {\n          free( pJobs );\n          return TRUE;\n     }\n     for (i=0; i < cJobs; i++)\n     {\n        if (pJobs[i].Status & JOB_STATUS_PRINTING)\n        {\n            if (pJobs[i].Status & (JOB_STATUS_ERROR |\n\t\t\t\t\t\t\t\t   JOB_STATUS_OFFLINE |\n\t\t\t\t\t\t\t\t   JOB_STATUS_PAPEROUT |\n\t\t\t\t\t\t\t\t   JOB_STATUS_BLOCKED_DEVQ)) {\n                free( pJobs );\n                return TRUE;\n            }\n        }\n     }\n    free( pJobs );\n    return FALSE;\n#endif\n}\t/* w32ParallelPort_isPrinterErrorNC */\n/*\n * Class:      w32ParallelPort_GetJobs\n * Method:     reading the printer / printer job status\n * Signature:  (I)Z\n * Return:     TRUE, FALSE\n */\nBOOL w32ParallelPort_GetJobs( HANDLE osHandle, JOB_INFO_2 **ppJobInfo,\n\t\t\t\t\t\t\t  int *pcJobs, DWORD *pStatus)\n{\n    DWORD           cByteNeeded,\n                    nReturned,\n                    cByteUsed;\n    JOB_INFO_2      *pJobStorage  = NULL;\n    PRINTER_INFO_2  *pPrinterInfo = NULL;\n   /* Get the buffer size needed. */ \n    if (!GetPrinter(osHandle, 2, NULL, 0, &cByteNeeded))\n    {\n        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)\n           return FALSE;\n    }\n    pPrinterInfo = (PRINTER_INFO_2 *)malloc(cByteNeeded);\n    if (!(pPrinterInfo)) return FALSE;\n    if (!GetPrinter(osHandle,\n\t\t\t\t    2,\n\t \t\t\t    (LPSTR)pPrinterInfo,\n\t\t\t\t\tcByteNeeded,\n\t\t\t\t\t&cByteUsed))\n    {\n        free(pPrinterInfo);\n        pPrinterInfo = NULL;\n        return FALSE;\n    }\n    if (!EnumJobs(osHandle,\n\t\t\t\t  0,\n\t\t\t\t  pPrinterInfo->cJobs,\n\t\t\t\t  2,\n\t\t\t\t  NULL,\n\t\t\t\t  0,\n\t\t\t\t  (LPDWORD)&cByteNeeded,\n\t\t\t\t  (LPDWORD)&nReturned))\n    {\n        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)\n        {\n            free(pPrinterInfo);\n            pPrinterInfo = NULL;\n            return FALSE;\n        }\n    }\n    pJobStorage = (JOB_INFO_2 *)malloc(cByteNeeded);\n    if (!pJobStorage)\n    {\n        free(pPrinterInfo);\n        pPrinterInfo = NULL;\n        return FALSE;\n    }\n    ZeroMemory(pJobStorage, cByteNeeded);\n    if (!EnumJobs(osHandle,\n\t\t\t\t  0,\n\t\t\t\t  pPrinterInfo->cJobs,\n\t\t\t\t  2,\n\t\t\t\t  (LPBYTE)pJobStorage,\n\t\t\t\t  cByteNeeded,\n\t\t\t\t  (LPDWORD)&cByteUsed,\n\t\t\t\t  (LPDWORD)&nReturned))\n    {\n         free(pPrinterInfo);\n         free(pJobStorage);\n         pJobStorage = NULL;\n         pPrinterInfo = NULL;\n         return FALSE;\n    }\n    *pcJobs = nReturned;\n    *pStatus = pPrinterInfo->Status;\n    *ppJobInfo = pJobStorage;\n    free(pPrinterInfo);\n    return TRUE;\n} /* w32ParallelPort_GetJobs() */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32SerialDataEventThread.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <windows.h>\n#include <winsock2.h>\n#ifndef _WIN32_WCE\n#include <errno.h>\n#else\n#include <winsock2.h>\n#endif\n#include \"org_eclipse_soda_dk_comm_SerialDataEventThread.h\"\n#define assertexc(s)       if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return;}\nstatic int\tgetPollingTime(JNIEnv *jenv) {\n  int\t\tptime = 5;\n  jclass\tcic;\n  jfieldID\tptID;\n  jint\t\tpt;\n  do {\n\tcic = (*jenv)->FindClass(jenv, \"javax/comm/CommPortIdentifier\");\n\tif (!cic) break;\n\tptID = (*jenv)->GetStaticFieldID(jenv, cic, \"pollingTime\", \"I\");\n\tif (!ptID) break;\n\tpt = (*jenv)->GetStaticIntField(jenv, cic, ptID);\n\tif (pt > 0)\n\t\tptime = pt;\n  } while (0);\n  return ptime;\n}\t/* getPollingTime() */\n#if _WIN32_WCE>=400\nstatic int getStopThreadFlag(JNIEnv *jenv, jobject jobj)\n{\n\tjclass cls;\n\tjfieldID fid;\n\tjint stopThreadFlag;\n\t\n\tcls = (*jenv)->GetObjectClass(jenv, jobj);\n\tif (!cls) (*jenv)->FatalError(jenv, \"Missing class\");\n\t\n\tfid = (*jenv)->GetFieldID(jenv, cls, \"stopThreadFlag\", \"I\");\n\tif (fid == NULL) (*jenv)->FatalError(jenv, \"Missing field\");\n\t\n\tstopThreadFlag = (*jenv)->GetIntField(jenv, jobj, fid);\n\t\n\treturn stopThreadFlag;\t\n}\n#endif //_WIN32_WCE>=400\n/*\n * Class:     org_eclipse_soda_dk_comm_SerialDataEventThread\n * Method:    monitorSerialDataNC\n * Signature: (I)V\n */\nvoid w32SerialDataEventThread_monitorSerialDataNC\n  (JNIEnv *jenv, jobject jobj, jint jfd) {\n    jclass\t\tjspec;\t\t\t\t\t/* serial port event class */\n    fd_set\t\tr_mask;\n    jfieldID\tdata_available_id;      /* field ID */\n    jint\t\tdata_available_event;\t/* field value */\n    jclass      jc;\n    jmethodID   jm;\n    jfieldID    spID;\n    jobject\t\tjsp;\n    jclass\t\tjspc;\n    jfieldID\tnotifyOnDataAvailableID;\n    jboolean\tnotifyOnDataAvailableFlag = JNI_FALSE;\n    int\t\t\tresult;\n\tint\t\t\tpollingTime;\t\t\t/* seconds */\n\tstruct\t\ttimeval\ttv;\n\tjboolean\tisInterruptedReturn;\n\tjclass\t\tjthreadClass;\n\tjmethodID\tjintMethod;\n#if _WIN32_WCE>=400\n\tjint \t\tstopThreadFlag;\n#endif\n\tpollingTime = getPollingTime(jenv);\n    jspec = (*jenv)->FindClass(jenv, \"javax/comm/SerialPortEvent\");\n    assertexc(jspec);\n    data_available_id = (*jenv)->GetStaticFieldID(jenv, jspec, \"DATA_AVAILABLE\", \"I\");\n    assertexc(data_available_id);\n    data_available_event = (*jenv)->GetStaticIntField(jenv, jspec, data_available_id);\n    /* Get the serial port object.*/\n    jc = (*jenv)->GetObjectClass(jenv, jobj);\n    assertexc(jc);\n    spID = (*jenv)->GetFieldID(jenv, jc, \"serialPort\", \"Lorg/eclipse/soda/dk/comm/NSSerialPort;\");\n    assertexc(spID);\n    jsp = (*jenv)->GetObjectField(jenv, jobj, spID);\n    assertexc(jsp);\n    /* Get the class ID of the serial port object.*/\n    jspc = (*jenv)->GetObjectClass(jenv, jsp);\n    assertexc(jspc);\n    /* Get access to the method to add a port.*/\n    jm = (*jenv)->GetMethodID(jenv, jspc, \"reportSerialEvent\", \"(IZZ)V\");\n    assertexc(jm);\n    notifyOnDataAvailableID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnDataFlag\", \"Z\");\n    assertexc(notifyOnDataAvailableID);\n\t/* Get access to the interrupted method.*/\n\tjthreadClass = (*jenv)->FindClass(jenv, \"java/lang/Thread\");\n\tassertexc(jthreadClass);\n\tjintMethod = (*jenv)->GetMethodID(jenv, jthreadClass, \"isInterrupted\", \"()Z\");\n\tassertexc(jintMethod);\n\twhile(1)\n\t{\n#if _WIN32_WCE>=400\n\t\tstopThreadFlag = getStopThreadFlag(jenv, jobj);\n\t\tif (stopThreadFlag)\n\t\t\tbreak;\t \t\n#endif\n\t\t/* check to see if this thread has been interrupted */\n\t\tisInterruptedReturn = (*jenv)->CallBooleanMethod(jenv,jobj,jintMethod);\n\t\tif(isInterruptedReturn == JNI_TRUE)\n\t\t\tbreak;\n\t\tmemset(&tv, 0, sizeof(tv));\n\t\ttv.tv_sec = pollingTime;\n\t\tFD_ZERO(&r_mask);\n\t\tFD_SET(jfd, &r_mask);\n\t\tresult = select(jfd + 1, &r_mask, NULL, NULL, &tv);\n#ifndef _WIN32_WCE\n\t\tif (result == -1 && errno != EINTR) break;\n#endif\n\t\tif (!result)  continue;\n\t\tif (FD_ISSET(jfd, &r_mask))\n\t\t{\n\t\t\tnotifyOnDataAvailableFlag = (*jenv)->GetBooleanField(jenv, jsp, notifyOnDataAvailableID);\n\t\t\tif(notifyOnDataAvailableFlag)\n\t\t\t\t(*jenv)->CallVoidMethod(jenv, jsp, jm, data_available_event, JNI_TRUE, JNI_TRUE);\n        }\n    }\n} /* w32SerialDataEventThread_monitorSerialDataNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32SerialPort.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include <windows.h>\n#include <winbase.h>\n#ifndef _WIN32_WCE\n#include <sys/types.h>\n#endif //_WIN32_WCE\n#include \"org_eclipse_soda_dk_comm_NSSerialPort.h\"\n#include \"NSCommLOG.h\"\n#if 0 //t.j\n#ifdef _POSIX_SEMAPHORES\n#include <semaphore.h>\n#include \"SysVStyleSemaphore.h\"\n#else \n#include <sys/ipc.h> \n#include <sys/sem.h> \n#endif\n#define NOOF_ELEMS(s)\t((sizeof(s))/(sizeof(s[0])))\n#ifndef _POSIX_SEMAPHORES\nstatic struct sembuf\tdev_test[] = {\n\t\t{ 0, 0, IPC_NOWAIT }\t/* test to see if it is free */\n};\nstatic struct sembuf\tdev_lock[] = {\n\t\t{ 0, 0, 0 },\t/* wait for the semaphore to be free */\n\t\t{ 0, 1, SEM_UNDO }\t/* lock it */\n};\nstatic struct sembuf\tdev_unlock[] = {\n\t\t// { 0, -1, (IPC_NOWAIT | SEM_UNDO) }\t/* unlock it */\n\t\t{ 0, -1,  0  }   \t/* wait til unlock it */\n};\n#endif\n#endif //t.j\n#define assert(s)  if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n\t\t\t\t return(-1);}\n/*------------------------------------------------------------------\n * constants\n *------------------------------------------------------------------*/\n#define W32COMM_PARITY_NONE       0\n#define W32COMM_PARITY_ODD        1\n#define W32COMM_PARITY_EVEN       2\n#define W32COMM_PARITY_MARK       3\n#define W32COMM_PARITY_SPACE      4\n#define W32COMM_STOPBITS_1_5      0\n#define W32COMM_STOPBITS_1        1\n#define W32COMM_STOPBITS_2        2\n#define W32COMM_DATABITS_5        5\n#define W32COMM_DATABITS_6        6\n#define W32COMM_DATABITS_7        7\n#define W32COMM_DATABITS_8        8\n#define assertexc(s) if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); \\\n                            return(-1);}\njint w32getfd(JNIEnv *jenv, jobject jobj)\n{\n    jclass        jc;\n    jfieldID      jf;\n    jint          fd = -1;\n    // Get the file descriptor.\n    jc = (*jenv)->GetObjectClass(jenv, jobj);\n    assertexc(jc);\n    jf = (*jenv)->GetFieldID(jenv, jc, \"fd\", \"I\");\n    assertexc(jf);\n    return (*jenv)->GetIntField(jenv, jobj, jf);\n}  /* w32getfd() */\n/*\n * Function:   w32SerialPort_closeDeviceNC\n * Purpose:    Close a I/O Device\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\n */\nint w32SerialPort_closeDeviceNC\n  (JNIEnv *env, jobject jobj, jint fd, jint semId)\n{\n\tHANDLE osHandle = (HANDLE) fd;\n\tenv;\n\treturn CloseHandle(osHandle);\n}\t/* w32SerialPort_closeDeviceNC */\n/*\n * Function:   w32SerialPort_openDeviceNC\n * Purpose:    open a I/O Device\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32SerialPort_openDeviceNC\n  (JNIEnv *jenv, jobject jobj, jstring name, jint semId)\n{\n#if _WIN32_WCE>=400\n\t//TCHAR\t\tappends[2] = L\":\";\n\t//const unsigned short *portName = NULL;\n\t//const unsigned short *portName_wince = NULL;\n\tLPTSTR\tportName = NULL;\n\tLPTSTR\tportName_wince = NULL;\n\tLPTSTR\tappends = TEXT(\":\");\n#else\n\tconst char *portName = NULL;\n#endif\n\tint\t\t\tfd = -1;\n\tHANDLE      osHandle;\n#ifdef WINCE\n\tportName = (*jenv)->GetStringChars(jenv, name, 0);\n#else\n\tportName = (*jenv)->GetStringUTFChars(jenv, name, 0);\n#endif //_WIN32_WCE\n\tif( portName == NULL )\n\t{\n#ifdef DEBUG\n//\t\tLOG((\"Can not open port because get NULL name\\n\"));\n\t\tprintf( \"Can not open port because get NULL name\\n\" );\n\t    fflush( stdout );\n#endif\n\t\tprintf(\"portName is NULL\\n\");\n\t\treturn fd;\n\t}\n#if _WIN32_WCE>=400\n\tlstrcat(portName, appends);\n\t// TEXT(\"COM1:\")\n\t\n\tosHandle =\tCreateFile(\n\t\t\t\tportName,\n\t\t\t\tGENERIC_READ | GENERIC_WRITE,\n\t\t\t\t0,\n\t\t\t\tNULL,\n\t\t\t\tOPEN_EXISTING,\n\t\t\t\t0,\n\t\t\t\tNULL);\n#else\n\tosHandle =\tCreateFile(\n\t\t\t\tportName,\n\t\t\t\tGENERIC_READ | GENERIC_WRITE,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t\tOPEN_EXISTING,\n\t\t\t\tFILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,\n\t\t\t\t0);\n#endif //_WIN32_WCE\n\t\n\tif (INVALID_HANDLE_VALUE == osHandle) {\n\t\tfd = GetLastError();\n\t\tiveSerThrowWin(jenv,\"Error opening port\", fd);\n\t\treturn 0;\n\t}\n#if _WIN32_WCE>=400\n\t(*jenv)->ReleaseStringChars(jenv, name, portName);\n#else\n\t(*jenv)->ReleaseStringUTFChars(jenv, name, portName);\n#endif //_WIN32_WCE\n#ifdef DEBUG\n//\t\tLOG((\"w32SerialPort_openDeviceNC(%s)\",portName));\n\t\tprintf( \"w32SerialPort_openDeviceNC(%s) osHandle: %d\\n\", portName, osHandle );\n\t    fflush( stdout );\n#endif\n\treturn (jint) osHandle;\n}  /* w32SerialPort_openDeviceNC */\n/*\n * Function:   w32SerialPort_setFlowControlModeNC\n * Purpose:    setup the comm port flow control\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32SerialPort_setFlowControlModeNC(JNIEnv *jenv, jobject jobj, jint fd, jint fc )\n{\n    HANDLE  osHandle = (HANDLE) fd;\n    DWORD   lastRc;\n    DCB     dcb;\n    BOOL    success;\n\t(void)memset(&dcb, 0, sizeof(DCB));\n    success = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n        return success;\n    }\n\tif (fc == 0) {\t\t\t// None for both hardware and software\n\t\t /* Do nothing, as all the flow control modes are already turned off now. */\n\t\tdcb.fOutxCtsFlow      = FALSE; //(config->hardwareFlowControl != 0);\n\t    dcb.fOutxDsrFlow      = FALSE; \n\t\tdcb.fTXContinueOnXoff = FALSE;\n\t    dcb.fOutX             = FALSE; //(config->softwareFlowControl != 0);\n\t\tdcb.fInX              = FALSE; //(config->softwareFlowControl != 0);\n\t} else {\n\t\tif (fc & 1) {\t\t/* hardware flow control RTSCTS_IN */\n\t\t\tdcb.fOutxCtsFlow  = TRUE; \n\t\t\tdcb.fRtsControl   = RTS_CONTROL_ENABLE;\n\t\t }\n\t\t if (fc & 2) {\t\t/* hardware flow control RTSCTS_OUT */\n\t\t\tdcb.fOutxCtsFlow  = TRUE; \n\t\t\tdcb.fRtsControl   = RTS_CONTROL_ENABLE;\n\t\t }\n\t\t if (fc & 4) {\t\t/* software flow control XONXOFF_IN */\n\t\t\tdcb.fInX = TRUE;\n\t\t }\n\t\t if (fc & 8) {\t\t/* software flow control XONXOFF_OUT */\n\t\t\tdcb.fOutX  = TRUE;\n\t\t } \n\t}\n\tsuccess = SetCommState(osHandle,&dcb);\n\tif (!success) {\n\t\tlastRc = GetLastError();\n\t\tiveSerThrowWin(jenv,\"SetCommState() failed\",lastRc);\n\t\tprintf(\"w32SerialPort_setDTRNC() failed to set the DCB: %d\\n\", success);\n\t}\n\treturn success;\n}  /* w32SerialPort_setFlowControlModeNC */\n/*\n * Function:   w32SerialPort_getFlowControlModeNC\n * Purpose:    get the current comm port flow control settings\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32SerialPort_getFlowControlModeNC(JNIEnv *jenv, jobject jobj, jint fd )\n{\n    HANDLE  osHandle = (HANDLE) fd;\n    DWORD   lastRc;\n    DCB     dcb;\n    int     ret = -1;\n\t(void)memset(&dcb, 0, sizeof(DCB));\n    ret = GetCommState(osHandle,&dcb);\n    if (!ret) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n        return ret;\n    }\n  // Determine the flow control.\n  if ( !dcb.fOutxCtsFlow && !dcb.fOutxDsrFlow && !dcb.fTXContinueOnXoff && !dcb.fOutX && !dcb.fInX )\n     ret = 0;\t\t\t\t/* None for both hardware and software flow control */\n  else {\n     ret = 0;\n     if ( dcb.fOutxCtsFlow && (dcb.fRtsControl==RTS_CONTROL_ENABLE) )\t/* hardware flow control RTSCTS_IN */\n        ret |= 1;\n     if ( dcb.fOutxCtsFlow && (dcb.fRtsControl==RTS_CONTROL_ENABLE) )\t/* hardware flow control RTSCTS_IN */\n        ret |= 2;\n     if (dcb.fInX  & TRUE)\t\t/* software flow control XONXOFF_IN */\n        ret |= 4;\n     if (dcb.fOutX & TRUE)\t\t/* software flow control XONXOFF_OUT */\n        ret |= 8;\n  }\n  \n  return ret;\n} /* w32SerialPort_getFlowControlModeNC */\n/*\n * Function:   w32SerialPort_getBaudRateNC\n * Purpose:    get the current comm port baud rate settings\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32SerialPort_getBaudRateNC(JNIEnv *jenv, jobject jobj, jint fd)\n{\n    HANDLE  osHandle = (HANDLE) fd;\n    DWORD   lastRc;\n    DCB     dcb;\n    BOOL    success;\n\t(void)memset(&dcb, 0, sizeof(DCB));\n    success = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n        return success;\n    }\n#ifdef DEBUG\n\tprintf( \"win32SerialPort_getBaudRateNC(), baud rate: %d\\n\", dcb.BaudRate );\n\tfflush( stdout ); \n#endif\n\treturn dcb.BaudRate;\n}  /* w32SerialPort_getBaudRateNC() */\n/*\n * Function:   w32SerialPort_getDataBitsNC\n * Purpose:    get the current comm port data bits settings\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32SerialPort_getDataBitsNC(JNIEnv *jenv, jobject jobj, jint fd)\n{\n    HANDLE  osHandle = (HANDLE) fd;\n    DWORD   lastRc;\n    DCB     dcb;\n    BOOL    success;\n\t(void)memset(&dcb, 0, sizeof(DCB));\n    success = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n        return success;\n    }\n#ifdef DEBUG\n\tprintf( \"w32SerialPort_getDataBitsNC(), baud rate: %d\\n\", dcb.ByteSize );\n\tfflush( stdout ); \n#endif\n\treturn dcb.ByteSize;\n}  /* w32SerialPort_getDataBitsNC() */\n   \n/*\n * Function:   w32SerialPort_getStopBitsNC\n * Purpose:    get the current comm port stop bits settings\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32SerialPort_getStopBitsNC(JNIEnv *jenv, jobject jobj, jint fd)\n{\n    HANDLE  osHandle = (HANDLE) fd;\n    DCB     dcb;\n    DWORD   lastRc;\n    BOOL    success;\n    BYTE    stopBits;\n\t(void)memset(&dcb, 0, sizeof(DCB));\n    success = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n        return success;\n    }\n\t\n    switch (dcb.StopBits) {\n\t\tcase ONE5STOPBITS:\tstopBits = W32COMM_STOPBITS_1_5; break;\n        case TWOSTOPBITS:\tstopBits = W32COMM_STOPBITS_2;   break;\n        case ONESTOPBIT:   \n        default:            stopBits = W32COMM_STOPBITS_1;   break;\n    }\n\treturn (jint) stopBits;\n}  /* w32SerialPort_getStopBitsNC() */\n/*\n * Function:   w32SerialPort_getParityNC\n * Purpose:    get the current comm port parity bits settings\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32SerialPort_getParityNC(JNIEnv *jenv, jobject jobj, jint fd)\n{\n    HANDLE  osHandle = (HANDLE) fd;\n    DCB     dcb;\n    DWORD   lastRc;\n    BOOL    success;\n    BYTE    parity;\n\t(void)memset(&dcb, 0, sizeof(DCB));\n    success = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n        return success;\n    }\n\t\n\tif ( dcb.fParity == TRUE )\n\t{\n\t    switch (dcb.Parity) {\n\t\t\tcase EVENPARITY:   parity = W32COMM_PARITY_EVEN;  break;\n\t\t\tcase ODDPARITY:    parity = W32COMM_PARITY_ODD;   break;\n\t\t\tcase MARKPARITY:   parity = W32COMM_PARITY_MARK;  break;\n\t\t\tcase SPACEPARITY:  parity = W32COMM_PARITY_SPACE; break;\n\t\t\tcase NOPARITY:\t   \n\t\t\tdefault:           parity = W32COMM_PARITY_NONE;  break;\n    \n\t\t}\n\t}\n#ifdef DEBUG\n\tprintf( \"win32SerialPort_getParityNC():  parity = %d\\n\", parity); \n#endif /* DEBUG */\n  \n\treturn (jint) parity;\n} /* w32SerialPort_getParityNC() */\n/*\n * Function:   w32SerialPort_setDTRNC\n * Purpose:    setup the comm port DTR bit settings\n * Signature: (Ljava/lang/String;I)I\n * Return:     none\t\n */\nvoid w32SerialPort_setDTRNC(JNIEnv *jenv, jobject jobj, jboolean bool)\n{\n    DCB     dcb;\n    DWORD   lastRc;\n    BOOL    success;\n    HANDLE  osHandle = (HANDLE) w32getfd(jenv, jobj);\n\t(void)memset(&dcb, 0, sizeof(DCB));\n    success = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n\t\tprintf(\"w32SerialPort_setDTRNC() failed to get the DCB: %d\\n\", success);\n    }\n\tdcb.fDtrControl = DTR_CONTROL_ENABLE;\n    success = SetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"SetCommState() failed\",lastRc);\n\t\tprintf(\"w32SerialPort_setDTRNC() failed to set the DCB: %d\\n\", success);\n    }\n}  /* w32SerialPort_setDTRNC() */\n/*\n * Function:   w32SerialPort_isDTRNC\n * Purpose:    checking the current comm port DTR bit settings\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nBOOL w32SerialPort_isDTRNC(JNIEnv *jenv, jobject jobj)\n{\n    DCB     dcb;\n    DWORD   lastRc;\n    BOOL    success;\n    HANDLE  osHandle = (HANDLE) w32getfd(jenv, jobj);\n\tif (osHandle == (HANDLE)-1) return -1;                    \n\t(void)memset(&dcb, 0, sizeof(DCB));\n    success = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n\t\tprintf(\"w32SerialPort_setDTRNC() failed to get the DCB: %d\\n\", success);\n    }\n\treturn (dcb.fDtrControl & DTR_CONTROL_ENABLE);\n}  /* w32SerialPort_isDTRNC() */\n/*\n * Function:   w32SerialPort_setRTSNC\n * Purpose:    setup the comm port RTS bit\n * Signature: (Ljava/lang/String;I)I\n * Return:     none\t\n */\nvoid w32SerialPort_setRTSNC(JNIEnv *jenv, jobject jobj, jboolean bool)\n{\n    DCB     dcb;\n    DWORD   lastRc;\n    BOOL    success;\n    HANDLE  osHandle = (HANDLE) w32getfd(jenv, jobj);\n\t(void)memset(&dcb, 0, sizeof(DCB));\n    success = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n\t\tprintf(\"w32SerialPort_setDTRNC() failed to get the DCB: %d\\n\", success);\n    }\n\tdcb.fRtsControl = RTS_CONTROL_ENABLE;\n    success = SetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"SetCommState() failed\",lastRc);\n\t\tprintf(\"w32SerialPort_setDTRNC() failed to set the DCB: %d\\n\", success);\n    }\n}  /* w32SerialPort_setRTSNC() */\n/*\n * Function:   w32SerialPort_isRTSNC\n * Purpose:    checking the current comm port RTS bit settings\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nBOOL w32SerialPort_isRTSNC( JNIEnv *jenv, jobject jobj )\n{\n    DCB     dcb;\n    DWORD   lastRc;\n    BOOL    success;\n    HANDLE  osHandle = (HANDLE) w32getfd(jenv, jobj);\n\tif (osHandle == (HANDLE)-1) return -1;                    \n\t(void)memset(&dcb, 0, sizeof(DCB));\n    success = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n\t\tprintf(\"w32SerialPort_isRTSNC() failed to get the DCB: %d\\n\", success);\n    }\n\treturn (dcb.fRtsControl&RTS_CONTROL_ENABLE);\n}  /* w32SerialPort_isRTSNC() */\n/*\n * Function:   w32SerialPort_isCTSNC\n * Purpose:    checking the current comm port CTS bit\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nBOOL w32SerialPort_isCTSNC( JNIEnv *jenv, jobject jobj )\n{\n    DWORD\tdwCommFlags = 0;\n\tHANDLE  osHandle = (HANDLE) w32getfd(jenv, jobj);\n\tif (osHandle == (HANDLE)-1) return -1;                    \n\t\n\tGetCommModemStatus( osHandle, &dwCommFlags );\n\treturn  (dwCommFlags&MS_CTS_ON);\n}  /* w32SerialPort_isCTSNC */\n/*\n * Function:   w32SerialPort_isDSRNC\n * Purpose:    checking the current comm port DSR bit\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nBOOL w32SerialPort_isDSRNC( JNIEnv *jenv, jobject jobj )\n{\n    DWORD\tdwCommFlags = 0;\n\tHANDLE  osHandle = (HANDLE) w32getfd(jenv, jobj);\n\tif (osHandle == (HANDLE)-1) return -1;                    \n\t\n\tGetCommModemStatus( osHandle, &dwCommFlags );\n\treturn  (dwCommFlags&MS_DSR_ON);\n} /* w32SerialPort_isDSRNC() */\n/*\n * Function:   w32SerialPort_isRINC\n * Purpose:    checking the current comm port RIN bit\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nBOOL w32SerialPort_isRINC( JNIEnv *jenv, jobject jobj )\n{\n    DWORD\tdwCommFlags = 0;\n\tHANDLE  osHandle = (HANDLE) w32getfd(jenv, jobj);\n\tif (osHandle == (HANDLE)-1) return -1;                    \n\t\n\tGetCommModemStatus( osHandle, &dwCommFlags );\n\treturn  (dwCommFlags&MS_RING_ON);\n}  /* w32SerialPort_isRINC() */\n/*\n * Function:   w32SerialPort_isCDNC\n * Purpose:    checking the current comm port CD bit\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nBOOL w32SerialPort_isCDNC(JNIEnv *jenv, jobject jobj)\n{\n    DWORD\tdwCommFlags = 0;\n\tHANDLE  osHandle = (HANDLE) w32getfd(jenv, jobj);\n\tif (osHandle == (HANDLE)-1) return -1;                    \n\t\n\tGetCommModemStatus( osHandle, &dwCommFlags );\n\treturn  (dwCommFlags&MS_RLSD_ON);\n}  /* w32SerialPort_isCDNC() */\n#if 0 //t.j\n/*\n * Function:     org_eclipse_soda_dk_comm_NSSerialPort\n * Method:    sendBreakNC\n * Signature: (II)I\n */\nint w32SerialPort_sendBreakNC(JNIEnv *jenv, jobject jobj, jint jfd, jint jmillis) {\n   (void)tcsendbreak(jfd, jmillis);\n} /* w32SerialPort_sendBreakNC() */\n#endif //t.j\n/*\n * Function:   w32SerialPort_setSerialPortParamsNC\n * Purpose:    config the comm port\n * Signature: (Ljava/lang/String;I)I\n * Return:     0 - Fail\n *\t\t\t   none zero - succeeds\t\n */\nint w32SerialPort_setSerialPortParamsNC\n  (JNIEnv *jenv, jobject jobj, jint fd, jint jbaudrate, jint jdatabits, jint jstopbits, jint jparity ) {\n    HANDLE       osHandle = (HANDLE) fd;\n    DCB          dcb;\n    COMMTIMEOUTS commTimeouts;\n    BOOL         success;\n    DWORD        lastRc;\n    BYTE         parity;\n    BYTE         stopBits;\n//t.j    int          rts;\n    switch (jparity) {\n        case W32COMM_PARITY_EVEN:  parity = EVENPARITY;  break;\n        case W32COMM_PARITY_ODD:   parity = ODDPARITY;   break;\n        case W32COMM_PARITY_MARK:  parity = MARKPARITY;  break;\n        case W32COMM_PARITY_SPACE: parity = SPACEPARITY; break;\n        case W32COMM_PARITY_NONE:  \n        default:                   parity = NOPARITY;    break;\n    }\n    switch (jstopbits) {\n        case W32COMM_STOPBITS_1_5: stopBits = ONE5STOPBITS; break;\n        case W32COMM_STOPBITS_2:   stopBits = TWOSTOPBITS;  break;\n        case W32COMM_STOPBITS_1:   \n        default:                   stopBits = ONESTOPBIT;   break;\n    }\n//t.j    if (config->hardwareFlowControl) {\n//        rts = RTS_CONTROL_HANDSHAKE;\n//    }\n//    else {\n//        rts = RTS_CONTROL_ENABLE;\n//t.j    }\n    memset(&dcb, 0, sizeof(DCB));\n\tsuccess = GetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"GetCommState() failed\",lastRc);\n        return success;\n    }\n#ifdef DEBUG\n//       LOG( (\"pName: %s, %s, dName: %s, semID %d\\n\", pName,pp->portName, dName, semID) );\n       printf( \"before==> baudrate: %d, databits %d, stopbits: %d parity %d\\n\", dcb.BaudRate, dcb.ByteSize, dcb.StopBits, dcb.Parity );\n       fflush( stdout );\n#endif\n\tdcb.BaudRate          = jbaudrate;\n    dcb.fBinary           = TRUE;\n    dcb.fParity           = TRUE;\n    dcb.fTXContinueOnXoff = FALSE;\n    dcb.fErrorChar        = FALSE;\n    dcb.fNull             = FALSE;\n    dcb.fAbortOnError     = FALSE;\n    dcb.ByteSize          = jdatabits;\n    dcb.Parity            = parity;\n    dcb.StopBits          = stopBits;\n\tdcb.fOutxCtsFlow      = FALSE; //(config->hardwareFlowControl != 0);\n    dcb.fOutxDsrFlow      = FALSE; \n\tdcb.fTXContinueOnXoff = FALSE;\n    dcb.fOutX             = FALSE; //(config->softwareFlowControl != 0);\n\tdcb.fInX              = FALSE; //(config->softwareFlowControl != 0);\n\tdcb.XonChar           = 0;\n\tdcb.XoffChar\t\t  = 0;\n    success = SetCommState(osHandle,&dcb);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"SetCommState() failed\",lastRc);\n        return success;\n    }\n    memset(&commTimeouts,0,sizeof(commTimeouts));\n    // this will wait for a char for 500ms and then return\n    commTimeouts.ReadIntervalTimeout\t\t = MAXDWORD;\n    commTimeouts.ReadTotalTimeoutConstant\t = 500;\n    commTimeouts.ReadTotalTimeoutMultiplier\t = MAXDWORD;\n    commTimeouts.WriteTotalTimeoutConstant\t = 0;\n    commTimeouts.WriteTotalTimeoutMultiplier = 0;\n    success = SetCommTimeouts(osHandle,&commTimeouts);\n    if (!success) {\n        lastRc = GetLastError();\n        iveSerThrowWin(jenv,\"SetCommTimeouts() failed\",lastRc);\n        return success;\n    }\n#ifdef DEBUG\n//       LOG( (\"pName: %s, %s, dName: %s, semID %d\\n\", pName,pp->portName, dName, semID) );\n       printf( \"after==> baudrate: %d, databits %d, stopbits: %d parity %d\\n\", dcb.BaudRate, dcb.ByteSize, dcb.StopBits, dcb.Parity );\n       fflush( stdout );\n#endif\n    return success;\n} /* w32SerialPort_setSerialPortParamsNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32SerialPort.h",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <windows.h>\nint  w32SerialPort_closeDeviceNC( JNIEnv *, jobject, jint, jint );\nint  w32SerialPort_openDeviceNC( JNIEnv *, jobject, jstring, jint );\nint  w32SerialPort_getBaudRateNC( JNIEnv *, jobject, jint );\nint  w32SerialPort_getDataBitsNC( JNIEnv *, jobject, jint );\nint  w32SerialPort_getStopBitsNC( JNIEnv *, jobject, jint );\nint  w32SerialPort_getParityNC( JNIEnv *, jobject, jint );\nvoid w32SerialPort_setDTRNC( JNIEnv *, jobject, jboolean );\nvoid w32SerialPort_setRTSNC( JNIEnv *, jobject, jboolean );\nBOOL w32SerialPort_isDTRNC( JNIEnv *, jobject );\nBOOL w32SerialPort_isRTSNC( JNIEnv *, jobject );\nBOOL w32SerialPort_isCTSNC( JNIEnv *, jobject );\nBOOL w32SerialPort_isDSRNC( JNIEnv *, jobject );\nBOOL w32SerialPort_isRINC(  JNIEnv *, jobject );\nBOOL w32SerialPort_isCDNC(  JNIEnv *, jobject );\nint  w32SerialPort_setFlowControlModeNC( JNIEnv *, jobject, jint, jint );\nint  w32SerialPort_getFlowControlModeNC(JNIEnv *, jobject, jint );\nint  w32SerialPort_setSerialPortParamsNC( JNIEnv *, jobject, jint, jint, jint, jint, jint );\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/c/w32SerialStatusEventThread.c",
    "content": "/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <time.h>\n#include <windows.h>\n#include <winbase.h>\n#ifndef _WIN32_WCE\n#include <sys/types.h>\n#endif\n#include \"org_eclipse_soda_dk_comm_SerialStatusEventThread.h\"\n#define assertexc(s) if (!s) {printf(\"\\n\\n%d asserted!\\n\\n\", __LINE__); return;}\nstatic int\tgetPollingTime(JNIEnv *jenv) {\n  int\t\tptime = 5;\n  jclass\tcic;\n  jfieldID\tptID;\n  jint\t\tpt;\n  do {\n\tcic = (*jenv)->FindClass(jenv, \"javax/comm/CommPortIdentifier\");\n\tif (!cic) break;\n\tptID = (*jenv)->GetStaticFieldID(jenv, cic, \"pollingTime\", \"I\");\n\tif (!ptID) break;\n\tpt = (*jenv)->GetStaticIntField(jenv, cic, ptID);\n\tif (pt > 0)\n\t\tptime = pt;\n  } while (0);\n  return ptime;\n}\t/* getPollingTime() */\n/*\n * Class:     org_eclipse_soda_dk_comm_SerialStatusEventThread\n * Method:    monitorSerialStatusNC\n * Signature: (I)V\n */\nvoid w32SerialStatusEventThread_monitorSerialStatusNC\n\t\t(JNIEnv *jenv, jobject jobj, jint jfd) {\n\tint\t\t pollingTime;\t\t\t\t\t\t\t\t/* seconds */\n\tHANDLE   osHandle = (HANDLE)jfd;\n\tDWORD\t oldStatus, newStatus;\n\tjfieldID notifyOnCDID, notifyOnCTSID;\n\tjfieldID notifyOnDSRID, notifyOnRIID;\n\tjboolean notifyOnCDFlag = JNI_FALSE;\n\tjboolean notifyOnCTSFlag = JNI_FALSE;\n\tjboolean notifyOnDSRFlag = JNI_FALSE;\n\tjboolean notifyOnRIFlag = JNI_FALSE;\n\tjclass      jc;\n\tjmethodID   jm;\n\tjclass\t\tjspc;\n\tjfieldID \tspID;\n\tjobject\t\tjsp;\n\tjboolean\tisInterruptedReturn;\n\tjclass\t\tjspec;\t\t\t\t\t\t\t\t\t/* serial port event class */\n\tjfieldID\tspeCDID,speCTSID, speDSRID, speRIID ;\t/* field ID\t\t*/\n\tjint\t\tspeCD, speCTS, speDSR, speRI;\t\t\t/* field value\t*/\n\tjmethodID\tjintMethod;\n\tjclass\t\tjthreadClass;\n\tpollingTime = getPollingTime(jenv);\n\t/* Get the const values for all the serial port event types.*/\n\tjspec = (*jenv)->FindClass(jenv, \"javax/comm/SerialPortEvent\");\n\tassertexc(jspec);\n\tspeCDID = (*jenv)->GetStaticFieldID(jenv, jspec, \"CD\", \"I\");\n\tassertexc(speCDID);\n\tspeCD = (*jenv)->GetStaticIntField(jenv, jspec, speCDID);\n\tspeCTSID = (*jenv)->GetStaticFieldID(jenv, jspec, \"CTS\", \"I\");\n\tassertexc(speCTSID);\n\tspeCTS = (*jenv)->GetStaticIntField(jenv, jspec, speCTSID);\n\tspeDSRID = (*jenv)->GetStaticFieldID(jenv, jspec, \"DSR\", \"I\");\n\tassertexc(speDSRID);\n\tspeDSR = (*jenv)->GetStaticIntField(jenv, jspec, speDSRID);\n\tspeRIID = (*jenv)->GetStaticFieldID(jenv, jspec, \"RI\", \"I\");\n\tassertexc(speRIID);\n\tspeRI = (*jenv)->GetStaticIntField(jenv, jspec, speRIID);\n\t/* Get the serial port object.*/\n\tjc = (*jenv)->GetObjectClass(jenv, jobj);\n\tassertexc(jc);\n\tspID = (*jenv)->GetFieldID(jenv, jc, \"serialPort\", \"Lorg/eclipse/soda/dk/comm/NSSerialPort;\");\n\tassertexc(spID);\n\tjsp = (*jenv)->GetObjectField(jenv, jobj, spID);\n\tassertexc(jsp);\n\t/* Get the class ID of the serial port object.*/\n\tjspc = (*jenv)->GetObjectClass(jenv, jsp);\n\tassertexc(jspc);\n\tnotifyOnCDID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnCDFlag\", \"Z\");\n\tassertexc(notifyOnCDID);\n\tnotifyOnCTSID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnCTSFlag\", \"Z\");\n\tassertexc(notifyOnCTSID);\n\tnotifyOnDSRID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnDSRFlag\", \"Z\");\n\tassertexc(notifyOnDSRID);\n\tnotifyOnRIID = (*jenv)->GetFieldID(jenv, jspc, \"notifyOnRIFlag\", \"Z\");\n\tassertexc(notifyOnRIID);\n\t/* Get access to the method to add a port.*/\n\tjm = (*jenv)->GetMethodID(jenv, jspc, \"reportSerialEvent\", \"(IZZ)V\");\n\tassertexc(jm);\n\t/* Get access to the interrupted method.*/\n\tjthreadClass = (*jenv)->FindClass(jenv, \"java/lang/Thread\");\n\tassertexc(jthreadClass);\n\tjintMethod = (*jenv)->GetMethodID(jenv, jthreadClass, \"isInterrupted\", \"()Z\");\n\tassertexc(jintMethod);\n//\tif (ioctl(jfd, TIOCMGET, &oldStatus) < 0) {\n//\t\t(void)fprintf(stderr, \"Java_org_eclipse_soda_dk_comm_SerialStatusEventThread_monitorSerialStatusNC: ioctl error %d!\\n\", errno);\n//\t\treturn;\n//t.j\t}\n#ifndef _WIN32_WCE\n\tif (GetCommModemStatus(osHandle, &oldStatus) < 0) {\n\t\terrno = GetLastError();\n\t\t(void)fprintf(stderr, \"w32SerialStatusEventThread_monitorSerialStatusNC: GetCommModemStatus() error %d!\\n\", errno);\n\t\treturn;\n\t}\n#endif //_WIN32_WCE\n\twhile(1)\n\t{\n\t\tSleep(pollingTime);\n\t\t/* check to see if this thread has been interrupted */\n\t\tisInterruptedReturn = (*jenv)->CallBooleanMethod(jenv,jobj,jintMethod);\n\t\tif(isInterruptedReturn == JNI_TRUE)\n\t\t\tbreak;\n\t\tnotifyOnCDFlag  = (*jenv)->GetBooleanField(jenv, jsp, notifyOnCDID);\n\t\tnotifyOnCTSFlag = (*jenv)->GetBooleanField(jenv, jsp, notifyOnCTSID);\n\t\tnotifyOnDSRFlag = (*jenv)->GetBooleanField(jenv, jsp, notifyOnDSRID);\n\t\tnotifyOnRIFlag  = (*jenv)->GetBooleanField(jenv, jsp, notifyOnRIID);\n#ifndef _WIN32_WCE\n\t\tif (GetCommModemStatus(osHandle, &newStatus) < 0) {\n\t\t\terrno = GetLastError();\n\t\t\t(void)fprintf(stderr, \"w32SerialStatusEventThread_monitorSerialStatusNC: ioctl error %d!\\n\", errno);\n\t\t\treturn;\n\t\t}\n#endif //_WIN32_WCE\n\t\tif (newStatus == oldStatus)\n\t\t\tcontinue;\n\t\tif((newStatus & MS_RLSD_ON) != (oldStatus & MS_RLSD_ON))\n\t\t{\n\t\t\tif(notifyOnCDFlag)        /* need to use jsp to access this field */\n\t\t\t\t(*jenv)->CallVoidMethod(jenv, jsp, jm, speCD,\n\t\t\t\t    (oldStatus & MS_RLSD_ON)? JNI_TRUE:JNI_FALSE,(newStatus & MS_RLSD_ON)? JNI_TRUE:JNI_FALSE);\n\t\t}\n\t\tif((newStatus & MS_CTS_ON) != (oldStatus & MS_CTS_ON))\n\t\t{\n\t\t\tif(notifyOnCTSFlag)\n\t\t\t\t(*jenv)->CallVoidMethod(jenv, jsp, jm, speCTS,\n\t\t\t\t    (oldStatus & MS_CTS_ON)? JNI_TRUE:JNI_FALSE,(newStatus & MS_CTS_ON)? JNI_TRUE:JNI_FALSE);\n\t\t}\n\t\tif((newStatus & MS_DSR_ON) != (oldStatus & MS_DSR_ON))\n\t\t{\n\t\t\tif(notifyOnDSRFlag)\n\t\t\t\t(*jenv)->CallVoidMethod(jenv, jsp, jm, speDSR,\n\t\t\t\t    (oldStatus & MS_DSR_ON)? JNI_TRUE:JNI_FALSE,(newStatus & MS_DSR_ON)? JNI_TRUE:JNI_FALSE);\n\t\t}\n\t\tif((newStatus & MS_RING_ON) != (oldStatus & MS_RING_ON))\n\t\t{\n\t\t\tif(notifyOnRIFlag)\n\t\t\t\t(*jenv)->CallVoidMethod(jenv, jsp, jm, speRI,\n\t\t\t\t    (oldStatus & MS_RING_ON)? JNI_TRUE:JNI_FALSE,(newStatus & MS_RING_ON)? JNI_TRUE:JNI_FALSE);\n\t\t}\n\t\toldStatus = newStatus;\n\t}\t/* end of while() */\n} /* w32SerialStatusEventThread_monitorSerialStatusNC */\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/CommDriver.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic interface CommDriver {\n\t/**\n\t * Get comm port with the specified port name and port type parameters and return the CommPort result.\n\t * @param portName\tThe port name (<code>String</code>) parameter.\n\t * @param portType\tThe port type (<code>int</code>) parameter.\n\t * @return\tResults of the get comm port (<code>CommPort</code>) value.\n\t */\n\tpublic abstract CommPort getCommPort(final String portName, final int portType);\n\n\t/**\n\t * Initialize.\n\t */\n\tpublic abstract void initialize();\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/CommPort.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.io.*;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic abstract class CommPort extends Object {\n\t/**\n\t * Define the name (String) field.\n\t */\n\tprotected String name = null;\n\n\t/**\n\t * Close.\n\t */\n\tpublic void close() {\n\t\tCommPortIdentifier cport;\n\t\ttry {\n\t\t\tcport = CommPortIdentifier.getPortIdentifier(this);\n\t\t} catch (final NoSuchPortException nspe) {\n\t\t\tcport = null;\n\t\t}\n\t\tif (cport != null) {\n\t\t\tcport.internalClosePort();\n\t\t}\n\t}\n\n\t/**\n\t * Disable receive framing.\n\t * @see #enableReceiveFraming(int)\n\t */\n\tpublic abstract void disableReceiveFraming();\n\n\t/**\n\t * Disable receive threshold.\n\t * @see #enableReceiveThreshold(int)\n\t * @see #getReceiveThreshold()\n\t */\n\tpublic abstract void disableReceiveThreshold();\n\n\t/**\n\t * Disable receive timeout.\n\t * @see #enableReceiveTimeout(int)\n\t * @see #getReceiveTimeout()\n\t */\n\tpublic abstract void disableReceiveTimeout();\n\n\t/**\n\t * Enable receive framing with the specified framing byte parameter.\n\t * @param framingByte\tThe framing byte (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #disableReceiveFraming()\n\t */\n\tpublic abstract void enableReceiveFraming(final int framingByte) throws UnsupportedCommOperationException;\n\n\t/**\n\t * Enable receive threshold with the specified thresh parameter.\n\t * @param thresh\tThe thresh (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #disableReceiveThreshold()\n\t * @see #getReceiveThreshold()\n\t */\n\tpublic abstract void enableReceiveThreshold(final int thresh) throws UnsupportedCommOperationException;\n\n\t/**\n\t * Enable receive timeout with the specified rcv timeout parameter.\n\t * @param rcvTimeout\tThe rcv timeout (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #disableReceiveTimeout()\n\t * @see #getReceiveTimeout()\n\t */\n\tpublic abstract void enableReceiveTimeout(final int rcvTimeout) throws UnsupportedCommOperationException;\n\n\t/**\n\t * Gets the input buffer size (int) value.\n\t * @return\tThe input buffer size (<code>int</code>) value.\n\t * @see #setInputBufferSize(int)\n\t */\n\tpublic abstract int getInputBufferSize();\n\n\t/**\n\t * Gets the input stream value.\n\t * @return\tThe input stream (<code>InputStream</code>) value.\n\t * @throws IOException IOException.\n\t */\n\tpublic abstract InputStream getInputStream() throws IOException;\n\n\t/**\n\t * Gets the name (String) value.\n\t * @return\tThe name (<code>String</code>) value.\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Gets the output buffer size (int) value.\n\t * @return\tThe output buffer size (<code>int</code>) value.\n\t * @see #setOutputBufferSize(int)\n\t */\n\tpublic abstract int getOutputBufferSize();\n\n\t/**\n\t * Gets the output stream value.\n\t * @return\tThe output stream (<code>OutputStream</code>) value.\n\t * @throws IOException IOException.\n\t */\n\tpublic abstract OutputStream getOutputStream() throws IOException;\n\n\t/**\n\t * Gets the receive framing byte (int) value.\n\t * @return\tThe receive framing byte (<code>int</code>) value.\n\t */\n\tpublic abstract int getReceiveFramingByte();\n\n\t/**\n\t * Gets the receive threshold (int) value.\n\t * @return\tThe receive threshold (<code>int</code>) value.\n\t * @see #disableReceiveThreshold()\n\t * @see #enableReceiveThreshold(int)\n\t */\n\tpublic abstract int getReceiveThreshold();\n\n\t/**\n\t * Gets the receive timeout (int) value.\n\t * @return\tThe receive timeout (<code>int</code>) value.\n\t * @see #disableReceiveTimeout()\n\t * @see #enableReceiveTimeout(int)\n\t */\n\tpublic abstract int getReceiveTimeout();\n\n\t/**\n\t * Gets the receive framing enabled (boolean) value.\n\t * @return\tThe receive framing enabled (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isReceiveFramingEnabled();\n\n\t/**\n\t * Gets the receive threshold enabled (boolean) value.\n\t * @return\tThe receive threshold enabled (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isReceiveThresholdEnabled();\n\n\t/**\n\t * Gets the receive timeout enabled (boolean) value.\n\t * @return\tThe receive timeout enabled (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isReceiveTimeoutEnabled();\n\n\t/**\n\t * Sets the input buffer size value.\n\t * @param size\tThe size (<code>int</code>) parameter.\n\t * @see #getInputBufferSize()\n\t */\n\tpublic abstract void setInputBufferSize(final int size);\n\n\t/**\n\t * Sets the output buffer size value.\n\t * @param size\tThe size (<code>int</code>) parameter.\n\t * @see #getOutputBufferSize()\n\t */\n\tpublic abstract void setOutputBufferSize(final int size);\n\n\t/**\n\t * Returns the string value.\n\t * @return\tThe string (<code>String</code>) value.\n\t */\n\tpublic String toString() {\n\t\tString str;\n\t\tString pt;\n\t\tCommPortIdentifier cport;\n\t\t/* This should be port name + port type. */\n\t\ttry {\n\t\t\tcport = CommPortIdentifier.getPortIdentifier(this);\n\t\t} catch (final NoSuchPortException nspe) {\n\t\t\tcport = null;\n\t\t}\n\t\tif (cport != null) {\n\t\t\tpt = cport.getPortType() == CommPortIdentifier.PORT_SERIAL ? \"SERIAL\" : \"PARALLEL\"; //$NON-NLS-1$//$NON-NLS-2$\n\t\t} else {\n\t\t\tpt = \" \"; //$NON-NLS-1$\n\t\t}\n\t\tstr = new String(this.name + ':' + pt);\n\t\treturn str;\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/CommPortIdentifier.java",
    "content": "package javax.comm;\n\n/**************************************************************************************************************************************************************************************************************************************************************\n * Copyright (c) 1999, 2009 IBM Corporation and others. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-v10.html Contributors: IBM Corporation - initial API and implementation\n *************************************************************************************************************************************************************************************************************************************************************/\nimport java.io.FileDescriptor;\nimport java.util.Enumeration;\nimport java.util.Hashtable;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Vector;\n\nimport org.eclipse.soda.dk.comm.internal.Library;\n\n/**\n * @author IBM\n */\npublic class CommPortIdentifier {\n\t/**\n\t * Define polling time value.\n\t */\n\tpublic static final int pollingTime = 1;\n\n\t/**\n\t * Define port serial value.\n\t */\n\tpublic static final int PORT_SERIAL = 1;\n\n\t/**\n\t * Define port parallel value.\n\t */\n\tpublic static final int PORT_PARALLEL = 2;\n\n\tstatic CommDriver commDriver = null;\n\n\tstatic boolean initialized = false;\n\n\tstatic Hashtable identifiers = new Hashtable(4); // initial number of\n\t// ports\n\t// static block to ensure proper initialization\n\tstatic {\n\t\t// TODO: Create a factory that would return the proper Comdriver based\n\t\t// on the property file\n\t\t// where the comdrivers are registered. (javax.comm.properties)\n\t\t// lazy initialization to avoid overhead.\n\t\ttry {\n\t\t\t// System.loadLibrary(\"dkcomm\"); // replace the old ibmcomm //$NON-NLS-1$\n\t\t\tLibrary.load_dkcomm();\n\t\t} catch (final UnsatisfiedLinkError e) {\n\t\t\te.printStackTrace();\n\t\t\tSystem.exit(1);\n\t\t}\n\t\tif (!initialized) {\n\t\t\tcommDriver = new org.eclipse.soda.dk.comm.NSCommDriver();\n\t\t\tcommDriver.initialize();\n\t\t\tinitialized = true;\n\t\t}\n\t}\n\n\t/**\n\t * Adds <CODE>portName</CODE> to the list of ports.\n\t * \n\t * @param portName\n\t *            The name of the port being added\n\t * @param portType\n\t *            The type of the port being added\n\t * @param commDriver\n\t *            The driver representing the port being added\n\t * @see javax.comm.CommDriver\n\t * @since CommAPI 1.1\n\t */\n\t// TODO: This method is not done yet. CommDriver needs to be registered.\n\t// Also the signature is non-standard. Type needs to be added.\n\tpublic static void addPortName(final String portName, final int portType, final CommDriver commDriver) {\n\t\t// what do I do with CommDriver??\n\t\tidentifiers.put(portName, new CommPortIdentifier(portName, portType));\n\t\t// name=portName;\n\t}\n\n\t/**\n\t * Obtains the <CODE>CommPortIdentifier</CODE> object corresponding to a port that has already been opened by the application.\n\t * \n\t * @param port\n\t *            a CommPort object obtained from a previous open\n\t * @return a CommPortIdentifier object\n\t * @exception NoSuchPortException\n\t *                if the port object is invalid\n\t */\n\tpublic static CommPortIdentifier getPortIdentifier(final CommPort port) throws NoSuchPortException {\n\t\treturn CommPortIdentifier.getPortIdentifier(port.getName());\n\t}\n\n\t/**\n\t * Obtains a <CODE>CommPortIdentifier</CODE> object by using a port name. The port name may have been stored in persistent storage by the application.\n\t * \n\t * @param portName\n\t *            name of the port to open\n\t * @return a <CODE>CommPortIdentifier</CODE> object\n\t * @exception NoSuchPortException\n\t *                if the port does not exist\n\t */\n\tpublic static CommPortIdentifier getPortIdentifier(final String portName) throws NoSuchPortException {\n\t\tfinal Object comPortId = identifiers.get(portName);\n\t\tif (comPortId == null) {\n\t\t\tthrow new NoSuchPortException();\n\t\t}\n\t\treturn (CommPortIdentifier) comPortId;\n\t}\n\n\t/**\n\t * Obtains an enumeration object that contains a <CODE>CommPortIdentifier</CODE> object for each port in the system.\n\t * \n\t * @return an <CODE> Enumeration </CODE> object that can be used to enumerate all the ports known to the system\n\t * @see java.util.Enumeration\n\t */\n\tpublic static Enumeration getPortIdentifiers() {\n\t\treturn identifiers.elements();\n\t}\n\n\tString name = null;\n\n\tString currentOwner = null;\n\n\tboolean currentlyOwned = false;\n\n\tprivate List listeners;\n\n\tCommPort commPort = null;\n\n\tint type = 0;\n\n\tprivate CommPortIdentifier(final String id, final int type) {\n\t\tthis.name = id;\n\t\tthis.type = type;\n\t\tthis.listeners = new Vector();\n\t}\n\n\t/**\n\t * Registers an interested application so that it can receive notification of changes in port ownership. This includes notification of the following events:\n\t * <UL>\n\t * <LI> <CODE>PORT_OWNED</CODE>: Port became owned\n\t * <LI> <CODE>PORT_UNOWNED</CODE>: Port became unowned\n\t * <LI> <CODE>PORT_OWNERSHIP_REQUESTED</CODE>: If the application owns this port and is willing to give up ownership, then it should call <CODE>close</CODE> now.\n\t * </UL>\n\t * The <CODE>ownershipChange</CODE> method of the listener registered using <CODE>addPortOwnershipListener</CODE> will be called with one of the above events.\n\t * \n\t * @param listener\n\t *            a <CODE>CommPortOwnershipListener</CODE> callback object\n\t */\n\tpublic void addPortOwnershipListener(final CommPortOwnershipListener listener) {\n\t\tif ((listener != null) && !this.listeners.contains(listener)) {\n\t\t\tthis.listeners.add(listener);\n\t\t}\n\t}\n\n\t/**\n\t * Non-Api method. Called when close() method is called on CommPort object. Required to set port owner to null and propagate CommPortOwnership event.\n\t */\n\tpublic synchronized void closePort() {\n\t\tthis.currentlyOwned = false;\n\t\tthis.currentOwner = null;\n\t\tthis.commPort = null;\n\t\tfireOwnershipEvent(CommPortOwnershipListener.PORT_UNOWNED);\n\t}\n\n\t/**\n\t * This method needs to be called when ownership of the port changes.\n\t */\n\tvoid fireOwnershipEvent(final int eventType) {\n\t\tfor (final Iterator eventListeners = this.listeners.iterator(); eventListeners.hasNext();) {\n\t\t\tfinal CommPortOwnershipListener listener = (CommPortOwnershipListener) eventListeners.next();\n\t\t\tlistener.ownershipChange(eventType);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the owner of the port.\n\t * \n\t * @return current owner of the port.\n\t */\n\tpublic String getCurrentOwner() {\n\t\treturn this.currentOwner;\n\t\t// TODO: Native code needs to check the owner of the port\n\t}\n\n\t/**\n\t * Returns the name of the port.\n\t * \n\t * @return the name of the port\n\t */\n\tpublic String getName() {\n\t\treturn this.name;\n\t}\n\n\t/**\n\t * Returns the port type.\n\t * \n\t * @return portType - PORT_SERIAL or PORT_PARALLEL\n\t */\n\tpublic int getPortType() {\n\t\treturn this.type; // CommPortIdentifier.PORT_SERIAL, PORT_PARALLEL is\n\t\t// not implemented;\n\t}\n\n\t/**\n\t * Non-Api method. Called when close() method is called on CommPort object. Required to set port owner to null and propagate CommPortOwnership event.\n\t */\n\tsynchronized void internalClosePort() {\n\t\tclosePort();\n\t}\n\n\t/**\n\t * Checks whether the port is owned.\n\t * \n\t * @return boolean <CODE>true</CODE> if the port is owned by some application, <CODE>false</CODE> if the port is not owned.\n\t */\n\tpublic boolean isCurrentlyOwned() {\n\t\treturn this.currentlyOwned;\n\t\t// TODO: Native code needs to check the owner of port\n\t}\n\n\t/**\n\t * Opens the communications port using a <CODE>FileDescriptor</CODE> object on platforms that support this technique.\n\t * \n\t * @param fileDescriptor\n\t *            The <CODE>FileDescriptor</CODE> object used to build a <CODE>CommPort</CODE>.\n\t * @return a <CODE>CommPort</CODE> object.\n\t * @exception UnsupportedCommOperationException\n\t *                is thrown on platforms which do not support this functionality.\n\t */\n\tpublic CommPort open(final FileDescriptor fileDescriptor) throws UnsupportedCommOperationException {\n\t\tthrow new UnsupportedCommOperationException(\"Opening port with FileDescriptor is not supported!\");\n\t}\n\n\t/**\n\t * @param appName\n\t * @param timeout\n\t * @return comport\n\t * @throws PortInUseException\n\t */\n\tpublic synchronized CommPort open(final String appName, final int timeout) throws PortInUseException {\n\t\tif (isCurrentlyOwned()) {\n\t\t\tfinal PortInUseException piux = new PortInUseException(appName);\n\t\t\tpiux.currentOwner = getCurrentOwner();\n\t\t\tthrow piux;\n\t\t}\n\t\tthis.currentOwner = appName;\n\t\tthis.currentlyOwned = true;\n\t\tfireOwnershipEvent(CommPortOwnershipListener.PORT_OWNERSHIP_REQUESTED);\n\t\treturn commDriver.getCommPort(getName(), getPortType());\n\t}\n\n\t/**\n\t * Deregisters a <CODE>CommPortOwnershipListener</CODE> registered using <CODE>addPortOwnershipListener</CODE>\n\t * \n\t * @param listener\n\t *            The CommPortOwnershipListener object that was previously registered using addPortOwnershipListener\n\t */\n\tpublic void removePortOwnershipListener(final CommPortOwnershipListener listener) {\n\t\tif (listener != null) {\n\t\t\tthis.listeners.remove(listener);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/CommPortOwnershipListener.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.util.*;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic interface CommPortOwnershipListener extends EventListener {\n\t/**\n\t * Define the port owned (int) constant.\n\t */\n\tpublic static final int PORT_OWNED = 1;\n\n\t/**\n\t * Define the port unowned (int) constant.\n\t */\n\tpublic static final int PORT_UNOWNED = 2;\n\n\t/**\n\t * Define the port ownership requested (int) constant.\n\t */\n\tpublic static final int PORT_OWNERSHIP_REQUESTED = 3;\n\n\t/**\n\t * Ownership change with the specified type parameter.\n\t * @param type\tThe type (<code>int</code>) parameter.\n\t */\n\tpublic abstract void ownershipChange(final int type);\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/NoSuchPortException.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class NoSuchPortException extends Exception {\n\t/**\n\t * Define the serial version uid (long) constant.\n\t */\n\tprivate static final long serialVersionUID = 4635426743616819612L;\n\n\t/**\n\t * Constructs an instance of this class.\n\t * @see #NoSuchPortException(String)\n\t */\n\tpublic NoSuchPortException() {\n\t\tsuper();\n\t}\n\n\t/**\n\t * Constructs an instance of this class from the specified msg parameter.\n\t * @param msg\tThe msg (<code>String</code>) parameter.\n\t * @see #NoSuchPortException()\n\t */\n\tpublic NoSuchPortException(final String msg) {\n\t\tsuper(msg);\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/ParallelPort.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.util.*;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic abstract class ParallelPort extends CommPort {\n\t/**\n\t * Define the lpt mode any (int) constant.\n\t */\n\tpublic static final int LPT_MODE_ANY = 0;\n\n\t/**\n\t * Define the lpt mode spp (int) constant.\n\t */\n\tpublic static final int LPT_MODE_SPP = 1;\n\n\t/**\n\t * Define the lpt mode ps2 (int) constant.\n\t */\n\tpublic static final int LPT_MODE_PS2 = 2;\n\n\t/**\n\t * Define the lpt mode epp (int) constant.\n\t */\n\tpublic static final int LPT_MODE_EPP = 3;\n\n\t/**\n\t * Define the lpt mode ecp (int) constant.\n\t */\n\tpublic static final int LPT_MODE_ECP = 4;\n\n\t/**\n\t * Define the lpt mode nibble (int) constant.\n\t */\n\tpublic static final int LPT_MODE_NIBBLE = 5;\n\n\t/**\n\t * Constructs an instance of this class.\n\t */\n\tprotected ParallelPort() {\n\t\tsuper();\n\t}\n\n\t/**\n\t * Add event listener with the specified lsnr parameter.\n\t * @param lsnr\tThe lsnr (<code>ParallelPortEventListener</code>) parameter.\n\t * @throws TooManyListenersException Too Many Listeners Exception.\n\t * @see #removeEventListener()\n\t */\n\tpublic abstract void addEventListener(final ParallelPortEventListener lsnr) throws TooManyListenersException;\n\n\t/**\n\t * Gets the mode (int) value.\n\t * @return\tThe mode (<code>int</code>) value.\n\t * @see #setMode(int)\n\t */\n\tpublic abstract int getMode();\n\n\t/**\n\t * Gets the output buffer free (int) value.\n\t * @return\tThe output buffer free (<code>int</code>) value.\n\t */\n\tpublic abstract int getOutputBufferFree();\n\n\t/**\n\t * Gets the paper out (boolean) value.\n\t * @return\tThe paper out (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isPaperOut();\n\n\t/**\n\t * Gets the printer busy (boolean) value.\n\t * @return\tThe printer busy (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isPrinterBusy();\n\n\t/**\n\t * Gets the printer error (boolean) value.\n\t * @return\tThe printer error (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isPrinterError();\n\n\t/**\n\t * Gets the printer selected (boolean) value.\n\t * @return\tThe printer selected (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isPrinterSelected();\n\n\t/**\n\t * Gets the printer timed out (boolean) value.\n\t * @return\tThe printer timed out (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isPrinterTimedOut();\n\n\t/**\n\t * Notify on buffer with the specified notify parameter.\n\t * @param notify\tThe notify (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnBuffer(final boolean notify);\n\n\t/**\n\t * Notify on error with the specified notify parameter.\n\t * @param notify\tThe notify (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnError(final boolean notify);\n\n\t/**\n\t * Remove event listener.\n\t * @see #addEventListener(ParallelPortEventListener)\n\t */\n\tpublic abstract void removeEventListener();\n\n\t/**\n\t * Restart.\n\t */\n\tpublic abstract void restart();\n\n\t/**\n\t * Sets the mode value.\n\t * @param mode\tThe mode (<code>int</code>) parameter.\n\t * @return\tThe mode (<code>int</code>) value.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #getMode()\n\t */\n\tpublic abstract int setMode(final int mode) throws UnsupportedCommOperationException;\n\n\t/**\n\t * Suspend.\n\t */\n\tpublic abstract void suspend();\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/ParallelPortEvent.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.util.*;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class ParallelPortEvent extends EventObject {\n\t/**\n\t * Define the serial version uid (long) constant.\n\t */\n\tprivate static final long serialVersionUID = 3956965758537808226L;\n\n\t/**\n\t * Define the par ev error (int) constant.\n\t */\n\tpublic static final int PAR_EV_ERROR = 1;\n\n\t/**\n\t * Define the par ev buffer (int) constant.\n\t */\n\tpublic static final int PAR_EV_BUFFER = 2;\n\n\t/**\n\t * Define the event type (int) field.\n\t */\n\tpublic int eventType;\n\n\t/**\n\t * Define the new val (boolean) field.\n\t */\n\tprivate boolean newVal;\n\n\t/**\n\t * Define the old val (boolean) field.\n\t */\n\tprivate boolean oldVal;\n\n\t/**\n\t * Constructs an instance of this class from the specified srcport, eventtype, oldvalue and newvalue parameters.\n\t * @param srcport\tThe srcport (<code>ParallelPort</code>) parameter.\n\t * @param eventtype\tThe eventtype (<code>int</code>) parameter.\n\t * @param oldvalue\tThe oldvalue (<code>boolean</code>) parameter.\n\t * @param newvalue\tThe newvalue (<code>boolean</code>) parameter.\n\t */\n\tpublic ParallelPortEvent(final ParallelPort srcport, final int eventtype, final boolean oldvalue, final boolean newvalue) {\n\t\tsuper(srcport);\n\t\tthis.eventType = eventtype;\n\t\tthis.newVal = newvalue;\n\t\tthis.oldVal = oldvalue;\n\t}\n\n\t/**\n\t * Gets the event type (int) value.\n\t * @return\tThe event type (<code>int</code>) value.\n\t */\n\tpublic int getEventType() {\n\t\treturn this.eventType;\n\t}\n\n\t/**\n\t * Gets the new value (boolean) value.\n\t * @return\tThe new value (<code>boolean</code>) value.\n\t */\n\tpublic boolean getNewValue() {\n\t\treturn this.newVal;\n\t}\n\n\t/**\n\t * Gets the old value (boolean) value.\n\t * @return\tThe old value (<code>boolean</code>) value.\n\t */\n\tpublic boolean getOldValue() {\n\t\treturn this.oldVal;\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/ParallelPortEventListener.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.util.*;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic interface ParallelPortEventListener extends EventListener {\n\t/**\n\t * Parallel event with the specified ev parameter.\n\t * @param ev\tThe ev (<code>ParallelPortEvent</code>) parameter.\n\t */\n\tpublic abstract void parallelEvent(final ParallelPortEvent ev);\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/PortInUseException.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class PortInUseException extends Exception {\n\t/**\n\t * Define the serial version uid (long) constant.\n\t */\n\tprivate static final long serialVersionUID = -2619871379515236575L;\n\n\t/**\n\t * Define the current owner (String) field.\n\t */\n\tpublic String currentOwner;\n\n\t/**\n\t * Constructs an instance of this class from the specified co parameter.\n\t * @param co\tThe co (<code>String</code>) parameter.\n\t */\n\tpublic PortInUseException(final String co) {\n\t\tthis.currentOwner = co;\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/SerialPort.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.util.*;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic abstract class SerialPort extends CommPort {\n\t/**\n\t * Define the databits5 (int) constant.\n\t */\n\tpublic static final int DATABITS_5 = 5;\n\n\t/**\n\t * Define the databits6 (int) constant.\n\t */\n\tpublic static final int DATABITS_6 = 6;\n\n\t/**\n\t * Define the databits7 (int) constant.\n\t */\n\tpublic static final int DATABITS_7 = 7;\n\n\t/**\n\t * Define the databits8 (int) constant.\n\t */\n\tpublic static final int DATABITS_8 = 8;\n\n\t/**\n\t * Define the stopbits1 (int) constant.\n\t */\n\tpublic static final int STOPBITS_1 = 1;\n\n\t/**\n\t * Define the stopbits2 (int) constant.\n\t */\n\tpublic static final int STOPBITS_2 = 2;\n\n\t/**\n\t * Define the stopbits15 (int) constant.\n\t */\n\tpublic static final int STOPBITS_1_5 = 3;\n\n\t/**\n\t * Define the parity none (int) constant.\n\t */\n\tpublic static final int PARITY_NONE = 0;\n\n\t/**\n\t * Define the parity odd (int) constant.\n\t */\n\tpublic static final int PARITY_ODD = 1;\n\n\t/**\n\t * Define the parity even (int) constant.\n\t */\n\tpublic static final int PARITY_EVEN = 2;\n\n\t/**\n\t * Define the parity mark (int) constant.\n\t */\n\tpublic static final int PARITY_MARK = 3;\n\n\t/**\n\t * Define the parity space (int) constant.\n\t */\n\tpublic static final int PARITY_SPACE = 4;\n\n\t/**\n\t * Define the flowcontrol none (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_NONE = 0;\n\n\t/**\n\t * Define the flowcontrol rtscts in (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_RTSCTS_IN = 1;\n\n\t/**\n\t * Define the flowcontrol rtscts out (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_RTSCTS_OUT = 2;\n\n\t/**\n\t * Define the flowcontrol xonxoff in (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_XONXOFF_IN = 4;\n\n\t/**\n\t * Define the flowcontrol xonxoff out (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_XONXOFF_OUT = 8;\n\n\t/**\n\t * Constructs an instance of this class.\n\t */\n\tprotected SerialPort() {\n\t\tsuper();\n\t}\n\n\t/**\n\t * Add event listener with the specified lsnr parameter.\n\t * @param lsnr\tThe lsnr (<code>SerialPortEventListener</code>) parameter.\n\t * @throws TooManyListenersException Too Many Listeners Exception.\n\t * @see #removeEventListener()\n\t */\n\tpublic abstract void addEventListener(final SerialPortEventListener lsnr) throws TooManyListenersException;\n\n\t/**\n\t * Gets the baud rate (int) value.\n\t * @return\tThe baud rate (<code>int</code>) value.\n\t */\n\tpublic abstract int getBaudRate();\n\n\t/**\n\t * Gets the data bits (int) value.\n\t * @return\tThe data bits (<code>int</code>) value.\n\t */\n\tpublic abstract int getDataBits();\n\n\t/**\n\t * Gets the flow control mode (int) value.\n\t * @return\tThe flow control mode (<code>int</code>) value.\n\t * @see #setFlowControlMode(int)\n\t */\n\tpublic abstract int getFlowControlMode();\n\n\t/**\n\t * Gets the parity (int) value.\n\t * @return\tThe parity (<code>int</code>) value.\n\t */\n\tpublic abstract int getParity();\n\n\t/**\n\t * Gets the stop bits (int) value.\n\t * @return\tThe stop bits (<code>int</code>) value.\n\t */\n\tpublic abstract int getStopBits();\n\n\t/**\n\t * Gets the cd (boolean) value.\n\t * @return\tThe cd (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isCD();\n\n\t/**\n\t * Gets the cts (boolean) value.\n\t * @return\tThe cts (<code>boolean</code>) value.\n\t * @see #notifyOnCTS(boolean)\n\t */\n\tpublic abstract boolean isCTS();\n\n\t/**\n\t * Gets the dsr (boolean) value.\n\t * @return\tThe dsr (<code>boolean</code>) value.\n\t * @see #notifyOnDSR(boolean)\n\t */\n\tpublic abstract boolean isDSR();\n\n\t/**\n\t * Gets the dtr (boolean) value.\n\t * @return\tThe dtr (<code>boolean</code>) value.\n\t * @see #setDTR(boolean)\n\t */\n\tpublic abstract boolean isDTR();\n\n\t/**\n\t * Gets the ri (boolean) value.\n\t * @return\tThe ri (<code>boolean</code>) value.\n\t */\n\tpublic abstract boolean isRI();\n\n\t/**\n\t * Gets the rts (boolean) value.\n\t * @return\tThe rts (<code>boolean</code>) value.\n\t * @see #setRTS(boolean)\n\t */\n\tpublic abstract boolean isRTS();\n\n\t/**\n\t * Notify on break interrupt with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnBreakInterrupt(final boolean enable);\n\n\t/**\n\t * Notify on cts with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnCTS(final boolean enable);\n\n\t/**\n\t * Notify on carrier detect with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnCarrierDetect(final boolean enable);\n\n\t/**\n\t * Notify on dsr with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnDSR(final boolean enable);\n\n\t/**\n\t * Notify on data available with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnDataAvailable(final boolean enable);\n\n\t/**\n\t * Notify on framing error with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnFramingError(final boolean enable);\n\n\t/**\n\t * Notify on output empty with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnOutputEmpty(final boolean enable);\n\n\t/**\n\t * Notify on overrun error with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnOverrunError(final boolean enable);\n\n\t/**\n\t * Notify on parity error with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnParityError(final boolean enable);\n\n\t/**\n\t * Notify on ring indicator with the specified enable parameter.\n\t * @param enable\tThe enable (<code>boolean</code>) parameter.\n\t */\n\tpublic abstract void notifyOnRingIndicator(final boolean enable);\n\n\t/**\n\t * Remove event listener.\n\t * @see #addEventListener(SerialPortEventListener)\n\t */\n\tpublic abstract void removeEventListener();\n\n\t/**\n\t * Send break with the specified millis parameter.\n\t * @param millis\tThe millis (<code>int</code>) parameter.\n\t */\n\tpublic abstract void sendBreak(final int millis);\n\n\t/**\n\t * Sets the dtr value.\n\t * @param dtr\tThe dtr (<code>boolean</code>) parameter.\n\t * @see #isDTR()\n\t */\n\tpublic abstract void setDTR(final boolean dtr);\n\n\t/**\n\t * Sets the flow control mode value.\n\t * @param flowcontrol\tThe flowcontrol (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #getFlowControlMode()\n\t */\n\tpublic abstract void setFlowControlMode(final int flowcontrol) throws UnsupportedCommOperationException;\n\n\t/**\n\t * Sets the rts value.\n\t * @param rts\tThe rts (<code>boolean</code>) parameter.\n\t * @see #isRTS()\n\t */\n\tpublic abstract void setRTS(final boolean rts);\n\n\t/**\n\t * Sets the rcv fifo trigger value.\n\t * @param trigger\tThe trigger (<code>int</code>) parameter.\n\t */\n\tpublic void setRcvFifoTrigger(final int trigger) {\n\t\t/* do nothing */\n\t}\n\n\t/**\n\t * Set serial port params with the specified baudrate, data bits, stop bits and parity parameters.\n\t * @param baudrate\tThe baudrate (<code>int</code>) parameter.\n\t * @param dataBits\tThe data bits (<code>int</code>) parameter.\n\t * @param stopBits\tThe stop bits (<code>int</code>) parameter.\n\t * @param parity\tThe parity (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t */\n\tpublic abstract void setSerialPortParams(final int baudrate, final int dataBits, final int stopBits, final int parity) throws UnsupportedCommOperationException;\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/SerialPortEvent.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.util.*;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class SerialPortEvent extends EventObject {\n\t/**\n\t * Define the serial version uid (long) constant.\n\t */\n\tprivate static final long serialVersionUID = 8913102891237934499L;\n\n\t/**\n\t * Define the data available (int) constant.\n\t */\n\tpublic static final int DATA_AVAILABLE = 1;\n\n\t/**\n\t * Define the output buffer empty (int) constant.\n\t */\n\tpublic static final int OUTPUT_BUFFER_EMPTY = 2;\n\n\t/**\n\t * Define the cts (int) constant.\n\t */\n\tpublic static final int CTS = 3;\n\n\t/**\n\t * Define the dsr (int) constant.\n\t */\n\tpublic static final int DSR = 4;\n\n\t/**\n\t * Define the ri (int) constant.\n\t */\n\tpublic static final int RI = 5;\n\n\t/**\n\t * Define the cd (int) constant.\n\t */\n\tpublic static final int CD = 6;\n\n\t/**\n\t * Define the oe (int) constant.\n\t */\n\tpublic static final int OE = 7;\n\n\t/**\n\t * Define the pe (int) constant.\n\t */\n\tpublic static final int PE = 8;\n\n\t/**\n\t * Define the fe (int) constant.\n\t */\n\tpublic static final int FE = 9;\n\n\t/**\n\t * Define the bi (int) constant.\n\t */\n\tpublic static final int BI = 10;\n\n\t/**\n\t * Define the event type (int) field.\n\t */\n\tpublic int eventType;\n\n\t/**\n\t * Define the new val (boolean) field.\n\t */\n\tprivate boolean newVal;\n\n\t/**\n\t * Define the old val (boolean) field.\n\t */\n\tprivate boolean oldVal;\n\n\t/**\n\t * Constructs an instance of this class from the specified srcport, eventtype, oldvalue and newvalue parameters.\n\t * @param srcport\tThe srcport (<code>SerialPort</code>) parameter.\n\t * @param eventtype\tThe eventtype (<code>int</code>) parameter.\n\t * @param oldvalue\tThe oldvalue (<code>boolean</code>) parameter.\n\t * @param newvalue\tThe newvalue (<code>boolean</code>) parameter.\n\t */\n\tpublic SerialPortEvent(final SerialPort srcport, final int eventtype, final boolean oldvalue, final boolean newvalue) {\n\t\tsuper(srcport);\n\t\tthis.eventType = eventtype;\n\t\tthis.newVal = newvalue;\n\t\tthis.oldVal = oldvalue;\n\t}\n\n\t/**\n\t * Gets the event type (int) value.\n\t * @return\tThe event type (<code>int</code>) value.\n\t */\n\tpublic int getEventType() {\n\t\treturn this.eventType;\n\t}\n\n\t/**\n\t * Gets the new value (boolean) value.\n\t * @return\tThe new value (<code>boolean</code>) value.\n\t */\n\tpublic boolean getNewValue() {\n\t\treturn this.newVal;\n\t}\n\n\t/**\n\t * Gets the old value (boolean) value.\n\t * @return\tThe old value (<code>boolean</code>) value.\n\t */\n\tpublic boolean getOldValue() {\n\t\treturn this.oldVal;\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/SerialPortEventListener.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.util.*;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic interface SerialPortEventListener extends EventListener {\n\t/**\n\t * Serial event with the specified ev parameter.\n\t * @param ev\tThe ev (<code>SerialPortEvent</code>) parameter.\n\t */\n\tpublic abstract void serialEvent(final SerialPortEvent ev);\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/SerialPortException.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class SerialPortException extends Exception {\n\t/**\n\t * Define the serial version uid (long) constant.\n\t */\n\tprivate static final long serialVersionUID = 1409005327231826071L;\n\n\t/**\n\t * Constructs an instance of this class from the specified msg parameter.\n\t * @param msg\tThe msg (<code>String</code>) parameter.\n\t */\n\tpublic SerialPortException(final String msg) {\n\t\tsuper(msg);\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/UnsupportedCommOperationException.java",
    "content": "package javax.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class UnsupportedCommOperationException extends Exception {\n\t/**\n\t * Define the serial version uid (long) constant.\n\t */\n\tprivate static final long serialVersionUID = -1653996043267525578L;\n\n\t/**\n\t * Constructs an instance of this class.\n\t * @see #UnsupportedCommOperationException(String)\n\t */\n\tpublic UnsupportedCommOperationException() {\n\t\tsuper();\n\t}\n\n\t/**\n\t * Constructs an instance of this class from the specified str parameter.\n\t * @param str\tThe str (<code>String</code>) parameter.\n\t * @see #UnsupportedCommOperationException()\n\t */\n\tpublic UnsupportedCommOperationException(final String str) {\n\t\tsuper(str);\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/javax/comm/package.html",
    "content": "<!DOCTYPE html PUBLIC \"..//W3C/DTD XHTML 1.0 Strict/EN\"  DTD/xhtml-strict.dtd\">\n<!-- Copyright (c) 2008, 2009 IBM.                                         -->\n<!-- All rights reserved. This program and the accompanying materials      -->\n<!-- are made available under the terms of the Eclipse Public License v1.0 -->\n<!-- which accompanies this distribution, and is available at              -->\n<!-- http://www.eclipse.org/legal/epl-v10.html                             -->\n<!--                                                                       -->\n<!-- Contributors:                                                         -->\n<!--     IBM - initial API and implementation                              -->\n    \n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\t<head>\n\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n\t\t<meta name=\"Security\" content=\"public\"/>\n\t\t<meta name=\"Copyright\" content=\"Copyright (c) 2009 IBM. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page.\"/>\n\t\t<meta scheme=\"rfc1766\" name=\"DC.Language\" content=\"en-us\"/>\n\t\t<meta name=\"Keywords\" content=\"javax.comm, org.eclipse.soda.dk.comm\"/>\n\t\t<link rel=\"STYLESHEET\" href=\"stylesheet.css\" charset=\"UTF-8\" type=\"text/css\"/>\t\t\n\t\t<title>javax.comm Package</title>\n\t</head>\n\t<body>\n\t\t<p>This package is part of the org.eclipse.soda.dk.comm project.</p> \n\t</body>\n</html>\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/DeviceList.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class DeviceList {\n\t/**\n\t * Define the head entry (DeviceListEntry) field.\n\t */\n\tDeviceListEntry headEntry = null;\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/DeviceListEntry.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class DeviceListEntry {\n\t/**\n\t * Define the logical name (String) field.\n\t */\n\tString logicalName;\n\n\t/**\n\t * Define the physical name (String) field.\n\t */\n\tString physicalName;\n\n\t/**\n\t * Define the port type (int) field.\n\t */\n\tint portType;\n\n\t/**\n\t * Define the sem id (int) field.\n\t */\n\tint semID;\n\n\t/**\n\t * Define the opened (boolean) field.\n\t */\n\tboolean opened;\n\n\t/**\n\t * Define the next (DeviceListEntry) field.\n\t */\n\tDeviceListEntry next;\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/NSCommDriver.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.io.IOException;\nimport javax.comm.CommDriver;\nimport javax.comm.CommPort;\nimport javax.comm.CommPortIdentifier;\nimport org.eclipse.soda.dk.comm.internal.Library;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class NSCommDriver implements CommDriver {\n\tstatic {\n\t\ttry {\n\t\t\tLibrary.load_dkcomm();\n\t\t} catch (final UnsatisfiedLinkError exception) {\n\t\t\texception.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * Define the device list (DeviceList) field.\n\t */\n\tDeviceList devicelist = new DeviceList();\n\n\t/**\n\t * Add device to list with the specified port name, port type, device name and sem id parameters.\n\t * @param portName\n\t *\t\tThe port name (<code>String</code>) parameter.\n\t * @param portType\n\t *\t\tThe port type (<code>int</code>) parameter.\n\t * @param deviceName\n\t *\t\tThe device name (<code>String</code>) parameter.\n\t * @param semID\n\t *\t\tThe sem ID (<code>int</code>) parameter.\n\t */\n\tprotected void addDeviceToList(final String portName, final int portType, final String deviceName, final int semID) {\n\t\tDeviceListEntry cur = this.devicelist.headEntry;\n\t\tDeviceListEntry prev = null;\n\t\twhile (cur != null) {\n\t\t\tprev = cur;\n\t\t\tcur = cur.next;\n\t\t}\n\t\tcur = new DeviceListEntry();\n\t\tcur.logicalName = portName;\n\t\tcur.physicalName = deviceName;\n\t\tcur.portType = portType;\n\t\tcur.semID = semID;\n\t\tcur.next = null;\n\t\tif (prev == null) {\n\t\t\tthis.devicelist.headEntry = cur;\n\t\t} else {\n\t\t\tprev.next = cur;\n\t\t}\n\t}\n\n\t/**\n\t * Discover devices nc.\n\t */\n\tprivate native void discoverDevicesNC();\n\n\t/**\n\t * Get comm port with the specified port name and port type parameters and return the CommPort result.\n\t * @param portName\n\t *\t\tThe port name (<code>String</code>) parameter.\n\t * @param portType\n\t *\t\tThe port type (<code>int</code>) parameter.\n\t * @return Results of the get comm port (<code>CommPort</code>) value.\n\t */\n\tpublic CommPort getCommPort(final String portName, final int portType) {\n\t\tCommPort port = null;\n\t\ttry {\n\t\t\tswitch (portType) {\n\t\t\tcase CommPortIdentifier.PORT_SERIAL:\n\t\t\t\tport = new NSSerialPort(portName, this);\n\t\t\t\tbreak;\n\t\t\tcase CommPortIdentifier.PORT_PARALLEL:\n\t\t\t\tport = new NSParallelPort(portName, this);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} catch (final IOException exception) {\n\t\t\texception.printStackTrace();\n\t\t\t/* port is being used by another app? */\n\t\t}\n\t\treturn port;\n\t}\n\n\t/**\n\t * Gets the first dle (DeviceListEntry) value.\n\t * @return The first dle (<code>DeviceListEntry</code>) value.\n\t */\n\tDeviceListEntry getFirstDLE() {\n\t\treturn this.devicelist.headEntry;\n\t}\n\n\t/**\n\t * Get next dle with the specified dle parameter and return the DeviceListEntry result.\n\t * @param dle\n\t *\t\tThe dle (<code>DeviceListEntry</code>) parameter.\n\t * @return Results of the get next dle (<code>DeviceListEntry</code>) value.\n\t */\n\tDeviceListEntry getNextDLE(final DeviceListEntry dle) {\n\t\tDeviceListEntry cur = this.devicelist.headEntry;\n\t\tDeviceListEntry ndle = null;\n\t\twhile (cur != null) {\n\t\t\tif (cur == dle) {\n\t\t\t\tndle = cur.next;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcur = cur.next;\n\t\t}\n\t\treturn ndle;\n\t}\n\n\t/**\n\t * Initialize.\n\t */\n\tpublic void initialize() {\n\t\tdiscoverDevicesNC();\n\t\tfor (DeviceListEntry cur = getFirstDLE(); cur != null; cur = getNextDLE(cur)) {\n\t\t\tCommPortIdentifier.addPortName(cur.logicalName, cur.portType, this);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/NSDeviceInputStream.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*******************************************************************************\n * Copyright (c) 1999, 2009 IBM Corporation and others.\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-v10.html\n * \n * Contributors:\n *     IBM Corporation - initial API and implementation\n *******************************************************************************/\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.comm.CommPort;\nimport javax.comm.CommPortIdentifier;\n\n/**\n * @author IBM\n */\npublic class NSDeviceInputStream extends InputStream {\n// -----------------------------------------------------------------------------\n// Variables\n// -----------------------------------------------------------------------------\n\tint fd = -1;\n\n\tprivate int bufsize = 0;\n\n\tprivate int readCount = 0; // read by the app\n\n\tprivate int bufferCount = 0; // read by this object from the device\n\n\tprivate int thc = -1; // threshold value from serial/parallel ports\n\n\tprivate int tmo = -1; // timeout value from serial/parallel ports\n\n\tprivate boolean tmoDone = false; // timeout occurred?\n\n\tprivate NSSerialPort sp = null;\n\n\tprivate NSParallelPort pp = null;\n\n\tprivate byte[] buffer = null; // size equivalent to insBufferSize\n\n\t// of NSSerialPort or NSParallelPort\n// -----------------------------------------------------------------------------\n// Methods - constructors\n// -----------------------------------------------------------------------------\n\tNSDeviceInputStream(final CommPort port, final int portType) {\n\t\tif (portType == CommPortIdentifier.PORT_PARALLEL) {\n\t\t\tthis.pp = (NSParallelPort) port;\n\t\t\tthis.bufsize = this.pp.insBufferSize;\n\t\t\tthis.thc = this.pp.rcvThreshold;\n\t\t} else {\n\t\t\tthis.sp = (NSSerialPort) port;\n\t\t\tthis.bufsize = this.sp.insBufferSize;\n\t\t\tthis.thc = this.sp.rcvThreshold;\n\t\t}\n\t\tthis.buffer = new byte[this.bufsize];\n\t}\n\n// -----------------------------------------------------------------------------\n// Methods - public\n// -----------------------------------------------------------------------------\n\tpublic int available() throws IOException {\n\t\tint rc;\n\t\tint nbc = 0; // no of bytes that can be read without blocking\n\t\t// Check to see if any data is in our internal buffer first.\n\t\tif (this.bufferCount > this.readCount) {\n\t\t\tnbc += this.bufferCount - this.readCount;\n\t\t}\n\t\t// Now query the device to see if any and how much data is pending\n\t\t// to be read.\n\t\trc = getReadCountNC();\n\t\tif (rc > 0) {\n\t\t\tnbc += rc;\n\t\t}\n\t\treturn nbc;\n\t}\n\n\tprivate native int getReadCountNC() throws IOException;\n\n\tpublic int read() throws IOException {\n\t\tint rc;\n\t\t// If there is data already read from the device and buffered up,\n\t\t// pick up one byte from it. If not, read it from the device.\n\t\tif (this.bufferCount > this.readCount) {\n\t\t\trc = this.buffer[this.readCount++];\n\t\t\tif (this.readCount == this.bufferCount) {\n\t\t\t\tthis.readCount = this.bufferCount = 0;\n\t\t\t}\n\t\t} else {\n\t\t\t// Obtain the timeout trigger value.\n\t\t\tif (this.pp != null) {\n\t\t\t\tthis.tmo = this.pp.rcvTimeout;\n\t\t\t} else if (this.sp != null) {\n\t\t\t\tthis.tmo = this.sp.rcvTimeout;\n\t\t\t}\n\t\t\trc = readDeviceOneByteNC(); // throws IOException\n\t\t}\n\t\treturn rc;\n\t}\n\n\tpublic int read(final byte b[]) throws IOException {\n\t\treturn read(b, 0, b.length); // throws IOException\n\t}\n\n// -----------------------------------------------------------------------------\n// Methods - private\n// -----------------------------------------------------------------------------\n\tpublic int read(final byte b[], final int off, final int len) throws IOException {\n\t\tint toff = off;\n\t\tint tlen = len;\n\t\tint rc;\n\t\tboolean excflag = false;\n\t\tint rdc = 0;\n\t\t// Determine the minimum of length and threshold (if set).\n\t\tif (this.pp != null) {\n\t\t\tthis.thc = this.pp.rcvThreshold;\n\t\t\tthis.tmo = this.pp.rcvTimeout;\n\t\t} else if (this.sp != null) {\n\t\t\tthis.thc = this.sp.rcvThreshold;\n\t\t\tthis.tmo = this.sp.rcvTimeout;\n\t\t}\n\t\tif ((this.thc > 0) && (this.thc < tlen)) {\n\t\t\ttlen = this.thc;\n\t\t}\n\t\t// If buffer size is 0, then no buffering is to be done.\n\t\tif (this.bufsize == 0) {\n\t\t\tthis.readCount = this.bufferCount = 0;\n\t\t\twhile (tlen != 0) {\n\t\t\t\tthis.tmoDone = false;\n\t\t\t\trc = readDeviceNC(b, toff, tlen);\n\t\t\t\tif (rc < 0) {\n\t\t\t\t\texcflag = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\ttoff += rc;\n\t\t\t\ttlen -= rc;\n\t\t\t\trdc += rc;\n\t\t\t\t// If no data had been received this time, discontinue.\n\t\t\t\tif (rc == 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// If threshold is never set, we're done with whatever\n\t\t\t\t// we got so far.\n\t\t\t\tif (this.thc < 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// If timeout is enabled and timeout occurred,\n\t\t\t\t// discontinue.\n\t\t\t\tif ((this.tmo > 0) && this.tmoDone) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} // end of while\n\t\t} else {\n\t\t\twhile (tlen != 0) {\n\t\t\t\tint cc;\n\t\t\t\tthis.tmoDone = false;\n\t\t\t\t// if no data in the buffer, get some data.\n\t\t\t\tif (this.bufferCount == 0) {\n\t\t\t\t\tthis.readCount = 0;\n\t\t\t\t\trc = readDeviceNC(this.buffer, 0, this.bufsize);\n\t\t\t\t\tif (rc < 0) {\n\t\t\t\t\t\texcflag = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tthis.bufferCount = rc;\n\t\t\t\t\t// If no data had been received this time,\n\t\t\t\t\t// discontinue.\n\t\t\t\t\tif (rc == 0) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Copy the buffered up data.\n\t\t\t\tcc = tlen <= this.bufferCount - this.readCount ? tlen : this.bufferCount - this.readCount;\n\t\t\t\tSystem.arraycopy(this.buffer, this.readCount, b, toff, cc);\n\t\t\t\ttoff += cc;\n\t\t\t\ttlen -= cc;\n\t\t\t\tthis.readCount += cc;\n\t\t\t\trdc += cc;\n\t\t\t\tif (this.readCount == this.bufferCount) {\n\t\t\t\t\tthis.readCount = this.bufferCount = 0;\n\t\t\t\t}\n\t\t\t\t// If threshold is never set, we're done with whatever\n\t\t\t\t// we got so far.\n\t\t\t\tif (this.thc < 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// If timeout is enabled and timeout occurred,\n\t\t\t\t// discontinue.\n\t\t\t\tif ((this.tmo > 0) && this.tmoDone) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} // end of while\n\t\t}\n\t\tif (excflag) {\n\t\t\tfinal IOException e = new IOException();\n\t\t\tthrow e;\n\t\t}\n\t\treturn rdc;\n\t}\n\n\tprivate native int readDeviceNC(byte buf[], int offset, int nBytes);\n\n\t// private native int setFDNC();\n\tprivate native int readDeviceOneByteNC() throws IOException;\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/NSDeviceOutputStream.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*******************************************************************************\n * Copyright (c) 1999, 2009 IBM Corporation and others.\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * which accompanies this distribution, and is available at\n * http://www.eclipse.org/legal/epl-v10.html\n * \n * Contributors:\n *     IBM Corporation - initial API and implementation\n *******************************************************************************/\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport javax.comm.CommPort;\nimport javax.comm.CommPortIdentifier;\nimport javax.comm.ParallelPortEvent;\nimport javax.comm.SerialPortEvent;\n\n/**\n * @author IBM\n */\npublic class NSDeviceOutputStream extends OutputStream {\n// -----------------------------------------------------------------------------\n// Variables\n// -----------------------------------------------------------------------------\n\tint fd = -1;\n\n\tprivate int pt; // determines whether to use sp or pp; 1 = p, 2 = s\n\n\tprivate int bufsize;\n\n\tprivate NSSerialPort sp = null;\n\n\tprivate NSParallelPort pp = null;\n\n\tprivate byte[] buffer = null; // size equivalent to insBufferSize\n\n\t// of NSSerialPort or NSParallelPort\n// -----------------------------------------------------------------------------\n// Methods - constructors\n// -----------------------------------------------------------------------------\n\tNSDeviceOutputStream(final CommPort port, final int portType) {\n\t\tif (portType == CommPortIdentifier.PORT_PARALLEL) {\n\t\t\tthis.pt = 1;\n\t\t\tthis.pp = (NSParallelPort) port;\n\t\t\tthis.bufsize = this.pp.outsBufferSize;\n\t\t} else {\n\t\t\tthis.pt = 2;\n\t\t\tthis.sp = (NSSerialPort) port;\n\t\t\tthis.bufsize = this.sp.outsBufferSize;\n\t\t}\n\t\tthis.buffer = new byte[this.bufsize];\n\t}\n\n// -----------------------------------------------------------------------------\n// Methods - public\n// -----------------------------------------------------------------------------\n\tpublic void flush() throws IOException {\n\t\tint rc;\n\t\tint obc = 0;\n\t\tif (this.pp != null) {\n\t\t\tobc = this.pp.outsBufferCount;\n\t\t} else if (this.sp != null) {\n\t\t\tobc = this.sp.outsBufferCount;\n\t\t}\n\t\trc = writeDeviceNC(this.buffer, 0, obc);\n\t\t// If any errors were encountered during writes to the device, throw\n\t\t// an exception.\n\t\tif (rc != obc) {\n\t\t\tfinal IOException e = new IOException();\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\t/**\n\t * @return pt\n\t */\n\tpublic int getPt() {\n\t\treturn this.pt;\n\t}\n\n\tpublic void write(final byte b[]) throws IOException {\n\t\twrite(b, 0, b.length);\n\t}\n\n\tpublic void write(final byte b[], final int off, final int len) throws IOException {\n\t\t// ???? How about if data is to be suspended for the parallel port ????\n\t\tint toff = off;\n\t\tint tlen = len;\n\t\tint rc;\n\t\tboolean excflag = false;\n\t\tint obc = 0;\n\t\tfinal int oldbufsize = this.bufsize;\n\t\tboolean notify = false;\n\t\tthis.bufsize = 0;\n\t\t// If buffer size has been changed since the last time, flush out the\n\t\t// current data in the internal buffer.\n\t\tif (this.pp != null) {\n\t\t\tthis.bufsize = this.pp.outsBufferSize;\n\t\t\tobc = this.pp.outsBufferCount;\n\t\t} else if (this.sp != null) {\n\t\t\tthis.bufsize = this.sp.outsBufferSize;\n\t\t\tobc = this.sp.outsBufferCount;\n\t\t}\n\t\tif (this.bufsize != oldbufsize) {\n\t\t\tif (obc != 0) {\n\t\t\t\trc = writeDeviceNC(this.buffer, 0, obc);\n\t\t\t\tif (this.pp != null) {\n\t\t\t\t\tthis.pp.outsBufferCount = 0;\n\t\t\t\t} else if (this.sp != null) {\n\t\t\t\t\tthis.sp.outsBufferCount = 0;\n\t\t\t\t}\n\t\t\t\tif (rc != obc) {\n\t\t\t\t\texcflag = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.buffer = null; // hopefully this is freed now\n\t\t\tthis.buffer = new byte[this.bufsize];\n\t\t}\n\t\t// If buffer size is 0, then no buffering is to be done.\n\t\tif (this.bufsize == 0) {\n\t\t\tif (this.pp != null) {\n\t\t\t\tthis.pp.outsBufferCount = 0;\n\t\t\t} else if (this.sp != null) {\n\t\t\t\tthis.sp.outsBufferCount = 0;\n\t\t\t}\n\t\t\trc = writeDeviceNC(b, toff, tlen);\n\t\t\tif (rc != tlen) {\n\t\t\t\texcflag = true;\n\t\t\t}\n\t\t} else { // save the data internally, and if full, write it out\n\t\t\twhile (tlen != 0) {\n\t\t\t\tint wc;\n\t\t\t\tif (this.pp != null) {\n\t\t\t\t\tobc = this.pp.outsBufferCount;\n\t\t\t\t} else if (this.sp != null) {\n\t\t\t\t\tobc = this.sp.outsBufferCount;\n\t\t\t\t}\n\t\t\t\tif (obc + tlen >= this.bufsize) {\n\t\t\t\t\twc = this.bufsize - obc;\n\t\t\t\t\t// save this in buffer and write buffer to dev\n\t\t\t\t\tjava.lang.System.arraycopy(b, toff, this.buffer, obc, wc);\n\t\t\t\t\trc = writeDeviceNC(this.buffer, 0, this.bufsize);\n\t\t\t\t\tif (this.pp != null) {\n\t\t\t\t\t\tthis.pp.outsBufferCount = 0;\n\t\t\t\t\t} else if (this.sp != null) {\n\t\t\t\t\t\tthis.sp.outsBufferCount = 0;\n\t\t\t\t\t}\n\t\t\t\t\tif (rc != this.bufsize) {\n\t\t\t\t\t\texcflag = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\twc = tlen;\n\t\t\t\t\t// save this in buffer\n\t\t\t\t\tjava.lang.System.arraycopy(b, toff, this.buffer, obc, wc);\n\t\t\t\t\tif (this.pp != null) {\n\t\t\t\t\t\tthis.pp.outsBufferCount += wc;\n\t\t\t\t\t} else if (this.sp != null) {\n\t\t\t\t\t\tthis.sp.outsBufferCount += wc;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttoff += wc;\n\t\t\t\ttlen -= wc;\n\t\t\t}\n\t\t}\n\t\t// If any errors were encountered during writes to the device, throw\n\t\t// an exception.\n\t\tif (excflag) {\n\t\t\tfinal IOException e = new IOException();\n\t\t\tthrow e;\n\t\t}\n\t\t// If the internal buffer has been drained out to the device, send\n\t\t// a corresponding event, if notification is set.\n\t\tif (this.pp != null) {\n\t\t\tobc = this.pp.outsBufferCount;\n\t\t\tnotify = this.pp.notifyOnBufferFlag;\n\t\t} else if (this.sp != null) {\n\t\t\tobc = this.sp.outsBufferCount;\n\t\t\tnotify = this.sp.notifyOnBufferFlag;\n\t\t}\n\t\tif (notify && (obc == 0)) {\n\t\t\tif (this.pp != null) {\n\t\t\t\tthis.pp.reportParallelEvent(ParallelPortEvent.PAR_EV_BUFFER, false, true);\n\t\t\t} else if (this.sp != null) {\n\t\t\t\tthis.sp.reportSerialEvent(SerialPortEvent.OUTPUT_BUFFER_EMPTY, false, true);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic void write(final int i) throws IOException {\n\t\tfinal byte b[] = new byte[1];\n\t\tb[0] = (byte) (i & 0xff);\n\t\twrite(b, 0, 1);\n\t}\n\n// -----------------------------------------------------------------------------\n// Methods - private\n// -----------------------------------------------------------------------------\n\tprivate native int writeDeviceNC(byte buf[], int offset, int nBytes);\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/NSParallelPort.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport javax.comm.*;\nimport java.io.*;\nimport java.util.*;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class NSParallelPort extends ParallelPort {\n\t/**\n\t * Define the lpt mode any (int) constant.\n\t */\n\tpublic static final int LPT_MODE_ANY = 0;\n\n\t/**\n\t * Define the lpt mode spp (int) constant.\n\t */\n\tpublic static final int LPT_MODE_SPP = 1;\n\n\t/**\n\t * Define the lpt mode ps2 (int) constant.\n\t */\n\tpublic static final int LPT_MODE_PS2 = 2;\n\n\t/**\n\t * Define the lpt mode epp (int) constant.\n\t */\n\tpublic static final int LPT_MODE_EPP = 3;\n\n\t/**\n\t * Define the lpt mode ecp (int) constant.\n\t */\n\tpublic static final int LPT_MODE_ECP = 4;\n\n\t/**\n\t * Define the lpt mode nibble (int) constant.\n\t */\n\tpublic static final int LPT_MODE_NIBBLE = 5;\n\n\t/**\n\t * Define the mode (int) field.\n\t */\n\tprivate int mode = LPT_MODE_SPP; // only SPP mode is supported at this time\n\n\t/**\n\t * Define the fd (int) field.\n\t */\n\tint fd = -1; // file descriptor for the open device\n\n\t/**\n\t * Define the fd (FileDescriptor) field.\n\t */\n\tFileDescriptor FD = null; // FileDescriptor for the open device\n\n\t/**\n\t * Define the ins (NSDeviceInputStream) field.\n\t */\n\tprivate NSDeviceInputStream ins = null;\n\n\t/**\n\t * Define the outs (NSDeviceOutputStream) field.\n\t */\n\tprivate NSDeviceOutputStream outs = null;\n\n\t/**\n\t * Define the rcv threshold (int) field.\n\t */\n\tint rcvThreshold = -1;\n\n\t/**\n\t * Define the rcv timeout (int) field.\n\t */\n\tint rcvTimeout = -1;\n\n\t/**\n\t * Define the rcv framing (boolean) field.\n\t */\n\tboolean rcvFraming = false;\n\n\t/**\n\t * Define the rcv framing byte (int) field.\n\t */\n\tint rcvFramingByte;\n\n\t/**\n\t * Define the rcv framing byte received (boolean) field.\n\t */\n\tboolean rcvFramingByteReceived;\n\n\t/**\n\t * Disable read buffering for now\n\t */\n\tint insBufferSize = 0;\n\n\t/**\n\t * Define the ins buffer count (int) field.\n\t */\n\tint insBufferCount = 0;\n\n\t/**\n\t * Define the outs suspended (boolean) field.\n\t */\n\tboolean outsSuspended = false;\n\n\t/**\n\t * Disable write buffering for default\n\t */\n\tint outsBufferSize = 0;\n\n\t/**\n\t * Define the outs buffer count (int) field.\n\t */\n\tint outsBufferCount = 0;\n\n\t/**\n\t * Define the listener (ParallelPortEventListener) field.\n\t */\n\tprivate ParallelPortEventListener listener = null;\n\n\t/**\n\t * Define the notify on error flag (boolean) field.\n\t */\n\tprivate boolean notifyOnErrorFlag = false;\n\n\t/**\n\t * Define the notify on buffer flag (boolean) field.\n\t */\n\tboolean notifyOnBufferFlag = false;\n\n\t/**\n\t * Define the error thread (ParallelErrorEventThread) field.\n\t */\n\tprivate ParallelErrorEventThread errorThread = null;\n\n\t/**\n\t * Define the dle (DeviceListEntry) field.\n\t */\n\tprivate DeviceListEntry dle = null;\n\n\t/**\n\t * Define the cd (NSCommDriver) field.\n\t */\n\tprivate NSCommDriver cd = null;\n\n\t/**\n\t * Constructs an instance of this class from the specified port name and driver parameters.\n\t * @param portName The port name (<code>String</code>) parameter.\n\t * @param driver The driver (<code>NSCommDriver</code>) parameter.\n\t * @throws IOException IOException.\n\t */\n\tNSParallelPort(final String portName, final NSCommDriver driver) throws IOException {\n\t\t/* NSParallelPort-extends-ParallelPort-extends-CommPort->name */\n\t\tthis.name = portName;\n\t\t// save CommDriver\n\t\tthis.cd = driver;\n\t\t// look for portName in DeviceList\n\t\tfor (DeviceListEntry cur = this.cd.getFirstDLE(); cur != null; cur = this.cd.getNextDLE(cur)) {\n\t\t\tif (cur.logicalName.equals(portName)) {\n\t\t\t\t/* found the portName in list, attempt to open it using native method. */\n\t\t\t\tif ((this.fd == -1) || !cur.opened) {\n\t\t\t\t\tif ((this.fd = openDeviceNC(cur.physicalName, cur.semID)) == -1) {\n\t\t\t\t\t\t// file descriptor is NOT valid, throw an Exception\n\t\t\t\t\t\tthrow new IOException();\n\t\t\t\t\t}\n\t\t\t\t\t/* Got a good file descriptor. */\n\t\t\t\t\t/* keep a copy of the DeviceListEntry where you found the portName */\n\t\t\t\t\t/* get a FileDescriptor object */\n\t\t\t\t\t/* turn opened ON */\n\t\t\t\t\tthis.dle = cur;\n\t\t\t\t\tthis.dle.opened = true;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new IOException();\n\t\t\t\t}\n\t\t\t\tbreak; // found our port\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Add event listener with the specified lst parameter.\n\t * @param lst The lst (<code>ParallelPortEventListener</code>) parameter.\n\t * @throws TooManyListenersException Too Many Listeners Exception.\n\t * @see #removeEventListener()\n\t */\n\tpublic synchronized void addEventListener(final ParallelPortEventListener lst) throws TooManyListenersException {\n\t\tif (this.listener != null) {\n\t\t\tthrow new TooManyListenersException();\n\t\t}\n\t\tthis.listener = lst;\n\t\tif (this.notifyOnErrorFlag && (this.errorThread == null)) {\n\t\t\tthis.errorThread = new ParallelErrorEventThread(this.fd, this);\n\t\t\t// errorThread.setDaemon( true ); // check it out\n\t\t\tthis.errorThread.start();\n\t\t}\n\t}\n\n\t/**\n\t * Close.\n\t */\n\tpublic void close() {\n\t\t// check if either fd or opened is not valid\n\t\t// nothing to be done\n\t\tif (this.fd == -1) {\n\t\t\treturn;\n\t\t}\n\t\t// if the error thread is alive, kill it\n\t\tif (this.errorThread != null) {\n\t\t\tthis.errorThread.setStopThreadFlag(1);\n\t\t\tthis.errorThread = null;\n\t\t\tthis.notifyOnErrorFlag = false;\n\t\t}\n\t\t// check ins and outs\n\t\tif (this.outs != null) {\n\t\t\ttry {\n\t\t\t\tthis.outs.flush();\n\t\t\t} catch (final IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\tthis.outs = null;\n\t\t}\n\t\tif (this.ins != null) {\n\t\t\tthis.ins = null;\n\t\t}\n\t\t/* close the device. */\n\t\tcloseDeviceNC(this.fd, this.dle.semID);\n\t\t/* reset fd and opened. */\n\t\tthis.fd = -1;\n\t\tthis.dle.opened = false;\n\t\t// close the commport\n\t\tsuper.close();\n\t}\n\n\t/**\n\t * Close device nc with the specified fd and sem id parameters and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @param semID The sem id (<code>int</code>) parameter.\n\t * @return Results of the close device nc (<code>int</code>) value.\n\t */\n\tprivate native int closeDeviceNC(final int fd, final int semID);\n\n\t/**\n\t * Disable receive framing.\n\t * @see #enableReceiveFraming(int)\n\t */\n\tpublic void disableReceiveFraming() {\n\t\tthis.rcvFraming = false;\n\t}\n\n\t/**\n\t * Disable receive threshold.\n\t * @see #enableReceiveThreshold(int)\n\t * @see #getReceiveThreshold()\n\t */\n\tpublic void disableReceiveThreshold() {\n\t\tthis.rcvThreshold = -1;\n\t}\n\n\t/**\n\t * Disable receive timeout.\n\t * @see #enableReceiveTimeout(int)\n\t * @see #getReceiveTimeout()\n\t */\n\tpublic void disableReceiveTimeout() {\n\t\tthis.rcvTimeout = -1;\n\t}\n\n\t/**\n\t * Enable receive framing with the specified rcv framing byte parameter.\n\t * @param rcvFramingByte The rcv framing byte (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #disableReceiveFraming()\n\t */\n\tpublic void enableReceiveFraming(final int rcvFramingByte) throws UnsupportedCommOperationException {\n\t\tthrow new UnsupportedCommOperationException();\n\t}\n\n\t/**\n\t * Enable receive threshold with the specified thresh parameter.\n\t * @param thresh The thresh (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #disableReceiveThreshold()\n\t * @see #getReceiveThreshold()\n\t */\n\tpublic void enableReceiveThreshold(final int thresh) throws UnsupportedCommOperationException {\n\t\tif (thresh > 0) {\n\t\t\tthis.rcvThreshold = thresh;\n\t\t}\n\t}\n\n\t/**\n\t * Enable receive timeout with the specified rt parameter.\n\t * @param rt The rt (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #disableReceiveTimeout()\n\t * @see #getReceiveTimeout()\n\t */\n\tpublic void enableReceiveTimeout(final int rt) throws UnsupportedCommOperationException {\n\t\tif (rt > 0) {\n\t\t\tthis.rcvTimeout = rt;\n\t\t} else if (rt == 0) {\n\t\t\tthis.rcvTimeout = -1;\n\t\t}\n\t}\n\n\t/**\n\t * Finalize.\n\t * @throws IOException IOException.\n\t */\n\tprotected void finalize() throws IOException {\n\t\tclose();\n\t}\n\n\t/**\n\t * Gets the input buffer size (int) value.\n\t * @return The input buffer size (<code>int</code>) value.\n\t * @see #setInputBufferSize(int)\n\t */\n\tpublic int getInputBufferSize() {\n\t\treturn this.insBufferSize;\n\t}\n\n\t/**\n\t * Gets the input stream value.\n\t * @return The input stream (<code>InputStream</code>) value.\n\t * @throws IOException IOException.\n\t */\n\tpublic InputStream getInputStream() throws IOException {\n\t\tif (this.ins == null) {\n\t\t\tif ((this.ins = new NSDeviceInputStream(this, this.dle.portType)) == null) {\n\t\t\t\tthrow new IOException();\n\t\t\t}\n\t\t\tthis.ins.fd = this.fd;\n\t\t}\n\t\treturn this.ins;\n\t}\n\n\t/**\n\t * Gets the mode (int) value.\n\t * @return The mode (<code>int</code>) value.\n\t * @see #setMode(int)\n\t */\n\tpublic int getMode() {\n\t\treturn this.mode;\n\t}\n\n\t/**\n\t * Gets the output buffer free (int) value.\n\t * @return The output buffer free (<code>int</code>) value.\n\t */\n\tpublic int getOutputBufferFree() {\n\t\treturn (this.outsBufferSize > this.outsBufferCount ? this.outsBufferSize - this.outsBufferCount : 0);\n\t}\n\n\t/**\n\t * Gets the output buffer size (int) value.\n\t * @return The output buffer size (<code>int</code>) value.\n\t * @see #setOutputBufferSize(int)\n\t */\n\tpublic int getOutputBufferSize() {\n\t\treturn this.outsBufferSize;\n\t}\n\n\t/**\n\t * Gets the output stream value.\n\t * @return The output stream (<code>OutputStream</code>) value.\n\t * @throws IOException IOException.\n\t */\n\tpublic OutputStream getOutputStream() throws IOException {\n\t\tif (this.outs == null) {\n\t\t\tif ((this.outs = new NSDeviceOutputStream(this, this.dle.portType)) == null) {\n\t\t\t\tthrow new IOException();\n\t\t\t}\n\t\t\tthis.outs.fd = this.fd;\n\t\t}\n\t\treturn this.outs;\n\t}\n\n\t/**\n\t * Gets the receive framing byte (int) value.\n\t * @return The receive framing byte (<code>int</code>) value.\n\t */\n\tpublic int getReceiveFramingByte() {\n\t\treturn this.rcvFramingByte;\n\t}\n\n\t/**\n\t * Gets the receive threshold (int) value.\n\t * @return The receive threshold (<code>int</code>) value.\n\t * @see #disableReceiveThreshold()\n\t * @see #enableReceiveThreshold(int)\n\t */\n\tpublic int getReceiveThreshold() {\n\t\treturn this.rcvThreshold;\n\t}\n\n\t/**\n\t * Gets the receive timeout (int) value.\n\t * @return The receive timeout (<code>int</code>) value.\n\t * @see #disableReceiveTimeout()\n\t * @see #enableReceiveTimeout(int)\n\t */\n\tpublic int getReceiveTimeout() {\n\t\treturn this.rcvTimeout;\n\t}\n\n\t/**\n\t * Gets the paper out (boolean) value.\n\t * @return The paper out (<code>boolean</code>) value.\n\t */\n\tpublic boolean isPaperOut() {\n\t\treturn isPaperOutNC(this.fd);\n\t}\n\n\t/**\n\t * Is paper out nc with the specified fd parameter and return the boolean result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the is paper out nc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isPaperOutNC(final int fd);\n\n\t/**\n\t * Gets the printer busy (boolean) value.\n\t * @return The printer busy (<code>boolean</code>) value.\n\t */\n\tpublic boolean isPrinterBusy() {\n\t\treturn isPrinterBusyNC(this.fd);\n\t}\n\n\t/**\n\t * Is printer busy nc with the specified fd parameter and return the boolean result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the is printer busy nc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isPrinterBusyNC(final int fd);\n\n\t/**\n\t * Gets the printer error (boolean) value.\n\t * @return The printer error (<code>boolean</code>) value.\n\t */\n\tpublic boolean isPrinterError() {\n\t\treturn isPrinterErrorNC(this.fd);\n\t}\n\n\t/**\n\t * Is printer error nc with the specified fd parameter and return the boolean result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the is printer error nc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isPrinterErrorNC(final int fd);\n\n\t/**\n\t * Gets the printer selected (boolean) value.\n\t * @return The printer selected (<code>boolean</code>) value.\n\t */\n\tpublic boolean isPrinterSelected() {\n\t\treturn isPrinterSelectedNC(this.fd);\n\t}\n\n\t/**\n\t * Is printer selected nc with the specified fd parameter and return the boolean result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the is printer selected nc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isPrinterSelectedNC(final int fd);\n\n\t/**\n\t * Gets the printer timed out (boolean) value.\n\t * @return The printer timed out (<code>boolean</code>) value.\n\t */\n\tpublic boolean isPrinterTimedOut() {\n\t\treturn isPrinterTimedOutNC(this.fd);\n\t}\n\n\t/**\n\t * Is printer timed out nc with the specified fd parameter and return the boolean result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the is printer timed out nc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isPrinterTimedOutNC(final int fd);\n\n\t/**\n\t * Gets the receive framing enabled (boolean) value.\n\t * @return The receive framing enabled (<code>boolean</code>) value.\n\t */\n\tpublic boolean isReceiveFramingEnabled() {\n\t\treturn this.rcvFraming;\n\t}\n\n\t/**\n\t * Gets the receive threshold enabled (boolean) value.\n\t * @return The receive threshold enabled (<code>boolean</code>) value.\n\t */\n\tpublic boolean isReceiveThresholdEnabled() {\n\t\treturn (this.rcvThreshold == -1 ? false : true);\n\t}\n\n\t/**\n\t * Gets the receive timeout enabled (boolean) value.\n\t * @return The receive timeout enabled (<code>boolean</code>) value.\n\t */\n\tpublic boolean isReceiveTimeoutEnabled() {\n\t\treturn (this.rcvTimeout == -1 ? false : true);\n\t}\n\n\t/**\n\t * Notify on buffer with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnBuffer(final boolean notify) {\n\t\tthis.notifyOnBufferFlag = notify;\n\t}\n\n\t/**\n\t * Notify on error with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnError(final boolean notify) {\n\t\tif (notify) {\n\t\t\tif (!this.notifyOnErrorFlag) {\n\t\t\t\t// instantiate ParallelErrorEventThread\n\t\t\t\tif ((this.errorThread == null) && (this.listener != null)) {\n\t\t\t\t\tthis.errorThread = new ParallelErrorEventThread(this.fd, this);\n\t\t\t\t\tthis.errorThread.start();\n\t\t\t\t}\n\t\t\t\tthis.notifyOnErrorFlag = true;\n\t\t\t}\n\t\t} else {\n\t\t\tif (this.notifyOnErrorFlag) {\n\t\t\t\t/* Stop ParallelErrorEventThread */\n\t\t\t\tif (this.errorThread != null) {\n\t\t\t\t\tthis.errorThread.setStopThreadFlag(1);\n\t\t\t\t}\n\t\t\t\tthis.notifyOnErrorFlag = false;\n\t\t\t\tthis.errorThread = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Open device nc with the specified device name and sem id parameters and return the int result.\n\t * @param deviceName The device name (<code>String</code>) parameter.\n\t * @param semID The sem id (<code>int</code>) parameter.\n\t * @return Results of the open device nc (<code>int</code>) value.\n\t */\n\tprivate native int openDeviceNC(final String deviceName, final int semID);\n\n\t/**\n\t * Remove event listener.\n\t * @see #addEventListener(ParallelPortEventListener)\n\t */\n\tpublic synchronized void removeEventListener() {\n\t\tif (this.listener != null) {\n\t\t\tif (this.errorThread != null) {\n\t\t\t\tthis.errorThread.setStopThreadFlag(1);\n\t\t\t}\n\t\t\tthis.errorThread = null;\n\t\t\tthis.listener = null;\n\t\t}\n\t}\n\n\t/**\n\t * Report parallel event with the specified event type, oldvalue and newvalue parameters.\n\t * @param eventType The event type (<code>int</code>) parameter.\n\t * @param oldvalue The oldvalue (<code>boolean</code>) parameter.\n\t * @param newvalue The newvalue (<code>boolean</code>) parameter.\n\t */\n\tsynchronized void reportParallelEvent(final int eventType, final boolean oldvalue, final boolean newvalue) {\n\t\tif (this.listener != null) {\n\t\t\tfinal ParallelPortEvent pe = new ParallelPortEvent(this, eventType, oldvalue, newvalue);\n\t\t\tthis.listener.parallelEvent(pe);\n\t\t}\n\t}\n\n\t/**\n\t * Restart.\n\t */\n\tpublic void restart() {\n\t\tthis.outsSuspended = false;\n\t}\n\n\t/**\n\t * Sets the input buffer size value.\n\t * @param size The size (<code>int</code>) parameter.\n\t * @see #getInputBufferSize()\n\t */\n\tpublic void setInputBufferSize(final int size) {\n\t\t/* do nothing */\n\t}\n\n\t/**\n\t * Sets the mode value.\n\t * @param md The md (<code>int</code>) parameter.\n\t * @return The mode (<code>int</code>) value.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #getMode()\n\t */\n\tpublic int setMode(final int md) throws UnsupportedCommOperationException {\n\t\tthrow new UnsupportedCommOperationException();\n\t}\n\n\t/**\n\t * Sets the output buffer size value.\n\t * @param size The size (<code>int</code>) parameter.\n\t * @see #getOutputBufferSize()\n\t */\n\tpublic void setOutputBufferSize(final int size) {\n\t\tif (size >= 0) {\n\t\t\tthis.outsBufferSize = size;\n\t\t}\n\t}\n\n\t/**\n\t * Suspend.\n\t */\n\tpublic void suspend() {\n\t\tthis.outsSuspended = true;\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/NSSerialPort.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*************************************************************************\n * Copyright (c) 1999, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport javax.comm.*;\nimport java.io.*;\nimport java.util.*;\n\n/**\n * An RS-232 serial communications port. SerialPort describes the\n * low-level interface to a serial communications port made\n * available by the underlying system. SerialPort defines the\n * minimum required functionality for serial communications ports.\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\nclass NSSerialPort extends SerialPort {\n\t/**\n\t * Define the databits5 (int) constant.\n\t */\n\tpublic static final int DATABITS_5 = 5;\n\n\t/**\n\t * Define the databits6 (int) constant.\n\t */\n\tpublic static final int DATABITS_6 = 6;\n\n\t/**\n\t * Define the databits7 (int) constant.\n\t */\n\tpublic static final int DATABITS_7 = 7;\n\n\t/**\n\t * Define the databits8 (int) constant.\n\t */\n\tpublic static final int DATABITS_8 = 8;\n\n\t/**\n\t * Define the stopbits1 (int) constant.\n\t */\n\tpublic static final int STOPBITS_1 = 1;\n\n\t/**\n\t * Define the stopbits2 (int) constant.\n\t */\n\tpublic static final int STOPBITS_2 = 2;\n\n\t/**\n\t * Define the stopbits15 (int) constant.\n\t */\n\tpublic static final int STOPBITS_1_5 = 3;\n\n\t/**\n\t * Define the parity none (int) constant.\n\t */\n\tpublic static final int PARITY_NONE = 0;\n\n\t/**\n\t * Define the parity odd (int) constant.\n\t */\n\tpublic static final int PARITY_ODD = 1;\n\n\t/**\n\t * Define the parity even (int) constant.\n\t */\n\tpublic static final int PARITY_EVEN = 2;\n\n\t/**\n\t * Define the parity mark (int) constant.\n\t */\n\tpublic static final int PARITY_MARK = 3;\n\n\t/**\n\t * Define the parity space (int) constant.\n\t */\n\tpublic static final int PARITY_SPACE = 4;\n\n\t/**\n\t * Define the flowcontrol none (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_NONE = 0;\n\n\t/**\n\t * Define the flowcontrol rtscts in (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_RTSCTS_IN = 1;\n\n\t/**\n\t * Define the flowcontrol rtscts out (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_RTSCTS_OUT = 2;\n\n\t/**\n\t * Define the flowcontrol xonxoff in (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_XONXOFF_IN = 4;\n\n\t/**\n\t * Define the flowcontrol xonxoff out (int) constant.\n\t */\n\tpublic static final int FLOWCONTROL_XONXOFF_OUT = 8;\n\n\t/**\n\t * Define the flowcontrol (int) field.\n\t */\n\tprivate int flowcontrol = FLOWCONTROL_NONE;\n\n\t/**\n\t * Define the baudrate (int) field.\n\t */\n\tprivate int baudrate = 9600;\n\n\t/**\n\t * Define the databits (int) field.\n\t */\n\tprivate int databits = DATABITS_8;\n\n\t/**\n\t * Define the stopbits (int) field.\n\t */\n\tprivate int stopbits = STOPBITS_1;\n\n\t/**\n\t * Define the parity (int) field.\n\t */\n\tprivate int parity = PARITY_NONE;\n\n\t/**\n\t * Define the dtr (boolean) field.\n\t */\n\tprivate boolean dtr;\n\n\t/**\n\t * Define the rts (boolean) field.\n\t */\n\tprivate boolean rts;\n\n\t/**\n\t * Define the dle (DeviceListEntry) field.\n\t */\n\tprivate DeviceListEntry dle = null;\n\n\t/**\n\t * Define the cd (NSCommDriver) field.\n\t */\n\tprivate NSCommDriver cd = null;\n\n\t/**\n\t * Define the fd (int) field.\n\t */\n\tint fd = -1; // file descriptor for the open device\n\n\t/**\n\t * Define the fd (FileDescriptor) field.\n\t */\n\tFileDescriptor FD = null; // FileDescriptor for the open device for which buffers can be built upon\n\n\t/**\n\t * Define the ins (NSDeviceInputStream) field.\n\t */\n\tprivate NSDeviceInputStream ins = null;\n\n\t/**\n\t * Define the outs (NSDeviceOutputStream) field.\n\t */\n\tprivate NSDeviceOutputStream outs = null;\n\n\t/**\n\t * Define the rcv threshold (int) field.\n\t */\n\tint rcvThreshold = -1;\n\n\t/**\n\t * Define the rcv timeout (int) field.\n\t */\n\tint rcvTimeout = -1;\n\n\t/**\n\t * Define the rcv framing (boolean) field.\n\t */\n\tboolean rcvFraming = false;\n\n\t/**\n\t * Define the rcv framing byte (int) field.\n\t */\n\tint rcvFramingByte;\n\n\t/**\n\t * Define the rcv framing byte received (boolean) field.\n\t */\n\tboolean rcvFramingByteReceived;\n\n\t/**\n\t * Disable read buffering for now\n\t */\n\tint insBufferSize = 0;\n\n\t/**\n\t * Define the ins buffer count (int) field.\n\t */\n\tint insBufferCount = 0;\n\n\t/**\n\t * Disable write buffering for default\n\t */\n\tint outsBufferSize = 0;\n\n\t/**\n\t * Define the outs buffer count (int) field.\n\t */\n\tint outsBufferCount = 0;\n\n\t/**\n\t * Define the listener (SerialPortEventListener) field.\n\t */\n\tprivate SerialPortEventListener listener = null;\n\n\t/**\n\t * Define the notify on ctsflag (boolean) field.\n\t */\n\tprivate boolean notifyOnCTSFlag = false;\n\n\t/**\n\t * Define the notify on dsrflag (boolean) field.\n\t */\n\tprivate boolean notifyOnDSRFlag = false;\n\n\t/**\n\t * Define the notify on riflag (boolean) field.\n\t */\n\tprivate boolean notifyOnRIFlag = false;\n\n\t/**\n\t * Define the notify on cdflag (boolean) field.\n\t */\n\tprivate boolean notifyOnCDFlag = false;\n\n\t/**\n\t * Define the notify on orflag (boolean) field.\n\t */\n\tprivate boolean notifyOnORFlag = false;\n\n\t/**\n\t * Define the notify on peflag (boolean) field.\n\t */\n\tprivate boolean notifyOnPEFlag = false;\n\n\t/**\n\t * Define the notify on feflag (boolean) field.\n\t */\n\tprivate boolean notifyOnFEFlag = false;\n\n\t/**\n\t * Define the notify on biflag (boolean) field.\n\t */\n\tprivate boolean notifyOnBIFlag = false;\n\n\t/**\n\t * Define the notify on buffer flag (boolean) field.\n\t */\n\tboolean notifyOnBufferFlag = false;\n\n\t/**\n\t * Define the notify on data flag (boolean) field.\n\t */\n\tprivate boolean notifyOnDataFlag = false;\n\n\t/**\n\t * Define the status thread (SerialStatusEventThread) field.\n\t */\n\tprivate SerialStatusEventThread statusThread = null;\n\n\t/**\n\t * Define the data thread (SerialDataEventThread) field.\n\t */\n\tprivate SerialDataEventThread dataThread = null;\n\n\t/**\n\t * Constructor\n\t * @param portName The port name (<code>String</code>) parameter.\n\t * @param driver The driver (<code>NSCommDriver</code>) parameter.\n\t * @throws IOException IOException.\n\t */\n\tpublic NSSerialPort(final String portName, final NSCommDriver driver) throws IOException {\n\t\t/* caller wants port portName */\n\t\t/* NSSerialPort-extends-SerialPort-extends-CommPort->name */\n\t\tthis.name = portName;\n\t\t// save CommDriver\n\t\tthis.cd = driver;\n\t\t// look for portName in DeviceList\n\t\tfor (DeviceListEntry cur = this.cd.getFirstDLE(); cur != null; cur = this.cd.getNextDLE(cur)) {\n\t\t\tif (cur.logicalName.equals(portName)) {\n\t\t\t\t/* found the portName in list, attempt to open it using native method. */\n\t\t\t\tif ((this.fd == -1) || !cur.opened) {\n\t\t\t\t\tif ((this.fd = openDeviceNC(cur.physicalName, cur.semID)) == -1) {\n\t\t\t\t\t\t// file descriptor is NOT valid, throw an Exception\n\t\t\t\t\t\tthrow new IOException();\n\t\t\t\t\t}\n\t\t\t\t\t/* Got a good file descriptor. */\n\t\t\t\t\t/* keep a copy of the DeviceListEntry where you found the portName */\n\t\t\t\t\t/* get a FileDescriptor object */\n\t\t\t\t\t/* turn opened ON */\n\t\t\t\t\tthis.dle = cur;\n\t\t\t\t\tthis.dle.opened = true;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new IOException();\n\t\t\t\t}\n\t\t\t\tbreak; // found our port\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Add event listener with the specified lstnr parameter.\n\t * @param lstnr The lstnr (<code>SerialPortEventListener</code>) parameter.\n\t * @throws TooManyListenersException Too Many Listeners Exception.\n\t * @see #removeEventListener()\n\t */\n\tpublic synchronized void addEventListener(final SerialPortEventListener lstnr) throws TooManyListenersException {\n\t\tif (this.listener != null) {\n\t\t\tthrow new TooManyListenersException();\n\t\t}\n\t\tthis.listener = lstnr;\n\t\t// check all other related flags, all must be false\n\t\tif ((this.notifyOnDSRFlag || this.notifyOnRIFlag || this.notifyOnCDFlag || this.notifyOnORFlag || this.notifyOnPEFlag || this.notifyOnFEFlag || this.notifyOnCTSFlag || this.notifyOnBIFlag) && (this.statusThread == null)) {\n\t\t\tthis.statusThread = new SerialStatusEventThread(this.fd, this);\n\t\t\t// statusThread.setDaemon( true ); // check it out ???\n\t\t\tthis.statusThread.start();\n\t\t}\n\t\tif (this.notifyOnDataFlag && (this.dataThread == null)) {\n\t\t\tthis.dataThread = new SerialDataEventThread(this.fd, this);\n\t\t\t// dataThread.setDaemon( true ); // check it out ???\n\t\t\tthis.dataThread.start();\n\t\t}\n\t}\n\n\t/**\n\t * Close.\n\t */\n\tpublic void close() {\n\t\tif (this.fd == -1) {\n\t\t\treturn;\n\t\t}\n\t\t// if thread are alive, kill them\n\t\tif (this.statusThread != null) {\n\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\tthis.notifyOnCTSFlag = false;\n\t\t\tthis.notifyOnDSRFlag = false;\n\t\t\tthis.notifyOnRIFlag = false;\n\t\t\tthis.notifyOnCDFlag = false;\n\t\t\tthis.notifyOnORFlag = false;\n\t\t\tthis.notifyOnPEFlag = false;\n\t\t\tthis.notifyOnFEFlag = false;\n\t\t\tthis.notifyOnBIFlag = false;\n\t\t}\n\t\tif (this.dataThread != null) {\n\t\t\tthis.dataThread.setStopThreadFlag(1);\n\t\t\tthis.notifyOnDataFlag = false;\n\t\t}\n\t\t// check ins and outs\n\t\tif (this.outs != null) {\n\t\t\ttry {\n\t\t\t\tthis.outs.flush();\n\t\t\t} catch (final IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t\tthis.outs = null;\n\t\t}\n\t\tif (this.ins != null) {\n\t\t\tthis.ins = null;\n\t\t}\n\t\t/* close the device. */\n\t\tcloseDeviceNC(this.fd, this.dle.semID);\n\t\t/* reset fd and opened. */\n\t\tthis.fd = -1;\n\t\tthis.dle.opened = false;\n\t\t// close the commport\n\t\tsuper.close();\n\t}\n\n\t/**\n\t * Close device nc with the specified fd and sem id parameters and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @param semID The sem id (<code>int</code>) parameter.\n\t * @return Results of the close device nc (<code>int</code>) value.\n\t */\n\tprivate native int closeDeviceNC(final int fd, final int semID);\n\n\t/**\n\t * Disable receive framing.\n\t * @see #enableReceiveFraming(int)\n\t */\n\tpublic void disableReceiveFraming() {\n\t\tthis.rcvFraming = false;\n\t}\n\n\t/**\n\t * Disable receive threshold.\n\t * @see #enableReceiveThreshold(int)\n\t * @see #getReceiveThreshold()\n\t */\n\tpublic void disableReceiveThreshold() {\n\t\tthis.rcvThreshold = -1;\n\t}\n\n\t/**\n\t * Disable receive timeout.\n\t * @see #enableReceiveTimeout(int)\n\t * @see #getReceiveTimeout()\n\t */\n\tpublic void disableReceiveTimeout() {\n\t\tthis.rcvTimeout = -1;\n\t}\n\n\t/**\n\t * Enable receive framing with the specified rcv framing byte parameter.\n\t * @param rcvFramingByte The rcv framing byte (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #disableReceiveFraming()\n\t */\n\tpublic void enableReceiveFraming(final int rcvFramingByte) throws UnsupportedCommOperationException {\n\t\tthrow new UnsupportedCommOperationException();\n\t}\n\n\t/**\n\t * Enable receive threshold with the specified thresh parameter.\n\t * @param thresh The thresh (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #disableReceiveThreshold()\n\t * @see #getReceiveThreshold()\n\t */\n\tpublic void enableReceiveThreshold(final int thresh) throws UnsupportedCommOperationException {\n\t\tif (thresh > 0) {\n\t\t\tthis.rcvThreshold = thresh;\n\t\t}\n\t}\n\n\t/**\n\t * Enable receive timeout with the specified rt parameter.\n\t * @param rt The rt (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #disableReceiveTimeout()\n\t * @see #getReceiveTimeout()\n\t */\n\tpublic void enableReceiveTimeout(final int rt) throws UnsupportedCommOperationException {\n\t\tif (rt > 0) {\n\t\t\tthis.rcvTimeout = rt;\n\t\t} else if (rt == 0) {\n\t\t\tthis.rcvTimeout = -1;\n\t\t}\n\t}\n\n\t/**\n\t * Finalize.\n\t * @throws IOException IOException.\n\t */\n\tprotected void finalize() throws IOException {\n\t\tclose();\n\t}\n\n\t/**\n\t * Gets the baud rate (int) value.\n\t * @return The baud rate (<code>int</code>) value.\n\t */\n\tpublic int getBaudRate() {\n\t\tint bdrate = 0;\n\t\tif (this.fd > -1) {\n\t\t\tbdrate = getBaudRateNC(this.fd);\n\t\t\tif (bdrate < 0) {\n\t\t\t\tbdrate = 0;\n\t\t\t} else {\n\t\t\t\tthis.baudrate = bdrate;\n\t\t\t\t// no need to map native values to java values here\n\t\t\t}\n\t\t}\n\t\treturn bdrate;\n\t}\n\n\t/**\n\t * Get baud rate nc with the specified fd parameter and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the get baud rate nc (<code>int</code>) value.\n\t */\n\tprivate native int getBaudRateNC(final int fd);\n\n\t/**\n\t * Gets the baudrate (int) value.\n\t * @return The baudrate (<code>int</code>) value.\n\t */\n\tpublic int getBaudrate() {\n\t\treturn this.baudrate;\n\t}\n\n\t/**\n\t * Gets the data bits (int) value.\n\t * @return The data bits (<code>int</code>) value.\n\t */\n\tpublic int getDataBits() {\n\t\tint db = 0;\n\t\tif (this.fd > -1) {\n\t\t\tdb = getDataBitsNC(this.fd);\n\t\t\tif (db != -1) {\n\t\t\t\tswitch (db) {\n\t\t\t\tcase 5:\n\t\t\t\t\tthis.databits = DATABITS_5;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 6:\n\t\t\t\t\tthis.databits = DATABITS_6;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 7:\n\t\t\t\t\tthis.databits = DATABITS_7;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t\tthis.databits = DATABITS_8;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this.databits;\n\t}\n\n\t/**\n\t * Get data bits nc with the specified fd parameter and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the get data bits nc (<code>int</code>) value.\n\t */\n\tprivate native int getDataBitsNC(final int fd);\n\n\t/**\n\t * Gets the currently configured flow control mode.\n\t * Returns:\n\t * an integer bitmask of the modes FLOWCONTROL_NONE,\n\t * FLOWCONTROL_RTSCTS_IN,\n\t * FLOWCONTROL_RTSCTS_OUT,\n\t * FLOWCONTROL_XONXOFF_IN, and\n\t * FLOWCONTROL_XONXOFF_OUT.\n\t * @return Results of the get flow control mode (<code>int</code>) value.\n\t * @see #setFlowControlMode(int)\n\t */\n\tpublic int getFlowControlMode() {\n\t\tif (this.fd > -1) {\n\t\t\tfinal int retCode = getFlowControlModeNC(this.fd);\n\t\t\tif (retCode == -1) {\n\t\t\t\treturn this.flowcontrol;\n\t\t\t}\n\t\t\tif (retCode == 0) {\n\t\t\t\tthis.flowcontrol = FLOWCONTROL_NONE;\n\t\t\t} else {\n\t\t\t\tint fl = 0;\n\t\t\t\tif ((retCode & 1) != 0) {\n\t\t\t\t\tfl |= FLOWCONTROL_RTSCTS_IN;\n\t\t\t\t}\n\t\t\t\tif ((retCode & 2) != 0) {\n\t\t\t\t\tfl |= FLOWCONTROL_RTSCTS_OUT;\n\t\t\t\t}\n\t\t\t\tif ((retCode & 4) != 0) {\n\t\t\t\t\tfl |= FLOWCONTROL_XONXOFF_IN;\n\t\t\t\t}\n\t\t\t\tif ((retCode & 8) != 0) {\n\t\t\t\t\tfl |= FLOWCONTROL_XONXOFF_OUT;\n\t\t\t\t}\n\t\t\t\tthis.flowcontrol = fl;\n\t\t\t}\n\t\t} else {\n\t\t\treturn this.flowcontrol;\n\t\t}\n\t\treturn this.flowcontrol;\n\t}\n\n\t/**\n\t * Get flow control mode nc with the specified fd parameter and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the get flow control mode nc (<code>int</code>) value.\n\t */\n\tprivate native int getFlowControlModeNC(final int fd);\n\n\t/**\n\t * Gets the input buffer size (int) value.\n\t * @return The input buffer size (<code>int</code>) value.\n\t * @see #setInputBufferSize(int)\n\t */\n\tpublic int getInputBufferSize() {\n\t\treturn this.insBufferSize;\n\t}\n\n\t/**\n\t * Gets the input stream value.\n\t * @return The input stream (<code>InputStream</code>) value.\n\t * @throws IOException IOException.\n\t */\n\tpublic InputStream getInputStream() throws IOException {\n\t\tif (this.ins != null) {\n\t\t\treturn this.ins;\n\t\t}\n\t\tif ((this.ins = new NSDeviceInputStream(this, this.dle.portType)) == null) {\n\t\t\tthrow new IOException();\n\t\t}\n\t\tthis.ins.fd = this.fd;\n\t\treturn this.ins;\n\t}\n\n\t/**\n\t * Gets the output buffer size (int) value.\n\t * @return The output buffer size (<code>int</code>) value.\n\t * @see #setOutputBufferSize(int)\n\t */\n\tpublic int getOutputBufferSize() {\n\t\treturn this.outsBufferSize;\n\t}\n\n\t/**\n\t * Gets the output stream value.\n\t * @return The output stream (<code>OutputStream</code>) value.\n\t * @throws IOException IOException.\n\t */\n\tpublic OutputStream getOutputStream() throws IOException {\n\t\tif (this.outs != null) {\n\t\t\treturn this.outs;\n\t\t}\n\t\t/* Y: get a new DeviceOutputStream */\n\t\tif ((this.outs = new NSDeviceOutputStream(this, this.dle.portType)) == null) {\n\t\t\tthrow new IOException();\n\t\t}\n\t\t// what do I do here\n\t\tthis.outs.fd = this.fd;\n\t\treturn this.outs;\n\t}\n\n\t/**\n\t * Gets the parity (int) value.\n\t * @return The parity (<code>int</code>) value.\n\t */\n\tpublic int getParity() {\n\t\tint p = 0;\n\t\tif (this.fd > -1) {\n\t\t\tp = getParityNC(this.fd);\n\t\t\tif (p != -1) {\n\t\t\t\tswitch (p) {\n\t\t\t\tcase 0:\n\t\t\t\t\tthis.parity = PARITY_NONE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tthis.parity = PARITY_ODD;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tthis.parity = PARITY_EVEN;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3:\n\t\t\t\t\tthis.parity = PARITY_MARK;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 4:\n\t\t\t\t\tthis.parity = PARITY_SPACE;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this.parity;\n\t}\n\n\t/**\n\t * Get parity nc with the specified fd parameter and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the get parity nc (<code>int</code>) value.\n\t */\n\tprivate native int getParityNC(final int fd);\n\n\t/**\n\t * Gets the receive framing byte (int) value.\n\t * @return The receive framing byte (<code>int</code>) value.\n\t */\n\tpublic int getReceiveFramingByte() {\n\t\treturn this.rcvFramingByte;\n\t}\n\n\t/**\n\t * Gets the receive threshold (int) value.\n\t * @return The receive threshold (<code>int</code>) value.\n\t * @see #disableReceiveThreshold()\n\t * @see #enableReceiveThreshold(int)\n\t */\n\tpublic int getReceiveThreshold() {\n\t\treturn this.rcvThreshold;\n\t}\n\n\t/**\n\t * Gets the receive timeout (int) value.\n\t * @return The receive timeout (<code>int</code>) value.\n\t * @see #disableReceiveTimeout()\n\t * @see #enableReceiveTimeout(int)\n\t */\n\tpublic int getReceiveTimeout() {\n\t\treturn this.rcvTimeout;\n\t}\n\n\t/**\n\t * Gets the stop bits (int) value.\n\t * @return The stop bits (<code>int</code>) value.\n\t */\n\tpublic int getStopBits() {\n\t\tint sb = 0;\n\t\tif (this.fd > -1) {\n\t\t\tsb = getStopBitsNC(this.fd);\n\t\t\tif (sb != -1) {\n\t\t\t\tswitch (sb) {\n\t\t\t\tcase 0:\n\t\t\t\t\tthis.stopbits = STOPBITS_1_5;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tthis.stopbits = STOPBITS_1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tthis.stopbits = STOPBITS_2;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this.stopbits;\n\t}\n\n\t/**\n\t * Get stop bits nc with the specified fd parameter and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @return Results of the get stop bits nc (<code>int</code>) value.\n\t */\n\tprivate native int getStopBitsNC(final int fd);\n\n\t/**\n\t * Gets the cd (boolean) value.\n\t * @return The cd (<code>boolean</code>) value.\n\t */\n\tpublic boolean isCD() {\n\t\treturn isCDNC();\n\t}\n\n\t/**\n\t * Gets the cdnc (boolean) value.\n\t * @return The cdnc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isCDNC();\n\n\t/**\n\t * Gets the cts (boolean) value.\n\t * @return The cts (<code>boolean</code>) value.\n\t * @see #notifyOnCTS(boolean)\n\t */\n\tpublic boolean isCTS() {\n\t\treturn isCTSNC();\n\t}\n\n\t/**\n\t * Gets the ctsnc (boolean) value.\n\t * @return The ctsnc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isCTSNC();\n\n\t/**\n\t * Gets the dsr (boolean) value.\n\t * @return The dsr (<code>boolean</code>) value.\n\t * @see #notifyOnDSR(boolean)\n\t */\n\tpublic boolean isDSR() {\n\t\treturn isDSRNC();\n\t}\n\n\t/**\n\t * Gets the dsrnc (boolean) value.\n\t * @return The dsrnc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isDSRNC();\n\n\t/**\n\t * Gets the dtr (boolean) value.\n\t * @return The dtr (<code>boolean</code>) value.\n\t * @see #setDTR(boolean)\n\t */\n\tpublic boolean isDTR() {\n\t\treturn isDTRNC();\n\t}\n\n\t/**\n\t * Gets the dtrnc (boolean) value.\n\t * @return The dtrnc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isDTRNC();\n\n\t/**\n\t * Gets the dtr (boolean) value.\n\t * @return The dtr (<code>boolean</code>) value.\n\t */\n\tpublic boolean isDtr() {\n\t\treturn this.dtr;\n\t}\n\n\t/**\n\t * Gets the ri (boolean) value.\n\t * @return The ri (<code>boolean</code>) value.\n\t */\n\tpublic boolean isRI() {\n\t\treturn isRINC();\n\t}\n\n\t/**\n\t * Gets the rinc (boolean) value.\n\t * @return The rinc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isRINC();\n\n\t/**\n\t * Gets the rts (boolean) value.\n\t * @return The rts (<code>boolean</code>) value.\n\t * @see #setRTS(boolean)\n\t */\n\tpublic boolean isRTS() {\n\t\treturn isRTSNC();\n\t}\n\n\t/**\n\t * Gets the rtsnc (boolean) value.\n\t * @return The rtsnc (<code>boolean</code>) value.\n\t */\n\tprivate native boolean isRTSNC();\n\n\t/**\n\t * Gets the receive framing enabled (boolean) value.\n\t * @return The receive framing enabled (<code>boolean</code>) value.\n\t */\n\tpublic boolean isReceiveFramingEnabled() {\n\t\treturn this.rcvFraming;\n\t}\n\n\t/**\n\t * Gets the receive threshold enabled (boolean) value.\n\t * @return The receive threshold enabled (<code>boolean</code>) value.\n\t */\n\tpublic boolean isReceiveThresholdEnabled() {\n\t\tif (this.rcvThreshold == -1) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Gets the receive timeout enabled (boolean) value.\n\t * @return The receive timeout enabled (<code>boolean</code>) value.\n\t */\n\tpublic boolean isReceiveTimeoutEnabled() {\n\t\tif (this.rcvTimeout == -1) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Gets the rts (boolean) value.\n\t * @return The rts (<code>boolean</code>) value.\n\t */\n\tpublic boolean isRts() {\n\t\treturn this.rts;\n\t}\n\n\t/**\n\t * Notify on break interrupt with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnBreakInterrupt(final boolean notify) {\n\t\tif (notify && this.notifyOnBIFlag) {\n\t\t\treturn; // already enabled\n\t\t}\n\t\tif (notify && !this.notifyOnBIFlag) {\n\t\t\t// instantiate SerialStatusEventThread\n\t\t\tif (this.statusThread == null) {\n\t\t\t\tthis.statusThread = new SerialStatusEventThread(this.fd, this);\n\t\t\t\t// statusThread.setDaemon( true ); // check it out\n\t\t\t\tthis.statusThread.start();\n\t\t\t}\n\t\t\tthis.notifyOnBIFlag = true;\n\t\t} else {\n\t\t\t// check all other related flags, all must be false\n\t\t\tif (!this.notifyOnCTSFlag && !this.notifyOnDSRFlag && !this.notifyOnRIFlag && !this.notifyOnCDFlag && !this.notifyOnORFlag && !this.notifyOnPEFlag && !this.notifyOnFEFlag) {\n\t\t\t\tif (this.statusThread != null) {\n\t\t\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\t\t\tthis.statusThread = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.notifyOnBIFlag = false;\n\t\t}\n\t}\n\n\t/**\n\t * Notify on cts with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnCTS(final boolean notify) {\n\t\tif (notify && this.notifyOnCTSFlag) {\n\t\t\treturn; // already enabled\n\t\t}\n\t\tif (notify && !this.notifyOnCTSFlag) {\n\t\t\tif (this.statusThread == null) {\n\t\t\t\tthis.statusThread = new SerialStatusEventThread(this.fd, this);\n\t\t\t\t// statusThread.setDaemon( true ); // check it out\n\t\t\t\tthis.statusThread.start();\n\t\t\t}\n\t\t\tthis.notifyOnCTSFlag = true;\n\t\t} else {\n\t\t\t// check all other related flags, all must be false\n\t\t\tif (!this.notifyOnDSRFlag && !this.notifyOnRIFlag && !this.notifyOnCDFlag && !this.notifyOnORFlag && !this.notifyOnPEFlag && !this.notifyOnFEFlag && !this.notifyOnBIFlag) {\n\t\t\t\tif (this.statusThread != null) {\n\t\t\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\t\t\tthis.statusThread = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.notifyOnCTSFlag = false;\n\t\t}\n\t}\n\n\t/**\n\t * Notify on carrier detect with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnCarrierDetect(final boolean notify) {\n\t\tif (notify && this.notifyOnCDFlag) {\n\t\t\treturn; // already enabled\n\t\t}\n\t\tif (notify && !this.notifyOnCDFlag) {\n\t\t\t// instantiate SerialStatusEventThread\n\t\t\tif (this.statusThread == null) {\n\t\t\t\tthis.statusThread = new SerialStatusEventThread(this.fd, this);\n\t\t\t\t// statusThread.setDaemon( true ); // check it out\n\t\t\t\tthis.statusThread.start();\n\t\t\t}\n\t\t\tthis.notifyOnCDFlag = true;\n\t\t} else {\n\t\t\t// check all other related flags, all must be false\n\t\t\tif (!this.notifyOnCTSFlag && !this.notifyOnDSRFlag && !this.notifyOnORFlag && !this.notifyOnRIFlag && !this.notifyOnPEFlag && !this.notifyOnFEFlag && !this.notifyOnBIFlag) {\n\t\t\t\tif (this.statusThread != null) {\n\t\t\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\t\t\tthis.statusThread = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.notifyOnCDFlag = false;\n\t\t}\n\t}\n\n\t/**\n\t * Notify on dsr with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnDSR(final boolean notify) {\n\t\tif (notify && this.notifyOnDSRFlag) {\n\t\t\treturn; // already enabled\n\t\t}\n\t\tif (notify && !this.notifyOnDSRFlag) {\n\t\t\tif (this.statusThread == null) {\n\t\t\t\tthis.statusThread = new SerialStatusEventThread(this.fd, this);\n\t\t\t\tthis.statusThread.start();\n\t\t\t}\n\t\t\tthis.notifyOnDSRFlag = true;\n\t\t} else {\n\t\t\t// check all other related flags, all must be false\n\t\t\tif (!this.notifyOnCTSFlag && !this.notifyOnRIFlag && !this.notifyOnCDFlag && !this.notifyOnORFlag && !this.notifyOnPEFlag && !this.notifyOnFEFlag && !this.notifyOnBIFlag) {\n\t\t\t\tif (this.statusThread != null) {\n\t\t\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\t\t\tthis.statusThread = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.notifyOnDSRFlag = false;\n\t\t}\n\t}\n\n\t/**\n\t * Notify on data available with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnDataAvailable(final boolean notify) {\n\t\tif (notify) {\n\t\t\tif (!this.notifyOnDataFlag) {\n\t\t\t\t// instantiate SerialDataEventThread\n\t\t\t\tif (this.dataThread == null) {\n\t\t\t\t\tthis.dataThread = new SerialDataEventThread(this.fd, this);\n\t\t\t\t\t// dataThread.setDaemon( true ); // check it out\n\t\t\t\t\tthis.dataThread.start();\n\t\t\t\t}\n\t\t\t\tthis.notifyOnDataFlag = true;\n\t\t\t}\n\t\t} else {\n\t\t\tif (this.notifyOnDataFlag) {\n\t\t\t\t/* Stop SerialDataEventThread */\n\t\t\t\tif (this.dataThread != null) {\n\t\t\t\t\tthis.dataThread.setStopThreadFlag(1);\n\t\t\t\t}\n\t\t\t\tthis.notifyOnDataFlag = false;\n\t\t\t\tthis.dataThread = null;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Notify on framing error with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnFramingError(final boolean notify) {\n\t\tif (notify && this.notifyOnFEFlag) {\n\t\t\treturn; // already enabled\n\t\t}\n\t\tif (notify && !this.notifyOnFEFlag) {\n\t\t\tif (this.statusThread == null) {\n\t\t\t\tthis.statusThread = new SerialStatusEventThread(this.fd, this);\n\t\t\t\t// statusThread.setDaemon( true ); // check it out\n\t\t\t\tthis.statusThread.start();\n\t\t\t}\n\t\t\tthis.notifyOnFEFlag = true;\n\t\t} else {\n\t\t\t// check all other related flags, all must be false\n\t\t\tif (!this.notifyOnCTSFlag && !this.notifyOnDSRFlag && !this.notifyOnRIFlag && !this.notifyOnCDFlag && !this.notifyOnORFlag && !this.notifyOnPEFlag && !this.notifyOnBIFlag) {\n\t\t\t\tif (this.statusThread != null) {\n\t\t\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\t\t\tthis.statusThread = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.notifyOnFEFlag = false;\n\t\t}\n\t}\n\n\t/**\n\t * Notify on output empty with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnOutputEmpty(final boolean notify) {\n\t\tthis.notifyOnBufferFlag = notify;\n\t}\n\n\t/**\n\t * Notify on overrun error with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnOverrunError(final boolean notify) {\n\t\tif (notify && this.notifyOnORFlag) {\n\t\t\treturn; // already enabled\n\t\t}\n\t\tif (notify && !this.notifyOnORFlag) {\n\t\t\t// instantiate SerialStatusEventThread\n\t\t\tif (this.statusThread == null) {\n\t\t\t\tthis.statusThread = new SerialStatusEventThread(this.fd, this);\n\t\t\t\t// statusThread.setDaemon( true ); // check it out\n\t\t\t\tthis.statusThread.start();\n\t\t\t}\n\t\t\tthis.notifyOnORFlag = true;\n\t\t} else {\n\t\t\t// check all other related flags, all must be false\n\t\t\tif (!this.notifyOnCTSFlag && !this.notifyOnDSRFlag && !this.notifyOnRIFlag && !this.notifyOnCDFlag && !this.notifyOnPEFlag && !this.notifyOnFEFlag && !this.notifyOnBIFlag) {\n\t\t\t\tif (this.statusThread != null) {\n\t\t\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\t\t\tthis.statusThread = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.notifyOnORFlag = false;\n\t\t}\n\t}\n\n\t/**\n\t * Notify on parity error with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnParityError(final boolean notify) {\n\t\tif (notify && this.notifyOnPEFlag) {\n\t\t\treturn; // already enabled\n\t\t}\n\t\tif (notify && !this.notifyOnPEFlag) {\n\t\t\t// instantiate SerialStatusEventThread\n\t\t\tif (this.statusThread == null) {\n\t\t\t\tthis.statusThread = new SerialStatusEventThread(this.fd, this);\n\t\t\t\t// statusThread.setDaemon( true ); // check it out\n\t\t\t\tthis.statusThread.start();\n\t\t\t}\n\t\t\tthis.notifyOnPEFlag = true;\n\t\t} else {\n\t\t\t// check all other related flags, all must be false\n\t\t\tif (!this.notifyOnCTSFlag && !this.notifyOnDSRFlag && !this.notifyOnRIFlag && !this.notifyOnCDFlag && !this.notifyOnORFlag && !this.notifyOnFEFlag && !this.notifyOnBIFlag) {\n\t\t\t\tif (this.statusThread != null) {\n\t\t\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\t\t\tthis.statusThread = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.notifyOnPEFlag = false;\n\t\t}\n\t}\n\n\t/**\n\t * Notify on ring indicator with the specified notify parameter.\n\t * @param notify The notify (<code>boolean</code>) parameter.\n\t */\n\tpublic synchronized void notifyOnRingIndicator(final boolean notify) {\n\t\tif (notify && this.notifyOnRIFlag) {\n\t\t\treturn; // already enabled\n\t\t}\n\t\tif (notify && !this.notifyOnRIFlag) {\n\t\t\tif (this.statusThread == null) {\n\t\t\t\tthis.statusThread = new SerialStatusEventThread(this.fd, this);\n\t\t\t\t// statusThread.setDaemon( true ); // check it out\n\t\t\t\tthis.statusThread.start();\n\t\t\t}\n\t\t\tthis.notifyOnRIFlag = true;\n\t\t} else {\n\t\t\t// check all other related flags, all must be false\n\t\t\tif (!this.notifyOnCTSFlag && !this.notifyOnDSRFlag && !this.notifyOnCDFlag && !this.notifyOnORFlag && !this.notifyOnPEFlag && !this.notifyOnFEFlag && !this.notifyOnBIFlag) {\n\t\t\t\tif (this.statusThread != null) {\n\t\t\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\t\t\tthis.statusThread = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.notifyOnRIFlag = false;\n\t\t}\n\t}\n\n\t/**\n\t * Open device nc with the specified device name and sem id parameters and return the int result.\n\t * @param deviceName The device name (<code>String</code>) parameter.\n\t * @param semID The sem id (<code>int</code>) parameter.\n\t * @return Results of the open device nc (<code>int</code>) value.\n\t */\n\tprivate native int openDeviceNC(final String deviceName, final int semID);\n\n\t/**\n\t * Remove event listener.\n\t * @see #addEventListener(SerialPortEventListener)\n\t */\n\tpublic synchronized void removeEventListener() {\n\t\tif (this.listener != null) {\n\t\t\tif (this.statusThread != null) {\n\t\t\t\tthis.statusThread.setStopThreadFlag(1);\n\t\t\t}\n\t\t\tthis.statusThread = null;\n\t\t\tif (this.dataThread != null) {\n\t\t\t\tthis.dataThread.setStopThreadFlag(1);\n\t\t\t}\n\t\t\tthis.dataThread = null;\n\t\t\tthis.listener = null;\n\t\t}\n\t}\n\n\t/**\n\t * Report serial event with the specified event type, oldvalue and newvalue parameters.\n\t * @param eventType The event type (<code>int</code>) parameter.\n\t * @param oldvalue The oldvalue (<code>boolean</code>) parameter.\n\t * @param newvalue The newvalue (<code>boolean</code>) parameter.\n\t */\n\tsynchronized void reportSerialEvent(final int eventType, final boolean oldvalue, final boolean newvalue) {\n\t\tif (this.listener != null) {\n\t\t\tfinal SerialPortEvent se = new SerialPortEvent(this, eventType, oldvalue, newvalue);\n\t\t\tthis.listener.serialEvent(se);\n\t\t}\n\t}\n\n\t/**\n\t * Send break with the specified millis parameter.\n\t * @param millis The millis (<code>int</code>) parameter.\n\t */\n\tpublic void sendBreak(final int millis) {\n\t\tif (this.fd != -1) {\n\t\t\tsendBreakNC(this.fd, millis);\n\t\t}\n\t}\n\n\t/**\n\t * Send break nc with the specified fd and millis parameters and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @param millis The millis (<code>int</code>) parameter.\n\t * @return Results of the send break nc (<code>int</code>) value.\n\t */\n\tprivate native int sendBreakNC(final int fd, final int millis);\n\n\t/**\n\t * Sets the dtr value.\n\t * @param dtr The dtr (<code>boolean</code>) parameter.\n\t * @see #isDTR()\n\t */\n\tpublic void setDTR(final boolean dtr) {\n\t\tsetDTRNC(dtr);\n\t}\n\n\t/**\n\t * Sets the dtrnc value.\n\t * @param dtr The dtr (<code>boolean</code>) parameter.\n\t */\n\tprivate native void setDTRNC(final boolean dtr);\n\n\t/**\n\t * Sets the flow control mode value.\n\t * @param flowctrl The flowctrl (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t * @see #getFlowControlMode()\n\t */\n\tpublic void setFlowControlMode(final int flowctrl) throws UnsupportedCommOperationException {\n\t\t/* Check for invalid combinations. */\n\t\tif ((this.fd == -1) ||\n\t\t/* Now FLOWCONTROL_NONE is 0 instead of 1, and hence no need for this\n\t\t   check below!!! */\n\t\t/**************************\n\t\t   (((flowctrl & FLOWCONTROL_NONE) != 0) &&\n\t\t(((flowctrl & FLOWCONTROL_RTSCTS_IN) != 0) ||\n\t\t ((flowctrl & FLOWCONTROL_RTSCTS_OUT) != 0) ||\n\t\t ((flowctrl & FLOWCONTROL_XONXOFF_IN) != 0) ||\n\t\t ((flowctrl & FLOWCONTROL_XONXOFF_OUT) != 0))) ||\n\t\t **************************/\n\t\t(((flowctrl & FLOWCONTROL_RTSCTS_IN) != 0) && ((flowctrl & FLOWCONTROL_XONXOFF_OUT) != 0)) || (((flowctrl & FLOWCONTROL_XONXOFF_IN) != 0) && ((flowctrl & FLOWCONTROL_RTSCTS_OUT) != 0))\n\t\t\t\t|| (((flowctrl & FLOWCONTROL_RTSCTS_IN) != 0) && ((flowctrl & FLOWCONTROL_XONXOFF_IN) != 0)) || (((flowctrl & FLOWCONTROL_RTSCTS_OUT) != 0) && ((flowctrl & FLOWCONTROL_XONXOFF_OUT) != 0))) {\n\t\t\tthrow new UnsupportedCommOperationException();\n\t\t}\n\t\t// retcode of -1 is a problem\n\t\tif (setFlowControlModeNC(this.fd, flowctrl) != -1) {\n\t\t\tthis.flowcontrol = flowctrl;\n\t\t} else {\n\t\t\tthrow new UnsupportedCommOperationException();\n\t\t}\n\t}\n\n\t/**\n\t * Set flow control mode nc with the specified fd and flowctrl parameters and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @param flowctrl The flowctrl (<code>int</code>) parameter.\n\t * @return Results of the set flow control mode nc (<code>int</code>) value.\n\t */\n\tprivate native int setFlowControlModeNC(final int fd, final int flowctrl);\n\n\t/**\n\t * Sets the input buffer size value.\n\t * @param size The size (<code>int</code>) parameter.\n\t * @see #getInputBufferSize()\n\t */\n\tpublic void setInputBufferSize(final int size) {\n\t\t/* do nothing */\n\t}\n\n\t/**\n\t * Sets the output buffer size value.\n\t * @param size The size (<code>int</code>) parameter.\n\t * @see #getOutputBufferSize()\n\t */\n\tpublic void setOutputBufferSize(final int size) {\n\t\tif (size >= 0) {\n\t\t\tthis.outsBufferSize = size;\n\t\t}\n\t}\n\n\t/**\n\t * Sets the rts value.\n\t * @param rts The rts (<code>boolean</code>) parameter.\n\t * @see #isRTS()\n\t */\n\tpublic void setRTS(final boolean rts) {\n\t\tsetRTSNC(rts);\n\t}\n\n\t/**\n\t * Sets the rtsnc value.\n\t * @param rts The rts (<code>boolean</code>) parameter.\n\t */\n\tprivate native void setRTSNC(final boolean rts);\n\n\t/**\n\t * Sets the rcv fifo trigger value.\n\t * @param trigger The trigger (<code>int</code>) parameter.\n\t */\n\tpublic void setRcvFifoTrigger(final int trigger) {\n\t\t/* do nothing */\n\t}\n\n\t/**\n\t * Set serial port params with the specified bd, db, sb and par parameters.\n\t * @param bd The bd (<code>int</code>) parameter.\n\t * @param db The db (<code>int</code>) parameter.\n\t * @param sb The sb (<code>int</code>) parameter.\n\t * @param par The par (<code>int</code>) parameter.\n\t * @throws UnsupportedCommOperationException Unsupported Comm Operation Exception.\n\t */\n\tpublic void setSerialPortParams(final int bd, final int db, final int sb, final int par) throws UnsupportedCommOperationException {\n\t\t/* Validate the values. */\n\t\tif (this.fd == -1) {\n\t\t\tthrow new UnsupportedCommOperationException();\n\t\t}\n\t\tif ((db != DATABITS_5) && (db != DATABITS_6) && (db != DATABITS_7) && (db != DATABITS_8)) {\n\t\t\tthrow new UnsupportedCommOperationException();\n\t\t}\n\t\tif ((sb != STOPBITS_1) && (sb != STOPBITS_2) && (sb != STOPBITS_1_5)) { // 1.5 not supported\n\t\t\tthrow new UnsupportedCommOperationException();\n\t\t}\n\t\tif ((par != PARITY_NONE) && (par != PARITY_ODD) && (par != PARITY_EVEN) && (par != PARITY_MARK) && (par != PARITY_SPACE)) {\n\t\t\tthrow new UnsupportedCommOperationException();\n\t\t}\n\t\t/* Now set the desired communication characteristics. */\n\t\tif (setSerialPortParamsNC(this.fd, bd, db, sb, par) < 0) {\n\t\t\tthrow new UnsupportedCommOperationException();\n\t\t}\n\t}\n\n\t/**\n\t * Set serial port params nc with the specified fd, bd, db, sb and par parameters and return the int result.\n\t * @param fd The fd (<code>int</code>) parameter.\n\t * @param bd The bd (<code>int</code>) parameter.\n\t * @param db The db (<code>int</code>) parameter.\n\t * @param sb The sb (<code>int</code>) parameter.\n\t * @param par The par (<code>int</code>) parameter.\n\t * @return Results of the set serial port params nc (<code>int</code>) value.\n\t */\n\tprivate native int setSerialPortParamsNC(final int fd, final int bd, final int db, final int sb, final int par);\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/ParallelErrorEventThread.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*************************************************************************\n * Copyright (c) 2007, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\nclass ParallelErrorEventThread extends Thread {\n\t/**\n\t * Define the pp (NSParallelPort) field.\n\t */\n\tNSParallelPort pp = null;\n\n\t/**\n\t * Define the polling time (int) field.\n\t */\n\tprivate final int pollingTime = 5; //  ??\n\n\t/**\n\t * Define the fd (int) field.\n\t */\n\tprivate int fd = -1;\n\n\t/**\n\t * Define the stop thread flag (int) field.\n\t */\n\tprivate int stopThreadFlag = 0;\n\n\t/**\n\t * Constructs an instance of this class from the specified ifd and port parameters.\n\t * @param ifd\tThe ifd (<code>int</code>) parameter.\n\t * @param port\tThe port (<code>NSParallelPort</code>) parameter.\n\t */\n\tParallelErrorEventThread(final int ifd, final NSParallelPort port) {\n\t\tthis.fd = ifd;\n\t\tthis.pp = port;\n\t}\n\n\t/**\n\t * Gets the polling time (int) value.\n\t * @return\tThe polling time (<code>int</code>) value.\n\t */\n\tpublic int getPollingTime() {\n\t\treturn this.pollingTime;\n\t}\n\n\t/**\n\t * Gets the stop thread flag (int) value.\n\t * @return\tThe stop thread flag (<code>int</code>) value.\n\t * @see #setStopThreadFlag(int)\n\t */\n\tpublic int getStopThreadFlag() {\n\t\treturn this.stopThreadFlag;\n\t}\n\n\t/**\n\t * Monitor parallel error nc with the specified fd parameter.\n\t * @param fd\tThe fd (<code>int</code>) parameter.\n\t */\n\tprivate native void monitorParallelErrorNC(final int fd);\n\n\t/**\n\t * Run.\n\t */\n\tpublic void run() {\n\t\tmonitorParallelErrorNC(this.fd);\n\t}\n\n\t/**\n\t * Sets the stop thread flag value.\n\t * @param value\tThe value (<code>int</code>) parameter.\n\t * @see #getStopThreadFlag()\n\t */\n\tpublic void setStopThreadFlag(final int value) {\n\t\tthis.stopThreadFlag = value;\n\t\treturn;\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/SerialDataEventThread.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*************************************************************************\n * Copyright (c) 2007, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\nclass SerialDataEventThread extends Thread {\n\t/**\n\t * Define the serial port (NSSerialPort) field.\n\t */\n\tNSSerialPort serialPort = null;\n\n\t/**\n\t * Define the file descriptor (int) field.\n\t */\n\tprivate int fileDescriptor = -1;\n\n\t/**\n\t * Define the stop thread flag (int) field.\n\t */\n\tprivate int stopThreadFlag = 0;\n\n\t/**\n\t * Constructs an instance of this class from the specified fd and sp parameters.\n\t * @param fd\tThe fd (<code>int</code>) parameter.\n\t * @param sp\tThe sp (<code>NSSerialPort</code>) parameter.\n\t */\n\tSerialDataEventThread(final int fd, final NSSerialPort sp) {\n\t\tthis.serialPort = sp;\n\t\tthis.fileDescriptor = fd;\n\t}\n\n\t/**\n\t * Gets the stop thread flag (int) value.\n\t * @return\tThe stop thread flag (<code>int</code>) value.\n\t * @see #setStopThreadFlag(int)\n\t */\n\tpublic int getStopThreadFlag() {\n\t\treturn this.stopThreadFlag;\n\t}\n\n\t/**\n\t * Monitor serial data nc with the specified fd parameter.\n\t * @param fd\tThe fd (<code>int</code>) parameter.\n\t */\n\tprivate native void monitorSerialDataNC(final int fd);\n\n\t/**\n\t * Run.\n\t */\n\tpublic void run() {\n\t\tmonitorSerialDataNC(this.fileDescriptor);\n\t}\n\n\t/**\n\t * Sets the stop thread flag value.\n\t * @param value\tThe value (<code>int</code>) parameter.\n\t * @see #getStopThreadFlag()\n\t */\n\tpublic void setStopThreadFlag(final int value) {\n\t\tthis.stopThreadFlag = value;\n\t\treturn;\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/SerialStatusEventThread.java",
    "content": "package org.eclipse.soda.dk.comm;\n\n/*************************************************************************\n * Copyright (c) 2007, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\nclass SerialStatusEventThread extends Thread {\n\t/**\n\t * Define the serial port (NSSerialPort) field.\n\t */\n\tNSSerialPort serialPort = null;\n\n\t/**\n\t * Define the polling time (int) field.\n\t */\n\tprivate final int pollingTime = 5; //  ??\n\n\t/**\n\t * Define the file descriptor (int) field.\n\t */\n\tprivate int fileDescriptor = -1;\n\n\t/**\n\t * Define the stop thread flag (int) field.\n\t */\n\tprivate int stopThreadFlag = 0;\n\n\t/**\n\t * Constructs an instance of this class from the specified fd and sp parameters.\n\t * @param fd\tThe fd (<code>int</code>) parameter.\n\t * @param sp\tThe sp (<code>NSSerialPort</code>) parameter.\n\t */\n\tSerialStatusEventThread(final int fd, final NSSerialPort sp) {\n\t\tthis.fileDescriptor = fd;\n\t\tthis.serialPort = sp;\n\t}\n\n\t/**\n\t * Gets the polling time (int) value.\n\t * @return\tThe polling time (<code>int</code>) value.\n\t */\n\tpublic int getPollingTime() {\n\t\treturn this.pollingTime;\n\t}\n\n\t/**\n\t * Gets the stop thread flag (int) value.\n\t * @return\tThe stop thread flag (<code>int</code>) value.\n\t * @see #setStopThreadFlag(int)\n\t */\n\tpublic int getStopThreadFlag() {\n\t\treturn this.stopThreadFlag;\n\t}\n\n\t/**\n\t * Monitor serial status nc with the specified fd parameter.\n\t * @param fd\tThe fd (<code>int</code>) parameter.\n\t */\n\tprivate native void monitorSerialStatusNC(final int fd);\n\n\t/**\n\t * Run.\n\t */\n\tpublic void run() {\n\t\tmonitorSerialStatusNC(this.fileDescriptor);\n\t}\n\n\t/**\n\t * Sets the stop thread flag value.\n\t * @param value\tThe value (<code>int</code>) parameter.\n\t * @see #getStopThreadFlag()\n\t */\n\tpublic void setStopThreadFlag(final int value) {\n\t\tthis.stopThreadFlag = value;\n\t\treturn;\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/bundle/Activator.java",
    "content": "package org.eclipse.soda.dk.comm.bundle;\n\n/*************************************************************************\n * Copyright (c) 2007, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport org.eclipse.soda.dk.comm.internal.Library;\nimport org.osgi.framework.BundleActivator;\nimport org.osgi.framework.BundleContext;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class Activator implements BundleActivator {\n\t/**\n\t * Parse bundle list with the specified raw list and bundle file parameters and return the String result.\n\t * @param rawList\tThe raw list (<code>String</code>) parameter.\n\t * @param bundleFile\tThe bundle file (<code>String</code>) parameter.\n\t * @return\tResults of the parse bundle list (<code>String</code>) value.\n\t */\n\tprivate String parseBundleList(final String rawList, final String bundleFile) {\n\t\tString result = null;\n\t\tint i = rawList.indexOf(bundleFile);\n\t\tif (i != -1) {\n\t\t\tint j = rawList.lastIndexOf(',', i);\n\t\t\tint k = rawList.lastIndexOf(\"file:\", i); //$NON-NLS-1$\n\t\t\tif (k != -1) {\n\t\t\t\tresult = rawList.substring(k + 5, i + bundleFile.length());\n\t\t\t} else {\n\t\t\t\tresult = rawList.substring(j + 1, i + bundleFile.length());\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Parse install with the specified raw install parameter and return the String result.\n\t * @param rawInstall\tThe raw install (<code>String</code>) parameter.\n\t * @return\tResults of the parse install (<code>String</code>) value.\n\t */\n\tprivate String parseInstall(final String rawInstall) {\n\t\tString result;\n\t\tint i = rawInstall.indexOf(\"file:\"); //$NON-NLS-1$\n\t\tresult = rawInstall.substring(i + 5);\n\t\tif (result.startsWith(\"/\")) { //$NON-NLS-1$\n\t\t\tresult = result.substring(1);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Parse loc with the specified raw loc parameter and return the String result.\n\t * @param rawLoc\tThe raw loc (<code>String</code>) parameter.\n\t * @return\tResults of the parse loc (<code>String</code>) value.\n\t */\n\tprivate String parseLoc(final String rawLoc) {\n\t\tString result;\n\t\tint i = rawLoc.indexOf(\"file:\"); //$NON-NLS-1$\n\t\tresult = rawLoc.substring(i + 5);\n\t\tif (rawLoc.endsWith(\"/\")) { //$NON-NLS-1$\n\t\t\tresult = result.substring(0, result.length() - 1);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Start with the specified arg0 parameter.\n\t * @param arg0\tThe arg0 (<code>BundleContext</code>) parameter.\n\t * @throws Exception Exception.\n\t */\n\tpublic void start(final BundleContext arg0) throws Exception {\n\t\t/*\n\t\tString bundle_loc = arg0.getBundle().getLocation();\n\t\tif (bundle_loc.startsWith(Library.HTTP)) {\n\t\t\tLibrary.setBundlepath(Library.HTTP, bundle_loc);\n\t\t} else {\n\t\t\tString bundle_file_name = parseLoc(bundle_loc);\n\t\t\tString bundle_install = parseInstall(System.getProperty(\"osgi.install.area\")); //$NON-NLS-1$\n\t\t\tString bundle_path = parseBundleList(System.getProperty(\"osgi.bundles\"), bundle_file_name); //$NON-NLS-1$\n\t\t\tif (bundle_path == null || bundle_path.length() == bundle_file_name.length()) {\n\t\t\t\tbundle_path = bundle_install + bundle_file_name;\n\t\t\t}\n\t\t\t/*\n\t\t\t System.out.println(\"bundle=\" + bundle_file_name);\n\t\t\t System.out.println(\"bundle_install=\" + bundle_install);\n\t\t\t System.out.println(\"bundle_path=\" + bundle_path);\t\t\t\n\t\t\t \n\t\t\tLibrary.setBundlepath(Library.FILE, bundle_path);\n\t\t}\n\t*/\n\t}\n\n\t/**\n\t * Stop with the specified arg0 parameter.\n\t * @param arg0\tThe arg0 (<code>BundleContext</code>) parameter.\n\t * @throws Exception Exception.\n\t */\n\tpublic void stop(final BundleContext arg0) throws Exception {\n\t\t/* do nothing */\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/bundle/package.html",
    "content": "<!DOCTYPE html PUBLIC \"..//W3C/DTD XHTML 1.0 Strict/EN\"  DTD/xhtml-strict.dtd\">\n<!-- Copyright (c) 2008, 2009 IBM.                                         -->\n<!-- All rights reserved. This program and the accompanying materials      -->\n<!-- are made available under the terms of the Eclipse Public License v1.0 -->\n<!-- which accompanies this distribution, and is available at              -->\n<!-- http://www.eclipse.org/legal/epl-v10.html                             -->\n<!--                                                                       -->\n<!-- Contributors:                                                         -->\n<!--     IBM - initial API and implementation                              -->\n    \n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\t<head>\n\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n\t\t<meta name=\"Security\" content=\"public\"/>\n\t\t<meta name=\"Copyright\" content=\"Copyright (c) 2009 IBM. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page.\"/>\n\t\t<meta scheme=\"rfc1766\" name=\"DC.Language\" content=\"en-us\"/>\n\t\t<meta name=\"Keywords\" content=\"org.eclipse.soda.dk.comm.bundle, org.eclipse.soda.dk.comm\"/>\n\t\t<link rel=\"STYLESHEET\" href=\"stylesheet.css\" charset=\"UTF-8\" type=\"text/css\"/>\t\t\n\t\t<title>org.eclipse.soda.dk.comm.bundle Package</title>\n\t</head>\n\t<body>\n\t\t<p>This package is part of the org.eclipse.soda.dk.comm project.</p> \n\t</body>\n</html>\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/internal/Library.java",
    "content": "package org.eclipse.soda.dk.comm.internal;\n\n/*************************************************************************\n * Copyright (c) 2007, 2009 IBM.                                         *\n * All rights reserved. This program and the accompanying materials      *\n * are made available under the terms of the Eclipse Public License v1.0 *\n * which accompanies this distribution, and is available at              *\n * http://www.eclipse.org/legal/epl-v10.html                             *\n *                                                                       *\n * Contributors:                                                         *\n *     IBM - initial API and implementation                              *\n ************************************************************************/\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.util.zip.ZipFile;\nimport java.util.zip.ZipInputStream;\n\n/**\n * @author IBM\n * @version 1.2.0\n * @since 1.0\n */\npublic class Library {\n\t/**\n\t * Define the http (String) constant.\n\t */\n\tpublic static final String HTTP = \"http\"; //$NON-NLS-1$\n\n\t/**\n\t * Define the file (String) constant.\n\t */\n\tpublic static final String FILE = \"file\"; //$NON-NLS-1$\n\n\t/**\n\t * Define the pathtype (String) field.\n\t */\n\tprivate static String pathtype = \"\"; //$NON-NLS-1$\n\n\t/**\n\t * Define the bundlepath (String) field.\n\t */\n\tprivate static String bundlepath = \"\"; //$NON-NLS-1$\n\n\t/**\n\t * Load_dkcomm.\n\t */\n\tpublic static void load_dkcomm() {\n\t\tif (load_from_java_lib_path() == false) {\n\t\t\t// To remain portable across OSGI implementations, Kura will only load from lib path\n\t\t\t//load_from_bundle();\n\t\t}\n\t}\n\n\t/**\n\t * Load_from_bundle.\n\t */\n\tprivate static void load_from_bundle() {\n\t\tString file_separator = System.getProperty(\"file.separator\"); //$NON-NLS-1$\n\t\tString javalibpath = System.getProperty(\"java.library.path\"); //$NON-NLS-1$\n\t\tString path_seperator = System.getProperty(\"path.separator\"); //$NON-NLS-1$\n\t\tint i = javalibpath.indexOf(path_seperator);\n\t\tjavalibpath = javalibpath.substring(0, i) + file_separator;\n\t\tString os = System.getProperty(\"osgi.ws\"); //$NON-NLS-1$\n\t\tString processor = System.getProperty(\"org.osgi.framework.processor\"); //$NON-NLS-1$\n\t\tString libname = \"\"; //$NON-NLS-1$\n\t\tif (os.equalsIgnoreCase(\"win32\")) { //$NON-NLS-1$\n\t\t\tlibname = \"dkcomm.dll\"; //$NON-NLS-1$\n\t\t} else if (os.equalsIgnoreCase(\"linux\")) { //$NON-NLS-1$\n\t\t\tlibname = \"dkcomm.so\"; //$NON-NLS-1$\n\t\t}\n\t\tString libpath = \"lib/\" + os + '/' + processor + '/'; //$NON-NLS-1$\n\t\ttry {\n\t\t\tif (pathtype.equals(FILE)) {\n\t\t\t\tunzipLib_local(javalibpath, libpath, libname, bundlepath);\n\t\t\t} else if (pathtype.equals(HTTP)) {\n\t\t\t\tunzipLib_http(javalibpath, libpath, libname, bundlepath);\n\t\t\t}\n\t\t} catch (final IOException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\ttry {\n\t\t\tSystem.load(javalibpath + libname);\n\t\t} catch (java.lang.UnsatisfiedLinkError e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n\n\t/**\n\t * Load_from_java_lib_path and return the boolean result.\n\t * @return Results of the load_from_java_lib_path (<code>boolean</code>) value.\n\t */\n\tprivate static boolean load_from_java_lib_path() {\n\t\ttry {\n\t\t\tSystem.loadLibrary(\"dkcomm\"); //$NON-NLS-1$\n\t\t} catch (final UnsatisfiedLinkError e) {\n\t\t\te.printStackTrace();\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Perform unzip with the specified input and output parameters.\n\t * @param input\n\t *\t\tThe input (<code>BufferedInputStream</code>) parameter.\n\t * @param output\n\t *\t\tThe output (<code>BufferedOutputStream</code>) parameter.\n\t * @throws IOException IOException.\n\t */\n\tprivate static void performUnzip(final BufferedInputStream input, final BufferedOutputStream output) throws IOException {\n\t\tint block_size = 4000;\n\t\tbyte[] block = new byte[block_size];\n\t\tint len = input.read(block, 0, block_size);\n\t\twhile (len != -1) {\n\t\t\toutput.write(block, 0, len);\n\t\t\tlen = input.read(block, 0, block_size);\n\t\t}\n\t\toutput.flush();\n\t\tinput.close();\n\t\toutput.close();\n\t}\n\n\t/**\n\t * Set bundlepath with the specified type and path parameters.\n\t * @param type\n\t *\t\tThe type (<code>String</code>) parameter.\n\t * @param path\n\t *\t\tThe path (<code>String</code>) parameter.\n\t */\n\tpublic static void setBundlepath(final String type, final String path) {\n\t\tpathtype = type;\n\t\tbundlepath = path;\n\t}\n\n\t/**\n\t * Unzip lib_http with the specified javalibpath, libpath, libname and url parameters.\n\t * @param javalibpath\n\t *\t\tThe javalibpath (<code>String</code>) parameter.\n\t * @param libpath\n\t *\t\tThe libpath (<code>String</code>) parameter.\n\t * @param libname\n\t *\t\tThe libname (<code>String</code>) parameter.\n\t * @param url\n\t *\t\tThe URL (<code>String</code>) parameter.\n\t * @throws IOException IOException.\n\t */\n\tprivate static void unzipLib_http(final String javalibpath, final String libpath, final String libname, final String url) throws IOException {\n\t\tZipInputStream zipInput = new ZipInputStream(new URL(url).openStream());\n\t\twhile (zipInput.available() != 0) {\n\t\t\ttry {\n\t\t\t\tif (zipInput.getNextEntry().getName().equals(libpath + libname)) {\n\t\t\t\t\tBufferedInputStream input = new BufferedInputStream(zipInput);\n\t\t\t\t\tBufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(javalibpath + libname));\n\t\t\t\t\tperformUnzip(input, output);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} catch (final Exception e) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Unzip lib_local with the specified javalibpath, libpath, libname and jarname parameters.\n\t * @param javalibpath\n\t *\t\tThe javalibpath (<code>String</code>) parameter.\n\t * @param libpath\n\t *\t\tThe libpath (<code>String</code>) parameter.\n\t * @param libname\n\t *\t\tThe libname (<code>String</code>) parameter.\n\t * @param jarname\n\t *\t\tThe jarname (<code>String</code>) parameter.\n\t * @throws IOException IOException.\n\t */\n\tprivate static void unzipLib_local(final String javalibpath, final String libpath, final String libname, final String jarname) throws IOException {\n\t\tZipFile bundleJar = new ZipFile(jarname);\n\t\tBufferedInputStream input = new BufferedInputStream(bundleJar.getInputStream(bundleJar.getEntry(libpath + libname)));\n\t\tBufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(javalibpath + libname));\n\t\tperformUnzip(input, output);\n\t}\n}\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/internal/package.html",
    "content": "<!DOCTYPE html PUBLIC \"..//W3C/DTD XHTML 1.0 Strict/EN\"  DTD/xhtml-strict.dtd\">\n<!-- Copyright (c) 2008, 2009 IBM.                                         -->\n<!-- All rights reserved. This program and the accompanying materials      -->\n<!-- are made available under the terms of the Eclipse Public License v1.0 -->\n<!-- which accompanies this distribution, and is available at              -->\n<!-- http://www.eclipse.org/legal/epl-v10.html                             -->\n<!--                                                                       -->\n<!-- Contributors:                                                         -->\n<!--     IBM - initial API and implementation                              -->\n    \n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\t<head>\n\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n\t\t<meta name=\"Security\" content=\"public\"/>\n\t\t<meta name=\"Copyright\" content=\"Copyright (c) 2009 IBM. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page.\"/>\n\t\t<meta scheme=\"rfc1766\" name=\"DC.Language\" content=\"en-us\"/>\n\t\t<meta name=\"Keywords\" content=\"org.eclipse.soda.dk.comm.internal, org.eclipse.soda.dk.comm\"/>\n\t\t<link rel=\"STYLESHEET\" href=\"stylesheet.css\" charset=\"UTF-8\" type=\"text/css\"/>\t\t\n\t\t<title>org.eclipse.soda.dk.comm.internal Package</title>\n\t</head>\n\t<body>\n\t\t<p>This package is part of the org.eclipse.soda.dk.comm project.</p> \n\t</body>\n</html>\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm/src/main/java/org/eclipse/soda/dk/comm/package.html",
    "content": "<!DOCTYPE html PUBLIC \"..//W3C/DTD XHTML 1.0 Strict/EN\"  DTD/xhtml-strict.dtd\">\n<!-- Copyright (c) 2008, 2009 IBM.                                         -->\n<!-- All rights reserved. This program and the accompanying materials      -->\n<!-- are made available under the terms of the Eclipse Public License v1.0 -->\n<!-- which accompanies this distribution, and is available at              -->\n<!-- http://www.eclipse.org/legal/epl-v10.html                             -->\n<!--                                                                       -->\n<!-- Contributors:                                                         -->\n<!--     IBM - initial API and implementation                              -->\n    \n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\t<head>\n\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n\t\t<meta name=\"Security\" content=\"public\"/>\n\t\t<meta name=\"Copyright\" content=\"Copyright (c) 2009 IBM. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page.\"/>\n\t\t<meta scheme=\"rfc1766\" name=\"DC.Language\" content=\"en-us\"/>\n\t\t<meta name=\"Keywords\" content=\"org.eclipse.soda.dk.comm, org.eclipse.soda.dk.comm\"/>\n\t\t<link rel=\"STYLESHEET\" href=\"stylesheet.css\" charset=\"UTF-8\" type=\"text/css\"/>\t\t\n\t\t<title>org.eclipse.soda.dk.comm Package</title>\n\t</head>\n\t<body>\n\t\t<p>This package is part of the org.eclipse.soda.dk.comm project.</p> \n\t</body>\n</html>\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.aarch64/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.aarch64/about_files/epl-v10.html",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n<title>Eclipse Public License - Version 1.0</title>\n<style type=\"text/css\">\n  body {\n    size: 8.5in 11.0in;\n    margin: 0.25in 0.5in 0.25in 0.5in;\n    tab-interval: 0.5in;\n    }\n  p {  \t\n    margin-left: auto;\n    margin-top:  0.5em;\n    margin-bottom: 0.5em;\n    }\n  p.list {\n  \tmargin-left: 0.5in;\n    margin-top:  0.05em;\n    margin-bottom: 0.05em;\n    }\n  </style>\n\n</head>\n\n<body lang=\"EN-US\">\n\n<h2>Eclipse Public License - v 1.0</h2>\n\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\nPUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR\nDISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS\nAGREEMENT.</p>\n\n<p><b>1. DEFINITIONS</b></p>\n\n<p>&quot;Contribution&quot; means:</p>\n\n<p class=\"list\">a) in the case of the initial Contributor, the initial\ncode and documentation distributed under this Agreement, and</p>\n<p class=\"list\">b) in the case of each subsequent Contributor:</p>\n<p class=\"list\">i) changes to the Program, and</p>\n<p class=\"list\">ii) additions to the Program;</p>\n<p class=\"list\">where such changes and/or additions to the Program\noriginate from and are distributed by that particular Contributor. A\nContribution 'originates' from a Contributor if it was added to the\nProgram by such Contributor itself or anyone acting on such\nContributor's behalf. Contributions do not include additions to the\nProgram which: (i) are separate modules of software distributed in\nconjunction with the Program under their own license agreement, and (ii)\nare not derivative works of the Program.</p>\n\n<p>&quot;Contributor&quot; means any person or entity that distributes\nthe Program.</p>\n\n<p>&quot;Licensed Patents&quot; mean patent claims licensable by a\nContributor which are necessarily infringed by the use or sale of its\nContribution alone or when combined with the Program.</p>\n\n<p>&quot;Program&quot; means the Contributions distributed in accordance\nwith this Agreement.</p>\n\n<p>&quot;Recipient&quot; means anyone who receives the Program under\nthis Agreement, including all Contributors.</p>\n\n<p><b>2. GRANT OF RIGHTS</b></p>\n\n<p class=\"list\">a) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free copyright license to reproduce, prepare derivative works\nof, publicly display, publicly perform, distribute and sublicense the\nContribution of such Contributor, if any, and such derivative works, in\nsource code and object code form.</p>\n\n<p class=\"list\">b) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free patent license under Licensed Patents to make, use, sell,\noffer to sell, import and otherwise transfer the Contribution of such\nContributor, if any, in source code and object code form. This patent\nlicense shall apply to the combination of the Contribution and the\nProgram if, at the time the Contribution is added by the Contributor,\nsuch addition of the Contribution causes such combination to be covered\nby the Licensed Patents. The patent license shall not apply to any other\ncombinations which include the Contribution. No hardware per se is\nlicensed hereunder.</p>\n\n<p class=\"list\">c) Recipient understands that although each Contributor\ngrants the licenses to its Contributions set forth herein, no assurances\nare provided by any Contributor that the Program does not infringe the\npatent or other intellectual property rights of any other entity. Each\nContributor disclaims any liability to Recipient for claims brought by\nany other entity based on infringement of intellectual property rights\nor otherwise. As a condition to exercising the rights and licenses\ngranted hereunder, each Recipient hereby assumes sole responsibility to\nsecure any other intellectual property rights needed, if any. For\nexample, if a third party patent license is required to allow Recipient\nto distribute the Program, it is Recipient's responsibility to acquire\nthat license before distributing the Program.</p>\n\n<p class=\"list\">d) Each Contributor represents that to its knowledge it\nhas sufficient copyright rights in its Contribution, if any, to grant\nthe copyright license set forth in this Agreement.</p>\n\n<p><b>3. REQUIREMENTS</b></p>\n\n<p>A Contributor may choose to distribute the Program in object code\nform under its own license agreement, provided that:</p>\n\n<p class=\"list\">a) it complies with the terms and conditions of this\nAgreement; and</p>\n\n<p class=\"list\">b) its license agreement:</p>\n\n<p class=\"list\">i) effectively disclaims on behalf of all Contributors\nall warranties and conditions, express and implied, including warranties\nor conditions of title and non-infringement, and implied warranties or\nconditions of merchantability and fitness for a particular purpose;</p>\n\n<p class=\"list\">ii) effectively excludes on behalf of all Contributors\nall liability for damages, including direct, indirect, special,\nincidental and consequential damages, such as lost profits;</p>\n\n<p class=\"list\">iii) states that any provisions which differ from this\nAgreement are offered by that Contributor alone and not by any other\nparty; and</p>\n\n<p class=\"list\">iv) states that source code for the Program is available\nfrom such Contributor, and informs licensees how to obtain it in a\nreasonable manner on or through a medium customarily used for software\nexchange.</p>\n\n<p>When the Program is made available in source code form:</p>\n\n<p class=\"list\">a) it must be made available under this Agreement; and</p>\n\n<p class=\"list\">b) a copy of this Agreement must be included with each\ncopy of the Program.</p>\n\n<p>Contributors may not remove or alter any copyright notices contained\nwithin the Program.</p>\n\n<p>Each Contributor must identify itself as the originator of its\nContribution, if any, in a manner that reasonably allows subsequent\nRecipients to identify the originator of the Contribution.</p>\n\n<p><b>4. COMMERCIAL DISTRIBUTION</b></p>\n\n<p>Commercial distributors of software may accept certain\nresponsibilities with respect to end users, business partners and the\nlike. While this license is intended to facilitate the commercial use of\nthe Program, the Contributor who includes the Program in a commercial\nproduct offering should do so in a manner which does not create\npotential liability for other Contributors. Therefore, if a Contributor\nincludes the Program in a commercial product offering, such Contributor\n(&quot;Commercial Contributor&quot;) hereby agrees to defend and\nindemnify every other Contributor (&quot;Indemnified Contributor&quot;)\nagainst any losses, damages and costs (collectively &quot;Losses&quot;)\narising from claims, lawsuits and other legal actions brought by a third\nparty against the Indemnified Contributor to the extent caused by the\nacts or omissions of such Commercial Contributor in connection with its\ndistribution of the Program in a commercial product offering. The\nobligations in this section do not apply to any claims or Losses\nrelating to any actual or alleged intellectual property infringement. In\norder to qualify, an Indemnified Contributor must: a) promptly notify\nthe Commercial Contributor in writing of such claim, and b) allow the\nCommercial Contributor to control, and cooperate with the Commercial\nContributor in, the defense and any related settlement negotiations. The\nIndemnified Contributor may participate in any such claim at its own\nexpense.</p>\n\n<p>For example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those\nperformance claims and warranties, and if a court requires any other\nContributor to pay any damages as a result, the Commercial Contributor\nmust pay those damages.</p>\n\n<p><b>5. NO WARRANTY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS\nPROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS\nOF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,\nANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY\nOR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely\nresponsible for determining the appropriateness of using and\ndistributing the Program and assumes all risks associated with its\nexercise of rights under this Agreement , including but not limited to\nthe risks and costs of program errors, compliance with applicable laws,\ndamage to or loss of data, programs or equipment, and unavailability or\ninterruption of operations.</p>\n\n<p><b>6. DISCLAIMER OF LIABILITY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT\nNOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING\nWITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR\nDISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED\nHEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>\n\n<p><b>7. GENERAL</b></p>\n\n<p>If any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further action\nby the parties hereto, such provision shall be reformed to the minimum\nextent necessary to make such provision valid and enforceable.</p>\n\n<p>If Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other\nsoftware or hardware) infringes such Recipient's patent(s), then such\nRecipient's rights granted under Section 2(b) shall terminate as of the\ndate such litigation is filed.</p>\n\n<p>All Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of time\nafter becoming aware of such noncompliance. If all Recipient's rights\nunder this Agreement terminate, Recipient agrees to cease use and\ndistribution of the Program as soon as reasonably practicable. However,\nRecipient's obligations under this Agreement and any licenses granted by\nRecipient relating to the Program shall continue and survive.</p>\n\n<p>Everyone is permitted to copy and distribute copies of this\nAgreement, but in order to avoid inconsistency the Agreement is\ncopyrighted and may only be modified in the following manner. The\nAgreement Steward reserves the right to publish new versions (including\nrevisions) of this Agreement from time to time. No one other than the\nAgreement Steward has the right to modify this Agreement. The Eclipse\nFoundation is the initial Agreement Steward. The Eclipse Foundation may\nassign the responsibility to serve as the Agreement Steward to a\nsuitable separate entity. Each new version of the Agreement will be\ngiven a distinguishing version number. The Program (including\nContributions) may always be distributed subject to the version of the\nAgreement under which it was received. In addition, after a new version\nof the Agreement is published, Contributor may elect to distribute the\nProgram (including its Contributions) under the new version. Except as\nexpressly stated in Sections 2(a) and 2(b) above, Recipient receives no\nrights or licenses to the intellectual property of any Contributor under\nthis Agreement, whether expressly, by implication, estoppel or\notherwise. All rights in the Program not expressly granted under this\nAgreement are reserved.</p>\n\n<p>This Agreement is governed by the laws of the State of New York and\nthe intellectual property laws of the United States of America. No party\nto this Agreement will bring a legal action under this Agreement more\nthan one year after the cause of action arose. Each party waives its\nrights to a jury trial in any resulting litigation.</p>\n\n</body>\n\n</html>"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.aarch64/build.properties",
    "content": "#########################################################################\n# Copyright (c) 2006, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nadditional.bundles=org.eclipse.osgi,org.eclipse.osgi.services\nbin.includes=.,META-INF/,copyright.txt,lib/,OSGI-INF/,OSGI-INF/l10n/,about.html\noutput..=bin/\nsource..=src/\nsrc.includes=copyright.txt\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.aarch64/copyright.txt",
    "content": "Copyright (c) 1999, 2009 IBM.\nAll rights reserved. This program and the accompanying materials\nare made available under the terms of the Eclipse Public License v1.0\nwhich accompanies this distribution, and is available at\nhttp://www.eclipse.org/legal/epl-v10.html\n\nContributors:\n    IBM - initial API and implementation"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.aarch64/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n  \n    Contributors:\n     Eurotech\n     Cavium\n\n-->\n\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>org.eclipse.soda.dk.comm-parent</artifactId>\n        <version>2.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.soda.dk.comm.aarch64</artifactId>\n    <packaging>bundle</packaging>\n\n    <name>Native libraries for 'org.eclipse.soda.dk.comm' on ARM 64 bits</name>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>${maven-surefire-plugin.version}</version>\n                <configuration>\n                    <systemPropertyVariables>\n                        <java.library.path>${project.basedir}/src/main/lib/linux</java.library.path>\n                    </systemPropertyVariables>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>${maven-bundle-plugin.version}</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Name>%bundle.name</Bundle-Name>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Bundle-Vendor>%bundle.vendor</Bundle-Vendor>\n                        <Bundle-Copyright>%bundle.copyright</Bundle-Copyright>\n                        <Include-Resource>\n                            lib=${project.basedir}/src/main/lib/linux,\n                            ${project.basedir}/about.html,\n                            about_files=${project.basedir}/about_files/\n                        </Include-Resource>\n                        <Bundle-NativeCode>\n                            lib/libdkcomm.so; osname=Linux; processor=aarch64\n                        </Bundle-NativeCode>\n                        <Fragment-Host>org.eclipse.soda.dk.comm;bundle-version=\"[2.0.0,3.0.0)\"</Fragment-Host>\n                    </instructions>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>${maven-dependency-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n        </plugins>\n        <pluginManagement>\n            <plugins>\n        \t\t<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>${lifecycle-mapping.version}</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.apache.maven.plugins\n                                        </groupId>\n                                        <artifactId>\n                                            maven-dependency-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [2.1,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>\n                                                copy-dependencies\n                                            </goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.x86_64/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.x86_64/about_files/epl-v10.html",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n<title>Eclipse Public License - Version 1.0</title>\n<style type=\"text/css\">\n  body {\n    size: 8.5in 11.0in;\n    margin: 0.25in 0.5in 0.25in 0.5in;\n    tab-interval: 0.5in;\n    }\n  p {  \t\n    margin-left: auto;\n    margin-top:  0.5em;\n    margin-bottom: 0.5em;\n    }\n  p.list {\n  \tmargin-left: 0.5in;\n    margin-top:  0.05em;\n    margin-bottom: 0.05em;\n    }\n  </style>\n\n</head>\n\n<body lang=\"EN-US\">\n\n<h2>Eclipse Public License - v 1.0</h2>\n\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\nPUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE, REPRODUCTION OR\nDISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS\nAGREEMENT.</p>\n\n<p><b>1. DEFINITIONS</b></p>\n\n<p>&quot;Contribution&quot; means:</p>\n\n<p class=\"list\">a) in the case of the initial Contributor, the initial\ncode and documentation distributed under this Agreement, and</p>\n<p class=\"list\">b) in the case of each subsequent Contributor:</p>\n<p class=\"list\">i) changes to the Program, and</p>\n<p class=\"list\">ii) additions to the Program;</p>\n<p class=\"list\">where such changes and/or additions to the Program\noriginate from and are distributed by that particular Contributor. A\nContribution 'originates' from a Contributor if it was added to the\nProgram by such Contributor itself or anyone acting on such\nContributor's behalf. Contributions do not include additions to the\nProgram which: (i) are separate modules of software distributed in\nconjunction with the Program under their own license agreement, and (ii)\nare not derivative works of the Program.</p>\n\n<p>&quot;Contributor&quot; means any person or entity that distributes\nthe Program.</p>\n\n<p>&quot;Licensed Patents&quot; mean patent claims licensable by a\nContributor which are necessarily infringed by the use or sale of its\nContribution alone or when combined with the Program.</p>\n\n<p>&quot;Program&quot; means the Contributions distributed in accordance\nwith this Agreement.</p>\n\n<p>&quot;Recipient&quot; means anyone who receives the Program under\nthis Agreement, including all Contributors.</p>\n\n<p><b>2. GRANT OF RIGHTS</b></p>\n\n<p class=\"list\">a) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free copyright license to reproduce, prepare derivative works\nof, publicly display, publicly perform, distribute and sublicense the\nContribution of such Contributor, if any, and such derivative works, in\nsource code and object code form.</p>\n\n<p class=\"list\">b) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free patent license under Licensed Patents to make, use, sell,\noffer to sell, import and otherwise transfer the Contribution of such\nContributor, if any, in source code and object code form. This patent\nlicense shall apply to the combination of the Contribution and the\nProgram if, at the time the Contribution is added by the Contributor,\nsuch addition of the Contribution causes such combination to be covered\nby the Licensed Patents. The patent license shall not apply to any other\ncombinations which include the Contribution. No hardware per se is\nlicensed hereunder.</p>\n\n<p class=\"list\">c) Recipient understands that although each Contributor\ngrants the licenses to its Contributions set forth herein, no assurances\nare provided by any Contributor that the Program does not infringe the\npatent or other intellectual property rights of any other entity. Each\nContributor disclaims any liability to Recipient for claims brought by\nany other entity based on infringement of intellectual property rights\nor otherwise. As a condition to exercising the rights and licenses\ngranted hereunder, each Recipient hereby assumes sole responsibility to\nsecure any other intellectual property rights needed, if any. For\nexample, if a third party patent license is required to allow Recipient\nto distribute the Program, it is Recipient's responsibility to acquire\nthat license before distributing the Program.</p>\n\n<p class=\"list\">d) Each Contributor represents that to its knowledge it\nhas sufficient copyright rights in its Contribution, if any, to grant\nthe copyright license set forth in this Agreement.</p>\n\n<p><b>3. REQUIREMENTS</b></p>\n\n<p>A Contributor may choose to distribute the Program in object code\nform under its own license agreement, provided that:</p>\n\n<p class=\"list\">a) it complies with the terms and conditions of this\nAgreement; and</p>\n\n<p class=\"list\">b) its license agreement:</p>\n\n<p class=\"list\">i) effectively disclaims on behalf of all Contributors\nall warranties and conditions, express and implied, including warranties\nor conditions of title and non-infringement, and implied warranties or\nconditions of merchantability and fitness for a particular purpose;</p>\n\n<p class=\"list\">ii) effectively excludes on behalf of all Contributors\nall liability for damages, including direct, indirect, special,\nincidental and consequential damages, such as lost profits;</p>\n\n<p class=\"list\">iii) states that any provisions which differ from this\nAgreement are offered by that Contributor alone and not by any other\nparty; and</p>\n\n<p class=\"list\">iv) states that source code for the Program is available\nfrom such Contributor, and informs licensees how to obtain it in a\nreasonable manner on or through a medium customarily used for software\nexchange.</p>\n\n<p>When the Program is made available in source code form:</p>\n\n<p class=\"list\">a) it must be made available under this Agreement; and</p>\n\n<p class=\"list\">b) a copy of this Agreement must be included with each\ncopy of the Program.</p>\n\n<p>Contributors may not remove or alter any copyright notices contained\nwithin the Program.</p>\n\n<p>Each Contributor must identify itself as the originator of its\nContribution, if any, in a manner that reasonably allows subsequent\nRecipients to identify the originator of the Contribution.</p>\n\n<p><b>4. COMMERCIAL DISTRIBUTION</b></p>\n\n<p>Commercial distributors of software may accept certain\nresponsibilities with respect to end users, business partners and the\nlike. While this license is intended to facilitate the commercial use of\nthe Program, the Contributor who includes the Program in a commercial\nproduct offering should do so in a manner which does not create\npotential liability for other Contributors. Therefore, if a Contributor\nincludes the Program in a commercial product offering, such Contributor\n(&quot;Commercial Contributor&quot;) hereby agrees to defend and\nindemnify every other Contributor (&quot;Indemnified Contributor&quot;)\nagainst any losses, damages and costs (collectively &quot;Losses&quot;)\narising from claims, lawsuits and other legal actions brought by a third\nparty against the Indemnified Contributor to the extent caused by the\nacts or omissions of such Commercial Contributor in connection with its\ndistribution of the Program in a commercial product offering. The\nobligations in this section do not apply to any claims or Losses\nrelating to any actual or alleged intellectual property infringement. In\norder to qualify, an Indemnified Contributor must: a) promptly notify\nthe Commercial Contributor in writing of such claim, and b) allow the\nCommercial Contributor to control, and cooperate with the Commercial\nContributor in, the defense and any related settlement negotiations. The\nIndemnified Contributor may participate in any such claim at its own\nexpense.</p>\n\n<p>For example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those\nperformance claims and warranties, and if a court requires any other\nContributor to pay any damages as a result, the Commercial Contributor\nmust pay those damages.</p>\n\n<p><b>5. NO WARRANTY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS\nPROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS\nOF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,\nANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY\nOR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely\nresponsible for determining the appropriateness of using and\ndistributing the Program and assumes all risks associated with its\nexercise of rights under this Agreement , including but not limited to\nthe risks and costs of program errors, compliance with applicable laws,\ndamage to or loss of data, programs or equipment, and unavailability or\ninterruption of operations.</p>\n\n<p><b>6. DISCLAIMER OF LIABILITY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT\nNOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING\nWITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR\nDISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED\nHEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>\n\n<p><b>7. GENERAL</b></p>\n\n<p>If any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further action\nby the parties hereto, such provision shall be reformed to the minimum\nextent necessary to make such provision valid and enforceable.</p>\n\n<p>If Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other\nsoftware or hardware) infringes such Recipient's patent(s), then such\nRecipient's rights granted under Section 2(b) shall terminate as of the\ndate such litigation is filed.</p>\n\n<p>All Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of time\nafter becoming aware of such noncompliance. If all Recipient's rights\nunder this Agreement terminate, Recipient agrees to cease use and\ndistribution of the Program as soon as reasonably practicable. However,\nRecipient's obligations under this Agreement and any licenses granted by\nRecipient relating to the Program shall continue and survive.</p>\n\n<p>Everyone is permitted to copy and distribute copies of this\nAgreement, but in order to avoid inconsistency the Agreement is\ncopyrighted and may only be modified in the following manner. The\nAgreement Steward reserves the right to publish new versions (including\nrevisions) of this Agreement from time to time. No one other than the\nAgreement Steward has the right to modify this Agreement. The Eclipse\nFoundation is the initial Agreement Steward. The Eclipse Foundation may\nassign the responsibility to serve as the Agreement Steward to a\nsuitable separate entity. Each new version of the Agreement will be\ngiven a distinguishing version number. The Program (including\nContributions) may always be distributed subject to the version of the\nAgreement under which it was received. In addition, after a new version\nof the Agreement is published, Contributor may elect to distribute the\nProgram (including its Contributions) under the new version. Except as\nexpressly stated in Sections 2(a) and 2(b) above, Recipient receives no\nrights or licenses to the intellectual property of any Contributor under\nthis Agreement, whether expressly, by implication, estoppel or\notherwise. All rights in the Program not expressly granted under this\nAgreement are reserved.</p>\n\n<p>This Agreement is governed by the laws of the State of New York and\nthe intellectual property laws of the United States of America. No party\nto this Agreement will bring a legal action under this Agreement more\nthan one year after the cause of action arose. Each party waives its\nrights to a jury trial in any resulting litigation.</p>\n\n</body>\n\n</html>"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.x86_64/build.properties",
    "content": "#########################################################################\n# Copyright (c) 2006, 2009 IBM.                                         #\n# All rights reserved. This program and the accompanying materials      #\n# are made available under the terms of the Eclipse Public License v1.0 #\n# which accompanies this distribution, and is available at              #\n# http://www.eclipse.org/legal/epl-v10.html                             #\n#                                                                       #\n# Contributors:                                                         #\n#     IBM - initial API and implementation                              #\n#########################################################################\nadditional.bundles=org.eclipse.osgi,org.eclipse.osgi.services\nbin.includes=.,META-INF/,copyright.txt,lib/,OSGI-INF/,OSGI-INF/l10n/,about.html\noutput..=bin/\nsource..=src/\nsrc.includes=copyright.txt\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.x86_64/copyright.txt",
    "content": "Copyright (c) 1999, 2009 IBM.\nAll rights reserved. This program and the accompanying materials\nare made available under the terms of the Eclipse Public License v1.0\nwhich accompanies this distribution, and is available at\nhttp://www.eclipse.org/legal/epl-v10.html\n\nContributors:\n    IBM - initial API and implementation"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/org.eclipse.soda.dk.comm.x86_64/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n    \n    SPDX-License-Identifier: EPL-2.0\n  \n    Contributors:\n     Eurotech\n \n-->\n\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>org.eclipse.soda.dk.comm-parent</artifactId>\n        <version>2.0.0-SNAPSHOT</version>\n    </parent>\n\n    <artifactId>org.eclipse.soda.dk.comm.x86_64</artifactId>\n    <packaging>bundle</packaging>\n\n    <name>Native libraries for 'org.eclipse.soda.dk.comm' on x86_64</name>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-surefire-plugin</artifactId>\n                <version>${maven-surefire-plugin.version}</version>\n                <configuration>\n                    <systemPropertyVariables>\n                        <java.library.path>${project.basedir}/src/main/lib/linux</java.library.path>\n                    </systemPropertyVariables>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>${maven-bundle-plugin.version}</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Bundle-Activator>org.eclipse.soda.dk.comm.bundle.Activator</Bundle-Activator>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Name>%bundle.name</Bundle-Name>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Bundle-Vendor>%bundle.vendor</Bundle-Vendor>\n                        <Bundle-Copyright>%bundle.copyright</Bundle-Copyright>\n                        <Include-Resource>\n                            lib=${project.basedir}/src/main/lib/linux,\n                            ${project.basedir}/about.html,\n                            about_files=${project.basedir}/about_files/\n                        </Include-Resource>\n                        <Bundle-NativeCode>\n                            lib/libdkcomm.so; osname=Linux; processor=x86-64\n                        </Bundle-NativeCode>\n                        <Fragment-Host>org.eclipse.soda.dk.comm;bundle-version=\"[2.0.0,3.0.0)\"</Fragment-Host>\n                    </instructions>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <version>${maven-dependency-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n        </plugins>\n        <pluginManagement>\n            <plugins>\n        \t\t<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>${lifecycle-mapping.version}</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.apache.maven.plugins\n                                        </groupId>\n                                        <artifactId>\n                                            maven-dependency-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [2.1,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>\n                                                copy-dependencies\n                                            </goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/org.eclipse.soda.dk.comm-parent/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<!--\n\n    Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n \n    Contributors:\n     Eurotech\n     Cavium\n     \n-->\n\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>target-platform</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n        <relativePath>..</relativePath>\n    </parent>\n\n    <artifactId>org.eclipse.soda.dk.comm-parent</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>pom</packaging>\n\n    <modules>\n        <module>org.eclipse.soda.dk.comm</module>\n        <module>org.eclipse.soda.dk.comm.x86_64</module>\n        <module>org.eclipse.soda.dk.comm.aarch64</module>\n    </modules>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <build>\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.apache.felix</groupId>\n                    <artifactId>maven-bundle-plugin</artifactId>\n                    <version>${maven-bundle-plugin.version}</version>\n                    <extensions>true</extensions>\n                    <configuration>\n                        <instructions>\n                            <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                            <Require-Capability>\n                                osgi.ee;filter:=\"(&amp;(osgi.ee=JavaSE)(version=21))\"\n                            </Require-Capability>\n                        </instructions>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n\n        <plugins>\n        \t<plugin>\n         \t\t<groupId>org.apache.maven.plugins</groupId>\n         \t\t<artifactId>maven-checkstyle-plugin</artifactId>\n                <version>${maven-checkstyle-plugin.version}</version>\n         \t\t<configuration>\n         \t\t\t<skip>true</skip>\n         \t\t</configuration>\n         \t</plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>${maven-compiler-plugin.version}</version>\n                <configuration>\n                    <release>${maven.compiler.release}</release>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n</project>\n"
  },
  {
    "path": "target-platform/org.moka7/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n\n\t\t<h3>Third Party Content</h3>\n\t\t<p>The Content includes items that have been sourced from third parties as set out below. If you\n\t\tdid not receive this Content directly from the Eclipse Foundation, the following is provided\n\t\tfor informational purposes only, and you should look to the Redistributor's license for\n\t\tterms and conditions of use.</p>\n\t\t<h4>Moka7 1.0.2</h4>\n\t\t<p>\n\t\tThis jar contains the Moka7 library version 1.0.2 (<a href=\"http://snap7.sourceforge.net/moka7.html\">http://snap7.sourceforge.net/moka7.html</a>) compiled from source without modification and repackaged as an OSGI bundle.\n\t\tMoka7 is developed by Davide Nardella.\n\t\t</p>\n\t\t<p>\n\t\tMoka7 1.0.2 is released in dual license form: it is available under the LGPL3 or EPL 1.0 licenses.\n    <br>\n\t\tEclipse Foundation elects to redistribute it under the EPL 1.0 License.\n\t\t<br>\n    The orginal License Files and License Information available in the distribution package (moka7-full-1.0.2.zip) are included in this jar under the about_files folder.\n    <br>\n\t\tThe source code for Moka7 1.0.2 is available at <a href=\"https://sourceforge.net/projects/snap7/files/Moka7/1.0.2/\">https://sourceforge.net/projects/snap7/files/Moka7/1.0.2/</a>.\n\t\t</p>\n</body>\n</html>\n"
  },
  {
    "path": "target-platform/org.moka7/about_files/Eclipse Public License - Version 1.0.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<!-- saved from url=(0046)https://eclipse.org/org/documents/epl-v10.html -->\n<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n\n<title>Eclipse Public License - Version 1.0</title>\n<style type=\"text/css\">\n  body {\n    size: 8.5in 11.0in;\n    margin: 0.25in 0.5in 0.25in 0.5in;\n    tab-interval: 0.5in;\n    }\n  p {  \t\n    margin-left: auto;\n    margin-top:  0.5em;\n    margin-bottom: 0.5em;\n    }\n  p.list {\n  \tmargin-left: 0.5in;\n    margin-top:  0.05em;\n    margin-bottom: 0.05em;\n    }\n  </style>\n\n</head>\n\n<body lang=\"EN-US\">\n\n<h2>Eclipse Public License - v 1.0</h2>\n\n<p>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE\nPUBLIC LICENSE (\"AGREEMENT\"). ANY USE, REPRODUCTION OR\nDISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS\nAGREEMENT.</p>\n\n<p><b>1. DEFINITIONS</b></p>\n\n<p>\"Contribution\" means:</p>\n\n<p class=\"list\">a) in the case of the initial Contributor, the initial\ncode and documentation distributed under this Agreement, and</p>\n<p class=\"list\">b) in the case of each subsequent Contributor:</p>\n<p class=\"list\">i) changes to the Program, and</p>\n<p class=\"list\">ii) additions to the Program;</p>\n<p class=\"list\">where such changes and/or additions to the Program\noriginate from and are distributed by that particular Contributor. A\nContribution 'originates' from a Contributor if it was added to the\nProgram by such Contributor itself or anyone acting on such\nContributor's behalf. Contributions do not include additions to the\nProgram which: (i) are separate modules of software distributed in\nconjunction with the Program under their own license agreement, and (ii)\nare not derivative works of the Program.</p>\n\n<p>\"Contributor\" means any person or entity that distributes\nthe Program.</p>\n\n<p>\"Licensed Patents\" mean patent claims licensable by a\nContributor which are necessarily infringed by the use or sale of its\nContribution alone or when combined with the Program.</p>\n\n<p>\"Program\" means the Contributions distributed in accordance\nwith this Agreement.</p>\n\n<p>\"Recipient\" means anyone who receives the Program under\nthis Agreement, including all Contributors.</p>\n\n<p><b>2. GRANT OF RIGHTS</b></p>\n\n<p class=\"list\">a) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free copyright license to reproduce, prepare derivative works\nof, publicly display, publicly perform, distribute and sublicense the\nContribution of such Contributor, if any, and such derivative works, in\nsource code and object code form.</p>\n\n<p class=\"list\">b) Subject to the terms of this Agreement, each\nContributor hereby grants Recipient a non-exclusive, worldwide,\nroyalty-free patent license under Licensed Patents to make, use, sell,\noffer to sell, import and otherwise transfer the Contribution of such\nContributor, if any, in source code and object code form. This patent\nlicense shall apply to the combination of the Contribution and the\nProgram if, at the time the Contribution is added by the Contributor,\nsuch addition of the Contribution causes such combination to be covered\nby the Licensed Patents. The patent license shall not apply to any other\ncombinations which include the Contribution. No hardware per se is\nlicensed hereunder.</p>\n\n<p class=\"list\">c) Recipient understands that although each Contributor\ngrants the licenses to its Contributions set forth herein, no assurances\nare provided by any Contributor that the Program does not infringe the\npatent or other intellectual property rights of any other entity. Each\nContributor disclaims any liability to Recipient for claims brought by\nany other entity based on infringement of intellectual property rights\nor otherwise. As a condition to exercising the rights and licenses\ngranted hereunder, each Recipient hereby assumes sole responsibility to\nsecure any other intellectual property rights needed, if any. For\nexample, if a third party patent license is required to allow Recipient\nto distribute the Program, it is Recipient's responsibility to acquire\nthat license before distributing the Program.</p>\n\n<p class=\"list\">d) Each Contributor represents that to its knowledge it\nhas sufficient copyright rights in its Contribution, if any, to grant\nthe copyright license set forth in this Agreement.</p>\n\n<p><b>3. REQUIREMENTS</b></p>\n\n<p>A Contributor may choose to distribute the Program in object code\nform under its own license agreement, provided that:</p>\n\n<p class=\"list\">a) it complies with the terms and conditions of this\nAgreement; and</p>\n\n<p class=\"list\">b) its license agreement:</p>\n\n<p class=\"list\">i) effectively disclaims on behalf of all Contributors\nall warranties and conditions, express and implied, including warranties\nor conditions of title and non-infringement, and implied warranties or\nconditions of merchantability and fitness for a particular purpose;</p>\n\n<p class=\"list\">ii) effectively excludes on behalf of all Contributors\nall liability for damages, including direct, indirect, special,\nincidental and consequential damages, such as lost profits;</p>\n\n<p class=\"list\">iii) states that any provisions which differ from this\nAgreement are offered by that Contributor alone and not by any other\nparty; and</p>\n\n<p class=\"list\">iv) states that source code for the Program is available\nfrom such Contributor, and informs licensees how to obtain it in a\nreasonable manner on or through a medium customarily used for software\nexchange.</p>\n\n<p>When the Program is made available in source code form:</p>\n\n<p class=\"list\">a) it must be made available under this Agreement; and</p>\n\n<p class=\"list\">b) a copy of this Agreement must be included with each\ncopy of the Program.</p>\n\n<p>Contributors may not remove or alter any copyright notices contained\nwithin the Program.</p>\n\n<p>Each Contributor must identify itself as the originator of its\nContribution, if any, in a manner that reasonably allows subsequent\nRecipients to identify the originator of the Contribution.</p>\n\n<p><b>4. COMMERCIAL DISTRIBUTION</b></p>\n\n<p>Commercial distributors of software may accept certain\nresponsibilities with respect to end users, business partners and the\nlike. While this license is intended to facilitate the commercial use of\nthe Program, the Contributor who includes the Program in a commercial\nproduct offering should do so in a manner which does not create\npotential liability for other Contributors. Therefore, if a Contributor\nincludes the Program in a commercial product offering, such Contributor\n(\"Commercial Contributor\") hereby agrees to defend and\nindemnify every other Contributor (\"Indemnified Contributor\")\nagainst any losses, damages and costs (collectively \"Losses\")\narising from claims, lawsuits and other legal actions brought by a third\nparty against the Indemnified Contributor to the extent caused by the\nacts or omissions of such Commercial Contributor in connection with its\ndistribution of the Program in a commercial product offering. The\nobligations in this section do not apply to any claims or Losses\nrelating to any actual or alleged intellectual property infringement. In\norder to qualify, an Indemnified Contributor must: a) promptly notify\nthe Commercial Contributor in writing of such claim, and b) allow the\nCommercial Contributor to control, and cooperate with the Commercial\nContributor in, the defense and any related settlement negotiations. The\nIndemnified Contributor may participate in any such claim at its own\nexpense.</p>\n\n<p>For example, a Contributor might include the Program in a commercial\nproduct offering, Product X. That Contributor is then a Commercial\nContributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance\nclaims and warranties are such Commercial Contributor's responsibility\nalone. Under this section, the Commercial Contributor would have to\ndefend claims against the other Contributors related to those\nperformance claims and warranties, and if a court requires any other\nContributor to pay any damages as a result, the Commercial Contributor\nmust pay those damages.</p>\n\n<p><b>5. NO WARRANTY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS\nPROVIDED ON AN \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS\nOF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,\nANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY\nOR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely\nresponsible for determining the appropriateness of using and\ndistributing the Program and assumes all risks associated with its\nexercise of rights under this Agreement , including but not limited to\nthe risks and costs of program errors, compliance with applicable laws,\ndamage to or loss of data, programs or equipment, and unavailability or\ninterruption of operations.</p>\n\n<p><b>6. DISCLAIMER OF LIABILITY</b></p>\n\n<p>EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT\nNOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING\nWITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF\nLIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR\nDISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED\nHEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</p>\n\n<p><b>7. GENERAL</b></p>\n\n<p>If any provision of this Agreement is invalid or unenforceable under\napplicable law, it shall not affect the validity or enforceability of\nthe remainder of the terms of this Agreement, and without further action\nby the parties hereto, such provision shall be reformed to the minimum\nextent necessary to make such provision valid and enforceable.</p>\n\n<p>If Recipient institutes patent litigation against any entity\n(including a cross-claim or counterclaim in a lawsuit) alleging that the\nProgram itself (excluding combinations of the Program with other\nsoftware or hardware) infringes such Recipient's patent(s), then such\nRecipient's rights granted under Section 2(b) shall terminate as of the\ndate such litigation is filed.</p>\n\n<p>All Recipient's rights under this Agreement shall terminate if it\nfails to comply with any of the material terms or conditions of this\nAgreement and does not cure such failure in a reasonable period of time\nafter becoming aware of such noncompliance. If all Recipient's rights\nunder this Agreement terminate, Recipient agrees to cease use and\ndistribution of the Program as soon as reasonably practicable. However,\nRecipient's obligations under this Agreement and any licenses granted by\nRecipient relating to the Program shall continue and survive.</p>\n\n<p>Everyone is permitted to copy and distribute copies of this\nAgreement, but in order to avoid inconsistency the Agreement is\ncopyrighted and may only be modified in the following manner. The\nAgreement Steward reserves the right to publish new versions (including\nrevisions) of this Agreement from time to time. No one other than the\nAgreement Steward has the right to modify this Agreement. The Eclipse\nFoundation is the initial Agreement Steward. The Eclipse Foundation may\nassign the responsibility to serve as the Agreement Steward to a\nsuitable separate entity. Each new version of the Agreement will be\ngiven a distinguishing version number. The Program (including\nContributions) may always be distributed subject to the version of the\nAgreement under which it was received. In addition, after a new version\nof the Agreement is published, Contributor may elect to distribute the\nProgram (including its Contributions) under the new version. Except as\nexpressly stated in Sections 2(a) and 2(b) above, Recipient receives no\nrights or licenses to the intellectual property of any Contributor under\nthis Agreement, whether expressly, by implication, estoppel or\notherwise. All rights in the Program not expressly granted under this\nAgreement are reserved.</p>\n\n<p>This Agreement is governed by the laws of the State of New York and\nthe intellectual property laws of the United States of America. No party\nto this Agreement will bring a legal action under this Agreement more\nthan one year after the cause of action arose. Each party waives its\nrights to a jury trial in any resulting litigation.</p>\n\n\n\n\n</body></html>"
  },
  {
    "path": "target-platform/org.moka7/about_files/Moka-License.txt",
    "content": "Moka7 starting from 1.0.2 is released under dual license : LGPL3 and EPL 1.0\nThe EPL and the GPL are not compatible, so you have to choose in advance which take before you import the library into your project."
  },
  {
    "path": "target-platform/org.moka7/about_files/gpl.txt",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "target-platform/org.moka7/about_files/lgpl-3.0.txt",
    "content": "                   GNU LESSER GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\n  This version of the GNU Lesser General Public License incorporates\nthe terms and conditions of version 3 of the GNU General Public\nLicense, supplemented by the additional permissions listed below.\n\n  0. Additional Definitions.\n\n  As used herein, \"this License\" refers to version 3 of the GNU Lesser\nGeneral Public License, and the \"GNU GPL\" refers to version 3 of the GNU\nGeneral Public License.\n\n  \"The Library\" refers to a covered work governed by this License,\nother than an Application or a Combined Work as defined below.\n\n  An \"Application\" is any work that makes use of an interface provided\nby the Library, but which is not otherwise based on the Library.\nDefining a subclass of a class defined by the Library is deemed a mode\nof using an interface provided by the Library.\n\n  A \"Combined Work\" is a work produced by combining or linking an\nApplication with the Library.  The particular version of the Library\nwith which the Combined Work was made is also called the \"Linked\nVersion\".\n\n  The \"Minimal Corresponding Source\" for a Combined Work means the\nCorresponding Source for the Combined Work, excluding any source code\nfor portions of the Combined Work that, considered in isolation, are\nbased on the Application, and not on the Linked Version.\n\n  The \"Corresponding Application Code\" for a Combined Work means the\nobject code and/or source code for the Application, including any data\nand utility programs needed for reproducing the Combined Work from the\nApplication, but excluding the System Libraries of the Combined Work.\n\n  1. Exception to Section 3 of the GNU GPL.\n\n  You may convey a covered work under sections 3 and 4 of this License\nwithout being bound by section 3 of the GNU GPL.\n\n  2. Conveying Modified Versions.\n\n  If you modify a copy of the Library, and, in your modifications, a\nfacility refers to a function or data to be supplied by an Application\nthat uses the facility (other than as an argument passed when the\nfacility is invoked), then you may convey a copy of the modified\nversion:\n\n   a) under this License, provided that you make a good faith effort to\n   ensure that, in the event an Application does not supply the\n   function or data, the facility still operates, and performs\n   whatever part of its purpose remains meaningful, or\n\n   b) under the GNU GPL, with none of the additional permissions of\n   this License applicable to that copy.\n\n  3. Object Code Incorporating Material from Library Header Files.\n\n  The object code form of an Application may incorporate material from\na header file that is part of the Library.  You may convey such object\ncode under terms of your choice, provided that, if the incorporated\nmaterial is not limited to numerical parameters, data structure\nlayouts and accessors, or small macros, inline functions and templates\n(ten or fewer lines in length), you do both of the following:\n\n   a) Give prominent notice with each copy of the object code that the\n   Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the object code with a copy of the GNU GPL and this license\n   document.\n\n  4. Combined Works.\n\n  You may convey a Combined Work under terms of your choice that,\ntaken together, effectively do not restrict modification of the\nportions of the Library contained in the Combined Work and reverse\nengineering for debugging such modifications, if you also do each of\nthe following:\n\n   a) Give prominent notice with each copy of the Combined Work that\n   the Library is used in it and that the Library and its use are\n   covered by this License.\n\n   b) Accompany the Combined Work with a copy of the GNU GPL and this license\n   document.\n\n   c) For a Combined Work that displays copyright notices during\n   execution, include the copyright notice for the Library among\n   these notices, as well as a reference directing the user to the\n   copies of the GNU GPL and this license document.\n\n   d) Do one of the following:\n\n       0) Convey the Minimal Corresponding Source under the terms of this\n       License, and the Corresponding Application Code in a form\n       suitable for, and under terms that permit, the user to\n       recombine or relink the Application with a modified version of\n       the Linked Version to produce a modified Combined Work, in the\n       manner specified by section 6 of the GNU GPL for conveying\n       Corresponding Source.\n\n       1) Use a suitable shared library mechanism for linking with the\n       Library.  A suitable mechanism is one that (a) uses at run time\n       a copy of the Library already present on the user's computer\n       system, and (b) will operate properly with a modified version\n       of the Library that is interface-compatible with the Linked\n       Version.\n\n   e) Provide Installation Information, but only if you would otherwise\n   be required to provide such information under section 6 of the\n   GNU GPL, and only to the extent that such information is\n   necessary to install and execute a modified version of the\n   Combined Work produced by recombining or relinking the\n   Application with a modified version of the Linked Version. (If\n   you use option 4d0, the Installation Information must accompany\n   the Minimal Corresponding Source and Corresponding Application\n   Code. If you use option 4d1, you must provide the Installation\n   Information in the manner specified by section 6 of the GNU GPL\n   for conveying Corresponding Source.)\n\n  5. Combined Libraries.\n\n  You may place library facilities that are a work based on the\nLibrary side by side in a single library together with other library\nfacilities that are not Applications and are not covered by this\nLicense, and convey such a combined library under terms of your\nchoice, if you do both of the following:\n\n   a) Accompany the combined library with a copy of the same work based\n   on the Library, uncombined with any other library facilities,\n   conveyed under the terms of this License.\n\n   b) Give prominent notice with the combined library that part of it\n   is a work based on the Library, and explaining where to find the\n   accompanying uncombined form of the same work.\n\n  6. Revised Versions of the GNU Lesser General Public License.\n\n  The Free Software Foundation may publish revised and/or new versions\nof the GNU Lesser General Public License from time to time. Such new\nversions will be similar in spirit to the present version, but may\ndiffer in detail to address new problems or concerns.\n\n  Each version is given a distinguishing version number. If the\nLibrary as you received it specifies that a certain numbered version\nof the GNU Lesser General Public License \"or any later version\"\napplies to it, you have the option of following the terms and\nconditions either of that published version or of any later version\npublished by the Free Software Foundation. If the Library as you\nreceived it does not specify a version number of the GNU Lesser\nGeneral Public License, you may choose any version of the GNU Lesser\nGeneral Public License ever published by the Free Software Foundation.\n\n  If the Library as you received it specifies that a proxy can decide\nwhether future versions of the GNU Lesser General Public License shall\napply, that proxy's public statement of acceptance of any version is\npermanent authorization for you to choose that version for the\nLibrary.\n"
  },
  {
    "path": "target-platform/org.moka7/build.properties",
    "content": "source.. = src/\noutput.. = bin/\nbin.includes = META-INF/,\\\n               .\n"
  },
  {
    "path": "target-platform/org.moka7/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <artifactId>org.moka7</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>bundle</packaging>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>target-platform</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <version>${maven-checkstyle-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <id>checkstyle-validation</id>\n                        <phase>process-sources</phase>\n                        <configuration>\n                            <skip>true</skip>\n                        </configuration>\n                        <goals>\n                            <goal>check</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>${maven-bundle-plugin.version}</version>\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Include-Resource>\n                            ${project.basedir}/about.html,\n                            about_files=${project.basedir}/about_files/,\n                        </Include-Resource>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Name>${project.artifactId}</Bundle-Name>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Export-Package>\n                            Moka7;version=\"1.0.2\"\n                        </Export-Package>\n                        <Require-Capability>\n                            osgi.ee;filter:=\"(&amp;(osgi.ee=JavaSE)(version=21))\"\n                        </Require-Capability>\n                    </instructions>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/org.moka7/src/main/java/Moka7/IntByRef.java",
    "content": "/*=============================================================================|\n|  PROJECT Moka7                                                         1.0.2 |\n|==============================================================================|\n|  Copyright (C) 2013, 2016 Davide Nardella                                    |\n|  All rights reserved.                                                        |\n|==============================================================================|\n|  SNAP7 is free software: you can redistribute it and/or modify               |\n|  it under the terms of the Lesser GNU General Public License as published by |\n|  the Free Software Foundation, either version 3 of the License, or under     |\n|  EPL Eclipse Public License 1.0.                                             |\n|                                                                              |\n|  This means that you have to chose in advance which take before you import   |\n|  the library into your project.                                              |\n|                                                                              |\n|  SNAP7 is distributed in the hope that it will be useful,                    |\n|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |\n|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you    |\n|  decide to adopt.                                                            |\n|                                                                              |\n|=============================================================================*/\n\npackage Moka7;\n\n/**\n * Quick class to pass an integer by reference\n * @author Davide\n */\n\npublic class IntByRef {\n   \n    public IntByRef(int Val)\n    {\n        this.Value=Val;\n    }\n    public IntByRef()\n    {\n        this.Value=0;\n    }\n    public int Value;\n}\n"
  },
  {
    "path": "target-platform/org.moka7/src/main/java/Moka7/S7.java",
    "content": "/*=============================================================================|\n|  PROJECT Moka7                                                         1.0.2 |\n|==============================================================================|\n|  Copyright (C) 2013, 2016 Davide Nardella                                    |\n|  All rights reserved.                                                        |\n|==============================================================================|\n|  SNAP7 is free software: you can redistribute it and/or modify               |\n|  it under the terms of the Lesser GNU General Public License as published by |\n|  the Free Software Foundation, either version 3 of the License, or under     |\n|  EPL Eclipse Public License 1.0.                                             |\n|                                                                              |\n|  This means that you have to chose in advance which take before you import   |\n|  the library into your project.                                              |\n|                                                                              |\n|  SNAP7 is distributed in the hope that it will be useful,                    |\n|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |\n|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you    |\n|  decide to adopt.                                                            |\n|                                                                              |\n|=============================================================================*/\npackage Moka7;\n\nimport java.io.UnsupportedEncodingException;\nimport java.util.Date;\nimport java.util.Calendar;\n\n/**\n *\n * @author Davide\n */\n\n\n// Step 7 Constants and Conversion helper class\npublic class S7 {\n    // S7 ID Area (Area that we want to read/write)\n    public static final int S7AreaPE = 0x81;\n    public static final int S7AreaPA = 0x82;\n    public static final int S7AreaMK = 0x83;\n    public static final int S7AreaDB = 0x84;\n    public static final int S7AreaCT = 0x1C;\n    public static final int S7AreaTM = 0x1D;   \n    // Connection types\n    public static final byte PG = 0x01;\n    public static final byte OP = 0x02;\n    public static final byte S7_BASIC = 0x03;\n    // Block type\n    public static final int Block_OB   = 0x38;\n    public static final int Block_DB   = 0x41;\n    public static final int Block_SDB  = 0x42;\n    public static final int Block_FC   = 0x43;\n    public static final int Block_SFC  = 0x44;\n    public static final int Block_FB   = 0x45;\n    public static final int Block_SFB  = 0x46;\n    // Sub Block Type\n    public static final int SubBlk_OB  = 0x08;\n    public static final int SubBlk_DB  = 0x0A;\n    public static final int SubBlk_SDB = 0x0B;\n    public static final int SubBlk_FC  = 0x0C;\n    public static final int SubBlk_SFC = 0x0D;\n    public static final int SubBlk_FB  = 0x0E;\n    public static final int SubBlk_SFB = 0x0F;\n    // Block languages\n    public static final int BlockLangAWL       = 0x01;\n    public static final int BlockLangKOP       = 0x02;\n    public static final int BlockLangFUP       = 0x03;\n    public static final int BlockLangSCL       = 0x04;\n    public static final int BlockLangDB        = 0x05;\n    public static final int BlockLangGRAPH     = 0x06;\n    // PLC Status\n    public static final int S7CpuStatusUnknown = 0x00;\n    public static final int S7CpuStatusRun     = 0x08;\n    public static final int S7CpuStatusStop    = 0x04;\n    // Type Var\n    public static final int S7TypeBool = 1;   \n    public static final int S7TypeInt = 1;   \n    \n    // Returns the bit at Pos.Bit \n    public static boolean GetBitAt(byte[] Buffer, int Pos, int Bit)\n    {\n        int Value = Buffer[Pos] & 0x0FF;\n        byte[] Mask = {\n            (byte)0x01,(byte)0x02,(byte)0x04,(byte)0x08,\n            (byte)0x10,(byte)0x20,(byte)0x40,(byte)0x80\n        };   \n        if (Bit<0) Bit=0;\n        if (Bit>7) Bit=7;\n        \n        return (Value & Mask[Bit])!=0;    \n    }  \n    /**\n     * Returns a 16 bit unsigned value : from 0 to 65535 (2^16-1)\n     * @param Buffer\n     * @param Pos start position\n     * @return\n     */\n    public static int GetWordAt(byte[] Buffer, int Pos)\n    {\n        int hi = (Buffer[Pos] & 0x00FF);\n        int lo = (Buffer[Pos+1] & 0x00FF);\n        return (hi<<8)+lo;\n    }  \n    \n    // Returns a 16 bit signed value : from -32768 to 32767\n    public static int GetShortAt(byte[] Buffer, int Pos)\n    {\n        int hi = (Buffer[Pos]);\n        int lo = (Buffer[Pos+1] & 0x00FF);\n        return ((hi<<8)+lo);\n    }  \n\n    // Returns a 32 bit unsigned value : from 0 to 4294967295 (2^32-1)\n    public static long GetDWordAt(byte[] Buffer, int Pos)\n    {\n        long Result;\n        Result=(long)(Buffer[Pos] & 0x0FF);\n        Result<<=8;\n        Result+=(long)(Buffer[Pos+1] & 0x0FF);\n        Result<<=8;\n        Result+=(long)(Buffer[Pos+2] & 0x0FF);\n        Result<<=8;\n        Result+=(long)(Buffer[Pos+3] & 0x0FF);\n        return Result;\n    }  \n\n    // Returns a 32 bit signed value : from 0 to 4294967295 (2^32-1)\n    public static int GetDIntAt(byte[] Buffer, int Pos)\n    {\n        int Result;\n        Result=  Buffer[Pos];\n        Result<<=8;\n        Result+=(Buffer[Pos+1] & 0x0FF);\n        Result<<=8;\n        Result+=(Buffer[Pos+2] & 0x0FF);\n        Result<<=8;\n        Result+=(Buffer[Pos+3] & 0x0FF);\n        return Result;\n    }  \n\n    // Returns a 32 bit floating point\n    public static float GetFloatAt(byte[] Buffer, int Pos)\n    {\n        int IntFloat = GetDIntAt(Buffer, Pos);\n        return Float.intBitsToFloat(IntFloat);\n    }\n\n    // Returns an ASCII string\n    public static String GetStringAt(byte[] Buffer, int Pos, int MaxLen)\n    {\n        byte[] StrBuffer = new byte[MaxLen];\n        System.arraycopy(Buffer, Pos, StrBuffer, 0, MaxLen);\n        String S;   \n        try {\n            S = new String(StrBuffer, \"UTF-8\"); // the charset is UTF-8\n        } catch (UnsupportedEncodingException ex) {\n            S = \"\";\n        }\n        return S;\n    }\n    \n    public static String GetPrintableStringAt(byte[] Buffer, int Pos, int MaxLen)\n    {\n        byte[] StrBuffer = new byte[MaxLen];\n        System.arraycopy(Buffer, Pos, StrBuffer, 0, MaxLen);\n        for (int c = 0; c < MaxLen; c++)\n        {\n            if ((StrBuffer[c]<31) || (StrBuffer[c]>126))\n                StrBuffer[c]=46; // '.'\n        }\n        String S;   \n        try {\n            S = new String(StrBuffer, \"UTF-8\"); // the charset is UTF-8\n        } catch (UnsupportedEncodingException ex) {\n            S = \"\";\n        }\n        return S;\n    }\n\n    public static Date GetDateAt(byte[] Buffer, int Pos)\n    {\n        int Year, Month, Day, Hour, Min, Sec;\n        Calendar S7Date = Calendar.getInstance();\n\n        Year = S7.BCDtoByte(Buffer[Pos]);\n        if (Year<90)\n            Year+=2000;\n        else\n            Year+=1900;\n\n        Month=S7.BCDtoByte(Buffer[Pos+1])-1;\n        Day  =S7.BCDtoByte(Buffer[Pos+2]);\n        Hour =S7.BCDtoByte(Buffer[Pos+3]);\n        Min  =S7.BCDtoByte(Buffer[Pos+4]);\n        Sec  =S7.BCDtoByte(Buffer[Pos+5]);\n\n        S7Date.set(Year, Month, Day, Hour, Min, Sec);                   \n        \n        return S7Date.getTime();\n    }\n        \n    public static void SetBitAt(byte[] Buffer, int Pos, int Bit, boolean Value)\n    {              \n        byte[] Mask = {\n            (byte)0x01,(byte)0x02,(byte)0x04,(byte)0x08,\n            (byte)0x10,(byte)0x20,(byte)0x40,(byte)0x80\n        };   \n        if (Bit<0) Bit=0;\n        if (Bit>7) Bit=7;\n  \n        if (Value)\n            Buffer[Pos]= (byte) (Buffer[Pos] | Mask[Bit]);\n        else\n            Buffer[Pos]= (byte) (Buffer[Pos] & ~Mask[Bit]);\n    }  \n\n    public static void SetWordAt(byte[] Buffer, int Pos, int Value)\n    {\n        int Word = Value & 0x0FFFF;\n        Buffer[Pos]   = (byte) (Word >> 8);\n        Buffer[Pos+1] = (byte) (Word & 0x00FF);\n    }   \n    \n    public static void SetShortAt(byte[] Buffer, int Pos, int Value)\n    {\n        Buffer[Pos]   = (byte) (Value >> 8);\n        Buffer[Pos+1] = (byte) (Value & 0x00FF);\n    }   \n    public static void SetDWordAt(byte[] Buffer, int Pos, long Value)\n    {\n        long DWord = Value &0x0FFFFFFFF;\n        Buffer[Pos+3] = (byte) (DWord &0xFF);\n        Buffer[Pos+2] = (byte) ((DWord >> 8) &0xFF);\n        Buffer[Pos+1] = (byte) ((DWord >> 16) &0xFF);\n        Buffer[Pos]   = (byte) ((DWord >> 24) &0xFF);\n    }\n    \n    public static void SetDIntAt(byte[] Buffer, int Pos, int Value)\n    {       \n        Buffer[Pos+3] = (byte) (Value &0xFF);\n        Buffer[Pos+2] = (byte) ((Value >> 8) &0xFF);\n        Buffer[Pos+1] = (byte) ((Value >> 16) &0xFF);\n        Buffer[Pos]   = (byte) ((Value >> 24) &0xFF);\n    }\n\n    public static void SetFloatAt(byte[] Buffer, int Pos, float Value)\n    {\n        int DInt = Float.floatToIntBits(Value);\n        SetDIntAt(Buffer, Pos, DInt);\n    }\n   \n    public static void SetDateAt(byte[] Buffer, int Pos, Date DateTime)\n    {        \n        int Year, Month, Day, Hour, Min, Sec, Dow;\n        Calendar S7Date = Calendar.getInstance();\n        S7Date.setTime(DateTime);\n        \n        Year  = S7Date.get(Calendar.YEAR);\n        Month = S7Date.get(Calendar.MONTH)+1;\n        Day   = S7Date.get(Calendar.DAY_OF_MONTH);\n        Hour  = S7Date.get(Calendar.HOUR_OF_DAY);\n        Min   = S7Date.get(Calendar.MINUTE);\n        Sec   = S7Date.get(Calendar.SECOND);\n        Dow   = S7Date.get(Calendar.DAY_OF_WEEK);\n        \n        if (Year>1999)\n            Year-=2000;\n        \n        Buffer[Pos]  =ByteToBCD(Year);\n        Buffer[Pos+1]=ByteToBCD(Month);\n        Buffer[Pos+2]=ByteToBCD(Day);\n        Buffer[Pos+3]=ByteToBCD(Hour);\n        Buffer[Pos+4]=ByteToBCD(Min);\n        Buffer[Pos+5]=ByteToBCD(Sec);\n        Buffer[Pos+6]=0;        \n        Buffer[Pos+7]=ByteToBCD(Dow);        \n    }\n\n    public static int BCDtoByte(byte B)\n    {\n        return ((B >> 4) * 10) + (B & 0x0F);        \n    }\n \n    public static byte ByteToBCD(int Value)\n    {\n        return (byte) (((Value / 10) << 4) | (Value % 10));        \n    }\n    \n}\n"
  },
  {
    "path": "target-platform/org.moka7/src/main/java/Moka7/S7BlockInfo.java",
    "content": "/*=============================================================================|\n|  PROJECT Moka7                                                         1.0.2 |\n|==============================================================================|\n|  Copyright (C) 2013, 2016 Davide Nardella                                    |\n|  All rights reserved.                                                        |\n|==============================================================================|\n|  SNAP7 is free software: you can redistribute it and/or modify               |\n|  it under the terms of the Lesser GNU General Public License as published by |\n|  the Free Software Foundation, either version 3 of the License, or under     |\n|  EPL Eclipse Public License 1.0.                                             |\n|                                                                              |\n|  This means that you have to chose in advance which take before you import   |\n|  the library into your project.                                              |\n|                                                                              |\n|  SNAP7 is distributed in the hope that it will be useful,                    |\n|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |\n|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you    |\n|  decide to adopt.                                                            |\n|                                                                              |\n|=============================================================================*/\npackage Moka7;\nimport java.util.Date;\n/**\n *\n * @author Davide\n */\npublic class S7BlockInfo {\n\n    private final int BufSize = 96;\n    // MilliSeconds between 1970/1/1 (Java time base) and 1984/1/1 (Siemens base)\n    private final long DeltaMilliSecs = 441763200000L; \n    protected byte[] Buffer = new byte[BufSize];       \n        \n    protected void Update(byte[] Src, int Pos)\n    {\n        System.arraycopy(Src, Pos, Buffer, 0, BufSize);\n    }   \n    public int BlkType()\n    {\n       return Buffer[2];\n    }\n    public int BlkNumber()\n    {\n       return S7.GetWordAt(Buffer, 3);\n    }\n    public int BlkLang()\n    {\n       return Buffer[1];\n    }\n    public int BlkFlags()\n    {\n       return Buffer[0];\n    }\n    public int MC7Size()  // The real size in bytes\n    {\n       return S7.GetWordAt(Buffer, 31);\n    }\n    public int LoadSize()\n    {\n       return S7.GetDIntAt(Buffer, 5);\n    }\n    public int LocalData()\n    {\n       return S7.GetWordAt(Buffer, 29);\n    }\n    public int SBBLength()\n    {\n       return S7.GetWordAt(Buffer, 25);\n    }\n    public int Checksum()\n    {\n       return S7.GetWordAt(Buffer, 59);\n    }\n    public int Version()\n    {\n       return Buffer[57];\n    }\n    public Date CodeDate()\n    {\n        long BlockDate = ((long)S7.GetWordAt(Buffer, 17))*86400000L+DeltaMilliSecs;\n        return new Date(BlockDate);\n    }\n    public Date IntfDate()\n    {\n        long BlockDate = ((long)S7.GetWordAt(Buffer, 23))*86400000L+DeltaMilliSecs;\n        return new Date(BlockDate);\n    }\n    public String Author()\n    {\n      return S7.GetStringAt(Buffer,33,8);\n    }\n    public String Family()\n    {\n      return S7.GetStringAt(Buffer,41,8);\n    }\n    public String Header()\n    {\n      return S7.GetStringAt(Buffer,49,8);\n    }\n    \n}\n"
  },
  {
    "path": "target-platform/org.moka7/src/main/java/Moka7/S7Client.java",
    "content": "/*=============================================================================|\n|  PROJECT Moka7                                                         1.0.2 |\n|==============================================================================|\n|  Copyright (C) 2013, 2016 Davide Nardella                                    |\n|  All rights reserved.                                                        |\n|==============================================================================|\n|  SNAP7 is free software: you can redistribute it and/or modify               |\n|  it under the terms of the Lesser GNU General Public License as published by |\n|  the Free Software Foundation, either version 3 of the License, or under     |\n|  EPL Eclipse Public License 1.0.                                             |\n|                                                                              |\n|  This means that you have to chose in advance which take before you import   |\n|  the library into your project.                                              |\n|                                                                              |\n|  SNAP7 is distributed in the hope that it will be useful,                    |\n|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |\n|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you    |\n|  decide to adopt.                                                            |\n|                                                                              |\n|=============================================================================*/\npackage Moka7;\n\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.net.SocketAddress;\nimport java.util.Date;\n\n\n/**\n *\n * @author Dave Nardella\n */\npublic class S7Client \n{\n    // WordLength\n    private static final byte S7WLByte    =0x02;\n    private static final byte S7WLCounter =0x1C;\n    private static final byte S7WLTimer   =0x1D;\n    // Error Codes\n    public static final int errTCPConnectionFailed = 0x0001;\n    public static final int errTCPDataSend         = 0x0002;\n    public static final int errTCPDataRecv         = 0x0003;\n    public static final int errTCPDataRecvTout     = 0x0004;\n    public static final int errTCPConnectionReset  = 0x0005;\n    public static final int errISOInvalidPDU       = 0x0006;\n    public static final int errISOConnectionFailed = 0x0007;\n    public static final int errISONegotiatingPDU   = 0x0008; \n    public static final int errS7InvalidPDU        = 0x0009; \n    public static final int errS7DataRead          = 0x000A; \n    public static final int errS7DataWrite         = 0x000B;\n    public static final int errS7BufferTooSmall    = 0x000C;\n    public static final int errS7FunctionError     = 0x000D;\n    public static final int errS7InvalidParams     = 0x000E;           \n    \n    // Public fields\n    public boolean Connected = false;\n    public int LastError = 0;\n    public int RecvTimeout = 2000;\n    \n    // Privates\n    private static final int ISOTCP = 102; // ISOTCP Port\n    private static final int MinPduSize = 16;\n    private static final int DefaultPduSizeRequested = 480;\n    private static final int IsoHSize = 7; // TPKT+COTP Header Size\n    private static final int MaxPduSize = DefaultPduSizeRequested+IsoHSize; \n    \n    \n    private Socket TCPSocket;\n    private final byte[] PDU = new byte[2048];\n    \n    private DataInputStream InStream = null;\n    private DataOutputStream OutStream = null;\n            \n    private String IPAddress;\n           \n    private byte LocalTSAP_HI;\n    private byte LocalTSAP_LO;\n    private byte RemoteTSAP_HI;\n    private byte RemoteTSAP_LO;\n    private byte LastPDUType;\n    \n    private short ConnType = S7.PG; \n    private int _PDULength = 0;\n    \n    // Telegrams\n    // ISO Connection Request telegram (contains also ISO Header and COTP Header)\n    private static final byte ISO_CR[] = {\n        // TPKT (RFC1006 Header)\n        (byte)0x03, // RFC 1006 ID (3) \n        (byte)0x00, // Reserved, always 0\n        (byte)0x00, // High part of packet lenght (entire frame, payload and TPDU included)\n        (byte)0x16, // Low part of packet lenght (entire frame, payload and TPDU included)\n        // COTP (ISO 8073 Header)\n        (byte)0x11, // PDU Size Length\n        (byte)0xE0, // CR - Connection Request ID\n        (byte)0x00, // Dst Reference HI\n        (byte)0x00, // Dst Reference LO\n        (byte)0x00, // Src Reference HI\n        (byte)0x01, // Src Reference LO\n        (byte)0x00, // Class + Options Flags\n        (byte)0xC0, // PDU Max Length ID\n        (byte)0x01, // PDU Max Length HI\n        (byte)0x0A, // PDU Max Length LO\n        (byte)0xC1, // Src TSAP Identifier\n        (byte)0x02, // Src TSAP Length (2 bytes)\n        (byte)0x01, // Src TSAP HI (will be overwritten)\n        (byte)0x00, // Src TSAP LO (will be overwritten)\n        (byte)0xC2, // Dst TSAP Identifier\n        (byte)0x02, // Dst TSAP Length (2 bytes)\n        (byte)0x01, // Dst TSAP HI (will be overwritten)\n        (byte)0x02  // Dst TSAP LO (will be overwritten)\n    };\n    \n    // S7 PDU Negotiation Telegram (contains also ISO Header and COTP Header)\n    private static final byte S7_PN[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x19, \n        (byte)0x02, (byte)0xf0, (byte)0x80, // TPKT + COTP (see above for info)\n        (byte)0x32, (byte)0x01, (byte)0x00, (byte)0x00, \n        (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x08, \n        (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x00, \n        (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01, \n        (byte)0x00, (byte)0x1e // PDU Length Requested = HI-LO 480 bytes\n\t};\n\n    // S7 Read/Write Request Header (contains also ISO Header and COTP Header)\n    private static final byte S7_RW[] = { // 31-35 bytes\n        (byte)0x03,(byte)0x00, \n        (byte)0x00,(byte)0x1f,  // Telegram Length (Data Size + 31 or 35)\n        (byte)0x02,(byte)0xf0, (byte)0x80, // COTP (see above for info)\n        (byte)0x32,             // S7 Protocol ID \n        (byte)0x01,             // Job Type\n        (byte)0x00,(byte)0x00,  // Redundancy identification\n        (byte)0x05,(byte)0x00,  // PDU Reference\n        (byte)0x00,(byte)0x0e,  // Parameters Length\n        (byte)0x00,(byte)0x00,  // Data Length = Size(bytes) + 4      \n        (byte)0x04,             // Function 4 Read Var, 5 Write Var  \n        (byte)0x01,             // Items count\n        (byte)0x12,             // Var spec.\n        (byte)0x0a,             // Length of remaining bytes\n        (byte)0x10,             // Syntax ID \n        S7WLByte,               // Transport Size                        \n        (byte)0x00,(byte)0x00,  // Num Elements                          \n        (byte)0x00,(byte)0x00,  // DB Number (if any, else 0)            \n        (byte)0x84,             // Area Type                            \n        (byte)0x00,(byte)0x00,(byte)0x00, // Area Offset                     \n        // WR area\n        (byte)0x00,             // Reserved \n        (byte)0x04,             // Transport size\n        (byte)0x00,(byte)0x00,  // Data Length * 8 (if not timer or counter) \n    };\n    private static final int Size_RD = 31;\n    private static final int Size_WR = 35;\n\n    // S7 Get Block Info Request Header (contains also ISO Header and COTP Header)\n    private static final byte S7_BI[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x05, \n        (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, \n        (byte)0x0c, (byte)0x00, (byte)0x01, (byte)0x12, \n        (byte)0x04, (byte)0x11, (byte)0x43, (byte)0x03, \n        (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, \n        (byte)0x08, (byte)0x30, \n        (byte)0x41, // Block Type\n        (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, // ASCII Block Number\n        (byte)0x41 \n\t};    \n    \n    // SZL First telegram request   \n    private static final byte S7_SZL_FIRST[] = {\n\t(byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x07, (byte)0x00, (byte)0x00, \n        (byte)0x05, (byte)0x00, // Sequence out\n        (byte)0x00, (byte)0x08, (byte)0x00, \n        (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x12, \n        (byte)0x04, (byte)0x11, (byte)0x44, (byte)0x01, \n        (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, \n        (byte)0x04, \n        (byte)0x00, (byte)0x00, // ID (29)\n        (byte)0x00, (byte)0x00  // Index (31)\n    };    \n    \n    // SZL Next telegram request \n    private static final byte S7_SZL_NEXT[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x06, \n        (byte)0x00, (byte)0x00, (byte)0x0c, (byte)0x00, \n        (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12, \n        (byte)0x08, (byte)0x12, (byte)0x44, (byte)0x01, \n        (byte)0x01, // Sequence\n        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,\n        (byte)0x0a, (byte)0x00, (byte)0x00, (byte)0x00\n    };    \n\n    // Get Date/Time request\n    private static final byte S7_GET_DT[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x1d, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x38, \n        (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, \n        (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12, \n        (byte)0x04, (byte)0x11, (byte)0x47, (byte)0x01, \n        (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x00, \n        (byte)0x00        \n    };\n    \n    // Set Date/Time command\n    private static final byte S7_SET_DT[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x27, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x89, \n        (byte)0x03, (byte)0x00, (byte)0x08, (byte)0x00, \n        (byte)0x0e, (byte)0x00, (byte)0x01, (byte)0x12, \n        (byte)0x04, (byte)0x11, (byte)0x47, (byte)0x02, \n        (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00,\n        (byte)0x0a, (byte)0x00, (byte)0x19, // Hi part of Year\n        (byte)0x13, // Lo part of Year\n        (byte)0x12, // Month\n        (byte)0x06, // Day\n        (byte)0x17, // Hour\n        (byte)0x37, // Min\n        (byte)0x13, // Sec\n        (byte)0x00, (byte)0x01 // ms + Day of week   \n    };\n\n    // S7 STOP request\n    private static final byte S7_STOP[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0e, \n        (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00, \n        (byte)0x00, (byte)0x29, (byte)0x00, (byte)0x00, \n        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x09, \n        (byte)0x50, (byte)0x5f, (byte)0x50, (byte)0x52, \n        (byte)0x4f, (byte)0x47, (byte)0x52, (byte)0x41, \n        (byte)0x4d \n    };    \n    \n    // S7 HOT Start request\n    private static final byte S7_HOT_START[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0c,\n        (byte)0x00, (byte)0x00, (byte)0x14, (byte)0x00, \n        (byte)0x00, (byte)0x28, (byte)0x00, (byte)0x00, \n        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, \n        (byte)0xfd, (byte)0x00, (byte)0x00, (byte)0x09, \n        (byte)0x50, (byte)0x5f, (byte)0x50, (byte)0x52, \n        (byte)0x4f, (byte)0x47, (byte)0x52, (byte)0x41, \n        (byte)0x4d\n    };    \n    \n    // S7 COLD Start request\n    private static final byte S7_COLD_START[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x27, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0f, \n        (byte)0x00, (byte)0x00, (byte)0x16, (byte)0x00, \n        (byte)0x00, (byte)0x28, (byte)0x00, (byte)0x00, \n        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, \n        (byte)0xfd, (byte)0x00, (byte)0x02, (byte)0x43, \n        (byte)0x20, (byte)0x09, (byte)0x50, (byte)0x5f, \n        (byte)0x50, (byte)0x52, (byte)0x4f, (byte)0x47, \n        (byte)0x52, (byte)0x41, (byte)0x4d\n    };    \n\n    // S7 Get PLC Status \n    private static final byte S7_GET_STAT[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x2c, \n        (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, \n        (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x12, \n        (byte)0x04, (byte)0x11, (byte)0x44, (byte)0x01, \n        (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, \n        (byte)0x04, (byte)0x04, (byte)0x24, (byte)0x00, \n        (byte)0x00 \n    };\n\n    // S7 Set Session Password \n    private static final byte S7_SET_PWD[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x27, \n        (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, \n        (byte)0x0c, (byte)0x00, (byte)0x01, (byte)0x12, \n        (byte)0x04, (byte)0x11, (byte)0x45, (byte)0x01, \n        (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, \n        (byte)0x08, \n        // 8 Char Encoded Password\n        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, \n        (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00        \n    };\n\n    // S7 Clear Session Password \n    private static final byte S7_CLR_PWD[] = {\n        (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x1d, \n        (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, \n        (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x29, \n        (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, \n        (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12, \n        (byte)0x04, (byte)0x11, (byte)0x45, (byte)0x02, \n        (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x00, \n        (byte)0x00    \n    };    \n        \n    public S7Client()\n    {\n        // Placeholder for future implementations\n    }\n\n    public static String ErrorText(int Error)\n    {\n        switch (Error)\n        {            \n            case errTCPConnectionFailed :\n                return \"TCP Connection failed.\";\n            case errTCPDataSend :\n                return \"TCP Sending error.\";\n            case errTCPDataRecv :        \n                return \"TCP Receiving error.\";\n            case errTCPDataRecvTout :\n                return \"Data Receiving timeout.\";\n            case errTCPConnectionReset :\n                return \"Connection reset by the peer.\";\n            case errISOInvalidPDU :\n                return \"Invalid ISO PDU received.\";\n            case errISOConnectionFailed :\n                return \"ISO connection refused by the CPU.\";\n            case errISONegotiatingPDU :\n                return \"ISO error negotiating the PDU length.\";\n            case errS7InvalidPDU :\n                return \"Invalid S7 PDU received.\";\n            case errS7DataRead :\n                return \"S7 Error reading data from the CPU.\";\n            case errS7DataWrite :\n                return \"S7 Error writing data to the CPU.\";\n            case errS7BufferTooSmall :\n                return \"The Buffer supplied to the function is too small.\";\n            case errS7FunctionError :\n                return \"S7 function refused by the CPU.\";\n            case errS7InvalidParams :\n                return \"Invalid parameters supplied to the function.\";\n            default : \n                return \"Unknown error : 0x\"+Integer.toHexString(Error);\n        }\n    }\n    \n    private int TCPConnect() \n    {\n        SocketAddress sockaddr = new InetSocketAddress(IPAddress, ISOTCP);\n        LastError=0;\n        try {                       \n            TCPSocket = new Socket(); \n            TCPSocket.connect(sockaddr ,5000);\n            TCPSocket.setTcpNoDelay(true);\n            InStream = new DataInputStream(TCPSocket.getInputStream());\n            OutStream = new DataOutputStream(TCPSocket.getOutputStream());           \n        }\n        catch (IOException e) {\n            LastError=errTCPConnectionFailed;\n        }       \n        return LastError;\n    }\n    \n    private int WaitForData(int Size, int Timeout) \n    {\n        int cnt = 0;\n        LastError=0;\n        int SizeAvail;\n        boolean Expired = false;\n        try \n        {\n            SizeAvail=InStream.available();\n            while ((SizeAvail<Size) && (!Expired) && (LastError==0))\n            {\n                \n                cnt++;\n                try {\n                    Thread.sleep(1);\n                } \n                catch (InterruptedException ex) {\n                    LastError=errTCPDataRecvTout;\n                }\n                SizeAvail=InStream.available();              \n                Expired=cnt>Timeout;\n                // If timeout we clean the buffer\n                if (Expired && (SizeAvail>0) && (LastError==0))\n                  InStream.read(PDU, 0, SizeAvail);\n            }\n        } \n        catch (IOException ex) \n        {\n            LastError=errTCPDataRecvTout;\n        }\n        if (cnt>=Timeout)\n        {\n            LastError=errTCPDataRecvTout;\n        }        \n        return LastError;\n    }\n    \n    private int RecvPacket(byte[] Buffer, int Start, int Size)\n    {\n\tint BytesRead=0;\n        LastError=WaitForData(Size,RecvTimeout);\n\tif (LastError==0)\n        {\n            try {\n                BytesRead = InStream.read(Buffer, Start, Size);\n            } catch (IOException ex) {\n                LastError=errTCPDataRecv;\n            }\n            if (BytesRead==0)\n                LastError=errTCPConnectionReset;        \n        }\n        return LastError;\n    }\n\n    private void SendPacket(byte[] Buffer, int Len)\n    {\n        LastError = 0;\n        try {\n            OutStream.write(Buffer,0,Len);\n            OutStream.flush();\n        } catch (IOException ex) {\n            LastError = errTCPDataSend; \n        }\n    }   \n    private void SendPacket(byte[] Buffer)\n    {\n        SendPacket(Buffer,Buffer.length);\n    }   \n    \n    private int RecvIsoPacket()\n    {\n        Boolean Done = false;\n        int Size = 0;\n\twhile ((LastError==0) && !Done)\n\t{\n            // Get TPKT (4 bytes)\n            RecvPacket(PDU, 0, 4); \n            if (LastError==0)\n            {\n                Size=S7.GetWordAt(PDU,2);\n                // Check 0 bytes Data Packet (only TPKT+COTP = 7 bytes)\n                if (Size==IsoHSize)\n                    RecvPacket(PDU,4, 3); // Skip remaining 3 bytes and Done is still false\n                else\n                {\n                    if ((Size>MaxPduSize) || (Size<MinPduSize))\n                        LastError=errISOInvalidPDU;\n                    else\n                        Done = true; // a valid Length !=7 && >16 && <247\n                }\n            }               \n        }\n        if (LastError==0)\n        {\n            RecvPacket(PDU,4, 3); // Skip remaining 3 COTP bytes\n            LastPDUType=PDU[5];   // Stores PDU Type, we need it \n            // Receives the S7 Payload          \n            RecvPacket(PDU, 7, Size-IsoHSize);          \n        }\n        if (LastError==0)\n            return Size;\n        else\n            return 0;\n    }\n    \n    private int ISOConnect() \n    {\n    \tint Size;\n        ISO_CR[16]=LocalTSAP_HI;\n        ISO_CR[17]=LocalTSAP_LO;\n        ISO_CR[20]=RemoteTSAP_HI;\n        ISO_CR[21]=RemoteTSAP_LO;\n        \n        // Sends the connection request telegram      \n        SendPacket(ISO_CR);\n        if (LastError==0)\n        {            \n            // Gets the reply (if any)\n            Size=RecvIsoPacket();\n            if (LastError==0) \n            {\n                if (Size==22) \n                {\n                    if (LastPDUType!=(byte)0xD0) // 0xD0 = CC Connection confirm\n                        LastError=errISOConnectionFailed;\n                }\n                else\n                    LastError=errISOInvalidPDU;\n            }\n        }        \n        return LastError;\n    }        \n    \n    private int NegotiatePduLength()\n    {\n        int Length;\n        // Set PDU Size Requested\n        S7.SetWordAt(S7_PN,23,DefaultPduSizeRequested);            \n        // Sends the connection request telegram\n        SendPacket(S7_PN);\n        if (LastError==0)    \n        {\n            Length=RecvIsoPacket();\n            if (LastError==0)                 \n            {\n                // check S7 Error\n                if ((Length==27) && (PDU[17]==0) && (PDU[18]==0))  // 20 = size of Negotiate Answer\n                {\n                    // Get PDU Size Negotiated\n                    _PDULength = S7.GetWordAt(PDU,25);\n                    if (_PDULength>0)\n                        return 0;\n                    else\n                        LastError=errISONegotiatingPDU;\n                }\n                else \n                    LastError=errISONegotiatingPDU;\n            }\n        }\n        return LastError;\n    }\n      \n    public void SetConnectionType(short ConnectionType)\n    {\n        ConnType=ConnectionType;\n    }\n      \n    public int Connect() \n    {\n        LastError=0;\n        if (!Connected)\n        {\n            TCPConnect();\n            if (LastError==0) // First stage : TCP Connection\n            {\n                ISOConnect();\n                if (LastError==0) // Second stage : ISOTCP (ISO 8073) Connection\n                {\n                    LastError=NegotiatePduLength(); // Third stage : S7 PDU negotiation\n                }\n            }\t            \n        }\n        Connected=LastError==0;\n        \n        // In case the connection is not completely established (TCP connection + ISO connection + PDU negotiation)\n        // we close the socket and its IO streams to revert the object back to pre-Connect() state\n        if (!Connected)\n        {\n            if (TCPSocket != null) {\n                try {\n                    TCPSocket.close();\n                } catch (IOException ex) {\n                }\n            }\n            if (InStream != null) {\n                try {\n                    InStream.close();\n                } catch (IOException ex) {\n                }\n            }\n            if (OutStream != null) {\n                try {\n                    OutStream.close();\n                } catch (IOException ex) {\n                }\n            }\n            _PDULength = 0;\n        }                \n        \n\treturn LastError;\n    }\n    \n    public void Disconnect()\n    {\n        if (Connected)\n        {\n            try {\n                OutStream.close();\n                InStream.close();\n                TCPSocket.close();\n                _PDULength=0;\n            } catch (IOException ex) {            \n            }\n            Connected=false;\n        }\n    }\n    \n    public int ConnectTo(String Address, int Rack, int Slot) \n    {       \n        int RemoteTSAP=(ConnType<<8)+ (Rack * 0x20) + Slot;\n        SetConnectionParams(Address, 0x0100, RemoteTSAP);\n        return Connect();\n    }\n    \n    public int PDULength()\n    {\n        return _PDULength;\n    }\n    \n    public void SetConnectionParams(String Address, int LocalTSAP, int RemoteTSAP)\n    {\n        int LocTSAP = LocalTSAP & 0x0000FFFF;\n        int RemTSAP = RemoteTSAP & 0x0000FFFF;        \n        IPAddress    =  Address;\n        LocalTSAP_HI = (byte) (LocTSAP>>8);\n        LocalTSAP_LO = (byte) (LocTSAP & 0x00FF);\n        RemoteTSAP_HI= (byte) (RemTSAP>>8);\n        RemoteTSAP_LO= (byte) (RemTSAP & 0x00FF);      \n    }\n \n    public int ReadArea(int Area, int DBNumber, int Start, int Amount, byte[] Data)\n    {\n\tint Address;\n\tint NumElements;\n\tint MaxElements;\n\tint TotElements;\n\tint SizeRequested;\n\tint Length;\n\tint Offset = 0;\n\tint WordSize = 1;\n\t     \n\tLastError=0;\n\t\t\n\t// If we are addressing Timers or counters the element size is 2\n\tif ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM))\n            WordSize = 2;\n\t\n        MaxElements=(_PDULength-18) / WordSize; // 18 = Reply telegram header\n            TotElements=Amount;\n\t\n        while ((TotElements>0) && (LastError==0))\n        {\n            NumElements=TotElements;\n            if (NumElements>MaxElements)\n               NumElements=MaxElements;\n\n            SizeRequested = NumElements * WordSize;\n\n            // Setup the telegram\n            System.arraycopy(S7_RW, 0, PDU, 0, Size_RD);\n            // Set DB Number\n            PDU[27] = (byte) Area;\n            // Set Area\n            if (Area==S7.S7AreaDB) \n                S7.SetWordAt(PDU,25,DBNumber);\n\n            // Adjusts Start and word length\n            if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM))\n            {\n                Address = Start;\n                if (Area==S7.S7AreaCT)\n                    PDU[22]=S7WLCounter;\n                else\n                    PDU[22]=S7WLTimer;\n            }\n            else\n                Address = Start<<3;\n\n            // Num elements\n            S7.SetWordAt(PDU,23,NumElements);\n\n            // Address into the PLC (only 3 bytes)           \n            PDU[30] = (byte) (Address & 0x0FF);\n            Address = Address >> 8;\n            PDU[29] = (byte) (Address & 0x0FF);\n            Address = Address >> 8;\n            PDU[28] = (byte) (Address & 0x0FF);         \n            \n            SendPacket(PDU, Size_RD);\n            if (LastError==0)\n            {\n                Length=RecvIsoPacket();\n                if (LastError==0)\n                {\n                    if (Length>=25)\n                    {\n                        if ((Length-25==SizeRequested) && (PDU[21]==(byte)0xFF))\n                        {\n                            System.arraycopy(PDU, 25, Data, Offset, SizeRequested);\n                            Offset+=SizeRequested;\n                        }\n                        else\n                            LastError = errS7DataRead;\n                    }\n                    else\n                        LastError = errS7InvalidPDU;\n                }\n            }\n\n            TotElements -= NumElements;\n            Start += NumElements*WordSize;\n        }\n        return LastError;\n    }\n\n    public int WriteArea(int Area, int DBNumber, int Start, int Amount, byte[] Data)\n    {\n\tint Address;\n\tint NumElements;\n\tint MaxElements;\n\tint TotElements;\n\tint DataSize;\n\tint IsoSize;\n\tint Length;\n\tint Offset = 0;\n\tint WordSize = 1;\n     \n\tLastError=0;\n\t\n\t// If we are addressing Timers or counters the element size is 2\n\tif ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM))\n            WordSize = 2;\n\n        MaxElements=(_PDULength-35) / WordSize; // 18 = Reply telegram header\n\tTotElements=Amount;\n\t\n        while ((TotElements>0) && (LastError==0))\n        {\n            NumElements=TotElements;\n            if (NumElements>MaxElements)\n               NumElements=MaxElements;\n\n            DataSize = NumElements * WordSize;\n            IsoSize  = Size_WR + DataSize;\n\n            // Setup the telegram\n            System.arraycopy(S7_RW, 0, PDU, 0, Size_WR);\n            // Whole telegram Size\n            S7.SetWordAt(PDU,2,IsoSize);\n            // Data Length\n            Length=DataSize+4;\n            S7.SetWordAt(PDU,15,Length);\n            // Function\n            PDU[17]= (byte) 0x05;\n            // Set DB Number\n            PDU[27] = (byte) Area;\n            if (Area==S7.S7AreaDB) \n                S7.SetWordAt(PDU,25,DBNumber);\n\n            // Adjusts Start and word length\n            if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM))\n            {\n                Address = Start;\n                Length = DataSize;\n                if (Area==S7.S7AreaCT)\n                    PDU[22]=S7WLCounter;\n                else\n                    PDU[22]=S7WLTimer;\n            }\n            else\n            {\n                Address = Start<<3;\n                Length  = DataSize<<3;\n            }\n            // Num elements\n            S7.SetWordAt(PDU,23,NumElements);\n            // Address into the PLC\n            PDU[30] = (byte) (Address & 0x0FF);\n            Address = Address >> 8;\n            PDU[29] = (byte) (Address & 0x0FF);\n            Address = Address >> 8;\n            PDU[28] = (byte) (Address & 0x0FF);\n            // Length\n            S7.SetWordAt(PDU,33,Length);\n            \n            // Copies the Data\n            System.arraycopy(Data, Offset, PDU, 35, DataSize);\n                        \n            SendPacket(PDU, IsoSize);\n            if (LastError==0)\n            {\n                Length=RecvIsoPacket();\n                if (LastError==0)\n                {\n                    if (Length==22)\n                    {\n                        if ((S7.GetWordAt(PDU,17)!=0) || (PDU[21]!=(byte)0xFF))\n                            LastError = errS7DataWrite;\n                    }\n                    else\n                        LastError = errS7InvalidPDU;\n                }\n            }\n\n            Offset+=DataSize;\n            TotElements -= NumElements;\n            Start += NumElements*WordSize;\n        }\n        return LastError;\n    }\n   \n    public int GetAgBlockInfo(int BlockType, int BlockNumber, S7BlockInfo Block)\n    {\n    \tint Length;\n        LastError=0;\n        // Block Type\n        S7_BI[30] = (byte) BlockType;\n        // Block Number\n        S7_BI[31]=(byte) ((BlockNumber / 10000)+0x30);\n        BlockNumber=BlockNumber % 10000;\n        S7_BI[32]=(byte) ((BlockNumber / 1000)+0x30);\n        BlockNumber=BlockNumber % 1000;\n        S7_BI[33]=(byte) ((BlockNumber / 100)+0x30);\n        BlockNumber=BlockNumber % 100;\n        S7_BI[34]=(byte) ((BlockNumber / 10)+0x30);\n        BlockNumber=BlockNumber % 10;\n        S7_BI[35]=(byte) ((BlockNumber / 1)+0x30);\n        \n        SendPacket(S7_BI);\n        if (LastError==0)\n        {\n            Length=RecvIsoPacket();\n            if (Length > 32) // the minimum expected\n            {\n                if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF))\n                {\n                    Block.Update(PDU, 42);\n                }\n                else\n                    LastError = errS7FunctionError;\n            }\n            else\n                LastError = errS7InvalidPDU;\n        }\n        \n        return LastError;\n    }      \n    /**\n     * \n     * @param DBNumber DB Number\n     * @param Buffer   Destination buffer\n     * @param SizeRead How many bytes were read\n     * @return \n     */\n    public int DBGet(int DBNumber, byte[] Buffer, IntByRef SizeRead)\n    {\n        S7BlockInfo Block = new S7BlockInfo();\n        // Query the DB Length\n        LastError = GetAgBlockInfo(S7.Block_DB, DBNumber, Block);\n        if (LastError==0)\n        {\n            int SizeToRead = Block.MC7Size();\n            // Checks the room\n            if (SizeToRead<=Buffer.length)\n            {\n                LastError=ReadArea(S7.S7AreaDB, DBNumber, 0, SizeToRead, Buffer);\n                if (LastError==0)\n                    SizeRead.Value=SizeToRead;\n            }\n            else\n                LastError=errS7BufferTooSmall;\n        }\n        return LastError;\n    }  \n    \n    public int ReadSZL(int ID, int Index, S7Szl SZL)\n    {\n    \tint Length;\n        int DataSZL;\n        int Offset = 0;\n        boolean Done = false;\n        boolean First = true;\n        byte Seq_in =0x00;\n        int Seq_out =0x0000;\n        \n        LastError=0;\n        SZL.DataSize=0;\n        do\n        {\n            if (First)\n            {\n                S7.SetWordAt(S7_SZL_FIRST, 11, ++Seq_out);\n                S7.SetWordAt(S7_SZL_FIRST, 29, ID);\n                S7.SetWordAt(S7_SZL_FIRST, 31, Index);\n                SendPacket(S7_SZL_FIRST);                \n            }\n            else\n            {\n                S7.SetWordAt(S7_SZL_NEXT, 11, ++Seq_out);\n                PDU[24] = (byte)Seq_in;\n                SendPacket(S7_SZL_NEXT);                \n            }\n            if (LastError!=0)\n                return LastError;\n            \n            Length=RecvIsoPacket();\n            if (LastError==0)\n            {\n                if (First)\n                {\n                    if (Length > 32) // the minimum expected\n                    {\n                        if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF))\n                        {\n                            // Gets Amount of this slice\n                            DataSZL=S7.GetWordAt(PDU,31)-8; // Skips extra params (ID, Index ...)\n                            Done=PDU[26]==0x00;\n                            Seq_in=(byte)PDU[24]; // Slice sequence\n                            \n                            SZL.LENTHDR=S7.GetWordAt(PDU, 37);\n                            SZL.N_DR=S7.GetWordAt(PDU, 39);\n                            SZL.Copy(PDU, 41, Offset, DataSZL);                       \n                            Offset+=DataSZL;\n                            SZL.DataSize+=DataSZL;\n                        }\n                        else\n                            LastError = errS7FunctionError;\n                    }\n                    else\n                        LastError = errS7InvalidPDU;\n                }\n                else\n                {\n                    if (Length > 32) // the minimum expected\n                    {\n                        if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF))\n                        {\n                            // Gets Amount of this slice\n                            DataSZL=S7.GetWordAt(PDU,31); \n                            Done=PDU[26]==0x00;\n                            Seq_in=(byte)PDU[24]; // Slice sequence\n                            SZL.Copy(PDU, 37, Offset, DataSZL);                       \n                            Offset+=DataSZL;\n                            SZL.DataSize+=DataSZL;\n                        }\n                        else\n                            LastError = errS7FunctionError;\n                    }\n                    else\n                        LastError = errS7InvalidPDU;\n                }\n            }            \n            First=false;\n        }            \n        while(!Done && (LastError==0));\n        \n        return LastError;\n    }\n    \n    \n    public int GetCpuInfo(S7CpuInfo Info)\n    {\n        S7Szl SZL = new S7Szl(1024);\n        \n        LastError = ReadSZL(0x001C, 0x0000, SZL);\n        if (LastError==0)\n        {\n            Info.Update(SZL.Data, 0);\n        }\n        return LastError;\n    }\n\n    public int GetCpInfo(S7CpInfo Info)\n    {\n        S7Szl SZL = new S7Szl(1024);\n        \n        LastError = ReadSZL(0x0131, 0x0001, SZL);\n        if (LastError==0)\n        {\n            Info.Update(SZL.Data, 0);\n        }\n        return LastError;\n    }\n    \n    public int GetOrderCode(S7OrderCode Code)\n    {\n        S7Szl SZL = new S7Szl(1024);\n        \n        LastError = ReadSZL(0x0011, 0x0000, SZL);\n        if (LastError==0)\n        {\n            Code.Update(SZL.Data, 0, SZL.DataSize);\n        }\n        return LastError;\n    }\n\n    public int GetPlcDateTime(Date DateTime)\n    {\n        int Length;\n\n        LastError = 0;\n        SendPacket(S7_GET_DT);\n        if (LastError==0)\n        {\n            Length=RecvIsoPacket();\n            if (Length > 30) // the minimum expected\n            {\n                if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF))\n                {\n                    DateTime=S7.GetDateAt(PDU, 34);\n                }\n                else\n                    LastError = errS7FunctionError;\n            }\n            else\n                LastError = errS7InvalidPDU;\n        }\n        \n        return LastError;\n    }\n\n    public int SetPlcDateTime(Date DateTime)\n    {\n        int Length;\n       \n        LastError = 0;\n        S7.SetDateAt(S7_SET_DT, 31, DateTime);\n        \n        SendPacket(S7_SET_DT);\n        if (LastError==0)\n        {\n            Length=RecvIsoPacket();\n            if (Length > 30) // the minimum expected\n            {\n                if (S7.GetWordAt(PDU,27)!=0) \n                    LastError = errS7FunctionError;\n            }\n            else\n                LastError = errS7InvalidPDU;\n        }\n        \n        return LastError;\n    }\n\n    public int SetPlcSystemDateTime()\n    {\n        return SetPlcDateTime(new Date());\n    }\n    \n    public int PlcStop()\n    {\n        int Length;\n       \n        LastError = 0;\n        SendPacket(S7_STOP);\n        if (LastError==0)\n        {\n            Length=RecvIsoPacket();\n            if (Length > 18) // 18 is the minimum expected\n            {\n                if (S7.GetWordAt(PDU,17)!=0) \n                    LastError = errS7FunctionError;\n            }\n            else\n                LastError = errS7InvalidPDU;\n        }\n        return LastError;\n    }\n\n    public int PlcHotStart()\n    {\n        int Length;\n       \n        LastError = 0;\n        SendPacket(S7_HOT_START);\n        if (LastError==0)\n        {\n            Length=RecvIsoPacket();\n            if (Length > 18) // the minimum expected\n            {\n                if (S7.GetWordAt(PDU,17)!=0) \n                    LastError = errS7FunctionError;\n            }\n            else\n                LastError = errS7InvalidPDU;\n        }\n        return LastError;\n    }\n\n    public int PlcColdStart()\n    {\n        int Length;\n       \n        LastError = 0;\n        SendPacket(S7_COLD_START);\n        if (LastError==0)\n        {\n            Length=RecvIsoPacket();\n            if (Length > 18) // the minimum expected\n            {\n                if (S7.GetWordAt(PDU,17)!=0) \n                    LastError = errS7FunctionError;\n            }\n            else\n                LastError = errS7InvalidPDU;\n        }\n        return LastError;\n    }\n\n    public int GetPlcStatus(IntByRef Status)\n    {\n        int Length;\n       \n        LastError = 0;\n        SendPacket(S7_GET_STAT);\n        if (LastError==0)\n        {\n            Length=RecvIsoPacket();\n            if (Length > 30) // the minimum expected\n            {\n                if (S7.GetWordAt(PDU,27)==0) \n                {\n                    switch (PDU[44])\n                    {\n                        case S7.S7CpuStatusUnknown :\n                        case S7.S7CpuStatusRun     :\n                        case S7.S7CpuStatusStop    : Status.Value=PDU[44];\n                        break;\n                        default :\n                        // Since RUN status is always 0x08 for all CPUs and CPs, STOP status\n                        // sometime can be coded as 0x03 (especially for old cpu...)\n                            Status.Value=S7.S7CpuStatusStop;\n                    }                    \n                }\n                else\n                    LastError = errS7FunctionError;\n            }\n            else\n                LastError = errS7InvalidPDU;\n        }            \n        return LastError;\n    }\n\n    public int SetSessionPassword(String Password)\n    {\n        byte[] pwd = {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20};\n        int Length;\n\n        LastError = 0;\n        // Adjusts the Password length to 8\n        if (Password.length()>8) \n            Password=Password.substring(0, 8);\n        else\n        {\n            while (Password.length()<8)\n                Password=Password+\" \";\n        }\n        \n        try {\n            pwd = Password.getBytes(\"UTF-8\");\n        } catch (UnsupportedEncodingException ex) {\n            LastError = errS7InvalidParams;\n        }\n        if (LastError==0)\n        {            \n            // Encodes the password\n            pwd[0]=(byte) (pwd[0] ^ 0x55);\n            pwd[1]=(byte) (pwd[1] ^ 0x55);\n            for (int c = 2; c < 8; c++)\n            {\n                pwd[c]=(byte) (pwd[c] ^ 0x55 ^ pwd[c-2]);            \n            }\n            System.arraycopy(pwd, 0, S7_SET_PWD, 29, 8);\n            // Sends the telegrem\n            SendPacket(S7_SET_PWD);\n            if (LastError==0)\n            {\n                Length=RecvIsoPacket();\n                if (Length > 32) // the minimum expected\n                {\n                    if (S7.GetWordAt(PDU,27)!=0) \n                        LastError = errS7FunctionError;                    \n                }                \n                else\n                    LastError = errS7InvalidPDU;                \n            }            \n        }        \n        return LastError;\n    }\n        \n    public int ClearSessionPassword()\n    {\n        int Length;\n       \n        LastError = 0;       \n        SendPacket(S7_CLR_PWD);\n        if (LastError==0)\n        {\n            Length=RecvIsoPacket();\n            if (Length > 30) // the minimum expected\n            {\n                if (S7.GetWordAt(PDU,27)!=0) \n                    LastError = errS7FunctionError;\n            }\n            else\n                LastError = errS7InvalidPDU;\n        }        \n        return LastError;\n    }\n    \n    public int GetProtection(S7Protection Protection)\n    {\n        S7Szl SZL = new S7Szl(256);\n        \n        LastError = ReadSZL(0x0232, 0x0004, SZL);\n        if (LastError==0)\n        {\n            Protection.Update(SZL.Data);\n        }\n        return LastError;\n    }\n    \n}\n"
  },
  {
    "path": "target-platform/org.moka7/src/main/java/Moka7/S7CpInfo.java",
    "content": "/*=============================================================================|\n|  PROJECT Moka7                                                         1.0.2 |\n|==============================================================================|\n|  Copyright (C) 2013, 2016 Davide Nardella                                    |\n|  All rights reserved.                                                        |\n|==============================================================================|\n|  SNAP7 is free software: you can redistribute it and/or modify               |\n|  it under the terms of the Lesser GNU General Public License as published by |\n|  the Free Software Foundation, either version 3 of the License, or under     |\n|  EPL Eclipse Public License 1.0.                                             |\n|                                                                              |\n|  This means that you have to chose in advance which take before you import   |\n|  the library into your project.                                              |\n|                                                                              |\n|  SNAP7 is distributed in the hope that it will be useful,                    |\n|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |\n|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you    |\n|  decide to adopt.                                                            |\n|                                                                              |\n|=============================================================================*/\npackage Moka7;\n\n/**\n *\n * @author Davide\n */\npublic class S7CpInfo {\n\n    public int MaxPduLength;\n    public int MaxConnections;\n    public int MaxMpiRate;\n    public int MaxBusRate;\n\n    protected void Update(byte[] Src, int Pos)\n    {\n        MaxPduLength = S7.GetShortAt(Src, 2);\n        MaxConnections = S7.GetShortAt(Src, 4);\n        MaxMpiRate = S7.GetDIntAt(Src, 6);\n        MaxBusRate = S7.GetDIntAt(Src, 10);                      \n    }         \n}\n"
  },
  {
    "path": "target-platform/org.moka7/src/main/java/Moka7/S7CpuInfo.java",
    "content": "/*=============================================================================|\n|  PROJECT Moka7                                                         1.0.2 |\n|==============================================================================|\n|  Copyright (C) 2013, 2016 Davide Nardella                                    |\n|  All rights reserved.                                                        |\n|==============================================================================|\n|  SNAP7 is free software: you can redistribute it and/or modify               |\n|  it under the terms of the Lesser GNU General Public License as published by |\n|  the Free Software Foundation, either version 3 of the License, or under     |\n|  EPL Eclipse Public License 1.0.                                             |\n|                                                                              |\n|  This means that you have to chose in advance which take before you import   |\n|  the library into your project.                                              |\n|                                                                              |\n|  SNAP7 is distributed in the hope that it will be useful,                    |\n|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |\n|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you    |\n|  decide to adopt.                                                            |\n|                                                                              |\n|=============================================================================*/\npackage Moka7;\n\n/**\n *\n * @author Davide\n */\npublic class S7CpuInfo {\n    \n    private final int BufSize = 256;\n    protected byte[] Buffer = new byte[BufSize];       \n\n    protected void Update(byte[] Src, int Pos)\n    {\n        System.arraycopy(Src, Pos, Buffer, 0, BufSize);\n    }   \n    \n    public String ModuleTypeName()\n    {\n        return S7.GetStringAt(Buffer,172,32);\n    }\n    public String SerialNumber()\n    {\n        return S7.GetStringAt(Buffer,138,24);\n    }\n    public String ASName()\n    {\n        return S7.GetStringAt(Buffer,2,24);\n    }\n    public String Copyright()\n    {\n        return S7.GetStringAt(Buffer,104,26);\n    }\n    public String ModuleName()\n    {\n        return S7.GetStringAt(Buffer,36,24);\n    }\n}\n"
  },
  {
    "path": "target-platform/org.moka7/src/main/java/Moka7/S7OrderCode.java",
    "content": "/*=============================================================================|\n|  PROJECT Moka7                                                         1.0.2 |\n|==============================================================================|\n|  Copyright (C) 2013, 2016 Davide Nardella                                    |\n|  All rights reserved.                                                        |\n|==============================================================================|\n|  SNAP7 is free software: you can redistribute it and/or modify               |\n|  it under the terms of the Lesser GNU General Public License as published by |\n|  the Free Software Foundation, either version 3 of the License, or under     |\n|  EPL Eclipse Public License 1.0.                                             |\n|                                                                              |\n|  This means that you have to chose in advance which take before you import   |\n|  the library into your project.                                              |\n|                                                                              |\n|  SNAP7 is distributed in the hope that it will be useful,                    |\n|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |\n|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you    |\n|  decide to adopt.                                                            |\n|                                                                              |\n|=============================================================================*/\npackage Moka7;\n\n/**\n *\n * @author Davide\n */\npublic class S7OrderCode {\n  \n    public int V1;\n    public int V2;\n    public int V3;\n    protected byte[] Buffer = new byte[1024];       \n\n    protected void Update(byte[] Src, int Pos, int Size)\n    {\n        System.arraycopy(Src, Pos, Buffer, 0, Size);\n        V1 = (byte) Src[Size-3];\n        V2 = (byte) Src[Size-2];\n        V3 = (byte) Src[Size-1];\n    }   \n\n    public String Code()\n    {\n        return S7.GetStringAt(Buffer, 2, 20);\n    }\n}\n"
  },
  {
    "path": "target-platform/org.moka7/src/main/java/Moka7/S7Protection.java",
    "content": "/*=============================================================================|\n|  PROJECT Moka7                                                         1.0.2 |\n|==============================================================================|\n|  Copyright (C) 2013, 2016 Davide Nardella                                    |\n|  All rights reserved.                                                        |\n|==============================================================================|\n|  SNAP7 is free software: you can redistribute it and/or modify               |\n|  it under the terms of the Lesser GNU General Public License as published by |\n|  the Free Software Foundation, either version 3 of the License, or under     |\n|  EPL Eclipse Public License 1.0.                                             |\n|                                                                              |\n|  This means that you have to chose in advance which take before you import   |\n|  the library into your project.                                              |\n|                                                                              |\n|  SNAP7 is distributed in the hope that it will be useful,                    |\n|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |\n|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you    |\n|  decide to adopt.                                                            |\n|                                                                              |\n|=============================================================================*/\npackage Moka7;\n\n// See §33.19 of \"System Software for S7-300/400 System and Standard Functions\"\npublic class S7Protection {\n   public int sch_schal;\n   public int sch_par;\n   public int sch_rel;\n   public int bart_sch;\n   public int anl_sch;\n   protected void Update(byte[] Src)\n   {\n       sch_schal = S7.GetWordAt(Src,2);\n       sch_par   = S7.GetWordAt(Src,4);\n       sch_rel   = S7.GetWordAt(Src,6);\n       bart_sch  = S7.GetWordAt(Src,8);\n       anl_sch   = S7.GetWordAt(Src,10);\n   }\n}\n"
  },
  {
    "path": "target-platform/org.moka7/src/main/java/Moka7/S7Szl.java",
    "content": "/*=============================================================================|\n|  PROJECT Moka7                                                         1.0.2 |\n|==============================================================================|\n|  Copyright (C) 2013, 2016 Davide Nardella                                    |\n|  All rights reserved.                                                        |\n|==============================================================================|\n|  SNAP7 is free software: you can redistribute it and/or modify               |\n|  it under the terms of the Lesser GNU General Public License as published by |\n|  the Free Software Foundation, either version 3 of the License, or under     |\n|  EPL Eclipse Public License 1.0.                                             |\n|                                                                              |\n|  This means that you have to chose in advance which take before you import   |\n|  the library into your project.                                              |\n|                                                                              |\n|  SNAP7 is distributed in the hope that it will be useful,                    |\n|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |\n|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you    |\n|  decide to adopt.                                                            |\n|                                                                              |\n|=============================================================================*/\npackage Moka7;\n\n/**\n *\n * @author Davide\n */\npublic class S7Szl {\n    \n    public int LENTHDR;\n    public int N_DR;\n    public int DataSize;\n    public byte Data[];\n    \n    public S7Szl(int BufferSize)\n    {\n        Data = new byte[BufferSize];\n    }\n    protected void Copy(byte[] Src, int SrcPos, int DestPos, int Size)\n    {\n        System.arraycopy(Src, SrcPos, Data, DestPos, Size);\n    }   \n}\n"
  },
  {
    "path": "target-platform/org.usb4java/.gitignore",
    "content": "lib/\nMETA-INF\n"
  },
  {
    "path": "target-platform/org.usb4java/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n\t\t\n\t\t<h3>Third Party Content</h3>\n\t\t<p>The Content includes items that have been sourced from third parties as set out below. If you \n\t\tdid not receive this Content directly from the Eclipse Foundation, the following is provided \n\t\tfor informational purposes only, and you should look to the Redistributor's license for \n\t\tterms and conditions of use.</p>\n\t\t<p><em>\n\t\t<strong>javax.usb.common-1.0.2.jar</strong> <br/><br/>\n\t\tCommon Public License 1.0\n\t\t</em></p>\n\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/org.usb4java/about_files/cpl-v10.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n<HTML>\n<HEAD>\n<TITLE>Common Public License - v 1.0</TITLE>\n<meta http-equiv=Content-Type content=\"text/html; charset=ISO-8859-1\">\n</HEAD>\n\n<BODY BGCOLOR=\"#FFFFFF\" VLINK=\"#800000\">\n\n\n<P ALIGN=\"CENTER\"><B>Common Public License - v 1.0</B>\n\n<P><FONT SIZE=\"2\"><B>Updated 16 Apr 2009</B></FONT>\n\n<P><FONT SIZE=\"2\"><B>As of 25 Feb 2009, IBM has assigned the Agreement Steward role for the CPL to the Eclipse Foundation. \nEclipse has designated the Eclipse Public License (EPL) as the follow-on version of the CPL.</B></FONT>\n\n<P><B></B><FONT SIZE=\"3\"></FONT>\n<P><FONT SIZE=\"3\"></FONT><FONT SIZE=\"2\">THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE (\"AGREEMENT\").  ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"><B>1.  DEFINITIONS</B></FONT>\n<P><FONT SIZE=\"2\">\"Contribution\" means:</FONT>\n\n<UL><FONT SIZE=\"2\">a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and<BR CLEAR=\"LEFT\">\nb) in the case of each subsequent Contributor:</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">i)\t \tchanges to the Program, and</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">ii)\t\tadditions to the Program;</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.  </FONT><FONT SIZE=\"2\">A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf.  </FONT><FONT SIZE=\"2\">Contributions do not include additions to the Program which:  (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.  </FONT></UL>\n\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">\"Contributor\" means any person or entity that distributes the Program.</FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">\"Licensed Patents \" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.  </FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">\"Program\" means the Contributions distributed in accordance with this Agreement.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">\"Recipient\" means anyone who receives the Program under this Agreement, including all Contributors.</FONT>\n<P><FONT SIZE=\"2\"><B></B></FONT>\n<P><FONT SIZE=\"2\"><B>2.  GRANT OF RIGHTS</B></FONT>\n\n<UL><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">a)\t</FONT><FONT SIZE=\"2\">Subject to the terms of this Agreement, each Contributor hereby grants</FONT><FONT SIZE=\"2\"> Recipient a non-exclusive, worldwide, royalty-free copyright license to</FONT><FONT SIZE=\"2\" COLOR=\"#FF0000\"> </FONT><FONT SIZE=\"2\">reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">b) \tSubject to the terms of this Agreement, each Contributor hereby grants </FONT><FONT SIZE=\"2\">Recipient a non-exclusive, worldwide,</FONT><FONT SIZE=\"2\" COLOR=\"#008000\"> </FONT><FONT SIZE=\"2\">royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form.  This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents.  The patent license shall not apply to any other combinations which include the Contribution.  No hardware per se is licensed hereunder.   </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">c)\tRecipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity.  Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise.  As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any.  For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">d)\tEach Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT></UL>\n\n<P><FONT SIZE=\"2\"><B>3.  REQUIREMENTS</B></FONT>\n<P><FONT SIZE=\"2\"><B></B>A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:</FONT>\n\n<UL><FONT SIZE=\"2\">a)\tit complies with the terms and conditions of this Agreement; and</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">b)\tits license agreement:</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">i)\teffectively disclaims</FONT><FONT SIZE=\"2\"> on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">ii) \teffectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">iii)</FONT><FONT SIZE=\"2\">\tstates that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">iv)\tstates that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.</FONT><FONT SIZE=\"2\" COLOR=\"#0000FF\"> </FONT><FONT SIZE=\"2\" COLOR=\"#FF0000\"></FONT></UL>\n\n\n<UL><FONT SIZE=\"2\" COLOR=\"#FF0000\"></FONT><FONT SIZE=\"2\"></FONT></UL>\n\n<P><FONT SIZE=\"2\">When the Program is made available in source code form:</FONT>\n\n<UL><FONT SIZE=\"2\">a)\tit must be made available under this Agreement; and </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">b)\ta copy of this Agreement must be included with each copy of the Program.  </FONT></UL>\n\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\" COLOR=\"#0000FF\"><STRIKE></STRIKE></FONT>\n<P><FONT SIZE=\"2\" COLOR=\"#0000FF\"><STRIKE></STRIKE></FONT><FONT SIZE=\"2\">Contributors may not remove or alter any copyright notices contained within the Program.  </FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.  </FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"><B>4.  COMMERCIAL DISTRIBUTION</B></FONT>\n<P><FONT SIZE=\"2\">Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like.  While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors.   Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (\"Commercial Contributor\") hereby agrees to defend and indemnify every other Contributor (\"Indemnified Contributor\") against any losses, damages and costs (collectively \"Losses\") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering.  The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement.  In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations.  The Indemnified Contributor may participate in any such claim at its own expense.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">For example, a Contributor might include the Program in a commercial product offering, Product X.  That Contributor is then a Commercial Contributor.  If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone.  Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.</FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\" COLOR=\"#0000FF\"></FONT>\n<P><FONT SIZE=\"2\" COLOR=\"#0000FF\"></FONT><FONT SIZE=\"2\"><B>5.  NO WARRANTY</B></FONT>\n<P><FONT SIZE=\"2\">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is</FONT><FONT SIZE=\"2\"> solely responsible for determining the appropriateness of using and distributing </FONT><FONT SIZE=\"2\">the Program</FONT><FONT SIZE=\"2\"> and assumes all risks associated with its exercise of rights under this Agreement</FONT><FONT SIZE=\"2\">, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, </FONT><FONT SIZE=\"2\">programs or equipment, and unavailability or interruption of operations</FONT><FONT SIZE=\"2\">.  </FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"><B>6.  DISCLAIMER OF LIABILITY</B></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES </FONT><FONT SIZE=\"2\">(INCLUDING WITHOUT LIMITATION LOST PROFITS),</FONT><FONT SIZE=\"2\"> HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"><B>7.  GENERAL</B></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed.  In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. </FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance.  If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable.  However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.  </FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted  and may only be modified in the following manner. The Agreement Steward reserves the right to </FONT><FONT SIZE=\"2\">publish new versions (including revisions) of this Agreement from time to </FONT><FONT SIZE=\"2\">time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward.   IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity.  </FONT><FONT SIZE=\"2\">Each new version of the Agreement will be given a distinguishing version number.  The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new </FONT><FONT SIZE=\"2\">version.  </FONT><FONT SIZE=\"2\">Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, </FONT><FONT SIZE=\"2\">by implication, estoppel or otherwise</FONT><FONT SIZE=\"2\">.</FONT><FONT SIZE=\"2\">  All rights in the Program not expressly granted under this Agreement are reserved.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose.  Each party waives its rights to a jury trial in any resulting litigation.</FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT>\n\n</BODY>\n\n</HTML>"
  },
  {
    "path": "target-platform/org.usb4java/build.properties",
    "content": "output.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               lib/\n"
  },
  {
    "path": "target-platform/org.usb4java/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2015, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>target-platform</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n    <artifactId>org.usb4java</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>bundle</packaging>\n    <name>usb4java</name>\n    <description>usb4java libraries using libusb</description>\n    <url>usb4java.org/</url>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.usb4java</groupId>\n            <artifactId>usb4java</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>*</groupId>\n                    <artifactId>*</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.usb4java</groupId>\n            <artifactId>libusb4java</artifactId>\n            <classifier>linux-aarch64</classifier>\n            <exclusions>\n                <exclusion>\n                    <groupId>*</groupId>\n                    <artifactId>*</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.usb4java</groupId>\n            <artifactId>libusb4java</artifactId>\n            <classifier>linux-x86-64</classifier>\n            <exclusions>\n                <exclusion>\n                    <groupId>*</groupId>\n                    <artifactId>*</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-clean-plugin</artifactId>\n                <configuration>\n                    <verbose>true</verbose>\n                    <filesets>\n                        <fileset>\n                            <directory>lib/</directory>\n                            <followSymlinks>false</followSymlinks>\n                        </fileset>\n                    </filesets>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <outputDirectory>${project.basedir}/lib</outputDirectory>\n                            <excludeClassifiers>\n                                sources,osx-x86_64,osx-x86,osx-aarch_64,windows-x86,windows-x86_64,linux-x86,linux-arm\n                            </excludeClassifiers>\n                            <excludeTransitive>true</excludeTransitive>\n                            <stripVersion>true</stripVersion>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>2.3.5</version> <!-- This exact version is required to be built properly -->\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Name>${project.name}</Bundle-Name>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Bundle-ClassPath>\n                            .,libusb4java-linux-aarch64.jar,libusb4java-linux-x86-64.jar,usb4java.jar</Bundle-ClassPath>\n                        <Include-Resource>\n                            ${project.basedir}/lib,\n                            ${project.basedir}/about.html,\n                            about_files=${project.basedir}/about_files/\n                        </Include-Resource>\n                        <Export-Package>\n                            org.usb4java.linux-aarch64;version=\"${usb4java.version}\",\n                            org.usb4java.linux-x86-64;version=\"${usb4java.version}\",\n                            org.usb4java;uses:=\"org.apache.commons.lang3.builder,org.apache.commons.lang3.tuple\";version=\"${usb4java.version}\"\n                        </Export-Package>\n                        <Require-Capability>\n                            osgi.ee;filter:=\"(&amp;(osgi.ee=JavaSE)(version=21))\"\n                        </Require-Capability>\n                    </instructions>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others\n  \n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n \n    SPDX-License-Identifier: EPL-2.0\n \n    Contributors:\n     Eurotech\n     Red Hat Inc\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n    <groupId>org.eclipse.kura</groupId>\n    <artifactId>target-platform</artifactId>\n    <version>6.0.0-SNAPSHOT</version>\n\n    <packaging>pom</packaging>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <check.plugins.exist.remote>false</check.plugins.exist.remote>\n        <kura.addons.url>https://artifactory.dev.everyware.io/artifactory/kura-addons</kura.addons.url>\n\n        <maven.compiler.release>21</maven.compiler.release>\n\n        <!-- Plugins versions -->\n        <exists-maven-plugin.version>0.0.3</exists-maven-plugin.version>\n        <lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>\n        <maven-antrun-plugin.version>1.8</maven-antrun-plugin.version>\n        <maven-bundle-plugin.version>5.1.8</maven-bundle-plugin.version>\n        <maven-clean-plugin.version>2.4.1</maven-clean-plugin.version>\n        <maven-compiler-plugin.version>3.15.0</maven-compiler-plugin.version>\n        <maven-checkstyle-plugin.version>2.17</maven-checkstyle-plugin.version>\n        <maven-dependency-plugin.version>3.0.0</maven-dependency-plugin.version>\n        <maven-deploy-plugin.version>2.8.1</maven-deploy-plugin.version>\n        <maven-site-plugin.version>3.3</maven-site-plugin.version>\n        <maven-surefire-plugin.version>2.7.2</maven-surefire-plugin.version>\n\n        <!-- dependencies versions -->\n        <commons-fileupload.version>2.0.0-M4</commons-fileupload.version>\n        <hk2.version>3.1.1</hk2.version>\n        <io.netty.version>4.1.130.Final</io.netty.version>\n        <jersey.version>3.1.11</jersey.version>\n        <log4j.version>2.25.3</log4j.version>\n        <org.apache.camel.version>2.25.3</org.apache.camel.version>\n        <org.bouncycastle.version>1.78.1</org.bouncycastle.version>\n        <org.eclipse.jetty.version>12.0.14</org.eclipse.jetty.version>\n        <org.eclipse.osgi-technology.rest.version>1.2.3</org.eclipse.osgi-technology.rest.version>\n        <org.ow2.asm.version>9.7.1</org.ow2.asm.version>\n        <slf4j.version>2.0.17</slf4j.version>\n        <spring.version>4.3.20.RELEASE_1</spring.version>\n        <jackson.core.version>2.19.2</jackson.core.version>\n        <byte-buddy.version>1.17.7</byte-buddy.version>\n        <objenesis.version>3.3</objenesis.version>\n        <mockito.version>5.21.0</mockito.version>\n        <org.hamcrest.version>1.1.0.v20090501071000</org.hamcrest.version>\n        <usb4java.version>1.3.0</usb4java.version>\n        <usb-api.version>1.0.2</usb-api.version>\n    </properties>\n\n    <modules>\n        <module>target-platform-pde-deps</module>\n        <module>org.eclipse.kura.camel.sun.misc</module>\n        <module>org.eclipse.kura.sun.misc</module>\n        <module>com.codeminders.hidapi-parent</module>\n        <module>org.usb4java</module>\n        <module>usb4java-javax</module>\n        <module>org.moka7</module>\n        <module>org.eclipse.soda.dk.comm-parent</module>\n        <module>log4j2-api-config</module>\n    </modules>\n\n    <repositories>\n        <repository>\n            <id>Kura Releases</id>\n            <name>Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </repository>\n        <repository>\n            <id>Kura Snapshots</id>\n            <name>Kura Repository - Snapshots</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </repository>\n        <repository>\n            <id>kura_addons</id>\n            <name>Kura Addons Maven Repository</name>\n            <url>${kura.addons.url}</url>\n            <snapshots>\n                <enabled>true</enabled>\n                <updatePolicy>always</updatePolicy>\n            </snapshots>\n        </repository>\n        <repository>\n            <id>Eclipse Paho Repo</id>\n            <url>https://repo.eclipse.org/content/repositories/paho-releases/</url>\n        </repository>\n        <repository>\n            <!-- moquette-broker -->\n            <id>jitpack.io</id>\n            <url>https://jitpack.io</url>\n        </repository>\n    </repositories>\n\n    <distributionManagement>\n        <repository>\n            <id>repo.eclipse.org</id>\n            <name>Kura Repository - Releases</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-releases/</url>\n        </repository>\n        <snapshotRepository>\n            <id>repo.eclipse.org</id>\n            <name>Kura Repository - Snapshots</name>\n            <url>https://repo.eclipse.org/content/repositories/kura-snapshots/</url>\n        </snapshotRepository>\n    </distributionManagement>\n\n    <dependencyManagement>\n        <dependencies>\n            <!-- START target platform wrapped dependencies -->\n            <dependency>\n                <groupId>org.usb4java</groupId>\n                <artifactId>usb4java</artifactId>\n                <version>${usb4java.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.usb4java</groupId>\n                <artifactId>libusb4java</artifactId>\n                <version>${usb4java.version}</version>\n                <classifier>linux-aarch64</classifier>\n            </dependency>\n            <dependency>\n                <groupId>org.usb4java</groupId>\n                <artifactId>libusb4java</artifactId>\n                <version>${usb4java.version}</version>\n                <classifier>linux-x86-64</classifier>\n            </dependency>\n            <dependency>\n                <groupId>javax.usb</groupId>\n                <artifactId>usb-api</artifactId>\n                <version>${usb-api.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.usb4java</groupId>\n                <artifactId>usb4java-javax</artifactId>\n                <version>${usb4java.version}</version>\n            </dependency>\n            <!-- END target platform wrapped dependencies -->\n            <!-- START common dependencies -->\n            <dependency>\n                <groupId>commons-net</groupId>\n                <artifactId>commons-net</artifactId>\n                <version>3.8.0</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.protobuf</groupId>\n                <artifactId>protobuf-java</artifactId>\n                <version>4.30.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.paho</groupId>\n                <artifactId>org.eclipse.paho.client.mqttv3</artifactId>\n                <version>1.2.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hamcrest</groupId>\n                <artifactId>org.hamcrest.core</artifactId>\n                <version>1.3.0.v201303031735</version>\n            </dependency>\n            <dependency>\n                <groupId>com.h2database</groupId>\n                <artifactId>h2</artifactId>\n                <version>2.4.240</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>slf4j-api</artifactId>\n                <version>${slf4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>jcl-over-slf4j</artifactId>\n                <version>${slf4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>jul-to-slf4j</artifactId>\n                <version>${slf4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.logging.log4j</groupId>\n                <artifactId>log4j-api</artifactId>\n                <version>${log4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.logging.log4j</groupId>\n                <artifactId>log4j-core</artifactId>\n                <version>${log4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.logging.log4j</groupId>\n                <artifactId>log4j-slf4j2-impl</artifactId>\n                <version>${log4j.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-fileupload2-jakarta-servlet5</artifactId>\n                <version>${commons-fileupload.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-fileupload2-core</artifactId>\n                <version>${commons-fileupload.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-exec</artifactId>\n                <version>1.3</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-io</groupId>\n                <artifactId>commons-io</artifactId>\n                <version>2.19.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-lang3</artifactId>\n                <version>3.19.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-csv</artifactId>\n                <version>1.4</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.camel</groupId>\n                <artifactId>camel-amqp</artifactId>\n                <version>${org.apache.camel.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.camel</groupId>\n                <artifactId>camel-core</artifactId>\n                <version>${org.apache.camel.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.camel</groupId>\n                <artifactId>camel-core-osgi</artifactId>\n                <version>${org.apache.camel.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.camel</groupId>\n                <artifactId>camel-jms</artifactId>\n                <version>${org.apache.camel.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.camel</groupId>\n                <artifactId>camel-script</artifactId>\n                <version>${org.apache.camel.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.camel</groupId>\n                <artifactId>camel-stream</artifactId>\n                <version>${org.apache.camel.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.qpid</groupId>\n                <artifactId>qpid-jms-client</artifactId>\n                <version>0.45.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.qpid</groupId>\n                <artifactId>proton-j</artifactId>\n                <version>0.33.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.servicemix.bundles</groupId>\n                <artifactId>org.apache.servicemix.bundles.spring-beans</artifactId>\n                <version>${spring.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.servicemix.bundles</groupId>\n                <artifactId>org.apache.servicemix.bundles.spring-context</artifactId>\n                <version>${spring.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.servicemix.bundles</groupId>\n                <artifactId>org.apache.servicemix.bundles.spring-core</artifactId>\n                <version>${spring.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.servicemix.bundles</groupId>\n                <artifactId>org.apache.servicemix.bundles.spring-expression</artifactId>\n                <version>${spring.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.servicemix.bundles</groupId>\n                <artifactId>org.apache.servicemix.bundles.spring-jms</artifactId>\n                <version>${spring.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.servicemix.bundles</groupId>\n                <artifactId>org.apache.servicemix.bundles.spring-tx</artifactId>\n                <version>${spring.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>osgi.annotation</artifactId>\n                <version>8.1.0</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.code.gson</groupId>\n                <artifactId>gson</artifactId>\n                <version>2.9.0</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.guava</groupId>\n                <artifactId>guava</artifactId>\n                <version>32.1.1-jre</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.guava</groupId>\n                <artifactId>failureaccess</artifactId>\n                <version>1.0.1</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-buffer</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-codec</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-codec-http</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-codec-mqtt</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-common</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-handler</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-resolver</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-transport</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-transport-native-epoll</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-transport-classes-epoll</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-transport-classes-kqueue</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-transport-native-kqueue</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-transport-native-unix-common</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-codec-socks</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-handler-proxy</artifactId>\n                <version>${io.netty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.hk2</groupId>\n                <artifactId>osgi-resource-locator</artifactId>\n                <version>1.0.3</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.useradmin</artifactId>\n                <version>1.0.4.k1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.bouncycastle</groupId>\n                <artifactId>bcpkix-jdk18on</artifactId>\n                <version>${org.bouncycastle.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.bouncycastle</groupId>\n                <artifactId>bcprov-jdk18on</artifactId>\n                <version>${org.bouncycastle.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.bouncycastle</groupId>\n                <artifactId>bctls-jdk18on</artifactId>\n                <version>${org.bouncycastle.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.bouncycastle</groupId>\n                <artifactId>bcutil-jdk18on</artifactId>\n                <version>${org.bouncycastle.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.bouncycastle</groupId>\n                <artifactId>bcpg-jdk18on</artifactId>\n                <version>${org.bouncycastle.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.servicemix.bundles</groupId>\n                <artifactId>org.apache.servicemix.bundles.c3p0</artifactId>\n                <version>0.9.5.5_1</version>\n            </dependency>\n            <dependency>\n                <groupId>com.zaxxer</groupId>\n                <artifactId>HikariCP</artifactId>\n                <version>2.7.9</version>\n            </dependency>\n            <dependency>\n                <groupId>org.quartz-scheduler</groupId>\n                <artifactId>quartz</artifactId>\n                <version>2.5.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.xerial</groupId>\n                <artifactId>sqlite-jdbc</artifactId>\n                <version>3.42.0.0</version>\n            </dependency>\n            <dependency>\n                <groupId>com.eclipsesource.minimal-json</groupId>\n                <artifactId>minimal-json</artifactId>\n                <version>0.9.5</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.dependencymanager</artifactId>\n                <version>3.0.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.deploymentadmin</artifactId>\n                <version>0.9.5</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.http.servlet-api</artifactId>\n                <version>3.0.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.http.bridge</artifactId>\n                <version>5.1.8</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.http.proxy</artifactId>\n                <version>4.0.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.http.wrappers</artifactId>\n                <version>1.1.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.knowhowlab.osgi</groupId>\n                <artifactId>monitoradmin</artifactId>\n                <version>1.0.3</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.jetty</groupId>\n                <artifactId>jetty-http</artifactId>\n                <version>${org.eclipse.jetty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.jetty</groupId>\n                <artifactId>jetty-security</artifactId>\n                <version>${org.eclipse.jetty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.jetty</groupId>\n                <artifactId>jetty-server</artifactId>\n                <version>${org.eclipse.jetty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.jetty</groupId>\n                <artifactId>jetty-session</artifactId>\n                <version>${org.eclipse.jetty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.jetty</groupId>\n                <artifactId>jetty-util</artifactId>\n                <version>${org.eclipse.jetty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.jetty</groupId>\n                <artifactId>jetty-io</artifactId>\n                <version>${org.eclipse.jetty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.jetty.ee10</groupId>\n                <artifactId>jetty-ee10-servlet</artifactId>\n                <version>${org.eclipse.jetty.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.http.whiteboard</artifactId>\n                <version>1.1.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.servlet</artifactId>\n                <version>2.0.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.osgi-technology.rest</groupId>\n                <artifactId>org.eclipse.osgitech.rest</artifactId>\n                <version>${org.eclipse.osgi-technology.rest.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.osgi-technology.rest</groupId>\n                <artifactId>org.eclipse.osgitech.rest.sse</artifactId>\n                <version>${org.eclipse.osgi-technology.rest.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.osgi-technology.rest</groupId>\n                <artifactId>org.eclipse.osgitech.rest.servlet.whiteboard</artifactId>\n                <version>${org.eclipse.osgi-technology.rest.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.aries.spifly</groupId>\n                <artifactId>org.apache.aries.spifly.dynamic.bundle</artifactId>\n                <version>1.3.7</version>\n            </dependency>\n            <dependency>\n                <groupId>org.ow2.asm</groupId>\n                <artifactId>asm</artifactId>\n                <version>${org.ow2.asm.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.ow2.asm</groupId>\n                <artifactId>asm-commons</artifactId>\n                <version>${org.ow2.asm.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.ow2.asm</groupId>\n                <artifactId>asm-tree</artifactId>\n                <version>${org.ow2.asm.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.ow2.asm</groupId>\n                <artifactId>asm-util</artifactId>\n                <version>${org.ow2.asm.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.ow2.asm</groupId>\n                <artifactId>asm-analysis</artifactId>\n                <version>${org.ow2.asm.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.hk2</groupId>\n                <artifactId>hk2-api</artifactId>\n                <version>${hk2.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.hk2.external</groupId>\n                <artifactId>aopalliance-repackaged</artifactId>\n                <version>${hk2.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.hk2</groupId>\n                <artifactId>hk2-locator</artifactId>\n                <version>${hk2.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.hk2</groupId>\n                <artifactId>hk2-utils</artifactId>\n                <version>${hk2.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.inject</groupId>\n                <artifactId>jersey-hk2</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.containers</groupId>\n                <artifactId>jersey-container-servlet</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.containers</groupId>\n                <artifactId>jersey-container-servlet-core</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.core</groupId>\n                <artifactId>jersey-client</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.core</groupId>\n                <artifactId>jersey-common</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.core</groupId>\n                <artifactId>jersey-server</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.ext</groupId>\n                <artifactId>jersey-entity-filtering</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.media</groupId>\n                <artifactId>jersey-media-jaxb</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.media</groupId>\n                <artifactId>jersey-media-sse</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.glassfish.jersey.media</groupId>\n                <artifactId>jersey-media-multipart</artifactId>\n                <version>${jersey.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.javassist</groupId>\n                <artifactId>javassist</artifactId>\n                <version>3.30.2-GA</version>\n            </dependency>\n            <dependency>\n                <groupId>org.jvnet.mimepull</groupId>\n                <artifactId>mimepull</artifactId>\n                <version>1.10.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.component.annotations</artifactId>\n                <version>1.5.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.metatype.annotations</artifactId>\n                <version>1.4.1</version>\n            </dependency>\n            <dependency>\n                <groupId>com.fasterxml.jackson.core</groupId>\n                <artifactId>jackson-databind</artifactId>\n                <version>${jackson.core.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.fasterxml.jackson.core</groupId>\n                <artifactId>jackson-annotations</artifactId>\n                <version>${jackson.core.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.fasterxml.jackson.core</groupId>\n                <artifactId>jackson-core</artifactId>\n                <version>${jackson.core.version}</version>\n            </dependency>\n            <!-- END common dependencies -->\n            <!-- START Artemis and Camel common dependencies -->\n            <dependency>\n                <groupId>org.apache.geronimo.specs</groupId>\n                <artifactId>geronimo-jms_2.0_spec</artifactId>\n                <version>1.0-alpha-2</version>\n            </dependency>\n            <!-- END Artemis and Camel common dependencies -->\n            <!-- START Jakarta dependencies -->\n            <dependency>\n                <groupId>jakarta.inject</groupId>\n                <artifactId>jakarta.inject-api</artifactId>\n                <version>2.0.1</version>\n            </dependency>\n            <dependency>\n                <groupId>jakarta.validation</groupId>\n                <artifactId>jakarta.validation-api</artifactId>\n                <version>3.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>jakarta.xml.bind</groupId>\n                <artifactId>jakarta.xml.bind-api</artifactId>\n                <version>4.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>jakarta.activation</groupId>\n                <artifactId>jakarta.activation-api</artifactId>\n                <version>2.1.2</version>\n            </dependency>\n            <dependency>\n                <groupId>jakarta.annotation</groupId>\n                <artifactId>jakarta.annotation-api</artifactId>\n                <version>2.1.1</version>\n            </dependency>\n            <dependency>\n                <groupId>jakarta.xml.ws</groupId>\n                <artifactId>jakarta.xml.ws-api</artifactId>\n                <version>4.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>jakarta.xml.soap</groupId>\n                <artifactId>jakarta.xml.soap-api</artifactId>\n                <version>3.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>com.sun.xml.bind</groupId>\n                <artifactId>jaxb-osgi</artifactId>\n                <version>4.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>jakarta.ws.rs</groupId>\n                <artifactId>jakarta.ws.rs-api</artifactId>\n                <version>3.1.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.jakartars</artifactId>\n                <version>2.0.0</version>\n            </dependency>\n            <!-- END Jakarta dependencies -->\n            <!-- START Equinox dependencies -->\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.cm</artifactId>\n                <version>1.6.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.component</artifactId>\n                <version>1.5.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.coordinator</artifactId>\n                <version>1.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.device</artifactId>\n                <version>1.1.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.event</artifactId>\n                <version>1.4.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.log.stream</artifactId>\n                <version>1.0.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.metatype</artifactId>\n                <version>1.4.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.prefs</artifactId>\n                <version>1.1.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.provisioning</artifactId>\n                <version>1.2.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.upnp</artifactId>\n                <version>1.2.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.useradmin</artifactId>\n                <version>1.1.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.service.wireadmin</artifactId>\n                <version>1.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.util.function</artifactId>\n                <version>1.2.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.util.measurement</artifactId>\n                <version>1.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.util.position</artifactId>\n                <version>1.0.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.util.promise</artifactId>\n                <version>1.3.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.util.pushstream</artifactId>\n                <version>1.1.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.osgi</groupId>\n                <artifactId>org.osgi.util.xml</artifactId>\n                <version>1.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.cm</artifactId>\n                <version>1.6.100</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.common</artifactId>\n                <version>3.19.100</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.console</artifactId>\n                <version>1.4.800</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.registry</artifactId>\n                <version>3.12.100</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.event</artifactId>\n                <version>1.7.100</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.io</artifactId>\n                <version>1.1.300</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.metatype</artifactId>\n                <version>1.6.600</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.launcher</artifactId>\n                <version>1.6.900</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.util</artifactId>\n                <version>1.1.300</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.wireadmin</artifactId>\n                <version>1.0.800</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.scr</artifactId>\n                <version>2.2.12</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.core.runtime</artifactId>\n                <version>3.31.100</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.core.jobs</artifactId>\n                <version>3.15.400</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.preferences</artifactId>\n                <version>3.11.100</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.core.contenttype</artifactId>\n                <version>3.9.500</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.equinox.app</artifactId>\n                <version>1.7.200</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.osgi</artifactId>\n                <version>3.21.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.platform</groupId>\n                <artifactId>org.eclipse.osgi.util</artifactId>\n                <version>3.7.300</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.gogo.command</artifactId>\n                <version>1.1.2</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.gogo.runtime</artifactId>\n                <version>1.1.6</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.apache.felix.gogo.shell</artifactId>\n                <version>1.1.4</version>\n            </dependency>\n            <!-- END Equinox dependencies -->\n            <!-- START test dependencies -->\n            <dependency>\n                <groupId>org.junit</groupId>\n                <artifactId>org.junit</artifactId>\n                <version>4.12.0.v201504281640</version>\n            </dependency>\n            <dependency>\n                <groupId>io.dropwizard.metrics</groupId>\n                <artifactId>metrics-core</artifactId>\n                <version>3.2.2</version>\n            </dependency>\n            <dependency>\n                <groupId>com.github.moquette-io.moquette</groupId>\n                <artifactId>moquette-broker</artifactId>\n                <version>0.18.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hamcrest</groupId>\n                <artifactId>org.hamcrest</artifactId>\n                <version>${org.hamcrest.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hamcrest</groupId>\n                <artifactId>org.hamcrest.integration</artifactId>\n                <version>1.1.0.v201303031500</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hamcrest</groupId>\n                <artifactId>org.hamcrest.library</artifactId>\n                <version>${org.hamcrest.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hamcrest</groupId>\n                <artifactId>org.hamcrest.text</artifactId>\n                <version>${org.hamcrest.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.mockito</groupId>\n                <artifactId>mockito-core</artifactId>\n                <version>${mockito.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>net.bytebuddy</groupId>\n                <artifactId>byte-buddy</artifactId>\n                <version>${byte-buddy.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>net.bytebuddy</groupId>\n                <artifactId>byte-buddy-agent</artifactId>\n                <version>${byte-buddy.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.objenesis</groupId>\n                <artifactId>objenesis</artifactId>\n                <version>${objenesis.version}</version>\n            </dependency>\n            <!-- END test dependencies -->\n            <!-- START Kura target platform BOM -->\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>com.codeminders.hidapi</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>com.codeminders.hidapi.x86_64</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>com.codeminders.hidapi.aarch64</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>log4j2-api-config</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.camel.sun.misc</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.kura.sun.misc</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.soda.dk.comm</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.soda.dk.comm.x86_64</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.eclipse.soda.dk.comm.aarch64</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.moka7</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>org.usb4java</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <dependency>\n                <groupId>org.eclipse.kura</groupId>\n                <artifactId>usb4java-javax</artifactId>\n                <version>2.0.0-SNAPSHOT</version>\n            </dependency>\n            <!-- END Kura target platform BOM -->\n        </dependencies>\n    </dependencyManagement>\n\n    <profiles>\n        <profile>\n            <id>check-exists-plugin</id>\n            <properties>\n                <check.plugins.exist.remote>true</check.plugins.exist.remote>\n            </properties>\n        </profile>\n    </profiles>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-site-plugin</artifactId>\n                <version>${maven-site-plugin.version}</version>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-deploy-plugin</artifactId>\n                <version>${maven-deploy-plugin.version}</version>\n                <configuration>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <version>${maven-checkstyle-plugin.version}</version>\n                <dependencies>\n                    <dependency>\n                        <groupId>org.slf4j</groupId>\n                        <artifactId>jcl-over-slf4j</artifactId>\n                        <version>1.7.36</version>\n                    </dependency>\n                    <dependency>\n                        <groupId>org.slf4j</groupId>\n                        <artifactId>slf4j-jdk14</artifactId>\n                        <version>1.7.36</version>\n                    </dependency>\n                </dependencies>\n                <executions>\n                    <execution>\n                        <id>checkstyle-validation</id>\n                        <phase>process-sources</phase>\n                        <configuration>\n                            <encoding>UTF-8</encoding>\n                            <consoleOutput>true</consoleOutput>\n                            <failsOnError>true</failsOnError>\n                            <linkXRef>false</linkXRef>\n                            <configLocation>../checkstyle_checks.xml</configLocation>\n                        </configuration>\n                        <goals>\n                            <goal>check</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <groupId>org.honton.chas</groupId>\n                <artifactId>exists-maven-plugin</artifactId>\n                <version>${exists-maven-plugin.version}</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>remote</goal>\n                        </goals>\n                        <configuration>\n                            <skipIfSnapshot>true</skipIfSnapshot>\n                            <failIfExists>${check.plugins.exist.remote}</failIfExists>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n        </plugins>\n\n        <pluginManagement>\n            <plugins>\n                <plugin>\n                    <groupId>org.apache.felix</groupId>\n                    <artifactId>maven-bundle-plugin</artifactId>\n                    <version>${maven-bundle-plugin.version}</version>\n                </plugin>\n                <plugin>\n                    <groupId>org.eclipse.m2e</groupId>\n                    <artifactId>lifecycle-mapping</artifactId>\n                    <version>${lifecycle-mapping.version}</version>\n                    <configuration>\n                        <lifecycleMappingMetadata>\n                            <pluginExecutions>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.jacoco\n                                        </groupId>\n                                        <artifactId>\n                                            jacoco-maven-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [0.6.4.201312101107,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>\n                                                prepare-agent\n                                            </goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.apache.maven.plugins\n                                        </groupId>\n                                        <artifactId>\n                                            maven-dependency-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [2.1,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>\n                                                copy-dependencies\n                                            </goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.apache.maven.plugins\n                                        </groupId>\n                                        <artifactId>\n                                            maven-antrun-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [1.7,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>run</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.codehaus.mojo\n                                        </groupId>\n                                        <artifactId>\n                                            build-helper-maven-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [1.9,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>regex-property</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.apache.maven.plugins\n                                        </groupId>\n                                        <artifactId>\n                                            maven-checkstyle-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [2.14,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>check</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                                <pluginExecution>\n                                    <pluginExecutionFilter>\n                                        <groupId>\n                                            org.codehaus.mojo\n                                        </groupId>\n                                        <artifactId>\n                                            exec-maven-plugin\n                                        </artifactId>\n                                        <versionRange>\n                                            [1.2,)\n                                        </versionRange>\n                                        <goals>\n                                            <goal>exec</goal>\n                                        </goals>\n                                    </pluginExecutionFilter>\n                                    <action>\n                                        <ignore></ignore>\n                                    </action>\n                                </pluginExecution>\n                            </pluginExecutions>\n                        </lifecycleMappingMetadata>\n                    </configuration>\n                </plugin>\n            </plugins>\n        </pluginManagement>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/target-platform-pde-deps/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<!-- // Content with portions generated by generative AI platform -->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\n    <modelVersion>4.0.0</modelVersion>\n\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>target-platform</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n\n    <groupId>org.eclipse.kura</groupId>\n    <artifactId>target-platform-pde-deps</artifactId>\n    <packaging>pom</packaging>\n    <name>Kura target platform PDE Dependencies</name>\n\n    <!-- dependencies available in target definition -->\n    <dependencies>\n        <!-- START common dependencies -->\n        <dependency>\n            <groupId>commons-net</groupId>\n            <artifactId>commons-net</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.google.protobuf</groupId>\n            <artifactId>protobuf-java</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.paho</groupId>\n            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.hamcrest</groupId>\n            <artifactId>org.hamcrest.core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>jcl-over-slf4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>jul-to-slf4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.logging.log4j</groupId>\n            <artifactId>log4j-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.logging.log4j</groupId>\n            <artifactId>log4j-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.logging.log4j</groupId>\n            <artifactId>log4j-slf4j2-impl</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-fileupload2-jakarta-servlet5</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-fileupload2-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-exec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-csv</artifactId>\n        </dependency>\n        <!-- TODO: do we need these? -->\n        <dependency>\n            <groupId>org.apache.camel</groupId>\n            <artifactId>camel-amqp</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.camel</groupId>\n            <artifactId>camel-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.camel</groupId>\n            <artifactId>camel-core-osgi</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.camel</groupId>\n            <artifactId>camel-jms</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.camel</groupId>\n            <artifactId>camel-script</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.camel</groupId>\n            <artifactId>camel-stream</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.qpid</groupId>\n            <artifactId>qpid-jms-client</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.qpid</groupId>\n            <artifactId>proton-j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.servicemix.bundles</groupId>\n            <artifactId>org.apache.servicemix.bundles.spring-beans</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.servicemix.bundles</groupId>\n            <artifactId>org.apache.servicemix.bundles.spring-context</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.servicemix.bundles</groupId>\n            <artifactId>org.apache.servicemix.bundles.spring-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.servicemix.bundles</groupId>\n            <artifactId>org.apache.servicemix.bundles.spring-expression</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.servicemix.bundles</groupId>\n            <artifactId>org.apache.servicemix.bundles.spring-jms</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.servicemix.bundles</groupId>\n            <artifactId>org.apache.servicemix.bundles.spring-tx</artifactId>\n        </dependency>\n        <!-- END PREVIOUS TODO -->\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>osgi.annotation</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.google.code.gson</groupId>\n            <artifactId>gson</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>failureaccess</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-buffer</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec-http</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec-mqtt</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-common</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-handler</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-resolver</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-native-epoll</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-classes-epoll</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-classes-kqueue</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-native-kqueue</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-native-unix-common</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec-socks</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-handler-proxy</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.hk2</groupId>\n            <artifactId>osgi-resource-locator</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.useradmin</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.bouncycastle</groupId>\n            <artifactId>bcpkix-jdk18on</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.bouncycastle</groupId>\n            <artifactId>bcprov-jdk18on</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.bouncycastle</groupId>\n            <artifactId>bctls-jdk18on</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.bouncycastle</groupId>\n            <artifactId>bcutil-jdk18on</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.bouncycastle</groupId>\n            <artifactId>bcpg-jdk18on</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.servicemix.bundles</groupId>\n            <artifactId>org.apache.servicemix.bundles.c3p0</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.zaxxer</groupId>\n            <artifactId>HikariCP</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.quartz-scheduler</groupId>\n            <artifactId>quartz</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.xerial</groupId>\n            <artifactId>sqlite-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.eclipsesource.minimal-json</groupId>\n            <artifactId>minimal-json</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.dependencymanager</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.deploymentadmin</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.http.servlet-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.http.bridge</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.http.proxy</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.http.wrappers</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.knowhowlab.osgi</groupId>\n            <artifactId>monitoradmin</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.jetty</groupId>\n            <artifactId>jetty-http</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.jetty</groupId>\n            <artifactId>jetty-security</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.jetty</groupId>\n            <artifactId>jetty-server</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.jetty</groupId>\n            <artifactId>jetty-session</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.jetty</groupId>\n            <artifactId>jetty-util</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.jetty</groupId>\n            <artifactId>jetty-io</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.jetty.ee10</groupId>\n            <artifactId>jetty-ee10-servlet</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.http.whiteboard</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.servlet</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.osgi-technology.rest</groupId>\n            <artifactId>org.eclipse.osgitech.rest</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.osgi-technology.rest</groupId>\n            <artifactId>org.eclipse.osgitech.rest.sse</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.osgi-technology.rest</groupId>\n            <artifactId>org.eclipse.osgitech.rest.servlet.whiteboard</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.aries.spifly</groupId>\n            <artifactId>org.apache.aries.spifly.dynamic.bundle</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.ow2.asm</groupId>\n            <artifactId>asm</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.ow2.asm</groupId>\n            <artifactId>asm-commons</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.ow2.asm</groupId>\n            <artifactId>asm-tree</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.ow2.asm</groupId>\n            <artifactId>asm-util</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.ow2.asm</groupId>\n            <artifactId>asm-analysis</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.hk2</groupId>\n            <artifactId>hk2-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.hk2.external</groupId>\n            <artifactId>aopalliance-repackaged</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.hk2</groupId>\n            <artifactId>hk2-locator</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.hk2</groupId>\n            <artifactId>hk2-utils</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.inject</groupId>\n            <artifactId>jersey-hk2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.containers</groupId>\n            <artifactId>jersey-container-servlet</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.containers</groupId>\n            <artifactId>jersey-container-servlet-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.core</groupId>\n            <artifactId>jersey-client</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.core</groupId>\n            <artifactId>jersey-common</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.core</groupId>\n            <artifactId>jersey-server</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.ext</groupId>\n            <artifactId>jersey-entity-filtering</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.media</groupId>\n            <artifactId>jersey-media-jaxb</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.media</groupId>\n            <artifactId>jersey-media-sse</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.glassfish.jersey.media</groupId>\n            <artifactId>jersey-media-multipart</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.javassist</groupId>\n            <artifactId>javassist</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.jvnet.mimepull</groupId>\n            <artifactId>mimepull</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.component.annotations</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.metatype.annotations</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-databind</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-annotations</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.fasterxml.jackson.core</groupId>\n            <artifactId>jackson-core</artifactId>\n        </dependency>\n        <!-- END common dependencies -->\n        <!-- START Artemis and Camel common dependencies -->\n        <dependency>\n            <groupId>org.apache.geronimo.specs</groupId>\n            <artifactId>geronimo-jms_2.0_spec</artifactId>\n        </dependency>\n        <!-- END Artemis and Camel common dependencies -->\n        <!-- START Jakarta dependencies -->\n        <dependency>\n            <groupId>jakarta.inject</groupId>\n            <artifactId>jakarta.inject-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>jakarta.validation</groupId>\n            <artifactId>jakarta.validation-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>jakarta.xml.bind</groupId>\n            <artifactId>jakarta.xml.bind-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>jakarta.activation</groupId>\n            <artifactId>jakarta.activation-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>jakarta.annotation</groupId>\n            <artifactId>jakarta.annotation-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>jakarta.xml.ws</groupId>\n            <artifactId>jakarta.xml.ws-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>jakarta.xml.soap</groupId>\n            <artifactId>jakarta.xml.soap-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.sun.xml.bind</groupId>\n            <artifactId>jaxb-osgi</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>jakarta.ws.rs</groupId>\n            <artifactId>jakarta.ws.rs-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.jakartars</artifactId>\n        </dependency>\n        <!-- END Jakarta dependencies -->\n        <!-- START Equinox dependencies -->\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.cm</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.component</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.coordinator</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.device</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.event</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.log.stream</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.metatype</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.prefs</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.provisioning</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.upnp</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.useradmin</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.service.wireadmin</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.util.function</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.util.measurement</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.util.position</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.util.promise</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.util.pushstream</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.osgi</groupId>\n            <artifactId>org.osgi.util.xml</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.cm</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.common</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.console</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.registry</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.event</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.io</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.metatype</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.launcher</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.util</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.wireadmin</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.scr</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.core.runtime</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.core.jobs</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.preferences</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.core.contenttype</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.equinox.app</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.osgi</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.platform</groupId>\n            <artifactId>org.eclipse.osgi.util</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.gogo.command</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.gogo.runtime</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.apache.felix.gogo.shell</artifactId>\n        </dependency>\n        <!-- END Equinox dependencies -->\n        <!-- START test dependencies -->\n        <dependency>\n            <groupId>org.junit</groupId>\n            <artifactId>org.junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>io.dropwizard.metrics</groupId>\n            <artifactId>metrics-core</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.github.moquette-io.moquette</groupId>\n            <artifactId>moquette-broker</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.hamcrest</groupId>\n            <artifactId>org.hamcrest</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.hamcrest</groupId>\n            <artifactId>org.hamcrest.integration</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.hamcrest</groupId>\n            <artifactId>org.hamcrest.library</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.hamcrest</groupId>\n            <artifactId>org.hamcrest.text</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-core</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>net.bytebuddy</groupId>\n            <artifactId>byte-buddy</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>net.bytebuddy</groupId>\n            <artifactId>byte-buddy-agent</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.objenesis</groupId>\n            <artifactId>objenesis</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <!-- END test dependencies -->\n        <!-- START Kura target platform PDE Dependencies -->\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>com.codeminders.hidapi</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>com.codeminders.hidapi.x86_64</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>com.codeminders.hidapi.aarch64</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>log4j2-api-config</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.camel.sun.misc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.kura.sun.misc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.soda.dk.comm</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.soda.dk.comm.x86_64</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.eclipse.soda.dk.comm.aarch64</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.moka7</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>org.usb4java</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.eclipse.kura</groupId>\n            <artifactId>usb4java-javax</artifactId>\n        </dependency>\n        <!-- END Kura target platform PDE Dependencies -->\n    </dependencies>\n</project>"
  },
  {
    "path": "target-platform/usb4java-javax/.gitignore",
    "content": "lib/\nMETA-INF\n"
  },
  {
    "path": "target-platform/usb4java-javax/about.html",
    "content": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n        \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n    <title>About</title>\n</head>\n<body lang=\"EN-US\">\n<h2>About This Content</h2>\n\n<p>November 30, 2017</p>\n<h3>License</h3>\n\n<p>\n    The Eclipse Foundation makes available all content in this plug-in\n    (&quot;Content&quot;). Unless otherwise indicated below, the Content\n    is provided to you under the terms and conditions of the Eclipse\n    Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is\n    available at <a href=\"http://www.eclipse.org/legal/epl-2.0\">http://www.eclipse.org/legal/epl-2.0</a>.\n    For purposes of the EPL, &quot;Program&quot; will mean the Content.\n</p>\n\n<p>\n    If you did not receive this Content directly from the Eclipse\n    Foundation, the Content is being redistributed by another party\n    (&quot;Redistributor&quot;) and different terms and conditions may\n    apply to your use of any object code in the Content. Check the\n    Redistributor's license that was provided with the Content. If no such\n    license exists, contact the Redistributor. Unless otherwise indicated\n    below, the terms and conditions of the EPL still apply to any source\n    code in the Content and such source code may be obtained at <a\n        href=\"http://www.eclipse.org/\">http://www.eclipse.org</a>.\n</p>\n\n\t\t\n\t\t<h3>Third Party Content</h3>\n\t\t<p>The Content includes items that have been sourced from third parties as set out below. If you \n\t\tdid not receive this Content directly from the Eclipse Foundation, the following is provided \n\t\tfor informational purposes only, and you should look to the Redistributor's license for \n\t\tterms and conditions of use.</p>\n\t\t<p><em>\n\t\t<strong>javax.usb.common-1.0.2.jar</strong> <br/><br/>\n\t\tCommon Public License 1.0\n\t\t</em></p>\n\n\n</body>\n</html>"
  },
  {
    "path": "target-platform/usb4java-javax/about_files/cpl-v10.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n<HTML>\n<HEAD>\n<TITLE>Common Public License - v 1.0</TITLE>\n<meta http-equiv=Content-Type content=\"text/html; charset=ISO-8859-1\">\n</HEAD>\n\n<BODY BGCOLOR=\"#FFFFFF\" VLINK=\"#800000\">\n\n\n<P ALIGN=\"CENTER\"><B>Common Public License - v 1.0</B>\n\n<P><FONT SIZE=\"2\"><B>Updated 16 Apr 2009</B></FONT>\n\n<P><FONT SIZE=\"2\"><B>As of 25 Feb 2009, IBM has assigned the Agreement Steward role for the CPL to the Eclipse Foundation. \nEclipse has designated the Eclipse Public License (EPL) as the follow-on version of the CPL.</B></FONT>\n\n<P><B></B><FONT SIZE=\"3\"></FONT>\n<P><FONT SIZE=\"3\"></FONT><FONT SIZE=\"2\">THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC LICENSE (\"AGREEMENT\").  ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"><B>1.  DEFINITIONS</B></FONT>\n<P><FONT SIZE=\"2\">\"Contribution\" means:</FONT>\n\n<UL><FONT SIZE=\"2\">a) in the case of the initial Contributor, the initial code and documentation distributed under this Agreement, and<BR CLEAR=\"LEFT\">\nb) in the case of each subsequent Contributor:</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">i)\t \tchanges to the Program, and</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">ii)\t\tadditions to the Program;</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">where such changes and/or additions to the Program originate from and are distributed by that particular Contributor.  </FONT><FONT SIZE=\"2\">A Contribution 'originates' from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf.  </FONT><FONT SIZE=\"2\">Contributions do not include additions to the Program which:  (i) are separate modules of software distributed in conjunction with the Program under their own license agreement, and (ii) are not derivative works of the Program.  </FONT></UL>\n\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">\"Contributor\" means any person or entity that distributes the Program.</FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">\"Licensed Patents \" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.  </FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">\"Program\" means the Contributions distributed in accordance with this Agreement.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">\"Recipient\" means anyone who receives the Program under this Agreement, including all Contributors.</FONT>\n<P><FONT SIZE=\"2\"><B></B></FONT>\n<P><FONT SIZE=\"2\"><B>2.  GRANT OF RIGHTS</B></FONT>\n\n<UL><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">a)\t</FONT><FONT SIZE=\"2\">Subject to the terms of this Agreement, each Contributor hereby grants</FONT><FONT SIZE=\"2\"> Recipient a non-exclusive, worldwide, royalty-free copyright license to</FONT><FONT SIZE=\"2\" COLOR=\"#FF0000\"> </FONT><FONT SIZE=\"2\">reproduce, prepare derivative works of, publicly display, publicly perform, distribute and sublicense the Contribution of such Contributor, if any, and such derivative works, in source code and object code form.</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">b) \tSubject to the terms of this Agreement, each Contributor hereby grants </FONT><FONT SIZE=\"2\">Recipient a non-exclusive, worldwide,</FONT><FONT SIZE=\"2\" COLOR=\"#008000\"> </FONT><FONT SIZE=\"2\">royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in source code and object code form.  This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents.  The patent license shall not apply to any other combinations which include the Contribution.  No hardware per se is licensed hereunder.   </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">c)\tRecipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity.  Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise.  As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any.  For example, if a third party patent license is required to allow Recipient to distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">d)\tEach Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\"></FONT></UL>\n\n<P><FONT SIZE=\"2\"><B>3.  REQUIREMENTS</B></FONT>\n<P><FONT SIZE=\"2\"><B></B>A Contributor may choose to distribute the Program in object code form under its own license agreement, provided that:</FONT>\n\n<UL><FONT SIZE=\"2\">a)\tit complies with the terms and conditions of this Agreement; and</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">b)\tits license agreement:</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">i)\teffectively disclaims</FONT><FONT SIZE=\"2\"> on behalf of all Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">ii) \teffectively excludes on behalf of all Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">iii)</FONT><FONT SIZE=\"2\">\tstates that any provisions which differ from this Agreement are offered by that Contributor alone and not by any other party; and</FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">iv)\tstates that source code for the Program is available from such Contributor, and informs licensees how to obtain it in a reasonable manner on or through a medium customarily used for software exchange.</FONT><FONT SIZE=\"2\" COLOR=\"#0000FF\"> </FONT><FONT SIZE=\"2\" COLOR=\"#FF0000\"></FONT></UL>\n\n\n<UL><FONT SIZE=\"2\" COLOR=\"#FF0000\"></FONT><FONT SIZE=\"2\"></FONT></UL>\n\n<P><FONT SIZE=\"2\">When the Program is made available in source code form:</FONT>\n\n<UL><FONT SIZE=\"2\">a)\tit must be made available under this Agreement; and </FONT></UL>\n\n\n<UL><FONT SIZE=\"2\">b)\ta copy of this Agreement must be included with each copy of the Program.  </FONT></UL>\n\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\" COLOR=\"#0000FF\"><STRIKE></STRIKE></FONT>\n<P><FONT SIZE=\"2\" COLOR=\"#0000FF\"><STRIKE></STRIKE></FONT><FONT SIZE=\"2\">Contributors may not remove or alter any copyright notices contained within the Program.  </FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">Each Contributor must identify itself as the originator of its Contribution, if any, in a manner that reasonably allows subsequent Recipients to identify the originator of the Contribution.  </FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"><B>4.  COMMERCIAL DISTRIBUTION</B></FONT>\n<P><FONT SIZE=\"2\">Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like.  While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors.   Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (\"Commercial Contributor\") hereby agrees to defend and indemnify every other Contributor (\"Indemnified Contributor\") against any losses, damages and costs (collectively \"Losses\") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering.  The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement.  In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations.  The Indemnified Contributor may participate in any such claim at its own expense.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">For example, a Contributor might include the Program in a commercial product offering, Product X.  That Contributor is then a Commercial Contributor.  If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone.  Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.</FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\" COLOR=\"#0000FF\"></FONT>\n<P><FONT SIZE=\"2\" COLOR=\"#0000FF\"></FONT><FONT SIZE=\"2\"><B>5.  NO WARRANTY</B></FONT>\n<P><FONT SIZE=\"2\">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is</FONT><FONT SIZE=\"2\"> solely responsible for determining the appropriateness of using and distributing </FONT><FONT SIZE=\"2\">the Program</FONT><FONT SIZE=\"2\"> and assumes all risks associated with its exercise of rights under this Agreement</FONT><FONT SIZE=\"2\">, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, </FONT><FONT SIZE=\"2\">programs or equipment, and unavailability or interruption of operations</FONT><FONT SIZE=\"2\">.  </FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"><B>6.  DISCLAIMER OF LIABILITY</B></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES </FONT><FONT SIZE=\"2\">(INCLUDING WITHOUT LIMITATION LOST PROFITS),</FONT><FONT SIZE=\"2\"> HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"><B>7.  GENERAL</B></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">If Recipient institutes patent litigation against a Contributor with respect to a patent applicable to software (including a cross-claim or counterclaim in a lawsuit), then any patent licenses granted by that Contributor to such Recipient under this Agreement shall terminate as of the date such litigation is filed.  In addition, if Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. </FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance.  If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable.  However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.  </FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\">Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted  and may only be modified in the following manner. The Agreement Steward reserves the right to </FONT><FONT SIZE=\"2\">publish new versions (including revisions) of this Agreement from time to </FONT><FONT SIZE=\"2\">time. No one other than the Agreement Steward has the right to modify this Agreement. IBM is the initial Agreement Steward.   IBM may assign the responsibility to serve as the Agreement Steward to a suitable separate entity.  </FONT><FONT SIZE=\"2\">Each new version of the Agreement will be given a distinguishing version number.  The Program (including Contributions) may always be distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to distribute the Program (including its Contributions) under the new </FONT><FONT SIZE=\"2\">version.  </FONT><FONT SIZE=\"2\">Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, </FONT><FONT SIZE=\"2\">by implication, estoppel or otherwise</FONT><FONT SIZE=\"2\">.</FONT><FONT SIZE=\"2\">  All rights in the Program not expressly granted under this Agreement are reserved.</FONT>\n<P><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\">This Agreement is governed by the laws of the State of New York and the intellectual property laws of the United States of America. No party to this Agreement will bring a legal action under this Agreement more than one year after the cause of action arose.  Each party waives its rights to a jury trial in any resulting litigation.</FONT>\n<P><FONT SIZE=\"2\"></FONT><FONT SIZE=\"2\"></FONT>\n<P><FONT SIZE=\"2\"></FONT>\n\n</BODY>\n\n</HTML>"
  },
  {
    "path": "target-platform/usb4java-javax/build.properties",
    "content": "source.. = src/main/resources/\noutput.. = target/classes/\nbin.includes = META-INF/,\\\n               .,\\\n               lib/\n"
  },
  {
    "path": "target-platform/usb4java-javax/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n    Copyright (c) 2015, 2026 Eurotech and/or its affiliates and others\n\n    This program and the accompanying materials are made\n    available under the terms of the Eclipse Public License 2.0\n    which is available at https://www.eclipse.org/legal/epl-2.0/\n\n    SPDX-License-Identifier: EPL-2.0\n\n    Contributors:\n     Eurotech\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <groupId>org.eclipse.kura</groupId>\n        <artifactId>target-platform</artifactId>\n        <version>6.0.0-SNAPSHOT</version>\n    </parent>\n    <artifactId>usb4java-javax</artifactId>\n    <version>2.0.0-SNAPSHOT</version>\n    <packaging>bundle</packaging>\n    <name>usb4java-javax</name>\n    <description>javax.usb API using usb4java</description>\n\n    <dependencies>\n        <dependency>\n            <groupId>javax.usb</groupId>\n            <artifactId>usb-api</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>*</groupId>\n                    <artifactId>*</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.usb4java</groupId>\n            <artifactId>usb4java-javax</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>*</groupId>\n                    <artifactId>*</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <plugins>\n            <plugin>\n                <artifactId>maven-clean-plugin</artifactId>\n                <configuration>\n                    <verbose>true</verbose>\n                    <filesets>\n                        <fileset>\n                            <directory>lib/</directory>\n                            <followSymlinks>false</followSymlinks>\n                        </fileset>\n                    </filesets>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <artifactId>maven-dependency-plugin</artifactId>\n                <executions>\n                    <execution>\n                        <id>copy-dependencies</id>\n                        <phase>generate-sources</phase>\n                        <goals>\n                            <goal>copy-dependencies</goal>\n                        </goals>\n                        <configuration>\n                            <outputDirectory>${project.basedir}/lib</outputDirectory>\n                            <excludeTransitive>true</excludeTransitive>\n                            <stripVersion>true</stripVersion>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>maven-bundle-plugin</artifactId>\n                <version>2.3.5</version> <!-- This exact version is required to be built properly -->\n                <extensions>true</extensions>\n                <configuration>\n                    <manifestLocation>META-INF</manifestLocation>\n                    <instructions>\n                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>\n                        <Bundle-Name>${project.name}</Bundle-Name>\n                        <Bundle-Version>${project.version}</Bundle-Version>\n                        <Bundle-ClassPath>.,usb-api.jar,usb4java-javax.jar</Bundle-ClassPath>\n                        <Include-Resource>\n                            ${project.basedir}/lib,\n                            ${project.basedir}/src/main/resources/,\n                            ${project.basedir}/about.html,\n                            about_files=${project.basedir}/about_files/\n                        </Include-Resource>\n                        <Export-Package>\n                            javax.usb;version=\"${usb-api.version}\",\n                            javax.usb.event;version=\"${usb-api.version}\",\n                            javax.usb.util;version=\"${usb-api.version}\"\n                        </Export-Package>\n                        <Require-Capability>\n                            osgi.ee;filter:=\"(&amp;(osgi.ee=JavaSE)(version=21))\"\n                        </Require-Capability>\n                    </instructions>\n                </configuration>\n            </plugin>\n\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-checkstyle-plugin</artifactId>\n                <version>${maven-checkstyle-plugin.version}</version>\n                <configuration>\n                    <skip>true</skip>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "target-platform/usb4java-javax/src/main/resources/javax.usb.properties",
    "content": "javax.usb.services = org.usb4java.javax.Services\norg.usb4java.javax.timeout = 750"
  }
]